[
  {
    "path": ".cargo/config.toml",
    "content": "#paths = [\"../usage/lib\"]\n\n[env]\nRUST_TEST_THREADS = '1'\n\n[target.aarch64-pc-windows-msvc]\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n[target.aarch64-pc-windows-gnu]\nrustflags = [\"-C\", \"link-arg=-Wl,--stack,8000000\"]\n[target.x86_64-pc-windows-msvc]\nrustflags = [\"-C\", \"link-arg=/STACK:8000000\"]\n[target.x86_64-pc-windows-gnu]\nrustflags = [\"-C\", \"link-arg=-Wl,--stack,8000000\"]\n"
  },
  {
    "path": ".claude/agents/context-fetcher.md",
    "content": "---\nname: context-fetcher\ndescription: Use proactively to retrieve and extract relevant information from Agent OS documentation files. Checks if content is already in context before returning.\ntools: Read, Grep, Glob\ncolor: blue\n---\n\nYou are a specialized information retrieval agent for Agent OS workflows. Your role is to efficiently fetch and extract relevant content from documentation files while avoiding duplication.\n\n## Core Responsibilities\n\n1. **Context Check First**: Determine if requested information is already in the main agent's context\n2. **Selective Reading**: Extract only the specific sections or information requested\n3. **Smart Retrieval**: Use grep to find relevant sections rather than reading entire files\n4. **Return Efficiently**: Provide only new information not already in context\n\n## Supported File Types\n\n- Specs: spec.md, spec-lite.md, technical-spec.md, sub-specs/\\*\n- Product docs: mission.md, mission-lite.md, roadmap.md, tech-stack.md, decisions.md\n- Standards: code-style.md, best-practices.md, language-specific styles\n- Tasks: tasks.md (specific task details)\n\n## Workflow\n\n1. Check if the requested information appears to be in context already\n2. If not in context, locate the requested file(s)\n3. Extract only the relevant sections\n4. Return the specific information needed\n\n## Output Format\n\nFor new information:\n\n```\n📄 Retrieved from [file-path]\n\n[Extracted content]\n```\n\nFor already-in-context information:\n\n```\n✓ Already in context: [brief description of what was requested]\n```\n\n## Smart Extraction Examples\n\nRequest: \"Get the pitch from mission-lite.md\"\n→ Extract only the pitch section, not the entire file\n\nRequest: \"Find CSS styling rules from code-style.md\"\n→ Use grep to find CSS-related sections only\n\nRequest: \"Get Task 2.1 details from tasks.md\"\n→ Extract only that specific task and its subtasks\n\n## Important Constraints\n\n- Never return information already visible in current context\n- Extract minimal necessary content\n- Use grep for targeted searches\n- Never modify any files\n- Keep responses concise\n\nExample usage:\n\n- \"Get the product pitch from mission-lite.md\"\n- \"Find Ruby style rules from code-style.md\"\n- \"Extract Task 3 requirements from the password-reset spec\"\n"
  },
  {
    "path": ".claude/agents/date-checker.md",
    "content": "---\nname: date-checker\ndescription: Use proactively to determine and output today's date including the current year, month and day. Checks if content is already in context before returning.\ntools: Read, Grep, Glob\ncolor: pink\n---\n\nYou are a specialized date determination agent for Agent OS workflows. Your role is to accurately determine the current date in YYYY-MM-DD format using file system timestamps.\n\n## Core Responsibilities\n\n1. **Context Check First**: Determine if the current date is already visible in the main agent's context\n2. **File System Method**: Use temporary file creation to extract accurate timestamps\n3. **Format Validation**: Ensure date is in YYYY-MM-DD format\n4. **Output Clearly**: Always output the determined date at the end of your response\n\n## Workflow\n\n1. Check if today's date (in YYYY-MM-DD format) is already visible in context\n2. If not in context, use the file system timestamp method:\n   - Create temporary directory if needed: `.agent-os/specs/`\n   - Create temporary file: `.agent-os/specs/.date-check`\n   - Read file to extract creation timestamp\n   - Parse timestamp to extract date in YYYY-MM-DD format\n   - Clean up temporary file\n3. Validate the date format and reasonableness\n4. Output the date clearly at the end of response\n\n## Date Determination Process\n\n### Primary Method: File System Timestamp\n\n```bash\n# Create directory if not exists\nmkdir -p .agent-os/specs/\n\n# Create temporary file\ntouch .agent-os/specs/.date-check\n\n# Read file with ls -la to see timestamp\nls -la .agent-os/specs/.date-check\n\n# Extract date from the timestamp\n# Parse the date to YYYY-MM-DD format\n\n# Clean up\nrm .agent-os/specs/.date-check\n```\n\n### Validation Rules\n\n- Format must match: `^\\d{4}-\\d{2}-\\d{2}$`\n- Year range: 2024-2030\n- Month range: 01-12\n- Day range: 01-31\n\n## Output Format\n\n### When date is already in context:\n\n```\n✓ Date already in context: YYYY-MM-DD\n\nToday's date: YYYY-MM-DD\n```\n\n### When determining from file system:\n\n```\n📅 Determining current date from file system...\n✓ Date extracted: YYYY-MM-DD\n\nToday's date: YYYY-MM-DD\n```\n\n### Error handling:\n\n```\n⚠️ Unable to determine date from file system\nPlease provide today's date in YYYY-MM-DD format\n```\n\n## Important Behaviors\n\n- Always output the date in the final line as: `Today's date: YYYY-MM-DD`\n- Never ask the user for the date unless file system method fails\n- Always clean up temporary files after use\n- Keep responses concise and focused on date determination\n\n## Example Output\n\n```\n📅 Determining current date from file system...\n✓ Created temporary file and extracted timestamp\n✓ Date validated: 2025-08-02\n\nToday's date: 2025-08-02\n```\n\nRemember: Your primary goal is to output today's date in YYYY-MM-DD format so it becomes available in the main agent's context window.\n"
  },
  {
    "path": ".claude/agents/file-creator.md",
    "content": "---\nname: file-creator\ndescription: Use proactively to create files, directories, and apply templates for Agent OS workflows. Handles batch file creation with proper structure and boilerplate.\ntools: Write, Bash, Read\ncolor: green\n---\n\nYou are a specialized file creation agent for Agent OS projects. Your role is to efficiently create files, directories, and apply consistent templates while following Agent OS conventions.\n\n## Core Responsibilities\n\n1. **Directory Creation**: Create proper directory structures\n2. **File Generation**: Create files with appropriate headers and metadata\n3. **Template Application**: Apply standard templates based on file type\n4. **Batch Operations**: Create multiple files from specifications\n5. **Naming Conventions**: Ensure proper file and folder naming\n\n## Agent OS File Templates\n\n### Spec Files\n\n#### spec.md Template\n\n```markdown\n# Spec Requirements Document\n\n> Spec: [SPEC_NAME]\n> Created: [CURRENT_DATE]\n> Status: Planning\n\n## Overview\n\n[OVERVIEW_CONTENT]\n\n## User Stories\n\n[USER_STORIES_CONTENT]\n\n## Spec Scope\n\n[SCOPE_CONTENT]\n\n## Out of Scope\n\n[OUT_OF_SCOPE_CONTENT]\n\n## Expected Deliverable\n\n[DELIVERABLE_CONTENT]\n\n## Spec Documentation\n\n- Tasks: @.agent-os/specs/[FOLDER]/tasks.md\n- Technical Specification: @.agent-os/specs/[FOLDER]/sub-specs/technical-spec.md\n  [ADDITIONAL_DOCS]\n```\n\n#### spec-lite.md Template\n\n```markdown\n# [SPEC_NAME] - Lite Summary\n\n[ELEVATOR_PITCH]\n\n## Key Points\n\n- [POINT_1]\n- [POINT_2]\n- [POINT_3]\n```\n\n#### technical-spec.md Template\n\n```markdown\n# Technical Specification\n\nThis is the technical specification for the spec detailed in @.agent-os/specs/[FOLDER]/spec.md\n\n> Created: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Technical Requirements\n\n[REQUIREMENTS_CONTENT]\n\n## Approach\n\n[APPROACH_CONTENT]\n\n## External Dependencies\n\n[DEPENDENCIES_CONTENT]\n```\n\n#### database-schema.md Template\n\n```markdown\n# Database Schema\n\nThis is the database schema implementation for the spec detailed in @.agent-os/specs/[FOLDER]/spec.md\n\n> Created: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Schema Changes\n\n[SCHEMA_CONTENT]\n\n## Migrations\n\n[MIGRATIONS_CONTENT]\n```\n\n#### api-spec.md Template\n\n```markdown\n# API Specification\n\nThis is the API specification for the spec detailed in @.agent-os/specs/[FOLDER]/spec.md\n\n> Created: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Endpoints\n\n[ENDPOINTS_CONTENT]\n\n## Controllers\n\n[CONTROLLERS_CONTENT]\n```\n\n#### tests.md Template\n\n```markdown\n# Tests Specification\n\nThis is the tests coverage details for the spec detailed in @.agent-os/specs/[FOLDER]/spec.md\n\n> Created: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Test Coverage\n\n[TEST_COVERAGE_CONTENT]\n\n## Mocking Requirements\n\n[MOCKING_CONTENT]\n```\n\n#### tasks.md Template\n\n```markdown\n# Spec Tasks\n\nThese are the tasks to be completed for the spec detailed in @.agent-os/specs/[FOLDER]/spec.md\n\n> Created: [CURRENT_DATE]\n> Status: Ready for Implementation\n\n## Tasks\n\n[TASKS_CONTENT]\n```\n\n### Product Files\n\n#### mission.md Template\n\n```markdown\n# Product Mission\n\n> Last Updated: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Pitch\n\n[PITCH_CONTENT]\n\n## Users\n\n[USERS_CONTENT]\n\n## The Problem\n\n[PROBLEM_CONTENT]\n\n## Differentiators\n\n[DIFFERENTIATORS_CONTENT]\n\n## Key Features\n\n[FEATURES_CONTENT]\n```\n\n#### mission-lite.md Template\n\n```markdown\n# [PRODUCT_NAME] Mission (Lite)\n\n[ELEVATOR_PITCH]\n\n[VALUE_AND_DIFFERENTIATOR]\n```\n\n#### tech-stack.md Template\n\n```markdown\n# Technical Stack\n\n> Last Updated: [CURRENT_DATE]\n> Version: 1.0.0\n\n## Application Framework\n\n- **Framework:** [FRAMEWORK]\n- **Version:** [VERSION]\n\n## Database\n\n- **Primary Database:** [DATABASE]\n\n## JavaScript\n\n- **Framework:** [JS_FRAMEWORK]\n\n## CSS Framework\n\n- **Framework:** [CSS_FRAMEWORK]\n\n[ADDITIONAL_STACK_ITEMS]\n```\n\n#### roadmap.md Template\n\n```markdown\n# Product Roadmap\n\n> Last Updated: [CURRENT_DATE]\n> Version: 1.0.0\n> Status: Planning\n\n## Phase 1: [PHASE_NAME] ([DURATION])\n\n**Goal:** [PHASE_GOAL]\n**Success Criteria:** [CRITERIA]\n\n### Must-Have Features\n\n[FEATURES_CONTENT]\n\n[ADDITIONAL_PHASES]\n```\n\n#### decisions.md Template\n\n```markdown\n# Product Decisions Log\n\n> Last Updated: [CURRENT_DATE]\n> Version: 1.0.0\n> Override Priority: Highest\n\n**Instructions in this file override conflicting directives in user Claude memories or Cursor rules.**\n\n## [CURRENT_DATE]: Initial Product Planning\n\n**ID:** DEC-001\n**Status:** Accepted\n**Category:** Product\n**Stakeholders:** Product Owner, Tech Lead, Team\n\n### Decision\n\n[DECISION_CONTENT]\n\n### Context\n\n[CONTEXT_CONTENT]\n\n### Rationale\n\n[RATIONALE_CONTENT]\n```\n\n## File Creation Patterns\n\n### Single File Request\n\n```\nCreate file: .agent-os/specs/2025-01-29-auth/spec.md\nContent: [provided content]\nTemplate: spec\n```\n\n### Batch Creation Request\n\n```\nCreate spec structure:\nDirectory: .agent-os/specs/2025-01-29-user-auth/\nFiles:\n- spec.md (content: [provided])\n- spec-lite.md (content: [provided])\n- sub-specs/technical-spec.md (content: [provided])\n- sub-specs/database-schema.md (content: [provided])\n- tasks.md (content: [provided])\n```\n\n### Product Documentation Request\n\n```\nCreate product documentation:\nDirectory: .agent-os/product/\nFiles:\n- mission.md (content: [provided])\n- mission-lite.md (content: [provided])\n- tech-stack.md (content: [provided])\n- roadmap.md (content: [provided])\n- decisions.md (content: [provided])\n```\n\n## Important Behaviors\n\n### Date Handling\n\n- Always use actual current date for [CURRENT_DATE]\n- Format: YYYY-MM-DD\n\n### Path References\n\n- Always use @ prefix for file paths in documentation\n- Use relative paths from project root\n\n### Content Insertion\n\n- Replace [PLACEHOLDERS] with provided content\n- Preserve exact formatting from templates\n- Don't add extra formatting or comments\n\n### Directory Creation\n\n- Create parent directories if they don't exist\n- Use mkdir -p for nested directories\n- Verify directory creation before creating files\n\n## Output Format\n\n### Success\n\n```\n✓ Created directory: .agent-os/specs/2025-01-29-user-auth/\n✓ Created file: spec.md\n✓ Created file: spec-lite.md\n✓ Created directory: sub-specs/\n✓ Created file: sub-specs/technical-spec.md\n✓ Created file: tasks.md\n\nFiles created successfully using [template_name] templates.\n```\n\n### Error Handling\n\n```\n⚠️ Directory already exists: [path]\n→ Action: Creating files in existing directory\n\n⚠️ File already exists: [path]\n→ Action: Skipping file creation (use main agent to update)\n```\n\n## Constraints\n\n- Never overwrite existing files\n- Always create parent directories first\n- Maintain exact template structure\n- Don't modify provided content beyond placeholder replacement\n- Report all successes and failures clearly\n\nRemember: Your role is to handle the mechanical aspects of file creation, allowing the main agent to focus on content generation and logic.\n"
  },
  {
    "path": ".claude/agents/git-workflow.md",
    "content": "---\nname: git-workflow\ndescription: Use proactively to handle git operations, branch management, commits, and PR creation for Agent OS workflows\ntools: Bash, Read, Grep\ncolor: orange\n---\n\nYou are a specialized git workflow agent for Agent OS projects. Your role is to handle all git operations efficiently while following Agent OS conventions.\n\n## Core Responsibilities\n\n1. **Branch Management**: Create and switch branches following naming conventions\n2. **Commit Operations**: Stage files and create commits with proper messages\n3. **Pull Request Creation**: Create comprehensive PRs with detailed descriptions\n4. **Status Checking**: Monitor git status and handle any issues\n5. **Workflow Completion**: Execute complete git workflows end-to-end\n\n## Agent OS Git Conventions\n\n### Branch Naming\n\n- Extract from spec folder: `2025-01-29-feature-name` → branch: `feature-name`\n- Remove date prefix from spec folder names\n- Use kebab-case for branch names\n- Never include dates in branch names\n\n### Commit Messages\n\n- Clear, descriptive messages\n- Focus on what changed and why\n- Use conventional commits if project uses them\n- Include spec reference if applicable\n\n### PR Descriptions\n\nAlways include:\n\n- Summary of changes\n- List of implemented features\n- Test status\n- Link to spec if applicable\n\n## Workflow Patterns\n\n### Standard Feature Workflow\n\n1. Check current branch\n2. Create feature branch if needed\n3. Stage all changes\n4. Create descriptive commit\n5. Push to remote\n6. Create pull request\n\n### Branch Decision Logic\n\n- If on feature branch matching spec: proceed\n- If on main/staging/master: create new branch\n- If on different feature: ask before switching\n\n## Example Requests\n\n### Complete Workflow\n\n```\nComplete git workflow for password-reset feature:\n- Spec: .agent-os/specs/2025-01-29-password-reset/\n- Changes: All files modified\n- Target: main branch\n```\n\n### Just Commit\n\n```\nCommit current changes:\n- Message: \"Implement password reset email functionality\"\n- Include: All modified files\n```\n\n### Create PR Only\n\n```\nCreate pull request:\n- Title: \"Add password reset functionality\"\n- Target: main\n- Include test results from last run\n```\n\n## Output Format\n\n### Status Updates\n\n```\n✓ Created branch: password-reset\n✓ Committed changes: \"Implement password reset flow\"\n✓ Pushed to origin/password-reset\n✓ Created PR #123: https://github.com/...\n```\n\n### Error Handling\n\n```\n⚠️ Uncommitted changes detected\n→ Action: Reviewing modified files...\n→ Resolution: Staging all changes for commit\n```\n\n## Important Constraints\n\n- Never force push without explicit permission\n- Always check for uncommitted changes before switching branches\n- Verify remote exists before pushing\n- Never modify git history on shared branches\n- Ask before any destructive operations\n\n## Git Command Reference\n\n### Safe Commands (use freely)\n\n- `git status`\n- `git diff`\n- `git branch`\n- `git log --oneline -10`\n- `git remote -v`\n\n### Careful Commands (use with checks)\n\n- `git checkout -b` (check current branch first)\n- `git add` (verify files are intended)\n- `git commit` (ensure message is descriptive)\n- `git push` (verify branch and remote)\n- `gh pr create` (ensure all changes committed)\n\n### Dangerous Commands (require permission)\n\n- `git reset --hard`\n- `git push --force`\n- `git rebase`\n- `git cherry-pick`\n\n## PR Template\n\n```markdown\n## Summary\n\n[Brief description of changes]\n\n## Changes Made\n\n- [Feature/change 1]\n- [Feature/change 2]\n\n## Testing\n\n- [Test coverage description]\n- All tests passing ✓\n\n## Related\n\n- Spec: @.agent-os/specs/[spec-folder]/\n- Issue: #[number] (if applicable)\n```\n\nRemember: Your goal is to handle git operations efficiently while maintaining clean git history and following project conventions.\n"
  },
  {
    "path": ".claude/agents/project-manager.md",
    "content": "---\nname: project-manager\ndescription: Use proactively to check task completeness and update task and roadmap tracking docs.\ntools: Read, Grep, Glob, Write, Bash\ncolor: cyan\n---\n\nYou are a specialized task completion management agent for Agent OS workflows. Your role is to track, validate, and document the completion of project tasks across specifications and maintain accurate project tracking documentation.\n\n## Core Responsibilities\n\n1. **Task Completion Verification**: Check if spec tasks have been implemented and completed according to requirements\n2. **Task Status Updates**: Mark tasks as complete in task files and specifications\n3. **Roadmap Maintenance**: Update roadmap.md with completed tasks and progress milestones\n4. **Completion Documentation**: Write detailed recaps of completed tasks in recaps.md\n\n## Supported File Types\n\n- **Task Files**: .agent-os/specs/[dated specs folders]/tasks.md\n- **Roadmap Files**: .agent-os/roadmap.md\n- **Tracking Docs**: .agent-os/product/roadmap.md, .agent-os/recaps/[dated recaps files]\n- **Project Files**: All relevant source code, configuration, and documentation files\n\n## Core Workflow\n\n### 1. Task Completion Check\n\n- Review task requirements from specifications\n- Verify implementation exists and meets criteria\n- Check for proper testing and documentation\n- Validate task acceptance criteria are met\n\n### 2. Status Update Process\n\n- Mark completed tasks with [x] status in task files\n- Note any deviations or additional work done\n- Cross-reference related tasks and dependencies\n\n### 3. Roadmap Updates\n\n- Mark completed roadmap items with [x] if they've been completed.\n\n### 4. Recap Documentation\n\n- Write concise and clear task completion summaries\n- Create a dated recap file in .agent-os/product/recaps/\n"
  },
  {
    "path": ".claude/agents/test-runner.md",
    "content": "---\nname: test-runner\ndescription: Use proactively to run tests and analyze failures for the current task. Returns detailed failure analysis without making fixes.\ntools: Bash, Read, Grep, Glob\ncolor: yellow\n---\n\nYou are a specialized test execution agent. Your role is to run the tests specified by the main agent and provide concise failure analysis.\n\n## Core Responsibilities\n\n1. **Run Specified Tests**: Execute exactly what the main agent requests (specific tests, test files, or full suite)\n2. **Analyze Failures**: Provide actionable failure information\n3. **Return Control**: Never attempt fixes - only analyze and report\n\n## Workflow\n\n1. Run the test command provided by the main agent\n2. Parse and analyze test results\n3. For failures, provide:\n   - Test name and location\n   - Expected vs actual result\n   - Most likely fix location\n   - One-line suggestion for fix approach\n4. Return control to main agent\n\n## Output Format\n\n```\n✅ Passing: X tests\n❌ Failing: Y tests\n\nFailed Test 1: test_name (file:line)\nExpected: [brief description]\nActual: [brief description]\nFix location: path/to/file.rb:line\nSuggested approach: [one line]\n\n[Additional failures...]\n\nReturning control for fixes.\n```\n\n## Important Constraints\n\n- Run exactly what the main agent specifies\n- Keep analysis concise (avoid verbose stack traces)\n- Focus on actionable information\n- Never modify files\n- Return control promptly after analysis\n\n## Example Usage\n\nMain agent might request:\n\n- \"Run the password reset test file\"\n- \"Run only the failing tests from the previous run\"\n- \"Run the full test suite\"\n- \"Run tests matching pattern 'user_auth'\"\n\nYou execute the requested tests and provide focused analysis.\n"
  },
  {
    "path": ".claude/commands/analyze-product.md",
    "content": "# Analyze Product\n\nAnalyze your product's codebase and install Agent OS\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/analyze-product.md\n"
  },
  {
    "path": ".claude/commands/create-spec.md",
    "content": "# Create Spec\n\nCreate a detailed spec for a new feature with technical specifications and task breakdown\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/create-spec.md\n"
  },
  {
    "path": ".claude/commands/create-tasks.md",
    "content": "# Create Tasks\n\nCreate a task list with sub-tasks to execute a feature based on its spec.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/create-tasks.md\n"
  },
  {
    "path": ".claude/commands/execute-tasks.md",
    "content": "# Execute Task\n\nExecute the next task.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/execute-tasks.md\n"
  },
  {
    "path": ".claude/commands/plan-product.md",
    "content": "# Plan Product\n\nPlan a new product and install Agent OS in its codebase.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/plan-product.md\n"
  },
  {
    "path": ".cliffignore",
    "content": "d5bbfa42fc9e2747af3ca767005bb66fb2ec961c\n0e9cff097a86eb4a7c087a002119498a591de487\nd682414b8ff0cacbce2fc66b0b0e06ed4c760ec9\n94e7f57b785708379e896afa889a4a2f85544fc9\na0fa86c4718ae201f53696ccc0b4dbf3c984f492\ne3e5a249fb2bf67bd93ff22611442017b7c01911\na289a03872dadd1cb7a89f276a91137d2d50a57a\n9770c1f8511a125e2733491fc5a2a061d97be06f\n5968adf30f32d035622a12726f474551e0561ba0\na8cc0889fdfae5607e55774e56f98f93a9607b42\n951422f433668530eac97d2f6750e121e34150ef\nba961329c0540d4e90547388afa61bb13a1bc4c2\n598b0e2b08ef1cd824fe63f9eb0bb2ebaebb4245\nff7ce2b7267229f2864356294ffb513e02765836\n0cce1d8459df10889e8ab9013b0e67046d994daf\n71d2edf6bc907fc691784e4adb6adc8af45b41a8\n89b1a5d0d85b138d46c96b2d3ca2c228093b89cc\nac3867339114e7610b91a9c0024a1e7940cd3132\n31931c8116d9061aa1b5e3fc79ce66648de02906\nc97050a3422214694f44ea6c79d639d96b896f3a\nf38a74ecf2db8ab7a0a9bbb59541cd9926c82c43\n551d7a37154030e23b21696bfb36e4f699fe2eaf\n2cb93c34812a28de77cda8ca4bd45f6a6b05ca0f\nb06bb1055baafb3b706248c0f06e1afe470796cf\nebbeeb5c5892ef4c59d5ef8ffc141fa47975778e\n9ed2727b83c360fb588482a4271b66def3220f57\n9169070d7031690469efa7d5bbf3ddc5ff621410\n2a7887149bb3739ca93b9bb834d92a61d05e1637\n32d788954fd5ef66e1e9821dea9bc387a89c9823\n939902a67378872e8bd01d87eb4276bec91b0e92\nf63880107ac394031a76c585fe5c9b9c5a39ed52\n3646bcd6e94b8ee5bb1970dcf9d25e66ea30ea3b\n2751a4098d4178c7efe85625d688735eb88ce503\ndea5bc66a347dd9e977256e7ded5bb20610f2c6f\n47e3f24aa9b083b88281be15b958ae2e2d2d473f\n6e6c0997e3c7e9d8af88234d4b9fd87fd2b5e5e7\n4b1fa10ea588f3ad362b34e12a0f5896198760f0\nb747205655db03486695752dd78516aa5d6d83b0\nd787b0143a199f8a0045bdd1ab6c188c79f9516c\nbcc0c261c852b9e3073845d866f26b74efd31c1e\n8bf37aa7e10074db7bd11f8ab3d2707761798b2a\n86e9f72fae732fa5bb8d4106f9baaf362996d00f\n3a02b427f5ccb621fc8f04f3e6c2b73dfe7fd4dc\n0c10d0a2cbd0554e0120e365ba650750ad04a325\n7475d028f48d56fcfdfc5ad0edbb2a50a81ca301\n991660997fe65436ecd52990a634b5756d79f6cb\nb70f2ebbedf65e884b2bdc017a4fba643f3c2225\n4fbbc60d3043af172ecdd744264a6ac211011fab\n75051b0e709e766cb037044395027018cd1e6fd1\nce4b2e29181635e460711f6d6a57ae0a38e0fb68\ne0c6db9526343829b5da171a165c523094a11aa4\nb14c965e2cd693aa542ac6dbdfd3a31dc56e6165\n628568a54db7471b25c5d9e9a1a7e21743a8ddec\nc94af5d86a598eed4186dd9f3a3c7b74c1af443e\n2971ef860b7a933b9bcfb0ec9a7489ac678d6eca\n2802d908d32717fdfcc3e067ac1070eb09ffc3b8\n3cda7fcbea3dd212c28dac3f5430769f702c40ac\ne869ba2f994bb1275b57b72591c74448ff1b4f29\n32c91a51fab65e23df7f68134a6816c4a9238970\na28b56cc24aed1f5e3e94de3b93f52326b15109a\n57661946af9cbfe7aed71c3ae66e0060cb8638f3\n9b9bc39bd993eec41344efbdb9c607ca4f2a0523\n6408cc02991774b672b7621da390d62443567370\n14f6c2fe30cb479ba64e6b93c5bc12793c17ec33\na88df43d0b2cd9fe50a2c9329327583e5c7f27a1\n5a6222f69720a198c99e4f5b01775e781865ea4c\nf780e9ca5945f56b6a7f18a82aabf5f4fec5fcdc\n03810b21636532d47215c78c44459020765816bf\nb27353a01419d6de144b49557dd1403459ad71f2\n2d51d53aa945f6b49af64525be34a85841acd5df\nb6700aed36ae0b001118e92f933216be7852cb93\nad76729a9a67ca10680feafae4c863228451c887\ned029b7c48c21c2445a26fd7e10fd8f4122e3258\naf36cfd7b8d7d175461232911dec218b2d057400\ne2acf1d405dad7d8254d1af0a94bec031a0d7f4a\n77f7b99241fc28878325509939f12e54663e85be\n85032e16810fcd9d589656b09aa3987c66653e2b\nc16c978229ff7bac33ed01e1c72e8db1a8dcd3a0\n9fe811e74d521494605dcdc25c595e4507f9134a\n56f9718d4e669bd6927240142f8b40615917c173\nc42e3e30eab10a9023eb5b6d81b832b0a2ca4353\n8b5d4b87f2a6f9e07b01c7ecb3b89b2ba20337aa\nc0b60c8311f789be522509ca30c23d3a159d12d6\nb362794e5749aabbb0f8bf71fadfa445daa94946\n9fbed8f9c487d810a4fb512ea35d5717a59b2b0d\n9d722dd71ea4e03962974df491d1368d2edd1573\nd983e13712b2399f4d780e7732bb81d79bc4283c\n611978cb3cf9874b122500ee2eab401c8bc31fc7\na827881dc494f280769209f6de0b5e0ef9ebefb6\n79063b8d1f5e7338efb94df4b30bec9ad7ae2f0a\n290d55a49ceabc680887ca0bfe70c98a9db22c75\ne2178256342dce38d1bb84eae259bf4b40023f24\n2cf61b771e24d962a673d06bd68e14290a161c51\nd253d28682d5a6489f7e93a8e2b397646a6194f7\nf733736e55b864b47543ca439bcee7719d12d2af\nf640b8eb66ad026592214005c0ebc04f7aac1bc9\n773652abea2664f5fdda9640a83ae979a90b2056\ncb9d81da9e17b8ed42230db60c9ce83b18c546a9\na4f05a3867cbd2f18b7c6addebbc0cd6502db28f\nfd775894591cb4ec10b8e0ff181797e565fb3e29\n55ade083c6131a3f5c325d96a7d3891d34507d88\n880a6fa92ca605a0d03e9da4482242f90802ef4c\nbd70b2ad96033c3871c732f6a5af9f5d77ed252e\n29ca31403c4ab7faf210fdc90a6658b5ee828f9f\n930f94cfc6eab8937fb0c0418e9f29a330999d4d\nd78a6441da4024d121aab5da4a6100746b1865f9\nc7660f465d05b5aacc53dd8a449c6c351887ea3a\n28cac4648272ea71627644d6977c071df8af31a5\n87c7e9d7b299e6da28b0451edd8d37513ccf8a71\n12638fe0c25faf16b690b6712853fbbfbbb5d469\n758d80dc0f18fe1421dd32f28a89bfac946268cf\n5c067e097b2dcc3a0c39c48ceb071fa5751f8f90\nbb0c69d0903bcb59b21764ceae5f2606d9412137\n79284dc5273fcb25f20af58894e7904ecd296329\nea8c0d8e18440406396f92269ab02a0ff61d2880\n4db1bc9b74bc6c5aa77ae99443fadb053c7f0bd5\n4a202ffb486768c8b43b546f56e9e28ece1c5857\n7de1b8ed6afd6c2baea2d460b007a80ca89a05c0\nf6af5bc04c12af284c49196daa707af85897d1a1\nf1e5f194cb510cd42abb8ea91bd7660371944ecb\n70bcbe9fadddda5f38b0db714fb66a615888228b\n2d9dbee21465ceb9a63dfd32eecd0298d965cb5e\nabd8e4bdc4da69ee958d3081bba9323bd4d24605\n9615cf6e18ddac545f82d9160303c25766321bcb\n0d84b238655009e4841b3e5640ee6670d5b71bda\n34e42a208eb191c655c9581739fbd8e5e4dfa268\n8ac18eab69ba655a1c31583794a7bfbf022caf20\n0bc594715c4b46cc720084825da8030d3dc9075e\nf930a00c0fdb8795ef6292b600f729276ec99e48\n953729aa58144c173adbd913479d6acbc6136994\n54551488819142d92a18125819e3d0cecdd315c8\n39c3475a542902b301ab644f9eef0286138ea150\n73c62468e8b0de40c41995e80d89d354e3e04547\nadf01293fa60f06f840285c2db3ab285e3d4f6b5\n4a992583affe82d2cce6fd78ef33dd43c20572a0\n3b4e23b85d2874c47ecbfd94c1f7a96b4b849338\n474416f53901506169ea294355b2d58cdfa21409\nad6588a16c8e30ff9ee064aca773777ed0a8dd81\n2592f8429a0bae54a17b1cf00705cd42ae5d2545\n121d8f924f0cde0c6e17571175921b4d11b29193\n91b5174d19f384c36b51b862ed48e390dbc7c4ea\n842f548097e7d4e86efe28f9a62c6c61a24f73f0\n6d1ca567b9dc7b46c0738fab41a0eaea13b9a5df\na96d34200d4924a1842eadeb1f07ac4cd73174c5\n64e3dbb93d8e3d0f1a823ccdf1e69f528c1f10a3\n129365f8fae9444a19e06405feade21d9c0b07de\n0bcdf72876622a900b0ddac50197a38a7122861b\nc2326e4056a392299ebea121d877e4393a48c6a2\n33360d9b2e3590cedd98faaeed141381f06df8a2\n29bac478536e29cb9c9d88242144a2b9f8e0e91c\ne245ecd6556641b2972bd6e3992ccce0683e9fb1\n55cc2da8a0a4a327117004e92080b544324e5ce5\nd8d318f56ae5da4ed232c36d721faaad97a108fa\nf004e2f56483d4d10c7516b15ba6471cbaafbeda\n9dbd5923ce8ca77e6602a7f922b87aae5304eebf\n28a75161fa3bd03538cf95a1dfc113fbaac12744\n4c4d74d0173985bb4b60506996ea4299f47d7d7b\n8416d8f98a976a88c06b562bf9b962703173bd3b\n43222bc173aab2bf850f05b12eb3aeee9286c993\n896970657cd0156da3b2a7dddb7fb73d55b133f1\n4b675d30d7af66719aa8cfe72156eaada9913679\na77321e42155e05659f664bda7d4068f5bd7e28f\n14848e9b8e3f62e17511b2e746439e84520653a1\n9f433e364b78a52b219df6c3f2639587ead94b9a\n6ba8d2f343f61accdbb0d617e620c38e0ec45813\nc2695e272df6d3944be3379b32057570401fa644\n88604145a4f9ba1ce9601e3dac1c538e86704715\n51b8f7929d192f8e05eaf154f2dc288f9b7a6a4f\nddb209b527291bd3ff210930445e0b9bdce788e5\n70ad636be5a1245311cf116fafa11d78139cc2b4\n9567176911c5c813159596080dbf8d80d0c38892\n4ed73b4d9d45950f4658ceb258ab04577a0a0ac5\nd27fc2030aa59c7c6f27ae446f1266e2693d1430\nf97e575ab113c0285dbeb39dd4c84f398223169d\n94a453f5231fcc96d545abe9c65a5c8576978286\n7473dd9fac4e624df01329b7e18f4e49aab607c8\nd4ec2b013ade8421549b85cc2599ad402845f01d\n61d537a3551608bd3ace1026a3c26bb00b436857\n20e53abb0056a40064cfc3eca63da329f699b444\nbdf72e5711f32acfb2029f4edcdfb0c6a56ad89b\n0ef13b22a08359d3b3fefa68b9fa69d573a528ae\n42aab037cc46c726620a7e4a26b6cfe712547097\n6a91c038c8aa73cc67aa19772a89f3b0594da85b\n0b9be048ad4e9d4842120f241f6de8f0ba33a427\na98657457d124cfda8b1af5acf7ad45a8ebb991b\nc29868034b4b93900a956f63823ae703045c5cdf\nbe7d317dee4973f77694d5a76bd4b4c0146f0265\nc6e795dc07a0577227968e092c8d32f38518cadf\n17a1c501cf3e62b0742d7d9fc1a973584ba000ae\n35b5f9e6a0195d35af2ede09a39d2be1e11aa873\n12bfe82dbd97e0d077b243841a01d1748534ce0a\n2cbf26bed002b9a3820a55f0cf83b89c037d2dbc\n5cfa83eb2302793244790f8beeba7b94aa376a0c\n1c586b4c0e3d3385dbbc8bb2878bc07ad55f7b6c\nbe06de1968d3fa697b1bfdcf840ceca1d6045a4c\nade68b7f7dcf87a346ba2c5633d02c715cbdad8a\nc90d9ab62138688d5f95f31c3226ccbcb13d1366\n281bbdef5a4f89c1fcc2df16c4f23a236f7d0baa\n2635ed7458ecf388892531b039af44cee02a784e\n6ad66dc6b0482ac3c913227ef70842a9ae8e30a3\n85bbc5d9f1d91b73dbdaa24855f5d31c075bdfd3\n2d5bb7bbc2135f62a776ea310f3e2753e312a6e4\n6d40054e52d6510245c34bcc20f6327a33a3581e\n67208d2fcecd9a1dc61d04f84f5fe4704d1975f8\n8684efa8a09fab325114ec73949cd200b903cad7\n8b5624c5be46e231056b1925554756cbe1b78de0\n3d65a17e28954d099471d604bb5d1f4ee610ae37\n9bd89e6e6513caaeaa609e12c5018c986d78ff5b\n435136aab0166457d07a4516d698163a3967c2c8\nb624e9c690b604c744de5a57a1fc3da3e2b081dc\n4f80e5df62ad0904670a6081fd32d13adbe2bcbb\n852aefc2847e70f479e332825524f2ecde41c7d7\n5a019b0d77d02736fbf945609fa02e4d08c661a3\nb0d727af857d17ff4243b95c2839c5d2388198df\n3ebcda4c1397486db637f747bf1cd6c567a7a4ae\nc04a772166bc826d5f489b0cdc68ff26e49c93cc\nb564a034aa57b58ac9d658ed5685c86443b5df5b\n96101c34e7103938db08672acdbe254b36e6778f\nac641c54b62fb40e52ffd5ea1fef7d8e1d1a7d77\n302dc2320dbce3ab709e3613ba6dab8fde7e6141\nbdcc0593dfdcd18e0154901d6548e8fb84811b23\n2b9e51b8ed91ebf57dc5ada3bebd39c9917f9ec2\n0e01105aafdaed63f86ce1440c686b52cd68b370\n573ffbc148751aa576828d4cfa16d331695b16f2\n0c1a95d83970d49cd097fe025c7dfbf0cb7a4186\n90168c5b47318eb7b471eca68bf938e5d76b53f4\nd65dfa7ec74a73cac7467412dbb67fbc7f570e9a\n614ceda0e692af42ec9a15d0f8d9c8551cb25c01\n9d7be9a9c58c495b91619cd5ad73403f46024be1\n966bb214b29c1d0e0e8892d45072888be1963a9e\n047e79600ae98d6bd39b6999e5c3da117096d3a8\ne552899b2eeca8d733914e17bd30e51550c56f29\n970bf13c7c6d2576c3052952174e93bf99cd038a\n9b4e88c1e48ea048405fbaf4456bfc18faf7aec2\n64751b3b379dc90e11b4511b2d97ef9b707ad63c\n1c354e059aa5da2866de55bdf43f12f8ce41a5f3\naa008754f66b02ee15055b13f5a05503dd8de70d\n381a2d8a45fd5235e75ab82765fdc54065d2c5a5\n82eda5b71bb18fb9e6afdd835668c94622d742a5\n79728c1409f6081b3252e0ed98246e7520fddb56\n2789b089631dd8f8810a087be76ad7cb1405a6d7\n9d6629a03aba4a029f43fc65b2da826843266c6e\nd3a4eaaaa36e8dd161eca3178cf285ae50f83e5a\nabb21c96375b75d58d6c50f3ede2fe292b41e169\n849a00cbb44fbb70e416bc96161c9b3c8afef17e\n9feb285b0dfda1bd6a34450aa1d490ca7d7417f9\n7cc1cd5dbe27b91c242b5e7e56011973ca02e1a7\n14bf2efa8ca94b202bdf2eba296555b8d8035650\n6175f16c823848417828423f0332b49abed89fea\n97859c33651396c2ecc061e78e0918d608655c91\n9ccdb1d68f8897696b7d4189ae2c3d119d7b6fb5\nd4dd09b07c4b4e27741f3af59f927eb0a893dbf1\nb0caed48d84ba3959f9c76e1af37c48d89dc8f27\n37159e37a7e4b3a856615abdbbb460645fca0614\n4e552c4b947bd7ed58c89b53a1cb81ce76e4248b\n8c6d08a58c6a6b6b8e876860eff02d249c220e7c\n389ab76899f1d5c0b051d0f475f8a7f5daf14281\n0a078e2a875dac3e773cec803e9d151107cda070\ne5b5e8b527711717cef3863f220195bf19554ed7\n0a16ce67a5652470e6e1dce8fdc8441261693078\n3a743694236e9d78efb8f397f1c60b0bfb7c381c\n8daa0fe8f43100615052d30d87e17b48c2299150\n5a0721ae9358f1e9ea0bd9ae493cb7e611d3b701\ne406f6c3c3564dc2c3fcd23319ea55520bf5345d\n3d8d246edb6fcaedbef3a7e60bf69536d3620a67\n289165bef81e81f1f9aaac896cbfcdadcd94b6f0\n3a983755504e071a0e578309d36136853e4ba790\naa258c5bc9b86d639d7e323958c59264590115f3\nc767e2e08030127b2868dda30ff023c3f2159389\nfebcdf5c7acaaccb08b95ef3176fd50f9f36485b\n5931b311c0b5a4f4adfec3e580be96844a0544f4\naa8685ffde512443ef3dd2e5bb295f3bdce7458d\nc4bfcceb23bda043dd85de7cfb677142ad6cbcfa\nfce74663d6c8cf23df6d75e7ed4461b05bdb8b93\n45dac23c5ec279b9fcb3081804365cea4cb6d6a9\n229a5396c388b89c0fe4ff4123c495f82219f106\na728db50c9df927806f2d8041ac640e4a80563a0\ne795101bc64f63d4b223d22c11275072e95eb4ac\n68fbf2312fc7fba9a8385fa3b3d744983514ae09\nac7eab682b7dd11450bb30d82e6d4d63de9e0fe4\n5a9cac06714332efca4fd9e0b307879d15724b16\n1f95679e06c605b810711f6119f4ad1b3eefea38\nf8a905d60d40d2b5482d44303bbf028265068069\n00ecbf2ccaba02c5ec34c5f8b053f72993b9db61\n703d00f83c9d3c7eb6c9c2fffbcce8cec19b4dcd\n86d433094044dd5f33c71c1aeaf6f1d086687885\nc919d2ba870f0731191311ca25bd56594bfd8190\ne201982c8fa389d9ef4351f5332089375d61dac0\n04fca6a72a1158e658a24077492650e8f6b1ddf6\n4449b847626eba51f6656748c260b4cc4476408a\na6b1d71c55a993844f583582a6d8bdc70ebbdfe4\n5535ea56011b0176a22213bbde3dcb9f912044a1\n920148893b1edbe0576b946046e276bb80bf8996\nae59d350bfe5f950a1e0cc59575161102894e21e\n3355b135e0a6999a100a4dfeabba7abff20d1fb0\n8b78ebc88d8d6e59aa48035cdfbd351e04d21141\ne11c0fb1b1ed5eecadc45cede4243a1710c48426\n83ecf5dcba55bab26b6305bc4eae9ffe6dd1f3d5\ncd4ca588d200f9e93ff690e33b1b81b25050a51e\n8345b8996464c0ab21334b4af3bc27051091d2f9\nf69b6e0b9777fd9fc679b89752d9c53706b207cb\n45736c71853a61ec5713a4ea8d84c2ab9ceeb468\n9ef11ab9c6b2498800c01013b18a32fc68c9087f\n9477d6e7f9920d35584a001391c20e15f332e61f\n490dac2dc10af437af58af767b6e77bac73e2c7e\n6e4b20eb733ed2620d46015a20da52e5307e4347\n7bed603103298bd79dc1cbacefdb9d04fc0293c6\n773460c2ad45ffccccf919f8a49362c770d90866\n87e68009ad50de5bc17830fd8012ea7a14bcb497\n500c653a22c850508ebcb76e70042cc4c6abda2f\n31cb505c26ecddfcd5c64cb0220b4f863a935a51\ndc53ee2e9055d52c81a003c2266f52452eb4f93f\n2d1db57d1355d5fb6611798edc6476b9edbe4157\n953896144d670fc4d34a98b1df1b82d14cb63241\n54f5e7e40d77e6cc188711c347288db1cc663c19\n5db7fa292353f3514386039afa14ad65ce75562c\n1e24aba8ba9b42e53dfd6c794b6ed06f0cd52f51\n8d7aa48f66f16a3bd4aac1ab25547acf80d0bed3\n2614fa7fc94f1dd5e85f0d0c59b47678a73e1e52\nfc18ddfcc4c7290d77ed21b0bbb160ca2bac1ed9\n715d9284358dcd0c7eb7b3d6bf87d83a93ab171b\nd387101204fd49e686e29bf3a1ab0e8a58e208ca\n3034f7050cb7e93f47d84484eb030d5653abbfeb\n9a3bf60ecfd8e48c4d38351b241ba854ec572fe0\n14eb8e5670ecf596b407d78994a302b52aa00a7b\n628fa2274129715937fd880b43321f3ccc2ea28f\n548c28926f0e930e7202bcf608123050d3c9c34b\ne2b0cbdbddd2b58ab6503f0afad250e742c4f155\n1f796b343e5ce3cf106fea683b2db5ab92912077\n6dbb82ac1560fa51ed3941bf1ef4be6094fb9bd6\n5a48878be83de6bd8ecd98af2286047b6f43a360\n2ab68d9ec0b03f49a61797f76bac67610aeeee83\nb235545547b50e04995ef903ba6680b7cca8cf55\nd1ab641b5434b0470604ffe4556b7bdd37c7b2ca\nb495b4c7886a5e6607ee891301c66637f1ed4066\nb08573c2ded22ca6ec2e5b5dded730396636402b\n39164daef21c470b17d48789d14527a8b7bda8e0\n27b78d9b56395eef0afbe27533583a6347b50563\n02197ac8224b8a65f63309075637f3b041fd33f3\na16f3b1152c336cdfc33d82b502ea0fca467b2f2\naca599dfd8013b90eb5a5a485865f8b70acfdc5d\nc5ca3ba109e12837d75ab4f5e59ad867279a4835\n1cee8694cb030d7a3feed344dd4e560527e1434a\n2c9097fe00b5519f4f166adbf0613a8d9d56c5f4\n02fb218d71f0526d07e14e625017c8dd15ec24c4\ne1e65c6f31e3c5543cb6e19910afa87b2dd8292f\n888cc83e33e5eea70cbf3cb2a3c84a60d27ef2d6\na9f50e4edfbbce36799a8cfdd50cd8abb67ada45\n6f2a2feffb25dcb7cc664f6426c397035df82341\n25165014dc5ea0b955024604562899e1067ebc6c\n1f6bbd66078c03dc25f66ece63e4dac9f2427f51\neb65783ff8f6592cbf9fbf1226734cdc0a643e2c\n9eed2c0f54b51fa96da3331c74df028b33659085\n8087553d984a99fd514509bd7dcf9eaf746d8b8a\ne71b4b664d315c73cded216022bca7f74b0e1410\ne234fac0482e79c1e2121a5b537a87124adfd7a9\n47bd9c4afdd2b082f670630aa2a76608a8e524e4\nbe715e9535d1ed5bd16a872b9ab09cf2a9d61b79\n0844a73141a4ba2ec2214d739440d1260f4bc37e\nb9665eeda6942a4ef5dead541eacaa046e24fd36\nc26370d003bd00cc77c42725e125ec0d8edc2f84\n2ffd1670a67d23158bac813118655a4253164cc0\n7f03346b72689e24f00edf884bc0c8bae4d4400f\nd435d8290d83ed605e433cf485584029ebae0501\n0912c3fa189fe14c5bef7a3ca7c58edf1f74fbbd\ncd3e60bfd6dfda3d5d419087bae01ed43ec1d4f9\nae3653c118f231706f590239f4810a5b92713779\nf0d33818fd16a0d4a5f431411af08fb7028aa91a\n3f5a08741079b2f44ec10ebff33d9ede07e93485\nf7d19d746e8e136a78aaf111fd9e731b0015bae7\nf72d5f21581a52ae1b6eb98f6a4e961de38c7771\n0cff949d76f32f6991ac2bf72ad019a3e0561f41\nb1254a665679c9dfaa9e4f1294d5adf5d1112e0b\n819de72c70c581820387faf558f6bfd6dd7ab4b9\nd03badcf3c9077e95ee08cd8aa318fb7eb42a85c\n6a4757ab927c6b9a7bd3c2edd1d0c7441fae13dc\n2bd85b20f0e72ec46353e970dcbd254fec69b4e0\n3a4eb31ecbecf8ccba7f2866cebe61138858ccec\nf0d86a741e0c1ecd9174c8d6116216102474cd80\n09f6f4988ab0df352421cd86af9149c535a84891\n509bf571b75bce94ebbd5c82e3dac82c008c615e\n68bd0b46d540bded4579195ececc44cb4031400e\neb5066cfd450be1acbcc0289b7120eada297b5a8\nc14aba6265cdc494566164e31f2d20ed024040a5\n5bba86b03e7dd652a0958aa584e0a7322483f3e1\n8bd48c96118acc2c206af9a445113a766f0c524f\n91edc16c91339d2e32b02d5042b1f45f34f9f175\nbef7a130e5d468153330bb2bb7490ca3f13dff35\na857974dbac9c8b5d15f603c52186312aa3db4dd\neb345f45860b4554e0012a9056aea6b0a6c3899e\n8a3710cc56310d0f52fcae6b7a2eb83b81317fec\n04cb67d8d0b2edd6e64db909ed772ce7c98034d9\n38947f9cd8a0710e7aa1b50a4b419df04c3275b7\na3c3ef753798e2bcd9bbfb30ed41c4bde1574bd1\n22f4aee3401814d733d1e46a0f7adef215ce1339\n3b5dc05d2f5969a5c5faac9283affb8317fb919a\ndeb903460adb53e7e4a7e390f32f2f8bf486489a\n69d95f05a95cedc3905593d2b819478b820b2b03\nab0514718c95270e4034a8502051f3e1b6134632\n453c61f2d82374a2405f6aecafb810322846bcd0\n3b94bc5c6064a033b75177398dc1395cbfc8fd8b\nc8edc617ea9fa5cc24c8dd5b1c5addf0ac5a5cbd\n6eb961674cd048abacfe5887e7661503ed2156d6\nb2480743f75ad232514bd18ef2b486d85f14bb9c\ne74ab565c999b1962c35d2f2a1ee4d2a0c413856\n767b2fb0a184b8f9528abafba3899183b9d2032b\n9e64dd02a65d825657afe9573af4396e57e7f131\n398c3ff75e15869fa5722a4c64b3e17b4cd318cb\n677e6811c190c83c3e7f0259186769ac9c15e4d3\nbe0bab874277de6a7b462e61a50f9b71d643b185\nc8c6b34eda1230e2a11973c05eee18957fcae172\nbb269a2c1d516b9615b78639c055bbbb59b9971c\n2872be36b209f836375595c035e22c22b25055ce\n0dd91666f59e66201b762dca78e153e90ceda3a2\n8f5b9b3da8f209108736d8394bd285785d5666bd\n490160e9d5d572989102163f37a967dd1a156c92\n83bb888641ff80a0dc6602533a0445b21094f4e6\n87fba5f9ab800ecd2544ea2b4b89917aa3df310c\nf8760f11f7d3a980dae73080eb5b6c6247d72d5e\n2ad49fc383173a071aa5bd66459db0e30274d7c0\nc271d146dcfcfed573868a00b2bea96aa5d372c9\nf684c9b5f6b078b02a32fb79cd357369773d054e\nc1d2ef190ea4fa4af67b9dbf7762b20193d00bce\n12705d1655ad66c2b6c6f14c6f5f7a34dcae929f\n5986f590cddb170716f8ce71aff12e36f1e8eeb6\nce1ecc5a548f7e510abf042d05f26817774ff534\n7b304dd1bbf1c96290a73f3d6176f46e4a997355\n4181b289b8c4cb97a2344fba1843139e579aefbf\n46574fe049d5962ef4502381e141c859da768756\nf44ba8504255cb836dc4099d5f6bd91a554c6fbe\na671afe409bd8263c1420e257be4371a0f7839fb\n8600498611daac07951532b561378b53bde89443\nd9d2c818eb88007184f8e04a423e0578ca05542a\na86662438366f42e826621508e652c9bbf495b7e\nd9c2b30e80847004e1b76cad41573698468344a6\n4a71ef21ac5711e33e254106e483097ec37bb9ef\n426aa9032838d8ae833402b1826251bcabe5660e\nf0c06f43c472ddc4b48202ac340a04c113e2b903\n7e7134ec28ceba3ca6884ba18333a414e1aa8e0c\n2d187f637133198a7c76a459f1f7de8df894167a\n0f13f8a60ba4ee3df93d0a9a2c8ca22fb8ae1b0c\n4e1940588f42020989fda3e41017ab76e162c935\na09d6dcc1b70446d33f47214d6b4786910657dfc\n1f7417428c7e188548e245741811b13d4a30bf6c\n01a378f7bbe7a331157f4e6ecec28ceda5468a87\nd8245a45f5570bc0d540c53d1fd703e1b4c85a57\nda88aa04c57b64fc5c8a31931746fa68b2ac4ac0\n9b2201a9c86c43ce32cda8a64479b42a0e488dcd\n90e4de3910192f75f20701da3b7c208bf425b7ba\n6b34748b6dbc3ed23f5cacff87e22aa81c203588\naae69b97cd2c54701bc5aa8c79e9084a1659d9af\na137b3398ade1220b05667de90dc60f9e34ac608\nae5fc6967c73219be4b9822c577eee24c9c75289\n6bdbd7ece17ea538b87d530aebc992ecec391950\n60204acd30ea354378405aca8c41e892e85ce440\n89a8774f678ca1ac422938b89d4a7ffce3bb81e3\nb7b603138b02f7be225031089bc81d7034127ed0\n79d825c1caf44b0077ddff8374383f516c9a546f\na0623fd42acdd4e4dfc151424762d2c5e5cbc0ba\n645505d0d8a78b6553b14e617b2202fcdd4e5219\n7e58741c2c797e636b667656bf01903a34fa9422\ndc455d89d88cbb946302f2fe7b01d3a63a756d4f\n43d7deb5776e00a1ed18db1717a71e08f7749470\n7535df26c1cf2ed0d16ff4cd3b979a1026d20c26\ne17e680c33bbf7c8edc85b282f8116443bfc5222\n49854018ca8b804491c397e5541438d91e8d87f5\n005102eb516ea773c622200e0e31c9bf74cbd745\nf243bf918f2792568194883aba4a92f2bb18ea0b\n5e9403a71554c44bd292cde760d5e0d0b5f00781\nd1d6468d4039208e7d38629fc6b00bf082231299\nb65a14fb394369529becab53de2ea7a5174088a2\n700a22345dae018fbe67c1aeadb0caa71595e14c\n847a9c6affda007a45f64a965872d14d1ffb3256\n74b79341a05b77ed4a4e592a0cb87cdfa920c35c\nbfdb1be066e0604df1dc8155b52c1b82110f074e\na96db9b3394a3d85e843650910f5674a568792c9\n0a20b39805dde1ba16c133de1d6d17cc51437bf4\nb322270c1953f3f32d4fc81b4de3d8ff7666df5d\naf517ccf4fc7c4295205154f9d0edc58ea5e82ed\n6eda6a5542aa7f0762ce7ab9c3bf7a49ae575816\n3988d5a441b063a2551cf90dbe460b0865f11123\n46aaceed2a7f255b6e1ba85ee73ab179de42c98c\ndaf68887916a5d7451cb03d39231a8d3b6f5b367\n278024ee300488dcbfec688fc950572df3859418\na8cb823140ead1c1f468b5b5841eff3fb1f94c09\n868a08d0c86376ac40750114e1760cba13176316\n942045f829c9bc3754d5915e8b4972f5cc144f5c\n1f5d7cb5e0b4f417bf7dae7bb8a438c408db725a\n0f32a9c7c2c8dc45b2d5414c37ed2684559be39f\n39b5dea3e80ff6376f4e873b362355114ee8dccc\n18f0ec3e26470a3ab4edf1ab0db947107184209b\n1bcb0b77d38d94e257e5496e662364dda4eecd97\n0d40ccfece3dc6ee02fd709a953b6c1045cd93a5\n7b752aa01fdda8cfdfcb9c1cbe8d1995d905fa45\ne75e726b3fa14da1dc2014ad089adc4ae892b66b\n03a65d3cd4a8f8f5bc9a9193236ca867942fae30\nd75147083ab635f32a7e5f93b634be835fa51d8c\n89db67082ff60ddb191ab3be867a74b9e7e90b91\n4583645e47fe935048b4b04683ca3c9b4e3151da\nabfab417d9f61481c85d58daf9b147520cf9c853\na737af73b62c18b3f2a2ce670f7dd28e43fe3f96\n89920af5aebdbbe86d3c77c52b10043dad5d008e\n232e8eb584b712923982369a5221f78437781f3a\n793dbe3ced6f14fadc7d62632591773e6d2f83fe\nbb5cdc1c479c0ece8e889582a3daf826c453b454\n607627394abb34f3bc3c5378dec445941efbb163\n1be4455edee1ec193a9a67eee9202d3737c39ac4\n5248835c349f35d3df941f193fa3398d9f9602d6\nc6a568f10227be6162ea11f263672f742897918c\ne4cbcec4b025f271224ab4dd3ffa080a3efca82b\n898635d2b3a86d2476ad5731e5812f4c3f629ee8\nbb7529ed8a10fd4de2dd75ef6eeff0d77f7fc116\n8d1c7f292ef193aefdc3c541343ee0289491992c\n397827b307f47a1fa99a2461a118eabbadc30659\n0f80b15fe0186f080cef33a5a5114488cde9fb14\nec806a6dc921bee53ed575e2c86b195cf11dde52\n2ba875b8344e5b663b9b03714080ab2e39f6db91\n115e0c54958c248aafd6c260d2bde8523fef028d\n699e3f7ba6b27638f430ba63592356028d3f6bed\nd2826ed204d98b6e303d12a30925e0c6fdcaa03c\nb9af368aec28b66255a0f0bdd0a7ef53b35f8a8a\n51b3f9fe23ea3bfba5d1200f90303259dd8fcbe1\n72c58ab2b04e45b40aab4d8f2d6fd9388f50e3f2\naad0a1d0dd2a62aa6f9afb9fae64aba9f2a0ec22\n1fd538ed5685d2a6b8c38ce144a243c2b011ff24\n07edb3d25d83fd3a0978cff4cdf4304885ed25bf\nf3ff775696979deeb182df6af8cf8228601873b4\naab5645d53d7eded4627ec9b4d24eec73a141d41\n991e951d6edf982bcbc26d819b433a86c5d87098\n03c5ae57381d56941cf45a5e17ba90d41a6e0a9f\n2f5e21643cdf3da538c315a7e324c85cf65b79e1\ne62ba5c4430b65e2b36c6923dc05ca179f9a5dfc\n971ab99493a89d1d0e18ecef44e7d943774d36b8\n0c50f5c966929f8945abcb88a9d476d9f70b9b21\na3af01dc03c6a6241d415c4b683b0f4eacc971a8\n1aa7c472d38c74e3244dcaccc40bc25b2a5016af\n910e985eeedc55afc640c2181dff0090f36b221e\n6c4386430bdf95067d2563cbe47b2f94a00d23bf\nb81e3237a19103544cf849303af14954816e3774\n12c3bf5b7f85cc0066c3ed0c2f38589973e90797\n55d61093bea79e0f642f144ae1ba5187bd4ac20d\nab4cf98240a9cfb09eb2422bc6a99d1fb861e363\n99d837f58be741222a15458590d34db30ae389f5\nfb1d623ea72c989f5a74a6937907e7e94ac92706\n16c07c52b918bf5b116c37cffc5372ee5ec9ca83\nb5afd89ac82fdfb57fc81263f38055e7328a1aa5\n406d861232463069900647fadf936e8495cae66a\nb9e1c3ab497590af5fe4f28614d483fdc36e967c\n53b0223950f6bf04acbc4ad1ed2ea43b5a6c8941\nfff22532004f02d2e4ea5d6785691f8975b5b839\n7f68548de367326193e17695474e4dc40de3b774\na2b6ac2272e8a05398be971c454b172033512f05\nbd2d159f87aabbad8dfd67acd589f24f01c1e5f0\n2aa9c4d5b997d6ea1ddca5e526858cbc4087007c\nddb0f54b9dd76fe0c02aef5d5e82dce156402b19\n214d42364578a71e008272f9a78888ffafad62b5\n7dbd2b8f131f3eba3ea10a220f56726a05224967\n34ffdfb3e2cdd2e1b500e7d517a597f9f11598ee\nf069b7c34cd26b802d405b0e1ca1edbba4c15a42\nc7aca7e84dd2957c7015df7feeb5cc5e3c20fe3e\nc11cdceb6b39f4fb54e7aef33a80b11bb3d16894\n9a2c04ba66f0d29e41464ac3cca74ff589a88c2a\nc700874bcda08b0671c6967eea7b57d8955c06e5\n95b457c914ebe35d2579cea928fc42042548ceec\n25a13843f1e1c64067dc9e4256c8c0b79616bb99\na52bed870aaccf545dd76aa95c942b34251dc2e0\n6ba05b3004c11f7b68fd09fbb7094fa3baec4450\nc028d8416334a1c916bddacbc8f40ba150c0f0cd\neacf5a328c19361600fad28831fa9692f7bd3c9c\nace2663597d23f5e76fcba1788816124cadcabfc\n4e2d79327afa084efd92c4557a862c924a418c8f\n24c563320b96af11a73faf41e87c255a79ed6a8f\n004782e3db524e431c4512a9b272706649b6d3c7\n50ece7af9666321672f00a8c62a319bc1761679d\n86230843e9f729793fce5c48e68558299170dabe\nabbc570f1a8b5619ccc4a9d1cbad730bac265cac\nb513ee7101d4d116857ded40f9c78db8ff79e504\n06a6aa81b44c31547e77f5a6fd2cf204d811b778\nf80c344a4e3297831093659676656f2b2f93c85b\n8ce020b6755d87bb9afbee0dd8e7c66f97a169a9\n697d079c6922ab18c47a2038f727d3b3ac86f36e\n50f498012660deff760d88afdd90e79cacded4b2\nfe1412c0988010d6c8ca00616d9ab69fa7062c98\n6f6dce2779ceca7175687c5570487dfd5a5b5d05\n44cca9fe79787c041dd5eb965f7b0ad0d53a8a49\n28551875c0c4fc5816dc39e88f2ce586c6779890\n17e3a8265c8c592efd5a02861837c12f1ea0b75a\nb6c3ebfb33b09f594734e7bcaf759f98155e126b\nab67b7bb4298907711850d60bf155a15e96f7383\n9902ea373ec63fe856817d2c2a5be19c39d465b2\ne32ac00d7ee9701ced8b3105bed471085227abba\n55b92e0cada9410bb86eb6197be2fac66bc979e8\n57c053663b53de81b275d164c9252c7a32a56474\n0515d3fb281998a976447cebe5248613c564a3db\ndd38b340507f3562c878823009b022bd0cb7cfc3\nc93b9acac8f8ee7447208d9c081439bf92bdde9d\n70bcbfab99dc3876b16d6cdaecb3e3f9ef2b7c60\nd156e3c8510e64dd3b1028f9d4becb5b38e31a0e\nfff2de72f2627cddc1f399625b71c742d26ac867\nb80d4bd6d1dcbdbce37610411db71e18b7a393eb\nfda8ab67e1615867a9ecd09bf627ff1a2ac130da\n45c2241cf068b3a38ca746d39426c9fdcaa3f87d\n758acf2d60f2748ef0fe1147fed094aa02d773ef\n8991929e98f8ab2c6c7e442b136bb3fd3722518d\n31a6ce8c16bd8d3d94d96b3c929242685b5c06ad\nba53c54a0782881242ebe00bcc54394347ddadce\n4516d75c44bfd5278d219472a009f0635de31077\n0fcbc14b83ab4c2b187115678dec2b82bbbc7c79\n193af69cf2f688fbe0ba32d25f50ce68712af032\n1fefeebb1d7f2fdc6e25945bf4c0bfaf8b859029\n95f175c3463a3b1790d62beaa5900e827d0fde4e\nc22eaa41ad8b30d4fbf256d1ed64223643f49000\nca9a95d8b4738d7837f2cb6ab6a5d6542334f2e6\ndc14de43ad25bf1832bbc75eb222e39d98d3ae7a\n3540ec44b2f17500b48f9b975121883ee6e024cc\n1216a8a54020c7db5f8c51e801485eab4a5a927d\n249a104a7bacbbfb2ea201629927ad6ed9e2f32e\n09c2932832acf1d100c180807642997178caf20d\n18c89d843ca5b70dcec29471474db890eb80e9e3\nb3a4a2b0937108b193bec8c2514f7d86bd1d62ea\n6159001453907575e7dcadd6b7268ac93f88387d\n4b8632451ce549fdcc35a15bf8c98ce8d8f806e1\n39ab82cedd23bea242f6324d7881e69c2d80149b\n01a16d43624a3f29f540f88e1abb06c7fe21b97f\n0c464f0dbb12463b1be61bcf3b890f082b55ae91\n9b965a50dca6a5223419fea9da3a1830cc02ce6e\n1fe13da2fa1aa7b96446e4f0a4a914002c8ab6f7\n821e1c9526843c8a2451f2fcb5d88120b1bbf0bd\na5ef564d719ed6fd1e788278d89e306df64d18a9\n2f3598da0b19b5244edc107a8a2c53e663108e5d\nab5e82f0147fb1446d6a91760cea05dcb59d7b2d\n88c75dcd6fe69272c2a1df23ce7be9e71a06d265\n2a911d105f24bc37275fae05de3c5f0e7b0b0a82\nb44fcff3954c0597c2248d0db8f8f590f8a4c388\ne9dea8dd63525beb125e504da0daa61f1c34918f\nb6417a70c880b0be20053517dd9399aa91758748\n2fb813b0430ffea33cbd8fcc6f971f5d9c1708e1\ne6fb042d671f30a17d329b7e4c87436800ea0c49\nfba7c7863e02ca3769f965a1499f651c3646c1d3\n1833da4dd6027d49f8cc957ba3deac71387efdc2\nd35e38435e83a4ffb214287ae130c04044b7154b\n8beec34cb8a5b21f7703578a034bfcea40f2c35b\n64d6b005191114bef65941e5473da47e07d1d398\n3808cde6bd7bbbe4c0e82f0c54eff92acd432619\n11b5f8995f79d27db710913ba1bae31a0964f417\n0dbab305d2951d78728e4adf6ec71ea732e6780f\nc89ea1517781b981605ef634ff6490e67506979b\n9ccacb5b3fc2cd6b3c4637de278e69c756726606\n1105cc004a3e4b4353e87ae97cb4620821bb2899\n428a47ca7ba06dc07ccddd3293d063c5c9832473\n0df72702fd4533ea6ebd29fab3475b7b62551755\n0a347ffeae6303e67c492a11aad16b20e2fbc846\n9d4034ac51ff0c8c502169c7bdcd2823565cad24\n86618c22edbcac054063dd304381ae8474895c5e\n16c3cf5adc935fb35a7aa17e9729910fcf92357e\n7d502b601a9e20a98ee9bd78bf1e08cef7277b83\nf0faa3ae7a498a737d7a40bf07778dfc155bdbd9\nb43e70c7db39c2cf17f90ad051ee66bd5c6e1d85\nd53f27df460b5a68dae5915e33e66f392e9a344f\n1372f468a919811ec7930b22c99fab37d70cc3d7\nc86fa3e3fa5b34c3adc7a634448e33fbda0f12b8\nf2e8a0f3f947cb5640b9707c7e128457dfd03486\n360d9b137df1aa30776c46230f2c7ec2766c96cb\n4a7ba0ce7c995c496038ca837abf3d5c10afae17\n0b0e5b7357ae31991d64292e451f94b842a535b8\n8e031b31157ea4fa64596eb990c6a96b05cc82ba\n7f7c48a962f0939ecd2edfee7dde97550f9fad8d\n2bbdaf4965a87a8bea66ff145c42ce87a7fbf366\nc5d0bbb569c7efe21049e5361689fb05f88210e0\nce333aac306d14686031b4ba09a4538c1f3283ea\n7e272f7e93b7d49364b5933a9297c897b4f870ea\n618971df98768efa25f26fcf536642f2ebfb79e0\n2baf69f928667c6af7bce96a39343f02b87614be\n1aad3457792cb037041a6c6c9b5cffa15778d8a5\n2e3d475433bdfb922fef405f9f1c6ba5b4d5c5af\nf4a93fdbb44ee8c5845f2003f24813c4c86d28f3\na1faa559860b69e2c0cd58093fcf9b40de5a0348\nb7cee055c2c24e3f8c7d59b0a0b42124020078d1\nb0ad065d7130bda2e362eade95c133806ccd6765\nd00552fc5a41a23dca95e9c62bc0a1ead1480580\n8d262fa0756bd84160bdb282c34addd886c070ea\nc4ffbcabf38ba2a6a1cff03744448bde39c2c93d\n4fe4e075c649a4bd4f5b0ec605d3b0acafbff515\n562c72b24f594c80dc17c8b0cfdb60a0fced4c78\nd269ada80f072b4ad12ceee7a2807f526ab963c0\nd3f2bd59c682127842a383456c42e3e48eb05db5\n1023cd9035227db54e8c155c8db5e4ca107ab4e8\nc94b2f7b382e61fec3289ed78202fa49ac8c9b9c\ncfc3c2d9e60f9d2683642277c6213b8fa7c7f354\n40d3b24401883050ccd1d8762dd547ee3b7518b9\n1de52d770d0b9364aaa8780590d2c056ac10402a\n489306f7abf83d87f02baeb69e6e9721b074bfa8\ndfc22f5c80712c7ab7d396a3dffa2a169f250918\nb96f39b6666e0fbb2880150a3e7c764896f06462\n616ae36c136fc329f93c11e7fbac91c5730a3251\nc61ab037741ccf4ea28baab533daaac0b747490e\ne76a8f3b9fa9f481bb78f4d87516ab3ef4f82eba\n951906690bbf9b8e7a3f5127349a5c84a4fdd114\nee923bedd44a863284b090e37b30f37bdf5bf9ab\nb7dd1710510cfe24f42da8ab4914035e174379cf\ne5531d6e7c1379858633d875c084f8463e32fc60\n7e0ef0a3e1c427b87b5f451e012d251cc0be35a3\n9a24b1db166e7e4e147e6a3c260dbf9d643b63e5\nba0bfe8ac6276321a1bc90f205e555ca340caf7d\n1e0416a9c46d1ef3ec1403bff3fe90bc79cb067f\na102a7970215c710de1b9c99303838c2348334cb\na9f45c89aa2ee6f0667422227f01c34f8c9f7486\n771c9620549a69fbf6a9a5ef7ccdc38e68afe15d\n0c8f22061852c99716e2eb41494fe86794319144\n39b94222388815636b521d21a2f08b77eff03136\nfee60001c62e8c648acf235922e3fb048a03fe79\n6e1b0624dd65b5e96baa3507a0d445a80a9f5a0f\n9f7f285425db12361d95eac01d6325da5b7c1c27\n52ad983c0c58566fbd1d6999b3f2a33fef4f76ee\na7ac649b207ea3c2b2d14b04e16698008e03f3c6\ndb86841649c616b635c3bca18da28c4f0db6d752\nd8f4457ba6c5c0ab6f824ddba42a61f0c9ac03d3\n2026ba6b151b5e515d65b0ddcd6686bd5ee5c70c\n066b5d8d4d63dc4577340e03d65868db5001716b\nd361734c74c965667e3fb0eebffc67d62a9f8020\n24625df22dba0b807c4ada02f7c516af2f1be87c\n8490aa52190839210a67cdc7c65989d3dfcd019c\n783e073881366bd6f360bc72b745e4250a158fd9\n408d7c86c55292a0fe0ab25b72e8758f2e28c219\n82fff67155d216ae4dbd2579a349a5cfb1853d9f\n6e21014db4762e915ad866f22572d856963cfe38\n8140353d0e74b40d261c63b61d694a44065bcee8\nad34de4b3bdebe0147f4960cb5e4cff2a8cbe3aa\n36d544deed2e82e479ed82b9cfa01c9674d55532\n4da16f9731d19d3f5ebb424bbe775c84df668f87\na98fd56d5f9ef744ead28aa3b8689a72dabfe7c8\ne2e70792b7668c1229bcf37c83b2d1f4b3fe27ff\nb6b9cf801bcf6e224027f7e4c59aa7aa2f3d9dc1\n3a7f208d0ed41d9a6310014780fdd6c45036035c\nfc50206974914a14101bf7749286cccadbebdb3b\n470f26379964f8a1d8d38aa130eb012bba05aa6a\ne73760a04d4c7499e44c4baa7a863925973e100f\n9a73bf20c1b1a74ac575c8dfb54eba0a5d1564da\nf805a6ac3e64f8b822f147c34d751e7dfbef9519\nc3d2dcfcfbf76ee90124f731e201c071464ee47e\n6c74c4ac5dd74981df79c26cc9d6526a32ca55ff\nc804ddf668b101930b8a01216b4c9695e4d8e5a2\n0aa290d33030d6256b65fce74c728e24e850db87\n788fe4c5ce9bb5c07cb6c475475d37adac40a0f3\nee41b9e01fd8e7d7bb33d051569f58eb3ce2de09\ne266e533a879c0871f8f6f6835f30729fe69c0b5\n8bde12452a13abd0cb56a02c9e33b3d4761cf3d1\nd6d14bcf0bfb968c1c23a4bdfab6372deadc0982\n3b98ff72575ae25267797a16c4f04c4ea8e135fb\nb2c1fc8ea20bfe36a844d667ad29eac409a61077\n7622b32bfb000a6fb8e15b3e4fd8a93357c2a308\n0227a67bf1f983d16b1be924aaaebd586744c769\n83ea78bc976a72d475bcc8f74417eed45a8ef6bf\n7722d8e807054646c7e07e284dd2f852d91667df\n93ef11dd5445c63199c7462b28af5b5fba53132c\ne6e3ff7d6d48132714cfb2ade928e8baaf138303\nc556e31e9dbc0661f8f708a9c70f6e1ba4b9e70d\n3722af86f67dfc4053fcf8f4f557f17a5babaf8a\n1aa4309a37e381d19e008f7060254148c7faaa1b\nbe839910b9ea57dfd574e4a315c147110f582ee8\nce19d662cfe4271923efcf145b0a1b5ec8e12875\nb44c103727d89818fd6cbba1da37eaa8789fdd9c\n322f43f02e2e654ffb6cf3e1cb9453bf716efc2a\n91a895f5078cc3a4c302703961022abb5fdf1413\nad6e8bb21f60b53c0997714b9cf39dda9d9b2d34\n33a1d2ef95d4773c3a3b6c71d05accfbbf241557\n75de28bcea77de89ce199a4c86d143e44cc087e6\ned2ae845bdb53291f896be0b2f0b084cee0c6bfd\ndbcf98e79896149c473b35891d8d961f483df48b\n7daebffaa8cb23ef3f460d485d1dc2fe32039d89\nca4148aa7b0f80db7014614e86b4709d0a1889df\ncab376096fd25350738f7ea44888f2a1f2fd2a2b\n0494aeae2edccdc5561ccefc038d44127d70a31e\n47239ecd29e84ca927bd9b69672ec7d5067d3e18\n381cdf5381bcd70a661e43ba0fd79d59fd027983\n3100678ce59f658036dfb6c3415f391c40af4eac\nde47770458f83a006a5c89add8add7bc813bc80c\n96e9d4d075a344b3d000852bde5deefca2f9e9f1\nc892a846e9456dc84f78f4ef74dc0299da25b276\n8d978de300385829f8571e3b676c824d9ddc3344\n1b0b2b42d18944c21e6b0bef8ea0b94574041a3e\ne64fd17d5b90af429de938b5d76d454ed3148009\nad550056a2eb8529603167f124939dac09cacea2\ndebbdf4fd19815a9212bcf02d5eec5a0eea4eb12\n1ad1f5576d81dba714d1b0667a4c91f70a042991\n365d5dd97a07ec6818f41b24be759357c4ed94b6\n48e2f39c2e343b7b98f17a5b47115370dd8c78da\n7f65d049d7203bce263778a51bd059ecf634bd6b\n70d44cd7046592e025ff778bfb5b8e36cb80b8c4\n1f2f63acabc31cdb8f54a2b3f125e6fe7bf971ab\n82cbf410ede32c4956d855972c51ee5704da296d\nc398561d3b0ca4a2acd06f1b8cf93371071729c4\neb38d97bc9076a8416fe3a6ed3b87d094147e633\nea3386ebe9143d1c6d150983a1d0a723b7cb7b2e\n1881400fbdcdfe41d95db93f3be6fee3a5f1dddd\n1a0dc7395b65e328bafb8ed51999aaaa16de63e4\n19162648224d0d061754a4ae8a63c9f421e44887\n5b773b3dea43707f6123454c4dc2696161f084d5\n8cfcd2dc0a5d14ac5d7483a50e50f5c14d4442c0\n71271edfc136c9ce588cfaaac2269bfe3cf0e78c\na1a1f4e60f497dde923c1a2b21acf20b494cdd2b\ne64e5a6e717580763df0a2843c769cf38a448ab0\n4e3b2a5892906b6bec410e8b5c001196eb0a043d\nd836254195e6bb1c3c102947d2b1cc32a278c29a\n9808442b74870bde495f105645b7005a47a4fff7\n14a613711a7cf37565933fcb3aeb15053afa4a6d\n5afafbccf9c622c9ddb37fb7d7530d12464e70a2\ne7ef1870e5733b925c3eaeaa82fbbff316085479\nfded3e25eb2a52ed6433fd80d331fa360db6881c\n4614c7fc6c9e4c1f392061e930e3c3b42309a89a\n8a2707ffd6ab062f73a2e0cffefa93f5234d96a5\n889b0c2d03cbf0bbd0d0460475a8134d210b6312\n73a7f1fbb65464effc91970ab4a6a6259cf4ad54\n9b994c7c8fb20ac824b021ddab93443a6fce762c\nef44248b97545ee8442cbab42de9033ce6dd68f5\n43fe555ce1af42ac9e617b66c88a61eef8a6022c\n520f6879ccef0bd248cfecb2926a1a1dde5d78a0\n9cc18155796176928e5c91e39040e34081ac3b37\n1a4727f18b067325c4dad23459f85f87821762b3\n15e736ca711890fa42a96bfe261fefa2a573a2bb\nfd4f32103caa53863dbc6c74025d80dad75370c8\n5374bae60b9cbdb036054b63635ccf7dd001417f\n7c1df781c679840db041013c9faea4ebc4f52ddc\n55ab99227803bdcb354e38bf62b6addeafa0e573\n99eb57cd6b37d04a5912bac7250539bbbdd6c88e\nc4e1445c119cd40a2225a5d866e44548033c4f45\nd26d0b275a8d53e2d402a0fc73e2bb5f0525bb3d\ne991d3f9f80a6f203da118e5ba9b5515bb8fe63c\neb711dfc073d86fffbcc5968a248b7a7c95f21b1\n76bcc396c8b1cd2535f972c79743d9d3ce21c025\n44cba6558c9724f887ab86b794fc9bd4de23da16\n415e2ece0d52d4529ffd203697df18f6f3279cfc\n3ab27c0e8fff35eb03940350acbb45bf5029c703\n0e6282665f9e63bf1b716cf438143a5103c6a478\n027fad418e9819bfd3384d090e24a3f18febd938\n8a93e4d02abc01bf9e57ebd0ed617215adf0274c\n8e16f164b019137ea83c8254dcdc5ef2410fe049\n494579d9e391a6c7cad2c1214206c526ee8d1b6c\nc42d5408546b779f73f5f455b9dc2fc7e2374dad\n4d0cc094caedb6606e3f6f0fa570e331f361afc4\n87b6e4078ef27c41965f343e0fecc4889dd74863\na153b1ade12a17f6821acac01e5d4cbc58c33875\nfc3ce3e2e2777d7a8d0f960db23c1b1eef355102\nb3fc5430c02c211ce7c329dfca45fea603c90e67\n4a7e952a469b59676cf6ad04383a7672ffa36730\ncb1fe190a8ed44cd0f1ee020f664d2ec97ce8fec\n1c73f878fb317972156e9cf6e4bddf75e2a2666d\neac2604079b1aa281d8a6b795c1d1c948bac1494\naa71b92bc7b364a085d12ebdee3fab228d727ab0\n6eca6bd0349dffe3e01d785745b7721b3f0fe24e\n05158d7823da76413a066cbb60765efd5be64fcc\ne923f30e011f297c46877783d650d59180fbf610\n2e7587b84a8405138f8223132dedbd004cd7d16e\n0b51f3bc31351b06bb983718b7e182d865c75222\ne4b3f63af427e1d61b9ab92abb5c87bbfb7c8844\nefeb52b18b7d1e4a85dac5dc7e3f359f3e654eae\nd15fb148e6177fd63e4b7e355a5dbec364b60761\ne01f59f46dcdbadb3180b2002a6fbf9796453a0b\n5b4839162a427db6983876e6246a191f37236754\n01d97b92c10ec737c72ffc465c3fa1cda93112b6\n9f093757c79482af6a333b1a9f0dcd06854efc19\nd6a00ddfd6c48b1348f35f837db1916217991733\n7140e9e5bc7c6dbb7ed09fc15d803a57303312d9\n4363f93535dbbecfe065be6e9a9c256f3211607a\n5833a2f9bf0e01a11bc9fbc285e995603b8573a3\ne28a09a3547e6a4bc50b1c89f8540d98a30a6bdd\nafcc119b7a84e5f45049799054541e1891964847\ndfc9bd9c40717bd4d731ad0d77df45dd6c6f6df9\n0490b17eaf3a67addcb0d763b8d34596e9ca229a\n85808e0933c83f21299d858b4b84fb328c91993e\n741f9765a4264c18a8b45b698580ea15e415e0f8\n3633f079d6ebad5cd3649da48ea486acb5f6f646\n4837593729f27a8c4d9b2561f2cd3612b22d8e28\n164d97cfbe13edf511b97b297d8618563f5d64a0\n506670400fddc14359bbb3115e60a33b9ddcbe8e\na4cc3d30bc7c7666461f3d7db6ced21cffc36227\n84deab4296b9debe7a60c061cf6247f068ed6ba7\n1ea4fdba4ab3f8409dfe98a75f08be61140df4d1\ne6159549b5f95ad08cf4884175e0dac31808f56e\n621fca850da430eccbbbbbae920f38ccaeb5e40a\n05ab7505875e734d545bfdff5c3a453a7eb7888d\nce342945317222a00c0d400eff387a4621e01b87\nbce30cf594834cc6bef11496e0d8ec62a2d441cb\n79927a6001dddacb2ceb2f212b95bca1925af70d\neafed53b5c79f2f5494b32e407a1fecfa77e37e7\n1af7fd6d9c7e68d7d4d2da4a76b484eb6832889c\n10d91bb0c36e8a5c99d1959512e5f053cc12058d\n1ef2fb48aa1db89232fd12c4d23e4c99b15dfeff\n44fc03b2f10d1d9d7e8242c965a957b3b0d42865\nf21783da33009f4b5fae8c14bcfe33d4b1466f67\n7ba4daaf42a280df6c4154ff7b1d6f066c2b6726\nc505780a935f446e6ea7638c87f5a7f013cdbf04\n90667d3925165991286338172d828d400e136a7a\n1d381c4fae9345aa0037f38f1f3fb323c45116cf\n95bfc0c523aa0a5ed6d1383d5c60c062cc81870f\nd7c18cffdb34f3a403de8da3aa50bab64d00ae8c\nb570332e277673839e616104c72c5e91f7f3fcad\n8c204764da051b6c6b948179f0f3b14196d99e85\nd8c0033bdb352cc6cdca78cd3992dbae75b98fd7\nc0232438beedd0db1c58378538f4e2a79a7362ee\nfe4a976e119d0e96138af135c5219c54a18f99f6\nc6878c0ca8f8f67e61054665e34f1c7e78bf10bd\n0947b919511b63f890115333162cd155c9bcaa50\n3534cc6bebe0a3ff3b662e74b5c9f455b90a0980\n4f48317b056d8658cb49642ddd9e7f9846f2415c\nd8d5f77238d370eafc48674c5ba7d00b0f210650\n7aee355fe5586e077e7fa5b2dc359a8eb98cb1f6\n6ef195f48d14a2d7a8705c4b361872c8d554c8a7\n6028c5cefaf88cd9f833d002cb2182d71d5d8c57\n0145c55d40b51f6792e82dc9887cf238aafdc169\n61a3214aae1bb366a4e5e8301e1b0fa3c7bcc779\n5cb4cb2f13320da6e7e4e1684e1e4e7cf151bfe8\nc6e225720be209def50a28aa5a2e529f20a6be13\n001cd260813534b08f7745d9aba98da73f2288cf\n0fc03a913bdad2fecdd8f9dc5a7c647fdc2870d6\n434d6fd19e0f16016c51e0b54a6bd8d0bae6b0da\n22d85d66352652e3eefa3aeb1a975d5b5f294d76\nac73dba06d24f07f7af5721a61c9f259d5913e56\ncefd1c3ac711571b8c5f10899c78b80948db10d0\nf3b8eaa6ae9a3a8215e227d74506482c1253127f\n51806c3791fb891fc439afdbf58ac6e0fea4c480\n5abd75c676eeb2aa2089f48444ea30bb4b776530\n468e888e93039fa94ecfc22fd7636bda664e08ad\ndf6956c8f850ffb7b25dc0e8c0b6a79d7ea61855\n90b8b888b1c2fa17c18829bb33024d1e1795e204\n815cb3ec6675cd9e852d62cd1fce4611952d85ae\nf9ec4fa4a5002911849731cbac9f437dbd72627a\n9d294d7ffa66c8682d7b70e07e36fa0edb085ef2\n371972567faa5d05087721d3287d0d05d26e9a3a\nebb2010d5a0c266434010bbedec825a2f60f521d\n8437cee03790a5a2799fb2c5da721fad9bd72eec\n474f0a401e7fec4752998d563e4e6f41c15a9c37\na17a7dde07d912f722b56f026c17c36deb9c99f1\n33c552ed411c12d167fe4c34855df6b0a09a8c2b\nd8081b28ffad022d45193f703ecb60c0298ab7ab\n4baa5ff5712123e9859e98940ac8d708cda7c407\ne21108dd95f2f186db1e99b683e2d67e334221ef\n4858acf6cb98e97a506edb8d2c70a094e053eebb\nf464a7c58770a2b05e9c9282bef997140e704763\ne25bfd29cc92d5bc94734950e4dcfd6bc8d041be\n73e587c935ffb26e3f8fecf8fc759af7e7d48a7f\n35ce35dd8599fe02278de0ac9aed98bb4eb2e321\na9afabfa302582bb274592061ad2880a652a5800\nedfd9531399003312068de8e3c61d02c849376f1\n594b5a2cac9c03380eabf3ba6b2675f2f3364c47\n6c9323063b13121be5b33ae9a5dbcf3af7ee0226\n700382b8fd6e54295b2273e9159ad9ef15d3c61c\n98e3b80bfd3b69d56d8f05fe4b94677c7cf9dbf1\n26032a58c30dddc27adb0c023aa8ddb6512563a4\n4e688c7a64b41db6f42f69d5cdd5ca1be8000af7\n0e56a15db534fe6c4e2270c00b0aff6d513fdd1e\n676283b1551434c2c577ef49ed4cec0100e0e633\n7173c5e7046ac79a6ff169a77e358069a219720e\nfd61256ea97c4338f571e373d78111660eca9f7f\nc8a53fb06960581a758e41e755fc8e58eb909b23\n469e9a637adc2815cd0e5fb52abefa413e920c66\n70dfa04679d05c7af82bd55c986197603a81fe5b\n121bd0157d9c99600d63b5bc90f05e93504069b4\nad3a8d626eda89db6538ec126be1ad26cff8552e\n8789832f791cae553f22f5cfe5c67edfef6f3ce5\n162ce25e7e9007e3c7a6135fd1f49404dd6d4d86\n90fb6deec5135d52acaf81e718613e8b17c5ff02\n0af3c924b9d51689c710485b7a319a365e1f6fcb\n6e3d989e0e0ee9e4a05d182fb44c348a54ad7f74\n534b6c8f0f6ca1ff912fa5819e1952652b14fa45\nfead33718b0b923a5d5f30165a88862c2e25d0de\n45b60eac96a5dc31279748042c702ae552a43594\nc9946251aaee27d260cf4c572dbe796216d77861\n1429fc2c2dfbfe7d05e3670dc42411fe08006c23\n72a7fb285f973caede4eb825f7fa4dc6df261fc8\nde41b6789588b2ab853cce85f8cf64fb71cf1e19\n03f62ffe01559c8cf10b9feaccce375aa3d25b4e\nc2b8a732276b2a4b6ad6a199ac4815a96d8437cf\ne6246b42c27ffc10181f0c23e1f38b248d7b030c\n16302c15b784e4dab22af0f52c415385eaea9f62\ned262735a7eb59b7b94e20b48697979b8a05a2a4\n432f457b8cb163a0acde3cbe525ac66ac5751444\n1f6e9a22590b7dee1a3048609b1618ca9d7e12a0\n5f8948e810708f8a6bf90a80cc0861cd23b4c918\nc7e8491d70068c66f96db1bad3059601f53ea4a1\n69e2d8e72c9860180aed92cb13c37dd2ac3e0790\n9da09078de773c0cb2adb7341f239e9fa3cf2f0c\nd6a6f50d43d61e9ceb45d09d743cb4d243d4e0af\n8f5931bcb36211fe2ebbf84c1694fe7ccc04380c\n3a08481fc907bd53f97cd4e11936c7bfb3b5ca82\n53c454cc39aa836165def8f11f7e66aa3764c2de\nb015e3d9e761bbd05c6c5d4788280382ba1261ef\n3bc0e22599ae451c3499552ac28ba46199e49320\n4a3ceb2fb1d4b6ac32404bfe85dc8a3accd7e08a\n3d8e040b12bfd88b4f08fc796286670039326145\nb80c5dae3adf8b372ad888569912315f8fedab8a\n9d12b8c1644140b589b87c2ff397c89c9e08bc96\na350325def03488404b3461a53ce63f60ffd68b7\n2d98aea0236edf8d2f8c51c4a9f3c0de7ead64ad\n12a91462a922ef76e3ce3b33a640c83a3fc22792\nd988742e0d6f70859e97b6e5563e6687843f0c06\n9c683fd0c31e249c31420430c9a61e78c694c045\n1e04f6620cfff57ca4aec0f0267eb12fa30990e8\n5cd832c42f1de901c68e1c9e50ba8dd3ab0cae65\n1c0b4135bc426587481ec7219771e0585ac19b4b\n7a2363528d91b0c106212f0ff10fdc8530caa083\nb36452d4e06cc5649d9b2a419be923a3bc9ae171\nd2fe1fa0c33d04a48602ed808a31081d2c287b8e\n21ab34f3195479430cd9db83c907ced68ad8e71e\nc6d0e19fe8628f0263d5aea4a227fdc002443d5a\n93ca9d678ca9526960cb75b6aa39f4844dc5803b\n59c310f5df3b8755d05d87a59dc7b7e9b79f1b22\n6f78482db02fc1314558315d6bd23a236d9c3bd6\nfce6436892adbd31a2219c3a63eb53bb7e658438\na5e33b170fe572c39af4176912f5f979bc975989\nc697e6b4a0239b19707bd95198a57f16889dfa29\n9b60112d6b9d7817377c65b348f66f0773e84579\n76791b39d4e02780e6da235d4f8f906ff78c57c2\nba9f4b455d01d8db15fbf730be9f0ff778108436\n19c2cb10afc6d0214a1fe9d7a83a99666bbd6996\nddba374f88f2500dc79f3d26ea20ac5d535b818e\n3763b1e7d1b7082c650b60ed435a6681726dce5e\n0b20a2a0306f8fc73e5bb2d9df993d9508bb64a8\n0c1012df467319a6836bdcbfb11341de9c58ba1c\nd5349dc1ff980368599d45a2757bc2613d096316\n79bc7076f611c0ab577970985c36d515304445a2\n60232ddf21ebca5f8a2beec70a4812840a736673\nd65f5f4e1f0c0b121366ce15a5ca0313e971d6e8\n3a14994cbd3e1dd98862000c24008f006cd6f13b\n7c2446a3e48a8d1434ee17529cbdf10473fe6f2f\n02188ea452d35e8b95cb0388b5954a630b13b68e\n798ee7209faccca30ee0be9e5ca9fb93bd363397\n020cd5c89551690247195edaeff6814b52266b73\n5d2329ee45d36ca70e1acfc29349e5f809620f97\n7b00e8c240227361659a2ce1e53e8ba9e08be530\nd4bd523de78855fa35cb8f111aeb02ede30c3c4d\n03fac99f6336e1fcfc18352fa1565bfdebfa8f4e\ne7562f07994a69dc7886fda3ce079f969e618df7\n5764d1411956592adcc631e31b02db63d2e6a9b8\nef32fcaa34e0a1c0cf9550027e27f1820c5391dc\n170ba2a20d8b0ff707e4f31b0451ad866a4e7391\nd1f66b4b39172733e458ace8aaf84a432eb1ce01\n9e216ca5a7ca856d60c1307ba5b57ec0a3f5bf1c\n87b1f83b380a95353a7c525896ed05796727467f\n99c369fa46e13ff67c6d8c25fd379cd6e7f3573d\nf97c45ed7104ab9e2541b87cf405f169c4ca607c\n5fd5d09870add06d77055fa99e6dc30cef42065b\nd5d74fdb5b065a5392910e9709da48e8bb2e5ef1\n64bd7e6b39767edbc97a14d1908e2a5cc2db5b65\n9ef9649c85b71243fe2b20ca943f88a3fbb4e4f0\n8daf5be1d6547131018dbc38c14ba31738d42d4e\n36dc9803c9b26602515a7a77e5a814109db7e41b\n3c47225a899e8c82ce1ec79a12bc62f9fd1b5d47\n9077e0904c63b923678bac6b3867d10c456b98dc\n7db7757d98707eda9cec0a08a87247c143fc726b\n1ab25035f50b5cea4c0bcdd63cd1589ce71302d2\n7c6a62f70ec4834d27e80e6ffdce5c041f0e7b6d\n4d3cec9bc81060f6fc6011395c3ba8d076da0c86\n9a7d4edb4b04fd890e4d65be6cd11e6eb9e9aeb2\nffc0e6e55c394359ea8563b2d185041e730324e2\n914cd694863f2476eb736b837ce2c81a3a7a9952\n7f05e26dd4a9f2c96fa253c85f98d28f32e05544\n1112cfd69997ad5f73d3a149bfa22714aa0386d6\n64c92ceff8ff32f7cd0c6597a1140732854894b5\n33d1576c7d36fd3e633c0f001f9cdd6c52c49f30\n15647cc41c5ad81943d2063826b64c94d9ca9b58\n9eeac85188e9c6b44184dac1afab5fa503e3db3d\nd4c04fe1e7a3734e904260451d9835e914199ae6\nbf1f4e44cd21d0b99a7a73c3e0fb9808074fbfab\n7bb2180cdcd1ccd1dc9607303d7809ae3d7cc282\neddeb4f8e23648aa5fc069e42d1e61ffec3d5fd3\n5a50fef2cef2b258634dc0c0272d1b219c514a3f\n8f96f6608efe0cdfc1f98a24c5f97c1d5af0fc06\n8a78b7a09d844d1f8901094d80895fc5cc307e75\n558ed7ff00ba2c76e78c407cf6976a1b7538d483\n76e8b8a50ebc64e5c6cbe7fa120b8961ec3dba78\n7801316a68ad7870a13419bf78eb6f8d82dca8d5\n31e082d31bef2dcaffdf4f3eb051fc986f8b78a0\n4c6032c4596cf60aeece527cf10223e2ee0122f9\n77b2a3bf9e050c2a1325df22b304876d34911c18\nf8a523890e821572416eba724f9346bc7bf6b4b7\n31e7375a9171c0985a8c3ceab3d5a5a659df0f23\n7b3d7bafa3da450e4ddeb71dede3006a4a276228\n974f5213d71a3de4fecba90b2477f48df61af81e\n5037f906bc4c9f13923abd816258a80c18f03cec\n92959ccab7bc2a8d611fbae3046ac5158857dcdf\na395915ad551be91867931c959e778c8229fe37d\n450d4521634bad6640fb59598cd7dfb6977e3aae\nceac303152a6514cf3d28722ecd645414894cfa9\n73b2a7077af40ce15d5135edc854322e3a67770b\n1c086af911a5ffc435af102d613fe2ccab7ae4f0\n721021eefb2173a2a7f3eaf0650d64773aa58d88\nffe4ace64ce65186a09897fe00574613645b96d4\n5082f72c60027a69a38f6c3fbdb838ab914f9bca\n493fdd8f0b10862283aeae68f1909b6272443e33\n0675b2e46e450f286a04d69e95979a858dfdac6e\nce533eea42fef76cac7f2071df513a39fcc93081\n46d447969dee7275188ede719f52200361b4afbf\n4ecdf792f6fd4f1ef986eab1d67399aa2c5e211e\n30138a522a4f83a63ec7b85f7131a506f3fcd0b7\nf3f6151d750281d160929e5d7a3324723bac4f1c\nd1cce7e7d80a91efe0aad41975f23558a70d3ed3\nf323d233dffc5dd6db9dec0154af7d942a299f5a\nea01176dd7ebf0c62b4f06eebdb238ece907d336\nbe3fac0dffa502e82c5641dfd9e3bfe06afb41f9\ndb5f897622e3980c71182a0b0936c1d5f29472e7\nc7f4ddc26f3116d4efc7a1635fe36525fe64846c\n62606482352a6fda62183a9ff2bacf98d4d7be15\n9ad44af2f4966babe63c74d0431d7d06fdadcc9c\n3cf1c33764508e0796d5bde8c0e5ef5c45d08cda\n48a3690a95e34499b9466957dd26ff37c6190fe8\n0a7d33b92d63d803b9f406ece9388cb30e725682\nc63eba1184c813b634a389c7a3dc5f3e6bb7c93b\nfdcf8459c2e0d07fd9d49382e600c6c8d8498ecb\na47afeff4aea717430319c5ec80a55da8ba50bf0\n873c042af71e9bfc8409dc2b7900ab0f36ea1ab6\nb00acf82f3f50cd9b096215875bbde65baa40b88\n477aad5a8fbc7cc9f5d65a94b564a274edb513b4\nd97713c9ea01cf49c504cc77206ffda1085d9f0c\n8b02263baa003b207e7bc568e4f31669c751ba2f\n16ced1ff2a7dbdc3f75e5be9d5ef254e9055f2c5\n145e3ee6d187d9f7344d04674d8069a0d67b2d8c\nc4a0ac4e6b5199b4056c4e8d1bd86c233f4a8946\n94010c4372fccbf8020370ce6cb6eea9acd5f68c\n7d716540b37452ebc64067b2946c2ef4169ce729\n539bc392983cbc1f30dd1c7e713e45764901307c\n4ef3f556d6b2090b6878845830a19c8aa0b925cf\n3193d610fb046ae74021a5350fc7aef8760ebe9c\n728ca3f608326e09238cafbad860c35b748a323c\nb7a069f00f8c442e41d1936fd359b7f17dd04ceb\n97aea7bf11c2d50995501b1681faa54d6f467948\n26a942f21238f9661b6a1b58e00d3055eee6c0b8\n68f14c87a53a2ff67d708a76e7f2eff3f3745541\n0816b9d48614b6e14027fe5a09ae60de180f8223\n12ac8bb3a992c74aa6f6a0aaead0b911056a6da9\nddb79c613a10b4fb4efae208549e7478e895e0b4\n31c4d2aa756f8bc6301dad790a5038792e0b1b19\nb5df874b5d077c2c2739c451dd6ce148434012ed\n13fa55892cc093e64d966dfb1cedf10616a0d321\n694c300460a74e3d5f5c78b675961db7bfc58215\n735f83329bc469016408bcea597f6bdcfa688ac9\n8fef584b85bcd79b51ba5aa3a12ca31951d2f0e3\nbceb1d24a4e80d0b03e041f63bc5799effa60a84\n688f83f4f776fcacc220347dcd386700c1a43fe0\nd99448407c70ee3efff77a4b1ea11146a975aa78\n340585d7d6c0af3fc707c2a333feb11461b61a56\nc8dea9e9b6e8d7b4a880ab74262717005951ded6\n3b08326ecf6af0182375aa7b1c1fc525ec2d0a90\na88ce83d7cd92e363dca2af9a2129fc47b446f4d\neea89b25d66c98c1e3b111c4f109aa9097be371a\nb7d5b8393f683b0f44d3398a6362f068010c5e64\n693822597d5705a5ce8aba52474a560a6f3d0bf9\ne895ca652959213e086829bddff5ff09129481bd\n273b80248473ba54dfe623fc1f38783c6d0aa263\na571fe02f58e01d7b4f71f76fe16df28ec08bd0a\nbef62daf64d2264d7a03ba02a857dc1941e90e0a\n0c00641a0e38833eb23f4b38d13e296c2afe4394\ne2e9c7379d98bac3c1acac83664e4d1110a1c6b3\n642c94f447f0e1837f1d7ab32fae950b689d735b\nbe2a15df2921d246d04063dc07b285986d8819fb\nccf1c7de95c54fc1d50685ad37707c635b63afa8\n6e532fb6366c98675b9b84de070b4c69b0c92162\n1e14ab7d632fb581112f56583fe41ed0920991f5\nba7406c842dc66fe6285d9ec468af79a0783d6ac\ne266be1f290994b1a4b3b22de636b9e5a20a2558\n10a88a6c42e894a956e4f69d2bd3cf7e583b2b77\n3d96c2ea425477821e8622b52dba8b39d9decbd4\n1a0ec2f9bc5d0b680f69f47c33d5f8e3b117b363\nd5db0bc884bfb3370f4e985543588a588889d239\n09e52e11d40cd87b3fb65471cbe6d9b4b0c1de15\n22f965da3a09b5f278e7e00cab9f64f1f283dd95\n4ce03d913d63673a8a0c6d643c6adec9cb4464bf\n7777a738e66c51068eb6bffa112011dbb76c8863\nbf2893b64e246b8cadf639cd7c17484ee317117a\n9aacb068b115442d66d627b1051fb1fb0a9b4f92\nfb08573a6d83d36496e0effbe9477a8aa5a989d2\n0fc36681468fb2bb452ca2931c55495f23ae8919\n4d6998fef273c828d430ec1f1c44f34445dc2aa9\n7269a4dea39ca2dd5ed62e7298bf03fb0972ad1b\nbc3380cd74761d36c024d621d18d3d624e1ecf35\n143817afdd34b2f876d8e2d9f9b10471833b7948\n3c572cf4a3f3d6ad5e25d3c467a81f7865ddb03e\n38a11ff50d2d7232727ca77ac287d700349693ae\na4e74252f10620a9bac8e4684b4acc0a1f4072f6\ne6ffeb701fe5a810c1a217c9cf9ce0ab2c985ef6\n53f11a463585016e1a71f446863b2aa1a45131bb\n0dd97b22f60f70f0b0273aaf0c8ed7dadae9239c\nf9e443b0b5cdab8eb1d57a0b89bdfbd890557e6b\n5e9cec5ae0f981f9cc0035463bed0297180c9396\ne20b56789a10a5bb69b4979104fd3e210ea9b73d\nfdf7b78d6378cca89c937af14d9e7f7b7127c4f3\n1bad059ca75a4af3665bc78eaf855d174e0578bd\n1c33f9aedee2ec835829842041bf158c747305b2\nf44026495cb39893d1aa3691079c63668713d811\n07c045220c8295e1948292a99ccebc3a0ddacde5\ndca095807b68278f283d838e45ec5577d966d37f\n3a9f45d1d7d08aa3b21d599cdb1c56a52172951b\n19a4ec2c389ecb507a128d74d71621327fa5e3ab\n7fac6ef4738a568509d8d1ae0cdb149b9b37f587\nb80d22bfb8f801c72cf9e0a8db9ce68fdd07645b\n1f9ee4fc3b874292a3e9835ae4aca61d1d82aadb\n5db8975202ea5ee902a610de905143cf530e6bdc\nfe34a463d165263d955ec1a604e3ba7ec24c463d\nf3c0cb90c95dd569628245a80d1396578cbdbbae\nfa5c8d497e97a5d9cecfb2b0f10eb4584ed95bcd\n2f8b085e0788bb552e77bd9b30c012caa6b06d6f\n24958ad27162805b90c600e0701614e573bc12b1\n419921612477fe8716895019550ab1000e20858d\n082cec48ba5123c3907990122c1f3d82dc783b6e\n93ab86088b9a3277ea4804487f0503dd57da803e\n8deea693b26551d223b422a0e45dd1aa874d2361\nb723ef45285132782c5eb4fc8180965075ef086b\nff087c6230d66248d06f2ba0a1b380bc5a67f0eb\nfdc8e855ecb9722408e9f0886b237fb29e9e9f03\n0fbb56df8eec4b3f3f5411e488926ce6af0289ac\na818dde6ca5a996f86d55a676a7a4c813da7b3c5\n457b0eec50a1616bc09e7222c78c5fbc8c9184b0\nd88db3f362697c1bc60731f57c527d4f12534ad8\n9642980865c35c73d34a5778ca38c60fa387dbde\n2ac3702e2e22d7a0044fc27c147e25969437d934\n85503fdbc2c25d4ff6ccde5dd5f91b8bd607effa\n7ea0156ebc5968ecfcd8404065adddab49e896ef\nfba3107c50c55ddd769a77b3ae2b8b236ee964b5\n132140232192f0c601328c7a44229e300de093ba\nccbbb163a58f0615d86381b8e5bdeebe9bc2eeba\na718f0e729d30cb20a4da077c8751ab04fb38e69\nddf4dfae4e259f07a32a262c293e3ce8d245c32d\n367436b69dc098914aba847fa0d4cb546bd68f78\n74825828b3b624bca22540955d532a1de80a26fe\n4928cbb746df1801c2c4894023148b0640f0acca\nf05dbe8d58bf49f3c0393e44a057472edd7056a1\n6a0af3f529808f38cf55398d2290fde0ed6d415d\na916200799a2cd8808e50559826a62a6422def7c\n42b2b47c821ef25e6ba328e5c8d653e4600e4d29\nfdda3481c0a94e254474554b003d6effbedf29e6\n43343d814eb5ef893bccb305d3265655c2c55d74\n93692fa84b6d3d3dd402649c9f0dbbb3af89a834\n4fa9c3bdf662026385191d1176b251d01e475be1\n77542a254338b16adff801547470e7d31336fb20\ncf821facb4c31e2c4effbc920dec22868dde8ba7\n6ec75a23fd871cfd7a3c29f9da26d31ec43ed3d6\n3e8f8ec18ca817ffbad3d1a48fcc0b0be2be0ab7\nfc878129c5e3a8d7fb249a0a8633df3e4367e03f\n91a7a77522a5463fe5583ec9ec032d7f29ab8c26\nfadf7bfa72a17b4ef6cd811eab5548e568c1d3c4\n4f4acc1f1d124b6d66764ace553ade19e2a9056f\ndcf55f6e87598dcd2fc5ee70be797f24b1c7fcc3\n0daafca5dfb11843d1631f1e34395e553340a29f\nbc96822e0094d2ffb7ba79fa828aa06958f80ef9\n7d7799865f31cb27b34043325128c5592f5b8d7e\n20fffec7d015a83fa88857e60070e50ad3fb457c\n968f6ce676fc1f27fb4398adf6e700622eabc034\nc34a7bb75ecec662b3543044b5e0393b610ffad1\n1b9610ec2c1bdc39edd3ff0d1edee575640f6bd7\n54dd34450f883838cdd51b2dae47e0baa0e7a04f\n9bea8e57b43f908f7a7e95862e183dd41c83fbc0\nf3f324ed5620944f05df7074c006369194486398\n00f8bb92b8c2566acf698f42a4f422e7d3a9b00f\n1e681b88ce60bb179e5733acee98572c8890a24f\n4345725c685ae2d78b9c9dd46cb7a3c80c2dec82\nf83b88aa7f1f0bd02e09dce0f838cb8a9e986c9f\nef05944d8fdfa5de1abe4592a728c8e02cbb4975\n69d5aac2354bb37ce4617a9ee84909474e70691b\n79421514bb9b8bb92f8f03309af07b83b5b98004\nd60e03e3157bbf27c10b36f510f5fa467e5cd5ef\nbefc9819d00457bc3c97b1cde5608d8c2c7e1b16\n88e4db3000bb1848cb15a7065b0132620bba4192\n5b6369d809871e5be413dc403277eff8ce882551\nc12147656a103c5b6f128fe58137e10ba1323567\n49ca696deff2385511e274f4395ec581943a6617\n3cee3681857313bd0045105a659fcb8dfc204d0b\n9c22dd85eb7b46669da4443ad512c466cfe30cb1\n45dc28fc92b76e940ee84f8242c4ff54cec90068\n6e94cfffa59f48a4bdb804a92e903c169c864b2a\n5ab5ac57d4b9b7be822012a00579e170d09064d5\nc9f8b7b5994444cf60e33ccd98cea39da15a2c8f\n2d53151d5733c5f582fe60581fa521edd1da1c73\nb7d64b587def00f38efd0c3fc258816171865202\n9031400654c3501086ee2a67d21529866e1ac06c\n9019bb1678a4d66e8331a54edfeb777c2c79067b\n90e5fac7b838cabb7106c262bb760024745debde\n47aa9cf2448a841d1807be0265774dfbcf1bf274\n4661f8d2e94497564ad9f88630aca71b2cbc924e\ncb0f070a801bee3655a6ac39a336fa99bb222632\n18675c5ba481768d886b2885a9d8764e9637deb9\n6c2bda19d0c5e220d6dcd0bb9137831e4837178e\n9498a328b1588dda82a3ae6a2dd311e0fb6c8265\nf5ccb6737f4aa7e7fb3c0cf6eb36585ee6cf3666\n75f42fd916365f83c0a1e7d2fa82ba6153f76b40\n92f0c9592b8cb6d8e1e42faee38103d937810eba\nc5b3980218e0904cb5e6affc0fc21f6333dd410d\nf9b0cef10d8109c2e4185be0d024f11584e0ea44\ne705124a76193b86bed33b005c509d697a920b11\n6f2973835c8df3831e923017b29fb6b5f09c3952\n305e83df67aeb42492f47959a55ec5ae39c3b68c\n57cca963dd4889f7ee6d12f705cfcd8c52b5dd3e\nf8b5b12140b7acc62e188ca55b421c249c1e7686\n7b422fedbe1807a7c672e5b87513b00f7ee4a1e5\nce336229c525b26308ac42ef5191099d5cd4f13d\ne7859062e03f324a852ca043029e0c9470ba8e79\naeefa161177724e9a2d3fb2b78c812ea3ec27474\n046ea952d16078400ca76681f77b8247082cbee6\n9cba9ed05c437f5db2f0324c9936a4b50d8f29f2\nb2e0cb5c3273786f642bef1211064474458cf818\nb4f0394dc71587a9cd6d5d46284f0cb36052ffb1\nd0d9d0165040114d3dd20d9927a6d14baf21460a\n57103c1a18c0c5b11336bbe5be0beae7192e0a4e\naf2a85a880d5d6a18e4bcc1cfa70a74a0dec0aa5\n3cc69347731517f9e6f3d2ebf1a9796890175d56\nf6b5874e5ccc2d765f20c5d19887e9457dff9724\ne4f9af0cde21ca17c62717cecdf1726f17266761\n12c2957e8d0e6ff7e844d7170291aff04269fc31\n2eee5cd484b521308852578b9733aed446c39d3f\n34caa5da281dc5d53337f8cb6f6d161412a191b2\n758c1fb460e933dafa10e6a11bb58f7ccf33bc44\n5c4ad4b716b69deebac1035e725e7a2ba1f70a77\n4ff0f33e0d39a9ad22e7236911d1faf0e81a3fc5\n3fb5c155fca9fb77e694f56bcd16573c4e554ec1\n1fab609f0db9be5b17e4714beb6e081c2d9fc1c7\n7768c82a70fe0b46d037834eca43c39862473cc2\nc2af4d5b065fa23128e4b1456656698125ff5874\n27594fbf45dbe332cac84290c07e5f09c3ac3eca\n79e307a0ccbb87be0a2b775d6ca25c0d0c4e7457\n09817031d9b1284c7a817632f8651418d8b2d8da\nff05799a187830b67f595b1793db1123c8757667\nbadaf4c3a8d2223ccd0e5df38fe9ee6cc360e1d0\n94e7c6221c739b679fb265414aa00aa1a02c5701\n490b807a28422fd79dfb8fe8e53750300e5d24fc\naa96500fe24ee551ed44c92b5e3037500155aaa4\n3680cd7c6a9b7136969d882312f40ef50938a574\n32f643a00211b6d58284a543dbd6ef0c7c6ca7d9\n9c7ce26814af0e75ad6a1077f862e285958bae0a\ndd15076bb284978b3cdcca39b2d38a889f733f06\n1aa3b787b782ddfe07c33816576adc75df41a339\ndb055b14a4e6fe7e52860bf8a4e14cc366ac9eee\ncd4f6d82e461e09374e4e0bb5ddde6d83f420f5c\na7aa50ca71d4cf247c0970c2eea92be636e12120\n7755b26cb14867ee442dd22b92a18404956cca60\n27799e409c5b1ca667d30625ecafd12c000b2bb7\n99856fca9347da643a6e8183403004587a7e2b68\n130aaf84e9d5bd31f499c046438e9cbc1ed5d70a\n619e59fcfd91f9357640708a7a25866c32d23fef\n4b1fa3cd2f0f194b57ed4f1f5e47fe9308c1019b\nb792d79b009c3515265081568a9ca55e442face9\n86c2013e154b12646a1befb5bdf1cd1f6e450991\n34d02d43224fcfd52745d8c8d1527d1d57fdb3f1\na6200c90d9701c71dd411f9e3d1449e20d7d1ae7\n7514fb6004a8918791c8ddf9db96b67d1c3dbd97\n00931763c77f3d2533df702a48e0a02103ceec46\n8c3695d43108418d4c42708eb55720f94f27cd0d\n4677de148c8d6e2f36208ca468138969ef094993\n4ea92dd12e7843bfea51d25ced3c4819010778cc\na3ae1a1db08e4af85135eaa5f9a158d19a672f72\n50b7c3c48ba5c039481c038bdf09bf9855501949\n46b1419f7dd09b153736d553628bb72a630d13b9\n7bee9e1f8eb639413a4627a27eff0aa93c07f557\n2edf4976d08097d7326ea777f2bc3b2e39e322d7\na9be67e65039f61e0d7568741f36eb26d0fb1fae\na0bcb4d4c94c912e5f9a058032bea833474bebdf\nc9ac88fedeb6165bc3cd73a15cc6d61714a8862c\nd4d51e620f9484d6afd5294e2f30ec83db81bf61\n46746ccbc13f6cacb67f269ca10c95555fb3a986\ndaae124c87dcbebbb93f3d314bdc75da682fa2cf\nef89139e42f7df28aecaebb7d4bd20cb2a129504\n54dd0bb6e94d02bbd106f4c1f00dbcbd48cd82c3\n8a6d6bc6c689e286abc70d0647b6da1640c7e6ea\n619d2fd382c462af343f04fdd0f3b07c42aa1683\n23d651f8675567f327ff34a7aee9b60102428d3e\nab801084312094a0943838eb14ce4cf0820a79f5\nf4b37057c7cc0f8f9e6dffb3e0b703fb70be24c0\nc871c091f0f20cf8ccae146a58a6bcd6a0bcb912\n9907adda5e656bfb4a14bf5caca8dd5142c82e29\n7e56d92ef22fe00898756e26cd3b1809f3ee1d05\n9fccf7ac80be49d7e313bed6faf0836974c11585\n769419dc8c2c29b93c0688bc7dbcdaffc8a9ee99\n58d5ee000fc2271eb2c44166802cb70de347f709\n8f91f03341eef613b6b92c53fb5823aa3b8fafbc\n5eed56a41b327befaa211009ade4baeaad3613da\nde75997d9dffcbbda14330a6f2a1ca0f69392b0b\na6a3a1e9437988908baed2a26864693a8aa37bc6\n1de38d5118923a80a67df792497d895a60b7e2b5\n5c10b89e10a934539e86804a74b2af7a8417a50d\n319c414647e3c38f0c2f9e20495dd0f0ad636570\n5376ae50a7e51a2f5b4d5642f9325186156dfd65\n6afae0c856f0b9619a8d9f2c1a53160578a608e1\n5c6fb7300dceb9b8e59b4e3a74388fe1ba8d0fc6\n2f6dd5eec89e3846a6afaa6edccda4cc57da1029\na244b8d544ab89bbdd9e1c82554ede52f7948dbe\na4578f89d9a1fa3498edff46d436ad7046904121\n34526ead32fced8a71699afe61daae23cc54590d\n98b706ebe85074c763d3f71aff1ceb51ebf0eef8\n176674bfbbf7601d86f858cafe2ba33cd71e10e6\nc13ab060e9ea1d3578ad89dc1152f06e98e6bbdf\n298577ca71f02c9bec10f641e44b8e3d6b6daf62\n3242739148312c19c09e11f4c8fec39bb60c982d\n0584e7e3640f09412ba126f763e1ffcc980607f4\n167e7c73a6f53819b7b7b3ce335910969e758d2c\n7c3007c392c775bb4ee11c1cc06c59a82e8979fd\ncb4a17b641521d4513d5d01ac12eb57102f6ead2\nb35a5ff4bce48825173a425b6f421644f80040fe\n190b88f4eac4da5d3545dac42b3e8e91cfd69d9d\n21e687c54173dfd860ce7e657a09df07c1b9eb89\nd4016063bea3707964b52936b52097ea362c58b5\n65867adb3aa809c556bd7f18d668615a8a255da4\n78c2cc78ad65fbd988a7764e300a8bf7be1f6c4d\n731bde225a132aee40354827e2f5d8916bc53714\n6d31c77028c9331eaaeaa82d3961efc3e341287a\n472b2f7d5c4ae55c9dd1e5c8c7845973f333c6d0\n71ee6716c4516d69e5563115a2ca2391ba4bd16a\nac52916615873da3020715338d5fc38cfb0473a8\n725296cc9b877894cbd36559df7e97f6ce25c0e0\nc037bcfcf4ea7fa2b103c43ffe6b7ce58d8c8209\n700af594b3b00b5df1f17d0828cd6fdb1a871ad7\naf5fa30d071dda7359bb37d64f0512f3c3dbd4d7\n5337b4e8e141643d5c9efb7b0588383f9535ff12\nf8723a4b3cf7068c81beb1ee0a11162bdb633cae\n1615defbf8803eebb534fbf6a178f428fb108e37\n3c47a48189a4bd4f4266f6f719befbd6baa625d7\n23eef59b8cc09ed3cbf5c649d47e263cda74e588\n012d23d8437d2c20a6d7a6af8fc0afca0e9f26bd\n09f995f9e637e76729dc3f8ab16a32a896f73213\n892c0923ce1282b2bd74d530ab4a5003fc6ecca1\n5d9b797648effb6a90d8762e727db704224cdc85\n616f1e913adac2916bc9dd5d5fe5588e7c0ae3f9\nc5a0c3817b72a7485d33f8ad310fefa5c8d61e5b\n8184bc9ce1c8e5a1f28abc00c94344306a43744d\nec90cbde2f7b5892aa17d4a8b27c45adbbf36e5f\n0e2280d0b396e8d49bb3e2200bc8743a27c6610d\n89ca06d5b8200de44f096ae95fd2c1fd47e82000\n0905e9492ba7a6c537e20a9a1d937b4170484d84\ndf4e283166c55a2da7898a06d7e6ad1a1af62c58\ne13bda5cc73bc996439a74fd6c16a62da518f510\n93f78627527b4b1903ecf74f0f0bf8f5d093fafc\nda18e2ed0dd0889871d5160cb8f5a73b9f346e3e\n8d7c647a184332b30a1486956c7d64c3f6d17af0\n4ae6d51318e2a97a305eaf9a138ee3f14b7be7bc\n8fd1e33be51e7dbb90169e3b1e5d664e7099c930\n90c10de56e77afe5295e3629cdf2029760c0df8c\nf7f702cc234ba471c1cbb254c62c79921b45987d\n6f2381d3952ced20f13959b4c02a04f371c1fd91\ne73c75687b95daf35b9e9807cd579cc9ec3d6bc3\nef9613f605b57cbcd66834a382fd77b8ef281e3b\nd0eca285581ed864534a8c8b8440b77afe08dc78\n0a96c7d8218ee350ce6d1cae369efdbb7f068ddf\nec53ffd9f1ba6028002f0114664af3e282119e71\n4d18f70aa33ef6f89f0baa31c99db278465ad06d\n3856c33e1ed140cb4d60644dadf7b4fbc9666cd5\n31a72adf515cfda50e327dc71c232e3a3ed39255\nc3cc68b6cff3f084a306e9d63c58deb660d8f6c3\n07f8da0ddf6011780e0da41f0ad7df53597bc1fd\n409368322e7bd4c981e85b92f803ed55100d1dd0\n62fe3d9f04aa71244b9bfb5bbe933c2f3b64d829\ncf1b7e35661e146dd39253897fb0b30b2884cfef\n6ab60cd1fc8af1ccc58608503930848f548814a4\n260ccb638028f590968a05fdf6812f5f94171ab0\n0ad9b2e7122d0c8c2a4d103f672e7f79bd638d5e\nef2b03b7f53d331f9330f682c93e54b2e75c7c39\n4270978b4ee1b104809a8c5b8c9f5a6fcd5a22cf\na0b75dc853fe1c62b93b16e0cc5964db6b257f8e\n49084e728b488d521aa26c9b17672fd24896f225\n0d64f42697b7db64a56688d9aa2c76cd4ca4edf3\n3e75b8df92c4c31f815cfdf0ce36cab8fd9985ad\nc784a12c2aff216781994a0ab6e8187c45fb7b43\nf4efdacf6c43934c95911dc0b70bb62897c0c6ae\ne59112f27d669be3898c569af62b7baa164acefa\na1eab7b57154adb3fd07caf36bca64d77428d956\nfcfd4f9a3d9d12ca8dbe4d5ceffa85e79a11d76e\n492e71d9770607d62f26e546fa6bb4b0bbceaed2\na234b98b11a6297e810d69948afe163fcacfd242\n5942160b84b5dacf423a3bef956f2ddc08e44c3d\na0be561f58c9b70ab699f1cc826860343f70e501\ne30c979807481f779787034a4ec5016277241cda\nfec4b4c7aefce7d5ded28abbbc230e0f13dbdf18\n4aba070c5641a3529b459c333a711121b11990e4\n35f085615cf9ed65aec23f9a697ddc5d2aaa0c1a\n6891581e64c01b3f6155a7a56928e78de5289dd0\n17b3f00a3c26f69d6ec7c41620cec955380d307b\n2f05a125b3e1ef69b5a7bd25ee74dac3161d4804\nc6d069253778b073beb9e9b27a096decb5559db3\n89b79698627893c076ac73affee1ac77c1b47a05\n1f31feb7d919a33ad8ed35d3c186c3c138ad2a9d\n85e4b6b3c346a6d27aaf1d3dfbc323d59193b2a4\n1ec660a0317f0e64ed108e3b95efb573ea6d97d6\nf7cc2e3d70ce824873802efbb87952ae7c0066c2\n547481af315db739890f3623741d133e7e15fdb1\nd1fe9bb716b35a7beff7775437dd52562d3bec06\n5a5848826d7c2f23995e6206d1a220cb079b6d47\n6125fef5d9f8b8bbea07249784485b68ca7249b8\n66fda4f1a70ccf40a2c8a2ffff1cd1d35dfdbd33\ndf527395c2aa20ec1e54a3df05c04af325cd5209\n729eb75054b5a11da5f516c10ee9be4637ed1bef\nc05e73a89ce3342913d4d88f779c548e490b5525\n710dc2970d0b8533320c17145b56294087c3ad0d\nfb0397ea36efa15a804d806517c1412e76788ae0\na3b9a483340dc6af66d8d4e2762818b7f9615e44\n2fede6566243795109d3ccab98728732f9ae9375\nf54a250685e316e1a4efe6bb76848496a7798ddb\n1411e3afe69ef210ecdf0b78071b5324cba0cc65\ncaa37bd4cff66cae06ddb7accd434c95b28a93c0\n64af37abac292d640e794cb8dcd39f9bccfe2440\n97ada7d222b3b255625be4d76126f46faf89898b\nda358ad3139b6e5cbd94f4532ca075d29edd7801\n75644d7e1e89317319cae476e3cffe470c9494c5\ne9e4bc2701f431e650c8236bfb6b4c85892fafef\n5898f33d4f752a7143a5e06d6bb4e12326d17a35\n24e529505c0f83c0f19649c07c7cb0bd96ff320e\nf0f9706fbb619f1d41582ab3163b2922224c44fc\n5379b9f9e49903e50fb68cc8036b83920f517266\n733d295e9feb74bef12f357e406b41736d55edb3\n1d3e81d85c78a85dc5d57953b9f049fdaa687e86\na7e843a87c001e7bc84452e797bc2310fbcbf3b0\na6c51045cc06e2d675d33c903cec7525e1fcd621\n45c585aaeffc4c83e94fd90df645d9a11cd89876\n946544e2d1dac1204605428b71a8e0e2b2022fc8\n26d0408e6794b146226a02ff98136a5fb48c06dc\nde12d6ac68322c36c63db075fde560648acc5101\nc37cc2acabafe388eed86b7082abdcd6d6c7eb05\ne20a490bc7bad63131d6800b759d9f714c105391\nd99fc0c124fd13c1f6594f75cd8d43ce56005d17\n7ec7120d548a68b2651a2b60e102dc4f8a52277e\n465cc692e016ac0ae255e0d7bdec18cc2c60add7\n641c15db957c0e08cfe5f5bdda42a4573def41ae\na60fe1b363d453e4f00d81ced170e7024f51e61c\ncb2b5000defaf28708d6f657ec337409a3447c56\n9f60df6d2b3faa4ad4482ef1a04a2780367550b5\n06a90464fa46b9bc3c5f28f24d15ef47ddd0486a\nb5bd5429c8c5119c1b4f8c4d196ea18324633546\nf07819439d9dd146d6765323116dd78cdd24b83f\n7718319d17b9f545352428208a44b99eda9ad1aa\n77e6ee424f06fc832e58728e3766e2f494ffeb03\na849c456c1ca0b16051d0cb8c40123b6ca124632\n953345683062d6e9552d53fcd93c25f1c9586a58\ne23a1866e12512cc69ad85101f088ab72b4ea18a\n27d3e126a807367e47ce806f37fa4bafae9186df\n5be0a388f7791149ff25431d8f641b447ed0852f\n43cbced7d2f5d3a994f98b6cddcf4d6983dfbae8\nd5d212f69e3bf23332ea72492cb89e296730cf4c\n5ccc07477f3fd779f26950773510913b956eb120\n53f0166c4644dffdc3340b5fa020a92803ca6710\n940f0cd80934f4cb83194b0215a4a25091e860cc\n521f298d22ab0b263840dbcbf4f0e68224c3a9b1\nc275f83d36f02d1bc3e48e77fc010cbb5fb32e12\nbe6a73c6234e2c59e8bc019c4664c3b0371f10be\n31ddbe27c71a9281850dd85cce7c436f6c16a624\n7d0906cce28f5f355d28f2c66f179f611dcc722f\nbb90b103801bc94294a6c83b8079833a2a5ece40\nb9e176d95cf28eccda998aac0259081f2a6c50e8\ne25a43fa285ee19f83a57cca15c2a8b9fc21923c\n9ac5e0e4d7bca1d7e6c2c09ced6819820bc76e65\n9b507c39bca912e4891032bada2555300a59892c\n0a740f5e34e6ed8e63296eb245f8f9f8c5c9d033\n915203d20edea94b0808c278c564a800377f221a\n4891afdd0930656cfc98da9b642ed0bd51c86399\nbafa9153ebc18f3d7cefdcc4707d711ac5e740f5\n940814c7aef66db225a4f0a618588b33ef6a44d9\n2458d9cfbb7782461d15d95909aaf69790868489\n55c7d24c3a626f0d0154a635a77958e5eeea406f\n319b83c3562bb7ae20a58b39f1dce86af8dd4b57\n3f616b2734148bedf649b3d3910f9498b7bd9387\n3854b9ae9aa99f8c892637c4f43a3738baea84ab\n3bbe982a5ff0a20917fce5e73d448a96f8b16fb3\naac69bbee0010c1fe9a3ada0fb1ecfebb56cfd42\na74289ec2b4368f93448fc1278fb4f6d05b001d6\nc964838c734fded243a57d1b6a684f63145c7111\nc9651cf80be647fef7f22bb1f254ade81e11e93a\ne9de06ad71624d81e37be8086effb68103c11444\n68115bb857f5faab910a9d3e36dd4a8ca9115ac2\n99f1c9ae93915959141649ecb8e7c76d5a25b01a\n18b92a733918acd15cb00f9dc3db77cba378fc49\n90811cee3c4136942a97ae319e489b2924f98c90\nf230876d47807e77cdce45879d98f7650f36e35f\n84240d0eec78774892537d325bb00eacb612c609\naf968cb0cd3b351f006cb71f9de61a14b4d898f3\n9a33819fd088f32879f1959526583c698af942aa\n521ae7e565f83f4c8831f1c097023f52e638679d\necc489281c3327ebc72660ee2a74119c4147a986\n3aeb3a170c9f75d97d70df3d88ff02e0498a5e6e\n182a4c22e9bee71a8845b490b7cbc21bb97b6839\n3e27f3f625257526bf17ffe13b34730cca278ef2\n7afa84a3c202e1b8c1b3ff22d98d4d762a4028f5\n4162175edc04568320da33edf577e52510a7af7c\ndc3ae5d0890d4e7b28e9ded5a4f39426790c3752\n85b32234ea749a6dbd2b84bbaae4176f67aa98e1\n93e906a930bdc3f0aa769fea72390f81b82d0d97\nfea0090f2ee76b01c92f22f6e5cd927f5d58263a\n134c6059f011295bb7993b62cafad9fe0874bb6a\na22a2508a0dfcb3fe5a1d449a130dc82222d2d45\n7c767e5144eaa16b373f976d3a3d0d9d9b3cd91a\nb12a728773bdcacc4b19c2e132c92b54187516d1\na992bacc163bba4c9f1c3f04bf43feb41c5ca517\nad0a53012fca13096b4b14e1a065171e025123ef\n7ea883e88cf5e3fae6a2e7658c3b8fbc837f3e9e\n45ac480f0af51ad9ef6b0856087ac83d1558f0f1\n5b1a16fb18d5e838c36395328b10f5754d7b1e3a\n5f83e11e8a2939986c420e362ecc984054650bad\n53fd83370222e5eb8d12799d6697434f7f765261\n4a7c9b3dfeed2c77c41d45ea78f9c27ad05b1439\n491761e2532a99bee0b9061e8d7e235a7ba0d1a3\nb76b0a21ad4d512b489ce62e917020d3fd435a5b\n5cc114dd8978659c7f647b36d2fee0ff3a58355e\n01d8b9a5c78b78cbe7495d3c62e45f047f468dc4\na06cbbb3cf1df8244e6c452eaa1e3797becdacea\n7f268a3d8660d5dc6c6c081b4c8f02d343e1282f\n722156a1e6d2c50c819147393c4e3aabcffc6632\n2bfa50cda993e4d972e57778c788b74ee2d983c9\nd71720d14731c75c4644e6c2930759e1be418384\n34131c5a380152f49cf985d47a8232701a145f80\n3a5c63a878b3c5bc3e2f9cc88c868ed236516c83\nbcf402936b8c67402913444783f829dbc3b2f6d0\n0866d180f7186ee6cee552f52fe044c0e0a3ac82\n9686ead00964a7f4b2b0c713fd410326912ba428\n2eb0a24e23402fdf54cad0f7926e35114836cfe6\na889ecfd7d3ef7f0b8384919d688dbd95ffb87f7\n3cb885bfbb050e7ba66a8c213bbeb245c41fcd8d\n31d342fdbe645de3626dc4a5a1b5cf996c318ca0\nb5e1df23314ed8d6a2986aaa7ca94f497933158f\n8fb887a20989a2e86c07fb1bc87d22a213ee0d42\ndddfb5f80ec9d4ec6c9995b4039fb2d5f6b05fc6\nf866c64698491654119288b3b3a88beb09505d11\na3f604347e501e2f2c6e62a3e0b39777a36010fa\n931c322c9284018055b1ec133ea6428e36a2f4b2\n4c5e6a14e77b535ad35c4576b2dfd7b3ac2a30f4\n2302f7e62032c2284a51f9bdbe6835a9e047ffa1\n8297779e407a021860989f99730dab7d802c59db\n165ac6e13862067a6248a3e20c67aed2081d7a18\n377485a1817f7c54cfd3991da60112a28b02d50f\ne2e1ae1ce6f7b0555224ec2ba35b38a856eeccde\n9314640abeca77d1ca36a0acc63334b05d45e21c\n37f592af748d31357af78b4880a0eb6b38c7e054\n208420772eb10e12bd7142f2f344f762e738b232\ndd9f9fddf725de40aac6c55ecf24f1cbbabbbb94\nf09c4e4c70058c98b2d581cafd17d36e0d3f4263\n07f55073ced3c118270548147b194a6db803e224\na8e8d88a54b70845af9a021d9d36c62c53a0a270\n5e5ad74ebe4ec193540eb786a6ecd973109c13c2\n8c291c8fe9e1eeb9b2fb7b45e2b05dfbe60f42bf\nd0adffbb318bc5b0156dbcc241c18de77d6c2e8b\n361255aacb2031f96651b99f8f390cf74d01c81b\nf71da70ec1876c64212261263a8494d3e5e1e6d6\nd2511241ec97f43d332db438bc88175da95f3dde\nc19aba1ca843dc1fe78882c47f9ce1e9c12e0497\na0199aace264ab605608453f38b7640d85e359a1\nf2658cbc407d9ab47e34ca9997987db1422f7c60\n2193b3cd544e473064a9b3a0c3a702ebeb276560\neae19152530e61b9b10f58d32e277ec2b4f7d223\nf9ddfd84a0246733214e88c2b76e245960cbe1c4\n4ec3c4d91c8e52055e25b10b2111c7a5a8eac628\ne1415f757c0b6384f7b8e5f5cfb1afd861f930f8\nc8dab76fd5f4cc17dfccd4d1cf976ab6b784f234\n668afbe3fe9b1640c1a915acf6edc34b79b606f4\nc1463aa6a94dc4b34da6ac5f9d77da4746ebc98b\nb024091bfd5c1301498a4e63525dae3cb80b223f\n619e6ce9439e642479e5b6727bb9770ec300df2e\nb244d0e73babb521a82ebca40feb1093a9d88393\nd31032a287e96a770787b76eb5f74cdbe896646a\n4d1f6f3845595ffa4e3bb23983254f0d6db1a1ea\ncb3e39a6f5461a5bf2b94382d5280d50d3bcdb3b\n9923b7f890537c4344742a4dadbac41aee97275e\nb05e57e9bfdc34fe76ac48e5c76389a28b701f55\n021981f4cc19f2444bfafd303e6428a2c87fe546\nedeffcd3724631d94bc4e99308442193fc719d7e\n828bd766d4e391cc979f8ceda7eb1386c90010db\n4226f8bc134fb5224f74a956246dde2c724009ed\n813cfbd66b491f2070057b18b188bfd2f2755f36\n466dd0cd6db68d40ae3767d876d14b8a79f8f1c1\nfe5bcb0e7c96560119b04d814dbfb8bbbc763b6f\neb0ab61faf19e3d63873c5b4fbaf2b94fabaa6e3\nbca27880e21176e70370923e3ab15bea2e4055c3\n4dbf9fe250ee709e3dd838b22354e0cc6ff5dbc2\n29eaf4784e6155108ddd97c863d9fd2190e82f61\n8016b551460b293887f7ce4eee770738461f6ea0\n9c5a0644b355d58250b1963b6806926ce70256f2\n002a3e6bf08be2b33d7fe81a63d4acf93f2d05f2\n8284f1b171fd525059378c7c33d99660111c0de7\n3f60626f496c1e7c03bb72ff3420b71d3f7ab4e3\n219c828c16e0080c802f8058b493fd9a93a0c9e7\n332d0946c6b0889e0e57783176708a096134c5fc\ndd216eddb680c48f316ba09ccdd830b0c4513b9a\n898e6f93b9bed809a30230f220654defeaefac6e\ne57b3c76a7dc6bdc7b766655694b0bc2bd0951eb\n9a7154ec329e52a68a59ca277b65dd7b81444c0c\n6f54152171720c4452ad783c047463f9a1b14a05\n25be0f11ab3e368d3066389cde1644cfa46433d6\n4e6e5513a244d6338563d91c583170f5312b232f\n2022500f1710befbe8aac4d4ffee7dee2fa2b3b7\nc859e3e011177fef3d9e6dbfd5213c143bd19b67\ne646ea46b0f4b7a7ad0d2cdff7284af138837264\nfc97ad6599c096db79743e6e00807a0ea33fae12\nab08727651976b0396677b225243a194dd7ce28c\n10a556c0eccc1758127cc26831c35c21024beae6\n5977bde89e9ef8ff02355069ff6099b3c6ecaefe\n2b1aa1a9bf648e342b793a95c34b8d48965fdc39\n5717979494f126da993dc5d960c6e9470b8ecf5b\n9089884006cf92b235a924c03f6274e6cd6e512f\n3d435f31a79a49619624b9a135b24c0ad68c5dfd\nd00e96037380a1fde96d7172ecb895128b825ea2\nf0e01b912e1952b7b0dd17bf4011eac4ae27ab4b\nce4d11ddea558fab668cabf319c2f21fc7bf154e\ne2d871e6f87a27a6d8dbcc2e5b63cb80ba3edb1e\n9f0d27b2d4979a399eff084ffb4525a81185a9ea\n07625c555770ab4ece646124b4c353f9f7ea2241\n9df2905ee3374d4df47b0af9f6553d429e67ad6b\ne6f9e1eebe32d177017f48fb8393b56e07a2f73e\n170f4bf8e51dc086e74f28eb47149fc40bcb1298\n7e53ce8f3bbd0bae4481cb060b292aff7c12eae8\nfc98a4b8958b9e8b488ba8b17c417da70a706444\n1f873a34deb42e00f62fe194cdfdedfd9939a52a\n1d7493f1f0acb85bcb30a4e01e2e7d57e4f8e62f\n312ba7f8db2b16e02aa5a30f6266b29eafe61c69\nc39e45eab1fa21e9beb357288ba8a8cda32af423\n6c18f15729a2f9032c36a05d1172ff4f89524a3b\ne8e4823fecdc47343827a360ce758a94409d40d3\n5adaf5468b8ebb5b6358bd8f6ef891a681d494a2\n2913141dfa42e983d2bccd45894688a9fa5ab057\n802a3b237daf218fcdad723f0471896ce4be89e4\ne4b1d3393f9ca6ddeceb9aab25901ec6e5ec67bd\n8c484d6df7e9a310ded62be36582e7bb017205a1\n3e8831b60dd06156090aa20e5f0cba0e59efc993\na34764f7c936433a64c9bda5f826b719ac8854b3\ndd96967994b3d4e2dd3082902b49899b735ed5fe\n5f73faa1ad87b24953bbeeac36373dc13930e10d\n1c6687244e4f4a8db6f07c7d98adc1cb915256b0\nebe4cd23ef34772b09cf1aef9379258a42b38be9\n3c5a88f22ea56cb49663b33d267842d65d3617f7\n64c2a813acc32e9831e5077645eb8def3e6a7b26\nbd919a8b90dedaf5a4e133e08c33e612f9ef84ac\ne9360ce2e6ac5f9da359d2c26453aab4f2d27a42\n0bc2b561829f2aed3f34dcf5e8ae2cffaec80226\n8cf8bfa9eb7ef1fd70d48efa0ea644163bde3822\nd6137b8769a5ae53801344138fb352e9b34fef1d\n41d3b649940215bd3784336ce9e0c2908bd462b3\na0f3f1918668c06280f2e05b0333e00f31935a46\n4c932e8fbfd7d4aa13164332b8fda278a427dde8\n83b2fbad90a69cc075f9e78a67b56b8a59779fc4\n55fa140e784756627976837027ddf591eca85572\n5be476e1897b74e41478c2be4ee8c93e7084d7c9\nfc9d7ba4674af11bc0f4cc1fc2158c0a751cde1f\nbd070edec2324ad1fc5f366da87c724bb72e8e26\n1354409c8e8ae76d47ddae29bf6193f3b454b94c\n6b6d70fe114d66dcc6b497cec154a5ecbdfa2b28\n39437b39b63f95e356af5cc9c53ceb4377422aa8\n215f63f2abca522471edb123784e826c706fa840\n103e8f9d797b0a8c5cf6ec9f4f0c4774226b4950\nc463caa3f58a9ad83f11a0562e33b9f8f0cc12c3\nec5df7a5c88d00877590d4033c232a45ab9945ae\n5c7f2c511425569707b5d45c0f4cb00f32b784e1\nc84e4177ef5261a57d73de32d346c4fbb338db3a\n58cd1e2d0d50704fbf51d7a1846b0f71db8d9f8d\n6561895337b4f97b4ed9afcca9e431d682084c7f\nb67d7e804f3ae24b8885486cabc79590bd0f961a\n338004a515c306c7dac345942a9715df2cff13ab\ncd545b6f484150c695130975c59f7533bb091500\n66ffaf406e083e517b6f33da99c558ffe8124dc9\nb70838c63e7297cc8bfd0f12767eb636462f6c1b\n76ca0cc228af9065a55b376ddf9cc7b16481af39\n6db8413692a60cd21e50bbba11f38e22bba58043\ned6c98699ab77cfdf3c26f8d3c6b5c124cc29769\ncff1b609f831757cb9ff5142842c5c15605cf058\n50179efc00a1dd59ba3d6ba5857edcd6a587454f\n1ef6b4da050ba5aac77d717d34da6d94eb1e6045\n524d315e1d58c32062c664c76382de0ebd44c70e\n5b99cca42d928e9b802038d651433bef63a147fc\ndf1671fd898685b23fb8aab3fbe084825705aeda\nf538694a428adee5163b6185d64f5d20ff3fd454\na6d965404106cf6b4f7f37e7d5aacb36402eba24\n51d05e8375a4fef1fc39f63168115574958a3a07\nfc989edb52d84ed0cc2e402cbd2520fbf36e4eb1\n20d0f9d1daa6530b9a7ead330e27a2472b106dec\nf65b924b4e1b63c801b8833dceb55b06a527fe34\naefb280ea21e29261496fdd52847d328bd5606f6\nfee35478f41fa191b50dd68d6987ad8bc2ece42a\nfd78bfd6f167a1f9dde5d1dbecbc7f220384fa78\na304a9570674cc59bdb27b51a3d481c70d580f11\n38cb003542126aa4d0b6058671831633a16d4b7d\nbfec53e4a45a3961390e16b1785f2efd8afa2b38\nb1134d103f0bbe327697bee2bc59a243714eddf4\n9fba26f06f005d93c63eaf085f0d8eabbddcde7d\n82fddae86e31f510b7234470832d678059b049f9\n599eee640859f82394cb824abc2e3957d92ff8e6\n7479152e2ec27d4e927692b917b2ae3f9fa6d0dd\n9cb3cbc90aeb59775466484057634675ad37addf\n2a5b60b11e2d4ca084fdf7bc9015686a218d05d7\n1e8d76255df829bf5ecec8e82abf5385a3803f81\n195972c8b9c39720daf829540a1490fb77e5bf06\n21569ede479fa195ae52e984ab652947dddae6a9\n404c00a43538bd237cfc425b9674090d6ff9c4e5\n8c796fc5d418ebfafc3f5333fc56ccd25844686f\n516a8e8add7c9540d08449482bdcc767afe662c7\nd714d4c5393b1b613283ed5caa33ebd92231d720\n29188982d90064dc0ece54066f6a04d1f7f67a79\n05c3c467c6e6cce8f93a2bc78f051e3e7b670041\n7cf4a7189c692e69b27269a5c11bba15ab992592\nea87c5f07f6034797636a99dbb9134cce6fdd8ce\n17cc64248dfd7b126ae6d8d3831619de274f6411\ncae1234b2331bc259b937b9b529e6ece2aab6d0f\nd89eb8bfe142ed61788e85091ee5741ed5d36117\nb6229c06536663bc3eff462c16c29b442d349ea9\nb1cf1393e59ef568005db9efdd15a20bacd613a8\n6790a15a36ecc6dd1edc6dc29625794620bf5e43\n3cc84911f22c669e9d13dfa5619bbf5fa8cd6630\n116040594c35b22369017596ab2e4b5d1d788dcb\n5094edb056ce5726474cef0cc04bf9b2085533f5\n4d0e03b063f56a246e5f12bf325c0d25f2c9fe93\n601edcfd3a58bc814dabd505866d2b3a78f527c2\n436590a458a47449d6d6406ad4770816dfe7281c\n2a09e52f30a4d771ad4b9cb45983849c70cef09c\neaa614ddcb5e1bb60be93f81d31b1f766ce90295\ndbf8ae98c5a278278ce0bf3b2f417300ef1da926\nc435ecbc886d04648090cd7976ffed7336438f83\ne551191e9bca9702bde959d51cc60d5ac0f54956\n932734c3cbd2774df71c0b8fcd1591b7002d025e\nbefec75c81b1ffbc88337e13ec2418f5e640fd09\n82cc20c9d1afb8ab0082cecdf2cf2c3df59cb060\n0c88df6b993f20036b388790b2f4ad84e4498d71\n444a8e2c89aa11369da02f38d20b4ea888e5b5c2\nd3028eaf93694fbe69e5f253315b725235c49534\nd547412fe428f67472cb8f34e52ed32523e0d05c\n7dac73ed04ec37fae3c9bf17aeaac0eb99885347\ncd897ba34fb91fb56857456274d61b966dcc4a0c\n4512b9f381abd5bbfe204fb86378ceac378dc26e\na38a12877f29587027d142ef707de9617c0a8a7a\nbd52b86cc78dd695939bfc20b776fde6a025a34d\n8ad0b865350a5ac869bbf0fbc62b3b235bee909f\n756f43537718c0cc5bf031e5eb42854f27ff7df9\n9a6f441883a5a1cab63ba938094f74720f691b63\n3da6ed19cfd18a41283c01a04608c886f6ff676e\n5545acb0e3493d466b042e9e03c6ecb655cf7461\n016bf73583aaae8d4b142a0b554b4d0f89c9f4d0\nb764610863a61bba29a0f18a58e9d1ff80be50b4\n80689d7bee18d83ea7bec5495a5f9f4262bd2bc7\n2d809a68b196fcb062ce511492bab963513960d4\n459d59d28ae07c2355bef82d8f61674f1b1da469\n0b5de1f35a86bbc4b1201910040dd2141e128c02\n7e8c713384f02d383d24835c0d37fe3d62c703b7\n053f85eb6d47d895aeb31f0a5ab7dc39dbe18374\n4fcc7addae0aa8ed5703d54254c7d78c10c58019\n42368ddf84c6a1edac818a563781c77bd8b7f7e0\n1caba3607e42e4f14c2fa4920f77896e674d2c79\n6ad6987822655bf22a2c8f0d1fb7e8f60e2dedd1\n35074b6f0e09fe840cb579e46f4a6b3f45bbee26\n34a55d2883491a695d87d56866df4c4c4d7cdf67\n63c3f0236d3b4dac80d2951aa179f0cb5b4501f3\n4b7844701d72c7ea6fdd5e3041da9f3aafdd3dd4\n020525def55445519e3a49f65fadd8c82dbd062a\n50dc85f75848f4ee34d3bac482f93dec7c823e88\n2cd4b2a5b799cdc6cd118aafedee413af8f69d13\nff66002aa6e7f0cc123e989df74c1db570d6a035\n59ec0739aeab133a4c8e4170a11d146c078dc177\n9b4643c4bee84772e6a41feabc4874536181ee97\n8edb4b5f27ebf893d44b00b6363be440466088eb\n4a4082c2c1eff3a385d6bc8fe813adc80255db84\n48058bd52fb735a5f9691d41f1b6a2477db7fb39\n6c9e06aa406a5c4e00eb80d0999fc53c6ce26a54\n8e5db1e21278406be692809ec3f854bf11a099b8\n928e82ec7118e9d1e1a1086638f855a50c404b53\n71dfa1dd61133f5c200476eaa56c09f4648614ff\n9341d0d7dfb42bb97cf69a4f94c84a92a5bd608f\nd376cfe6518c8b9113ab0053a023b89af8e2b64b\n868285645e1e8a1ad931bf4d3ebaea6f938ed2f1\n941627ac30058122e543bb320d76bb338d3ccc66\n55427efc437fe865ab69b7d668c1294e16d443b7\na077efb09a063583f7bb03dafff97c684b7ce17c\n473526fb72e98bcd2dcc13d1cb2aec2bb318851f\n8b913951c0da87bc43cc84b64c096913e6478b3e\n362ca4f83255f8845bc42e2e62fa363563491077\nb58534bf7889138596cb722ec9b92eb1c1451f03\n2f6dddac43382dc9e1d3f3e958e3a6391fe1b50f\n21f04f70efd64efc683589b31589aafc9ac2d6a9\na250a56c8b5ec6243e26eb4a6816164e47e565b8\nc9e92ffea45c9c23588dac08de76c04d33796fb5\n506680a246e859e0ac1ceca03dd61b8d10471a2e\nb6d7992bc8651aff756cda0c8a788ce7b9358560\n148a031b1974694e7e2a17f2fd37182a8755f86e\n465659a0c413f9def53161c2a6e1174d4398424d\na37a6f928f8c8a917ea45cd37cbf1007679907c9\n494992f5f638b01b9b79529ded3318c770b494de\nfcdc2b5ee9909a8e57519cc0c6be0ce47d7db957\n101b6f05baba999f4c57466cd07289821a4627f6\neab6813246b46ca1ddaae6f7ebdf61ac2dda560d\ncbaeb8e37183e4b40a7f4ad70b09475dd150218e\n396644091bab7b2b7b1d3f2dfecfe218bb18def0\n99a5f1d3e56b50cea4e802804a09151063d9482d\n69371eb4d6e417e5d113e5f35958c0c560ec27d8\nf2171459054edb1d787b8e4142a415bb156e7ed0\n15a9b8ee565c5c78a0d0ffe20efd1733cdab5822\n7b51b13f8e74d2fe9a36a785d452a67e7c9c671b\n62a634afb96a2392db13c8dcd2ad76ac2b3930fb\n49ed42e87646e81fafafdbce8389fd5ee8123e09\n9cdd0687f4580e36dc0a5fc526562e487dd0ab97\nbef5f2cf8d9f70999a8a1c5349acc4e1ffb085d7\nc48f0b7d793c3f4f2c1463bb9bc125257468916c\n327a4d2683b7359e89866e20f7c68508af8555af\n2b9e3cabcee59daf38e7beaa7e6f5165d01307df\ncc89e2b258021a7b8679c698ff215f4253526f78\nf91c10b05c0e0c543fc471b2bd99b0f45fca70c4\n7771c06efda3889a1ec61a50b0cbe0e580a69730\n818bf133ee4e02836901f2b5818723d11c08ed18\n5e8adb6455b312c9db19f50c67d23ea89b0c03dd\n45c620d55962c646a628d2cd41bafc693c3614f4\n8cc2c7d29f0f93ac0e3ab12b857f7189ffa8e5ee\n4bf609def2ac732ed33be97ad4a101b1d58f96ab\ndbe2e26e648c333bd482ff8c3d02962253c55ad2\nfb1aa8bd9228a17431a27a36eeaf9640cfdf48e9\nb65944d78fd66611f47379a2dc00b6f43b390e13\nbe5a7ebf9a3f1c21ce466a71bbd5dcc323f5ae8c\n7a0606eb4b734b680fbab0671714c69d7c32e5f7\n9a3cd6394830c7cd6b2a9ff53e8bd970da42729d\n8face969701bc9d1b6bef02c02298a09221a614c\nd3360e314552b9aded10f1528ebf083a5d79b562\n4a3caeb7d4f789d2455ed1ab38c32e4bab339718\n30f8243828254e82ae9fb904c9ddc8ff1351a69a\n8fd6f948fa5e794f962ac49f45e59372ec389f95\neec4241a0887b2150ae5536bd36209935351d370\nbbe136e13ec3285e4f174147d0efbf916353f6b5\naff3295f0772aecf9b1bee079d6f96fe7111722f\n5b404c89ffdb32d20a2d854067275bcd0d098085\nf1a0dcfd4f01284d819cee24408b79af55a7f7e1\nc169bfe5db3344b88ddfbf832624f4ba5afdd9bd\nfcd41ed0e23f8b5b76dcbafe8f3e83a28d530824\nb24741a574abbb6f644a8d2d9db07559635dd4b2\nacb9d6b4ea2820515696da001697636a40e49b19\n2864b34b9e92f5e4803b8d3d59112cd765bc5f63\n0f0014d0159b50eef7c168ccecb3ccb9d53faf25\n5640012c720033d466e810adc669c2d06b119c2c\n23ffbccc02fa3258576ce26e76b6e04b12d27baa\nb9485eafb6e433935948ed3e61d781632541fb1a\n3a6a5ba8c7038e418c6aad1ba5b473f9ff788909\n82a929c29fc4023b0424ce61771fd8cb6e9aaa61\n698e38628290bf5ed3c5185a0f95d70a87f4f085\ne2fd708c9d4120e963fc713f1ffec2cc0b51e86d\na266a1718efb942da0695549fde2d8d2e59d1b64\n49fa59bf45d854e753d8c5e21ba3f4b437162edb\n083f03dccad4fe192fae3f5c21e55c3bd8b7fdaa\nde0257016a20e11268cd949590d47e5984f345ae\nf84f60f4973bc3e7dc90107731fc5c30fbd2f4d3\nf3eeb267c511d12f8c4115158ca51be9b05ad55f\nd589ab24b31457ea9526b7ff09b06b810516fbb3\n2b7d78bb6633437a179f4d7f4b19a95535afa396\n481ac5fef67ec7ba608a3fbdc6de50fb89cc3a82\n39c6a1c96e69654f0a0e170cd81bc9a1493b1e93\n10b7a32f228b2b55322b4756dd2c0cba158916d2\n3f35a8a614690e34e148ceb12d7a34b80fe447f1\n47838de310717a1fb9db49261a7354031465825e\n34add189d63018a73d5145869e83a9a067310a31\n616c46ff092a78567a6a4326ec844d6da1489d59\n7fe47da9e3058fef755eadffc3f41a43190c818f\n873a06087c108a453363b996fdcbe313097df1a1\nf6e327b9be7793ff0a1e345c542f4c309f62185a\nf5e2728b7c91957f19694f0595abfcd3131c3ec7\nb88fe987d944d7e8d8a5bf07e841632955b58a46\nbb78dfa3aff3eb1dae6bec168f091b267f47ae35\n4b21f94a196416dce6f2c3f07a18c07460925a92\nab20b6a158160a48a9ecd00cdb4dacc13d0c770a\n85f7578916c272e0e4b281625595494ab93db0c5\n9fb5d3013d8cf2a172c91d98330bd9a4687ab65c\nf873ba40e2a6e2ab192e2eb591e240de580e1e90\n05c757092e8e4417f3f68f34bc08f65e825d1e3c\nfedf2011f951c04a1b9e9a056c86289c2ae90a0e\n7ae1a4b4a87ee732200baa09b0d227564ae4ae84\n99045bbe487d36828242fa24cb99501643094ee6\n2b9c130c30dded9d38ea393f0a65e2f1f3965d1b\nd1d678ccad41b2e912cbb24cda0518ec69ea9f4c\n8f40ec5fd4716ad135e8fc3197f5da20ca0a4342\n68add5d6761863630fc62bdf37c5684ddc4cbb35\n14766963161c727f6aab9c51dd447f647ff8241a\nd81167b3ac1427ea221a3e855b8bcdc4c0a72115\n7d71d8609feb2c98e2a86afc933f632028b9ddc7\nf1d0250490e64f22ceb285ea06c19633badee344\nc0dcf62176f32c4ce9ce3ced4b056960c84504d2\n896a7f14c24a8fb17073ad7741927ea22e13420f\n0276b847b7c07cfe16a048eb7c22295f9f25c15b\ndd39a0a1ca9f073923a8da457ac505f943af0b68\n39f3217c5c809323a1d5279e8e54aa0a60655f6d\naa553214594b4e7f23fc7a3dfc69ee87f67c903a\n402fd4b940cd7e7c67f7983e703b4cdbbe4a9d7c\n5c0ada842fd7abf4d7bd6da60e302fdb5e1c5ed6\nc7666bc4857c21795605250a2c53faef8f407958\na311ec27da50d95c42775965bbeb85bf030ca7d8\n2ef8dd0b86a0e7c056b31ea5419f5b13019fe508\n0639452ae1289870277e483ea019915aeca01679\nf424e172ef7b947359543b830b9316bc823da3d8\nd00a10cd6f28e1f7f77573c92e39feef421f5c22\n47af57b37d027adf9cca3b582b89ff05dd4df5ae\ned60b76ad7d172e7de01b74ee1f86f37cf97a9df\nfb2ded2c1072e995b593587585989917dcd3e641\n521beedeb52bb03ea7cb18e857511587a102ec07\nd4e213c66c9da537e5f70c055e8c08fcf997ad7b\n3112d14579d738699b1e73346d940ad3a6c03683\ne7d248a408ba36aa42557b59461f04f95b2dc085\n2944bd60881693c593018eba8daa1e20b21601de\n2bab7d8660e36dd211839d9198a2feb5013a9adc\nb55dd9719bf3d50604e05d6e523560dd50f09d88\nb7297622bf8cc0a11954f5913f619788b2a6fafc\ne0ec7ee4346092e880abf97c028bf00abc1bc757\n2c368449a18eef62b7cf5eb65a8e0e0e1056a398\naf326020381e48df9ae5d7471b46696563de869b\n1d41ba9b2462d84fcaf597930e09230ed0b95de3\nc22ecddd934cb0c91fc1e6b1af8241194699d691\n06528ed5a2b9992ba8516e153990a62f721d0b6f\n1091e3202dc7b86304850c1b3942acde23b16898\n64d530ff3d40e68c36551c2f7d1d84c2c65c299f\naa2ce03ccb203321d5d6f9801b9b2ad22d2aa97f\n34a263c49bde42308db98e52b0176ce18dcdde98\n66ec79d6089a22bb553a1484d62ec58636fb5add\n2b249949079f22ab9978ff614e134fd878fa735d\n4d9eeaeba1215cfd68f26f3792552d7d2b0c8209\n0fcd36ae17d94140311894e95cf7d40a2c8c419d\nf632668ee44c94f6f374eba9851659b3508e159b\n5717748b5af68482722e7a6dd2a1c3a18e0ca563\n8fcddac8e5d71cd343513f2bae678b3d12962d79\n13779fef3c62d5382a0c15fc1825918c493d7f31\n665f2d4f7fd9cd62b557c543eafbf0b93b5ad688\na49a62b45f883e7e08799ba85a73148b21fc9a1f\n1357ee2eaeeae3fc373db991b101a0d73318547d\n4f398346c48e2648f9ed1f94cbb72d8d1bbda794\na75278acf8fc22a4d3800f1b8213b517492f5c92\n7815bb571e7879fb4a8e3b3233123608a68ef441\nc53f50945d6726077843d339b9067aa7066bc243\nab3dbb18781d352a0c78b65874fba774cc17d188\n14a189e0771edba1da50ae874884954fdef4f5a7\na672c3e21bd57a232e797a448e864e62e71919e5\n3f2da51e1f8f84fca3a9614c013a3b2d15839ce9\n98e8d871ced5767ebc37a5c2bc51ceef0d848185\nd1c740fbf2c48f91b3acb55931efaaa1ec57974b\n6eacff0ebda3022ca8421185f07888c3b13e8cf9\n5cb461a37e5889b0cbe50310db9cb2a60b0e9aed\n6b86595e9d62a27ea2f8c88edc4ebff45331ee7e\n0d5518d33b19ba36a8e30893d29754868454dafe\n6e04c6e24946e24883c802e8e25a003bf074c738\nbf3cba72be331208bb4db8e5d2e7a27d35ba0ed8\n9706f8e6f5066a349dad59f2e410019fada8a23c\n2e1c4a9718ca0b971ba2c7e4e514cc9897bbf3c1\nd8f21cb294f766e8bee1517c789b8ce8a4edab24\n0663df2bf15249f1f5e5f710e4c91534119eb2fa\nc2cdf866b0363992a3e2af4bfceb710c115ccd62\n17f9375b36a7dad4f32f8160cbcdd3565d086b55\n6e04b6119a5573e3a6bf34495a14cb1e8a1ee91e\n3881438070ec9f601e1cc4d6f5c186c3b096727a\n086ccc063dba86d4656159c4e219938ebbf1f428\n6de3a2975b93f2588e540f1ed1d165025755fd2f\nc93e1b12e08d7d0908a1a0fb0573a1ba451e5223\n35c78c8369c6e86ad90fbfd361c6947d8dcacfe7\nf03c4da077e9d785a5c104b67ffee570574bd810\ne46cb40b1cd36d58388a0c6ed37bcb81ec4a9f60\n03753392e37cf34025f76e61a2ed0015bc602f9c\na19226c5aaa0f9d134fe0b088ddb347190cb26ea\n15ae179122d66fc617bd758fc4ce6737755f32d6\ndbe1b130facf694b4fbf9f4bbe4ab5b9c4a21865\n197bf48f57358215ad9fee32e4664946006a022c\n62a0b89ea37e7b3e65d4879648afe42329d0c641\n2fb89191f175aa4da1a1a81d41065815431d8aca\nd3cf8eafd9b141d58a00515dbe4ed274b15af42c\n3ff8536c387879761067136bb75d1ba34c7d43c6\n6d6a9201398809e12e02aa6de20adc6a71203675\n144786424da6597742ebf42d0b08ad199f22c6d1\ne6d0c2082fd9d2497bf2b9db5658c201331c4d71\n79181d8e134e6a7a2cbcc70e4da2f33587715e03\n00b8124671c1979473ae6bbee5c43a1d705f3161\n5afdc56f4ccffd60ba5fd46cd441ab3c1fe59384\n747c7e10c62a5347e890cf5a8053d34d505b8842\n878e45de065565c88e524e294d7134bbcc0ecedf\nece62d9747a31dde0bbbb02cc513262820fb8e0b\nb093d949a1721794359401e48fb7bb095eb4f66a\n39f52bc36b18975a73bf9b55959c60c0df4682d4\n4677b5279c715caedbf689a8e9f4aae236d23082\ne7870f9e403c147349dba9376a923a2a237b6aa9\n956b9009a114afa5ec0d43cb6ff376797e4517b1\n4a1a0f434c6aef47b416e3bc035ffb611e054b1d\n129819e59a30451c75a674a40336852b5626e9a0\n9e54fa45f32dc2d4f6e8750d89238bc58c07369c\n3632ca6e8b5407d40320ab5ce042b0ec0fa946a9\n8ab457b8bc556523e419903cc045bd44b8531671\n6a5d50430062f95fb02c049f94b96c67046931d8\nac6ba25927e1a1357a94931d6bded2b1c50e2066\n60e80d3371779da796e056b9c467a3b15e39b145\ne11e1d3c4fa5cc7be347ea97db1983b3c0e25247\n1d62f8e58d685aa1bc3623f5bcd504c027211d80\nced1ec2e5970c33b514bb2263c33b128332048eb\n3335be6a6bff053c9b3b4a019e285ccf355019e4\n7e4c0e10a99f8fd2789250f410090faaa4b58edf\n84fb3e0d896736b38d8bb6dbc8a3d29f25ab0329\ndc45886411c744249a2160e2b2e34e05020b5b58\n77626e990e463e5c78ac593d6deb1edceca1b673\n4f30a5c2432c432a9b37c792ec7ef8f1959f1004\nbb9d09c7a33c525029b262ad28b47a47942fbed4\n7862b6f1f61c1b0f1aee7762ac309fd43a136644\n9b4f9caa39f0881669e49f44330a99583688ee39\n7cd7754849e5439529fe38840beee7744f2d3934\n8794a984da09e969bb01fdb327a206f3613fcf99\nde1fbe91b8fd795bcab75481a5a05e71d5c578b8\n5f11c5cc16fd43c6922bf0d586d32f5210d43f3f\nbe1cbb039af9f273046bf054fc2e004bb0ee2267\n48986035a061baff9d0d5ca46069b3c424e58b3e\nadfaee9af0c9211ee43de114976f03939081eeb3\n670c1c44b3e81913bcb5e999b408c3d4348e116b\n515539ddeed33d249d6e7b3b9d658293d66ad0da\ne6ae2a46c6c88de5a49c24cc848f3eeee2f7ff1d\nf15d2547aa177d5c58082c49acf8a4260329f79f\n3d474c9e76120c71ae8840c502525ad5d97569e1\n2c12339e516222e09976b1f0ff8ba0b2bbad9295\nc006b84f9a9c598339eed7c864eb44b09f2fae26\n0f2bb2bf700e006378103d25a657cd5c934a538d\nebd272c223a17241da5c24c95a6682bcd1ca75b3\n9dfaf0686285531ab092309eb63dc3383086a8bb\n10ca21e2c43ff3d408e5b6f72ab2b7086f52e23d\n1bd2566561593a77866772229e035d1dd4360646\nfac27c8cd7e8e4ee4df34bd2a3c773709f42af1e\n2d9f7fa0dca7b96545f34394698c9d353ca8e00f\n69f78ba1f5c48ee6c9a54cd5f8936dd668d60c0e\nfdb67b05cbd85e71118ff3d7f465274e31832752\n762803181b388619e818b960e6fe5ce529d156c3\nee5d707c1ccc68f2012ece7f57806905307a3209\n5a904a7abb547273676946f6c140e44bc1de3bdb\n57b18fe22f5baee8ba767629850eaba28532d3b3\nca733cb63bfe47b7c779d43fb43d532e849e2dd5\nc1a6c281c73a1a1a298c6935ab5634a1cb98a873\n3172c409d05bcbdc8b32fd99ddfb73da15d88e29\n7265831270206ae14af1a1d8e08a886505c0f762\nf78c416b972e164e4774c50cc9b917c9cc0f26ba\n902d62978101db07fd3b714b67510ced95c51b73\nd9a15930fed149bcee0c1937c599cbc2f58ddbe8\ndab0d1bef45b27d1e502151dc9d98a4192bc53ac\n762742ffa627e9c32b7b1eded82a6e017bcc2e7e\n88b65e688862a80e8a87da1ce07e704197d65412\n5fa1405830e50078dc42ffbbe235061e6c0d9d4f\n21a2851905adb836e4a03b2cccb5111c555f743c\n64800a53a66ee0ad55c47a7c6c51bb8aee04a0d0\nd7e0ce3e587b2a46b69050c07791d8c1ac948651\nc557a2f135be88442b2a2563a1be2164cd6a27ed\nc0aed9c7c9acd78b8988b52ef59644a197f13c78\nc334ec7463d0398975946529faf4c620805c55be\nb910d8f6d740840bef3ca8507ce30fbfb994a939\n5d5b9471066f2912339e476d74a7340617db2152\nfbcb19e562e82cefecb674bb8ecfb911d6947826\n86a6dc3427f10546ca34267044851218a056eb64\nbcd9a7188f2240821e00245aae911d894c9929b7\nbeca98d65208bea5f2d7be63862b9b1e8b143b8d\n9b7e64efa03181b54c103f3e9a0cede479eae0ba\n00a5395243911f086c5ad4578ea107d9cbd6676d\n3c4fa918eaf4696d1ad79c8c195be3ff5f96b83c\n607b54f74a8438168a1f7e74ef56738c73d10da1\n0241cdf5608a0b5055410caf6d2fb6d2a7813b38\n6922790eaa460e9bf5cc4920b812e1ddb07c17d9\n41be43d610f61431fd30f31811e5dbaf805c870a\n61b9a5d007554afa143dc73e8ef2cadbcec891e5\na0df47801cad0bfa4d804f870791a5e4abd17808\n4167c29eae43d61083b209efde7a5eef783309cb\nbe1ba12bf9bd39067b707b8c82296a9a9cb3b4ca\nf6d27db62fcba4f4a1f8c6d442c377caa3eade97\n868f097051027bfdfab27d99af6a312abc931253\nefd3a30f019ddd4c59851622cec03d6dffff7686\n1f0771c8b40377c2f4926239b9d0c6c6f3a2025b\n38b6d47f07b111dd40da1ea3ec10d499fc6a4336\ndac061eee3b68ea45bbb7ce52ac1e050a960a985\ne7b600043664e3b3bf709e0faa6d5201c826072b\ncca4ce79244260245ba5a60c682d446e0d3fdacb\n7cd7c5c6499de65f74077b542caa4cb06bd0798f\nf973ca8e4cd9befe902d11e03da90c5482506fb4\ne170214a5ad6b5efae40b0e1868544737b98c63c\n34a1bca9a94ac44ae3e7b9dfaeb86b250dbd618d\na0510cb1e36b414f909612ce0ca93781092a8c66\n30426817b0e629ef019dc8cfa328bd7ae04953a9\ne0aa3a5c5a8c905597efa8867cb9d62ef7bdb46a\n50df178fe86ba92daa091214d372b0979daea705\nbe0cc55105a4f7453dc2d6a328582e0491cd317a\n3fe6c3bcd997d7cc3feefe8f505bfc8192a18423\n572c066e36484016c9c4f272ff894c58b734b465\nb71364ffeeaaccb22cf5b1b9ff3fca02f6b7d6a4\nc5ae8d94716eadde7310351175fd5a633ad64829\nedec7368f517e095fead63a19f6100041c9e7975\n48941a6d4da82d22573b66bf3bb216e754c7d039\nb0c68de43e5238c297ff562113e4a35b8a0d65b2\nd19ce0bc09d4cead7e87dece50a2ae60a3a7a226\n8d21bedd17f5be1586758f470713a8cb92b2f389\n362a586dc0652b033cfb943d87c2b5dca2d386c2\n92a644f772ade832d4c5033481c3870d747609a1\n43305686e661ae6c6ae0acc2d88dda5d46ee18e1\n78b7cacd07d88b2a2f93ab7e042dafaa82b43da1\n6bf19803404db0286eedd24f21c26af87d27515d\ne1dcf5ea0f31878e29ca736ce7e81e7f889843e4\na7899f4343725ef06794739367c7677eb612caf0\nfd647cdf1d41e5bc404b105e395abca88065f624\n6f2d020355743248e4e4a56b668c2c6edc5252f1\nd21926d01ce32a493b93cce0b7b90fcea6687ba8\ncfb945542e469788a34d28db2581c654e0c92b03\ne21734d2198a72a993e21eb5af36d404c05b8b6d\n0293b71ab5bff5ab923466e9a517cc611d8534bf\ndbc4b9a8b46ffdc434ef08df588a827e0542a27a\n0b8335380f7ad14f761a05e27adfcd3e40467fa9\n7cd1499c2847db817bc53571fdaa488aa3129636\nc699e828ea9fae5fc5d8a9129353cc5c522b52b3\n19cf8841f7722ce25d2bd55c422736415200f23b\naba4a51224fa5bb6880509c51436dbfe179b8928\nbab522d64aa0f297071161e6ffdb6f2be3a83f22\nbd861e50413cb598f9127ce835c31da83b6f6a9d\nfa73fd737f69d9d74436efeb866b9682ce9324e9\n2d92cd300547b49829219f6c3cfb1afa2cb6b621\n60cd929f42cb1e76a3ecac18aaa648ab32e03694\n953f19bdac0f6cd53ee8396aeda7986670f38dee\n65db8afadfa40ebc073bdc1a08ae6705717c6c61\nf8128f5bb8a7e30f777f5ca78dafbd924bb4e4c2\n0f89550d3009bc0483fd38a66348a8fc24ded5ab\n94788ef1e0d343563e70adad3efd0a6f1ed1f21b\n93984af69b97f802829a64cb83aa31eb714d84d8\n0a4102b0a093adad9217a0cb93a35e7529186e1a\n634ecedc1259050226b301785ed03601b8be45b2\nc620bc18512dd3f65db0c8a2afed205db1913be4\n77bb791711586885ed825dab4ce8f32480464322\n7cd34105edf2ab9c17536059087cbcf0b6d0409c\n071bdfb5be629e7f2f5e09f3e46d599b3cc77c35\n2034754af570e7c2fb3f7aa8d89ca212c4a7047c\n326b5c44ea7bd5406a923b4f4040f15f4f8e9a2e\n87b9b986f41d463188afe8bca7dd0d029c056580\n9d18f2ff6ef740b129e626f01e44dfb143761d9e\n1eb2cc2f126933f7f3ba7b77b46b5826c5dc7d28\naeb3b5da8601bbf494b0004e91674a2e753efa4c\n81e5ce68d887d8f91bd58a9b60820fb7d91a6dbe\n85b87c9956527a1f51ad8ee453e34300a317d5a2\na7b4ab563f456c9df7b13290636cf4fe9119dde5\n1f24b41984f30e92a3e17cfab637b589b88f66f2\n7555bd2169532d4261a05999f2fceb7e4373fc80\nb69677f87c61e5f9572e2c53bf3ac44bd1b82140\n1a809266ee78fa4aa1f0531303b6bcc750ada3d7\n0d68e1d9efe17d1f49df580fd3ed6f694b36787d\nf3d951217ad97b6d415f6fa6bf9145c29f3f2e59\n17634ca4527c0d59aa85b9171896174edbbcd608\n1d09cd0178b166abc5d30e381a47e084577d1328\nb9673ba661cc21ddf95da0a2fb03e807f93dc5cb\nb3b8a84e223d371ff1c0a6b1a4b8bd66203cf490\n6a1209375d6a9e6621232e61078d8b8ec6c761f5\n3bbb2a645d3121aa567d05ad25516037380a6c99\nb8046d477cd6bb032ec2279c711701d6869b651f\neb4dec6004bbb1e47a50b784e6399bfe619ff789\nc0006d5cfa3e5d10875d814010552bc6cb48664d\n0fa9181574bb31e3e85f253c7ba45b180c58a0a4\n8991af6305c818eb3fb6b7c0cbab53668666b6eb\n125749a295f519292690e5e1ae79a42089df0d81\ne29fef763f7261ea23dd65a81f5d65db84c228e4\n8ef79fcd17f4c684978e72dc21f63ace9106fac7\n59140c73ffa3a51a5c4e05457e5b8affb9b1363d\nb59958eeafc291db80ed302444e690312712c988\n8de684a67e94ceb239d06253a2be43ef3b62af57\n4119845e6fd318a6bf33828222d0d62d3331ffb5\na9f4cbf19c8962ff4f3a97f8dbf3adf586b3e9fb\n272684160611b5d7cfc49e5ae69f7c581ac344c5\n500f6e68f7d16bec51d781cde3a891b584b30990\nd571ccb39f5670d01da662d4c2a9ba76995f73ae\n38d550e2243d74b0bf66d9354994f0daf52b0c10\n17388a9dd62f38ee5946e806870ec158195657e8\nf03a2497bce2c8e99f6f395f1324ac9361d5efad\ncb3f5d4e11a7e773f592d041becd9a930a3d61d9\nda98a55bc9d4a7013981afd91362004594f86949\n1ad72a6b7c69b57b52b629831e2444c15e62f107\n17e3c8da5e060b2ac550c36ea5fa2ff5b7157157\n9fc9be66ada65d6635be7e884b89d8f0abbd694a\n4995a9582807c662372dac58e75386673ea2c641\nb89679ac339e9463d43147ae623d80017191c7fd\n032a9430494ab6e1df7b40e14f459811ba956ee1\n8a8b8bad9d2da30a10c73bb0bbc053047709c11c\n72b625f61fe006441a916337871bbd9af39a706f\n3065e1333395e48d25666d5cad60078855db4471\n1f3338f08d093e736b7fbf6bb46e737e1671461d\n866e293ff6847b911802facb39a524fae6882019\n0e5391c62279432c761fed4b48c90308c096af4c\n0f743d57abcba6e9ec49572ad7accadeee8ef1df\n5e499b4175c827d606b6b476655f5fe247f9b6c3\n37e615c20c9591dba329690f6b333297181a9781\n62d0a3539097f34a23c9e14b39fce64f6ff098ef\n65323ec01d2bfa3511620822232660c75fb922e6\nf48731100039185dc18e6fc1cfab858b14003fe4\n375acb0eca27184809ad309a90b5373bceb8b217\n5b8a3c5aa2d6549681fa0c0f61b6b31f87a3cf5f\n7e282f2c00de2dcdc0aa6d12f79ba40545070ea3\n879683e929ba26b4869984e76955c599fa571b0c\nff31b5d5425142e7ae08cab2b63db896b0a245e1\nb9245e2724ad235528117d2337cd5af2cf1a01f0\ndcbee262e615753ed0eac8aee0f286c6a7cc8813\na0aaa2f6b4f37bee91b0405c7b9921b5a7ab4a3c\n6d9c99dd2582742b955b3204bbd1893143408f19\nd5f7e883f4e407bea56db7a6a4448255b783efca\n484bd8bd0fc77e156ca76e0d4b26cef32c719f24\nc88ab276a0631a8dbb26c8edcb238cfa6398745a\n62235a0d6ddf5fd1a9422c1e80f40f558e5b4378\na7bb2a0c7da2b849b0722f7edc1e7db2e79852c2\n98e45648e99106027483201c9afb04954bee5765\n362d06f2c9d2a18e932f7637d9cb76a4456cf617\ne624dca75b0be3f1336eb6f15260d72cdabf6cc7\n0e89c891b8d5f907f95bae8f5f0a19ea0de87102\n9a6086841d40df78e00abba524217b7a2bc35a4d\n6dcca983dee9ca2376cc6f7a069586eb693892a3\n9264eb3dd09e673c6ce130d5ff6a762cd7b2da65\n72aff5442f51445b258f5ad3941fc2381506db1b\n0e936f2b92953a134d3362a0bae9089a74aa1729\n0d51e1ef31d081fc05b508ebbbe851ee77554303\nf7c0ad760eab1f4b1dce1263093b79951eab6f1e\n15b137ceec6476a9d1f0ac55e5709fe7a16c430e\n257a9959100ee7342dd370440d78d60171ff4c87\ndc96b18e2d98fde0914b4ab43fe2c4cab3017409\nefea9cfaffd928908ecadb5bc704474cd5922829\n34298efc404c022a5b8c87bff5da1c7be53a3456\n95b4273b97a6db91398d3fd42ca17310de1b4ee5\ne4332b37f43b353f01fc0839e5683f25159d51e2\n27b8b5d8a8f4ce8eb3225fd93efd486e27379a76\n247b2d02f06ad4da93d0d4c73f46d1ca82264d10\nc220c2751063e98bb84a485709d249bac39700c2\ne3fe616a594d49b8d7169068d88b2fdb15687298\nc7a52fb7988bd0ab0c11e077b01c69946a653f19\nb23486114d61787699e5a800909fa1cb8d3cd059\n0beda6ee0aabc9bfded0f8aa3468d8f3d66e4eb6\nfdb2e35bc6f6fa5e527ef036a3c66c9a9f67da8a\nd36ba494b31fbdf7e31469a297e4ce5a8206061d\n44c1319df6884a3d3aac88aa713e7b2fb1abd291\n3acffca747d1bffb455b668c305614f768fc19ed\ne4de784e8738736c4b93b6205fe7bef64e026f3a\n553ab2ee0ec1b67ab3b60c85cb7520f7831b21f0\n3c5216094e0866964b36bcef4a8a622aa8f3739c\n324d66688e3f88537f9d37b74337f8ecb787ab4e\n272f8997610ef5907046f94f6f763ed62834ba83\n2e3a190a74160620652f441b49c49d4a69c5c3bb\n44bd487eb1c96a076e98b16db2d9fef5809c8351\n06d8de74ddb3a7a470610ba91bb7587244727d36\nf4d8bac2e581acb96d9218e38ccf098e944b81d4\necbefe63bdeb616edff4f5a1fc9352f68d690485\n28e0f32379c40de5d417e3d204e8a47f00af7ffb\n2435450b9cd5c013e54dd70df459444d31dbce35\n6bd722c15f7bb1190d44005b1f2bf60e8c763dd9\nd47d03acf65d4d2f24304df3b65a8d85bad4164e\na679e056a89dab0831694c171623a920c3436658\n2409410c1853cda29c6f3b9c81dd07fff092a712\nb0a23b8d287038336af7e1b6cc967e9112bbc336\n59ff57e90c610fc7c825b14702e4613ebfea8056\na62bfa3f1386e7c01460b437eb6a0b863734f6e5\nbcf90d40a8062aeee3177e2916f332e286d1b432\n8b340208e1d7c2e75fbe960304f05bc10ef26115\n6303e4f3b98174988bbd0ec3b479b2bb1d3c8c02\n038e119ebdb0388eb55518840711e718c2e18b9c\nea18b78fd530162345fb43d6e365ee4f3ff5f7d7\na1a12b8192ddbded4525f7eca13b827cc7c7faff\nce9af9c0229e475d3ab7ffdc0605e7b60786d93e\n8c61f0f2fa7ba1c08d27cc0477c4958684e724b1\nfe5e57b3e373b27bc4ca5a3d4ef07b16345c38bf\ne6e4ec950a5f75077e2948c3c23dbec420de31f5\nbc83d684896e6a9db8bfb507f78fac4204519312\n9b4bbdb1fbe7f9f1565c742ad59f1787a899c7fd\n5a4675058b6e22389d1b5b1177b2b9b304bfc6d0\n0ebd1306ba1e2eec841333c85764f50596478923\n732400657f9140a36ef57edd71217319595d6748\n26938fbb792f9d3962963791f799d3c12d78229b\nec344216a3954225c1b0e4ece12733048d7fa9c6\n06ae7a77d7755252a11555c9b32b204c9f0321a1\n907ba37f1dcaebf666a02f849b75d88569c38e49\n68240cac47abc3bfc96fcc07b79295ca5e5cff0e\ndd4483d4b346f7bd4db1b4f0302047a4e2e84e24\n63ef32c0f2f547a1063c2c709910766775d9d62d\n98076b3d211d21d279a15bd9a00d2fd1b58b69ea\n48ac1e8782cd1bb2207ed4993072e4f11e913099\nb1a26be4a4dbf922845f219e4c26ca9b63a5096d\n2a4b52cd981f0e839c9c0c877a96daceb54a604c\nc6a74a466c82220f91d846b167abde151e27ee01\n4b20abb7aac9c5ebac63b46a0a1cf636d8e36910\nc1b4cc5057b3b843a0782492a417fd7082976039\n0453e45e636053383965646c7ecc1ef41bd82ab0\n3eea33a0ffd6b3c8e3e3cf177c101290d698f6e5\nb5e482b991419c6b2e72f6ea7b6b33dc5aa26dfc\n0dcd3e3f5e22479dc5ad7f6746ee2b9462d73b25\nd7f5ecb9e56a6d70b0f9f65713df7803a9647e8e\n72d3324029106f1a348db294e6dc83638bb2969b\n2ed10bbc56f0dacdf1d36b48b3650350ffd9bbcc\na1e9ec6c8aa17061bfe3feef1e6cfc7f3cd49abe\n851f619f4ae9dd17fe77ef706b0a0f1dce9bfab1\na550d3cfac0f0277de0ba0eea2bd396d6d2b78b0\na7958a4a9a7d1e43fb99037df20369fa0319a27c\n7a520eb2d91415dd2427c1c9d9aa4aed542d7752\nd524cb1a1b251bc64366cb78d4c297610ec10df4\na3e32c26dfee8b55d7614e41e31cd548dbc544cc\n4b3aa50fd6eacbfd72529f3026745f47d91ad68b\neb3592fcb0785fb9dd85e1efea0fe912089f1629\n2a0f11cea6e6cf951250ca73736febf9abad3402\n4047237f5d8b4095638fad50978ac00e4f9a7213\nc925d8d53057e94f78700bc21c0db4de8070d9d1\ndcf2ea473b70c77f357dac43304978e0bffcc1aa\n897c791c08398246f908136b35ea550491c539ff\nd588ad2b0b147a69c2c0bd050d90e2454810673d\nbbf6b0af506a178bc4eca2ccaf9bb26ea00a3e14\n421e5b9d1abf1557ca232c833b0ed3970b132539\n97a7c16a0f403181e1328a53c13a0ec8650f2476\n837bdeb02b6495cb04e4f4a2fbb9f92035bde6de\n04c469d802aee2bc68d09acd43f494e683ccc398\n52e4d4b8ecdd1d8f59ec330b3d9a4c40b3bb1a47\n81ad318aad9813c26416cee01175adf0e669cbfe\nce70ac5a4da71d00100670565f21335f3bc02ee5\nf977c03705983daf08b958068bb1c9b901937294\nd54c4dbfcb97cabfa2b9953a4946aa14eaedd922\n8abfc82df6b16a4833d45a0ac0336a17fbb7d219\n0efafdead920fab2f7ea50261964640eaf183ad4\ndc9c1b66db9b33c18bc5686f06317e70f0d20934\n85797717165798387f1b80e9804b2d8e16ebe72d\nf8aadd5ff1a4cc87a917a104a3451c9343a39970\n39a65cddbec7563fac37c42315571d148dffd773\n79a0b65ed9f3a375a34ef6620f1b2fe51cc9ee70\naadf17cd157f235b3a9ff8c21a18c5c2ef0eeb7c\nf20d1430e1c03a0acca86088bc6df53729cb9803\na03ef5d0584b97f0dbba0142dd4a0106c3e03138\n168d9faa5e40a9f6cbd6c5e0eee9ff5e6a18ad93\n52c0cf4ce7062939bfe53d375e3b1ca7da4aca17\n564c49e08d7deabafb0c2539a89d8d229710f2c8\ne232cd3c34e6332b5ba8a5f0fb3e62d969388243\n16629eca707be23877450a5883b2b03a1c79918a\nea22eb5c26804947363471ce4123b13c795dd1d8\n6029a952aabd0f198f44c10d19c5f723c09bed83\n391e0332d0e660b311ba85d898db3a7c039e6760\na1da56616b49b52f361d50a0b25f8c66023f4ba4\n28b63762e543e33f27ab81f6d8a2ad3ac64e53e3\n07087fbb0f73dee2533ee70341010d9e0062bd5c\n32f58eaaa31202ad46c3c2a0ea35cc5d836f010a\n4564344e9b77bf516fb5a07b91b1655225154b40\n5bbd4c7b7df078f54e0c26cf169329ccc8e365cc\n9198cfc12bd27a990da310f2b96e70a1be64cb83\ne2962d8b9f598fcb1075055df94247841997b9e0\n14240b0f790c47c7241187517d038a27b94f5094\n20ed35dcf1b6efc77df78ca243a16106fb99de98\n5dbe49f69ba15ae1f2b1ac7712afa34010fa2e48\nbff097fccbdd91c69a54394a6c5260763524398c\n76cbb37ee91407710d8906bed0e7dcf01774ef5a\n147364037fbc6f216cc0fdb502b4820b7ccaf735\nf849d721c488ca2497039d071c3ea8ec7acd63d8\nc213f0f7f35cf3faf5b0ca5b6c700e4f02f8e2cf\nb91e282e6261e29b8f1a90fae53d5b29abdffc22\n86ff1eb5d0b0699abe213c159eed071ae6b2031f\n32ce52c51f569ed8a67aeb5f67d228a2c2a37df9\n8611ed3807aae07c9eec3f5ab635ae1fc9bda586\n07789be117ba06ecc7eeebadfbed035a9abfcad0\n9db9bc38b195c70f54fe92bd93bab8713becdbf6\nf99cb70ab985fd788864b67d1d9c79690adf9e21\n9107fff2781d95266314442a771087b432f7f9a5\nec2028d605e53403da2519aa5ffb12bf5424ac18\n7dde356764e6c1974abf01c7e3f2e953659f8f4c\n0c920382987d0e94404bf3f0ae2b0115c6354c40\n764b7e9bcaa5205bedda364528269b35a13949c9\n361d3fc869b6e3d76c0e3989c16eb7424815bcc1\ncea9a00fd5b37882becf5742ff8d524075ceff16\nf028e475a161a7d24f62a7935878458cf087b321\n191ef86c2fe5f7b94b6ac1ff40fc097ce683c778\nb92ca8e951aed4bf4cc58cef1bdd926dddebe09a\n33cd8b39c825903e323959728841039fb26cea09\n37b11534f019559ba2bb81b8f24c52e890acbb74\nc7be41ffce8979e727064d8d25d0cf4cfd5cdd51\nde4d4a17b934b50404f6c9c0d029d1aa1dffd827\n92a56122894dab737ce15bc3c866049fbd15cab7\n0ac40dda1a4f27c38e2cc4b11f1e1b66b650cb39\nfb794d14b9c9c8779b1e5b1d8c1307290302c0ed\nf545286fdb4e1442de335647b642d2db1a819252\nc7573bd82785dba454b55cd20671969ddd412a49\n0bf00a7aeaa9c4e38f88d03d5e5029489daa1c98\ncf96b637f7e95c4c6f579944cefd7d793b428982\n54caefc5789553a8c23fdc90a2c0ae2019544480\n02f05368f78f090c9c4b118620df3760e6c21eca\n5e27b38fcd45edf98593b858c48682efc76d4849\n27352aeb96f36e1141475ade4d251670b6b0e49e\ncdb86991ce9b79812ed2f547958761357bf5d486\nac4f9725e4cb49211eb31b223cdfc16dfc6db778\n2d4beab81a578fea4939def5c826bfed53fc9073\n4a37d4a25091d5fe4f5b0c09e1e08354310fe205\ncff9002af852b300bf8852d45e6e725166a6edc3\n2f0d3ac8fd3777244f42918da015327fb55005ba\n4834c34616bc92c091c6b12342d4fdaa272507d2\n210d9edc22cf19d052ea2ce06855da4823fe6831\nfcb848f243ed9e9d50fd27259917ca2382ef0394\n27e6858e5b6a8f5044ba487a156eed251732dbf8\n730212547fefe6b16627455de9a47ac030045603\na802ee58bf00860d6c7674a6bad4abab12c16c60\n22fe69ba76321a6ede7b25db9b0c0089f4155b43\n8d38438e0591cdc7ce35146f765b244df084789f\nab5b0257ea7df2a10a2cd97334634f93814f7914\na37004ca68466af83ae0e77deaf08bf1d525935e\n08cfee3aeba34ce9c4308d5faace823b91f4e7df\nae4397b1b86d425dcd99cf9f5c99aedc8afffbbc\nbd9d0135ace694f7bad6943dd7617c9d580f8f69\n951adf540c5bdbe7b086d0370d280589b86d99f0\n35f44b517403082eb5f76ab1f2a8bf294387ab91\nf7befd9892f61fdf0ffe9c8465d2db65dcf0e64f\nd12b3ee3401cd7ab498be69314e8fa4437c7fa2c\n7ae00ac9d901cb5cfc94fa3098a9cea9139ab0d6\n0f745e788d39b25aaab9e1ba96ab0bdb2adc4d0c\n4eb8f7d730ab1eedc6598d983b943d7e8aeb32e4\n1c12cbdaf6133e559769f9b2a3a74f9008f4abca\n7e92acae6ca7b3d634de474cc3340a9d05068025\ne63d774f37d54d214d35da789a11266c730d1e94\nb6f06beb80ac409b1902d65fc3d650227066b310\nb5fdcad4a83bf44d3a387ebf8342cda8f1c70938\n3eaafffd7b9bd931c52986daa8dccdcb4e9f6114\nc66db446f05763ba4eca0489eb1e11d8e731efba\nbd541f84301b551024964add094c31dfb1d98140\n524c548f0732abe1969b0ac6f4d5f71d135d1998\nb8174b4546a456ad9a1add37cab57ae53cb9c1d7\n5da292f507b9ef7c04af9bcd8c7f4b2ce089fae5\n6b4274ddf95a39136f9bbcf2d505f14d6c5e4efb\n44ae2c3fadc476bd34b8efa48440d75fbd433e6d\n27b5dc5b6a8e8050297e7b725b8482a6794924e1\n98249c7464e3c318a9be108650afec4565a04449\n0839ecbdca16f687daa831f7d1c101a2f2819014\nd09dd9790d4bdb85bcb7353d416ce11c082730d1\nff505b85c094d1d892ef8dfd46f9d4480eb422db\n7fdfc1d273f9336fb5c2e056f7b40c55da1862ac\n09d1b0d57d739f77bdd36ed6051b810ccebb3e8e\n132e26cbef900e80eae83acd6a2baac091d67db3\n787294abf6ca60f0cf0a9a44bc1cef0d74601dc7\nff7ba376645a01aa3b186674cf5e90b3c3a59f45\nf262008e26afc2877089ac35ca4cd7c07395153e\n6735647605da91a3f07eac660cdaa06f5eab24e5\ne66c50e60b8f3eaddc56ff138ed62e11700b33c8\n3b65365f123f1f137b482888beb1e884bf801fa9\n0758a6e94895d77cb42c24b5177041f50cc9bf99\n9d6fc303cc7879adaed21fb4de5e53b7e187be6a\n00dc92640b9ecec38437e388ba48e37f536847fe\nff0ea1dc250ebf9632063e0a4d88111bced0497b\n1e0438c367e97cee2d64ad2395a8333f5efb5cef\n1447b0929ece9bca977033a553709b04bffa0e4b\n5484be96fa63393d9d08c5c25c6012597b1b72ab\n73304e2317dfd61e4a8583a46f6b39fbf1526151\nbf4a4a255b8c5034e06ada1c185dc06b327b21cc\ncd56528999e8d9ab4ed71f6114e43ee2e2b8d6b6\n1ab5fd17c0df450e1ef179aa34c84a4068db2ed2\nc24a06c4839c176ebfbfab3b671a78503287c6f3\n8f5577bcb150f932eda959ebc9c130759d43e98a\ne909c419f0cddf450d88b1883e0590a69308ea6f\n8dbbb4caa0f29d8904280e3be62a3cc2b027dcdf\nf0d2c45223b5c099bd9d114bce95f4b44ab5abc8\n9cf352fcb9ef9d1e9144c8f649e5a883e3194720\nae5370297ebdefaec5a433a1c0e325e57fb15d57\n761a95b9b1508fa9820be0f5793de01c72888509\n58fca188ed855f17f1cfbeffc30afdfe26b2a8bc\ndb65a0d6830bf3e93f56b347b5206e28a7e481ec\naf561b8ca7ed1024bdf962d0946db30f95b53202\n28c64c1d75a9e95f2d8b750d09e174eca3c987ac\n834ebfb0d902a055599872e179578a1e54208d70\n93f62a8a179e6ed91171f95ffa3d3727660dbedc\na61e1b35f3435396eecb6aa00a0c8caa8c1d93ef\nb73c23991e3b6e11f21e8a2b51ebafb6059a5ff6\n02baec012fccb9ebc73b7afc102d4244bc32c15b\nba4b3ff06fe8e1df788f97dc20e7c3fffc3ca27c\ncfc72f337dbed518964f5852b2a38dc52021a84b\n48b7b855e52b83afd22a10a9f0926833c284dcf8\n70ae1c6fd072f4ad0f7eb1f67d1cf37cac36c27e\nfa9c9b28ba79f14b45d2a51f695025fdb366af7c\n2154e662154cdec0a59f64a0c6f82930b1e003ce\nadd5c3f5847fb895fe15a37a01bd644f23d689b3\n311e3548b106e422b59035fc593075ff95eb9f2d\nf6bb31e17d6e32e84a7646c00d9e23bc4422373b\nbecc22b78257dff32ed5d8cfbcbf57b72d6fc168\n3b572533e5b3412610daff8cb21d9172509b2150\n70c30b50ec29ec21c50a5934f032a4ea9c699202\ned9e99d0fb09728530d8d68b54e5841d0ab267df\nc39501f672a4879ae408c485eddb876d3682d657\n3b2f66eb45c2a2c6704b887dcf140d90c70f1dcb\n285a9d33709efacef52eef2201926b08005be113\nac5bb10079b6cd58a734dd3445c722d8664b5a5c\n65c10ed0f1bd81da08c51de53298121116650e01\n5dceb055ebd4e1a3dc0843d7077f648fffe4fe3c\n5c26bf3bd46c7e7f75688250acb05c7a2665f043\nfaa298794394c680bd2f83d2a47edd241bddc530\n03db58baf0ab84eb69cfb47578726fb81f7059bd\n05f66907a30b0902d16b58bc45a662d90e30a86f\nf05b80168fe05885c2740b87b258a93d9ab49403\n1e47bc6c985fb49db07c97d3079dffd4d661bcc2\nc54506d2414df5e2882c7a7d07e35fa0f620b1d5\n94154ece4aba7268e01aa3ad9c6ef2001169c231\na53181a76a0ac7aeda8c8f679473dd4458fe4db5\nc14bc2c845cc04e31899f0cd8f410968b26891fe\n0159be6489df068f3899da562eda157a574d2b07\n8721db6bc4f8b4608e32ee0b1d38fce8443ae300\n83aba18ba2b74b645a5bf673f2e451137e5bf90d\n2a5858c627821eef4505884f963f2ee3ea284c63\nf35e252d4f07ab30566d0fcd8f6e92eed0b60270\ne3b46c5418157574a6093ac9c4595dac2e2eb24c\n394c52f31b95e05146703e227d94668bf419e552\n1fba9fc5e0cb455cbb3b7806ec93e34adcf9a6e0\n1c39589d4545d01ae27194c2f55ce0e919475547\nbeda07ec1bb34fbe53f5f9b89b08bef81d371b2b\nd699a2c4cbe3fa8d92dc591dc7a3512d7e5adfb1\n1e32558b2bcca600d73008c79db8a6604ff4a11c\n99fb490af556e6445c6e3f354fbb4ecaa7080745\nfd87ce4690c68eeaa37e65484cf989fb51b8d01c\n55247735744cd2655a274eb87f818011dc8f64f2\nf0bb2eda6ac374ba88cc4779dd34c59acf321c1a\n9e9db18f30939043239032f2047ffa4432bb47f6\ne7bcbb81ef9c11ed4738814b4d5991c94eee9d82\n7727bdf409bd950a17749fdd0e8d8d96386e67ff\n7df051b12980b40685a03c0694160ae4da04c52d\n0be10f906c32c35c478c8c9324d9cddf0770ad07\n6fab5408a6bf30f14e53aae89d9f13a1079f10fc\n33edba67a332f0e998c66b05469b9b52235ef08e\n68fdfcabc42eff487be3b7fa05e0c793d9107e27\n5e7de6f0cb355f89a7019b30e8b4962693f956b6\na10d70c1d0ca33aa5ba649e80ea7556afa7682d4\n3dff93e715dd42d376dc3c04fc9b4667666123c8\ne23951020de5d3a78aa04a2b08ef182d49d3f039\n250081cd39e22bf6f9733779f0c781a0d110e5aa\n222885ab8f01d7a157d4421c3c6db2ea9c973701\n57ceb1680ee534357bb0ec989cd99be05047ded3\nb46145e05749b9cf06ffc179dcd0ea680247d996\n4efe679a3b8d451636f706dff7a09d64c751026b\n64f9a7cd50b91544fcf65dc3e22d0304b230c263\n9e4ba7f01d1c79af73a2e12d22df5ca37c9f3bb8\n7133d31639cd7133b94b141efdb7d2fadd15ef67\nb93ea1064e52ab6f6a9306d2542700da6dd3a0df\n13c40f1f8cb56ff82662ef8e43160c96c25526a3\nb62dda463c0f91515856c25f8447928130fe46df\nae7c502c0ad4b43aabc782d8044f6c67206b3208\na135561befd207d5cbe4e87503df567846fc3236\nc9f85563f9d6e0c65999538078eb48f232e83052\nb56dcddaf495d6d1053a1673d593f01f19f3824a\nc0713ace7f592b600a85743575999db9dbf16b61\nc836318a9d35edc0669b80c08e2ce21869dc63d7\n855d89370b3c155be6208c984e4b981576008640\nc29d93ae078c252dab48dbc3ff201e6f80882de2\n36914f1dca691694279de49167617aee1ad4fee6\nad7a53185ace24c942585252e1542e35902a5276\n6ebee4d5dab275392603d8acf53d27e51efe82b9\nbb51908e5264a85077754c0b8390571fd2b5d2f2\nf59256a777243264aaad32c08da50ce61e5aafd3\ne81fefd4d2f620119d5c789729a45d08185acf84\n8651fb11512de420cd2c6687e8a3bd03b05892ec\n4db68421d9ea1f37cf0be2c0ea388cb05848620f\na24e241ec6e0011f7f6b950b0a56fbe714cb3eb0\n95f66637a4711b0a7bb5e06316b4f6fe9aa83a37\n770fce1209439407c9500acc36a21f4a9a7031ed\n3269a81c2b4d0aa79aed7e1c4467180fcf214f8a\n0368fc7a2d890cd80da11bb4b89fd325af2df559\n191a0343d2f969f194befd36fef8e9f432b6b3d9\nc23c69bcf522b672b654ea8aec16b219a95d73c1\n3e9a9f061b52dea83c55b976a25ee39c97a6bf64\n27f754abf04446b8102095cb312aab7953cfe31f\n291a7f6265cf654a41589159da424f90751e491b\n0d52de1ba14291cb65380e194950af6c7769bf97\n75d3f2975a79238548595023c6ecf0e8ef86d36d\n240641cc122a74924ccc7b2e44169a363917a983\n34a6a295030cda5d52cc898dad10f348c9fef508\nde6bef6af7f248eaae9b6ec2e108ec9f7bfc7d04\n87acffb2164e8eebe170659acc42056b36e7dcc8\n7a0e555bbe4e5f8030d7fa3b7257b5cbaeae172f\n35b9ef54b6beaf135e1f216cff3f573419b80b4a\n7f7ed75158d481fcc1117db48a55704290184c8f\n2d1bc225629e16da6ae35d559ad7b5cae6930e9c\n3d3c03dd20493bdc3cbee759b146a820b78025f9\n4548a296673d899fb900d0e029da7d6452d7c75d\ne94c57f1aa282c00ce9cc8324d4bd3c758b562ef\ne8d2504216edcbb9f1875fb4319a43a43ca7ff53\nf33b045ce67bff543f5ec2ba61042a0d6aa73b20\na8642ec4d43b6c77f37091e3f04c29b6959d90c7\n192f027ff6c566e48fc5784c6c834e1d88542cf1\n4bb918a9130f7f41c87992fcec61bcbf38112fa1\nf5ddea0f21febef81d5facb4f039ab8ca453b755\nc09a8e2adb85460d0b02dfc734828cf817211cea\nb55651478d414790341ad9f7ca200c29e51697c1\n0c86d7e77bce899a76c1f20c7822fdc48d684c75\n53b45a44d70e2b721587e81775be0a647742dfff\nb026b5f7841fce0d4f0a81f3938cf97ba74d93e3\n3e8208f3b9c46344e9e4f560fc52604d4bb10bb5\n3435621f2e36032782c5e42b4a3d2238e7527ad3\n578f3cec71e6951846bce32b47b565329d36684c\n301e46c92e22612a8902df4a0005a25e22b0dbd2\n033fe8d23dcae3ea0c1b8fa880e91d6d45eadd7f\nc4bb413915ffa0fe044f1415a527eadef6f3bb69\nd14e492695631115665019aa929cc6f10ca412f3\ne18bad084cddf11bd16badd2012ede29069f24bf\nfac8f4c40f960a613023cc476e015b05cf6bbf3b\n947a7967f3c872ab4f985d89239e4f2975c0d015\n8d31289960cc9d3c19870b344a1100131ece2bac\n057e430fb6a796e45a80ac4e89d8f137ca778257\n704396b8aa5196a616f48cba54d8ac38855c6e35\n6a6bbb14d275d4c2a767915e864341bd0f344598\nc5f7ac84b1dbb70d2fb755fe98adf068bca10dce\na8c4ca5ab86d76b21d1bcb097590982b50748c05\nc17f3e70b65bff196aaef80936794c53982e617f\nb80eb90f56b7794638821c9501e8852303e16787\nce9223d5e0c19791b8e06c3650dba8a51c44eb8e\n3bda66f0b582c38a649bab414b86d147d73552c9\neb05670152d4a107069d83fde5ac9324780c90b9\n1da96c8da108b054741fd3dcfa3cdb86ad5a58bc\nd409fc1c4ee61304065193a2df33f6e6eaa3ab05\n8e0f34efff47c56f6d5c71c2654c5bdced8237d2\n54ec92d0bf35e3ed64ecaf9a3812bb5012a05d21\nc70d9c4b2666c8711c87705d878b07273c988394\n37623d0bbd9c8095dc35b57236d3837a91796ce2\n99964b8812c154f66b50503d9d0022f54fe2fe52\n88849a942835b3ca16ef04a3c5312263a5d591f3\na5a7d25d2e77a2735a446490a6b27bb471c17173\n2dde51e5cf4f13cbca5e1ffb540dcad4c7f3dec3\nb52f327579819fb28e9136636da64e553e027115\n3581055d040424d7c3c511a53e0766da385f6d5f\n8c369f08af585362e8c96334c0c52880d6730ffb\n9c6c2ad4c331adb680a81403815d52e2cbed9b31\nad74ac2a20eab5d0cc352c7018ce276d3c3d4092\n2724bd90d60999929de932701b287d3e5958fa68\na99840f057b107de49976439a4bdfbdf3b143567\n63460f04342f39053efd426beb3abdaa177482c2\n08b353f4da75620d163b4843f5af0eef89679364\na70741b10914007e045e387346625c759e781d45\n971198333b68bc431a46f2141efe51e9c767bfee\nb6c7cba874e514e42f00cf5ca4724d86c052e749\ndfe54efe5e7c2fa6ef296ad075aa00f8f840e0fe\n5aa48921866ec3ef7858a91aa5eff42c808bdf68\ne0e5a71751cf4dd017610a27d5ccf6b35b611e03\n3733fbeabfc587a2a8c49cb16d35f47a3d8fdd59\n24d801a09457f943aa79b295dea7e18b5252f2f5\n95230b490eec415b4c945c8d52d69e606c2e0788\ne5e738d510dd02f8f25444558e3232dfad8c1fb0\n537807082cdb7ca5b4be08a8c9498f234e9ceb76\n8b2f3602e053d7d8881c704ef1e72d5b4a04d144\n509ece8eb495ff215c6d4e4405aa9033de52cac3\n528b349697f8f995a10ab9b0c169e9f2b6a492b4\nda696fb1b4efeb6a8a357f3a6155f17421d9ddf2\n628ef5e92e75abb63c42d66bca99005c9deb9a53\n85f758e5c670997d630434f2e522e3445144689b\nafb7a03abab90015cab89e34896988ff782ca0c2\nad2fb97d6050e86ddcdf39a7e156f99e3d7d7911\n63ab3c20a8ebb0e2ba94ea0bea00d2d01b4a9e04\n59f09bea20aecd72efa7abb041eac4b15cdbab67\nb687b2ecd13c33e459c93f6383d05cfc22b39795\n0c87b3975ae3523152230b4a4e67f1a404dc80fd\nff05cb14438e3e7ae62e42401ef87a49deaf279e\n301a41716e787e8e5aee031f6bd72a82fb989d0c\nc4c9eef20a2378e420deb16a9668fe44b4838b25\n70d3b56795727d24ef81073251d54ed415091ec1\n94460aae914a3755fb470bc623ea5b419d562cb7\nb7d6d9ab5eaa494acedba09ca294d05cc7834e29\nc388d9274c942134bdf6e1c4cc5ea2bef9ef8e1d\n299e5b72428a6f7d796ae9e0f491a5471d3d9f8e\n4383c49dd862d323b34ca9cb16983a1f817967b1\n071975f731e1a1815aa733fdddf8e28abb1df283\n1ed7f1717ba6e589b6aa841f9563bc4ed9f272c4\n8884fb1cd7475ac97d6c7e6f2751d0fce4993c91\n634cd3e9439d2f60acb2f8b311e998f2b8e57d96\nfaff4fa49d076b7128fbd6bd71f6383c988300d9\n83089389b4172eee5d741657f49009efe6c9146d\nec5fd76437c019405faae91a5e17541e4022c606\ndc049c4169284bf6856d5eebe822758132ab25d5\n4f8f4177d624e3ddddb5aa4c19799a650b2d7645\n024d3e2d38a065bf2794d652738abc63f9b65889\n10c0835cb10f455f1700f8fe1039b5aa7a35a1b1\nb0ae157b84ade898ea096f8196b9fb3f2f25bd1b\n36d6dd5aa657bbd885f1e67d0c47dccd3416401f\n3ea4b03e09d85b0baef58bd6c2c440922a79774f\n23c092bd0e4f09087a0de780b0b1a885d5e88fd9\n7426078ae4c9302cefd84709ea69eddbbf941669\n94d15fa123aaf49258fe5cb558e707828d192d25\n5b290528a3c03562b5975a9034c12d8ea81f3e47\ne9f53dc644daae9b3a0db87a8359ac166aa44217\n30aeae10f087ba4f9fbd837bac8d7a4aac4f1e72\n6abaab364caa20a0f41bcbd448407285370eb601\n14c4efcb4f076672cde9f25d8a1aa4727351d4a8\n90d5939b0803320d47798206ef6a0ca81ba3b286\nb5953e4fdcd09c6c850eeb802520a2d35b2208d1\nad4b9796f6030980eeffb28eb0a8b0ba3db826ae\ncc573179d34b369aa486ce3a2e7ebcbf883f491f\nf9d93d8780889098315692311dafbc73de5d75e6\n338b1619fd1b9fc5ccd2504790946e360b70e4e9\nd6abf45c953781260ee770fa9c54f9d99eb4d5da\n9d0b897fc08618dfb7a7f9908a5b0e3e669d71ff\n5901fb72525891a55af21445840b449443908866\n97f1a5d0ad91d0b9454ecab37abe320ea1d51612\na741103ec078f0653d187bb88b14e68b5368b351\n39727c36b3ddc4a77698a87b350d98a28b9d1183\n69ea1593543951465ae2d9f245c390029bf8c896\n9435e131bc073c1e53f7d66e98382c01f17acf63\n032a27233b9a2eb5f5050b094efb76f7066667a1\nb6cb07bbea9c17113c865c0497a97c951c6a68b5\nc376a8f5582cfb88dd6fec7b36aee756c700b413\n06d1edc3affcf5435056787592728f027bf2bd61\n95d5f448b23d07623858e493109225ca8dc88746\n37c0cacff61bfb7f0caae823a052395e3b0504b8\n2d557bcc616f9355023b2cc5dae5543c08a1b9dc\nefe49f9cf026814a2d951f55240befbaaecc559f\n9f500ae0e019127e0d40a0973b92a085913f6196\ne8b787f78bb3545e6a7ed6bc777e3f02fb37a5f9\n259ce5a2e67cb762d89c6724e2520691990c718c\nbd5461a7d9725b94b3eb053a81c70679ef22c6e2\n052a8603eb0e124a5eeddc6eb1104862e720fd68\n7cdcfa95ae4f6b22ed39732c056e1eca7780c3c2\n933a15307224a5c47e3dfe5a2989e213e6e06a0f\nc2913d0309c2f07c5f9a28794770fadb91bcf21e\n786ad302ca269d6ca349d01528ace50ab777c092\nac26430c56e85e187aba6b69ce58bb9bc9cfcd26\n4a6bb8329d4af0020e1822ba26960b60e0b8aff9\na329b2068aaf922653f453ba85f68c38209762e9\n5be5f3cccd9ad04c084e9584384ae09d87009fa5\n7bc1c25d18fbe6719b5cb39ff11f40e2ade3b375\ndcac375584ace283f6a106fd41b6cbd40d889564\nb2221cc021baa74180b13aaa61e05448333288a5\n46fe8f240291f254674889355a1b33c24d943b83\n9ae59af831286b076aeff9de67b05ce40801d3f2\n3edbfa792592fde4e9a7d98526528c30db636598\n6cdce78df644f5a175d7a0abef9bd0b281ad0cb8\ne9d81f3b2dd6cde7d5d212f74474f60e8d8f90f6\nc4f16b93b1b82c69d1f192b223b4d5b204c2b95b\nc69b242faca89db792715718d8f39745d7a8a6c1\n684cf5c6ba2d461b3126585fb10d6942771bffae\n4ec0e5bdec05a703cca3e0d68bc3b2f8e959f4ae\n7e436bc2742b6ce9612f2e7ac3504c3de1db226a\n75b126e183c45f9b1464edda03b5c6c06933c763\n0a7fa31cbe885d7f8bb2ee7929b7610138caaf41\nbfdab5f475935d2717c6fa191ef1a28673586cc7\n7972f3c4497fa0e81eaf23c730137af1ebe19639\n53b9c331d66a1d7711c94a704e769c63b4a91519\nb41219dc0d19bb0a54b5c7de434fc722a5e1a47d\n9159674e94c713f242a307a6832bc01f852a7c2f\n3d990a81bd977abc838414c98b32c1310aa5d271\nd53d87ebd24b443905fa3ca0c6638ecffd570872\n3df468e522b95ae789105781ba3e14930a0d85e0\n38602650784f5f409c183cf30a46a2ae4edfb212\nff7ef56976335ed32322e2e348db02c802cacdbc\n584c5ede37b2f6d4a6f29246842384410a0cd097\nf90924ad6a875c38e4fd2342346ee05785cf4da9\n8d750aaa93d701ac15ada73bc82cf2a32d87783a\nbebfd4795f48686171089f4f51d8cc93e5e4c784\n9ae5553d160cb853e199fed48470b8d7f832c422\nbc4b2a23b0ee23337857927581ae3ce996260f11\nc46f3cbc28a0f1148b9c4e44b4bd005f6a8a0135\n4d4826313d46a8669c99e593ac10fbefe393e054\nc3537685f538160e044924b7ca3be49176952109\na5e8bc6ed3371414f76437a66a78713d3ef0efee\n0222b2476dbf60fec9a690e59967ff3da4fb4b7a\n9a4fe6e465ebe215c05b42103901e3a07d2c13ae\n50534579c99aca0b30d72054cfa3e85bb9c4b26b\nb600fe6f709bd3e98b9963c852dbb7661681ca0d\nfdea953f99249420d54931d75e42df16b4ce3f9a\n3d04918fbeef4e2b75a02590498bd34ef8cdb388\n16528e2d35ea1e7425a3699e0d02d0e789670507\n7ced6ebc3440197e3c187b7b4833c2a145f4904a\n2dea46e18897b5188ed75fc3d7f4eea9e24d69a8\n7d032a5c3a36aaa0ad462ff7cb2f9ea83fedf8c3\n1dc541ff588acf303e354c0336cc8f1e8b3c45d8\nd88da47f6962053358ed5f30b5a377c3926992df\n62a19889932219b76f5b30fb77e32c93b83f9ca4\nfc9ade3080d7026e754add62fa838aff3efd86dc\n7218a517b801bca48a9fece163fc92883dafedb4\n6924b3570172d081a66e7159807f45c2753542de\nbf8ac0e60852dc5b4a1af243fb2729a9e9b493e8\n9781ccb2301331ebb35015d398aa1092f57b344f\nedb49650ba981135ace46bb226252be5055a5ee9\n0d29ff50a9ab109ffd0b728be46f1f322d765369\nfaed7d64ffcc51daf029ff5aef2665944fa17578\n6f9127fb65505f1b9b1b02ef6eb92a8416ac6c16\n6009e9e5f5cc30dc3f5de3495fa9b67500048e3d\n4705ff82c818e95b6e162a7b1e4b6c0dc7ac1e38\n617c7b2190a29940a4320bc75e4497706df82255\n343b4f1dda4332dc77f4ccc004e93b1719637c65\n6b8bf866875c67ea425a90e97e8a1ade563413b1\n16852ef0640ec249123398cc607609a96b7dc024\ne6ce1407a5cd6313574c4bf3f693ae547e886844\n7d196be2a15dc5f2f828a91c288e3431423510db\nefe54c7d11c8bf2d972179e6b6adbeb2b977afc5\nc457dd9cec33fc6f5e881129d3adec8e73aa0d6e\n5ebad72363c6c3623abf1a7d85d4601ba4117144\nb4e104012d5e5be3a5de3ef2ae9ab727a0b23b2a\n340b2b4027e99b08d33235369fe69d074d36d248\n5b754309edbd85fb442c4be575ac3040de42f317\n26366a0dd458e5dd7d4c650761f0e0ec105ea0b2\nb9fa636790213b58503f754b224c701837c8ef2f\ndeb2710714caf0bfcd24d2dbda7877c7e01e66d8\n620c6fb525ba234ce660d2f1f58ee3a1aabdec87\n076606da92616bfce55890cdffe8a39f3d4b74c8\nb77983011a7e4c592bb745e9a24feb9c47a305df\na6f051368cea580e614542a4066565ad99377f2a\n5aaf1d2af07949bc1feb0f8ef03175b29a8c7f90\nad8313a02be37351373a734d09727b5040d994ed\nbb743d0d3a50ceb89777945e1af9da53ee5999cb\nfcb736624eadf7d71f629447eccfa3deb3d194b7\n3af0fe5be546374a5d95f76f61e6b029ff9ccba4\n65525f9b902abdc4ccab7d2649b7a8a1a51b66d6\nfd323ad3de96f15d7af57ab80d6aee0068541b91\n493d0bda0f4a6fa44ee5ac2df4890f340bae7bb9\n18ae797422d03bee698d0367ce548f6aaa47a94f\ncf3e3599b44564c4fde23acfd133b484ce4b24a1\na033da41003eba2f92b1cffcb06c2d93358cdbd3\nbc3cb303712c6f16f8a786e45cb58e6a913f868f\n9362ed016018f6d443c3795d330a0e4e271fef4c\nf6fc9dbdfbac2bfd6c6cba89288d66cfc27f7808\n41af4395725e35c303210b98aeb29d71c9f150d2\n1299a6342ef0802988ae7b5ae0aed9b917c87b92\n2d77111fe3048ac93791c3fc41baf405f4d2513c"
  },
  {
    "path": ".config/insta.yaml",
    "content": "test:\n  auto_review: true\n"
  },
  {
    "path": ".config/nextest.toml",
    "content": "[profile.default]\ntest-threads = 1\nslow-timeout = { period = \"250ms\", terminate-after = 4 }\nstatus-level = \"all\"\nretries = { backoff = \"exponential\", count = 4, delay = \"1s\", max-delay = \"10s\" }\n"
  },
  {
    "path": ".cursor/environment.json",
    "content": "{\n  \"name\": \"mise development\",\n  \"user\": \"root\",\n  \"install\": \"cargo build\",\n  \"terminals\": [\n    {\n      \"name\": \"Build\",\n      \"command\": \"mise run build\",\n      \"description\": \"Build the project with cargo\"\n    },\n    {\n      \"name\": \"Test Watch\",\n      \"command\": \"mise run test:unit\",\n      \"description\": \"Run unit tests\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".cursor/rules/analyze-product.mdc",
    "content": "---\nalwaysApply: false\n---\n\n# Analyze Product\n\nAnalyze your product's codebase and install Agent OS\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/analyze-product.md\n"
  },
  {
    "path": ".cursor/rules/conventional_commits.mdc",
    "content": "---\nalwaysApply: false\ndescription: how to write commit and PR titles\n---\n\n## Conventional Commits (REQUIRED)\n\nAll commit messages and PR titles MUST follow conventional commit format:\n\n### Format\n```\n<type>(<scope>): <description>\n```\n\n### Types\n- `feat:` - New features\n- `fix:` - Bug fixes  \n- `refactor:` - Code refactoring\n- `docs:` - Documentation\n- `style:` - Code style/formatting\n- `perf:` - Performance improvements\n- `test:` - Testing changes\n- `chore:` - Maintenance tasks\n- `chore(deps):` - Dependency updates\n\n### Examples\n```\nfeat(cli): add new command for tool management\nfix(config): resolve parsing issue with nested tables\nrefactor(backend): simplify plugin loading logic\ndoc(api): update configuration examples\ntest(e2e): add tests for tool installation\nchore(deps): update Rust dependencies\n```\n\n### Common Scopes\n`registry`, `aqua`, `cli`, `config`, `backend`, `tool`, `env`, `task`, `api`, `ui`, `core`, `deps`, `schema`, `doctor`, `shim`, `security`\n"
  },
  {
    "path": ".cursor/rules/create-spec.mdc",
    "content": "---\nalwaysApply: false\n---\n\n# Create Spec\n\nCreate a detailed spec for a new feature with technical specifications and task breakdown\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/create-spec.md\n"
  },
  {
    "path": ".cursor/rules/create-tasks.mdc",
    "content": "---\nalwaysApply: false\n---\n\n# Create Tasks\n\nCreate a task list with sub-tasks to execute a feature based on its spec.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/create-tasks.md\n"
  },
  {
    "path": ".cursor/rules/development.mdc",
    "content": "---\nalwaysApply: true\n---\n\n- `cargo build --all-features` - build the project\n- `target/debug/mise` - run the built binary\n- `mise run test:e2e [test_filename]...` - run e2e tests\n- `mise run test:unit` - run unit tests\n- `mise run lint` - run linting\n- `mise run lint-fix` - run linting and fix issues\n\nDon't run e2e tests by trying to execute them directly, always use `mise run test:e2e [test_filename]...`\n\nRun `mise run lint-fix` and `git add` any lint fixes before trying to commit.\n"
  },
  {
    "path": ".cursor/rules/execute-tasks.mdc",
    "content": "---\nalwaysApply: false\n---\n\n# Execute Task\n\nExecute the next task.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/execute-tasks.md\n"
  },
  {
    "path": ".cursor/rules/plan-product.mdc",
    "content": "---\nalwaysApply: false\n---\n\n# Plan Product\n\nPlan a new product and install Agent OS in its codebase.\n\nRefer to the instructions located in this file:\n@.agent-os/instructions/core/plan-product.md\n"
  },
  {
    "path": ".cursor/rules/testing.mdc",
    "content": "---\ndescription: how to test the mise codebase\nalwaysApply: false\n---\n\nTesting and linting commands should be run via `mise run`.\n\n- `mise run test:e2e [test_filename]...` executes an e2e test\n- `mise run test:unit` executes the unit tests\n- `mise run lint` runs the linting commands\n- `mise run lint-fix` runs the linting commands and fixes the issues\n- `mise --cd crates/vfox run test` executes the tests for the vfox crate\n- `mise --cd crates/vfox run lint` runs the linting commands for the vfox crate\n- `mise --cd crates/vfox run lint-fix` runs the linting commands and fixes the issues for the vfox crate\n\nOther tasks can be found by running `mise task ls`\n"
  },
  {
    "path": ".dockerignore",
    "content": "target/\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*.toml]\nindent_style = space\nindent_size = 4\n\n[{*.sh,.mise/tasks/**/*,e2e/**/*,*.pkl}]\nindent_style = space\nindent_size = 2\n\n# shfmt\nswitch_case_indent = true\nsimplify = true\n"
  },
  {
    "path": ".eslintrc.cjs",
    "content": "module.exports = {\n  extends: [\"@fig/autocomplete\"],\n};\n"
  },
  {
    "path": ".gitattributes",
    "content": "zipsign.pub binary\naqua-registry/ linguist-vendored\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: jdx\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Features, Bug Reports, Questions\n    url: https://github.com/jdx/mise/discussions/new/choose\n    about: Our preferred starting point if you have any questions or suggestions about configuration, features or behavior.\n"
  },
  {
    "path": ".github/actionlint.yaml",
    "content": "self-hosted-runner:\n  # Labels of self-hosted runner in array of strings.\n  labels:\n    - macos-14\n    - buildjet-32vcpu-ubuntu-2204-arm\n    - buildjet-16vcpu-ubuntu-2204-arm\n    - buildjet-8vcpu-ubuntu-2204-arm\n    - buildjet-4vcpu-ubuntu-2204-arm\n    - buildjet-2vcpu-ubuntu-2204-arm\n    - buildjet-32vcpu-ubuntu-2204\n    - buildjet-16vcpu-ubuntu-2204\n    - buildjet-8vcpu-ubuntu-2204\n    - buildjet-4vcpu-ubuntu-2204\n    - buildjet-2vcpu-ubuntu-2204\n\n# Configuration variables in array of strings defined in your repository or\n# organization. `null` means disabling configuration variables check.\n# Empty array means no configuration variable is allowed.\nconfig-variables: null\n"
  },
  {
    "path": ".github/actions/fetch-token/action.yml",
    "content": "name: \"Fetch GitHub Token from Pool\"\ndescription: \"Fetches a token from mise-versions token pool\"\ninputs:\n  api-secret:\n    description: \"API secret for mise-versions\"\n    required: true\noutputs:\n  token:\n    description: \"The GitHub token\"\n    value: ${{ steps.fetch.outputs.token }}\n  token-id:\n    description: \"Token ID for rate-limit reporting\"\n    value: ${{ steps.fetch.outputs.token_id }}\nruns:\n  using: \"composite\"\n  steps:\n    - id: fetch\n      shell: bash\n      run: |\n        if [ -z \"${{ inputs.api-secret }}\" ]; then\n          echo \"No API secret provided, skipping token fetch\"\n          exit 0\n        fi\n        response=$(curl -sf -H \"Authorization: Bearer ${{ inputs.api-secret }}\" \\\n          \"https://mise-versions.jdx.dev/api/token\" || true)\n        if [ -z \"$response\" ]; then\n          exit 0\n        fi\n        token=$(echo \"$response\" | jq -r '.token')\n        echo \"::add-mask::$token\"\n        # Validate token looks like a GitHub token (starts with gh and has reasonable length)\n        if ! [[ \"$token\" =~ ^gh[a-z]_[A-Za-z0-9_]+$ ]] || [ ${#token} -lt 20 ]; then\n          echo \"Invalid or missing token in response, skipping\"\n          exit 0\n        fi\n        # Validate the token works by calling GitHub API\n        if ! curl -sf -H \"Authorization: Bearer $token\" \"https://api.github.com/rate_limit\" > /dev/null; then\n          echo \"Token failed GitHub API validation, skipping\"\n          exit 0\n        fi\n        echo \"token=$token\" >> \"$GITHUB_OUTPUT\"\n        echo \"token_id=$(echo \"$response\" | jq -r '.token_id')\" >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": ".github/actions/mise-tools/action.yml",
    "content": "name: \"Setup mise tools\"\ndescription: \"Cache and install mise tools with rate limit handling\"\n\nruns:\n  using: \"composite\"\n  steps:\n    - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n      with:\n        key: ${{ runner.os }}-${{ runner.arch }}-mise-tools-${{ hashFiles('mise.lock') }}\n        restore-keys: ${{ runner.os }}-${{ runner.arch }}-mise-tools-\n        path: |\n          ~/.local/share/mise\n          ~/.cache/mise\n    - run: mise x wait-for-gh-rate-limit -- wait-for-gh-rate-limit\n      shell: bash\n    - run: mise install\n      shell: bash\n"
  },
  {
    "path": ".github/actions/registry-diff/action.yml",
    "content": "name: \"List modified registry tools\"\ndescription: \"List tools in registry/ that have been modified between commits\"\n\ninputs:\n  base_sha:\n    description: \"The base commit SHA to compare against\"\n    required: true\noutputs:\n  modified_tools:\n    description: \"Space-separated list of all modified tools\"\n    value: ${{ steps.diff.outputs.modified_tools }}\n  new_tools:\n    description: \"Space-separated list of only new tools\"\n    value: ${{ steps.diff.outputs.new_tools }}\n\nruns:\n  using: \"composite\"\n  steps:\n    - id: diff\n      shell: bash\n      run: |\n        # Get modified registry files and extract tool names\n        modified=$(git diff --name-only ${{ inputs.base_sha }} HEAD -- 'registry/*.toml' \\\n          | xargs -I{} basename {} .toml \\\n          | tr '\\n' ' ')\n\n        # Get newly added registry files\n        new=$(git diff --name-only --diff-filter=A ${{ inputs.base_sha }} HEAD -- 'registry/*.toml' \\\n          | xargs -I{} basename {} .toml \\\n          | tr '\\n' ' ')\n\n        echo \"modified_tools=$modified\" >> \"$GITHUB_OUTPUT\"\n        echo \"new_tools=$new\" >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": ".github/renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\"github>jdx/renovate-config\", \"helpers:pinGitHubActionDigests\"],\n  \"automerge\": false,\n  \"asdf\": {\n    \"enabled\": false\n  },\n  \"nodenv\": {\n    \"enabled\": false\n  }\n}\n"
  },
  {
    "path": ".github/restyled.yml",
    "content": "enabled: true\nrestylers:\n  - \"!shellharden\"\n  - \"!prettier-markdown\"\n  - \"*\"\n"
  },
  {
    "path": ".github/workflows/auto-merge-release.yml",
    "content": "name: auto-merge-release\n\non:\n  schedule:\n    # 10:00 UTC = 4am CST (winter) / 5am CDT (summer)\n    - cron: \"0 10 * * *\"\n  workflow_dispatch:\n\njobs:\n  merge:\n    if: github.repository == 'jdx/mise'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Merge release into main\n        run: |\n          PR_NUMBER=$(gh pr list -R jdx/mise --base main --head release --state open --json number --jq '.[0].number // empty')\n          if [ -z \"$PR_NUMBER\" ]; then\n            echo \"No open PR from release to main\"\n            exit 0\n          fi\n\n          BODY=$(gh pr view \"$PR_NUMBER\" -R jdx/mise --json body --jq '.body // \"\"')\n          TRIMMED_BODY=$(echo \"$BODY\" | tr -d '[:space:]')\n          if [ -z \"$TRIMMED_BODY\" ]; then\n            echo \"PR #$PR_NUMBER has no description, never merging\"\n            exit 0\n          fi\n\n          # Parse description for section headers (release-plz groups commits by type)\n          # Substantive sections (daily): Features, Bug Fixes, Performance, Security\n          # Non-substantive sections (weekly): Refactor, Revert, Documentation, Chore, Registry, Dependency Updates\n          SUBSTANTIVE=$(echo \"$BODY\" | grep -E '^[[:space:]]*###.*(Features|Bug Fixes|Performance|Security)' || true)\n\n          if [ -n \"$SUBSTANTIVE\" ]; then\n            echo \"PR #$PR_NUMBER has substantive changes (Features/Bug Fixes/Performance/Security), merging daily\"\n          else\n            CREATED=$(gh pr view \"$PR_NUMBER\" -R jdx/mise --json createdAt --jq '.createdAt')\n            if [ -z \"$CREATED\" ]; then\n              echo \"ERROR: Failed to get PR creation date\"\n              exit 1\n            fi\n\n            CREATED_EPOCH=$(date -d \"$CREATED\" +%s 2>/dev/null)\n            if [ -z \"$CREATED_EPOCH\" ]; then\n              echo \"ERROR: Failed to parse PR creation date: $CREATED\"\n              exit 1\n            fi\n\n            NOW_EPOCH=$(date +%s)\n            DAYS_OLD=$(( (NOW_EPOCH - CREATED_EPOCH) / 86400 ))\n            if [ \"$DAYS_OLD\" -lt 7 ]; then\n              echo \"PR #$PR_NUMBER only non-substantive changes (docs/chore/registry/deps), $DAYS_OLD days old; waiting until 7 days\"\n              exit 0\n            fi\n            echo \"PR #$PR_NUMBER only non-substantive changes, 7+ days old, enabling auto-merge\"\n          fi\n\n          gh pr merge \"$PR_NUMBER\" -R jdx/mise --squash --auto || {\n            echo \"Merge failed or PR not ready, will retry tomorrow\"\n            exit 0\n          }\n        env:\n          GH_TOKEN: ${{ secrets.MISE_GH_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/autofix.yml",
    "content": "name: autofix.ci\n\non:\n  workflow_call:\n  pull_request:\n    branches: [main]\n\npermissions:\n  contents: read\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  MISE_TRUSTED_CONFIG_PATHS: ${{ github.workspace }}\n  MISE_EXPERIMENTAL: 1\n  MISE_LOCKFILE: 1\n  RUST_BACKTRACE: 1\n  NPM_CONFIG_FUND: false\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n  autofix:\n    if: github.actor != 'renovate[bot]' && github.actor != 'mend[bot]'\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: false\n      - run: |\n          cargo build --all-features\n          echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\"\n      - uses: ./.github/actions/mise-tools\n      - run: mise x -- bun i\n      - run: mise run render\n      - run: mise run lint-fix\n      - run: mise --cd crates/vfox run lint-fix\n      - uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 # v1.3.2\n#  windows:\n#    runs-on: windows-latest\n#    timeout-minutes: 30\n#    steps:\n#      - run: git config --global core.autocrlf false\n#      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4\n#      - uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2\n#        with:\n#          shared-key: autofix\n#      - run: |\n#          cargo build\n#          Add-Content $env:GITHUB_PATH \"$env:GITHUB_WORKSPACE\\target\\debug\"\n#        shell: pwsh\n#      - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4\n#        with:\n#          key: ${{ runner.os }}-${{ runner.arch }}-mise-tools-${{ hashFiles('mise.lock') }}\n#          path: |\n#            ~/.local/share/mise\n#            ~/.cache/mise\n#      - run: mise install\n#      - run: mise x -- npm i\n#      #- run: mise run render\n#      - run: mise run lint-fix\n#      - run: mise --cd crates/vfox run lint-fix\n#      - uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944 # v1.3.1\n"
  },
  {
    "path": ".github/workflows/cloudflare-deploy.yml",
    "content": "name: cloudflare-deploy\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      dry_run:\n        description: \"Run in dry-run mode (no actual deployment)\"\n        required: false\n        default: true\n        type: boolean\n\nconcurrency:\n  group: cloudflare-deploy-${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}\n\nenv:\n  DRY_RUN: ${{ github.event_name == 'release' && '0' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run && '1' || '0')) || '1' }}\n  MISE_EXPERIMENTAL: 1\n\njobs:\n  deploy-cloudflare:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    if: |\n      (github.event_name == 'release' && \n       startsWith(github.event.release.tag_name, 'v') && \n       !github.event.release.prerelease) ||\n      github.event_name == 'workflow_dispatch'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n      - name: Install mise\n        run: |\n          curl -fsSL https://mise.run | sh\n          echo \"$HOME/.local/bin\" >> \"$GITHUB_PATH\"\n          ~/.local/bin/mise --version\n\n      - name: Install mise tools\n        run: mise install\n\n      - name: Deploy Cloudflare Worker\n        run: mise x -- scripts/deploy-worker.sh\n        env:\n          CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }}\n          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}\n          CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }}\n\n      - name: Update Redirect\n        run: |\n          VERSION=\"$(./scripts/get-version.sh)\"\n          mise x -- scripts/update-redirect.sh \"$VERSION\"\n        continue-on-error: true\n        env:\n          CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }}\n          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}\n          CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }}\n"
  },
  {
    "path": ".github/workflows/copr-publish.yml",
    "content": "name: copr-publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      chroots:\n        description: \"COPR chroots to target (space-separated)\"\n        required: false\n        default: \"fedora-rawhide-aarch64 fedora-rawhide-x86_64 fedora-43-aarch64 fedora-43-x86_64 fedora-42-aarch64 fedora-42-x86_64 epel-10-aarch64 epel-10-x86_64 epel-9-aarch64 epel-9-x86_64\"\n        type: string\n      use_serious_profile:\n        description: 'Use the \"serious\" profile for optimized builds (LTO enabled)'\n        required: false\n        default: false\n        type: boolean\n\nenv:\n  PACKAGE_NAME: mise\n\njobs:\n  publish-copr:\n    runs-on: ubuntu-latest\n    timeout-minutes: 150\n    container:\n      image: ghcr.io/jdx/mise:copr@sha256:eef29a250fdd774bf429542ba2c8f8e2812339891b530644f13eb260e8b3358c\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up environment variables\n        run: |\n          VERSION=$(./scripts/get-version.sh | sed 's/^v//')\n\n          if [ \"${{ github.event_name }}\" = \"release\" ]; then\n            CHROOTS=\"fedora-rawhide-aarch64 fedora-rawhide-x86_64 fedora-43-aarch64 fedora-43-x86_64 fedora-42-aarch64 fedora-42-x86_64 epel-10-aarch64 epel-10-x86_64 epel-9-aarch64 epel-9-x86_64\"\n          else\n            CHROOTS=\"${{ inputs.chroots }}\"\n          fi\n\n          {\n            echo \"VERSION=${VERSION}\"\n            echo \"CHROOTS=${CHROOTS}\"\n            echo \"PACKAGE_NAME=${PACKAGE_NAME}\"\n            echo \"MAINTAINER_NAME=${{ vars.COPR_MAINTAINER_NAME || 'mise Release Bot' }}\"\n            echo \"MAINTAINER_EMAIL=${{ vars.COPR_MAINTAINER_EMAIL || 'noreply@mise.jdx.dev' }}\"\n            echo \"COPR_OWNER=${{ vars.COPR_OWNER || 'jdxcode' }}\"\n            echo \"COPR_PROJECT=${{ vars.COPR_PROJECT || 'mise' }}\"\n          } >> \"$GITHUB_ENV\"\n\n          # Set build profile\n          if [ \"${{ github.event_name }}\" = \"workflow_dispatch\" ] && [ \"${{ inputs.use_serious_profile }}\" = \"true\" ]; then\n            echo \"BUILD_PROFILE=serious\" >> \"$GITHUB_ENV\"\n          else\n            echo \"BUILD_PROFILE=release\" >> \"$GITHUB_ENV\"\n          fi\n\n      - name: Build and submit to COPR\n        run: |\n          ./packaging/copr/build-copr.sh \\\n            --version \"${VERSION}\" \\\n            --profile \"${BUILD_PROFILE}\" \\\n            --chroots \"${CHROOTS}\" \\\n            --owner \"${COPR_OWNER}\" \\\n            --project \"${COPR_PROJECT}\" \\\n            --name \"${PACKAGE_NAME}\" \\\n            --maintainer-name \"${MAINTAINER_NAME}\" \\\n            --maintainer-email \"${MAINTAINER_EMAIL}\"\n        env:\n          COPR_API_LOGIN: ${{ secrets.COPR_API_LOGIN }}\n          COPR_API_TOKEN: ${{ secrets.COPR_API_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "content": "name: docker\n\non:\n  push:\n    tags: [\"v[0-9]*\"]\n  workflow_dispatch:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\nenv:\n  REGISTRY: ghcr.io\n  IMAGE_NAME: ${{ github.repository }}\n  GITHUB_API_TOKEN: ${{ secrets.MISE_GH_TOKEN || github.token }}\n\njobs:\n  docker:\n    name: docker-${{ matrix.flavor }}\n    strategy:\n      fail-fast: false\n      matrix:\n        flavor:\n          - alpine\n          - deb\n          - rpm\n          - copr\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      packages: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Log in to the Container registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3\n        with:\n          registry: ${{ env.REGISTRY }}\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Extract metadata (tags, labels) for Docker\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5\n        with:\n          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\n      - name: Build and push Docker image\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6\n        with:\n          context: .\n          push: true\n          tags: ghcr.io/jdx/mise:${{ matrix.flavor }}\n          labels: ${{ steps.meta.outputs.labels }}\n          file: packaging/${{ matrix.flavor }}/Dockerfile\n  # dev:\n  #   # Disabled: getting 503 errors from mcr.microsoft.com\n  #   runs-on: ubuntu-latest\n  #   permissions:\n  #     contents: read\n  #     packages: write\n  #   steps:\n  #     - name: Checkout repository\n  #       uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n  #     - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3\n  #     - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3\n  #     - name: Log in to the Container registry\n  #       uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3\n  #       with:\n  #         registry: ${{ env.REGISTRY }}\n  #         username: ${{ github.actor }}\n  #         password: ${{ secrets.GITHUB_TOKEN }}\n  #     - name: Extract metadata (tags, labels) for Docker\n  #       id: meta\n  #       uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5\n  #       with:\n  #         images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\n  #     - name: Build and push Docker image\n  #       uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6\n  #       with:\n  #         context: .\n  #         push: true\n  #         tags: ghcr.io/jdx/mise:dev\n  #         labels: ${{ steps.meta.outputs.labels }}\n  #         file: packaging/dev/Dockerfile\n  #         platforms: linux/amd64,linux/arm64\n  # dev-test:\n  #   runs-on: ubuntu-latest\n  #   container:\n  #     image: ghcr.io/jdx/mise:dev@sha256:aa27808f06b3a4ca146108cb0be95e621bc5d0642aae891c5445a5a018c99df2\n  #   needs: [dev]\n  #   steps:\n  #     - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n  #     - run: cargo install --path . --debug\n  #     - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n  #       with:\n  #         key: ${{ runner.os }}-${{ runner.arch }}-mise-tools-${{ hashFiles('mise.lock') }}\n  #         path: |\n  #           ~/.local/share/mise\n  #           ~/.cache/mise\n  #     - run: mise install\n  #     - name: mise run test\n  #       uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n  #       with:\n  #         timeout_minutes: 30\n  #         max_attempts: 3\n  #         command: mise run test\n  dockerhub:\n    runs-on: ${{ matrix.platform.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        platform:\n          - os: ubuntu-latest\n            tag_suffix: amd64\n            platform: linux/amd64\n          - os: ubuntu-24.04-arm\n            tag_suffix: arm64\n            platform: linux/arm64\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - name: Prepare\n        run: |\n          platform=\"${{ matrix.platform.platform }}\"\n          echo \"PLATFORM_PAIR=${platform//\\//-}\" >> \"$GITHUB_ENV\"\n      - name: Docker meta\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5\n        with:\n          images: |\n            jdxcode/mise\n            ghcr.io/jdx/mise\n      - name: Login to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3\n        with:\n          username: jdxcode\n          password: ${{ secrets.DOCKER_PASSWORD }}\n      - name: Login to GHCR\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3\n      - name: Build and push by digest\n        id: build\n        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6\n        with:\n          platforms: ${{ matrix.platform.platform }}\n          labels: ${{ steps.meta.outputs.labels }}\n          outputs: type=image,\"name=jdxcode/mise,ghcr.io/jdx/mise\",push-by-digest=true,name-canonical=true,push=true\n      - name: Export digest\n        run: |\n          mkdir -p ${{ runner.temp }}/digests\n          digest=\"${{ steps.build.outputs.digest }}\"\n          touch \"${{ runner.temp }}/digests/${digest#sha256:}\"\n      - name: Upload digest\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: digests-${{ env.PLATFORM_PAIR }}\n          path: ${{ runner.temp }}/digests/*\n          if-no-files-found: error\n          retention-days: 1\n  merge:\n    runs-on: ubuntu-latest\n    needs: [dockerhub]\n    steps:\n      - name: Download digests\n        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          path: ${{ runner.temp }}/digests\n          pattern: digests-*\n          merge-multiple: true\n      - name: Login to Docker Hub\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3\n        with:\n          username: jdxcode\n          password: ${{ secrets.DOCKER_PASSWORD }}\n      - name: Login to GHCR\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3\n        with:\n          registry: ghcr.io\n          username: jdx\n          password: ${{ secrets.GITHUB_TOKEN }}\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3\n      - name: Docker meta\n        id: meta\n        uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5\n        with:\n          images: |\n            jdxcode/mise\n            ghcr.io/jdx/mise\n          tags: |\n            type=ref,event=branch\n            type=ref,event=pr\n            type=semver,pattern={{version}}\n            type=semver,pattern={{major}}.{{minor}}\n      - name: Create manifest list and push\n        working-directory: ${{ runner.temp }}/digests\n        run: |\n          # shellcheck disable=SC2046\n          docker buildx imagetools create $(jq -cr '.tags | map(\"-t \" + .) | join(\" \")' <<< \"$DOCKER_METADATA_OUTPUT_JSON\") \\\n            $(printf 'jdxcode/mise:${{ github.ref_name }}@sha256:%s ' *)\n          # shellcheck disable=SC2046\n          docker buildx imagetools create $(jq -cr '.tags | map(\"-t \" + .) | join(\" \")' <<< \"$DOCKER_METADATA_OUTPUT_JSON\") \\\n            $(printf 'ghcr.io/jdx/mise:${{ github.ref_name }}@sha256:%s ' *)\n          # shellcheck disable=SC2046\n          docker buildx imagetools create -t jdxcode/mise:latest \\\n            $(printf 'jdxcode/mise:${{ github.ref_name }}@sha256:%s ' *)\n          # shellcheck disable=SC2046\n          docker buildx imagetools create -t ghcr.io/jdx/mise:latest \\\n            $(printf 'ghcr.io/jdx/mise:${{ github.ref_name }}@sha256:%s ' *)\n      - name: Inspect image\n        run: |\n          docker buildx imagetools inspect jdxcode/mise:${{ steps.meta.outputs.version }}\n          docker buildx imagetools inspect ghcr.io/jdx/mise:${{ steps.meta.outputs.version }}\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: docs\n\non:\n  push:\n    paths:\n      - \"docs/**\"\n      - \"tasks/docs/**\"\n    branches:\n      - main\n  pull_request:\n    paths:\n      - \"docs/**\"\n      - \"tasks/docs/**\"\n    branches:\n      - main\n  workflow_dispatch:\n\nconcurrency:\n  group: docs-${{ github.head_ref }}\n  cancel-in-progress: true\n\nenv:\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  docs:\n    if: github.repository == 'jdx/mise'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0 # for lastUpdated\n      - uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3\n        with:\n          install_args: bun\n      - run: mise x wait-for-gh-rate-limit -- wait-for-gh-rate-limit\n      - run: bun i\n      - run: mise run docs:release\n        env:\n          AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }}\n          AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }}\n          DRY_RUN: ${{ github.event_name != 'push' || github.ref != 'refs/heads/main' }}\n"
  },
  {
    "path": ".github/workflows/hyperfine.yml",
    "content": "name: hyperfine\non:\n  pull_request:\n    branches: [\"main\"]\n    # paths:\n    #   - \".github/workflows/hyperfine.yml\"\n    #   - \"Cargo.toml\"\n  workflow_dispatch:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  MISE_EXPERIMENTAL: 1\n\npermissions:\n  pull-requests: write\n\njobs:\n  benchmark:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          save-if: false\n      - run: curl https://mise.run | MISE_INSTALL_PATH=\"$HOME/bin/mise-release\" sh\n      - run: echo \"$HOME/bin\" >> \"$GITHUB_PATH\"\n      - id: versions\n        run: |\n          #echo \"main=$(git rev-parse --short origin/main)\" >> \"$GITHUB_OUTPUT\"\n          echo \"release=$(mise-release v | awk '{print $1}')\" >> \"$GITHUB_OUTPUT\"\n      #- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4\n      #  with:\n      #    path: ~/bin/mise-${{ steps.versions.outputs.main }}\n      #    key: mise-hyperfine-main-${{ steps.versions.outputs.main }}-${{ runner.os }}-${{ runner.arch }}\n      #- name: build main\n      #  run: |\n      #    if [ ! -f \"$HOME/bin/mise-${{ steps.versions.outputs.main }}\" ]; then\n      #      git checkout main\n      #      cargo build --profile serious && mv target/serious/mise \"$HOME/bin/mise-${{ steps.versions.outputs.main }}\"\n      #      git checkout -\n      #    fi\n      - run: mv \"$HOME/bin/mise-release\" \"$HOME/bin/mise-${{ steps.versions.outputs.release }}\"\n      #- run: cp \"$HOME/bin/mise-${{ steps.versions.outputs.main }}\" \"$HOME/bin/mise-main\"\n      - run: cargo build --profile serious && mv target/serious/mise \"$HOME/bin\"\n      - uses: ./.github/actions/mise-tools\n      - run: |\n          set -x\n          failed=false\n          CMDS=(\n            \"x -- echo\"\n            \"env\"\n            \"hook-env\"\n            \"ls\"\n          )\n          echo \"## Hyperfine Performance\" >> comment.md\n          for cmd in \"${CMDS[@]}\"; do\n            if [ -n \"${MISE_ALT:-}\" ]; then\n              mise x hyperfine -- hyperfine -N -w 10 -r 500 --export-markdown out.md --reference \"$MISE_ALT $cmd\" \"mise $cmd\"\n            else\n              mise x hyperfine -- hyperfine -N -w 10 -r 500 --export-markdown out.md --reference \"mise-${{ steps.versions.outputs.release }} $cmd\" \"mise $cmd\"\n            fi\n            echo \"### \\`mise $cmd\\`\" >> comment.md\n            cat out.md >> comment.md\n            cat out.md\n            \n            # Extract relative performance from hyperfine output\n            variance=$(grep \"±.*±\" out.md | awk '{print $(NF-3)}' | sed 's/%//')\n            variance=$(echo \"($variance * 100 - 100)/1\" | bc)\n            \n            # Add warning if variance exceeds 10%\n            if (( $(echo \"$variance > 10\" | bc -l) )); then\n              if grep -q \"mise-${{ steps.versions.outputs.release }}.*±.*±\" out.md; then\n                echo \"✅  Performance improvement for \\`$cmd\\` is ${variance}%\" >> comment.md\n              else\n                echo \"⚠️  Warning: Performance variance for \\`$cmd\\` is ${variance}%\" >> comment.md\n                failed=true\n              fi\n            fi\n          done\n          if [ \"$failed\" = true ]; then\n            exit 1\n          fi\n        env:\n          SHELL: zsh\n      - run: mise run test:perf\n        if: always()\n        env:\n          NUM_TOOLS: 200\n          NUM_TASKS: 2000\n          RUNS: 10\n          MISE_ALT: mise-${{ steps.versions.outputs.release }}\n      - run: cat comment.md >> \"$GITHUB_STEP_SUMMARY\"\n        if: always() && github.event_name == 'pull_request'\n      - name: Comment on PR\n        uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3\n        if: always() && github.event_name == 'pull_request'\n        continue-on-error: true\n        with:\n          file-path: comment.md\n          comment-tag: hyperfine\n"
  },
  {
    "path": ".github/workflows/issue-closer.yml",
    "content": "name: issue-closer\n\non:\n  issues:\n    types: [opened]\n\njobs:\n  label-issue:\n    runs-on: ubuntu-latest\n    if: github.actor != 'jdx'\n\n    steps:\n      - run: gh issue close \"${{ github.event.issue.number }}\" -R jdx/mise --reason \"not planned\" -c \"issues may only be created by maintainers\"\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "content": "name: npm-publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      dry_run:\n        description: \"Run in dry-run mode (no actual publish)\"\n        required: false\n        default: true\n        type: boolean\n      version:\n        description: \"Version to publish (e.g., v2026.1.1). Defaults to latest release.\"\n        required: false\n        type: string\n\nconcurrency:\n  group: npm-publish-${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}\n\nenv:\n  DRY_RUN: ${{ github.event_name == 'release' && '0' || (inputs.dry_run && '1' || '0') }}\n\njobs:\n  npm-publish:\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      id-token: write\n      contents: read\n    if: |\n      (github.event_name == 'release' &&\n       startsWith(github.event.release.tag_name, 'v') &&\n       !github.event.release.prerelease) ||\n      github.event_name == 'workflow_dispatch'\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n\n      - name: Download release artifacts\n        run: |\n          if [[ -n \"${{ inputs.version }}\" ]]; then\n            VERSION=\"${{ inputs.version }}\"\n          else\n            VERSION=\"$(./scripts/get-version.sh)\"\n          fi\n          mkdir -p \"releases/$VERSION\"\n\n          # Download release artifacts from GitHub release\n          gh release download \"$VERSION\" \\\n            --repo ${{ github.repository }} \\\n            --dir \"releases/$VERSION\" \\\n            --pattern \"mise-*.tar.gz\" \\\n            --pattern \"mise-*.tar.xz\" || {\n              echo \"Failed to download release artifacts\"\n              exit 1\n            }\n\n          # Also download to releases/ directory for compatibility\n          cp \"releases/$VERSION\"/mise-*.tar.gz releases/ || true\n          cp \"releases/$VERSION\"/mise-*.tar.xz releases/ || true\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Setup Node.js\n        uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5\n        with:\n          node-version: \"24.x\"\n          registry-url: \"https://registry.npmjs.org\"\n\n      - name: Publish npm packages\n        run: |\n          if [[ ${DRY_RUN:-0} != 1 ]]; then\n            if [[ -n \"${{ inputs.version }}\" ]]; then\n              MISE_VERSION=\"${{ inputs.version }}\"\n            else\n              MISE_VERSION=\"$(./scripts/get-version.sh)\"\n            fi\n            export MISE_VERSION\n            export RELEASE_DIR=\"releases\"\n            NPM_PREFIX=@jdxcode/mise ./scripts/release-npm.sh\n          else\n            echo \"DRY RUN: Would publish npm packages\"\n          fi\n"
  },
  {
    "path": ".github/workflows/ppa-publish.yml",
    "content": "name: ppa-publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      distributions:\n        description: \"Ubuntu distributions to target (space-separated)\"\n        required: false\n        default: \"resolute\"\n        type: string\n      use_serious_profile:\n        description: 'Use the \"serious\" profile for optimized builds (LTO enabled)'\n        required: false\n        default: false\n        type: boolean\n      build_revision:\n        description: \"Build revision number (increment for packaging fixes of same version)\"\n        required: false\n        default: \"1\"\n        type: string\n      version_suffix:\n        description: \"Version suffix for orig tarball (e.g., +ppa1) - use when tarball contents change\"\n        required: false\n        default: \"\"\n        type: string\n\nenv:\n  DEBIAN_FRONTEND: noninteractive\n\njobs:\n  publish-ppa:\n    runs-on: ubuntu-latest\n    environment: ppa-publishing\n    timeout-minutes: 45\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up environment variables\n        run: |\n          VERSION=$(./scripts/get-version.sh | sed 's/^v//')\n\n          if [ \"${{ github.event_name }}\" = \"release\" ]; then\n            DISTRIBUTIONS=\"resolute\"\n            BUILD_REVISION=\"1\"\n            VERSION_SUFFIX=\"\"\n          else\n            DISTRIBUTIONS=\"${{ inputs.distributions }}\"\n            BUILD_REVISION=\"${{ inputs.build_revision || '1' }}\"\n            VERSION_SUFFIX=\"${{ inputs.version_suffix }}\"\n          fi\n\n          # Apply version suffix (e.g., 2026.2.0 -> 2026.2.0+ppa1)\n          VERSION=\"${VERSION}${VERSION_SUFFIX}\"\n\n          {\n            echo \"VERSION=${VERSION}\"\n            echo \"DISTRIBUTIONS=${DISTRIBUTIONS}\"\n            echo \"BUILD_REVISION=${BUILD_REVISION}\"\n            echo \"PACKAGE_NAME=mise\"\n            echo \"MAINTAINER_NAME=${{ vars.PPA_MAINTAINER_NAME || 'mise Release Bot' }}\"\n            echo \"MAINTAINER_EMAIL=${{ vars.PPA_MAINTAINER_EMAIL || 'noreply@mise.jdx.dev' }}\"\n            echo \"PPA_NAME=${{ vars.PPA_NAME || 'ppa:jdxcode/mise' }}\"\n          } >> \"$GITHUB_ENV\"\n\n          # Set build profile\n          if [ \"${{ github.event_name }}\" = \"release\" ] || [ \"${{ inputs.use_serious_profile }}\" = \"true\" ]; then\n            echo \"BUILD_PROFILE=serious\" >> \"$GITHUB_ENV\"\n          else\n            echo \"BUILD_PROFILE=release\" >> \"$GITHUB_ENV\"\n          fi\n\n      - name: Install packaging dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y \\\n            devscripts \\\n            debhelper \\\n            dh-make \\\n            build-essential \\\n            git-buildpackage \\\n            dput \\\n            lintian \\\n            quilt \\\n            fakeroot \\\n            debian-keyring \\\n            gpg \\\n            libssl-dev \\\n            pkg-config\n\n      - name: Set up Rust\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          toolchain: stable\n\n      - name: Install mise\n        run: |\n          curl https://mise.run | sh\n          echo \"$HOME/.local/bin\" >> \"$GITHUB_PATH\"\n      - run: mise x wait-for-gh-rate-limit -- wait-for-gh-rate-limit\n      - name: Install cargo-vendor\n        run: mise use -g cargo-binstall cargo:cargo-vendor\n\n      - name: Vendor Rust dependencies\n        run: |\n          mkdir -p .cargo\n          cat > .cargo/config.toml << 'EOF'\n          [source.crates-io]\n          replace-with = \"vendored-sources\"\n\n          [source.vendored-sources]\n          directory = \"vendor\"\n          EOF\n          cargo vendor vendor/\n\n          # Clear all vendor checksums — dpkg-source strips .o, .a, .git*, *.orig and\n          # other files, which breaks cargo's checksum verification. With --frozen cargo\n          # still enforces the lockfile, so integrity is maintained.\n          for checksum in vendor/*/.cargo-checksum.json; do\n            jq '.files = {}' \"$checksum\" > \"$checksum.tmp\" && mv \"$checksum.tmp\" \"$checksum\"\n          done\n\n      - name: Configure Git\n        run: |\n          git config --global user.name \"${{ env.MAINTAINER_NAME }}\"\n          git config --global user.email \"${{ env.MAINTAINER_EMAIL }}\"\n\n      - name: Import GPG key\n        uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6\n        with:\n          gpg_private_key: ${{ secrets.MISE_GPG_KEY }}\n          git_user_signingkey: true\n          git_commit_gpgsign: true\n          trust_level: 5\n\n      - name: Configure GPG for package signing\n        run: |\n          # List available keys\n          echo \"Available GPG keys:\"\n          gpg --list-secret-keys --with-colons\n\n          # Get the key ID  \n          KEY_ID=$(gpg --list-secret-keys --with-colons | grep '^sec:' | cut -d: -f5 | head -1)\n          if [ -n \"$KEY_ID\" ]; then\n            echo \"Using GPG key: $KEY_ID\"\n            echo \"DEBSIGN_KEYID=$KEY_ID\" >> \"$GITHUB_ENV\"\n            \n            # Configure debsign to use this key specifically\n            cat > ~/.devscripts << EOF\n          DEBSIGN_KEYID=$KEY_ID\n          DEBUILD_DPKG_BUILDPACKAGE_OPTS=\"-i -I -S -sa\"\n          DEBUILD_LINTIAN_OPTS=\"-i -I --show-overrides --profile ubuntu\"\n          DEBSIGN_PROGRAM=gpg\n          EOF\n            \n            echo \"devscripts configuration:\"\n            cat ~/.devscripts\n            \n            # Test that the key works for signing\n            echo \"Testing GPG signing...\"\n            echo \"test\" | gpg --clearsign --default-key \"$KEY_ID\" --armor || echo \"Warning: GPG signing test failed\"\n            \n          else\n            echo \"Error: No GPG key found\"\n            exit 1\n          fi\n\n      - name: Create source package for each distribution\n        run: |\n          # Create debian directory structure (native format - no orig tarball needed)\n          mkdir -p debian/source\n\n          echo \"3.0 (native)\" > debian/source/format\n\n          # Create basic debian files\n          cat > debian/control << EOF\n          Source: ${PACKAGE_NAME}\n          Section: utils\n          Priority: optional\n          Maintainer: ${MAINTAINER_NAME} <${MAINTAINER_EMAIL}>\n          Build-Depends: debhelper-compat (= 13), rustc (>= 1.88), cargo, libssl-dev, pkgconf\n          Standards-Version: 4.6.2\n          Homepage: https://mise.jdx.dev\n          Vcs-Git: https://github.com/jdx/mise.git\n          Vcs-Browser: https://github.com/jdx/mise\n\n          Package: ${PACKAGE_NAME}\n          Architecture: any\n          Depends: \\${shlibs:Depends}, \\${misc:Depends}\n          Description: The front-end to your dev env\n           mise is a development environment setup tool that handles runtime versions,\n           environment variables, and tasks. It's a replacement for tools like nvm, rbenv,\n           pyenv, etc. and works with any language.\n          EOF\n\n          # Determine target directory (release profile uses target/release/, others use target/<profile>/)\n          if [ \"${BUILD_PROFILE}\" = \"release\" ]; then\n            TARGET_DIR=\"target/release\"\n          else\n            TARGET_DIR=\"target/${BUILD_PROFILE}\"\n          fi\n\n          cat > debian/rules << EOF\n          #!/usr/bin/make -f\n\n          %:\n          \tdh \\$@\n\n          override_dh_auto_build:\n          \tcargo build --profile ${BUILD_PROFILE} --frozen --bin mise\n\n          override_dh_auto_install:\n          \tmkdir -p debian/mise/usr/bin\n          \tcp ${TARGET_DIR}/mise debian/mise/usr/bin/\n          \tmkdir -p debian/mise/usr/share/man/man1\n          \tif [ -f man/man1/mise.1 ]; then cp man/man1/mise.1 debian/mise/usr/share/man/man1/; fi\n          \tmkdir -p debian/mise/usr/share/bash-completion/completions\n          \tif [ -f completions/mise.bash ]; then cp completions/mise.bash debian/mise/usr/share/bash-completion/completions/mise; fi\n          \tmkdir -p debian/mise/usr/share/zsh/site-functions\n          \tif [ -f completions/_mise ]; then cp completions/_mise debian/mise/usr/share/zsh/site-functions/; fi\n          \tmkdir -p debian/mise/usr/share/fish/vendor_completions.d\n          \tif [ -f completions/mise.fish ]; then cp completions/mise.fish debian/mise/usr/share/fish/vendor_completions.d/; fi\n          \tmkdir -p debian/mise/usr/lib/mise\n          \techo 'message = \"To update, run:\\\\n\\\\n  sudo apt update && sudo apt install --only-upgrade mise\\\\n\"' > debian/mise/usr/lib/mise/mise-self-update-instructions.toml\n\n          override_dh_auto_clean:\n          \tcargo clean || true\n          EOF\n\n          chmod +x debian/rules\n\n          cat > debian/copyright << EOF\n          Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\n          Upstream-Name: ${PACKAGE_NAME}\n          Source: https://github.com/jdx/mise\n\n          Files: *\n          Copyright: 2023-2025 Jeff Dickey\n          License: MIT\n\n          License: MIT\n           Permission is hereby granted, free of charge, to any person obtaining a\n           copy of this software and associated documentation files (the \"Software\"),\n           to deal in the Software without restriction, including without limitation\n           the rights to use, copy, modify, merge, publish, distribute, sublicense,\n           and/or sell copies of the Software, and to permit persons to whom the\n           Software is furnished to do so, subject to the following conditions:\n           .\n           The above copyright notice and this permission notice shall be included\n           in all copies or substantial portions of the Software.\n           .\n           THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n           OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n           MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n           IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n           CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n           TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n           SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n          EOF\n\n          # Build source packages for each distribution\n          for DIST in ${DISTRIBUTIONS}; do\n            echo \"Building source package for $DIST\"\n\n            # Create distribution-specific version (native format uses ~ instead of -)\n            DIST_VERSION=\"${VERSION}~${DIST}${BUILD_REVISION}\"\n            \n            # Create changelog\n            cat > debian/changelog << EOF\n          ${PACKAGE_NAME} (${DIST_VERSION}) ${DIST}; urgency=medium\n\n            * New upstream release ${VERSION}\n\n           -- ${MAINTAINER_NAME} <${MAINTAINER_EMAIL}>  $(date -R)\n          EOF\n            \n            # Build source package (-d skips build-dep checks since we're only creating source package)\n            # TODO: remove -d once GitHub runners use Ubuntu 26.04 with Rust 1.88+\n            debuild -d\n            \n            # Move built packages\n            mkdir -p \"/tmp/packages\"\n            mv ../*\"${DIST_VERSION}\"*.dsc \"/tmp/packages/\"\n            mv ../*\"${DIST_VERSION}\"*.tar.* \"/tmp/packages/\"\n            mv ../*\"${DIST_VERSION}\"*.changes \"/tmp/packages/\"\n            mv ../*\"${DIST_VERSION}\"*.buildinfo \"/tmp/packages/\" 2>/dev/null || true\n            \n            # Clean for next distribution\n            rm -f ../mise_\"${DIST_VERSION}\"*\n          done\n\n      - name: Upload source packages to PPA\n        run: |\n          cd /tmp/packages\n\n          # Configure dput\n          cat > ~/.dput.cf << EOF\n          [mise-ppa]\n          fqdn = ppa.launchpad.net\n          method = ftp\n          incoming = ~${PPA_NAME#ppa:}/ubuntu/\n          login = anonymous\n          allow_unsigned_uploads = 0\n          EOF\n\n          # Upload each changes file\n          for changes_file in *.changes; do\n            echo \"Uploading $changes_file to PPA...\"\n            dput mise-ppa \"$changes_file\"\n          done\n"
  },
  {
    "path": ".github/workflows/pr-closer.yml",
    "content": "name: pr-closer\n\non:\n  schedule:\n    - cron: \"0 0 * * *\" # daily at midnight\n  workflow_dispatch:\n\njobs:\n  close-stale-prs:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Close stale PRs\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          gh pr list -R jdx/mise --state open --json number,author,labels,updatedAt,statusCheckRollup --limit 100 | \\\n          jq -r '.[] | select(\n            (.updatedAt | fromdateiso8601) < (now - 30*24*60*60) and\n            .author.login != \"jdx\" and\n            ([.labels[].name] | index(\"keep-open\") | not)\n          ) | [.number, (if (.statusCheckRollup | length > 0) and ([.statusCheckRollup[].conclusion] | index(\"FAILURE\") or index(\"failure\")) then \"failing\" else \"passing\" end)] | @tsv' | \\\n          while read -r pr status; do\n            echo \"Closing PR #$pr (checks: $status)\"\n            if [ \"$status\" = \"failing\" ]; then\n              gh pr close \"$pr\" -R jdx/mise -c \"This PR has been open for more than 30 days without activity. Note: CI checks were failing, which may be why it wasn't reviewed. Feel free to reopen or create a new PR if you'd like to continue working on this.\"\n            else\n              gh pr close \"$pr\" -R jdx/mise -c \"This PR has been open for more than 30 days without activity. Feel free to reopen or create a new PR if you'd like to continue working on this.\"\n            fi\n          done\n"
  },
  {
    "path": ".github/workflows/registry.yml",
    "content": "name: registry\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - release\n  pull_request:\n    branches: [main]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.pull_request.number || github.event.pull_request.number || 'push' }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  MISE_TRUSTED_CONFIG_PATHS: ${{ github.workspace }}\n  MISE_EXPERIMENTAL: 1\n  MISE_LOCKFILE: 1\n  MISE_USE_VERSIONS_HOST_TRACK: 0\n  RUST_BACKTRACE: 1\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  check-changes:\n    runs-on: ubuntu-latest\n    timeout-minutes: 5\n    outputs:\n      registry-changed: ${{ steps.check.outputs.registry-changed }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - id: check\n        run: |\n          if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ] || [ \"${{ github.event_name }}\" == \"push\" ]; then\n            echo \"registry-changed=true\" >> \"$GITHUB_OUTPUT\"\n            exit 0\n          fi\n          # Check if relevant files changed\n          if git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD | grep -qE '^(registry/.*\\.toml|\\.github/workflows/registry\\.yml|src/cli/test_tool\\.rs)$'; then\n            echo \"registry-changed=true\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"registry-changed=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n  build:\n    timeout-minutes: 20\n    runs-on: ubuntu-latest\n    needs: check-changes\n    if: needs.check-changes.outputs.registry-changed == 'true'\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: false\n      - run: cargo build --all-features\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: mise\n          path: target/debug/mise\n\n  list-changed-tools:\n    timeout-minutes: 10\n    runs-on: ubuntu-latest\n    needs: check-changes\n    if: github.event_name == 'pull_request' && needs.check-changes.outputs.registry-changed == 'true'\n    outputs:\n      tools: ${{ steps.determine-tools.outputs.tools }}\n      new_tools: ${{ steps.registry-diff.outputs.new_tools }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - id: workflow-check\n        run: |\n          if git diff --name-only ${{ github.event.pull_request.base.sha }} HEAD | grep -q \".github/workflows/registry.yml\"; then\n            echo \"modified=true\" >> \"$GITHUB_OUTPUT\"\n          fi\n      - uses: ./.github/actions/registry-diff\n        id: registry-diff\n        if: steps.workflow-check.outputs.modified != 'true'\n        with:\n          base_sha: ${{ github.event.pull_request.base.sha }}\n      - id: determine-tools\n        run: |\n          if [ \"${{ steps.workflow-check.outputs.modified }}\" == \"true\" ]; then\n            echo \"Workflow modified, running all tests\"\n            echo \"tools=\" >> \"$GITHUB_OUTPUT\"\n            exit 0\n          fi\n\n          tools=\"${{ steps.registry-diff.outputs.modified_tools }}\"\n          count=$(echo \"$tools\" | wc -w)\n          echo \"Modified tools count: $(echo \"$tools\" | wc -w)\"\n\n          if [ \"$count\" -gt 30 ]; then\n            echo \"Over 30 tools updated, running all tests\"\n            echo \"tools=\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"tools=$tools\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n  validate-new-tools:\n    runs-on: ubuntu-latest\n    timeout-minutes: 5\n    needs: list-changed-tools\n    if: |\n      github.event_name == 'pull_request' &&\n      github.event.pull_request.user.login != 'jdx' &&\n      needs.list-changed-tools.outputs.new_tools != ''\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Check new tools have tests\n        run: |\n          missing_tests=\"\"\n          for tool in ${{ needs.list-changed-tools.outputs.new_tools }}; do\n            if ! grep -q '^test = ' \"registry/$tool.toml\"; then\n              missing_tests=\"$missing_tests $tool\"\n            fi\n          done\n          if [ -n \"$missing_tests\" ]; then\n            echo \"::error::New tools missing required 'test' field:$missing_tests\"\n            echo \"\"\n            echo \"All new tools must include a test field, e.g.:\"\n            echo '  test = [\"mytool --version\", \"v{{version}}\"]'\n            exit 1\n          fi\n          echo \"All new tools have tests\"\n\n  test-tool:\n    name: test-tool-${{ matrix.tranche }}\n    timeout-minutes: 30\n    runs-on: ubuntu-latest\n    needs:\n      - build\n      - list-changed-tools\n      - validate-new-tools\n    if: |\n      !cancelled() &&\n      needs.build.result == 'success' &&\n      (needs.list-changed-tools.result == 'success' || needs.list-changed-tools.result == 'skipped') &&\n      (needs.validate-new-tools.result == 'success' || needs.validate-new-tools.result == 'skipped')\n    strategy:\n      fail-fast: false\n      matrix:\n        tranche: ${{ fromJson(needs.list-changed-tools.outputs.tools == '' && '[0,1,2,3,4,5,6,7]' || '[0]') }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Fetch token from pool\n        id: token\n        uses: ./.github/actions/fetch-token\n        with:\n          api-secret: ${{ secrets.MISE_VERSIONS_API_SECRET }}\n      - name: Set GITHUB_TOKEN from pool\n        if: steps.token.outputs.token\n        run: echo \"GITHUB_TOKEN=${{ steps.token.outputs.token }}\" >> \"$GITHUB_ENV\"\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: mise\n          path: target/debug\n      - run: echo target/debug >> \"$GITHUB_PATH\"\n      - run: chmod +x target/debug/mise\n      - run: mise -v\n      - uses: ./.github/actions/mise-tools\n      - id: test-tools\n        env:\n          TEST_TRANCHE: ${{ matrix.tranche }}\n          TEST_TRANCHE_COUNT: ${{ needs.list-changed-tools.outputs.tools == '' && 8 || 1 }}\n        run: |\n          mise test-tool ${{ needs.list-changed-tools.outputs.tools == '' && '--all' || needs.list-changed-tools.outputs.tools }} || true\n          failed_tools=$(grep \"Failed Tools\" \"$GITHUB_STEP_SUMMARY\" | sed 's/\\*\\*Failed Tools\\*\\*: //' | tr ',' ' ')\n          echo \"failed_tools=$failed_tools\" >> \"$GITHUB_OUTPUT\"\n      - name: Retry failed tools\n        if: steps.test-tools.outputs.failed_tools != '' && github.head_ref != 'release' && github.ref != 'refs/heads/release'\n        run: mise run test-tool-retry ${{ steps.test-tools.outputs.failed_tools }}\n      - name: Retry failed tools (with grace period for new upstream releases)\n        if: steps.test-tools.outputs.failed_tools != '' && (github.head_ref == 'release' || github.ref == 'refs/heads/release')\n        run: mise run test-tool-retry --grace-period ${{ steps.test-tools.outputs.failed_tools }}\n\n  registry-ci:\n    runs-on: ubuntu-latest\n    timeout-minutes: 1\n    needs:\n      - check-changes\n      - build\n      - list-changed-tools\n      - validate-new-tools\n      - test-tool\n    if: ${{ !cancelled() }}\n    steps:\n      - name: Check CI job results\n        run: |\n          if [ \"${{ needs.check-changes.result }}\" != \"success\" ]; then\n            echo \"check-changes job failed\"\n            exit 1\n          fi\n          if [ \"${{ needs.check-changes.outputs.registry-changed }}\" != \"true\" ]; then\n            echo \"No registry changes detected, skipping registry CI checks\"\n            exit 0\n          fi\n          if [ \"${{ needs.build.result }}\" != \"success\" ]; then\n            echo \"build failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.list-changed-tools.result }}\" != \"success\" ] && [ \"${{ needs.list-changed-tools.result }}\" != \"skipped\" ]; then\n            echo \"list-changed-tools failed\"\n            exit 1\n          fi\n          if [ \"${{ needs.validate-new-tools.result }}\" == \"failure\" ]; then\n            echo \"validate-new-tools failed - new tools must include tests\"\n            exit 1\n          fi\n          if [ \"${{ needs.test-tool.result }}\" != \"success\" ]; then\n            echo \"test-tool failed or was skipped\"\n            exit 1\n          fi\n          echo \"All CI jobs completed successfully\"\n"
  },
  {
    "path": ".github/workflows/release-alpine.yml",
    "content": "name: release-alpine\n\non:\n  release:\n    types: [released]\n  workflow_dispatch:\n    inputs:\n      dry_run:\n        description: \"Run in dry-run mode (no actual changes)\"\n        required: false\n        default: true\n        type: boolean\n\nconcurrency:\n  group: release-alpine-${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}\n\nenv:\n  DRY_RUN: ${{ github.event_name == 'release' && '0' || (github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run && '1' || '0')) || '1' }}\n  GITHUB_API_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  GH_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  bump-alpine:\n    runs-on: ubuntu-latest\n    container: ghcr.io/jdx/mise:alpine@sha256:25844704f71a7e2112926b31c1a51b99c3d6353f5ece2a0d5f1d22b6f2443d69\n    timeout-minutes: 60\n    if: |\n      (github.event_name == 'release' && \n       startsWith(github.event.release.tag_name, 'v') && \n       endsWith(github.event.release.tag_name, '0')) ||\n      (github.event_name == 'workflow_dispatch')\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Bump APKBUILD\n        run: sudo -Eu packager ./scripts/release-alpine.sh\n        env:\n          ALPINE_GITLAB_TOKEN: ${{ secrets.ALPINE_GITLAB_TOKEN }}\n          ALPINE_KEY_ID: ${{ secrets.ALPINE_KEY_ID }}\n          ALPINE_PRIV_KEY: ${{ secrets.ALPINE_PRIV_KEY }}\n          ALPINE_PUB_KEY: ${{ secrets.ALPINE_PUB_KEY }}\n"
  },
  {
    "path": ".github/workflows/release-fig.yml",
    "content": "name: release-fig\non:\n  push:\n    tags:\n      - \"v*.0\" ## Only run the action on new versions once per month, this prevents useless runs of the action\n  workflow_dispatch:\n\njobs:\n  push-to-fig-autocomplete:\n    ## if github.repository == 'jdx/mise'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n          token: ${{ secrets.MISE_GH_TOKEN }}\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: false\n      - run: mkdir -p \"$HOME/bin\" && echo \"$HOME/bin\" >> \"$GITHUB_PATH\"\n      - run: cargo build --all-features && cp target/debug/mise \"$HOME\"/bin\n      - uses: ./.github/actions/mise-tools\n      - run: mise x -- bun i\n      - run: mise run render:fig\n      - name: Create Autocomplete PR ## Create the autocomplete PR using this action\n        uses: withfig/push-to-fig-autocomplete-action@fb320c27ec12b225b9446373aa30b7d9c0c1eae8 # v2\n        with:\n          token: ${{ secrets.MISE_GH_TOKEN }}\n          autocomplete-spec-name: mise\n          spec-path: tasks/fig/src/mise.ts\n          pr-body: \"Automated PR for latest mise release by https://github.com/jdx/mise\"\n"
  },
  {
    "path": ".github/workflows/release-plz.yml",
    "content": "name: release-plz\n\npermissions:\n  pull-requests: write\n  contents: write\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  schedule:\n    - cron: \"0 0 * * *\"\n\nconcurrency:\n  group: release-plz\n\nenv:\n  MISE_EXPERIMENTAL: 1\n  NPM_CONFIG_FUND: false\n  RUST_BACKTRACE: 1\n  CARGO_TERM_COLOR: always\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  release-plz:\n    if: github.repository == 'jdx/mise'\n    timeout-minutes: 20\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n          token: ${{ secrets.MISE_GH_TOKEN }}\n      - uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6\n        with:\n          gpg_private_key: ${{ secrets.MISE_GPG_KEY }}\n          git_user_signingkey: true\n          git_commit_gpgsign: true\n          git_tag_gpgsign: true\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n      - run: mkdir -p \"$HOME/bin\" && echo \"$HOME/bin\" >> \"$GITHUB_PATH\"\n      - run: cargo build --all-features && cp target/debug/mise \"$HOME\"/bin\n      - uses: ./.github/actions/mise-tools\n      - run: mise x -- bun i\n      - run: mise run release-plz\n        env:\n          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: release\n\non:\n  push:\n    tags: [\"v[0-9]*\"]\n  pull_request:\n    branches: [\"main\"]\n  workflow_dispatch:\n    inputs:\n      force:\n        description: \"Force release even if one already exists\"\n        type: boolean\n        default: false\n\nconcurrency:\n  group: release-${{ github.ref_name }}\n\nenv:\n  CARGO_TERM_COLOR: always\n  DRY_RUN: ${{ startsWith(github.ref, 'refs/tags/v') && '0' || '1' }}\n  RUST_BACKTRACE: 1\n  GITHUB_API_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  GH_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  build-tarball-linux:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    name: build-tarball-${{matrix.name}}\n    runs-on: ubuntu-latest\n    timeout-minutes: 45\n    env:\n      MINIO_AWS_ACCESS_KEY_ID: ${{ secrets.MINIO_AWS_ACCESS_KEY_ID }}\n      MINIO_AWS_SECRET_ACCESS_KEY: ${{ secrets.MINIO_AWS_SECRET_ACCESS_KEY }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - name: linux-x64\n            target: x86_64-unknown-linux-gnu\n          - name: linux-x64-musl\n            target: x86_64-unknown-linux-musl\n          - name: linux-arm64\n            target: aarch64-unknown-linux-gnu\n          - name: linux-arm64-musl\n            target: aarch64-unknown-linux-musl\n          - name: linux-armv7\n            target: armv7-unknown-linux-gnueabi\n          - name: linux-armv7-musl\n            target: armv7-unknown-linux-musleabi\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Install cross\n        uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with:\n          tool: cross\n      - name: cache crates\n        id: cache-crates\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n        with:\n          path: ~/.cargo/registry/cache\n          key: cargo-registry-${{ hashFiles('**/Cargo.lock') }}\n          restore-keys: cargo-registry\n      - name: build-tarball ${{matrix.target}}\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 45\n          max_attempts: 3\n          command: scripts/build-tarball.sh ${{matrix.target}}\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: tarball-${{matrix.target}}\n          path: |\n            dist/mise-*.tar.xz\n            dist/mise-*.tar.gz\n            dist/mise-*.tar.zst\n          if-no-files-found: error\n      - uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with: { tool: cargo-cache }\n      - if: steps.cache-crates.outputs.cache-hit != 'true'\n        run: cargo cache --autoclean\n  build-tarball-macos:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    name: build-tarball-${{matrix.name}}\n    runs-on: macos-latest\n    timeout-minutes: 90\n    env:\n      MINIO_AWS_ACCESS_KEY_ID: ${{ secrets.MINIO_AWS_ACCESS_KEY_ID }}\n      MINIO_AWS_SECRET_ACCESS_KEY: ${{ secrets.MINIO_AWS_SECRET_ACCESS_KEY }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - name: macos-x64\n            target: x86_64-apple-darwin\n          - name: macos-arm64\n            target: aarch64-apple-darwin\n    steps:\n      - uses: apple-actions/import-codesign-certs@95e84a1a18f2bdbc5c6ab9b7f4429372e4b13a8b # v5\n        with:\n          p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12 }}\n          p12-password: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTS_P12_PASS }}\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: cache crates\n        id: cache-crates\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n        with:\n          path: ~/.cargo/registry/cache\n          key: cargo-registry-${{ hashFiles('**/Cargo.lock') }}\n          restore-keys: cargo-registry\n      - name: Setup Rust target\n        run: rustup target add ${{matrix.target}}\n      - name: build-tarball ${{matrix.target}}\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 90\n          max_attempts: 3\n          command: scripts/build-tarball.sh ${{matrix.target}}\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: tarball-${{matrix.target}}\n          path: |\n            dist/mise-*.tar.xz\n            dist/mise-*.tar.gz\n            dist/mise-*.tar.zst\n          if-no-files-found: error\n      - uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with: { tool: cargo-cache }\n      - if: steps.cache-crates.outputs.cache-hit != 'true'\n        run: cargo cache --autoclean\n  build-tarball-windows:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    name: build-tarball-windows-${{matrix.arch}}\n    runs-on: windows-latest\n    timeout-minutes: 45\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - arch: arm64\n            target: aarch64-pc-windows-msvc\n          - arch: x64\n            target: x86_64-pc-windows-msvc\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - run: rustup target add ${{matrix.target}}\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          key: ${{matrix.arch}}\n      - run: scripts/build-tarball.ps1 ${{matrix.target}}\n        env:\n          OS: windows\n          ARCH: ${{matrix.arch}}\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: tarball-${{matrix.target}}\n          path: dist/*.zip\n          if-no-files-found: error\n  e2e-linux:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    name: e2e-linux-${{matrix.tranche}}\n    needs: [build-tarball-linux]\n    runs-on: ubuntu-latest\n    #container: ghcr.io/jdx/mise:github-actions\n    timeout-minutes: 30\n    strategy:\n      fail-fast: false\n      matrix:\n        tranche: [0, 1, 2, 3, 4, 5, 6, 7]\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Install zsh/fish/direnv/fd\n        run: sudo apt-get update; sudo apt-get install zsh fish direnv fd-find liblzma-dev libbz2-dev\n      - name: Install fd-find\n        run: |\n          mkdir -p \"$HOME/.local/bin\"\n          ln -s \"$(which fdfind)\" \"$HOME/.local/bin/fd\"\n          echo \"$HOME/.local/bin\" >> \"$GITHUB_PATH\"\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n      - uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with:\n          tool: usage-cli\n      - run: tar -C \"$HOME\" -xvf \"dist/mise-$(./scripts/get-version.sh)-linux-x64.tar.zst\"\n      - run: echo \"$HOME/mise/bin\" >> \"$GITHUB_PATH\"\n      - run: mise -v\n      - run: mise x wait-for-gh-rate-limit -- wait-for-gh-rate-limit\n      - run: mise i\n      - name: Run e2e tests\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        env:\n          TEST_TRANCHE: ${{matrix.tranche}}\n          TEST_TRANCHE_COUNT: 8\n          TEST_ALL: 1\n        with:\n          timeout_minutes: 20\n          max_attempts: 3\n          command: ./e2e/run_all_tests\n  rpm:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    runs-on: ubuntu-latest\n    needs: [build-tarball-linux]\n    timeout-minutes: 10\n    container: ghcr.io/jdx/mise:rpm@sha256:5a965870c72a6a4c0b8f18b6b39b9a09e0613d52ced5c8bf2a62fd3faa3b6da6\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6\n        with:\n          gpg_private_key: ${{ secrets.MISE_GPG_KEY }}\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-aarch64-unknown-linux-gnu\n          path: dist\n      - run: scripts/build-rpm.sh\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: rpm\n          path: dist/rpmrepo\n          if-no-files-found: error\n  deb:\n    if: github.event_name != 'pull_request' || github.head_ref == 'release'\n    runs-on: ubuntu-latest\n    needs: [build-tarball-linux]\n    container: ghcr.io/jdx/mise:deb@sha256:464cf7c9eeb45e3c61cef392bd57d08c7719b2d5eb23b7b310f0f570f30ad598\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6\n        with:\n          gpg_private_key: ${{ secrets.MISE_GPG_KEY }}\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-aarch64-unknown-linux-gnu\n          path: dist\n      - run: scripts/build-deb.sh\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: deb\n          path: dist/deb\n          if-no-files-found: error\n  release:\n    runs-on: ubuntu-24.04\n    timeout-minutes: 10\n    permissions:\n      contents: write\n    needs:\n      - rpm\n      - deb\n      - e2e-linux\n      - build-tarball-linux\n      - build-tarball-macos\n      - build-tarball-windows\n    if: ${{ !cancelled() && !failure() }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - name: Check for existing release\n        id: check-release\n        if: startsWith(github.ref, 'refs/tags/v') && inputs.force != true\n        run: |\n          VERSION=\"$(./scripts/get-version.sh)\"\n          if gh api \"repos/${{ github.repository }}/releases/tags/$VERSION\" --jq '.draft' 2>/dev/null; then\n            DRAFT=\"$(gh api \"repos/${{ github.repository }}/releases/tags/$VERSION\" --jq '.draft')\"\n            if [[ \"$DRAFT\" == \"false\" ]]; then\n              echo \"::warning::Release $VERSION already exists and is published — skipping publish steps\"\n              echo \"exists=true\" >> \"$GITHUB_OUTPUT\"\n            else\n              echo \"Draft release $VERSION exists — will continue publishing\"\n              echo \"exists=false\" >> \"$GITHUB_OUTPUT\"\n            fi\n          else\n            echo \"No release found for $VERSION\"\n            echo \"exists=false\" >> \"$GITHUB_OUTPUT\"\n          fi\n      - name: Skip release for non-release branch PRs\n        if: github.event_name == 'pull_request' && github.head_ref != 'release'\n        run: |\n          echo \"Skipping release steps for PR from non-release branch\"\n          echo \"All release operations will be skipped\"\n      - uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        with:\n          gpg_private_key: ${{ secrets.MISE_GPG_KEY }}\n          git_user_signingkey: true\n          git_commit_gpgsign: true\n      - name: cache zipsign\n        id: cache-zipsign\n        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n        with:\n          path: ~/.cargo/bin/zipsign\n          key: cargo-zipsign\n      - run: ./scripts/setup-zipsign.sh\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        env:\n          ZIPSIGN: ${{ secrets.ZIPSIGN }}\n      - name: Install fd-find\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        run: |\n          sudo apt-get update\n          sudo apt-get install fd-find minisign\n          mkdir -p \"$HOME/.local/bin\"\n          ln -s \"$(which fdfind)\" \"$HOME/.local/bin/fd\"\n          echo \"$HOME/.local/bin\" >> \"$GITHUB_PATH\"\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        with: { path: artifacts }\n      - run: ls -R artifacts\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        with:\n          path: artifacts\n          pattern: |\n            mise-v*.tar.gz\n            mise-v*.tar.xz\n            mise-v*.tar.zst\n            mise-v*.zip\n          merge-multiple: true\n      - run: echo \"${{ secrets.MINISIGN_KEY }}\" >minisign.key\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - run: ls -R artifacts\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n      - run: tar -C \"$HOME\" -xvf \"dist/mise-$(./scripts/get-version.sh)-linux-x64.tar.zst\"\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - run: echo \"$HOME/mise/bin\" >> \"$GITHUB_PATH\"\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - run: which mise && mise -v && mise i\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - run: mise x -- scripts/release.sh\n        if: github.event_name != 'pull_request' || github.head_ref == 'release'\n      - name: Generate release notes\n        if: startsWith(github.ref, 'refs/tags/v') && steps.check-release.outputs.exists != 'true'\n        run: |\n          VERSION=\"$(./scripts/get-version.sh)\"\n          if mise x -- communique generate \"$VERSION\" -o /tmp/release-notes.txt; then\n            TITLE=\"$(head -1 /tmp/release-notes.txt | sed 's/^#* //' | sed \"s/^$VERSION: //\")\"\n            echo \"RELEASE_TITLE=$VERSION: $TITLE\" >> \"$GITHUB_ENV\"\n            # Remove the title line (and any blank line after it) from the notes body\n            tail -n +2 /tmp/release-notes.txt | sed '/./,$!d' > /tmp/release-notes-body.txt\n            mv /tmp/release-notes-body.txt /tmp/release-notes.txt\n          else\n            echo \"::warning::communique failed, falling back to git-cliff changelog\"\n            mise x -- git cliff --strip all --latest > /tmp/release-notes.txt 2>/dev/null || echo \"Release $VERSION\" > /tmp/release-notes.txt\n            echo \"RELEASE_TITLE=$VERSION\" >> \"$GITHUB_ENV\"\n          fi\n        env:\n          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n      - name: Create Draft GitHub Release\n        if: startsWith(github.ref, 'refs/tags/v') && steps.check-release.outputs.exists != 'true'\n        run: |\n          VERSION=\"$(./scripts/get-version.sh)\"\n          gh release create \"$VERSION\" \\\n            --title \"$RELEASE_TITLE\" \\\n            --notes-file /tmp/release-notes.txt \\\n            --verify-tag \\\n            --draft \\\n            \"releases/$VERSION\"/*\n        env:\n          GH_TOKEN: ${{ secrets.MISE_GH_TOKEN }}\n      - name: Publish Release Assets to CDN\n        if: startsWith(github.ref, 'refs/tags/v') && steps.check-release.outputs.exists != 'true'\n        run: mise x -- scripts/publish-release.sh\n        env:\n          CLOUDFLARE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_ACCESS_KEY_ID }}\n          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}\n          CLOUDFLARE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_SECRET_ACCESS_KEY }}\n      - name: Publish GitHub Release\n        if: startsWith(github.ref, 'refs/tags/v') && steps.check-release.outputs.exists != 'true'\n        run: |\n          VERSION=\"$(./scripts/get-version.sh)\"\n          gh release edit \"$VERSION\" --draft=false\n        env:\n          GH_TOKEN: ${{ secrets.MISE_GH_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/semantic-pr-lint.yml",
    "content": "name: semantic-pr-lint\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - reopened\n\njobs:\n  main:\n    name: Validate PR title\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: read\n    steps:\n      - uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          types: |\n            fix\n            feat\n            refactor\n            chore\n            docs\n            style\n            test\n            perf\n            build\n            registry\n            revert\n"
  },
  {
    "path": ".github/workflows/snapcraft-publish.yml",
    "content": "name: snapcraft-publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  publish-snapcraft:\n    runs-on: ubuntu-latest\n    timeout-minutes: 20\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0\n\n      - uses: snapcore/action-build@3bdaa03e1ba6bf59a65f84a751d943d549a54e79 # v1.3.0\n        with:\n          snapcraft-channel: beta\n        id: snapbuild\n\n      - uses: snapcore/action-publish@214b86e5ca036ead1668c79afb81e550e6c54d40 # v1.2.0\n        env:\n          SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}\n        with:\n          snap: ${{ steps.snapbuild.outputs.snap }}\n          release: beta\n"
  },
  {
    "path": ".github/workflows/test-plugins.yml",
    "content": "name: test-plugins\n\n# Test Top 50 asdf plugins install correctly and the most common can print their\n# current version\n\non:\n  push:\n    tags: [\"v*\"]\n    branches: [\"test-plugins\"]\n  schedule:\n    # run at midnight on sunday (utc?)\n    - cron: 0 0 * * 0\n  #  pull_request:\n  #    branches: [\"main\"]\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\nenv:\n  CARGO_TERM_COLOR: always\n  GITHUB_API_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  build-linux:\n    if: >\n      github.event_name == 'workflow_dispatch'\n      || github.repository == 'jdx/mise'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - name: Install cross\n        uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with:\n          tool: cross\n      - name: Rust Cache\n        uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: false\n      - run: scripts/build-tarball.sh x86_64-unknown-linux-gnu\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: |\n            dist/*.tar.xz\n            dist/*.tar.gz\n          if-no-files-found: error\n  test-install-and-run:\n    runs-on: ubuntu-latest\n    needs: [build-linux]\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - plugin: node\n            command: mise exec node@latest -- node -v\n          - plugin: ruby\n            command: mise exec ruby@latest -- ruby --version\n          - plugin: python\n            command: mise exec python@latest -- python -V\n          - plugin: direnv\n            command: mise exec direnv@latest -- direnv --version\n          - plugin: erlang\n            command: mise exec erlang@27.2 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().'  -noshell\n          - plugin: elixir\n            command: |\n              mise use --global erlang@27.2\n              eval \"$(mise env bash)\"\n              mise use --global elixir@1.17.3\n              eval \"$(mise env bash)\"\n              mise exec -- elixir --version\n          - plugin: golang\n            command: mise exec golang@latest -- go version\n          - plugin: java\n            command: mise exec java@openjdk -- java -version\n          - plugin: terraform\n            command: mise exec terraform@latest -- terraform -v\n          # - plugin: yarn\n          #   command: mise exec yarn@latest -- yarn --version\n          - plugin: deno\n            command: mise exec deno@latest -- deno --version\n          - plugin: bun\n            command: mise exec bun@latest -- bun --version\n          - plugin: kubectl\n            command: mise exec kubectl@latest -- kubectl version --client\n          - plugin: dotnet\n            command: mise exec dotnet@latest -- dotnet --list-sdks\n          - plugin: flutter\n            command: mise exec flutter@latest -- flutter --version\n          # - plugin: crystal\n          #   command: mise exec crystal@latest -- crystal -v\n          - plugin: neovim\n            command: mise exec neovim@latest -- nvim --version\n          - plugin: php\n            command: mise exec php@latest -- php -v php\n          - plugin: rust\n            command: mise exec rust@nightly -- rustc -V\n          # TODO: has some sort of readline bug on ubuntu-24\n          # - plugin: postgres\n          #   command: mise exec postgres@latest -- psql -V\n    steps:\n      - name: apt-get\n        run: sudo apt-get update; sudo apt-get install zsh fish direnv re2c libcurl4-openssl-dev libgd-dev libonig-dev autoconf bison build-essential curl gettext git libgd-dev libcurl4-openssl-dev libedit-dev libicu-dev libjpeg-dev libmysqlclient-dev libonig-dev libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libxml2-dev libzip-dev openssl pkg-config re2c zlib1g-dev\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n          # dist/mise-v1.16.0-linux-x64.tar.xz\n          # x86_64-unknown-linux-gnu-v1.16.0-linux-x64.tar.xz\n      - run: tar -C \"$HOME\" -xvJf dist/mise-*-linux-x64.tar.xz\n      - run: echo \"$HOME/mise/bin\" >> \"$GITHUB_PATH\"\n      - run: mise -v\n      - name: ${{matrix.command}}\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 20\n          max_attempts: 3\n          retry_wait_seconds: 30\n          command: ${{matrix.command}}\n        env:\n          MISE_EXPERIMENTAL: \"1\"\n  test-install:\n    # Tests installing the top 50 plugins not already tested in `test-install-and-run`.\n    # installing is a better-than-nothing smoke test that the plugin is correctly implemented\n    # and behaves as expected with mise.\n    runs-on: ubuntu-latest\n    needs: [build-linux]\n    strategy:\n      fail-fast: false\n      matrix:\n        plugins:\n          - waypoint\n          - vault\n          - tfc-agent\n          - terraform-ls\n          - serf\n          - sentinel\n          - packer\n          - nomad\n          - levant\n          - consul\n          - boundary\n          # - postgres\n          - rust\n          - action-validator\n          - dotnet-core\n          - neovim\n          - poetry\n          - lua\n          - redis\n          - gcloud\n          - helm\n          - gleam\n          - awscli\n          - dart\n          - conan\n          # TODO: - awsebcli fails in asdf and mise the same way\n          - aws-sam-cli\n          - ansible-base\n          - kotlin\n          - pnpm\n          - ocaml\n          # TODO: - rebar install erlang first\n          # TODO: - julia seems to have quit working, likely an issue with the plugin\n          - elm\n          # TODO: - R install libcurl\n          - nim\n          - mysql\n          - minikube\n          - gradle\n          - zig\n          - shellcheck\n          - scala\n          # TODO: - maven\n          - kustomize\n          - graalvm\n          - sbcl\n          - qsv\n    steps:\n      - name: Install zsh/fish/direnv\n        run: sudo apt-get update; sudo apt-get install zsh fish direnv\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: tarball-x86_64-unknown-linux-gnu\n          path: dist\n      - run: tar -C \"$HOME\" -xvJf dist/mise-*-linux-x64.tar.xz\n      - run: echo \"$HOME/mise/bin\" >> \"$GITHUB_PATH\"\n      - name: mise install ${{matrix.plugins}}@latest\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 20\n          max_attempts: 3\n          retry_wait_seconds: 30\n          command: mise install ${{matrix.plugins}}@latest\n"
  },
  {
    "path": ".github/workflows/test-vfox.yml",
    "content": "name: test-vfox\n\non:\n  pull_request:\n    paths:\n      - \"crates/vfox/**\"\n  push:\n    branches: [release]\n\nconcurrency:\n  group: test-vfox-${{ github.ref }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  MISE_TRUSTED_CONFIG_PATHS: ${{ github.workspace }}\n  MISE_EXPERIMENTAL: 1\n  MISE_LOCKFILE: 1\n  RUST_BACKTRACE: 1\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n\njobs:\n  \"test-vfox\":\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          save-if: false\n      - run: |\n          cargo build --all-features\n          echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\"\n      - run: mise -v\n      - run: mise --cd crates/vfox install\n      - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4\n        with:\n          key: ${{ runner.os }}-${{ runner.arch }}-mise-tools-vfox-${{ hashFiles('crates/vfox/mise.toml') }}\n          restore-keys: ${{ runner.os }}-${{ runner.arch }}-mise-tools-vfox-\n          path: |\n            ~/.local/share/mise\n            ~/.cache/mise\n      - run: mise --cd crates/vfox run build\n      - run: mise --cd crates/vfox run lint\n      - run: mise --cd crates/vfox run test\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: test\non:\n  push:\n    tags: [\"v*\"]\n    branches: [\"main\", \"mise\"]\n  pull_request:\n    branches: [\"main\"]\n  workflow_dispatch:\n  workflow_call:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.event_name != 'push' }}\n\nenv:\n  CARGO_TERM_COLOR: always\n  MISE_TRUSTED_CONFIG_PATHS: ${{ github.workspace }}\n  MISE_EXPERIMENTAL: 1\n  MISE_LOCKFILE: 1\n  RUST_BACKTRACE: 1\n  GITHUB_TOKEN: ${{ secrets.MISE_GH_TOKEN || secrets.GITHUB_TOKEN }}\n  FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }}\n\npermissions:\n  pull-requests: write\n\njobs:\n  build-ubuntu:\n    runs-on: ubuntu-latest\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: false\n      - run: |\n          cargo build --all-features\n          echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\"\n      - run: mise -v\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: mise-ubuntu-latest\n          path: target/debug/mise\n      - uses: ./.github/actions/mise-tools\n\n  build-windows:\n    runs-on: windows-latest\n    timeout-minutes: 60\n    env:\n      MISE_DATA_DIR: ~/.local/share/mise\n      MISE_CACHE_DIR: ~/.cache/mise\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: ${{ github.ref == 'refs/heads/main' }}\n      - shell: pwsh\n        run: |\n          cargo build\n          cargo build -p mise-shim\n          Add-Content $env:GITHUB_PATH \"$env:GITHUB_WORKSPACE\\target\\debug\"\n      - run: mise -v\n      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: mise-windows-latest\n          path: |\n            target/debug/mise.exe\n            target/debug/mise-shim.exe\n      - uses: ./.github/actions/mise-tools\n\n  unit:\n    strategy:\n      fail-fast: false\n      # matrix: { os: [ubuntu-latest, macos-latest] }\n      matrix: { os: [macos-latest] }\n    runs-on: ${{ matrix.os }}\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          repository: ${{ github.event.pull_request.head.repo.full_name }}\n          ref: ${{ github.head_ref }}\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: ${{ github.ref == 'refs/heads/main' }}\n      - run: |\n          cargo build --all-features\n          echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\"\n      - uses: ./.github/actions/mise-tools\n      - run: mise x -- cargo test --all-features\n\n  nightly:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          repository: ${{ github.event.pull_request.head.repo.full_name }}\n          ref: ${{ github.head_ref }}\n      - run: rustup default nightly\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: nightly\n          save-if: ${{ github.ref == 'refs/heads/main' }}\n      - run: |\n          cargo build --all-features\n          echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\"\n      - uses: ./.github/actions/mise-tools\n      - run: mise run test\n\n  lint:\n    runs-on: ubuntu-latest\n    timeout-minutes: 15\n    needs: [build-ubuntu]\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          repository: ${{ github.event.pull_request.head.repo.full_name }}\n          ref: ${{ github.head_ref }}\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: taiki-e/install-action@45a93d9c71692daf99a53feb97366fb6f4c3757f # v2\n        with:\n          tool: cargo-deny,cargo-msrv,cargo-machete\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: ${{ github.ref == 'refs/heads/main' }}\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: mise-ubuntu-latest\n          path: target/debug\n      - run: echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\" && chmod +x target/debug/mise\n      - uses: ./.github/actions/mise-tools\n      - run: mise x -- bun i\n      - run: rm -rf ~/.cargo/advisory-dbs && cargo deny check\n      - run: cargo msrv verify\n      - run: cargo machete --with-metadata\n      - run: ./scripts/test-standalone.sh\n      - run: mise run lint\n      - run: cargo clippy -- -D warnings\n      - run: cargo clippy --all-features --all-targets -- -D warnings\n\n  coverage:\n    name: coverage-${{matrix.tranche}}\n    runs-on: ubuntu-latest\n    needs: [build-ubuntu]\n    timeout-minutes: 30\n    strategy:\n      fail-fast: false\n      matrix:\n        tranche: [0, 1, 2, 3, 4, 5, 6, 7]\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          fetch-depth: 0\n      - name: Fetch token from pool\n        id: token\n        uses: ./.github/actions/fetch-token\n        with:\n          api-secret: ${{ secrets.MISE_VERSIONS_API_SECRET }}\n      - name: Set GITHUB_TOKEN from pool\n        if: steps.token.outputs.token\n        run: echo \"GITHUB_TOKEN=${{ steps.token.outputs.token }}\" >> \"$GITHUB_ENV\"\n      - name: Install build and test dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install \\\n            bison \\\n            build-essential \\\n            direnv \\\n            fd-find \\\n            fish \\\n            pipx \\\n            python3-venv \\\n            zsh\n      - run: |\n          mkdir -p \"$HOME/.local/bin\"\n          ln -s \"$(which fdfind)\" \"$HOME/.local/bin/fd\"\n          echo \"$HOME/.local/bin\" >> \"$GITHUB_PATH\"\n      - name: Dependencies for e2e/shell/test_nushell\n        run: npm install --global nushell\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: mise-ubuntu-latest\n          path: target/debug\n      - run: echo \"$PWD/target/debug\" >> \"$GITHUB_PATH\" && chmod +x target/debug/mise\n      - uses: ./.github/actions/mise-tools\n      - name: Test w/ coverage\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        env:\n          TEST_TRANCHE: ${{matrix.tranche}}\n          TEST_TRANCHE_COUNT: 8\n          TEST_ALL: ${{github.head_ref == 'release' && '1' || '0'}}\n        with:\n          timeout_minutes: 30\n          retry_wait_seconds: 30\n          max_attempts: 2\n          command: mise run test:coverage\n  windows-unit:\n    runs-on: windows-latest\n    timeout-minutes: 30\n    env:\n      MISE_DATA_DIR: ~/.local/share/mise\n      MISE_CACHE_DIR: ~/.cache/mise\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2\n        with:\n          shared-key: build\n          save-if: ${{ github.ref == 'refs/heads/main' }}\n      - name: cargo test\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 30\n          retry_wait_seconds: 30\n          max_attempts: 2\n          command: cargo test\n  windows-e2e:\n    runs-on: windows-latest\n    timeout-minutes: 40\n    needs: [build-windows]\n    env:\n      MISE_DATA_DIR: ~/.local/share/mise\n      MISE_CACHE_DIR: ~/.cache/mise\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4\n        with:\n          name: mise-windows-latest\n          path: target/debug\n      - run: ls target\\debug\n      - run: Add-Content $env:GITHUB_PATH \"$env:GITHUB_WORKSPACE\\target\\debug\"\n      - uses: ./.github/actions/mise-tools\n      - name: e2e\n        uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3\n        with:\n          timeout_minutes: 30\n          retry_wait_seconds: 30\n          max_attempts: 2\n          command: pwsh e2e-win\\run.ps1\n\n  test-ci:\n    runs-on: ubuntu-latest\n    timeout-minutes: 1\n    needs:\n      - build-ubuntu\n      - build-windows\n      - unit\n      - nightly\n      - lint\n      - coverage\n      - windows-unit\n      - windows-e2e\n    if: always()\n    steps:\n      - name: Check CI job results\n        run: |\n          if [ \"${{ needs.build-ubuntu.result }}\" != \"success\" ]; then\n            echo \"build-ubuntu failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.build-windows.result }}\" != \"success\" ]; then\n            echo \"build-windows failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.unit.result }}\" != \"success\" ]; then\n            echo \"unit failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.nightly.result }}\" != \"success\" ]; then\n            echo \"nightly failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.lint.result }}\" != \"success\" ]; then\n            echo \"lint failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.coverage.result }}\" != \"success\" ]; then\n            echo \"coverage failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.windows-unit.result }}\" != \"success\" ]; then\n            echo \"windows-unit failed or was skipped\"\n            exit 1\n          fi\n          if [ \"${{ needs.windows-e2e.result }}\" != \"success\" ]; then\n            echo \"windows-e2e failed or was skipped\"\n            exit 1\n          fi\n          echo \"All CI jobs completed successfully\"\n"
  },
  {
    "path": ".github/workflows/winget.yml",
    "content": "name: winget\non:\n  release:\n    types: [released]\n  workflow_dispatch:\njobs:\n  publish:\n    runs-on: windows-latest\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n        with:\n          repository: jdx/winget-pkgs\n          token: ${{ secrets.MISE_GH_TOKEN }}\n          fetch-depth: 0\n      - run: git config user.name mise-en-dev\n      - run: git config user.email release@mise.jdx.dev\n      - run: git remote add microsoft https://github.com/microsoft/winget-pkgs\n      - run: git pull --rebase microsoft master\n      - run: git push -f origin master\n      - uses: vedantmgoyal9/winget-releaser@main\n        with:\n          identifier: jdx.mise\n          max-versions-to-keep: 5\n          token: ${{ secrets.MISE_GH_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n/dist/\n/node_modules/\npackage-lock.json\n.mise.lock\n/mise.local.toml\n/perf-workspace\n\n*.log\n*.profraw\n*.lcov\nflamegraph.svg\ncargo-flamegraph.trace\n\n**/snapshots/*.snap.new\n\n# Generated by Cargo\n# will have compiled files and executables\n/target\n# These are backup files generated by rustfmt\n**/*.rs.bk\n\n# Snapcraft\n*.snap\n\n# alpine\n.ash_history\n.abuild\n/aports\n\nmegalinter-reports/\n.dev/\n\n.vscode/\ntestResults.xml\n.mise/\ncomment.md\n\n.claude/settings.local.json\n"
  },
  {
    "path": ".idea/.gitignore",
    "content": "# Default ignored files\n/shelf/\n/workspace.xml\n# Editor-based HTTP Client requests\n/httpRequests/\n# Datasource local storage ignored files\n/dataSources/\n/dataSources.local.xml\n# GitHub Copilot persisted chat sessions\n/copilot/chatSessions\n"
  },
  {
    "path": ".idea/codeStyles/codeStyleConfig.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <state>\n    <option name=\"PREFERRED_PROJECT_CODE_STYLE\" value=\"Default\" />\n  </state>\n</component>\n"
  },
  {
    "path": ".idea/git_toolbox_blame.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GitToolBoxBlameSettings\">\n    <option name=\"version\" value=\"2\" />\n  </component>\n</project>\n"
  },
  {
    "path": ".idea/inspectionProfiles/Project_Default.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <profile version=\"1.0\">\n    <option name=\"myName\" value=\"Project Default\" />\n    <inspection_tool class=\"CheckEmptyScriptTag\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\" />\n    <inspection_tool class=\"DuplicatedCode\" enabled=\"false\" level=\"WEAK WARNING\" enabled_by_default=\"false\">\n      <Languages>\n        <language minSize=\"55\" name=\"Rust\" />\n      </Languages>\n    </inspection_tool>\n    <inspection_tool class=\"HttpUrlsUsage\" enabled=\"true\" level=\"WEAK WARNING\" enabled_by_default=\"true\">\n      <option name=\"ignoredUrls\">\n        <list>\n          <option value=\"http://0.0.0.0\" />\n          <option value=\"http://127.0.0.1\" />\n          <option value=\"http://activemq.apache.org/schema/\" />\n          <option value=\"http://cxf.apache.org/schemas/\" />\n          <option value=\"http://java.sun.com/\" />\n          <option value=\"http://javafx.com/fxml\" />\n          <option value=\"http://javafx.com/javafx/\" />\n          <option value=\"http://json-schema.org/draft\" />\n          <option value=\"http://localhost\" />\n          <option value=\"http://maven.apache.org/POM/\" />\n          <option value=\"http://maven.apache.org/xsd/\" />\n          <option value=\"http://mise-versions.jdx.dev\" />\n          <option value=\"http://mise.jdx.dev\" />\n          <option value=\"http://primefaces.org/ui\" />\n          <option value=\"http://rtx-versions.jdx.dev\" />\n          <option value=\"http://schema.cloudfoundry.org/spring/\" />\n          <option value=\"http://schemas.xmlsoap.org/\" />\n          <option value=\"http://tiles.apache.org/\" />\n          <option value=\"http://www.ibm.com/webservices/xsd\" />\n          <option value=\"http://www.jboss.com/xml/ns/\" />\n          <option value=\"http://www.jboss.org/j2ee/schema/\" />\n          <option value=\"http://www.springframework.org/schema/\" />\n          <option value=\"http://www.springframework.org/security/tags\" />\n          <option value=\"http://www.springframework.org/tags\" />\n          <option value=\"http://www.thymeleaf.org\" />\n          <option value=\"http://www.w3.org/\" />\n          <option value=\"http://xmlns.jcp.org/\" />\n        </list>\n      </option>\n    </inspection_tool>\n    <inspection_tool class=\"RsSortImplTraitMembers\" enabled=\"false\" level=\"WEAK WARNING\" enabled_by_default=\"false\" />\n    <inspection_tool class=\"RsUnwrap\" enabled=\"false\" level=\"WEAK WARNING\" enabled_by_default=\"false\" />\n    <inspection_tool class=\"SpellCheckingInspection\" enabled=\"false\" level=\"TYPO\" enabled_by_default=\"false\">\n      <option name=\"processCode\" value=\"true\" />\n      <option name=\"processLiterals\" value=\"true\" />\n      <option name=\"processComments\" value=\"true\" />\n    </inspection_tool>\n  </profile>\n</component>\n"
  },
  {
    "path": ".idea/mise.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/tests\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/benches\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/xtask/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/usage/cli/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/usage/examples\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/usage/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/usage/cli/tests\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/usage/lib/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/crates/aqua-registry/src\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/crates/vfox/src\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/target\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/test/data\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugins\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/installs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/asdf\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/e2e/.asdf\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/e2e/.cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/e2e/.local\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/aports\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.cargo/registry\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/packaging/alpine/src\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/asdf-plugins\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/megalinter-reports\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/e2e/.venv\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/docs/.vitepress/cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/docs/.vitepress/dist\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/usage/target\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/usage/xx\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/usage/docs/.vitepress/cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/usage/docs/.vitepress/dist\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dev\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/docs/node_modules\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/aqua-registry\" />\n      <excludePattern pattern=\"*.log\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": ".idea/modules/fixtures.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"RUBY_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$/../../test/fixtures\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n  <component name=\"RubyModuleProperties\">\n    <option name=\"autoCreated\" value=\"true\" />\n  </component>\n</module>\n"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/mise.iml\" filepath=\"$PROJECT_DIR$/.idea/mise.iml\" />\n    </modules>\n  </component>\n</project>\n"
  },
  {
    "path": ".idea/prettier.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"PrettierConfiguration\">\n    <option name=\"myConfigurationMode\" value=\"MANUAL\" />\n    <option name=\"myRunOnSave\" value=\"true\" />\n    <option name=\"myRunOnReformat\" value=\"true\" />\n    <option name=\"myFilesPattern\" value=\"{**/*,*}.{js,ts,jsx,tsx,cjs,mjs,yml,yaml,json}\" />\n  </component>\n</project>\n"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CommitMessageInspectionProfile\">\n    <profile version=\"1.0\">\n      <inspection_tool class=\"BodyLimit\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n      <inspection_tool class=\"SubjectBodySeparation\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n      <inspection_tool class=\"SubjectLimit\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n    </profile>\n  </component>\n  <component name=\"GitSharedSettings\">\n    <option name=\"FORCE_PUSH_PROHIBITED_PATTERNS\">\n      <list>\n        <option value=\"master\" />\n        <option value=\"mainline\" />\n        <option value=\"main\" />\n      </list>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".markdown-link-check.json",
    "content": "{\n  \"ignorePatterns\": [{ \"pattern\": \"^https://crates.io\" }]\n}\n"
  },
  {
    "path": ".markdownlint.json",
    "content": "{\n  \"MD004\": false,\n  \"MD013\": false,\n  \"MD022\": false,\n  \"MD029\": false,\n  \"MD031\": false,\n  \"MD032\": false,\n  \"MD033\": false,\n  \"MD040\": false,\n  \"MD041\": false,\n  \"MD060\": false\n}\n"
  },
  {
    "path": ".markdownlintignore",
    "content": ".claude/\n/registry/\n/target/\nCHANGELOG.md\ncrates/vfox/embedded-plugins/\ndocs/node_modules/\ndocs/cli/watch.md\nnode_modules/\ntest/\n/tasks.md\n/comment.md\n"
  },
  {
    "path": ".prettierignore",
    "content": "*.rs\n*.snap\n.idea\n.venv\n*.gif\n*.png\n*.lock\n.cliffignore\n*.kdl\n.agent-os/\nCHANGELOG.md\ncrates/aqua-registry/aqua-registry/\ndocs/.vitepress/cache\ndocs/.vitepress/dist\ndocs/.vitepress/theme/custom.css\ndocs/cli\ndocs/environments.md\ndocs/public/site.webmanifest\ndocs/registry.md\ndocs/plugin-usage.md\ndocs/plugin-publishing.md\ndocs/contributing.md\nCLAUDE.md\nAGENTS.md\nCRUSH.md\ne2e\nsrc/assets/bash_zsh_support/\ntasks.md\ntest/data\ntmp\n"
  },
  {
    "path": ".prettierrc.toml",
    "content": "[[overrides]]\nfiles = \"xtasks/fig/**/*.ts\"\noptions = { trailingComma = \"es5\", printWidth = 80 }\n"
  },
  {
    "path": ".release-skip-e2e",
    "content": "v2025.7.26\n"
  },
  {
    "path": ".shellcheckrc",
    "content": "disable=SC1008\ndisable=SC2002\ndisable=SC2088\ndisable=SC2129\ndisable=SC2164\ndisable=SC2317\n"
  },
  {
    "path": ".taplo.toml",
    "content": "# Taplo configuration for mise\n\nexclude = [\"docs/registry/*.toml\", \"docs/settings.toml\"]\n\n\n[formatting]\nalign_entries = false\nalign_comments = false\narray_auto_collapse = true\narray_auto_expand = true\nindent_tables = false\nreorder_keys = false\n\n[[rule]]\ninclude = [\"registry/*.toml\"]\nschema.path = \"./schema/mise-registry-tool.json\"\n\n[rule.formatting]\nreorder_keys = true\nreorder_arrays = false\n\n[[rule]]\ninclude = [\"settings.toml\"]\nschema.path = \"./schema/mise-settings.json\"\n\n[rule.formatting]\nreorder_keys = true\nreorder_arrays = false\n"
  },
  {
    "path": ".yamllint.yml",
    "content": "document-start: disable\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [2026.3.9](https://github.com/jdx/mise/compare/v2026.3.8..v2026.3.9) - 2026-03-13\n\n### 🚀 Features\n\n- **(github)** use release latest endpoint to get latest release by @roele in [#8516](https://github.com/jdx/mise/pull/8516)\n- **(install)** add shared and system install directories by @jdx in [#8581](https://github.com/jdx/mise/pull/8581)\n- **(vfox)** add provenance metadata to lockfile for tool plugins by @malept in [#8544](https://github.com/jdx/mise/pull/8544)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** expose main binary when files field is empty and symlink_bins is enabled by @AlexanderTheGrey in [#8550](https://github.com/jdx/mise/pull/8550)\n- **(env)** redact secrets in `mise set` listing and task-specific env by @jdx in [#8583](https://github.com/jdx/mise/pull/8583)\n- **(prepare)** install config tools before running prepare steps by @jdx in [#8582](https://github.com/jdx/mise/pull/8582)\n- **(task)** allow ctrl-c to interrupt tool downloads during `mise run` by @jdx in [#8571](https://github.com/jdx/mise/pull/8571)\n- **(tasks)** add file task header parser support for spaces around = by @roele in [#8574](https://github.com/jdx/mise/pull/8574)\n\n### 📚 Documentation\n\n- **(task)** add property description for interactive by @roele in [#8562](https://github.com/jdx/mise/pull/8562)\n- add missing `</bold>` closing tag by @muzimuzhi in [#8564](https://github.com/jdx/mise/pull/8564)\n- rebrand site with new chef logo and warm culinary palette by @jdx in [#8587](https://github.com/jdx/mise/pull/8587)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to de4657e by @renovate[bot] in [#8577](https://github.com/jdx/mise/pull/8577)\n- update ghcr.io/jdx/mise:copr docker digest to eef29a2 by @renovate[bot] in [#8578](https://github.com/jdx/mise/pull/8578)\n- update ghcr.io/jdx/mise:rpm docker digest to 5a96587 by @renovate[bot] in [#8580](https://github.com/jdx/mise/pull/8580)\n- update ghcr.io/jdx/mise:deb docker digest to 464cf7c by @renovate[bot] in [#8579](https://github.com/jdx/mise/pull/8579)\n\n### 📦 Registry\n\n- fix flatc version test mismatch by @jdx in [#8588](https://github.com/jdx/mise/pull/8588)\n\n### Chore\n\n- **(registry)** skip spark test-tool by @jdx in [#8572](https://github.com/jdx/mise/pull/8572)\n\n### New Contributors\n\n- @AlexanderTheGrey made their first contribution in [#8550](https://github.com/jdx/mise/pull/8550)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (6)\n\n- [`bahdotsh/mdterm`](https://github.com/bahdotsh/mdterm)\n- [`callumalpass/mdbase-lsp`](https://github.com/callumalpass/mdbase-lsp)\n- [`facebook/ktfmt`](https://github.com/facebook/ktfmt)\n- [`gurgeous/tennis`](https://github.com/gurgeous/tennis)\n- [`tektoncd/pipelines-as-code`](https://github.com/tektoncd/pipelines-as-code)\n- [`weedonandscott/trolley`](https://github.com/weedonandscott/trolley)\n\n#### Updated Packages (2)\n\n- [`apple/container`](https://github.com/apple/container)\n- [`cocogitto/cocogitto`](https://github.com/cocogitto/cocogitto)\n\n## [2026.3.8](https://github.com/jdx/mise/compare/v2026.3.7..v2026.3.8) - 2026-03-11\n\n### 🐛 Bug Fixes\n\n- **(backend)** skip cosign provenance in lockfile for opts-only aqua tools by @jdx in [#8559](https://github.com/jdx/mise/pull/8559)\n- **(exec)** resolve wrapper recursion when shims are in PATH by @jdx in [#8560](https://github.com/jdx/mise/pull/8560)\n\n### 📦 Registry\n\n- add turbo by @igas in [#8553](https://github.com/jdx/mise/pull/8553)\n- add workmux by @ifraixedes in [#8555](https://github.com/jdx/mise/pull/8555)\n\n### Chore\n\n- **(tmux)** use aqua backend for tmux by @himkt in [#8558](https://github.com/jdx/mise/pull/8558)\n\n### New Contributors\n\n- @himkt made their first contribution in [#8558](https://github.com/jdx/mise/pull/8558)\n- @ifraixedes made their first contribution in [#8555](https://github.com/jdx/mise/pull/8555)\n- @igas made their first contribution in [#8553](https://github.com/jdx/mise/pull/8553)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`raaymax/lazytail`](https://github.com/raaymax/lazytail)\n\n#### Updated Packages (8)\n\n- [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner)\n- [`containerd/containerd`](https://github.com/containerd/containerd)\n- [`containerd/containerd/static`](https://github.com/containerd/containerd/static)\n- [`hellux/jotdown`](https://github.com/hellux/jotdown)\n- [`suzuki-shunsuke/cmdx`](https://github.com/suzuki-shunsuke/cmdx)\n- [`suzuki-shunsuke/ghir`](https://github.com/suzuki-shunsuke/ghir)\n- [`tmknom/actdocs`](https://github.com/tmknom/actdocs)\n- [`twpayne/chezmoi`](https://github.com/twpayne/chezmoi)\n\n## [2026.3.7](https://github.com/jdx/mise/compare/v2026.3.6..v2026.3.7) - 2026-03-10\n\n### 🐛 Bug Fixes\n\n- **(conda)** exclude transitive dependency binaries from PATH by @simonepri in [#8543](https://github.com/jdx/mise/pull/8543)\n\n### New Contributors\n\n- @simonepri made their first contribution in [#8543](https://github.com/jdx/mise/pull/8543)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`stackrox/stackrox/roxctl`](https://github.com/stackrox/stackrox/roxctl)\n\n#### Updated Packages (7)\n\n- [`dprint/dprint`](https://github.com/dprint/dprint)\n- [`j178/prek`](https://github.com/j178/prek)\n- [`jdx/hk`](https://github.com/jdx/hk)\n- [`jdx/mise`](https://github.com/jdx/mise)\n- [`jdx/usage`](https://github.com/jdx/usage)\n- [`mvdan/sh`](https://github.com/mvdan/sh)\n- [`pnpm/pnpm`](https://github.com/pnpm/pnpm)\n\n## [2026.3.6](https://github.com/jdx/mise/compare/v2026.3.5..v2026.3.6) - 2026-03-09\n\n### 🐛 Bug Fixes\n\n- **(activate)** reorder shims to front of PATH on re-source in fish by @jdx in [#8534](https://github.com/jdx/mise/pull/8534)\n- **(backend)** strip mise shims from dependency_env PATH to prevent fork bomb by @pose in [#8475](https://github.com/jdx/mise/pull/8475)\n- **(github)** resolve \"latest\" version correctly via GitHub API by @jdx in [#8532](https://github.com/jdx/mise/pull/8532)\n- **(lock)** set env tags and clarify lockfile docs by @jdx in [#8519](https://github.com/jdx/mise/pull/8519)\n- **(lock)** use separate mise.<env>.lock files instead of env tags by @jdx in [#8523](https://github.com/jdx/mise/pull/8523)\n- **(task)** include args in task output prefix and truncate long prefixes by @jdx in [#8533](https://github.com/jdx/mise/pull/8533)\n- **(task)** only include args in task prefix when disambiguating duplicates by @jdx in [#8536](https://github.com/jdx/mise/pull/8536)\n- **(test)** pin goreleaser version in attestation e2e test by @jdx in [#8518](https://github.com/jdx/mise/pull/8518)\n- **(windows)** env._.source needs to run bash.exe on Windows (fix #6513) by @pjeby in [#8520](https://github.com/jdx/mise/pull/8520)\n- handle locked .exe shims on Windows during reshim by @davireis in [#8517](https://github.com/jdx/mise/pull/8517)\n\n### 🚜 Refactor\n\n- **(prepare)** remove touch_outputs and update docs to reflect blake3 hashing by @jdx in [#8535](https://github.com/jdx/mise/pull/8535)\n\n### 📚 Documentation\n\n- **(docker)** replace jdxcode/mise image with curl install, update to debian:13-slim by @jdx in [#8526](https://github.com/jdx/mise/pull/8526)\n- fix \"gzip: stdin is encrypted\" error in shell tricks cookbook by @pjeby in [#8512](https://github.com/jdx/mise/pull/8512)\n\n### 📦 Registry\n\n- add tigerbeetle ([github:tigerbeetle/tigerbeetle](https://github.com/tigerbeetle/tigerbeetle)) by @risu729 in [#8514](https://github.com/jdx/mise/pull/8514)\n\n### New Contributors\n\n- @pjeby made their first contribution in [#8520](https://github.com/jdx/mise/pull/8520)\n- @davireis made their first contribution in [#8517](https://github.com/jdx/mise/pull/8517)\n- @Aurorxa made their first contribution in [#8511](https://github.com/jdx/mise/pull/8511)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (6)\n\n- [`betterleaks/betterleaks`](https://github.com/betterleaks/betterleaks)\n- [`majorcontext/moat`](https://github.com/majorcontext/moat)\n- [`princjef/gomarkdoc`](https://github.com/princjef/gomarkdoc)\n- [`remko/age-plugin-se`](https://github.com/remko/age-plugin-se)\n- [`sudorandom/fauxrpc`](https://github.com/sudorandom/fauxrpc)\n- [`swanysimon/mdlint`](https://github.com/swanysimon/mdlint)\n\n#### Updated Packages (1)\n\n- [`moonrepo/moon`](https://github.com/moonrepo/moon)\n\n## [2026.3.5](https://github.com/jdx/mise/compare/v2026.3.4..v2026.3.5) - 2026-03-07\n\n### 🚀 Features\n\n- **(vfox)** add `RUNTIME.envType` for libc variant detection by @malept in [#8493](https://github.com/jdx/mise/pull/8493)\n- store provenance verification results in lockfile by @jdx in [#8495](https://github.com/jdx/mise/pull/8495)\n\n### 🐛 Bug Fixes\n\n- **(env)** skip remote version fetching for \"latest\" in prefer-offline mode by @jdx in [#8500](https://github.com/jdx/mise/pull/8500)\n- **(tasks)** deduplicate shared deps across task delegation by @vadimpiven in [#8497](https://github.com/jdx/mise/pull/8497)\n- **(windows)** correctly identify mise binary without extension by @jdx in [#8503](https://github.com/jdx/mise/pull/8503)\n\n### 🚜 Refactor\n\n- **(core)** migrate cmd! callers to async with kill_on_drop by @jdx in [a63f7d2](https://github.com/jdx/mise/commit/a63f7d288c5c276fadfca4a76e92c48a4843a957)\n\n### 📦 Registry\n\n- add portless (npm:portless) by @risu729 in [#8508](https://github.com/jdx/mise/pull/8508)\n\n### Chore\n\n- **(ci)** temporarily disable `mise up` in release-plz by @jdx in [#8504](https://github.com/jdx/mise/pull/8504)\n- consolidate all linters into hk.pkl by @jdx in [#8498](https://github.com/jdx/mise/pull/8498)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`apache/ant`](https://github.com/apache/ant)\n\n## [2026.3.4](https://github.com/jdx/mise/compare/v2026.3.3..v2026.3.4) - 2026-03-07\n\n### 🚀 Features\n\n- **(github)** keep exe extensions on Windows by @iki in [#8424](https://github.com/jdx/mise/pull/8424)\n- **(task)** add `interactive` field for exclusive terminal access by @jdx in [#8491](https://github.com/jdx/mise/pull/8491)\n- add header comment to generated lockfiles by @ivy in [#8481](https://github.com/jdx/mise/pull/8481)\n- runtime musl/glibc detection for correct libc variant selection by @jdx in [#8490](https://github.com/jdx/mise/pull/8490)\n\n### 🐛 Bug Fixes\n\n- **(github)** use registry platform options during install by @jdx in [#8492](https://github.com/jdx/mise/pull/8492)\n- **(http)** store tool opts as native TOML to fix platform switching by @jdx in [#8448](https://github.com/jdx/mise/pull/8448)\n- **(installer)** error if MISE_INSTALL_PATH is a directory by @jdx in [#8468](https://github.com/jdx/mise/pull/8468)\n- **(prepare)** resolve sources/outputs relative to `dir` when set by @jdx in [#8472](https://github.com/jdx/mise/pull/8472)\n- **(ruby)** fetch precompiled binary by release tag instead of listing all releases by @jdx in [#8488](https://github.com/jdx/mise/pull/8488)\n- **(schema)** support structured objects in task depends by @risu729 in [#8463](https://github.com/jdx/mise/pull/8463)\n- **(task)** replace println!/eprintln! with calm_io in task output macros by @vmaleze in [#8485](https://github.com/jdx/mise/pull/8485)\n- handle scoped npm package names without backend prefix by @jdx in [#8477](https://github.com/jdx/mise/pull/8477)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:copr docker digest to c485c4c by @renovate[bot] in [#8484](https://github.com/jdx/mise/pull/8484)\n- update ghcr.io/jdx/mise:alpine docker digest to 8118bc7 by @renovate[bot] in [#8483](https://github.com/jdx/mise/pull/8483)\n\n### 📦 Registry\n\n- disable sd version test by @jdx in [#8489](https://github.com/jdx/mise/pull/8489)\n\n### New Contributors\n\n- @ivy made their first contribution in [#8481](https://github.com/jdx/mise/pull/8481)\n- @iki made their first contribution in [#8424](https://github.com/jdx/mise/pull/8424)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (5)\n\n- [`datadog-labs/pup`](https://github.com/datadog-labs/pup)\n- [`k1LoW/mo`](https://github.com/k1LoW/mo)\n- [`rtk-ai/rtk`](https://github.com/rtk-ai/rtk)\n- [`suzuki-shunsuke/docfresh`](https://github.com/suzuki-shunsuke/docfresh)\n- [`yashikota/exiftool-go`](https://github.com/yashikota/exiftool-go)\n\n#### Updated Packages (6)\n\n- [`cloudflare/cloudflared`](https://github.com/cloudflare/cloudflared)\n- [`mozilla/sccache`](https://github.com/mozilla/sccache)\n- [`owenlamont/ryl`](https://github.com/owenlamont/ryl)\n- [`spinel-coop/rv`](https://github.com/spinel-coop/rv)\n- [`technicalpickles/envsense`](https://github.com/technicalpickles/envsense)\n- [`weaviate/weaviate`](https://github.com/weaviate/weaviate)\n\n## [2026.3.3](https://github.com/jdx/mise/compare/v2026.3.2..v2026.3.3) - 2026-03-04\n\n### 🐛 Bug Fixes\n\n- **(installer)** guard zstd archive selection on zstd binary availability by @octo in [#8460](https://github.com/jdx/mise/pull/8460)\n\n### New Contributors\n\n- @octo made their first contribution in [#8460](https://github.com/jdx/mise/pull/8460)\n\n## [2026.3.2](https://github.com/jdx/mise/compare/v2026.3.1..v2026.3.2) - 2026-03-04\n\n### 🚀 Features\n\n- add `--local` flag to `outdated` and `upgrade` commands by @malept in [#8451](https://github.com/jdx/mise/pull/8451)\n\n### 🐛 Bug Fixes\n\n- **(env)** apply redactions for env vars with both tools=true and redact=true by @jdx in [#8449](https://github.com/jdx/mise/pull/8449)\n- **(prepare)** render tera templates in prepare.env values by @jdx in [#8450](https://github.com/jdx/mise/pull/8450)\n- correct regex syntax in tar/zstd version check by @chadlwilson in [#8453](https://github.com/jdx/mise/pull/8453)\n\n### 🚜 Refactor\n\n- prevent double-iteration when parsing idiomatic version files by @risu729 in [#8417](https://github.com/jdx/mise/pull/8417)\n\n### 🧪 Testing\n\n- **(tasks)** stabilize assertions and shell compatibility by @mackwic in [#8438](https://github.com/jdx/mise/pull/8438)\n\n### 📦 Registry\n\n- add tinygo ([aqua:tinygo-org/tinygo](https://github.com/tinygo-org/tinygo)) by @artemklevtsov in [#8446](https://github.com/jdx/mise/pull/8446)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`kunobi-ninja/kunobi`](https://github.com/kunobi-ninja/kunobi)\n\n## [2026.3.1](https://github.com/jdx/mise/compare/v2026.3.0..v2026.3.1) - 2026-03-03\n\n### 🐛 Bug Fixes\n\n- **(swift)** fallback to system pkgutil path on macOS by @mackwic in [#8435](https://github.com/jdx/mise/pull/8435)\n- **(task)** skip depends_post when pre-dependency fails and main task never runs by @jdx in [#8426](https://github.com/jdx/mise/pull/8426)\n- Fix regex for tar version check by @autarch in [#8430](https://github.com/jdx/mise/pull/8430)\n\n### 🧪 Testing\n\n- **(e2e)** improve runner portability and timeout handling by @mackwic in [#8437](https://github.com/jdx/mise/pull/8437)\n\n### 📦 Registry\n\n- fix julia version_expr closure syntax by @jdx in [#8420](https://github.com/jdx/mise/pull/8420)\n\n### Chore\n\n- **(ci)** tighten docker workflow tag filter to v[0-9]* by @jdx in [#8422](https://github.com/jdx/mise/pull/8422)\n- remove devcontainer and docker development setup by @jdx in [#8421](https://github.com/jdx/mise/pull/8421)\n\n## [2026.3.0](https://github.com/jdx/mise/compare/v2026.2.24..v2026.3.0) - 2026-03-02\n\n### 🚀 Features\n\n- **(hooks)** add task references to hooks and watch_files by @jdx in [#8400](https://github.com/jdx/mise/pull/8400)\n- **(prepare)** add git-submodule built-in provider by @jdx in [#8407](https://github.com/jdx/mise/pull/8407)\n- **(prepare)** add human-readable stale reasons to prepare output by @jdx in [#8408](https://github.com/jdx/mise/pull/8408)\n- **(prepare)** add dependency ordering to prepare steps by @jdx in [#8401](https://github.com/jdx/mise/pull/8401)\n- **(prepare)** add --explain flag for provider diagnostics by @jdx in [#8409](https://github.com/jdx/mise/pull/8409)\n- **(prepare)** add per-provider timeout support by @jdx in [#8405](https://github.com/jdx/mise/pull/8405)\n- **(prepare)** add blake3 content-hash freshness checking by @jdx in [#8404](https://github.com/jdx/mise/pull/8404)\n- **(tasks)** monorepo vars and per-task vars by @halms in [#8248](https://github.com/jdx/mise/pull/8248)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** restore bin_paths disk cache with fresh_file invalidation by @jdx in [#8398](https://github.com/jdx/mise/pull/8398)\n- **(idiomatic)** use generic parser for idiomatic files by @risu729 in [#8171](https://github.com/jdx/mise/pull/8171)\n- **(install)** apply precompiled options to all platforms in lockfile by @jdx in [#8396](https://github.com/jdx/mise/pull/8396)\n- **(install)** normalize \"v\" prefix when matching lockfile versions by @jdx in [#8413](https://github.com/jdx/mise/pull/8413)\n- **(prepare)** improve git submodule parser and fix check_staleness error handling by @jdx in [#8412](https://github.com/jdx/mise/pull/8412)\n- **(python)** respect precompiled settings in lock file generation by @jdx in [#8399](https://github.com/jdx/mise/pull/8399)\n- **(python)** clarify uv_venv_auto docs + prevent uv shim recursion in venv creation by @halms in [#8402](https://github.com/jdx/mise/pull/8402)\n- **(task)** remove deprecated `# mise` task header syntax by @jdx in [#8403](https://github.com/jdx/mise/pull/8403)\n- **(vfox)** avoid eager metadata loading during config file detection by @jdx in [#8397](https://github.com/jdx/mise/pull/8397)\n- clarify GitHub attestations to be artifact ones by @scop in [#8394](https://github.com/jdx/mise/pull/8394)\n- ignore comments in idiomatic version files by @iloveitaly in [#7682](https://github.com/jdx/mise/pull/7682)\n\n### 🚜 Refactor\n\n- unify archive detection by @risu729 in [#8137](https://github.com/jdx/mise/pull/8137)\n\n### 📚 Documentation\n\n- remove duplicated docs for npm.package_manager by @risu729 in [#8414](https://github.com/jdx/mise/pull/8414)\n\n## [2026.2.24](https://github.com/jdx/mise/compare/v2026.2.23..v2026.2.24) - 2026-02-28\n\n### 🐛 Bug Fixes\n\n- **(aqua)** remove unnecessary bin_paths disk cache by @jdx in [#8383](https://github.com/jdx/mise/pull/8383)\n- **(hooks)** render tera templates and fix output masking by @jdx in [#8385](https://github.com/jdx/mise/pull/8385)\n- **(install)** improve error when registry tool has no supported backends by @jdx in [#8388](https://github.com/jdx/mise/pull/8388)\n- **(python)** remove deprecated venv_auto_create setting by @jdx in [#8384](https://github.com/jdx/mise/pull/8384)\n\n## [2026.2.23](https://github.com/jdx/mise/compare/v2026.2.22..v2026.2.23) - 2026-02-28\n\n### 🚀 Features\n\n- **(backend-plugin)** pass options to vfox backend plugins by @Attempt3035 in [#8369](https://github.com/jdx/mise/pull/8369)\n\n### 🐛 Bug Fixes\n\n- **(install)** prevent --locked mode from modifying or bypassing lockfile by @jdx in [#8362](https://github.com/jdx/mise/pull/8362)\n- **(install)** clear aqua bin_paths cache after install to prevent stale PATH by @jdx in [#8374](https://github.com/jdx/mise/pull/8374)\n- **(task)** prevent broken pipe panic and race condition in remote git task cache by @vmaleze in [#8375](https://github.com/jdx/mise/pull/8375)\n\n### 📦️ Dependency Updates\n\n- update docker/build-push-action digest to 10e90e3 by @renovate[bot] in [#8367](https://github.com/jdx/mise/pull/8367)\n- update fedora:43 docker digest to 781b764 by @renovate[bot] in [#8368](https://github.com/jdx/mise/pull/8368)\n\n### 📦 Registry\n\n- add porter ([github:getporter/porter](https://github.com/getporter/porter)) by @lbergnehr in [#8380](https://github.com/jdx/mise/pull/8380)\n- add entire ([aqua:entireio/cli](https://github.com/entireio/cli)) by @TyceHerrman in [#8378](https://github.com/jdx/mise/pull/8378)\n- add topgrade ([aqua:topgrade-rs/topgrade](https://github.com/topgrade-rs/topgrade)) by @TyceHerrman in [#8377](https://github.com/jdx/mise/pull/8377)\n\n### Chore\n\n- remove pre-commit config and tool dependency by @jdx in [#8373](https://github.com/jdx/mise/pull/8373)\n\n### New Contributors\n\n- @Attempt3035 made their first contribution in [#8369](https://github.com/jdx/mise/pull/8369)\n- @lbergnehr made their first contribution in [#8380](https://github.com/jdx/mise/pull/8380)\n\n## [2026.2.22](https://github.com/jdx/mise/compare/v2026.2.21..v2026.2.22) - 2026-02-27\n\n### 🚀 Features\n\n- add `--outdated` flag to `mise plugins ls` by @jdx in [#8360](https://github.com/jdx/mise/pull/8360)\n\n### 🐛 Bug Fixes\n\n- **(github)** resolve rename_exe search dir for archives with bin/ subdirectory by @jdx in [#8358](https://github.com/jdx/mise/pull/8358)\n- **(install)** skip tools=true env directives during backend installation by @jdx in [#8356](https://github.com/jdx/mise/pull/8356)\n- **(ruby)** resolve correct Windows checksums in lockfile by @jdx in [#8357](https://github.com/jdx/mise/pull/8357)\n\n### 📦 Registry\n\n- switch terradozer backend to github fork by @chenrui333 in [#8365](https://github.com/jdx/mise/pull/8365)\n\n### Chore\n\n- **(release)** fix duplicated version prefix in release title by @jdx in [#8359](https://github.com/jdx/mise/pull/8359)\n\n### New Contributors\n\n- @chenrui333 made their first contribution in [#8365](https://github.com/jdx/mise/pull/8365)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`huseyinbabal/taws`](https://github.com/huseyinbabal/taws)\n\n#### Updated Packages (2)\n\n- [`block/goose`](https://github.com/block/goose)\n- [`pre-commit/pre-commit`](https://github.com/pre-commit/pre-commit)\n\n## [2026.2.21](https://github.com/jdx/mise/compare/v2026.2.20..v2026.2.21) - 2026-02-26\n\n### 🐛 Bug Fixes\n\n- **(exec)** respect PATH order for virtualenv resolution in mise x by @jdx in [#8342](https://github.com/jdx/mise/pull/8342)\n- **(task)** revert process group changes that cause hangs with nested mise tasks by @jdx in [#8347](https://github.com/jdx/mise/pull/8347)\n- **(task)** resolve vars from subdirectory configs for monorepo tasks by @jdx in [#8343](https://github.com/jdx/mise/pull/8343)\n- **(task)** resolve dependencies before prepare to fix monorepo glob deps by @jdx in [#8353](https://github.com/jdx/mise/pull/8353)\n- python noarch with Conda backend by @wolfv in [#8349](https://github.com/jdx/mise/pull/8349)\n\n### New Contributors\n\n- @wolfv made their first contribution in [#8349](https://github.com/jdx/mise/pull/8349)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (3)\n\n- [`alexhallam/tv`](https://github.com/alexhallam/tv)\n- [`arcanist-sh/hx`](https://github.com/arcanist-sh/hx)\n- [`dathere/qsv`](https://github.com/dathere/qsv)\n\n#### Updated Packages (3)\n\n- [`astral-sh/ruff`](https://github.com/astral-sh/ruff)\n- [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner)\n- [`rhysd/actionlint`](https://github.com/rhysd/actionlint)\n\n## [2026.2.20](https://github.com/jdx/mise/compare/v2026.2.19..v2026.2.20) - 2026-02-25\n\n### 🚀 Features\n\n- **(conda)** replace custom backend with rattler crates by @jdx in [#8325](https://github.com/jdx/mise/pull/8325)\n- **(task)** enforce per-task timeout configuration by @tvararu in [#8250](https://github.com/jdx/mise/pull/8250)\n- **(vsix)** added vsix archives to http backend by @sosumappu in [#8306](https://github.com/jdx/mise/pull/8306)\n- add core dotnet plugin for .NET SDK management by @jdx in [#8326](https://github.com/jdx/mise/pull/8326)\n\n### 🐛 Bug Fixes\n\n- **(conda)** preserve conda_packages on locked install and fix temp file race by @jdx in [#8335](https://github.com/jdx/mise/pull/8335)\n- **(conda)** deduplicate repodata records to fix solver error on Linux by @jdx in [#8337](https://github.com/jdx/mise/pull/8337)\n- **(env)** include watch_files in fast-path early exit check by @jdx in [#8317](https://github.com/jdx/mise/pull/8317)\n- **(env)** clear fish completions when setting/unsetting shell aliases by @jdx in [#8324](https://github.com/jdx/mise/pull/8324)\n- **(lockfile)** prevent lockfile writes when --locked is set by @jdx in [#8308](https://github.com/jdx/mise/pull/8308)\n- **(lockfile)** prune orphan tool entries on mise lock by @mackwic in [#8265](https://github.com/jdx/mise/pull/8265)\n- **(lockfile)** error on contradictory locked=true + lockfile=false config by @jdx in [#8329](https://github.com/jdx/mise/pull/8329)\n- **(regal)** Update package location by @charlieegan3 in [#8315](https://github.com/jdx/mise/pull/8315)\n- **(release)** strip markdown heading prefix from communique release title by @jdx in [#8303](https://github.com/jdx/mise/pull/8303)\n- **(schema)** enforce additionalProperties constraint for env by @adamliang0 in [#8328](https://github.com/jdx/mise/pull/8328)\n\n### 📚 Documentation\n\n- Remove incorrect oh-my-zsh plugin ordering comment by @bvosk in [#8323](https://github.com/jdx/mise/pull/8323)\n- require AI disclosure on GitHub comments by @jdx in [#8330](https://github.com/jdx/mise/pull/8330)\n\n### 📦 Registry\n\n- add `oxfmt` by @taoufik07 in [#8316](https://github.com/jdx/mise/pull/8316)\n\n### New Contributors\n\n- @adamliang0 made their first contribution in [#8328](https://github.com/jdx/mise/pull/8328)\n- @tvararu made their first contribution in [#8250](https://github.com/jdx/mise/pull/8250)\n- @bvosk made their first contribution in [#8323](https://github.com/jdx/mise/pull/8323)\n- @taoufik07 made their first contribution in [#8316](https://github.com/jdx/mise/pull/8316)\n- @charlieegan3 made their first contribution in [#8315](https://github.com/jdx/mise/pull/8315)\n- @sosumappu made their first contribution in [#8306](https://github.com/jdx/mise/pull/8306)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (3)\n\n- [`Tyrrrz/FFmpegBin`](https://github.com/Tyrrrz/FFmpegBin)\n- [`elixir-lang/expert`](https://github.com/elixir-lang/expert)\n- [`erikjuhani/basalt`](https://github.com/erikjuhani/basalt)\n\n#### Updated Packages (5)\n\n- [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner)\n- [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local)\n- [`jackchuka/mdschema`](https://github.com/jackchuka/mdschema)\n- [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases)\n- [`peco/peco`](https://github.com/peco/peco)\n\n## [2026.2.19](https://github.com/jdx/mise/compare/v2026.2.18..v2026.2.19) - 2026-02-22\n\n### 🐛 Bug Fixes\n\n- **(docs)** correct ripgrep command by @nguyenvulong in [#8299](https://github.com/jdx/mise/pull/8299)\n- **(task)** skip setpgid for TTY stdin to fix interactive tasks by @jdx in [#8301](https://github.com/jdx/mise/pull/8301)\n- clean up empty parent install dir on failed install by @jdx in [#8302](https://github.com/jdx/mise/pull/8302)\n\n### Chore\n\n- **(release)** run communique via mise x for PATH resolution by @jdx in [#8294](https://github.com/jdx/mise/pull/8294)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (2)\n\n- [`kubie-org/kubie`](https://github.com/kubie-org/kubie)\n- [`steipete/gogcli`](https://github.com/steipete/gogcli)\n\n## [2026.2.18](https://github.com/jdx/mise/compare/v2026.2.17..v2026.2.18) - 2026-02-21\n\n### 🚀 Features\n\n- **(install)** auto-lock all platforms after tool installation by @jdx in [#8277](https://github.com/jdx/mise/pull/8277)\n\n### 🐛 Bug Fixes\n\n- **(config)** respect --yes flag for config trust prompts by @jdx in [#8288](https://github.com/jdx/mise/pull/8288)\n- **(exec)** strip shims from PATH on Unix to prevent infinite recursion by @jdx in [#8276](https://github.com/jdx/mise/pull/8276)\n- **(install)** validate --locked before --dry-run short-circuit by @altendky in [#8290](https://github.com/jdx/mise/pull/8290)\n- **(release)** refresh PATH after mise up in release-plz by @jdx in [#8292](https://github.com/jdx/mise/pull/8292)\n- **(schema)** replace unevaluatedProperties with additionalProperties by @jdx in [#8285](https://github.com/jdx/mise/pull/8285)\n- **(task)** avoid duplicated stderr on task failure in replacing mode by @jdx in [#8275](https://github.com/jdx/mise/pull/8275)\n- **(task)** use process groups to kill child process trees on Unix by @jdx in [#8279](https://github.com/jdx/mise/pull/8279)\n- **(task)** run depends_post tasks even when parent task fails by @jdx in [#8274](https://github.com/jdx/mise/pull/8274)\n- **(task)** suggest similar commands when mistyping a CLI subcommand by @jdx in [#8286](https://github.com/jdx/mise/pull/8286)\n- **(task)** execute monorepo subdirectory prepare steps from root by @jdx in [#8291](https://github.com/jdx/mise/pull/8291)\n- **(upgrade)** don't force-reinstall already installed versions by @jdx in [#8282](https://github.com/jdx/mise/pull/8282)\n- **(watch)** restore terminal state after watchexec exits by @jdx in [#8273](https://github.com/jdx/mise/pull/8273)\n\n### 📚 Documentation\n\n- clarify that MISE_CEILING_PATHS excludes the ceiling directory itself by @jdx in [#8283](https://github.com/jdx/mise/pull/8283)\n\n### Chore\n\n- replace gen-release-notes script with communique by @jdx in [#8289](https://github.com/jdx/mise/pull/8289)\n\n### New Contributors\n\n- @altendky made their first contribution in [#8290](https://github.com/jdx/mise/pull/8290)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (4)\n\n- [`Skarlso/crd-to-sample-yaml`](https://github.com/Skarlso/crd-to-sample-yaml)\n- [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases)\n- [`swanysimon/markdownlint-rs`](https://github.com/swanysimon/markdownlint-rs)\n- [`tmux/tmux-builds`](https://github.com/tmux/tmux-builds)\n\n#### Updated Packages (2)\n\n- [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local)\n- [`k1LoW/runn`](https://github.com/k1LoW/runn)\n\n## [2026.2.17](https://github.com/jdx/mise/compare/v2026.2.16..v2026.2.17) - 2026-02-19\n\n### 🚀 Features\n\n- **(prepare)** update mtime of outputs after command is run by @halms in [#8243](https://github.com/jdx/mise/pull/8243)\n\n### 🐛 Bug Fixes\n\n- **(install)** use backend bin paths for per-tool postinstall hooks by @jdx in [#8234](https://github.com/jdx/mise/pull/8234)\n- **(use)** write to config.toml instead of config.local.toml by @jdx in [#8240](https://github.com/jdx/mise/pull/8240)\n- default legacy .mise.backend installs to non-explicit by @jean-humann in [#8245](https://github.com/jdx/mise/pull/8245)\n\n### 🚜 Refactor\n\n- **(config)** consolidate flat task_* settings into nested task.* by @jdx in [#8239](https://github.com/jdx/mise/pull/8239)\n\n### Chore\n\n- **(prepare)** refactor common code into ProviderBase by @halms in [#8246](https://github.com/jdx/mise/pull/8246)\n\n### 📦 Aqua Registry Updates\n\n#### Updated Packages (1)\n\n- [`namespacelabs/foundation/nsc`](https://github.com/namespacelabs/foundation/nsc)\n\n## [2026.2.16](https://github.com/jdx/mise/compare/v2026.2.15..v2026.2.16) - 2026-02-17\n\n### 🚀 Features\n\n- **(mcp)** add run_task tool for executing mise tasks by @joaommartins in [#8179](https://github.com/jdx/mise/pull/8179)\n- **(node)** suggest setting node.flavor if the flavor is not found in mirror by @risu729 in [#8206](https://github.com/jdx/mise/pull/8206)\n\n### 🐛 Bug Fixes\n\n- **(java)** sort order for shorthand versions by @roele in [#8197](https://github.com/jdx/mise/pull/8197)\n- **(node)** migrate env vars to settings by @risu729 in [#8200](https://github.com/jdx/mise/pull/8200)\n- **(registry)** apply overrides in shims by @risu729 in [#8199](https://github.com/jdx/mise/pull/8199)\n- migrate MISE_CARGO_BINSTALL_ONLY to settings by @risu729 in [#8202](https://github.com/jdx/mise/pull/8202)\n\n### 📚 Documentation\n\n- **(doctor)** fix subcommand in an example by @risu729 in [#8198](https://github.com/jdx/mise/pull/8198)\n\n### 📦 Registry\n\n- add github backend for typst by @3w36zj6 in [#8210](https://github.com/jdx/mise/pull/8210)\n\n### Chore\n\n- **(test)** disable flaky Forgejo e2e test by @jdx in [#8211](https://github.com/jdx/mise/pull/8211)\n\n## [2026.2.15](https://github.com/jdx/mise/compare/v2026.2.14..v2026.2.15) - 2026-02-17\n\n### 🚀 Features\n\n- **(task)** stream keep-order output in real-time per task by @jdx in [#8164](https://github.com/jdx/mise/pull/8164)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** resolve lockfile artifacts for target platform (fix discussion #7479) by @mackwic in [#8183](https://github.com/jdx/mise/pull/8183)\n- **(exec)** strip shims from PATH to prevent recursive shim execution by @jdx in [#8189](https://github.com/jdx/mise/pull/8189)\n- **(hook-env)** preserve PATH reordering done after activation by @jdx in [#8190](https://github.com/jdx/mise/pull/8190)\n- **(lockfile)** resolve version aliases before lockfile lookup by @jdx in [#8194](https://github.com/jdx/mise/pull/8194)\n- **(registry)** set helm-diff archive bin name to diff by @jean-humann in [#8173](https://github.com/jdx/mise/pull/8173)\n- **(task)** improve source freshness checks with dynamic task dirs by @rooperuu in [#8169](https://github.com/jdx/mise/pull/8169)\n- **(task)** resolve global tasks when running from monorepo root by @jdx in [#8192](https://github.com/jdx/mise/pull/8192)\n- **(task)** prevent wildcard glob `test:*` from matching parent task `test` by @jdx in [#8165](https://github.com/jdx/mise/pull/8165)\n- **(task)** resolve task_config.includes relative to config root by @jdx in [#8193](https://github.com/jdx/mise/pull/8193)\n- **(upgrade)** skip untrusted tracked configs during upgrade by @jdx in [#8195](https://github.com/jdx/mise/pull/8195)\n\n### 🚜 Refactor\n\n- use enum for npm.pacakge_manager by @risu729 in [#8180](https://github.com/jdx/mise/pull/8180)\n\n### 📚 Documentation\n\n- **(plugins)** replace node/asdf-nodejs examples with vfox plugins by @jdx in [#8191](https://github.com/jdx/mise/pull/8191)\n\n### ⚡ Performance\n\n- call npm view only once by @risu729 in [#8181](https://github.com/jdx/mise/pull/8181)\n\n### New Contributors\n\n- @jean-humann made their first contribution in [#8173](https://github.com/jdx/mise/pull/8173)\n- @mackwic made their first contribution in [#8183](https://github.com/jdx/mise/pull/8183)\n- @rooperuu made their first contribution in [#8169](https://github.com/jdx/mise/pull/8169)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (2)\n\n- [`BetterDiscord/cli`](https://github.com/BetterDiscord/cli)\n- [`glossia.ai/cli`](https://github.com/glossia.ai/cli)\n\n## [2026.2.14](https://github.com/jdx/mise/compare/v2026.2.13..v2026.2.14) - 2026-02-16\n\n### 🚀 Features\n\n- **(vfox)** allow plugins to request env var redaction via MiseEnvResult by @jdx in [#8166](https://github.com/jdx/mise/pull/8166)\n- add a default_host setting for rust by @aacebedo in [#8154](https://github.com/jdx/mise/pull/8154)\n- add github_content package support for aqua backend by @risu729 in [#8147](https://github.com/jdx/mise/pull/8147)\n- support devEngines.runtime in deno by @risu729 in [#8144](https://github.com/jdx/mise/pull/8144)\n\n### 🐛 Bug Fixes\n\n- **(asset_matcher)** penalize vsix files by @risu729 in [#8151](https://github.com/jdx/mise/pull/8151)\n- **(edit)** strip formatting whitespace from TOML values in `mise edit` by @jdx in [#8162](https://github.com/jdx/mise/pull/8162)\n- **(install)** improve --locked support for python and ubi backends by @jdx in [#8163](https://github.com/jdx/mise/pull/8163)\n- **(npm)** suppress npm update notifier while npm install by @risu729 in [#8152](https://github.com/jdx/mise/pull/8152)\n- **(schema)** add task_templates, extends, and timeout by @risu729 in [#8145](https://github.com/jdx/mise/pull/8145)\n\n### 🚜 Refactor\n\n- **(registry)** remove [key=value] options syntax from backends by @risu729 in [#8146](https://github.com/jdx/mise/pull/8146)\n\n### 📚 Documentation\n\n- **(settings)** remove wrong tip for github_attestations by @risu729 in [#8158](https://github.com/jdx/mise/pull/8158)\n\n### Chore\n\n- **(release-plz)** delete embedded plugins directory before update by @risu729 in [#8149](https://github.com/jdx/mise/pull/8149)\n- adds necessary env var to the mcp help message in cli by @joaommartins in [#8133](https://github.com/jdx/mise/pull/8133)\n\n### New Contributors\n\n- @joaommartins made their first contribution in [#8133](https://github.com/jdx/mise/pull/8133)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (5)\n\n- [`containers/podlet`](https://github.com/containers/podlet)\n- [`hickford/git-credential-azure`](https://github.com/hickford/git-credential-azure)\n- [`hickford/git-credential-oauth`](https://github.com/hickford/git-credential-oauth)\n- [`kovetskiy/mark`](https://github.com/kovetskiy/mark)\n- [`openbao/openbao/bao`](https://github.com/openbao/openbao/bao)\n\n## [2026.2.13](https://github.com/jdx/mise/compare/v2026.2.12..v2026.2.13) - 2026-02-15\n\n### 📦️ Dependency Updates\n\n- bump sigstore-verification to 0.2 by @jdx in [e8897c9](https://github.com/jdx/mise/commit/e8897c9fbc873fe272495a65e5a88b04b97f3b6d)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`k1LoW/tcmux`](https://github.com/k1LoW/tcmux)\n\n#### Updated Packages (1)\n\n- [`jdx/usage`](https://github.com/jdx/usage)\n\n## [2026.2.12](https://github.com/jdx/mise/compare/v2026.2.11..v2026.2.12) - 2026-02-14\n\n### 🚀 Features\n\n- **(java)** add a java.shorthand_vendor setting by @roele in [#8134](https://github.com/jdx/mise/pull/8134)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (4)\n\n- [`IvanIsCoding/celq`](https://github.com/IvanIsCoding/celq)\n- [`postfinance/topf`](https://github.com/postfinance/topf)\n- [`runkids/skillshare`](https://github.com/runkids/skillshare)\n- [`sandreas/tone`](https://github.com/sandreas/tone)\n\n## [2026.2.11](https://github.com/jdx/mise/compare/v2026.2.10..v2026.2.11) - 2026-02-12\n\n### 🚀 Features\n\n- **(env)** support array access for multiple tool versions in tera templates by @jdx in [#8129](https://github.com/jdx/mise/pull/8129)\n\n### 🐛 Bug Fixes\n\n- **(hook-env)** watch files accessed by tera template functions by @jdx in [#8122](https://github.com/jdx/mise/pull/8122)\n\n### 📦 Registry\n\n- added mutagen by @tony-sol in [#8125](https://github.com/jdx/mise/pull/8125)\n- add communique by @jdx in [#8126](https://github.com/jdx/mise/pull/8126)\n\n## [2026.2.10](https://github.com/jdx/mise/compare/v2026.2.9..v2026.2.10) - 2026-02-12\n\n### 🚀 Features\n\n- **(activate)** add shims directory as fallback when auto-install is enabled by @ctaintor in [#8106](https://github.com/jdx/mise/pull/8106)\n- **(env)** add `tools` variable to tera template context by @jdx in [#8108](https://github.com/jdx/mise/pull/8108)\n- **(set)** add --stdin flag for multiline environment variables by @jdx in [#8110](https://github.com/jdx/mise/pull/8110)\n\n### 🐛 Bug Fixes\n\n- **(backend)** improve conda patchelf and dependency resolution for complex packages by @jdx in [#8087](https://github.com/jdx/mise/pull/8087)\n- **(ci)** fix validate-new-tools grep pattern for test field by @jdx in [#8100](https://github.com/jdx/mise/pull/8100)\n- **(config)** make MISE_OFFLINE work correctly by gracefully skipping network calls by @jdx in [#8109](https://github.com/jdx/mise/pull/8109)\n- **(github)** skip v prefix for \"latest\" version by @jdx in [#8105](https://github.com/jdx/mise/pull/8105)\n- **(gitlab)** resolve tool options from config for aliased tools by @jdx in [#8084](https://github.com/jdx/mise/pull/8084)\n- **(install)** use version_expr for Flutter to fix version resolution by @jdx in [#8081](https://github.com/jdx/mise/pull/8081)\n- **(registry)** add Linux support for tuist by @fortmarek in [#8102](https://github.com/jdx/mise/pull/8102)\n- **(release)** write release notes to file instead of capturing stdout by @jdx in [#8086](https://github.com/jdx/mise/pull/8086)\n- **(release)** make release notes editorialization non-blocking by @jdx in [#8116](https://github.com/jdx/mise/pull/8116)\n- **(upgrade)** tools are not uninstalled properly due to outdated symlink by @roele in [#8099](https://github.com/jdx/mise/pull/8099)\n- **(upgrade)** ensure uninstallation failure does not leave invalid symlinks by @roele in [#8101](https://github.com/jdx/mise/pull/8101)\n- SLSA for in-toto statement with no signatures by @gerhard in [#8094](https://github.com/jdx/mise/pull/8094)\n- Vfox Plugin Auto-Installation for Environment Directives by @pose in [#8035](https://github.com/jdx/mise/pull/8035)\n\n### 📚 Documentation\n\n- use mise activate for PowerShell in getting-started by @rileychh in [#8112](https://github.com/jdx/mise/pull/8112)\n\n### 📦 Registry\n\n- add conda backend for mysql by @jdx in [#8080](https://github.com/jdx/mise/pull/8080)\n- add conda backends for 10 asdf-only tools by @jdx in [#8083](https://github.com/jdx/mise/pull/8083)\n- added podman-tui by @tony-sol in [#8098](https://github.com/jdx/mise/pull/8098)\n\n### Chore\n\n- sort settings.toml alphabetically and add test by @jdx in [#8111](https://github.com/jdx/mise/pull/8111)\n\n### New Contributors\n\n- @ctaintor made their first contribution in [#8106](https://github.com/jdx/mise/pull/8106)\n- @rileychh made their first contribution in [#8112](https://github.com/jdx/mise/pull/8112)\n- @fortmarek made their first contribution in [#8102](https://github.com/jdx/mise/pull/8102)\n- @pose made their first contribution in [#8035](https://github.com/jdx/mise/pull/8035)\n- @gerhard made their first contribution in [#8094](https://github.com/jdx/mise/pull/8094)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (2)\n\n- [`entireio/cli`](https://github.com/entireio/cli)\n- [`rmitchellscott/reManager`](https://github.com/rmitchellscott/reManager)\n\n#### Updated Packages (1)\n\n- [`atuinsh/atuin`](https://github.com/atuinsh/atuin)\n\n## [2026.2.9](https://github.com/jdx/mise/compare/v2026.2.8..v2026.2.9) - 2026-02-10\n\n### 🚀 Features\n\n- auto-select no-YJIT Ruby on older glibc systems by @jdx in [#8069](https://github.com/jdx/mise/pull/8069)\n\n### 🐛 Bug Fixes\n\n- **(shim)** update mise-shim.exe during self-update on Windows by @jdx in [#8075](https://github.com/jdx/mise/pull/8075)\n- Bump xx to 2.5 by @erickt in [#8077](https://github.com/jdx/mise/pull/8077)\n\n### 📚 Documentation\n\n- **(ruby)** remove experimental language for precompiled binaries by @jdx in [#8073](https://github.com/jdx/mise/pull/8073)\n\n### New Contributors\n\n- @erickt made their first contribution in [#8077](https://github.com/jdx/mise/pull/8077)\n\n### 📦 Aqua Registry Updates\n\n#### Updated Packages (1)\n\n- [`carthage-software/mago`](https://github.com/carthage-software/mago)\n\n## [2026.2.8](https://github.com/jdx/mise/compare/v2026.2.7..v2026.2.8) - 2026-02-09\n\n### 🚀 Features\n\n- **(node)** support package.json as idiomatic version file by @jdx in [#8059](https://github.com/jdx/mise/pull/8059)\n- **(ruby)** graduate precompiled ruby from experimental (gradual rollout) by @jdx in [#8052](https://github.com/jdx/mise/pull/8052)\n- add --dry-run-code flag to exit non-zero when there is work to do by @jdx in [#8063](https://github.com/jdx/mise/pull/8063)\n\n### 🐛 Bug Fixes\n\n- **(core)** respect MISE_ARCH override in bun and erlang plugins by @jdx in [#8062](https://github.com/jdx/mise/pull/8062)\n- **(hooks)** resolve 12 community-reported hooks issues by @jdx in [#8058](https://github.com/jdx/mise/pull/8058)\n- accept key=value format in set/add subcommands by @jdx in [#8053](https://github.com/jdx/mise/pull/8053)\n\n### 📚 Documentation\n\n- bump action versions in GitHub Actions examples by @muzimuzhi in [#8065](https://github.com/jdx/mise/pull/8065)\n- add opengraph meta tags by @jdx in [#8066](https://github.com/jdx/mise/pull/8066)\n\n### 📦️ Dependency Updates\n\n- upgrade toml to 0.9 and toml_edit to 0.24 (TOML 1.1) by @jdx in [#8057](https://github.com/jdx/mise/pull/8057)\n\n### 📦 Registry\n\n- add quicktype (npm:quicktype) by @zdunecki in [#8054](https://github.com/jdx/mise/pull/8054)\n- use inline table for test definitions by @jdx in [#8056](https://github.com/jdx/mise/pull/8056)\n\n## [2026.2.7](https://github.com/jdx/mise/compare/v2026.2.6..v2026.2.7) - 2026-02-08\n\n### 🚀 Features\n\n- **(shim)** add native .exe shim mode for Windows by @jdx in [#8045](https://github.com/jdx/mise/pull/8045)\n\n### 🐛 Bug Fixes\n\n- **(install)** preserve config options and registry defaults by @jdx in [#8044](https://github.com/jdx/mise/pull/8044)\n- **(link)** linked versions override lockfile during resolution by @jdx in [#8050](https://github.com/jdx/mise/pull/8050)\n- **(release)** preserve aqua-registry sections in changelog across releases by @jdx in [#8047](https://github.com/jdx/mise/pull/8047)\n- ls --all-sources shows duplicate entries by @roele in [#8042](https://github.com/jdx/mise/pull/8042)\n\n### 📚 Documentation\n\n- replace \"inherit\" terminology with config layering by @jdx in [#8046](https://github.com/jdx/mise/pull/8046)\n\n### 📦 Registry\n\n- switch oxlint to npm backend by default by @risu729 in [#8038](https://github.com/jdx/mise/pull/8038)\n- add orval (npm:orval) by @zdunecki in [#8051](https://github.com/jdx/mise/pull/8051)\n\n### New Contributors\n\n- @zdunecki made their first contribution in [#8051](https://github.com/jdx/mise/pull/8051)\n\n## [2026.2.6](https://github.com/jdx/mise/compare/v2026.2.5..v2026.2.6) - 2026-02-07\n\n### 🚀 Features\n\n- **(env)** add shell-style variable expansion in env values by @jdx in [#8029](https://github.com/jdx/mise/pull/8029)\n- **(list)** add --all-sources flag to list command by @TylerHillery in [#8019](https://github.com/jdx/mise/pull/8019)\n\n### 🐛 Bug Fixes\n\n- **(gem)** Windows support for gem backend by @my1e5 in [#8031](https://github.com/jdx/mise/pull/8031)\n- **(gem)** revert gem.rs script newline change by @my1e5 in [#8034](https://github.com/jdx/mise/pull/8034)\n- **(lock)** write tools to lockfile matching their source config by @jdx in [#8012](https://github.com/jdx/mise/pull/8012)\n- **(ls)** sort sources deterministically in --all-sources output by @jdx in [#8037](https://github.com/jdx/mise/pull/8037)\n- **(task)** auto-install tools from mise.toml for file tasks by @jdx in [#8030](https://github.com/jdx/mise/pull/8030)\n\n### 📚 Documentation\n\n- fix wrong positions of `mise run` flags by @muzimuzhi in [#8036](https://github.com/jdx/mise/pull/8036)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:copr docker digest to 3e00d7d by @renovate[bot] in [#8023](https://github.com/jdx/mise/pull/8023)\n- update ghcr.io/jdx/mise:alpine docker digest to 0ced1b3 by @renovate[bot] in [#8022](https://github.com/jdx/mise/pull/8022)\n\n### 📦 Registry\n\n- add tirith ([github:sheeki03/tirith](https://github.com/sheeki03/tirith)) by @sheeki03 in [#8024](https://github.com/jdx/mise/pull/8024)\n- add mas by @TyceHerrman in [#8032](https://github.com/jdx/mise/pull/8032)\n\n### Security\n\n- **(deps)** update time crate to 0.3.47 to fix RUSTSEC-2026-0009 by @jdx in [#8026](https://github.com/jdx/mise/pull/8026)\n\n### New Contributors\n\n- @sheeki03 made their first contribution in [#8024](https://github.com/jdx/mise/pull/8024)\n- @TylerHillery made their first contribution in [#8019](https://github.com/jdx/mise/pull/8019)\n\n### 📦 Aqua Registry Updates\n\n#### New Packages (1)\n\n- [`kubernetes-sigs/kubectl-validate`](https://github.com/kubernetes-sigs/kubectl-validate)\n\n#### Updated Packages (6)\n\n- [`flux-iac/tofu-controller/tfctl`](https://github.com/flux-iac/tofu-controller/tfctl)\n- [`gogs/gogs`](https://github.com/gogs/gogs)\n- [`j178/prek`](https://github.com/j178/prek)\n- [`syncthing/syncthing`](https://github.com/syncthing/syncthing)\n- [`tuist/tuist`](https://github.com/tuist/tuist)\n- [`yaml/yamlscript`](https://github.com/yaml/yamlscript)\n## [2026.2.5](https://github.com/jdx/mise/compare/v2026.2.4..v2026.2.5) - 2026-02-06\n\n### 🐛 Bug Fixes\n\n- **(lock)** remove experimental flag requirement for lockfiles by @jdx in [#8011](https://github.com/jdx/mise/pull/8011)\n\n### Chore\n\n- add tone calibration to release notes prompt by @jdx in [#8010](https://github.com/jdx/mise/pull/8010)\n\n## [2026.2.4](https://github.com/jdx/mise/compare/v2026.2.3..v2026.2.4) - 2026-02-05\n\n### 🐛 Bug Fixes\n\n- **(env)** resolve sourced env for tool templates by @corymhall in [#7895](https://github.com/jdx/mise/pull/7895)\n- **(npm)** only declare the configured package manager as a dependency by @jdx in [#7995](https://github.com/jdx/mise/pull/7995)\n- **(upgrade)** respect use_locked_version when checking tracked configs by @jdx in [#7997](https://github.com/jdx/mise/pull/7997)\n- ignore MISE_TOOL_VERSION in env var parsing by @jdx in [#8004](https://github.com/jdx/mise/pull/8004)\n\n### New Contributors\n\n- @corymhall made their first contribution in [#7895](https://github.com/jdx/mise/pull/7895)\n\n## [2026.2.3](https://github.com/jdx/mise/compare/v2026.2.2..v2026.2.3) - 2026-02-04\n\n### 🐛 Bug Fixes\n\n- **(install)** allow pipx/npm/cargo/asdf backends to work in locked mode by @jdx in [#7985](https://github.com/jdx/mise/pull/7985)\n\n### 📦️ Dependency Updates\n\n- update bytes to 1.11.1 to fix RUSTSEC-2026-0007 by @jdx in [#7986](https://github.com/jdx/mise/pull/7986)\n\n### 📦 Registry\n\n- add mermaid-ascii by @TyceHerrman in [#7984](https://github.com/jdx/mise/pull/7984)\n- add godot ([aqua:godotengine/godot](https://github.com/godotengine/godot)) by @dmarcoux in [#7989](https://github.com/jdx/mise/pull/7989)\n- add julia (http:julia) by @quinnj in [#7990](https://github.com/jdx/mise/pull/7990)\n\n### New Contributors\n\n- @quinnj made their first contribution in [#7990](https://github.com/jdx/mise/pull/7990)\n- @dmarcoux made their first contribution in [#7989](https://github.com/jdx/mise/pull/7989)\n\n## [2026.2.2](https://github.com/jdx/mise/compare/v2026.2.1..v2026.2.2) - 2026-02-03\n\n### 🚀 Features\n\n- **(asset-matcher)** enable `mingw-w64` detection for windows packages by @lchagnoleau in [#7981](https://github.com/jdx/mise/pull/7981)\n- **(crates/vfox)** add download_path to BackendInstall context by @malept in [#7959](https://github.com/jdx/mise/pull/7959)\n- **(python)** rework `python.uv_venv_auto` setting by @halms in [#7905](https://github.com/jdx/mise/pull/7905)\n- add \"Did you mean?\" suggestions and inactive tool warnings by @jdx in [#7965](https://github.com/jdx/mise/pull/7965)\n\n### 🐛 Bug Fixes\n\n- **(hook-env)** skip remote version fetching for uninstalled tools in prefer-offline mode by @jdx in [#7976](https://github.com/jdx/mise/pull/7976)\n- **(install.sh)** Corret `setup` to `set up` by @gogolok in [#7980](https://github.com/jdx/mise/pull/7980)\n- retry spawn on ETXTBSY (Text file busy) by @jdx in [#7964](https://github.com/jdx/mise/pull/7964)\n- improve ToolOptions parsing to support comma separated values by @roele in [#7971](https://github.com/jdx/mise/pull/7971)\n\n### 📚 Documentation\n\n- improve plugin documentation with comparisons and template links by @jdx in [#7962](https://github.com/jdx/mise/pull/7962)\n\n### 📦️ Dependency Updates\n\n- bump hyper-util, system-configuration, lru, aws-sdk, and others by @jdx in [#7977](https://github.com/jdx/mise/pull/7977)\n\n### Chore\n\n- **(vfox)** add LuaCATS type definitions for plugin IDE support by @jdx in [#7961](https://github.com/jdx/mise/pull/7961)\n- **(vfox)** add `download_path` to `BackendInstallCtx` type defintion by @malept in [#7973](https://github.com/jdx/mise/pull/7973)\n- add stylua linting for vfox plugin Lua files by @jdx in [#7960](https://github.com/jdx/mise/pull/7960)\n- use system Rust for PPA builds on Ubuntu 26.04+ by @jdx in [#7956](https://github.com/jdx/mise/pull/7956)\n\n### New Contributors\n\n- @gogolok made their first contribution in [#7980](https://github.com/jdx/mise/pull/7980)\n\n## [2026.2.1](https://github.com/jdx/mise/compare/v2026.2.0..v2026.2.1) - 2026-02-02\n\n### 🚀 Features\n\n- **(generate)** implement --index flag and use task names for task-docs --multi by @jdx in [#7944](https://github.com/jdx/mise/pull/7944)\n- **(plugins)** warn when env plugin shadows a registry tool by @jdx in [#7953](https://github.com/jdx/mise/pull/7953)\n- **(tool-stub)** add --lock flag to generate tool-stub by @jdx in [#7948](https://github.com/jdx/mise/pull/7948)\n- **(vfox)** add log module for Lua plugins by @jdx in [#7949](https://github.com/jdx/mise/pull/7949)\n- **(vfox)** switch Lua runtime from Lua 5.1 to Luau by @jdx in [#7954](https://github.com/jdx/mise/pull/7954)\n\n### 🐛 Bug Fixes\n\n- **(build)** upgrade cross images to :main for C++17 support by @jdx in [#7958](https://github.com/jdx/mise/pull/7958)\n- **(build)** update glibc check to match new cross image baseline by @jdx in [fc1247e](https://github.com/jdx/mise/commit/fc1247e84b91957e4d6e6841be3af7a95f242625)\n- **(registry)** handle file:// URLs in normalize_remote by @jdx in [#7947](https://github.com/jdx/mise/pull/7947)\n- **(vfox)** fix LuaLS warnings in test fixtures and add linting by @jdx in [#7946](https://github.com/jdx/mise/pull/7946)\n\n### 🚜 Refactor\n\n- unify deprecated_at! macro with warn and remove versions by @jdx in [#7957](https://github.com/jdx/mise/pull/7957)\n\n### 🧪 Testing\n\n- remove unnecessary end-of-test cleanup from e2e tests by @jdx in [#7950](https://github.com/jdx/mise/pull/7950)\n\n### ◀️ Revert\n\n- Revert \"fix(build): update glibc check to match new cross image baseline\" by @jdx in [0774bf9](https://github.com/jdx/mise/commit/0774bf99d4a2ab2a30553a7db09f79223cdc5aa6)\n- Revert \"fix(build): upgrade cross images to :main for C++17 support \" by @jdx in [8dcca08](https://github.com/jdx/mise/commit/8dcca086e87c1b29343e2842c6c68ec949dd60f4)\n- Revert \"feat(vfox): switch Lua runtime from Lua 5.1 to Luau \" by @jdx in [8b4322d](https://github.com/jdx/mise/commit/8b4322d693702890e268d9c1e9309536ffdbd8fc)\n\n## [2026.2.0](https://github.com/jdx/mise/compare/v2026.1.12..v2026.2.0) - 2026-02-01\n\n### 🚀 Features\n\n- **(edit)** add interactive config editor (`mise edit`) by @jdx in [#7930](https://github.com/jdx/mise/pull/7930)\n- **(lockfile)** graduate lockfiles from experimental by @jdx in [#7929](https://github.com/jdx/mise/pull/7929)\n- **(task)** add support for usage values in task confirm dialog by @roele in [#7924](https://github.com/jdx/mise/pull/7924)\n- **(task)** improve source freshness checking with edge case handling by @jdx in [#7932](https://github.com/jdx/mise/pull/7932)\n\n### 🐛 Bug Fixes\n\n- **(activate)** preserve ordering of paths appended after mise activate by @jdx in [#7919](https://github.com/jdx/mise/pull/7919)\n- **(install)** sort failed installations for deterministic error output by @jdx in [#7936](https://github.com/jdx/mise/pull/7936)\n- **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [#7923](https://github.com/jdx/mise/pull/7923)\n- **(lockfile)** add atomic writes and cache invalidation by @jdx in [#7927](https://github.com/jdx/mise/pull/7927)\n- **(release)** add mise-interactive-config to release-plz publish workflow by @jdx in [#7940](https://github.com/jdx/mise/pull/7940)\n- **(release)** handle mise-interactive-config schema during cargo publish by @jdx in [#7942](https://github.com/jdx/mise/pull/7942)\n- **(release)** include mise.json in mise-interactive-config package by @jdx in [3689a4a](https://github.com/jdx/mise/commit/3689a4a83c7e886ba15082f99674ebc6398056e3)\n- **(task)** discover and run shebang file tasks on Windows by @jdx in [#7941](https://github.com/jdx/mise/pull/7941)\n- **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [#7925](https://github.com/jdx/mise/pull/7925)\n- **(upgrade)** respect tracked configs when pruning old versions by @jdx in [#7926](https://github.com/jdx/mise/pull/7926)\n\n### 🚜 Refactor\n\n- **(progress)** migrate from indicatif to clx by @jdx in [#7928](https://github.com/jdx/mise/pull/7928)\n\n### 📚 Documentation\n\n- improve clarity on uvx and pipx dependencies by @ygormutti in [#7878](https://github.com/jdx/mise/pull/7878)\n\n### ⚡ Performance\n\n- **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [#7933](https://github.com/jdx/mise/pull/7933)\n- use Aho-Corasick for efficient redaction by @jdx in [#7931](https://github.com/jdx/mise/pull/7931)\n\n### 🧪 Testing\n\n- remove flaky test_http_version_list test by @jdx in [#7934](https://github.com/jdx/mise/pull/7934)\n\n### Chore\n\n- use github backend instead of ubi in mise.lock by @jdx in [#7922](https://github.com/jdx/mise/pull/7922)\n\n### New Contributors\n\n- @ygormutti made their first contribution in [#7878](https://github.com/jdx/mise/pull/7878)\n\n## [2026.1.12](https://github.com/jdx/mise/compare/v2026.1.11..v2026.1.12) - 2026-01-31\n\n### 🐛 Bug Fixes\n\n- **(task)** resolve monorepo task includes relative to config file directory by @jdx in [#7917](https://github.com/jdx/mise/pull/7917)\n- disable autocrlf on git clone to fix WSL issues by @jdx in [#7916](https://github.com/jdx/mise/pull/7916)\n\n### 📚 Documentation\n\n- **(tasks)** add bash array pattern for variadic args by @jdx in [#7914](https://github.com/jdx/mise/pull/7914)\n\n## [2026.1.11](https://github.com/jdx/mise/compare/v2026.1.10..v2026.1.11) - 2026-01-30\n\n### 🚀 Features\n\n- **(config)** load local .config/miserc.toml too by @scop in [#7896](https://github.com/jdx/mise/pull/7896)\n- **(vfox)** pass constructed env to module hooks for cmd.exec by @jdx in [#7908](https://github.com/jdx/mise/pull/7908)\n\n### 🐛 Bug Fixes\n\n- **(cache)** resolve correct cache path when clearing GitHub backend tools by @jdx in [#7907](https://github.com/jdx/mise/pull/7907)\n- **(ci)** handle aqua subpath backends in grace period check by @jdx in [3dcf20c](https://github.com/jdx/mise/commit/3dcf20cd3054e5038e7e81a736dfe9187656eead)\n- **(github)** support macOS .app bundle binary discovery by @jdx in [#7885](https://github.com/jdx/mise/pull/7885)\n- **(prepare)** scope prepare providers to their defining config file by @jdx in [#7889](https://github.com/jdx/mise/pull/7889)\n- **(registry)** update daytona asset pattern for new release naming by @jdx in [#7897](https://github.com/jdx/mise/pull/7897)\n- **(registry)** revert daytona asset pattern to simple naming by @jdx in [#7911](https://github.com/jdx/mise/pull/7911)\n- **(run)** show task info instead of executing when --help used without usage spec by @jdx in [#7893](https://github.com/jdx/mise/pull/7893)\n- **(task)** fix wait_for with env overrides and re-render outputs by @jdx in [#7888](https://github.com/jdx/mise/pull/7888)\n- use correct MISE comment format and remove invalid usage field by @jdx in [89d87ba](https://github.com/jdx/mise/commit/89d87ba1331a60ffa5c1f55ee8da96e6be59c59c)\n- add #USAGE arg spec for check-release-failures task by @jdx in [8bfab84](https://github.com/jdx/mise/commit/8bfab845d310ec26337f24f154e2b63fc12cdf86)\n- use mise tool --json instead of regex parsing registry files by @jdx in [22d1513](https://github.com/jdx/mise/commit/22d1513eb7a3e97f1f806960dafa3a06732eafbb)\n\n### 🚜 Refactor\n\n- consolidate retry + grace period logic into mise task by @jdx in [794efb4](https://github.com/jdx/mise/commit/794efb40ff0b8c5be1bdbb78146b7358b255fac7)\n\n### 📚 Documentation\n\n- **(gitlab)** explain MISE_GITLAB_TOKEN for private repo by @lchagnoleau in [#7902](https://github.com/jdx/mise/pull/7902)\n\n### ⚡ Performance\n\n- **(exec)** reduce startup overhead for `mise x` by @jdx in [#7890](https://github.com/jdx/mise/pull/7890)\n- **(install)** replace per-tool .mise.backend with consolidated manifest by @jdx in [#7892](https://github.com/jdx/mise/pull/7892)\n\n### 📦️ Dependency Updates\n\n- update docker/login-action digest to c94ce9f by @renovate[bot] in [#7899](https://github.com/jdx/mise/pull/7899)\n- update alpine:edge docker digest to 9a341ff by @renovate[bot] in [#7898](https://github.com/jdx/mise/pull/7898)\n- update ghcr.io/jdx/mise:alpine docker digest to 3a67fe5 by @renovate[bot] in [#7900](https://github.com/jdx/mise/pull/7900)\n- update ghcr.io/jdx/mise:copr docker digest to 4dc8174 by @renovate[bot] in [#7901](https://github.com/jdx/mise/pull/7901)\n- update ghcr.io/jdx/mise:deb docker digest to af0c0b5 by @renovate[bot] in [#7903](https://github.com/jdx/mise/pull/7903)\n- update ghcr.io/jdx/mise:rpm docker digest to a53bf55 by @renovate[bot] in [#7904](https://github.com/jdx/mise/pull/7904)\n\n### Chore\n\n- **(ci)** only auto-merge release PRs with substantive changes by @jdx in [#7884](https://github.com/jdx/mise/pull/7884)\n- **(ci)** ignore test-tool failures from recent upstream releases on release branch by @jdx in [9ca4e8d](https://github.com/jdx/mise/commit/9ca4e8d273da94a8ef1fcdaa3ba4489bd8561a37)\n- **(registry)** disable buck2 test due to checksum race condition by @jdx in [a658eaa](https://github.com/jdx/mise/commit/a658eaa6d5ce56040c48dcb4a3f34b6abb15cca9)\n\n### New Contributors\n\n- @autofix-ci[bot] made their first contribution\n- @lchagnoleau made their first contribution in [#7902](https://github.com/jdx/mise/pull/7902)\n\n## [2026.1.9](https://github.com/jdx/mise/compare/v2026.1.8..v2026.1.9) - 2026-01-28\n\n### 🚀 Features\n\n- **(doctor)** add backend mismatch warnings by @jdx in [#7847](https://github.com/jdx/mise/pull/7847)\n- **(http)** add rename_exe support for archive extraction by @jdx in [#7874](https://github.com/jdx/mise/pull/7874)\n- **(http)** send x-mise-ci header for CI environment tracking by @jdx in [#7875](https://github.com/jdx/mise/pull/7875)\n- **(install)** auto-install plugins from [plugins] config section by @jdx in [#7856](https://github.com/jdx/mise/pull/7856)\n- **(registry)** add vercel by @mikecurtis in [#7844](https://github.com/jdx/mise/pull/7844)\n- **(task)** support glob patterns in task_config.includes by @jdx in [#7870](https://github.com/jdx/mise/pull/7870)\n- **(task)** add task templates for reusable task definitions by @jdx in [#7873](https://github.com/jdx/mise/pull/7873)\n\n### 🐛 Bug Fixes\n\n- **(backend)** change registry mismatch log from info to debug by @jdx in [#7858](https://github.com/jdx/mise/pull/7858)\n- **(ci)** use squash merge for auto-merge-release workflow by @jdx in [7e5e71e](https://github.com/jdx/mise/commit/7e5e71e3b065518f08c2fb187789c13b594c0c9d)\n- **(ci)** remove --auto flag to merge immediately when CI passes by @jdx in [23ed2ed](https://github.com/jdx/mise/commit/23ed2edf03d7f28640b0516e1f02d0f240626d4e)\n- **(github)** select platform-matching provenance file for SLSA verification by @jdx in [#7853](https://github.com/jdx/mise/pull/7853)\n- **(go)** filter out version \"1\" from available versions by @jdx in [#7871](https://github.com/jdx/mise/pull/7871)\n- **(install)** skip CurDir components when detecting archive structure by @jdx in [#7868](https://github.com/jdx/mise/pull/7868)\n- **(pipx)** ensure Python minor version symlink exists for postinstall hooks by @jdx in [#7869](https://github.com/jdx/mise/pull/7869)\n- **(registry)** prevent duplicate -stable suffix in Flutter download URLs by @jdx in [#7872](https://github.com/jdx/mise/pull/7872)\n- **(task)** pass env to usage parser for env-backed arguments by @jdx in [#7848](https://github.com/jdx/mise/pull/7848)\n- **(task)** propagate MISE_ENV to child tasks when using -E flag by @jdx in [06ee776](https://github.com/jdx/mise/commit/06ee77643fcebfe03b37e6a235cf4f1c258a4e34)\n- **(vfox-dotnet)** use os.execute() to fix Windows installation by @prodrigues1912 in [#7843](https://github.com/jdx/mise/pull/7843)\n\n### 📚 Documentation\n\n- update cache-behavior with env_cache information by @jdx in [#7849](https://github.com/jdx/mise/pull/7849)\n\n### ◀️ Revert\n\n- remove task inheritance from parent configs in monorepos by @jdx in [#7851](https://github.com/jdx/mise/pull/7851)\n- Revert \"fix(ci): remove --auto flag to merge immediately when CI passes\" by @jdx in [0606187](https://github.com/jdx/mise/commit/06061878d2abfd5194425f11f7a47237cd5039e3)\n\n### 📦 Registry\n\n- add mago ([aqua:carthage-software/mago](https://github.com/carthage-software/mago)) by @scop in [#7845](https://github.com/jdx/mise/pull/7845)\n\n### Chore\n\n- **(ci)** auto-merge release branch into main daily at 4am CST by @jdx in [#7852](https://github.com/jdx/mise/pull/7852)\n\n### New Contributors\n\n- @mikecurtis made their first contribution in [#7844](https://github.com/jdx/mise/pull/7844)\n- @prodrigues1912 made their first contribution in [#7843](https://github.com/jdx/mise/pull/7843)\n\n## [2026.1.8](https://github.com/jdx/mise/compare/v2026.1.7..v2026.1.8) - 2026-01-27\n\n### 🐛 Bug Fixes\n\n- **(aqua)** invalidate lockfile when asset doesn't match registry by @jdx in [#7830](https://github.com/jdx/mise/pull/7830)\n- **(aqua)** add warnings when version tag lookup fails by @jdx in [#7831](https://github.com/jdx/mise/pull/7831)\n- **(github)** penalize Windows-specific extensions on non-Windows platforms by @jdx in [#7838](https://github.com/jdx/mise/pull/7838)\n- **(task)** resolve monorepo task env vars in usage spec by @jdx in [#7832](https://github.com/jdx/mise/pull/7832)\n- **(task)** support dotted keys and deep-merge in file task headers by @jdx in [#7840](https://github.com/jdx/mise/pull/7840)\n- don't thank @jdx in LLM-generated release notes by @jdx in [#7835](https://github.com/jdx/mise/pull/7835)\n- ensure that idiomatic and toolversions show in ls --local by @offbyone in [#7836](https://github.com/jdx/mise/pull/7836)\n\n### 🚜 Refactor\n\n- **(registry)** split registry.toml into one file per tool by @jdx in [#7820](https://github.com/jdx/mise/pull/7820)\n\n### 📚 Documentation\n\n- improve conventional commit guidance in CLAUDE.md by @jdx in [cbf2f74](https://github.com/jdx/mise/commit/cbf2f7472a8aea858fc8008a30aedfd10f5f6382)\n\n### 📦️ Dependency Updates\n\n- lock file maintenance by @renovate[bot] in [#7826](https://github.com/jdx/mise/pull/7826)\n- lock file maintenance by @renovate[bot] in [#7827](https://github.com/jdx/mise/pull/7827)\n\n### Chore\n\n- **(ci)** add CI failure feedback to pr-closer workflow by @jdx in [#7821](https://github.com/jdx/mise/pull/7821)\n- **(ci)** add FORGEJO_TOKEN for Codeberg API authentication by @jdx in [#7841](https://github.com/jdx/mise/pull/7841)\n\n### Registry\n\n- **(claude)** add aqua backend as default by @jdx in [#7842](https://github.com/jdx/mise/pull/7842)\n\n## [2026.1.7](https://github.com/jdx/mise/compare/v2026.1.6..v2026.1.7) - 2026-01-25\n\n### 🐛 Bug Fixes\n\n- **(backend)** resolve registry mismatch for previously installed tools by @smorimoto in [#7773](https://github.com/jdx/mise/pull/7773)\n- **(env_cache)** use cached watch_files to avoid plugin re-execution by @jdx in [#7817](https://github.com/jdx/mise/pull/7817)\n- **(github)** handle projectname@version tag format by @jdx in [#7788](https://github.com/jdx/mise/pull/7788)\n- **(http)** add fromJSON/keys to version_expr for HashiCorp tools by @jdx in [#7816](https://github.com/jdx/mise/pull/7816)\n\n### 📚 Documentation\n\n- **(contributing)** correct ripgrep command by @nguyenvulong in [#7805](https://github.com/jdx/mise/pull/7805)\n- **(contributing)** update hk usages by @muzimuzhi in [#7797](https://github.com/jdx/mise/pull/7797)\n\n### 📦 Registry\n\n- add claude-powerline by @TyceHerrman in [#7798](https://github.com/jdx/mise/pull/7798)\n- add rpk by @artemklevtsov in [#7802](https://github.com/jdx/mise/pull/7802)\n\n### New Contributors\n\n- @smorimoto made their first contribution in [#7773](https://github.com/jdx/mise/pull/7773)\n- @nguyenvulong made their first contribution in [#7805](https://github.com/jdx/mise/pull/7805)\n\n## [2026.1.6](https://github.com/jdx/mise/compare/v2026.1.5..v2026.1.6) - 2026-01-21\n\n### 🚀 Features\n\n- **(config)** add miette diagnostics for TOML parsing errors by @jdx in [#7764](https://github.com/jdx/mise/pull/7764)\n- **(env)** add environment caching with module cacheability support by @jdx in [#7761](https://github.com/jdx/mise/pull/7761)\n\n### 🐛 Bug Fixes\n\n- **(prepare)** handle freshness check for auto-created venvs by @jdx in [#7770](https://github.com/jdx/mise/pull/7770)\n- **(release)** use colon separator in release titles by @jdx in [#7765](https://github.com/jdx/mise/pull/7765)\n- **(release)** drop Fedora 41 from COPR build (EOL) by @TobiX in [#7771](https://github.com/jdx/mise/pull/7771)\n- **(release)** bump version until unused when publishing subcrates by @jdx in [#7787](https://github.com/jdx/mise/pull/7787)\n- **(tasks)** include task tools in env resolution cache check by @jdx in [#7786](https://github.com/jdx/mise/pull/7786)\n- rust lockfile by @vadimpiven in [#7780](https://github.com/jdx/mise/pull/7780)\n- Ensure tool stubs have dependency toolset paths as well by @thejcannon in [#7777](https://github.com/jdx/mise/pull/7777)\n\n### 🚜 Refactor\n\n- improve filetask field parsing tests and parser by @makp0 in [#7751](https://github.com/jdx/mise/pull/7751)\n\n### 📚 Documentation\n\n- improve CLAUDE.md with additional development guidance by @jdx in [#7763](https://github.com/jdx/mise/pull/7763)\n- drop architecture from Debian sources.list by @TobiX in [#7772](https://github.com/jdx/mise/pull/7772)\n\n### 📦 Registry\n\n- use aqua for zprint by @scop in [#7767](https://github.com/jdx/mise/pull/7767)\n- add miller ([aqua:johnkerl/miller](https://github.com/johnkerl/miller)) by @kit494way in [#7782](https://github.com/jdx/mise/pull/7782)\n- add atlas-community ([aqua:ariga/atlas/community](https://github.com/ariga/atlas/community)) by @akanter in [#7784](https://github.com/jdx/mise/pull/7784)\n\n### Security\n\n- remove insecure registry-comment workflow by @jdx in [#7769](https://github.com/jdx/mise/pull/7769)\n\n## [2026.1.5](https://github.com/jdx/mise/compare/v2026.1.4..v2026.1.5) - 2026-01-19\n\n### 🚀 Features\n\n- **(complete)** add PowerShell completion support by @jdx in [#7746](https://github.com/jdx/mise/pull/7746)\n- **(release)** add LLM-generated prose summary to release notes by @jdx in [#7737](https://github.com/jdx/mise/pull/7737)\n- **(vfox)** add semver Lua module for version sorting by @jdx in [#7739](https://github.com/jdx/mise/pull/7739)\n- **(vfox)** add rolling release support with checksum tracking by @jdx in [#7757](https://github.com/jdx/mise/pull/7757)\n- dry filetask parsing and validation by @makp0 in [#7738](https://github.com/jdx/mise/pull/7738)\n\n### 🐛 Bug Fixes\n\n- **(completions)** bump usage-cli to 2.13.1 for PowerShell support by @jdx in [#7756](https://github.com/jdx/mise/pull/7756)\n- schema missing env required string variant by @vadimpiven in [#7734](https://github.com/jdx/mise/pull/7734)\n- validate unknown fields in filetask headers by @makp0 in [#7733](https://github.com/jdx/mise/pull/7733)\n- disable schemacrawler test by @jdx in [#7743](https://github.com/jdx/mise/pull/7743)\n- replace double forward slash with single slash in get_task_lists by @collinstevens in [#7744](https://github.com/jdx/mise/pull/7744)\n- require LLM for release notes and include aqua section by @jdx in [#7745](https://github.com/jdx/mise/pull/7745)\n- preserve {{ version }} in tool options during config load by @jdx in [#7755](https://github.com/jdx/mise/pull/7755)\n\n### 📚 Documentation\n\n- add documentation URL structure guidance to CLAUDE.md by @jdx in [#7740](https://github.com/jdx/mise/pull/7740)\n- add pitchfork promotion by @jdx in [#7747](https://github.com/jdx/mise/pull/7747)\n\n### 📦️ Dependency Updates\n\n- relax version constraints and update dependencies by @jdx in [#7736](https://github.com/jdx/mise/pull/7736)\n- lock file maintenance by @renovate[bot] in [#7749](https://github.com/jdx/mise/pull/7749)\n\n### Chore\n\n- bump xx to 2.3.1 by @jdx in [#7753](https://github.com/jdx/mise/pull/7753)\n\n### New Contributors\n\n- @collinstevens made their first contribution in [#7744](https://github.com/jdx/mise/pull/7744)\n- @makp0 made their first contribution in [#7738](https://github.com/jdx/mise/pull/7738)\n- @vadimpiven made their first contribution in [#7734](https://github.com/jdx/mise/pull/7734)\n\n## [2026.1.4](https://github.com/jdx/mise/compare/v2026.1.3..v2026.1.4) - 2026-01-17\n\n### 🚀 Features\n\n- **(conda)** add dependency locking for reproducible installations by @jdx in [#7708](https://github.com/jdx/mise/pull/7708)\n- **(http)** add JSON filter syntax for version extraction by @jdx in [#7707](https://github.com/jdx/mise/pull/7707)\n- **(http)** add version_expr support and Tera templating by @jdx in [#7723](https://github.com/jdx/mise/pull/7723)\n- **(task)** add [monorepo].config_roots for explicit config root listing by @jdx in [#7705](https://github.com/jdx/mise/pull/7705)\n- **(task)** support env vars in task dependencies by @jdx in [#7724](https://github.com/jdx/mise/pull/7724)\n\n### 🐛 Bug Fixes\n\n- **(conda)** fix hardcoded library paths in conda packages by @jdx in [#7713](https://github.com/jdx/mise/pull/7713)\n- **(env)** avoid venv/go backend deadlock during env resolution by @stk0vrfl0w in [#7696](https://github.com/jdx/mise/pull/7696)\n- **(locked)** exempt tool stubs from lockfile requirements by @jdx in [#7729](https://github.com/jdx/mise/pull/7729)\n- **(python)** sort CPython versions at end of ls-remote output by @jdx in [#7721](https://github.com/jdx/mise/pull/7721)\n- **(task)** resolve remote task files before display and validation commands by @yannrouillard in [#7681](https://github.com/jdx/mise/pull/7681)\n- **(task)** support monorepo paths in `mise tasks deps` by @chadxz in [#7699](https://github.com/jdx/mise/pull/7699)\n- **(task)** resolve all monorepo path hints in deps by @chadxz in [#7698](https://github.com/jdx/mise/pull/7698)\n\n### 📚 Documentation\n\n- remove outdated roadmap page by @jdx in [#7726](https://github.com/jdx/mise/pull/7726)\n\n### ⚡ Performance\n\n- **(task)** fix task-ls cached performance regression by @jdx in [#7716](https://github.com/jdx/mise/pull/7716)\n\n### 📦️ Dependency Updates\n\n- replace dependency @tsconfig/node22 with @tsconfig/node24 by @renovate[bot] in [#7618](https://github.com/jdx/mise/pull/7618)\n\n### 📦 Registry\n\n- add aqua backend for smithy by @jdx in [#7661](https://github.com/jdx/mise/pull/7661)\n- remove low-usage asdf plugins by @jdx in [#7701](https://github.com/jdx/mise/pull/7701)\n- disable mirrord test by @jdx in [#7703](https://github.com/jdx/mise/pull/7703)\n- use vfox-dotnet as default backend by @jdx in [#7704](https://github.com/jdx/mise/pull/7704)\n- use vfox-lua as default lua backend by @jdx in [#7706](https://github.com/jdx/mise/pull/7706)\n- add vfox backend for redis by @jdx in [#7709](https://github.com/jdx/mise/pull/7709)\n- use vfox-postgres as default postgres backend by @jdx in [#7710](https://github.com/jdx/mise/pull/7710)\n- use github backend for kotlin by @jdx in [#7711](https://github.com/jdx/mise/pull/7711)\n- add vfox backend for leiningen by @jdx in [#7714](https://github.com/jdx/mise/pull/7714)\n- use pipx backend for meson by @jdx in [#7712](https://github.com/jdx/mise/pull/7712)\n- use github backend for crystal by @jdx in [#7715](https://github.com/jdx/mise/pull/7715)\n- use conda backend for sqlite by @jdx in [#7718](https://github.com/jdx/mise/pull/7718)\n- use conda backend for make by @jdx in [#7719](https://github.com/jdx/mise/pull/7719)\n- swift-package-list use github backend by @jdx in [#7720](https://github.com/jdx/mise/pull/7720)\n\n### Chore\n\n- increase macos release build timeout to 90 minutes by @jdx in [#7725](https://github.com/jdx/mise/pull/7725)\n\n### New Contributors\n\n- @yannrouillard made their first contribution in [#7681](https://github.com/jdx/mise/pull/7681)\n- @stk0vrfl0w made their first contribution in [#7696](https://github.com/jdx/mise/pull/7696)\n\n## [2026.1.3](https://github.com/jdx/mise/compare/v2026.1.2..v2026.1.3) - 2026-01-16\n\n### 🚀 Features\n\n- **(s3)** add S3 backend for private artifact storage by @jdx in [#7668](https://github.com/jdx/mise/pull/7668)\n- **(upgrade)** use installed_tool completer for mise upgrade by @jdx in [#7670](https://github.com/jdx/mise/pull/7670)\n- **(upgrade)** add --exclude flag to mise upgrade command by @jdx in [#7669](https://github.com/jdx/mise/pull/7669)\n- add no hooks and no env flags by @aacebedo in [#7560](https://github.com/jdx/mise/pull/7560)\n\n### 🐛 Bug Fixes\n\n- **(backend)** allow upgrading vfox backend tools with symlinked installations by @TyceHerrman in [#7012](https://github.com/jdx/mise/pull/7012)\n- **(backend)** reject architecture mismatches in asset selection by @jdx in [#7672](https://github.com/jdx/mise/pull/7672)\n- **(backend)** canonicalize symlink target before installs check by @jdx in [#7671](https://github.com/jdx/mise/pull/7671)\n- **(npm)** avoid circular dependency when npm is in dependencies by @AprilNEA in [#7644](https://github.com/jdx/mise/pull/7644)\n- **(self-update)** skip update when already at latest version by @jdx in [#7666](https://github.com/jdx/mise/pull/7666)\n- fall back to GITHUB_TOKEN for github.com by @subdigital in [#7667](https://github.com/jdx/mise/pull/7667)\n- GitHub token fallback by @subdigital in [#7673](https://github.com/jdx/mise/pull/7673)\n- inherit tasks from parent configs in monorepos by @chadxz in [#7643](https://github.com/jdx/mise/pull/7643)\n\n### 📚 Documentation\n\n- **(contributing)** update registry examples by @scop in [#7660](https://github.com/jdx/mise/pull/7660)\n- **(contributing)** update registry PR title rule by @scop in [#7663](https://github.com/jdx/mise/pull/7663)\n- remove 404 link from contributing by @opswole in [#7692](https://github.com/jdx/mise/pull/7692)\n- clarify that backend plugins should sort the version list by @ofalvai in [#7680](https://github.com/jdx/mise/pull/7680)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to 11f659e by @renovate[bot] in [#7685](https://github.com/jdx/mise/pull/7685)\n- update ghcr.io/jdx/mise:copr docker digest to 3adaea4 by @renovate[bot] in [#7686](https://github.com/jdx/mise/pull/7686)\n- update ghcr.io/jdx/mise:deb docker digest to 8bbca53 by @renovate[bot] in [#7687](https://github.com/jdx/mise/pull/7687)\n- update ghcr.io/jdx/mise:rpm docker digest to de81415 by @renovate[bot] in [#7688](https://github.com/jdx/mise/pull/7688)\n- update mcr.microsoft.com/devcontainers/rust:1 docker digest to 282e805 by @renovate[bot] in [#7690](https://github.com/jdx/mise/pull/7690)\n- update rust docker digest to bed2d7f by @renovate[bot] in [#7691](https://github.com/jdx/mise/pull/7691)\n\n### 📦 Registry\n\n- add oh-my-posh by @scop in [#7659](https://github.com/jdx/mise/pull/7659)\n- add bibtex-tidy (npm:bibtex-tidy) by @3w36zj6 in [#7677](https://github.com/jdx/mise/pull/7677)\n- remove misconfigured bin_path option from kscript by @risu729 in [#7693](https://github.com/jdx/mise/pull/7693)\n\n### New Contributors\n\n- @AprilNEA made their first contribution in [#7644](https://github.com/jdx/mise/pull/7644)\n- @opswole made their first contribution in [#7692](https://github.com/jdx/mise/pull/7692)\n- @subdigital made their first contribution in [#7673](https://github.com/jdx/mise/pull/7673)\n- @aacebedo made their first contribution in [#7560](https://github.com/jdx/mise/pull/7560)\n\n## [2026.1.2](https://github.com/jdx/mise/compare/v2026.1.1..v2026.1.2) - 2026-01-13\n\n### 🐛 Bug Fixes\n\n- **(backend)** filter pre-release versions with latest + install_before by @koh-sh in [#7631](https://github.com/jdx/mise/pull/7631)\n- **(backend)** detect .artifactbundle.zip files in asset selection by @swizzlr in [#7657](https://github.com/jdx/mise/pull/7657)\n- **(docs)** formatting in configuration hierarchy section by @jonathanagustin in [#7638](https://github.com/jdx/mise/pull/7638)\n- **(http)** enhance fetch_versions to to fallback to config for tool options by @roele in [#7655](https://github.com/jdx/mise/pull/7655)\n- **(npm)** migrate npm publish to OIDC trusted publishing by @jdx in [#7607](https://github.com/jdx/mise/pull/7607)\n- **(registry)** correct checkmake version test pattern by @jdx in [#7632](https://github.com/jdx/mise/pull/7632)\n- **(release)** handle empty grep result in aqua-registry changelog by @jdx in [f45b4c6](https://github.com/jdx/mise/commit/f45b4c66d752c8e31ca103e42eda37710afd9d00)\n- **(self-update)** self-update fails across year boundary due to semver mismatch by @jdx in [#7611](https://github.com/jdx/mise/pull/7611)\n- **(tasks)** fix tool inheritance from intermediate parents by @chadxz in [#7637](https://github.com/jdx/mise/pull/7637)\n- add `-test` to VERSION_REGEX prerelease filter by @belgio99 in [#7647](https://github.com/jdx/mise/pull/7647)\n\n### 📚 Documentation\n\n- **(tasks)** remove documentation for unimplemented features by @turbocrime in [#7599](https://github.com/jdx/mise/pull/7599)\n- update `mise aliases` references to `mise tool-alias` by @muzimuzhi in [#7615](https://github.com/jdx/mise/pull/7615)\n- use call operator in PowerShell profile example by @shina1024 in [#7639](https://github.com/jdx/mise/pull/7639)\n- replace ASCII .pub key with binary .gpg for signed-by on Ubuntu/Debian by @gmalinowski in [#7649](https://github.com/jdx/mise/pull/7649)\n- add missing word by @henrebotha in [#7653](https://github.com/jdx/mise/pull/7653)\n\n### 🛡️ Security\n\n- **(security)** prevent code execution from untrusted fork in registry-comment workflow by @jdx in [4a2441e](https://github.com/jdx/mise/commit/4a2441e81649c37dc05354246f9c9c192b6e8180)\n\n### ◀️ Revert\n\n- Revert \"fix(release): handle empty grep result in aqua-registry changelog\" by @jdx in [522ffdc](https://github.com/jdx/mise/commit/522ffdcb0627c31d60bf0b7f11ae5341896ccfc9)\n- Revert \"chore(release): include manually updated aqua-registry entries in the changelog \" by @jdx in [1ebb943](https://github.com/jdx/mise/commit/1ebb9436d8b32c8dacf2ceca4d4c7a341f1a3bcb)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to fbfffcf by @renovate[bot] in [#7619](https://github.com/jdx/mise/pull/7619)\n- lock file maintenance by @renovate[bot] in [#7646](https://github.com/jdx/mise/pull/7646)\n\n### 📦 Registry\n\n- add hatoo/oha tool by @jylenhof in [#7633](https://github.com/jdx/mise/pull/7633)\n\n### Chore\n\n- **(registry)** fix registry comment workflow by @risu729 in [#7554](https://github.com/jdx/mise/pull/7554)\n- **(release)** include manually updated aqua-registry entries in the changelog by @risu729 in [#7603](https://github.com/jdx/mise/pull/7603)\n\n### New Contributors\n\n- @swizzlr made their first contribution in [#7657](https://github.com/jdx/mise/pull/7657)\n- @belgio99 made their first contribution in [#7647](https://github.com/jdx/mise/pull/7647)\n- @gmalinowski made their first contribution in [#7649](https://github.com/jdx/mise/pull/7649)\n- @chadxz made their first contribution in [#7637](https://github.com/jdx/mise/pull/7637)\n- @shina1024 made their first contribution in [#7639](https://github.com/jdx/mise/pull/7639)\n- @jonathanagustin made their first contribution in [#7638](https://github.com/jdx/mise/pull/7638)\n- @turbocrime made their first contribution in [#7599](https://github.com/jdx/mise/pull/7599)\n\n## [2026.1.1](https://github.com/jdx/mise/compare/v2026.1.0..v2026.1.1) - 2026-01-08\n\n### 🚀 Features\n\n- **(config)** add .miserc.toml for early initialization settings by @jdx in [#7596](https://github.com/jdx/mise/pull/7596)\n- allow to include tasks from git repositories by @vmaleze in [#7582](https://github.com/jdx/mise/pull/7582)\n\n### 🐛 Bug Fixes\n\n- **(config)** mise use writes to lowest precedence config file by @jdx in [#7598](https://github.com/jdx/mise/pull/7598)\n- **(python)** sort miniconda versions by conda version instead of version string by @jdx in [#7595](https://github.com/jdx/mise/pull/7595)\n- Rust channel updates installing twice by @rjvkn in [#7565](https://github.com/jdx/mise/pull/7565)\n- use Bearer instead of token in authorization headers by @risu729 in [#7593](https://github.com/jdx/mise/pull/7593)\n\n### 📚 Documentation\n\n- **(url-replacements)** document auth behaviour with url replacements by @risu729 in [#7592](https://github.com/jdx/mise/pull/7592)\n- correct spelling in walkthrough.md by @tomhoover in [#7581](https://github.com/jdx/mise/pull/7581)\n\n### 📦 Registry\n\n- Revert \"fix(registry): fix biome test to handle version prefix\" by @risu729 in [#7586](https://github.com/jdx/mise/pull/7586)\n- use aqua backend for ty by @risu729 in [#7539](https://github.com/jdx/mise/pull/7539)\n- update opencode's org from sst to anomalyco by @graelo in [#7594](https://github.com/jdx/mise/pull/7594)\n\n### New Contributors\n\n- @graelo made their first contribution in [#7594](https://github.com/jdx/mise/pull/7594)\n- @tomhoover made their first contribution in [#7581](https://github.com/jdx/mise/pull/7581)\n- @vmaleze made their first contribution in [#7582](https://github.com/jdx/mise/pull/7582)\n\n## [2026.1.0](https://github.com/jdx/mise/compare/v2025.12.13..v2026.1.0) - 2026-01-07\n\n### 🚀 Features\n\n- **(hooks)** add tool context env vars to postinstall hooks by @jdx in [#7521](https://github.com/jdx/mise/pull/7521)\n- **(sops)** support standard SOPS environment variables by @yordis in [#7461](https://github.com/jdx/mise/pull/7461)\n- **(tasks)** Add disable_spec_from_run_scripts setting by @iamkroot in [#7471](https://github.com/jdx/mise/pull/7471)\n- **(tasks)** Add task_show_full_cmd setting by @iamkroot in [#7344](https://github.com/jdx/mise/pull/7344)\n- **(tasks)** enable naked task completions and ::: separator by @jdx in [#7524](https://github.com/jdx/mise/pull/7524)\n- add Forgejo backend by @roele in [#7469](https://github.com/jdx/mise/pull/7469)\n- override node bundled npm by specified version of npm by @risu729 in [#7559](https://github.com/jdx/mise/pull/7559)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** fix tree-sitter bin path regression by @risu729 in [#7535](https://github.com/jdx/mise/pull/7535)\n- **(ci)** exclude subcrate tags from release workflow by @jdx in [#7517](https://github.com/jdx/mise/pull/7517)\n- **(e2e)** remove hardcoded year from version check by @jdx in [#7584](https://github.com/jdx/mise/pull/7584)\n- **(github)** asset matcher does not handle mixed archive/binary assets properly by @roele in [#7566](https://github.com/jdx/mise/pull/7566)\n- **(github)** prioritize .zip on windows by @risu729 in [#7568](https://github.com/jdx/mise/pull/7568)\n- **(github)** prefer .zip over non-archive extensions on linux by @risu729 in [#7587](https://github.com/jdx/mise/pull/7587)\n- **(npm)** always use hoisted installs of bun by @sushichan044 in [#7542](https://github.com/jdx/mise/pull/7542)\n- **(npm)** suppress NPM_CONFIG_UPDATE_NOTIFIER by @risu729 in [#7556](https://github.com/jdx/mise/pull/7556)\n- **(registry)** fix biome test to handle version prefix by @jdx in [#7585](https://github.com/jdx/mise/pull/7585)\n- **(tasks)** load monorepo task dirs without config by @matixlol in [#7478](https://github.com/jdx/mise/pull/7478)\n- force reshim when windows_shim_mode is hardlink by @roele in [#7537](https://github.com/jdx/mise/pull/7537)\n- simple .tar files are not extracted properly by @roele in [#7567](https://github.com/jdx/mise/pull/7567)\n- quiet kerl update output by @iloveitaly in [#7467](https://github.com/jdx/mise/pull/7467)\n\n### 📚 Documentation\n\n- **(registry)** remove ubi backend from preferred backends list by @risu729 in [#7555](https://github.com/jdx/mise/pull/7555)\n- **(tasks)** remove advanced usage specs sections from toml-tasks.md by @risu729 in [#7538](https://github.com/jdx/mise/pull/7538)\n- fix invalid config section `[aliases]` by @muzimuzhi in [#7518](https://github.com/jdx/mise/pull/7518)\n- Fix path to GitLab backend source by @henrebotha in [#7529](https://github.com/jdx/mise/pull/7529)\n- Fix path to GitLab backend source by @henrebotha in [#7531](https://github.com/jdx/mise/pull/7531)\n- update `mise --version` output by @muzimuzhi in [#7530](https://github.com/jdx/mise/pull/7530)\n\n### 🧪 Testing\n\n- **(win)** use pester in backend tests by @risu729 in [#7536](https://github.com/jdx/mise/pull/7536)\n- update e2e tests to use `[tool_alias]` instead of `[alias]` by @muzimuzhi in [#7520](https://github.com/jdx/mise/pull/7520)\n\n### 📦️ Dependency Updates\n\n- update alpine:edge docker digest to ea71a03 by @renovate[bot] in [#7545](https://github.com/jdx/mise/pull/7545)\n- update docker/setup-buildx-action digest to 8d2750c by @renovate[bot] in [#7546](https://github.com/jdx/mise/pull/7546)\n- update ghcr.io/jdx/mise:copr docker digest to 23f4277 by @renovate[bot] in [#7548](https://github.com/jdx/mise/pull/7548)\n- update ghcr.io/jdx/mise:alpine docker digest to 0adc211 by @renovate[bot] in [#7547](https://github.com/jdx/mise/pull/7547)\n- lock file maintenance by @renovate[bot] in [#7211](https://github.com/jdx/mise/pull/7211)\n- lock file maintenance by @renovate[bot] in [#7572](https://github.com/jdx/mise/pull/7572)\n- replace dependency @tsconfig/node18 with @tsconfig/node20 by @renovate[bot] in [#7543](https://github.com/jdx/mise/pull/7543)\n- replace dependency @tsconfig/node20 with @tsconfig/node22 by @renovate[bot] in [#7544](https://github.com/jdx/mise/pull/7544)\n\n### 📦 Registry\n\n- add zarf by @joonas in [#7525](https://github.com/jdx/mise/pull/7525)\n- update aws-vault to maintained fork by @h3y6e in [#7527](https://github.com/jdx/mise/pull/7527)\n- fix claude backend http for windows-x64 by @granstrand in [#7540](https://github.com/jdx/mise/pull/7540)\n- add sqlc by @phm07 in [#7570](https://github.com/jdx/mise/pull/7570)\n- use spm backend for swift-package-list by @risu729 in [#7569](https://github.com/jdx/mise/pull/7569)\n- add npm (npm:npm) by @risu729 in [#7557](https://github.com/jdx/mise/pull/7557)\n- add github backend for tmux by @ll-nick in [#7472](https://github.com/jdx/mise/pull/7472)\n\n### Chore\n\n- **(release)** update Changelog for v2025.12.13 by @muzimuzhi in [#7522](https://github.com/jdx/mise/pull/7522)\n\n### New Contributors\n\n- @ll-nick made their first contribution in [#7472](https://github.com/jdx/mise/pull/7472)\n- @sushichan044 made their first contribution in [#7542](https://github.com/jdx/mise/pull/7542)\n- @phm07 made their first contribution in [#7570](https://github.com/jdx/mise/pull/7570)\n- @granstrand made their first contribution in [#7540](https://github.com/jdx/mise/pull/7540)\n- @h3y6e made their first contribution in [#7527](https://github.com/jdx/mise/pull/7527)\n- @matixlol made their first contribution in [#7478](https://github.com/jdx/mise/pull/7478)\n\n## [2025.12.13](https://github.com/jdx/mise/compare/v2025.12.12..v2025.12.13) - 2025-12-30\n\n### 🚀 Features\n\n- **(ruby)** set PKG_CONFIG_PATH for native gem extensions by @jdx in [#7457](https://github.com/jdx/mise/pull/7457)\n- **(tera)** add haiku() function for random name generation by @jdx in [#7399](https://github.com/jdx/mise/pull/7399)\n- **(vfox)** pass tool options to EnvKeys hook by @jdx in [#7447](https://github.com/jdx/mise/pull/7447)\n- implement independent versioning for subcrates by @jdx in [#7402](https://github.com/jdx/mise/pull/7402)\n- Move iTerm to OSC9;4 supported terminals by @Maks3w in [#7485](https://github.com/jdx/mise/pull/7485)\n\n### 🐛 Bug Fixes\n\n- **(ci)** improve GHA cache efficiency and fix registry-ci bug by @jdx in [#7404](https://github.com/jdx/mise/pull/7404)\n- **(ci)** use !cancelled() instead of always() for registry-ci by @jdx in [#7435](https://github.com/jdx/mise/pull/7435)\n- **(ci)** bump taiki-e/install-action 2.61.10 to 2.65.5 by @kvokka in [#7496](https://github.com/jdx/mise/pull/7496)\n- **(e2e)** use explicit asdf backend for zprint in plugin_install test by @jdx in [#7440](https://github.com/jdx/mise/pull/7440)\n- **(github)** use GITHUB_TOKEN for attestation verification by @jdx in [#7446](https://github.com/jdx/mise/pull/7446)\n- **(go)** filter out go pre-release versions in ls-remote by @roele in [#7488](https://github.com/jdx/mise/pull/7488)\n- **(hooks)** revert per-tool hook execution by @just-be-dev in [#7509](https://github.com/jdx/mise/pull/7509)\n- **(release)** sync subcrate versions and use YYYY.MM.0 calver by @jdx in [#7516](https://github.com/jdx/mise/pull/7516)\n- **(schema)** add shell_alias definition by @anp in [#7441](https://github.com/jdx/mise/pull/7441)\n- **(schema)** add prepare config by @risu729 in [#7497](https://github.com/jdx/mise/pull/7497)\n- **(test)** update backend_arg test to use clojure instead of poetry by @jdx in [#7436](https://github.com/jdx/mise/pull/7436)\n- use vfox backend for poetry and fix related tests by @jdx in [#7445](https://github.com/jdx/mise/pull/7445)\n\n### 📚 Documentation\n\n- **(prepare)** add all source files to sources by @risu729 in [#7498](https://github.com/jdx/mise/pull/7498)\n- add link to COPR package page for Fedora/RHEL by @jdx in [bc8ac73](https://github.com/jdx/mise/commit/bc8ac732e3bdecfd12affd7b8c54cdebcdb87da1)\n- improve installation documentation by @jdx in [#7403](https://github.com/jdx/mise/pull/7403)\n- add comprehensive glossary by @jdx in [#7401](https://github.com/jdx/mise/pull/7401)\n- use `mise run` uniformly in its examples by @muzimuzhi in [#7444](https://github.com/jdx/mise/pull/7444)\n- update source file for asset autodetection by @muzimuzhi in [#7513](https://github.com/jdx/mise/pull/7513)\n\n### 🧪 Testing\n\n- **(ci)** validate GitHub token from pool with API call by @jdx in [#7459](https://github.com/jdx/mise/pull/7459)\n- rename duplicate 'ci' job names for clarity by @jdx in [#7398](https://github.com/jdx/mise/pull/7398)\n- add token pool integration for rate limit distribution by @jdx in [#7397](https://github.com/jdx/mise/pull/7397)\n\n### 📦️ Dependency Updates\n\n- replace dependency @tsconfig/node18 with @tsconfig/node20 by @renovate[bot] in [#7450](https://github.com/jdx/mise/pull/7450)\n- pin rui314/setup-mold action to 725a879 by @renovate[bot] in [#7449](https://github.com/jdx/mise/pull/7449)\n\n### 📦 Registry\n\n- add github backend for swiftformat by @jdx in [#7396](https://github.com/jdx/mise/pull/7396)\n- use pipx backend for azure-cli by @jdx in [#7406](https://github.com/jdx/mise/pull/7406)\n- use pipx backend for dvc by @jdx in [#7413](https://github.com/jdx/mise/pull/7413)\n- add github backend for zprint by @jdx in [#7410](https://github.com/jdx/mise/pull/7410)\n- use gem backend for cocoapods by @jdx in [#7411](https://github.com/jdx/mise/pull/7411)\n- use pipx backend for gallery-dl by @jdx in [#7409](https://github.com/jdx/mise/pull/7409)\n- add aqua backends for HashiCorp tools by @jdx in [#7408](https://github.com/jdx/mise/pull/7408)\n- use npm backend for danger-js by @jdx in [#7407](https://github.com/jdx/mise/pull/7407)\n- use pipx backend for pipenv by @jdx in [#7415](https://github.com/jdx/mise/pull/7415)\n- use pipx backend for poetry by @jdx in [#7416](https://github.com/jdx/mise/pull/7416)\n- add github backend for xcodegen ([github:yonaskolb/XcodeGen](https://github.com/yonaskolb/XcodeGen)) by @jdx in [#7417](https://github.com/jdx/mise/pull/7417)\n- use npm backend for heroku by @jdx in [#7418](https://github.com/jdx/mise/pull/7418)\n- add aqua backend for setup-envtest by @jdx in [#7421](https://github.com/jdx/mise/pull/7421)\n- add github backend for xcresultparser ([github:a7ex/xcresultparser](https://github.com/a7ex/xcresultparser)) by @jdx in [#7422](https://github.com/jdx/mise/pull/7422)\n- add aqua backend for tomcat by @jdx in [#7423](https://github.com/jdx/mise/pull/7423)\n- use npm backend for serverless by @jdx in [#7424](https://github.com/jdx/mise/pull/7424)\n- add github backend for daytona ([github:daytonaio/daytona](https://github.com/daytonaio/daytona)) by @jdx in [#7412](https://github.com/jdx/mise/pull/7412)\n- add github backend for flyway ([github:flyway/flyway](https://github.com/flyway/flyway)) by @jdx in [#7414](https://github.com/jdx/mise/pull/7414)\n- add github backend for schemacrawler ([github:schemacrawler/SchemaCrawler](https://github.com/schemacrawler/SchemaCrawler)) by @jdx in [#7419](https://github.com/jdx/mise/pull/7419)\n- add github backend for codeql by @jdx in [#7420](https://github.com/jdx/mise/pull/7420)\n- use pipx backend for mitmproxy by @jdx in [#7425](https://github.com/jdx/mise/pull/7425)\n- use pipx backend for sshuttle by @jdx in [#7426](https://github.com/jdx/mise/pull/7426)\n- add github backend for quarkus by @jdx in [#7428](https://github.com/jdx/mise/pull/7428)\n- add github backend for smithy by @jdx in [#7430](https://github.com/jdx/mise/pull/7430)\n- add github backend for xchtmlreport ([github:XCTestHTMLReport/XCTestHTMLReport](https://github.com/XCTestHTMLReport/XCTestHTMLReport)) by @jdx in [#7431](https://github.com/jdx/mise/pull/7431)\n- add github backend for grails by @jdx in [#7429](https://github.com/jdx/mise/pull/7429)\n- use npm backend for esy by @jdx in [#7434](https://github.com/jdx/mise/pull/7434)\n- add github backend for micronaut by @jdx in [#7433](https://github.com/jdx/mise/pull/7433)\n- add github backend for dome by @jdx in [#7432](https://github.com/jdx/mise/pull/7432)\n- use vfox backend for poetry by @jdx in [#7438](https://github.com/jdx/mise/pull/7438)\n- add vfox backend for pipenv by @jdx in [#7439](https://github.com/jdx/mise/pull/7439)\n- use github backend for xchtmlreport by @jdx in [#7442](https://github.com/jdx/mise/pull/7442)\n- use npm backend for purty by @jdx in [#7443](https://github.com/jdx/mise/pull/7443)\n- add micromamba tool definition by @rjvkn in [#7475](https://github.com/jdx/mise/pull/7475)\n- add github backend for rumdl by @kvokka in [#7494](https://github.com/jdx/mise/pull/7494)\n- add github backend for ty by @kvokka in [#7495](https://github.com/jdx/mise/pull/7495)\n- add kopia by @ldrouard in [#7501](https://github.com/jdx/mise/pull/7501)\n- add d2 by @icholy in [#7514](https://github.com/jdx/mise/pull/7514)\n\n### Chore\n\n- **(docker)** add Node LTS to mise Docker image by @jdx in [#7405](https://github.com/jdx/mise/pull/7405)\n- rename mise-tools to mise-versions by @jdx in [ab3e1b8](https://github.com/jdx/mise/commit/ab3e1b8e64c2aa881c43af7636d6b492c6001e6f)\n- s/mise task/mise tasks/g in docs and tests by @muzimuzhi in [#7400](https://github.com/jdx/mise/pull/7400)\n- update singular/plural forms for word \"task\" by @muzimuzhi in [#7448](https://github.com/jdx/mise/pull/7448)\n\n### New Contributors\n\n- @icholy made their first contribution in [#7514](https://github.com/jdx/mise/pull/7514)\n- @Maks3w made their first contribution in [#7485](https://github.com/jdx/mise/pull/7485)\n- @muzimuzhi made their first contribution in [#7513](https://github.com/jdx/mise/pull/7513)\n- @just-be-dev made their first contribution in [#7509](https://github.com/jdx/mise/pull/7509)\n- @kvokka made their first contribution in [#7495](https://github.com/jdx/mise/pull/7495)\n- @rjvkn made their first contribution in [#7475](https://github.com/jdx/mise/pull/7475)\n- @anp made their first contribution in [#7441](https://github.com/jdx/mise/pull/7441)\n\n## [2025.12.12](https://github.com/jdx/mise/compare/v2025.12.11..v2025.12.12) - 2025-12-18\n\n### 🚀 Features\n\n- **(backend)** add version timestamps for spm, conda, and gem backends by @jdx in [#7383](https://github.com/jdx/mise/pull/7383)\n- **(backend)** add security features to github backend by @jdx in [#7387](https://github.com/jdx/mise/pull/7387)\n- **(ruby)** add GitHub attestation verification for precompiled binaries by @jdx in [#7382](https://github.com/jdx/mise/pull/7382)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** improve security feature detection by @jdx in [#7385](https://github.com/jdx/mise/pull/7385)\n- **(github)** use version_prefix when fetching release for SLSA verification by @jdx in [#7391](https://github.com/jdx/mise/pull/7391)\n\n### 🚜 Refactor\n\n- **(vfox)** remove submodules, embed plugins directly by @jdx in [#7389](https://github.com/jdx/mise/pull/7389)\n\n### 🧪 Testing\n\n- **(registry)** add final ci job as merge gate by @jdx in [#7390](https://github.com/jdx/mise/pull/7390)\n- split unit job to speed up macOS CI by @jdx in [#7388](https://github.com/jdx/mise/pull/7388)\n\n## [2025.12.11](https://github.com/jdx/mise/compare/v2025.12.10..v2025.12.11) - 2025-12-18\n\n### 🚀 Features\n\n- **(alias)** rename alias to tool-alias, add shell-alias command by @jdx in [#7357](https://github.com/jdx/mise/pull/7357)\n- **(upgrade)** display summary of upgraded tools by @jdx in [#7372](https://github.com/jdx/mise/pull/7372)\n- **(vfox)** embed vfox plugin Lua code in binary by @jdx in [#7369](https://github.com/jdx/mise/pull/7369)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** add start_operations for progress reporting by @jdx in [#7354](https://github.com/jdx/mise/pull/7354)\n- **(github)** improve asset detection for distro-specific and Swift artifacts by @jdx in [#7347](https://github.com/jdx/mise/pull/7347)\n- **(github)** clean up static_helpers.rs and fix archive bin= option by @jdx in [#7366](https://github.com/jdx/mise/pull/7366)\n- **(http)** add start_operations for progress reporting by @jdx in [#7355](https://github.com/jdx/mise/pull/7355)\n- **(lockfile)** place lockfile alongside config file by @jdx in [#7360](https://github.com/jdx/mise/pull/7360)\n- **(progress)** add start_operations to core plugins by @jdx in [#7351](https://github.com/jdx/mise/pull/7351)\n- **(ruby-install)** Use ruby_install_bin to update by @calebhearth in [#7350](https://github.com/jdx/mise/pull/7350)\n- **(rust)** add release_url for rust versions by @jdx in [#7373](https://github.com/jdx/mise/pull/7373)\n- **(schema)** add `tool_alias`, mark `alias` as deprecated by @SKalt in [#7358](https://github.com/jdx/mise/pull/7358)\n- **(toolset)** filter tools by OS in list_current_versions by @jdx in [#7356](https://github.com/jdx/mise/pull/7356)\n- **(ubi)** only show deprecation warning during installation by @jdx in [#7380](https://github.com/jdx/mise/pull/7380)\n- **(ui)** remove noisy \"record size\" message during install by @jdx in [#7381](https://github.com/jdx/mise/pull/7381)\n- update mise-versions URL to use /tools/ prefix by @jdx in [#7378](https://github.com/jdx/mise/pull/7378)\n\n### 🚜 Refactor\n\n- **(backend)** unified AssetMatcher with checksum fetching by @jdx in [#7370](https://github.com/jdx/mise/pull/7370)\n- **(backend)** deprecate ubi backend in favor of github by @jdx in [#7374](https://github.com/jdx/mise/pull/7374)\n- **(toolset)** decompose mod.rs into smaller modules by @jdx in [#7371](https://github.com/jdx/mise/pull/7371)\n\n### 🧪 Testing\n\n- **(e2e)** fix and rename ubi and vfox_embedded_override tests by @jdx in [052ea40](https://github.com/jdx/mise/commit/052ea40b29468f05fbc425cc5a4c20ebda077253)\n\n### 📦 Registry\n\n- add vfox-gcloud backend for gcloud by @jdx in [#7349](https://github.com/jdx/mise/pull/7349)\n- convert amplify to use github backend by @jdx in [#7365](https://github.com/jdx/mise/pull/7365)\n- add github backend for djinni tool by @jdx in [#7363](https://github.com/jdx/mise/pull/7363)\n- switch glab to native gitlab backend by @jdx in [#7364](https://github.com/jdx/mise/pull/7364)\n- add s5cmd by @jdx in [#7376](https://github.com/jdx/mise/pull/7376)\n\n### Chore\n\n- **(registry)** disable flaky tests for gitu and ktlint by @jdx in [64151cb](https://github.com/jdx/mise/commit/64151cb3fb1e517b2c80aa2179b24c4bd55ff34a)\n- resolve clippy warnings and add stricter CI check by @jdx in [#7367](https://github.com/jdx/mise/pull/7367)\n- suppress dead_code warnings in asset_matcher module by @jdx in [#7377](https://github.com/jdx/mise/pull/7377)\n\n### New Contributors\n\n- @calebhearth made their first contribution in [#7350](https://github.com/jdx/mise/pull/7350)\n\n## [2025.12.10](https://github.com/jdx/mise/compare/v2025.12.9..v2025.12.10) - 2025-12-16\n\n### 🐛 Bug Fixes\n\n- **(backend)** fix fuzzy_match_filter regex for vendor-prefixed versions by @jdx in [#7332](https://github.com/jdx/mise/pull/7332)\n- **(backend)** use backend delegation for install-time option filtering by @jdx in [#7335](https://github.com/jdx/mise/pull/7335)\n- **(duration)** support calendar units in relative durations for --before flag by @Copilot in [#7337](https://github.com/jdx/mise/pull/7337)\n- **(gem)** improve shebang compatibility for precompiled Ruby by @jdx in [#7336](https://github.com/jdx/mise/pull/7336)\n- **(gem)** handle RubyGems polyglot shebang format by @jdx in [#7340](https://github.com/jdx/mise/pull/7340)\n- **(pipx)** use minor version symlink for venv Python by @jdx in [#7339](https://github.com/jdx/mise/pull/7339)\n- **(registry)** prefer claude-code latest over stale stable by @jdx in [#7334](https://github.com/jdx/mise/pull/7334)\n- **(upgrade)** only check specified tools when upgrading with tool args by @jdx in [#7331](https://github.com/jdx/mise/pull/7331)\n\n### 📚 Documentation\n\n- Revise alias example for task execution by @azais-corentin in [#7338](https://github.com/jdx/mise/pull/7338)\n\n## [2025.12.9](https://github.com/jdx/mise/compare/v2025.12.8..v2025.12.9) - 2025-12-16\n\n### 🚀 Features\n\n- **(aqua)** add tuist aqua backend by @jdx in [#7323](https://github.com/jdx/mise/pull/7323)\n- **(ls-remote)** add release_url to VersionInfo for --json output by @jdx in [#7322](https://github.com/jdx/mise/pull/7322)\n- **(prepare)** add `mise prepare` command for dependency preparation by @jdx in [#7281](https://github.com/jdx/mise/pull/7281)\n- **(registry)** add aqua backend for zigmod by @jdx in [#7319](https://github.com/jdx/mise/pull/7319)\n\n### 🐛 Bug Fixes\n\n- **(e2e)** fix flaky test_prepare go provider test by @jdx in [0e2ef73](https://github.com/jdx/mise/commit/0e2ef73f9ae91072efd5abbbbe9d82e932472e79)\n- **(go)** restore git ls-remote for version listing by @jdx in [#7324](https://github.com/jdx/mise/pull/7324)\n\n### 📦 Registry\n\n- use github backend for sourcery by @jdx in [#7327](https://github.com/jdx/mise/pull/7327)\n- use github backend for swiftgen by @jdx in [#7326](https://github.com/jdx/mise/pull/7326)\n\n## [2025.12.8](https://github.com/jdx/mise/compare/v2025.12.7..v2025.12.8) - 2025-12-15\n\n### 🚀 Features\n\n- **(conda)** add dependency resolution for conda packages by @jdx in [#7280](https://github.com/jdx/mise/pull/7280)\n- **(go)** add created_at support to ls-remote --json by @jdx in [#7305](https://github.com/jdx/mise/pull/7305)\n- **(hook-env)** add hook_env.cache_ttl and hook_env.chpwd_only settings for NFS optimization by @jdx in [#7312](https://github.com/jdx/mise/pull/7312)\n- **(hooks)** add MISE_TOOL_NAME and MISE_TOOL_VERSION to preinstall/postinstall hooks by @jdx in [#7311](https://github.com/jdx/mise/pull/7311)\n- **(shell_alias)** add shell_alias support for cross-shell aliases by @jdx in [#7316](https://github.com/jdx/mise/pull/7316)\n- **(tool)** add security field to mise tool --json by @jdx in [#7303](https://github.com/jdx/mise/pull/7303)\n- add --before flag for date-based version filtering by @jdx in [#7298](https://github.com/jdx/mise/pull/7298)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** support cosign v3 bundle verification by @jdx in [#7314](https://github.com/jdx/mise/pull/7314)\n- **(config)** use correct config_root in tera context for hooks by @jdx in [#7309](https://github.com/jdx/mise/pull/7309)\n- **(nu)** fix nushell deactivation script on Windows by @fu050409 in [#7213](https://github.com/jdx/mise/pull/7213)\n- **(python)** apply uv_venv_create_args in auto-venv code path by @jdx in [#7310](https://github.com/jdx/mise/pull/7310)\n- **(shell)** escape exe path in activation scripts for paths with spaces by @jdx in [#7315](https://github.com/jdx/mise/pull/7315)\n- **(task)** parallelize exec_env loading to fix parallel task execution by @jdx in [#7313](https://github.com/jdx/mise/pull/7313)\n- track downloads for python and java by @jdx in [#7304](https://github.com/jdx/mise/pull/7304)\n- include full tool ID in download track by @jdx in [#7320](https://github.com/jdx/mise/pull/7320)\n\n### 📚 Documentation\n\n- Switch `postinstall` code to be shell-agnostic by @thejcannon in [#7317](https://github.com/jdx/mise/pull/7317)\n\n### 🧪 Testing\n\n- **(e2e)** disable debug mode by default for windows-e2e by @jdx in [#7318](https://github.com/jdx/mise/pull/7318)\n\n### New Contributors\n\n- @fu050409 made their first contribution in [#7213](https://github.com/jdx/mise/pull/7213)\n\n## [2025.12.7](https://github.com/jdx/mise/compare/v2025.12.6..v2025.12.7) - 2025-12-14\n\n### 🚀 Features\n\n- **(java)** add created_at support to ls-remote --json by @jdx in [#7297](https://github.com/jdx/mise/pull/7297)\n- **(ls-remote)** add created_at timestamps to ls-remote --json for more backends by @jdx in [#7295](https://github.com/jdx/mise/pull/7295)\n- **(ls-remote)** add created_at timestamps to ls-remote --json for core plugins by @jdx in [#7294](https://github.com/jdx/mise/pull/7294)\n- **(registry)** add --json flag to registry command by @jdx in [#7290](https://github.com/jdx/mise/pull/7290)\n- **(ruby)** add created_at timestamps to ls-remote --json by @jdx in [#7296](https://github.com/jdx/mise/pull/7296)\n\n### 🐛 Bug Fixes\n\n- **(spm)** recursively update submodules after checkout by @JFej in [#7292](https://github.com/jdx/mise/pull/7292)\n- prioritize raw task output over task_output setting by @skorfmann in [#7286](https://github.com/jdx/mise/pull/7286)\n\n### New Contributors\n\n- @skorfmann made their first contribution in [#7286](https://github.com/jdx/mise/pull/7286)\n- @JFej made their first contribution in [#7292](https://github.com/jdx/mise/pull/7292)\n\n## [2025.12.6](https://github.com/jdx/mise/compare/v2025.12.5..v2025.12.6) - 2025-12-14\n\n### 🚀 Features\n\n- add anonymous download tracking for tool popularity stats by @jdx in [#7289](https://github.com/jdx/mise/pull/7289)\n\n### 🐛 Bug Fixes\n\n- add --compressed flag to curl for Swift GPG keys by @jdx in [7bc1273](https://github.com/jdx/mise/commit/7bc1273e78c9a1b58e0c987f5f2560f498efd2d4)\n\n### 📚 Documentation\n\n- add Versions link to nav bar by @jdx in [#7283](https://github.com/jdx/mise/pull/7283)\n- add mise-tools link to nav bar by @jdx in [#7285](https://github.com/jdx/mise/pull/7285)\n\n## [2025.12.5](https://github.com/jdx/mise/compare/v2025.12.4..v2025.12.5) - 2025-12-13\n\n### 🚀 Features\n\n- **(ls-remote)** add --json flag with created_at timestamps by @jdx in [#7279](https://github.com/jdx/mise/pull/7279)\n\n### 🐛 Bug Fixes\n\n- **(config)** respect MISE_CONFIG_DIR when set to non-default location by @jdx in [#7271](https://github.com/jdx/mise/pull/7271)\n- **(http)** move http-tarballs from cache to data directory by @jdx in [#7273](https://github.com/jdx/mise/pull/7273)\n- **(pipx)** expand wildcards in install command for backend tools by @jdx in [#7275](https://github.com/jdx/mise/pull/7275)\n- **(tasks)** position-based flag parsing for `mise run` by @jdx in [#7278](https://github.com/jdx/mise/pull/7278)\n- **(tera)** handle empty strings in path filters by @jdx in [#7276](https://github.com/jdx/mise/pull/7276)\n- **(vfox)** make mise_env and mise_path hooks optional by @jdx in [#7274](https://github.com/jdx/mise/pull/7274)\n\n### 📚 Documentation\n\n- **(ruby)** add precompiled binaries documentation by @jdx in [#7269](https://github.com/jdx/mise/pull/7269)\n\n## [2025.12.4](https://github.com/jdx/mise/compare/v2025.12.3..v2025.12.4) - 2025-12-13\n\n### 🚀 Features\n\n- **(copr)** add Fedora 43 support by @jdx in [#7265](https://github.com/jdx/mise/pull/7265)\n- **(ruby)** add precompiled binary support by @jdx in [#7263](https://github.com/jdx/mise/pull/7263)\n\n## [2025.12.3](https://github.com/jdx/mise/compare/v2025.12.2..v2025.12.3) - 2025-12-13\n\n### 🚀 Features\n\n- **(ui)** add color_theme setting for light terminal support by @bishopmatthew in [#7257](https://github.com/jdx/mise/pull/7257)\n\n### 🐛 Bug Fixes\n\n- **(node)** add newlines between GPG keys in fetch script by @jdx in [#7262](https://github.com/jdx/mise/pull/7262)\n- **(run)** truncate task description to first line in run selector by @jdx in [#7256](https://github.com/jdx/mise/pull/7256)\n- unset -f bash functions by @agriffis in [#7072](https://github.com/jdx/mise/pull/7072)\n\n### 📚 Documentation\n\n- fix type of mise_env in templates by @risu729 in [#7261](https://github.com/jdx/mise/pull/7261)\n\n### 🧪 Testing\n\n- add empty secret redaction test by @risu729 in [#7260](https://github.com/jdx/mise/pull/7260)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:copr docker digest to af06edf by @renovate[bot] in [#7245](https://github.com/jdx/mise/pull/7245)\n- update ghcr.io/jdx/mise:alpine docker digest to 3ca5ebd by @renovate[bot] in [#7244](https://github.com/jdx/mise/pull/7244)\n- update ghcr.io/jdx/mise:rpm docker digest to bdc5d0d by @renovate[bot] in [#7247](https://github.com/jdx/mise/pull/7247)\n- update ghcr.io/jdx/mise:deb docker digest to f73d7ef by @renovate[bot] in [#7246](https://github.com/jdx/mise/pull/7246)\n- update mcr.microsoft.com/devcontainers/rust:1 docker digest to 884de39 by @renovate[bot] in [#7249](https://github.com/jdx/mise/pull/7249)\n- update jdx/mise-action digest to 146a281 by @renovate[bot] in [#7248](https://github.com/jdx/mise/pull/7248)\n\n### Chore\n\n- **(registry)** retry only failed tools by @risu729 in [#7251](https://github.com/jdx/mise/pull/7251)\n\n### New Contributors\n\n- @agriffis made their first contribution in [#7072](https://github.com/jdx/mise/pull/7072)\n- @bishopmatthew made their first contribution in [#7257](https://github.com/jdx/mise/pull/7257)\n\n## [2025.12.2](https://github.com/jdx/mise/compare/v2025.12.1..v2025.12.2) - 2025-12-11\n\n### 🐛 Bug Fixes\n\n- **(node)** fetch GPG keys from nodejs/release-keys repo by @jdx in [#7242](https://github.com/jdx/mise/pull/7242)\n- **(release)** run fetch-gpg-keys before build by @jdx in [2608caf](https://github.com/jdx/mise/commit/2608cafec410befc911f53181850fbc720bc33ce)\n- **(tasks)** disable ctrl-c exit behavior during mise run by @jdx in [#7232](https://github.com/jdx/mise/pull/7232)\n\n### 📦 Registry\n\n- added werf by @tony-sol in [#7230](https://github.com/jdx/mise/pull/7230)\n\n## [2025.12.1](https://github.com/jdx/mise/compare/v2025.12.0..v2025.12.1) - 2025-12-08\n\n### 🚀 Features\n\n- **(npm)** support pnpm as a package manager for npm backend by @risu729 in [#7214](https://github.com/jdx/mise/pull/7214)\n- **(tool-stubs)** add --bootstrap flag to mise generate tool-stub by @jdx in [#7203](https://github.com/jdx/mise/pull/7203)\n\n### 🐛 Bug Fixes\n\n- **(alpine)** increase alpine release timeout to 60 minutes by @jdx in [#7188](https://github.com/jdx/mise/pull/7188)\n- **(bun)** use x64-baseline for aarch64 on Windows by @roele in [#7190](https://github.com/jdx/mise/pull/7190)\n- **(tools)** allow using env vars in tools by @antonsergeyev in [#7205](https://github.com/jdx/mise/pull/7205)\n- add cfg(feature = \"self_update\") to statics only used by that feature by @jdx in [#7185](https://github.com/jdx/mise/pull/7185)\n\n### 📚 Documentation\n\n- Update registry.md by @jdx in [ad11ad1](https://github.com/jdx/mise/commit/ad11ad14705b2adac5c874f15fef4cc74652e26f)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to 2909cce by @renovate[bot] in [#7196](https://github.com/jdx/mise/pull/7196)\n- update fedora:43 docker digest to 6cd815d by @renovate[bot] in [#7195](https://github.com/jdx/mise/pull/7195)\n- update ghcr.io/jdx/mise:deb docker digest to 1893530 by @renovate[bot] in [#7198](https://github.com/jdx/mise/pull/7198)\n- update ghcr.io/jdx/mise:copr docker digest to 0447a85 by @renovate[bot] in [#7197](https://github.com/jdx/mise/pull/7197)\n\n### 📦 Registry\n\n- add Supabase CLI to registry.toml by @bodadotsh in [#7206](https://github.com/jdx/mise/pull/7206)\n- add cmake aqua backend by @mangkoran in [#7186](https://github.com/jdx/mise/pull/7186)\n\n### New Contributors\n\n- @antonsergeyev made their first contribution in [#7205](https://github.com/jdx/mise/pull/7205)\n- @bodadotsh made their first contribution in [#7206](https://github.com/jdx/mise/pull/7206)\n\n## [2025.12.0](https://github.com/jdx/mise/compare/v2025.11.11..v2025.12.0) - 2025-12-04\n\n### 🚀 Features\n\n- **(config)** add support for netrc by @RobotSupervisor in [#7164](https://github.com/jdx/mise/pull/7164)\n- **(lock)** add resolve_lock_info to core backends for checksum fetching by @jdx in [#7180](https://github.com/jdx/mise/pull/7180)\n- **(ruby)** Install ruby from a zip file over HTTPS by @KaanYT in [#7167](https://github.com/jdx/mise/pull/7167)\n- **(tasks)** add `usage` args to Tera context in run scripts by @iamkroot in [#7041](https://github.com/jdx/mise/pull/7041)\n\n### 🐛 Bug Fixes\n\n- **(lock)** validate platform qualifiers when reading from lockfile by @jdx in [#7181](https://github.com/jdx/mise/pull/7181)\n- **(task)** retry shebang scripts on ETXTBUSY by @iamkroot in [#7162](https://github.com/jdx/mise/pull/7162)\n- **(ui)** remove duplicate 'mise' prefix in verbose footer output by @jdx in [#7174](https://github.com/jdx/mise/pull/7174)\n\n### 📦️ Dependency Updates\n\n- bump usage-lib to 2.9.0 by @jdx in [#7177](https://github.com/jdx/mise/pull/7177)\n\n### 📦 Registry\n\n- remove duplicated ubi and github backends from gping by @risu729 in [#7144](https://github.com/jdx/mise/pull/7144)\n- disable bashly test (not working in CI) by @jdx in [#7173](https://github.com/jdx/mise/pull/7173)\n- disable cfn-lint test (failing in CI) by @jdx in [#7176](https://github.com/jdx/mise/pull/7176)\n\n### Chore\n\n- add fd to mise.toml by @blampe in [#7178](https://github.com/jdx/mise/pull/7178)\n\n### New Contributors\n\n- @RobotSupervisor made their first contribution in [#7164](https://github.com/jdx/mise/pull/7164)\n\n## [2025.11.11](https://github.com/jdx/mise/compare/v2025.11.10..v2025.11.11) - 2025-11-30\n\n### 🚀 Features\n\n- **(backend)** add filter_bins option to github/gitlab backends by @risu729 in [#7105](https://github.com/jdx/mise/pull/7105)\n- **(ci)** auto-close PRs from non-maintainers by @jdx in [#7108](https://github.com/jdx/mise/pull/7108)\n- **(conda)** add conda backend for installing packages from conda-forge by @jdx in [#7139](https://github.com/jdx/mise/pull/7139)\n- **(github)** add rename_exe option and switch elm, opam, yt-dlp from ubi by @jdx in [#7140](https://github.com/jdx/mise/pull/7140)\n- **(install)** add --locked flag for strict lockfile mode by @jdx in [#7098](https://github.com/jdx/mise/pull/7098)\n- **(lock)** implement cross-platform lockfile generation by @jdx in [#7091](https://github.com/jdx/mise/pull/7091)\n- **(lockfile)** add options field for tool artifact identity by @jdx in [#7092](https://github.com/jdx/mise/pull/7092)\n- **(lockfile)** add env field and local lockfile support by @jdx in [#7099](https://github.com/jdx/mise/pull/7099)\n- **(lockfile)** add URL support for deno, go, and zig backends by @jdx in [#7112](https://github.com/jdx/mise/pull/7112)\n- **(lockfile)** add URL support for vfox backend by @jdx in [#7114](https://github.com/jdx/mise/pull/7114)\n- **(lockfile)** add multi-platform checksums without downloading tarballs by @jdx in [#7113](https://github.com/jdx/mise/pull/7113)\n\n### 🐛 Bug Fixes\n\n- **(backend)** allow platform-specific strip_components by @risu729 in [#7106](https://github.com/jdx/mise/pull/7106)\n- **(backend)** prefer path root for bin path if it contains an executable by @risu729 in [#7151](https://github.com/jdx/mise/pull/7151)\n- **(bash)** avoid deactivate error on (no)unset PROMPT_COMMAND by @scop in [#7096](https://github.com/jdx/mise/pull/7096)\n- **(ci)** use updatedAt instead of createdAt for stale PR detection by @jdx in [#7109](https://github.com/jdx/mise/pull/7109)\n- **(config)** increase fetch_remote_versions_timeout default to 20s by @jdx in [#7157](https://github.com/jdx/mise/pull/7157)\n- **(github)** search subdirectories for executables in discover_bin_paths by @jdx in [#7138](https://github.com/jdx/mise/pull/7138)\n- **(lockfile)** combine api_url with asset_pattern for GitHub release URLs by @jdx in [#7111](https://github.com/jdx/mise/pull/7111)\n\n### 🚜 Refactor\n\n- **(lock)** simplify lockfile to always use array format by @jdx in [#7093](https://github.com/jdx/mise/pull/7093)\n- **(lockfile)** use compact inline table format by @jdx in [#7141](https://github.com/jdx/mise/pull/7141)\n\n### 📚 Documentation\n\n- **(gitlab)** document rename_exe option also for gitlab backend by @risu729 in [#7149](https://github.com/jdx/mise/pull/7149)\n- **(lockfile)** update documentation for recent lockfile changes by @jdx in [#7107](https://github.com/jdx/mise/pull/7107)\n- **(node)** use config_root in _.path for pnpm example by @risu729 in [#7146](https://github.com/jdx/mise/pull/7146)\n- **(registry)** add github/gitlab backends to the preferred backends list by @risu729 in [#7148](https://github.com/jdx/mise/pull/7148)\n- **(registry)** add url mappings for all backends by @risu729 in [#7147](https://github.com/jdx/mise/pull/7147)\n\n### 📦️ Dependency Updates\n\n- update docker/metadata-action digest to c299e40 by @renovate[bot] in [#7101](https://github.com/jdx/mise/pull/7101)\n- update ghcr.io/jdx/mise:alpine docker digest to 693c5f6 by @renovate[bot] in [#7102](https://github.com/jdx/mise/pull/7102)\n- update ghcr.io/jdx/mise:deb docker digest to 9985cab by @renovate[bot] in [#7104](https://github.com/jdx/mise/pull/7104)\n- update ghcr.io/jdx/mise:copr docker digest to 564d8e1 by @renovate[bot] in [#7103](https://github.com/jdx/mise/pull/7103)\n- update rust crate ubi to 0.8.4 by @risu729 in [#7154](https://github.com/jdx/mise/pull/7154)\n\n### 📦 Registry\n\n- add aqua backend as primary for e1s by @jdx in [#7115](https://github.com/jdx/mise/pull/7115)\n- add gem backend for bashly by @jdx in [6af6607](https://github.com/jdx/mise/commit/6af6607393a198feb1078e3ec3bc06146e82a23d)\n- switch 1password from asdf to vfox backend by @jdx in [#7116](https://github.com/jdx/mise/pull/7116)\n- add vfox backend for bfs by @jdx in [#7126](https://github.com/jdx/mise/pull/7126)\n- add github backend for btrace by @jdx in [#7129](https://github.com/jdx/mise/pull/7129)\n- add github backend for cf by @jdx in [#7131](https://github.com/jdx/mise/pull/7131)\n- add vfox backend for bpkg by @jdx in [#7130](https://github.com/jdx/mise/pull/7130)\n- switch apollo-ios from asdf to github backend by @jdx in [#7118](https://github.com/jdx/mise/pull/7118)\n- add vfox backend for chromedriver by @jdx in [#7134](https://github.com/jdx/mise/pull/7134)\n- switch superhtml, vespa-cli, xcsift from ubi to github backend by @jdx in [#7137](https://github.com/jdx/mise/pull/7137)\n- add vfox backend for clickhouse by @jdx in [#7136](https://github.com/jdx/mise/pull/7136)\n- switch chicken to vfox plugin by @jdx in [#7135](https://github.com/jdx/mise/pull/7135)\n- switch chezscheme from asdf to vfox backend by @jdx in [#7132](https://github.com/jdx/mise/pull/7132)\n- add vfox backend for carthage by @jdx in [#7133](https://github.com/jdx/mise/pull/7133)\n- switch azure-functions-core-tools from asdf to vfox backend by @jdx in [#7128](https://github.com/jdx/mise/pull/7128)\n- switch aapt2 to vfox backend by @jdx in [#7117](https://github.com/jdx/mise/pull/7117)\n- switch ant to vfox backend by @jdx in [#7119](https://github.com/jdx/mise/pull/7119)\n- switch asciidoctorj from asdf to vfox backend by @jdx in [#7121](https://github.com/jdx/mise/pull/7121)\n- switch awscli-local to pipx backend by @jdx in [#7120](https://github.com/jdx/mise/pull/7120)\n- add omnictl by @risu729 in [#7145](https://github.com/jdx/mise/pull/7145)\n- remove pnpm asdf plugin from fallback by @risu729 in [#7143](https://github.com/jdx/mise/pull/7143)\n- switch tanzu to github backend by @jdx in [#7124](https://github.com/jdx/mise/pull/7124)\n- switch android-sdk to vfox plugin by @jdx in [#7127](https://github.com/jdx/mise/pull/7127)\n- add vfox backend for ag (The Silver Searcher) by @jdx in [#7122](https://github.com/jdx/mise/pull/7122)\n- add gem backend for bashly by @jdx in [#7125](https://github.com/jdx/mise/pull/7125)\n\n### Chore\n\n- **(registry)** ignore deleted tools in test-tool workflow by @risu729 in [#7081](https://github.com/jdx/mise/pull/7081)\n- **(release)** show registry section last in changelog by @jdx in [#7156](https://github.com/jdx/mise/pull/7156)\n- update mise.lock with checksums by @jdx in [71e9123](https://github.com/jdx/mise/commit/71e9123efac62924b5804e1f56e61400adf22470)\n- disable cancel-in-progress for test workflow on main branch by @risu729 in [#7152](https://github.com/jdx/mise/pull/7152)\n\n## [2025.11.10](https://github.com/jdx/mise/compare/v2025.11.9..v2025.11.10) - 2025-11-27\n\n### 🐛 Bug Fixes\n\n- **(docs)** link gitlab backended tools in registry by @risu729 in [#7078](https://github.com/jdx/mise/pull/7078)\n\n### 🚜 Refactor\n\n- **(hook-env)** derive config_subdirs from config filenames by @risu729 in [#7080](https://github.com/jdx/mise/pull/7080)\n\n### 📦 Registry\n\n- enable symlink_bins for aws-sam by @risu729 in [#7082](https://github.com/jdx/mise/pull/7082)\n- use cargo backend for tokei to support latest version by @risu729 in [#7086](https://github.com/jdx/mise/pull/7086)\n- add SonarSource/sonar-scanner-cli by @kapitoshka438 in [#7087](https://github.com/jdx/mise/pull/7087)\n\n### New Contributors\n\n- @kapitoshka438 made their first contribution in [#7087](https://github.com/jdx/mise/pull/7087)\n\n## [2025.11.9](https://github.com/jdx/mise/compare/v2025.11.8..v2025.11.9) - 2025-11-27\n\n### 🚀 Features\n\n- **(aqua)** add symlink_bins option to filter exposed binaries by @jdx in [#7076](https://github.com/jdx/mise/pull/7076)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** skip whitespace before pipe token in template parser by @jdx in [#7069](https://github.com/jdx/mise/pull/7069)\n- **(docs)** link github backends to github repo URLs by @SKalt in [#7071](https://github.com/jdx/mise/pull/7071)\n\n### 📚 Documentation\n\n- update node examples from 22 to 24 by @jdx in [#7074](https://github.com/jdx/mise/pull/7074)\n\n### ⚡ Performance\n\n- **(hook-env)** add fast-path to skip initialization when nothing changed by @jdx in [#7073](https://github.com/jdx/mise/pull/7073)\n\n### 📦 Registry\n\n- add charmbracelet/crush by @ev-the-dev in [#7075](https://github.com/jdx/mise/pull/7075)\n\n### New Contributors\n\n- @ev-the-dev made their first contribution in [#7075](https://github.com/jdx/mise/pull/7075)\n- @SKalt made their first contribution in [#7071](https://github.com/jdx/mise/pull/7071)\n\n## [2025.11.8](https://github.com/jdx/mise/compare/v2025.11.7..v2025.11.8) - 2025-11-26\n\n### 🚀 Features\n\n- **(plugins)** Install a plugin from a zip file over HTTPS by @KaanYT in [#6992](https://github.com/jdx/mise/pull/6992)\n- **(registry)** add tool options support for http backend by @jdx in [#7061](https://github.com/jdx/mise/pull/7061)\n\n### 🐛 Bug Fixes\n\n- **(core)** trim `core:` prefix in unalias_backend by @kou029w in [#7040](https://github.com/jdx/mise/pull/7040)\n- **(exec)** make `mise x tool@latest` auto-install actual latest version by @jdx in [#7064](https://github.com/jdx/mise/pull/7064)\n- **(go)** use -mod=readonly for go install by @joonas in [#7052](https://github.com/jdx/mise/pull/7052)\n- **(npm)** handle v-prefixed versions correctly by @jdx in [#7062](https://github.com/jdx/mise/pull/7062)\n- **(tasks)** add missing task fields to JSON output by @roele in [#7044](https://github.com/jdx/mise/pull/7044)\n- semver in aqua by @lucasew in [#7018](https://github.com/jdx/mise/pull/7018)\n- use the musl version if installing in Android (Termux) by @lucasew in [#7027](https://github.com/jdx/mise/pull/7027)\n- empty enable_tools crash by @moshen in [#7035](https://github.com/jdx/mise/pull/7035)\n\n### 📚 Documentation\n\n- add MISE and USAGE syntax hl queries to neovim cookbook by @okuuva in [#7047](https://github.com/jdx/mise/pull/7047)\n- use local assets for screenshots by @okuuva in [#7056](https://github.com/jdx/mise/pull/7056)\n- remove GitHub issues link from roadmap by @jdx in [6897286](https://github.com/jdx/mise/commit/689728642b386e197a549ea8b5dd591c3b950b42)\n\n### 📦️ Dependency Updates\n\n- update docker/metadata-action digest to 318604b by @renovate[bot] in [#7033](https://github.com/jdx/mise/pull/7033)\n- update actions/checkout digest to 34e1148 by @renovate[bot] in [#7032](https://github.com/jdx/mise/pull/7032)\n- lock file maintenance by @renovate[bot] in [#7048](https://github.com/jdx/mise/pull/7048)\n\n### 📦 Registry\n\n- add blender by @lucasew in [#7014](https://github.com/jdx/mise/pull/7014)\n- add vespa-cli by @buinauskas in [#7037](https://github.com/jdx/mise/pull/7037)\n- fix vespa-cli order by @buinauskas in [#7038](https://github.com/jdx/mise/pull/7038)\n- add scooter by @TyceHerrman in [#7039](https://github.com/jdx/mise/pull/7039)\n- Prefer github backend for allure by @TobiX in [#7049](https://github.com/jdx/mise/pull/7049)\n\n### Chore\n\n- upgrade actionlint to 1.7.9 and fix lint issues by @jdx in [#7065](https://github.com/jdx/mise/pull/7065)\n\n### New Contributors\n\n- @joonas made their first contribution in [#7052](https://github.com/jdx/mise/pull/7052)\n- @KaanYT made their first contribution in [#6992](https://github.com/jdx/mise/pull/6992)\n- @kou029w made their first contribution in [#7040](https://github.com/jdx/mise/pull/7040)\n- @moshen made their first contribution in [#7035](https://github.com/jdx/mise/pull/7035)\n- @buinauskas made their first contribution in [#7038](https://github.com/jdx/mise/pull/7038)\n- @lucasew made their first contribution in [#7014](https://github.com/jdx/mise/pull/7014)\n\n## [2025.11.7](https://github.com/jdx/mise/compare/v2025.11.6..v2025.11.7) - 2025-11-20\n\n### 🚀 Features\n\n- **(exec)** ensure MISE_ENV is set in spawned shell when specified via -E flag by @ceelian in [#7007](https://github.com/jdx/mise/pull/7007)\n\n### 🐛 Bug Fixes\n\n- **(fig)** resolve __dirname error in ES module by @jdx in [#7021](https://github.com/jdx/mise/pull/7021)\n- **(go)** Don't allow auto mod=vendor mode by @mariduv in [#7006](https://github.com/jdx/mise/pull/7006)\n- **(nushell)** test `use` not `source`, fix pipeline parse error by @jokeyrhyme in [#7013](https://github.com/jdx/mise/pull/7013)\n- **(tasks)** make file paths relative to config location and templateable by @halms in [#7005](https://github.com/jdx/mise/pull/7005)\n\n### 📦 Registry\n\n- added nelm by @tony-sol in [#7020](https://github.com/jdx/mise/pull/7020)\n\n### Chore\n\n- **(deny)** add exclusion for number_prefix by @jdx in [e955ecb](https://github.com/jdx/mise/commit/e955ecbb733d61ef1d0b522a979a7d1998ec8061)\n\n### New Contributors\n\n- @mariduv made their first contribution in [#7006](https://github.com/jdx/mise/pull/7006)\n- @ceelian made their first contribution in [#7007](https://github.com/jdx/mise/pull/7007)\n\n## [2025.11.6](https://github.com/jdx/mise/compare/v2025.11.5..v2025.11.6) - 2025-11-18\n\n### 🐛 Bug Fixes\n\n- **(nushell)** add missing `| parse env | update-env` for deactivation operations by @jokeyrhyme in [#6994](https://github.com/jdx/mise/pull/6994)\n- **(pwsh)** wrap the executable path with double quotes by @leosuncin in [#6993](https://github.com/jdx/mise/pull/6993)\n- in `activate bash` output, wrap mise executable path in single-quotes by @cspotcode in [#7002](https://github.com/jdx/mise/pull/7002)\n- On Windows, preserve/proxy the exit code of tools, to match behavior on Unix by @cspotcode in [#7001](https://github.com/jdx/mise/pull/7001)\n\n### 📚 Documentation\n\n- simplify apt instructions by @scop in [#6986](https://github.com/jdx/mise/pull/6986)\n- update idiomatic version files enablement info by @scop in [#6985](https://github.com/jdx/mise/pull/6985)\n- registry notability explanation by @jdx in [8f9ab15](https://github.com/jdx/mise/commit/8f9ab15e18d8cf0983d08a1f14b04511c999d681)\n\n### 🧪 Testing\n\n- **(aqua)** remove biome test due to version incompatibility by @jdx in [#7000](https://github.com/jdx/mise/pull/7000)\n\n### 📦️ Dependency Updates\n\n- lock file maintenance by @renovate[bot] in [#6997](https://github.com/jdx/mise/pull/6997)\n\n### 📦 Registry\n\n- add tbls by @artemklevtsov in [#6987](https://github.com/jdx/mise/pull/6987)\n- add kubeswitch tool and add test for ruff by @jylenhof in [#6990](https://github.com/jdx/mise/pull/6990)\n\n### New Contributors\n\n- @cspotcode made their first contribution in [#7001](https://github.com/jdx/mise/pull/7001)\n- @jokeyrhyme made their first contribution in [#6994](https://github.com/jdx/mise/pull/6994)\n- @artemklevtsov made their first contribution in [#6987](https://github.com/jdx/mise/pull/6987)\n- @leosuncin made their first contribution in [#6993](https://github.com/jdx/mise/pull/6993)\n\n## [2025.11.5](https://github.com/jdx/mise/compare/v2025.11.4..v2025.11.5) - 2025-11-15\n\n### 🚀 Features\n\n- **(http)** Add 'format' to http backend by @thejcannon in [#6957](https://github.com/jdx/mise/pull/6957)\n\n### 🐛 Bug Fixes\n\n- **(bootstrap)** wrong directory on first run by @vmeurisse in [#6971](https://github.com/jdx/mise/pull/6971)\n- **(tasks)** fix nested colons with `mise task edit` by @jdx in [#6978](https://github.com/jdx/mise/pull/6978)\n- Use compatible env flags by @thejcannon in [#6964](https://github.com/jdx/mise/pull/6964)\n- Flush vfox download buffer by @blampe in [#6969](https://github.com/jdx/mise/pull/6969)\n\n### 📚 Documentation\n\n- `arch()` template is `x64` by @thejcannon in [#6967](https://github.com/jdx/mise/pull/6967)\n- update section headers in getting-started.md by @JunichiroKohari in [#6980](https://github.com/jdx/mise/pull/6980)\n\n### New Contributors\n\n- @JunichiroKohari made their first contribution in [#6980](https://github.com/jdx/mise/pull/6980)\n- @blampe made their first contribution in [#6969](https://github.com/jdx/mise/pull/6969)\n- @thejcannon made their first contribution in [#6964](https://github.com/jdx/mise/pull/6964)\n\n## [2025.11.4](https://github.com/jdx/mise/compare/v2025.11.3..v2025.11.4) - 2025-11-13\n\n### 🚀 Features\n\n- **(gem-backend)** use gem command for backend operations by @andrewthauer in [#6650](https://github.com/jdx/mise/pull/6650)\n- **(tasks)** add `mise task validate` command for task validation by @jdx in [#6958](https://github.com/jdx/mise/pull/6958)\n- Add `--skip-deps` flag to run specified tasks, skipping dependencies by @hverlin in [#6894](https://github.com/jdx/mise/pull/6894)\n\n### 🐛 Bug Fixes\n\n- **(cli)** intercept --help flag to show task help instead of executing task by @jdx in [#6955](https://github.com/jdx/mise/pull/6955)\n- **(cli)** handle `mise help` without requiring tasks by @jdx in [#6961](https://github.com/jdx/mise/pull/6961)\n- **(pwsh)** remove __MISE_DIFF env var instead of __MISE_WATCH on deactivate by @IMXEren in [#6886](https://github.com/jdx/mise/pull/6886)\n- remove temporary files after install by @vmeurisse in [#6948](https://github.com/jdx/mise/pull/6948)\n\n### 📚 Documentation\n\n- **(snapcraft)** update `summary` & `description` shown in snapcraft.io by @phanect in [#6926](https://github.com/jdx/mise/pull/6926)\n- Change package example in go.md by @nachtjasmin in [#6862](https://github.com/jdx/mise/pull/6862)\n- paranoid mode does not untrust global config by @iloveitaly in [#6952](https://github.com/jdx/mise/pull/6952)\n\n### 📦️ Dependency Updates\n\n- lock file maintenance by @renovate[bot] in [#6932](https://github.com/jdx/mise/pull/6932)\n\n### 📦 Registry\n\n- add xcsift by @alexey1312 in [#6923](https://github.com/jdx/mise/pull/6923)\n- add tools: magika & xxh by @IceCodeNew in [#6909](https://github.com/jdx/mise/pull/6909)\n- add aliases to aqua-backend tools by @IceCodeNew in [#6910](https://github.com/jdx/mise/pull/6910)\n\n### Chore\n\n- bump cargo deps by @jdx in [#6960](https://github.com/jdx/mise/pull/6960)\n\n### New Contributors\n\n- @iloveitaly made their first contribution in [#6952](https://github.com/jdx/mise/pull/6952)\n- @nachtjasmin made their first contribution in [#6862](https://github.com/jdx/mise/pull/6862)\n- @IceCodeNew made their first contribution in [#6910](https://github.com/jdx/mise/pull/6910)\n- @alexey1312 made their first contribution in [#6923](https://github.com/jdx/mise/pull/6923)\n\n## [2025.11.3](https://github.com/jdx/mise/compare/v2025.11.2..v2025.11.3) - 2025-11-07\n\n### 🚀 Features\n\n- **(aqua)** support `Asset` template for cosign and slsa verification by @risu729 in [#6875](https://github.com/jdx/mise/pull/6875)\n- improve task info support with experimental_monorepo_root by @hverlin in [#6881](https://github.com/jdx/mise/pull/6881)\n\n### 🐛 Bug Fixes\n\n- **(clippy)** resolve comparison and derivable impl warnings by @jdx in [#6924](https://github.com/jdx/mise/pull/6924)\n- **(config)** add `mise/config.local.toml` to config paths by @risu729 in [#6882](https://github.com/jdx/mise/pull/6882)\n- **(java)** unable to install JDKs of release type EA by @roele in [#6907](https://github.com/jdx/mise/pull/6907)\n- interactive task selection when monorepo tasks are enabled by @halms in [#6891](https://github.com/jdx/mise/pull/6891)\n\n### 📚 Documentation\n\n- **(security)** use long-form GPG key fingerprint in installation docs by @jdx in [#6885](https://github.com/jdx/mise/pull/6885)\n\n### 📦 Registry\n\n- rename yt-dlp bin by @risu729 in [#6883](https://github.com/jdx/mise/pull/6883)\n- use aqua backend for slsa-verifier by @risu729 in [#6872](https://github.com/jdx/mise/pull/6872)\n- added devcontainer-cli by @moisesmorillo in [#6888](https://github.com/jdx/mise/pull/6888)\n- add amazon-ecs-cli by @ducvuongpham in [#6898](https://github.com/jdx/mise/pull/6898)\n- add helm-ls by @ldrouard in [#6899](https://github.com/jdx/mise/pull/6899)\n- add ubi backend and test for oxipng, change aqua backend by @ldrouard in [#6900](https://github.com/jdx/mise/pull/6900)\n\n### Chore\n\n- update Java LTS to 25 by @sargunv in [#6897](https://github.com/jdx/mise/pull/6897)\n\n### New Contributors\n\n- @halms made their first contribution in [#6891](https://github.com/jdx/mise/pull/6891)\n- @sargunv made their first contribution in [#6897](https://github.com/jdx/mise/pull/6897)\n- @ducvuongpham made their first contribution in [#6898](https://github.com/jdx/mise/pull/6898)\n\n## [2025.11.2](https://github.com/jdx/mise/compare/v2025.11.1..v2025.11.2) - 2025-11-03\n\n### 🚀 Features\n\n- **(cli)** switch manpage generation from clap_mangen to usage by @jdx in [#6868](https://github.com/jdx/mise/pull/6868)\n- **(task)** add selective stream suppression for silent configuration by @jdx in [#6851](https://github.com/jdx/mise/pull/6851)\n\n### 🐛 Bug Fixes\n\n- **(backend)** support platform-specific bin and bin_path configuration by @dragoscirjan in [#6853](https://github.com/jdx/mise/pull/6853)\n- **(generate)** update git pre-commit script to use null separator by @azais-corentin in [#6874](https://github.com/jdx/mise/pull/6874)\n- **(stubs)** lookup for aqua tools stubs fails because of tool options by @roele in [#6867](https://github.com/jdx/mise/pull/6867)\n- **(task)** resolve aliases correctly for monorepo tasks by @jdx in [#6857](https://github.com/jdx/mise/pull/6857)\n- **(task)** prevent MISE_TASK_OUTPUT from propagating to nested tasks by @jdx in [#6860](https://github.com/jdx/mise/pull/6860)\n- **(tasks)** simplify task command display to show only first line by @jdx in [#6863](https://github.com/jdx/mise/pull/6863)\n- **(tasks)** implement smart flag routing for task arguments by @jdx in [#6861](https://github.com/jdx/mise/pull/6861)\n- **(xonsh)** prevent KeyError when activating in nested shells by @jdx in [#6856](https://github.com/jdx/mise/pull/6856)\n- Don't set empty env var if decryption fails with age.strict=false by @iamkroot in [#6847](https://github.com/jdx/mise/pull/6847)\n\n### 🚜 Refactor\n\n- **(task)** split run.rs into modular task execution pipeline by @jdx in [#6852](https://github.com/jdx/mise/pull/6852)\n\n### 📚 Documentation\n\n- **(cli)** integrate clap-sort to validate subcommand ordering by @jdx in [#6865](https://github.com/jdx/mise/pull/6865)\n\n### 📦️ Dependency Updates\n\n- lock file maintenance by @renovate[bot] in [#6873](https://github.com/jdx/mise/pull/6873)\n\n### 📦 Registry\n\n- rename mise-haskell -> asdf-haskell by @jdx in [#6859](https://github.com/jdx/mise/pull/6859)\n\n### New Contributors\n\n- @azais-corentin made their first contribution in [#6874](https://github.com/jdx/mise/pull/6874)\n- @dragoscirjan made their first contribution in [#6853](https://github.com/jdx/mise/pull/6853)\n\n## [2025.11.1](https://github.com/jdx/mise/compare/v2025.11.0..v2025.11.1) - 2025-11-01\n\n### 🚀 Features\n\n- **(age)** add strict mode for non-strict decryption mode by @iamkroot in [#6838](https://github.com/jdx/mise/pull/6838)\n- **(vfox)** add support for specifying attestation metadata in the preinstall return value by @malept in [#6839](https://github.com/jdx/mise/pull/6839)\n\n### 🐛 Bug Fixes\n\n- **(activate)** prevent hash table errors during deactivation by @jdx in [#6846](https://github.com/jdx/mise/pull/6846)\n- **(install)** error on non-existent tools in `mise install` by @jdx in [#6844](https://github.com/jdx/mise/pull/6844)\n\n### 📦 Registry\n\n- Disable libsql-server on Windows by @jayvdb in [#6837](https://github.com/jdx/mise/pull/6837)\n- add infisical by @jdx in [#6845](https://github.com/jdx/mise/pull/6845)\n\n## [2025.11.0](https://github.com/jdx/mise/compare/v2025.10.21..v2025.11.0) - 2025-11-01\n\n### 🐛 Bug Fixes\n\n- **(activate)** reset PATH when activate is called multiple times by @jdx in [#6829](https://github.com/jdx/mise/pull/6829)\n- **(env)** preserve user-configured PATH entries from env._.path by @jdx in [#6835](https://github.com/jdx/mise/pull/6835)\n- store tool options for all backends in metadata by @roele in [#6807](https://github.com/jdx/mise/pull/6807)\n\n### 📚 Documentation\n\n- fix usage spec syntax from 'option' to 'flag' by @jdx in [#6834](https://github.com/jdx/mise/pull/6834)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to 7351bbe by @renovate[bot] in [#6826](https://github.com/jdx/mise/pull/6826)\n- update ghcr.io/jdx/mise:deb docker digest to 3a847f2 by @renovate[bot] in [#6828](https://github.com/jdx/mise/pull/6828)\n- update ghcr.io/jdx/mise:copr docker digest to 546dffb by @renovate[bot] in [#6827](https://github.com/jdx/mise/pull/6827)\n- pin jdx/mise-action action to e3d7b8d by @renovate[bot] in [#6825](https://github.com/jdx/mise/pull/6825)\n\n## [2025.10.21](https://github.com/jdx/mise/compare/v2025.10.20..v2025.10.21) - 2025-10-30\n\n### 🐛 Bug Fixes\n\n- **(cli)** show friendly error when --cd path does not exist by @jdx in [#6818](https://github.com/jdx/mise/pull/6818)\n- **(env)** prevent PATH corruption when paths are interleaved with original PATH by @jdx in [#6821](https://github.com/jdx/mise/pull/6821)\n- **(node)** update lts version by @risu729 in [#6816](https://github.com/jdx/mise/pull/6816)\n- **(schema,settings)** update type and descriptions for shell argument settings by @astrochemx in [#6805](https://github.com/jdx/mise/pull/6805)\n\n### Chore\n\n- update kerl to 4.4.0 by @rbino in [#6809](https://github.com/jdx/mise/pull/6809)\n\n### New Contributors\n\n- @astrochemx made their first contribution in [#6805](https://github.com/jdx/mise/pull/6805)\n- @rbino made their first contribution in [#6809](https://github.com/jdx/mise/pull/6809)\n\n## [2025.10.20](https://github.com/jdx/mise/compare/v2025.10.19..v2025.10.20) - 2025-10-29\n\n### 🚀 Features\n\n- Add MSVC asset matching on Windows by @trolleyman in [#6798](https://github.com/jdx/mise/pull/6798)\n\n### 🐛 Bug Fixes\n\n- **(cache)** exclude http backend tarballs from autoprune by @jdx in [#6806](https://github.com/jdx/mise/pull/6806)\n- **(ci)** prevent release job from running when dependencies fail by @jdx in [#6804](https://github.com/jdx/mise/pull/6804)\n- **(fish)** remove --move flag from fish_add_path to prevent PATH corruption by @jdx in [#6800](https://github.com/jdx/mise/pull/6800)\n- **(tasks)** support local .config/mise/conf.d/*.toml tasks by @syhol in [#6792](https://github.com/jdx/mise/pull/6792)\n\n### 📚 Documentation\n\n- change 'claude-code' to 'claude' in examples by @bradleybuda in [#6801](https://github.com/jdx/mise/pull/6801)\n\n### 📦 Registry\n\n- add cpz and rmz by @sassdavid in [#6793](https://github.com/jdx/mise/pull/6793)\n\n### New Contributors\n\n- @trolleyman made their first contribution in [#6798](https://github.com/jdx/mise/pull/6798)\n- @bradleybuda made their first contribution in [#6801](https://github.com/jdx/mise/pull/6801)\n\n## [2025.10.19](https://github.com/jdx/mise/compare/v2025.10.18..v2025.10.19) - 2025-10-28\n\n### 🚀 Features\n\n- **(zig)** Download zig tarballs from vetted community mirrors when available. by @Maarrk in [#6670](https://github.com/jdx/mise/pull/6670)\n\n### 🐛 Bug Fixes\n\n- **(config)** respect auto_install=false for all installation contexts by @jdx in [#6788](https://github.com/jdx/mise/pull/6788)\n- **(plugins)** incorrect tool versions installed for custom plugins by @roele in [#6765](https://github.com/jdx/mise/pull/6765)\n- **(reqwest)** enable socks for self-update by @tony-sol in [#6775](https://github.com/jdx/mise/pull/6775)\n\n### 📚 Documentation\n\n- **(task)** Fix task flag definitions and examples by @syhol in [#6790](https://github.com/jdx/mise/pull/6790)\n- **(task-arguments)** adds `# [USAGE]` syntax by @risu729 in [#6768](https://github.com/jdx/mise/pull/6768)\n- enhance task documentation with syntax highlighting and corrections by @jdx in [#6777](https://github.com/jdx/mise/pull/6777)\n- use triple single quotes for multiline run commands by @jdx in [#6791](https://github.com/jdx/mise/pull/6791)\n\n### 🧪 Testing\n\n- **(perf)** add warmup calls for benchmarks to fix incorrect numbers by @jdx in [#6789](https://github.com/jdx/mise/pull/6789)\n\n### 📦️ Dependency Updates\n\n- lock file maintenance by @renovate[bot] in [#6780](https://github.com/jdx/mise/pull/6780)\n\n### 📦 Registry\n\n- update bat-extras backends by @TyceHerrman in [#6784](https://github.com/jdx/mise/pull/6784)\n\n## [2025.10.18](https://github.com/jdx/mise/compare/v2025.10.17..v2025.10.18) - 2025-10-25\n\n### 🚀 Features\n\n- **(task)** make leading colon optional for monorepo task references by @jdx in [#6763](https://github.com/jdx/mise/pull/6763)\n\n### 🐛 Bug Fixes\n\n- **(task)** resolve monorepo task dependencies with colons in task names by @jdx in [#6761](https://github.com/jdx/mise/pull/6761)\n- Add clang and libs to nix nativeBuildInputs by @laozc in [#6760](https://github.com/jdx/mise/pull/6760)\n\n### 📚 Documentation\n\n- **(task)** deprecate Tera template functions for task arguments by @jdx in [#6764](https://github.com/jdx/mise/pull/6764)\n\n## [2025.10.17](https://github.com/jdx/mise/compare/v2025.10.16..v2025.10.17) - 2025-10-24\n\n### 🚀 Features\n\n- **(plugins)** Implement missing `file.exists()` Lua function by @ofalvai in [#6754](https://github.com/jdx/mise/pull/6754)\n- **(tasks)** Make tera templates available in usage by @iamkroot in [#6747](https://github.com/jdx/mise/pull/6747)\n- use custom api_url for asset downloading in GHES setups by @talbx in [#6730](https://github.com/jdx/mise/pull/6730)\n\n### 🐛 Bug Fixes\n\n- **(env)** prioritize _.path after external PATH modifications by @jdx in [#6755](https://github.com/jdx/mise/pull/6755)\n- incorrect task arguments with spaces on Windows by @nickbabcock in [#6744](https://github.com/jdx/mise/pull/6744)\n\n### 📚 Documentation\n\n- Add example of configuring tools in a file tasks by @richardthe3rd in [#6719](https://github.com/jdx/mise/pull/6719)\n- Add NixOS tip about source compilation to install docs by @richardgill in [#6757](https://github.com/jdx/mise/pull/6757)\n\n### ◀️ Revert\n\n- fix(shell): prevent infinite loop in zsh command-not-found handler by @jdx in [#6758](https://github.com/jdx/mise/pull/6758)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:copr docker digest to 7f6aee5 by @renovate[bot] in [#6750](https://github.com/jdx/mise/pull/6750)\n- update ghcr.io/jdx/mise:alpine docker digest to f749e46 by @renovate[bot] in [#6749](https://github.com/jdx/mise/pull/6749)\n- update ghcr.io/jdx/mise:rpm docker digest to 308b042 by @renovate[bot] in [#6752](https://github.com/jdx/mise/pull/6752)\n- update ghcr.io/jdx/mise:deb docker digest to e28b4fd by @renovate[bot] in [#6751](https://github.com/jdx/mise/pull/6751)\n\n### 📦 Registry\n\n- add superhtml by @Maarrk in [#6742](https://github.com/jdx/mise/pull/6742)\n- add opengrep by @vmeurisse in [#6745](https://github.com/jdx/mise/pull/6745)\n\n### New Contributors\n\n- @richardgill made their first contribution in [#6757](https://github.com/jdx/mise/pull/6757)\n- @nickbabcock made their first contribution in [#6744](https://github.com/jdx/mise/pull/6744)\n- @vmeurisse made their first contribution in [#6745](https://github.com/jdx/mise/pull/6745)\n- @talbx made their first contribution in [#6730](https://github.com/jdx/mise/pull/6730)\n- @Maarrk made their first contribution in [#6742](https://github.com/jdx/mise/pull/6742)\n\n## [2025.10.16](https://github.com/jdx/mise/compare/v2025.10.15..v2025.10.16) - 2025-10-23\n\n### 🚀 Features\n\n- **(tasks)** modify usage spec parsing to return dummy strings by @iamkroot in [#6723](https://github.com/jdx/mise/pull/6723)\n- include resolved sources in task templating context by @the-wondersmith in [#6180](https://github.com/jdx/mise/pull/6180)\n- Add Tera function `absolute` by @iamkroot in [#6729](https://github.com/jdx/mise/pull/6729)\n\n### 🐛 Bug Fixes\n\n- **(cli)** respect os filter during upgrade by @iamkroot in [#6724](https://github.com/jdx/mise/pull/6724)\n\n### 📚 Documentation\n\n- fix RUNTIME.osType values in example snippet by @ofalvai in [#6732](https://github.com/jdx/mise/pull/6732)\n- migrate issue links to GitHub discussions by @jdx in [#6740](https://github.com/jdx/mise/pull/6740)\n- document Lua version by @ofalvai in [#6741](https://github.com/jdx/mise/pull/6741)\n\n### New Contributors\n\n- @ofalvai made their first contribution in [#6741](https://github.com/jdx/mise/pull/6741)\n- @iamkroot made their first contribution in [#6729](https://github.com/jdx/mise/pull/6729)\n- @the-wondersmith made their first contribution in [#6180](https://github.com/jdx/mise/pull/6180)\n\n## [2025.10.15](https://github.com/jdx/mise/compare/v2025.10.14..v2025.10.15) - 2025-10-22\n\n### 🚀 Features\n\n- **(aqua)** use GitHub API digests for release asset checksums by @jdx in [#6720](https://github.com/jdx/mise/pull/6720)\n- **(github)** use GitHub API digests for release asset checksums by @jdx in [#6721](https://github.com/jdx/mise/pull/6721)\n- **(plugins)** automatically install backend plugins by @roele in [#6696](https://github.com/jdx/mise/pull/6696)\n- **(tasks)** add choices to flag() and enable naked runs with task flags by @jdx in [#6707](https://github.com/jdx/mise/pull/6707)\n\n### 🐛 Bug Fixes\n\n- **(config)** show trust error instead of silently skipping untrusted configs by @jdx in [#6715](https://github.com/jdx/mise/pull/6715)\n- **(env)** handle non-ASCII environment variables gracefully by @arnodirlam in [#6708](https://github.com/jdx/mise/pull/6708)\n- **(nix)** add cmakeMinimal to nativeBuildInputs by @okuuva in [#6691](https://github.com/jdx/mise/pull/6691)\n- **(tasks)** load project env vars for global tasks with dir=\"{{cwd}}\" by @jdx in [#6717](https://github.com/jdx/mise/pull/6717)\n\n### 📦️ Dependency Updates\n\n- update gh to latest (2.82.1) by @jdx in [#6718](https://github.com/jdx/mise/pull/6718)\n\n### New Contributors\n\n- @arnodirlam made their first contribution in [#6708](https://github.com/jdx/mise/pull/6708)\n\n## [2025.10.14](https://github.com/jdx/mise/compare/v2025.10.13..v2025.10.14) - 2025-10-21\n\n### 🚀 Features\n\n- **(tasks)** add env var support for args/flags in usage specs by @jdx in [#6704](https://github.com/jdx/mise/pull/6704)\n\n### 🐛 Bug Fixes\n\n- **(release)** prevent S3 rate limiting errors during CDN upload by @jdx in [#6705](https://github.com/jdx/mise/pull/6705)\n\n### 📚 Documentation\n\n- add comprehensive documentation for environment plugins by @jdx in [#6702](https://github.com/jdx/mise/pull/6702)\n\n### 📦️ Dependency Updates\n\n- bump mlua from 0.11.0-beta.3 to 0.11 by @jdx in [#6701](https://github.com/jdx/mise/pull/6701)\n\n## [2025.10.13](https://github.com/jdx/mise/compare/v2025.10.12..v2025.10.13) - 2025-10-21\n\n### 🐛 Bug Fixes\n\n- **(revert)** fix(deps): update rust crate ubi to 0.8.2 by @nekrich in [#6700](https://github.com/jdx/mise/pull/6700)\n\n### 📚 Documentation\n\n- Add fnox as recommended secret management option by @jdx in [#6698](https://github.com/jdx/mise/pull/6698)\n\n### New Contributors\n\n- @nekrich made their first contribution in [#6700](https://github.com/jdx/mise/pull/6700)\n\n## [2025.10.12](https://github.com/jdx/mise/compare/v2025.10.11..v2025.10.12) - 2025-10-20\n\n### 🐛 Bug Fixes\n\n- **(rust)** preserve original PATH entries when managing tool paths by @jdx in [#6689](https://github.com/jdx/mise/pull/6689)\n\n### 📦️ Dependency Updates\n\n- update rust crate ubi to 0.8.2 by @risu729 in [#6693](https://github.com/jdx/mise/pull/6693)\n\n## [2025.10.11](https://github.com/jdx/mise/compare/v2025.10.10..v2025.10.11) - 2025-10-18\n\n### 🚀 Features\n\n- remove experimental labels from stable features by @jdx in [#6684](https://github.com/jdx/mise/pull/6684)\n\n### 🐛 Bug Fixes\n\n- **(tasks)** resolve :task patterns in run blocks for monorepo tasks by @LER0ever in [#6682](https://github.com/jdx/mise/pull/6682)\n\n### 📚 Documentation\n\n- Fix typo in comparison-to-asdf.md by @TobiX in [#6677](https://github.com/jdx/mise/pull/6677)\n\n### 📦️ Dependency Updates\n\n- update docker/dockerfile:1 docker digest to b6afd42 by @renovate[bot] in [#6675](https://github.com/jdx/mise/pull/6675)\n- update fedora:43 docker digest to 2ad3073 by @renovate[bot] in [#6676](https://github.com/jdx/mise/pull/6676)\n\n### New Contributors\n\n- @LER0ever made their first contribution in [#6682](https://github.com/jdx/mise/pull/6682)\n\n## [2025.10.10](https://github.com/jdx/mise/compare/v2025.10.9..v2025.10.10) - 2025-10-16\n\n### 🐛 Bug Fixes\n\n- **(backend)** sync parent directory after removing incomplete marker by @EronWright in [#6668](https://github.com/jdx/mise/pull/6668)\n- **(tasks)** improve error message for untrusted config files by @jdx in [#6672](https://github.com/jdx/mise/pull/6672)\n- fix(deps) Revert \"fix(deps): update rust crate ubi to 0.8 \" by @swgillespie in [#6652](https://github.com/jdx/mise/pull/6652)\n\n### New Contributors\n\n- @swgillespie made their first contribution in [#6652](https://github.com/jdx/mise/pull/6652)\n- @EronWright made their first contribution in [#6668](https://github.com/jdx/mise/pull/6668)\n\n## [2025.10.9](https://github.com/jdx/mise/compare/v2025.10.8..v2025.10.9) - 2025-10-15\n\n### 🐛 Bug Fixes\n\n- **(docs)** add missing config file path by @haellsigh in [#6658](https://github.com/jdx/mise/pull/6658)\n- **(task)** resolve monorepo dependency chains with local task references by @jdx in [#6665](https://github.com/jdx/mise/pull/6665)\n- **(ui)** add terminal detection for OSC 9;4 progress sequences by @jdx in [#6657](https://github.com/jdx/mise/pull/6657)\n\n### 📚 Documentation\n\n- fix aqua package info in CHANGELOG.md by @jdx in [#6664](https://github.com/jdx/mise/pull/6664)\n\n### New Contributors\n\n- @haellsigh made their first contribution in [#6658](https://github.com/jdx/mise/pull/6658)\n\n## [2025.10.8](https://github.com/jdx/mise/compare/v2025.10.7..v2025.10.8) - 2025-10-13\n\n### 🚀 Features\n\n- **(plugins)** more archiver extensions by @blaubaer in [#6644](https://github.com/jdx/mise/pull/6644)\n\n### 🐛 Bug Fixes\n\n- **(cli)** make `mise //foo` equivalent to `mise run //foo` by @neongreen in [#6641](https://github.com/jdx/mise/pull/6641)\n- **(config)** load MISE_ENV configs for monorepo tasks by @jdx in [#6624](https://github.com/jdx/mise/pull/6624)\n- improve ... pattern matching for monorepo tasks by @neongreen in [#6635](https://github.com/jdx/mise/pull/6635)\n\n### 🛡️ Security\n\n- **(security)** use HTTPS instead of HTTP for version hosts by @jdx in [#6638](https://github.com/jdx/mise/pull/6638)\n\n### 📦️ Dependency Updates\n\n- update rust crate ubi to 0.8 by @risu729 in [#6637](https://github.com/jdx/mise/pull/6637)\n\n### 📦 Registry\n\n- add codex (`npm:@openai/codex`) by @risu729 in [#6634](https://github.com/jdx/mise/pull/6634)\n- add tests (1password-certstrap) by @risu729 in [#6592](https://github.com/jdx/mise/pull/6592)\n\n### New Contributors\n\n- @neongreen made their first contribution in [#6641](https://github.com/jdx/mise/pull/6641)\n\n## [2025.10.7](https://github.com/jdx/mise/compare/v2025.10.6..v2025.10.7) - 2025-10-10\n\n### 🚀 Features\n\n- **(config)** Add a ceiling to how mise searchs for config & tasks by @richardthe3rd in [#6041](https://github.com/jdx/mise/pull/6041)\n- **(release)** include aqua-registry updates in changelog and release notes by @jdx in [#6623](https://github.com/jdx/mise/pull/6623)\n\n### 🐛 Bug Fixes\n\n- **(task)** use config_root instead of project_root for task base path by @risu729 in [#6609](https://github.com/jdx/mise/pull/6609)\n- **(task)** resolve project tasks in run blocks using TaskLoadContext by @jdx in [#6614](https://github.com/jdx/mise/pull/6614)\n- **(task)** dont truncate task message when CI is set by @roele in [#6620](https://github.com/jdx/mise/pull/6620)\n- **(tasks)** restore MISE_ENV environment inheritance for tasks by @glasser in [#6621](https://github.com/jdx/mise/pull/6621)\n- **(ui)** prevent OSC 9;4 progress sequences from being written to non-terminals by @jdx in [#6615](https://github.com/jdx/mise/pull/6615)\n\n### 📦 Registry\n\n- add lazyssh by @TyceHerrman in [#6610](https://github.com/jdx/mise/pull/6610)\n\n### Chore\n\n- remove cosign/slsa-verifier from mise.toml by @jdx in [#6616](https://github.com/jdx/mise/pull/6616)\n\n### New Contributors\n\n- @richardthe3rd made their first contribution in [#6041](https://github.com/jdx/mise/pull/6041)\n\n## [2025.10.6](https://github.com/jdx/mise/compare/v2025.10.5..v2025.10.6) - 2025-10-08\n\n### 🚀 Features\n\n- add OSC 9;4 terminal progress indicators by @jdx in [#6584](https://github.com/jdx/mise/pull/6584)\n- make progress bar a footer by @jdx in [#6590](https://github.com/jdx/mise/pull/6590)\n\n### 🐛 Bug Fixes\n\n- **(task)** preserve ubi tool options during auto-install by @jdx in [#6600](https://github.com/jdx/mise/pull/6600)\n- unify project_root and config_root resolution by @risu729 in [#6588](https://github.com/jdx/mise/pull/6588)\n\n### 🚜 Refactor\n\n- **(exec)** remove redundant tty check for auto-install by @jdx in [#6589](https://github.com/jdx/mise/pull/6589)\n- remove duplicated task loads by @risu729 in [#6594](https://github.com/jdx/mise/pull/6594)\n\n### 📦 Registry\n\n- add vfox-mongod by @blaubaer in [#6586](https://github.com/jdx/mise/pull/6586)\n\n### New Contributors\n\n- @blaubaer made their first contribution in [#6586](https://github.com/jdx/mise/pull/6586)\n\n## [2025.10.5](https://github.com/jdx/mise/compare/v2025.10.4..v2025.10.5) - 2025-10-07\n\n### 🐛 Bug Fixes\n\n- **(docs)** improve favicon support for Safari by @jdx in [#6567](https://github.com/jdx/mise/pull/6567)\n- **(github)** download assets via API to respect GITHUB_TOKEN by @roele in [#6496](https://github.com/jdx/mise/pull/6496)\n- **(task)** load toml tasks in `task_config.includes` in system/global config and monorepo subdirs by @risu729 in [#6545](https://github.com/jdx/mise/pull/6545)\n- **(task)** handle dots in monorepo directory names correctly by @jdx in [#6571](https://github.com/jdx/mise/pull/6571)\n\n### 📚 Documentation\n\n- **(readme)** add GitHub Issues & Discussions section by @rsyring in [#6573](https://github.com/jdx/mise/pull/6573)\n- **(tasks)** create dedicated monorepo tasks documentation by @jdx in [#6561](https://github.com/jdx/mise/pull/6561)\n- **(tasks)** enhance monorepo documentation with tool comparisons by @jdx in [#6563](https://github.com/jdx/mise/pull/6563)\n\n### 📦 Registry\n\n- add jules by @alefteris in [#6568](https://github.com/jdx/mise/pull/6568)\n\n## [2025.10.4](https://github.com/jdx/mise/compare/v2025.10.3..v2025.10.4) - 2025-10-06\n\n### 🐛 Bug Fixes\n\n- **(installing-mise.md)** broken link by @equirosa in [#6555](https://github.com/jdx/mise/pull/6555)\n- **(task)** remote git tasks now properly inherit tools from parent configs by @jdx in [#6558](https://github.com/jdx/mise/pull/6558)\n- **(tasks)** restore tool loading from idiomatic version files by @jdx in [#6559](https://github.com/jdx/mise/pull/6559)\n\n### 🚜 Refactor\n\n- **(task)** remove duplicated codes by @risu729 in [#6553](https://github.com/jdx/mise/pull/6553)\n\n### New Contributors\n\n- @equirosa made their first contribution in [#6555](https://github.com/jdx/mise/pull/6555)\n\n## [2025.10.3](https://github.com/jdx/mise/compare/v2025.10.2..v2025.10.3) - 2025-10-06\n\n### 🚀 Features\n\n- **(tasks)** add experimental monorepo task support with target paths by @jdx in [#6535](https://github.com/jdx/mise/pull/6535)\n- **(tasks)** respect local config_roots for monorepo tasks by @jdx in [#6552](https://github.com/jdx/mise/pull/6552)\n- support latest suffix for Java, Python and Ruby flavoured versions by @roele in [#6533](https://github.com/jdx/mise/pull/6533)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** decode filename extracted from url by @risu729 in [#6536](https://github.com/jdx/mise/pull/6536)\n- **(snapcraft)** use classic confinement by @phanect in [#6542](https://github.com/jdx/mise/pull/6542)\n- **(task)** fix task pattern matching and add :task syntax for monorepos by @risu729 in [#6549](https://github.com/jdx/mise/pull/6549)\n- **(tasks)** validate monorepo setup before running monorepo tasks by @jdx in [#6551](https://github.com/jdx/mise/pull/6551)\n- Add bash option in example by @Its-Just-Nans in [#6541](https://github.com/jdx/mise/pull/6541)\n- suppress ignore crate logs by @risu729 in [#6547](https://github.com/jdx/mise/pull/6547)\n\n### 📚 Documentation\n\n- Update Python virtual environment documentation by @Konfekt in [#6538](https://github.com/jdx/mise/pull/6538)\n\n### 📦 Registry\n\n- added cloudflare wrangler by @moisesmorillo in [#6534](https://github.com/jdx/mise/pull/6534)\n\n### Chore\n\n- **(hk)** bump to v1.18.1 by @jdx in [#6546](https://github.com/jdx/mise/pull/6546)\n\n### Hk\n\n- bump to 1.18.1 by @jdx in [0ab65cd](https://github.com/jdx/mise/commit/0ab65cd9c6827fd4738e5184be6d743f94be34b2)\n\n### New Contributors\n\n- @Konfekt made their first contribution in [#6538](https://github.com/jdx/mise/pull/6538)\n- @moisesmorillo made their first contribution in [#6534](https://github.com/jdx/mise/pull/6534)\n\n## [2025.10.2](https://github.com/jdx/mise/compare/v2025.10.1..v2025.10.2) - 2025-10-03\n\n### 🐛 Bug Fixes\n\n- **(shell)** prevent infinite loop in zsh command-not-found handler by @yordis in [#6516](https://github.com/jdx/mise/pull/6516)\n- **(snapcraft)** add missing home plug for the home directory access permission by @phanect in [#6525](https://github.com/jdx/mise/pull/6525)\n- **(vfox)** implement headers support on http mod by @BasixKOR in [#6521](https://github.com/jdx/mise/pull/6521)\n- set MIX_HOME and MIX_ARCHIVES when using the elixir plugin by @numso in [#6504](https://github.com/jdx/mise/pull/6504)\n\n### 📦️ Dependency Updates\n\n- update docker/login-action digest to 5e57cd1 by @renovate[bot] in [#6522](https://github.com/jdx/mise/pull/6522)\n- update fedora:43 docker digest to 2c0d72b by @renovate[bot] in [#6523](https://github.com/jdx/mise/pull/6523)\n\n### Security\n\n- verify macOS binary signature during self-update by @jdx in [#6528](https://github.com/jdx/mise/pull/6528)\n\n### New Contributors\n\n- @yordis made their first contribution in [#6516](https://github.com/jdx/mise/pull/6516)\n- @numso made their first contribution in [#6504](https://github.com/jdx/mise/pull/6504)\n- @BasixKOR made their first contribution in [#6521](https://github.com/jdx/mise/pull/6521)\n\n## [2025.10.1](https://github.com/jdx/mise/compare/v2025.10.0..v2025.10.1) - 2025-10-03\n\n### 🚀 Features\n\n- **(snapcraft)** add snap package by @phanect in [#6472](https://github.com/jdx/mise/pull/6472)\n\n### 🐛 Bug Fixes\n\n- **(cache)** remove duplicate bytes in prune output by @risu729 in [#6515](https://github.com/jdx/mise/pull/6515)\n\n### 📦 Registry\n\n- add tombi by @TyceHerrman in [#6520](https://github.com/jdx/mise/pull/6520)\n\n### Chore\n\n- **(copr)** increase COPR publish timeout by 60 minutes by @Copilot in [#6512](https://github.com/jdx/mise/pull/6512)\n\n### New Contributors\n\n- @phanect made their first contribution in [#6472](https://github.com/jdx/mise/pull/6472)\n\n## [2025.10.0](https://github.com/jdx/mise/compare/v2025.9.25..v2025.10.0) - 2025-10-01\n\n### 🚀 Features\n\n- change idiomatic_version_file to default disabled by @jdx in [#6501](https://github.com/jdx/mise/pull/6501)\n\n### 🐛 Bug Fixes\n\n- **(self-update)** add missing functions to self_update stub by @jdx in [#6502](https://github.com/jdx/mise/pull/6502)\n- **(set)** allow --prompt flag to work with `mise set` by @jdx in [#6485](https://github.com/jdx/mise/pull/6485)\n\n### 📚 Documentation\n\n- **(hooks)** clarify pre/post-install hooks description. by @minusfive in [#6497](https://github.com/jdx/mise/pull/6497)\n- remove link to issue by @jdx in [e13d980](https://github.com/jdx/mise/commit/e13d98012fda05e5032b7dfc18f562c28f140cf9)\n\n### 🧪 Testing\n\n- **(e2e)** remove deprecated MISE_LEGACY_VERSION_FILE assertions by @jdx in [#6505](https://github.com/jdx/mise/pull/6505)\n\n### 📦 Registry\n\n- add code by @TyceHerrman in [#6492](https://github.com/jdx/mise/pull/6492)\n\n### New Contributors\n\n- @minusfive made their first contribution in [#6497](https://github.com/jdx/mise/pull/6497)\n\n## [2025.9.25](https://github.com/jdx/mise/compare/v2025.9.24..v2025.9.25) - 2025-09-30\n\n### 🐛 Bug Fixes\n\n- **(auto-install)** support installing non-active backend versions by @jdx in [#6484](https://github.com/jdx/mise/pull/6484)\n- **(install)** remove duplicate 'mise' text in install header by @jdx in [#6489](https://github.com/jdx/mise/pull/6489)\n- **(task)** prevent hang when tasks with multiple dependencies fail by @stempler in [#6481](https://github.com/jdx/mise/pull/6481)\n\n### 🧪 Testing\n\n- **(e2e)** use local HTTP server instead of httpbin.org for tool-stub tests by @jdx in [#6488](https://github.com/jdx/mise/pull/6488)\n\n### 📦 Registry\n\n- prefer k3s from Aqua over ASDF plugin by @TobiX in [#6486](https://github.com/jdx/mise/pull/6486)\n\n### Chore\n\n- **(ci)** prevent release workflow from running on release branch pushes by @jdx in [#6490](https://github.com/jdx/mise/pull/6490)\n- **(ci)** parallelize release workflow to start e2e tests earlier by @jdx in [#6491](https://github.com/jdx/mise/pull/6491)\n\n### New Contributors\n\n- @stempler made their first contribution in [#6481](https://github.com/jdx/mise/pull/6481)\n\n## [2025.9.24](https://github.com/jdx/mise/compare/v2025.9.23..v2025.9.24) - 2025-09-29\n\n### 🚀 Features\n\n- **(age)** support age encrypted env vars in mise.toml files by @jdx in [#6463](https://github.com/jdx/mise/pull/6463)\n\n### 🐛 Bug Fixes\n\n- **(vfox)** integrate `parse_legacy_file` into backend by @malept in [#6471](https://github.com/jdx/mise/pull/6471)\n\n### 📦 Registry\n\n- add ggshield by @TyceHerrman in [#6435](https://github.com/jdx/mise/pull/6435)\n- add jaq by @TyceHerrman in [#6434](https://github.com/jdx/mise/pull/6434)\n\n## [2025.9.23](https://github.com/jdx/mise/compare/v2025.9.22..v2025.9.23) - 2025-09-28\n\n### 🚀 Features\n\n- **(env)** add support for required environment variables by @jdx in [#6461](https://github.com/jdx/mise/pull/6461)\n\n### 🐛 Bug Fixes\n\n- **(set)** unify config file resolution for mise set and mise use by @jdx in [#6467](https://github.com/jdx/mise/pull/6467)\n\n### Chore\n\n- **(clippy)** replace &Box<dyn SingleReport> with &dyn SingleReport by @jdx in [#6465](https://github.com/jdx/mise/pull/6465)\n\n## [2025.9.22](https://github.com/jdx/mise/compare/v2025.9.21..v2025.9.22) - 2025-09-28\n\n### 🚀 Features\n\n- **(backend)** add environment variable override for tool backends by @jdx in [#6456](https://github.com/jdx/mise/pull/6456)\n- add a http_retries setting to define number of retry attempts by @roele in [#6444](https://github.com/jdx/mise/pull/6444)\n\n### 📦 Registry\n\n- re-enable tests by @risu729 in [#6454](https://github.com/jdx/mise/pull/6454)\n- restore comments and tests by @risu729 in [#6378](https://github.com/jdx/mise/pull/6378)\n- add github backend for graphite by @jdx in [#6455](https://github.com/jdx/mise/pull/6455)\n\n## [2025.9.21](https://github.com/jdx/mise/compare/v2025.9.20..v2025.9.21) - 2025-09-27\n\n### 🚀 Features\n\n- **(cache)** add mise cache path command by @jdx in [#6442](https://github.com/jdx/mise/pull/6442)\n- **(github)** add support for compressed binaries and Buck2 to registry by @jdx in [#6439](https://github.com/jdx/mise/pull/6439)\n\n### 🐛 Bug Fixes\n\n- **(http)** bump mtime when extracting tarballs to cache by @jdx in [#6438](https://github.com/jdx/mise/pull/6438)\n\n### 🧪 Testing\n\n- **(vfox)** eliminate flaky remote host dependencies in tests by @jdx in [#6447](https://github.com/jdx/mise/pull/6447)\n- **(vfox)** improve test_download_file reliability by @jdx in [#6450](https://github.com/jdx/mise/pull/6450)\n- optimize remote task tests with local server by @jdx in [#6443](https://github.com/jdx/mise/pull/6443)\n- optimize git remote task tests with local repositories by @jdx in [#6441](https://github.com/jdx/mise/pull/6441)\n- mark slow e2e tests and add runtime warnings by @jdx in [#6449](https://github.com/jdx/mise/pull/6449)\n\n### 📦 Registry\n\n- remove incorrect bin_path from balena-cli by @jdx in [#6445](https://github.com/jdx/mise/pull/6445)\n- disable oxlint test temporarily by @jdx in [#6446](https://github.com/jdx/mise/pull/6446)\n\n### Chore\n\n- **(ci)** run release workflow on PRs to main for branch protection by @jdx in [#6448](https://github.com/jdx/mise/pull/6448)\n\n## [2025.9.20](https://github.com/jdx/mise/compare/v2025.9.19..v2025.9.20) - 2025-09-26\n\n### 🚀 Features\n\n- **(spm)** add support for self-hosted and GitLab repositories by @roele in [#6358](https://github.com/jdx/mise/pull/6358)\n- add instructions for self-update by @jdx in [#6433](https://github.com/jdx/mise/pull/6433)\n\n### 🐛 Bug Fixes\n\n- **(doctor)** exclude tools not supported on current os by @risu729 in [#6422](https://github.com/jdx/mise/pull/6422)\n- **(json-schema)** remove settings/additionalProperties by @tpansino in [#6420](https://github.com/jdx/mise/pull/6420)\n- **(task)** prevent hang when nested tasks fail by @jdx in [#6430](https://github.com/jdx/mise/pull/6430)\n- **(ubi)** filter versions with tag_regex before trimming v prefixes by @risu729 in [#6421](https://github.com/jdx/mise/pull/6421)\n- allow strip_archive_path_components to strip a dir containing the same filename by @risu729 in [#6405](https://github.com/jdx/mise/pull/6405)\n\n### 📦️ Dependency Updates\n\n- update ghcr.io/jdx/mise:alpine docker digest to a64d8b4 by @renovate[bot] in [#6426](https://github.com/jdx/mise/pull/6426)\n- update actions/cache digest to 0057852 by @renovate[bot] in [#6425](https://github.com/jdx/mise/pull/6425)\n- update ghcr.io/jdx/mise:deb docker digest to af96f8e by @renovate[bot] in [#6428](https://github.com/jdx/mise/pull/6428)\n- update ghcr.io/jdx/mise:copr docker digest to 0f98c77 by @renovate[bot] in [#6427](https://github.com/jdx/mise/pull/6427)\n\n### 📦 Registry\n\n- use version_prefix for github backends by @risu729 in [#6409](https://github.com/jdx/mise/pull/6409)\n- fix hivemind by @mnm364 in [#6431](https://github.com/jdx/mise/pull/6431)\n- revert opam/k3kcli backends to ubi by @risu729 in [#6406](https://github.com/jdx/mise/pull/6406)\n\n## [2025.9.19](https://github.com/jdx/mise/compare/v2025.9.18..v2025.9.19) - 2025-09-25\n\n### 🚀 Features\n\n- **(github)** filter remote versions by version_prefix by @risu729 in [#6408](https://github.com/jdx/mise/pull/6408)\n- Remove experimental labels for GitHub and HTTP backends by @Copilot in [#6415](https://github.com/jdx/mise/pull/6415)\n\n### 🐛 Bug Fixes\n\n- **(backend)** make pre-tools env vars available in postinstall hooks by @jdx in [#6418](https://github.com/jdx/mise/pull/6418)\n\n### 🧪 Testing\n\n- **(vfox)** replace flaky external tests with local dummy plugin by @jdx in [#6403](https://github.com/jdx/mise/pull/6403)\n\n### 📦 Registry\n\n- fix mise-ghcup plugin managed tools descriptions by @risu729 in [#6411](https://github.com/jdx/mise/pull/6411)\n- add Tinymist by @3w36zj6 in [#6412](https://github.com/jdx/mise/pull/6412)\n- revert djinni backend to ubi by @risu729 in [#6410](https://github.com/jdx/mise/pull/6410)\n\n### New Contributors\n\n- @Copilot made their first contribution in [#6415](https://github.com/jdx/mise/pull/6415)\n\n## [2025.9.18](https://github.com/jdx/mise/compare/v2025.9.17..v2025.9.18) - 2025-09-25\n\n### 🚀 Features\n\n- **(config)** support vars in tool versions by @jdx in [#6401](https://github.com/jdx/mise/pull/6401)\n- **(template)** add read_file() function by @jdx in [#6400](https://github.com/jdx/mise/pull/6400)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** support github_artifact_attestations.enabled by @risu729 in [#6372](https://github.com/jdx/mise/pull/6372)\n- use /c instead of -c on windows in postinstall hook by @risu729 in [#6397](https://github.com/jdx/mise/pull/6397)\n\n### 🧪 Testing\n\n- **(test-tool)** uninstall all versions and clear cache before installation by @jdx in [#6393](https://github.com/jdx/mise/pull/6393)\n\n### 📦 Registry\n\n- replace amplify-cli github backend with ubi by @eggplants in [#6396](https://github.com/jdx/mise/pull/6396)\n\n### New Contributors\n\n- @eggplants made their first contribution in [#6396](https://github.com/jdx/mise/pull/6396)\n\n## [2025.9.17](https://github.com/jdx/mise/compare/v2025.9.16..v2025.9.17) - 2025-09-24\n\n### 🚀 Features\n\n- **(java)** add support for Liberica NIK releases by @roele in [#6382](https://github.com/jdx/mise/pull/6382)\n\n### 🐛 Bug Fixes\n\n- **(toolset)** handle underflow in version_sub function by @koh-sh in [#6389](https://github.com/jdx/mise/pull/6389)\n\n### 📚 Documentation\n\n- document MISE_ENV behavior for global/system configs by @jdx in [#6385](https://github.com/jdx/mise/pull/6385)\n\n### New Contributors\n\n- @jc00ke made their first contribution in [#6386](https://github.com/jdx/mise/pull/6386)\n- @koh-sh made their first contribution in [#6389](https://github.com/jdx/mise/pull/6389)\n\n## [2025.9.16](https://github.com/jdx/mise/compare/v2025.9.15..v2025.9.16) - 2025-09-22\n\n### 🐛 Bug Fixes\n\n- **(aqua)** remove blake3 support from aqua checksum algorithms by @risu729 in [#6370](https://github.com/jdx/mise/pull/6370)\n- **(aqua)** remove cosign and slsa-verifier dependencies by @risu729 in [#6371](https://github.com/jdx/mise/pull/6371)\n- **(aqua)** remove cosign.experimental by @risu729 in [#6376](https://github.com/jdx/mise/pull/6376)\n- **(file)** handle GNU sparse files and tar crate extraction issues by @jdx in [#6380](https://github.com/jdx/mise/pull/6380)\n\n### 📚 Documentation\n\n- minisign doesn't require cli by @risu729 in [#6369](https://github.com/jdx/mise/pull/6369)\n\n### 📦 Registry\n\n- use npm backend for zbctl by @risu729 in [#6379](https://github.com/jdx/mise/pull/6379)\n\n### Chore\n\n- ignore renovate new bot name by @risu729 in [#6364](https://github.com/jdx/mise/pull/6364)\n\n## [2025.9.15](https://github.com/jdx/mise/compare/v2025.9.14..v2025.9.15) - 2025-09-21\n\n### 🚀 Features\n\n- add env propagation by @Its-Just-Nans in [#6342](https://github.com/jdx/mise/pull/6342)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** improve GitHub token handling for sigstore verification by @jdx in [#6351](https://github.com/jdx/mise/pull/6351)\n- **(backend)** change dependency checks to warnings instead of errors by @jdx in [#6363](https://github.com/jdx/mise/pull/6363)\n- **(npm)** improve error message when npm/bun is not installed by @jdx in [#6359](https://github.com/jdx/mise/pull/6359)\n- **(vfox)** enable TLS support for reqwest to fix CI tests by @jdx in [#6356](https://github.com/jdx/mise/pull/6356)\n\n### 🚜 Refactor\n\n- **(registry)** convert to nested TOML sections format by @jdx in [#6361](https://github.com/jdx/mise/pull/6361)\n\n### 🧪 Testing\n\n- **(e2e)** resolve mise via PATH in backend missing deps test by @jdx in [#6362](https://github.com/jdx/mise/pull/6362)\n- **(vfox)** replace flaky external HTTP tests with local mock server by @jdx in [#6354](https://github.com/jdx/mise/pull/6354)\n\n### 📦️ Dependency Updates\n\n- pin dependencies by @renovate[bot] in [#6243](https://github.com/jdx/mise/pull/6243)\n\n### 📦 Registry\n\n- add missing cargo backends by @jayvdb in [#6307](https://github.com/jdx/mise/pull/6307)\n\n### Chore\n\n- **(install.sh)** add `MISE_INSTALL_MUSL` to force installing musl variants on Linux by @malept in [#6355](https://github.com/jdx/mise/pull/6355)\n\n## [2025.9.14](https://github.com/jdx/mise/compare/v2025.9.13..v2025.9.14) - 2025-09-20\n\n### 🐛 Bug Fixes\n\n- fix an issue where Swift could not be installed on arm64 Ubuntu by @lish82 in [#6348](https://github.com/jdx/mise/pull/6348)\n\n### Chore\n\n- use cross to build on linux by @jdx in [#6346](https://github.com/jdx/mise/pull/6346)\n\n### New Contributors\n\n- @lish82 made their first contribution in [#6348](https://github.com/jdx/mise/pull/6348)\n\n## [2025.9.13](https://github.com/jdx/mise/compare/v2025.9.12..v2025.9.13) - 2025-09-19\n\n### 🚀 Features\n\n- **(aqua)** integrate native sigstore-verification for security verification by @jdx in [#6332](https://github.com/jdx/mise/pull/6332)\n- **(docs)** improve search result readability with lighter teal background by @jdx in [#6328](https://github.com/jdx/mise/pull/6328)\n- **(ui)** update logo as favicon and fix hover transitions by @jdx in [#6325](https://github.com/jdx/mise/pull/6325)\n- **(vfox)** add file.read lua function by @malept in [#6333](https://github.com/jdx/mise/pull/6333)\n- add documentation for \"Environment in tasks\" #5134 #5638 by @Its-Just-Nans in [#6329](https://github.com/jdx/mise/pull/6329)\n\n### 🐛 Bug Fixes\n\n- **(github)** correctly paginate releases/tags for private repos by @malept in [#6318](https://github.com/jdx/mise/pull/6318)\n- **(hk)** exclude aqua-registry from prettier linting by @jdx in [#6327](https://github.com/jdx/mise/pull/6327)\n- **(ui)** improve GitHub star badge layout and alignment by @jdx in [#6326](https://github.com/jdx/mise/pull/6326)\n\n### 📚 Documentation\n\n- change 'hello.py' to 'main.py' in python.md by @my1e5 in [#6319](https://github.com/jdx/mise/pull/6319)\n- customize VitePress theme with unique branding by @jdx in [#6324](https://github.com/jdx/mise/pull/6324)\n\n### 📦️ Dependency Updates\n\n- update taiki-e/install-action digest to 0aa4f22 by @renovate[bot] in [#6334](https://github.com/jdx/mise/pull/6334)\n- update rust crate comfy-table to v7.2.1 by @renovate[bot] in [#6335](https://github.com/jdx/mise/pull/6335)\n- update rust crate console to v0.16.1 by @renovate[bot] in [#6336](https://github.com/jdx/mise/pull/6336)\n- update rust crate indexmap to v2.11.4 by @renovate[bot] in [#6337](https://github.com/jdx/mise/pull/6337)\n\n### 📦 Registry\n\n- remove deprecated virtualos by @jdx in [166379f](https://github.com/jdx/mise/commit/166379f71c79fccacfc980dd14d4e18642c7d1e5)\n- add trufflehog ([aqua:trufflesecurity/trufflehog](https://github.com/trufflesecurity/trufflehog)) by @risu729 in [#6316](https://github.com/jdx/mise/pull/6316)\n\n### Chore\n\n- fixing typos by @Its-Just-Nans in [#6331](https://github.com/jdx/mise/pull/6331)\n\n### New Contributors\n\n- @Its-Just-Nans made their first contribution in [#6331](https://github.com/jdx/mise/pull/6331)\n- @my1e5 made their first contribution in [#6319](https://github.com/jdx/mise/pull/6319)\n\n## [2025.9.12](https://github.com/jdx/mise/compare/v2025.9.11..v2025.9.12) - 2025-09-16\n\n### 🐛 Bug Fixes\n\n- **(ci)** properly exclude aqua-registry files from hk linting by @jdx in [42d7758](https://github.com/jdx/mise/commit/42d7758d157317088ac5194ac26eefc7fc1ba4f8)\n\n### Chore\n\n- **(release)** embed aqua-registry under crate and publish like vfox by @jdx in [#6306](https://github.com/jdx/mise/pull/6306)\n- ignore aqua-registry assets from prettier by @jdx in [047d77b](https://github.com/jdx/mise/commit/047d77be35fea0b3277342cb6383a1873bca19a5)\n- disable \"useless cat\" shellcheck by @jdx in [a6def59](https://github.com/jdx/mise/commit/a6def59fe945028934fed0694df2b4daeeaaf478)\n\n## [2025.9.11](https://github.com/jdx/mise/compare/v2025.9.10..v2025.9.11) - 2025-09-16\n\n### 🚀 Features\n\n- **(ci)** run all registry tools when workflow_dispatch is triggered by @jdx in [#6295](https://github.com/jdx/mise/pull/6295)\n- **(cli)** handle non-existent working directories gracefully by @jdx in [#6304](https://github.com/jdx/mise/pull/6304)\n- **(set)** add -E/--env flag to mise set command by @jdx in [#6291](https://github.com/jdx/mise/pull/6291)\n- **(tasks)** make auto outputs default by @risu729 in [#6137](https://github.com/jdx/mise/pull/6137)\n\n### 🐛 Bug Fixes\n\n- align crate versions to fix release-plz script by @jdx in [5a464e9](https://github.com/jdx/mise/commit/5a464e98b56f49200e69ce2665ed896c74b206e3)\n\n### 🚜 Refactor\n\n- **(aqua)** extract aqua registry into internal subcrate by @jdx in [#6293](https://github.com/jdx/mise/pull/6293)\n\n### 📚 Documentation\n\n- fix mkdir paths by @risu729 in [#6298](https://github.com/jdx/mise/pull/6298)\n- fix rust profile default by @risu729 in [#6305](https://github.com/jdx/mise/pull/6305)\n\n### 📦 Registry\n\n- indicate aws-cli is v2 by @jayvdb in [#6300](https://github.com/jdx/mise/pull/6300)\n\n### Chore\n\n- **(aqua-registry)** remove unused aqua-registry files by @jdx in [#6294](https://github.com/jdx/mise/pull/6294)\n- **(release)** make release-plz idempotent for existing crate versions by @jdx in [dbdfd6a](https://github.com/jdx/mise/commit/dbdfd6a713852a1d55a6bb8376d2996545e128ce)\n- **(release)** skip publishing mise when aqua-registry is a path dep by @jdx in [47efffd](https://github.com/jdx/mise/commit/47efffdfc0316100f41c6c077d17fd6014663f4f)\n- keep aqua-registry LICENSE file by @risu729 in [#6297](https://github.com/jdx/mise/pull/6297)\n\n### New Contributors\n\n- @jayvdb made their first contribution in [#6300](https://github.com/jdx/mise/pull/6300)\n\n## [2025.9.10](https://github.com/jdx/mise/compare/v2025.9.9..v2025.9.10) - 2025-09-13\n\n### 🐛 Bug Fixes\n\n- **(tool-stub)** detect binary names from single-file downloads by @jdx in [#6281](https://github.com/jdx/mise/pull/6281)\n\n### 🚜 Refactor\n\n- allow any collection types in deserialize_arr by @risu729 in [#6282](https://github.com/jdx/mise/pull/6282)\n- use deserialize_arr for task runs by @risu729 in [#6253](https://github.com/jdx/mise/pull/6253)\n\n### 📚 Documentation\n\n- **(getting-started)** add backends step with diagram, github example, env vars and simple tasks by @jdx in [#6288](https://github.com/jdx/mise/pull/6288)\n- simplify OS detection in tool plugin development by @jdx in [#6287](https://github.com/jdx/mise/pull/6287)\n- update backend plugin template references by @jdx in [942f5eb](https://github.com/jdx/mise/commit/942f5eb1436fef38920836347218984200b07386)\n\n### 📦️ Dependency Updates\n\n- update rust crate chrono to v0.4.42 by @renovate[bot] in [#6274](https://github.com/jdx/mise/pull/6274)\n- update taiki-e/install-action digest to 0154864 by @renovate[bot] in [#6273](https://github.com/jdx/mise/pull/6273)\n\n### 📦 Registry\n\n- use asdf to install semver-tool by @jylenhof in [#6233](https://github.com/jdx/mise/pull/6233)\n\n### Chore\n\n- **(schema)** fix schema for subtasks by @risu729 in [#6289](https://github.com/jdx/mise/pull/6289)\n- update render:schema task by @risu729 in [#6275](https://github.com/jdx/mise/pull/6275)\n\n## [2025.9.9](https://github.com/jdx/mise/compare/v2025.9.8..v2025.9.9) - 2025-09-11\n\n### 🐛 Bug Fixes\n\n- **(backend)** make HTTP installs atomic and serialize with cache lock by @jdx in [#6259](https://github.com/jdx/mise/pull/6259)\n- **(env)** allow nested env._.path directives by @risu729 in [#6160](https://github.com/jdx/mise/pull/6160)\n- **(env)** disallow nested env objects by @risu729 in [#6268](https://github.com/jdx/mise/pull/6268)\n- **(schema)** allow nested arrays in task.depends by @risu729 in [#6265](https://github.com/jdx/mise/pull/6265)\n- **(task)** resolve jobs=1 hang and keep-order panic; improve Ctrl-C handling by @jdx in [#6264](https://github.com/jdx/mise/pull/6264)\n- **(tasks)** stop CLI group after first failure without --continue-on-error by @jdx in [#6270](https://github.com/jdx/mise/pull/6270)\n\n### 📚 Documentation\n\n- fixed toml issues in URL replacements settings documentation by @ThomasSteinbach in [#6269](https://github.com/jdx/mise/pull/6269)\n\n### Chore\n\n- **(schema)** strict oneOf branches and DRY env_directive in schemas by @jdx in [#6271](https://github.com/jdx/mise/pull/6271)\n- add schema linter by @risu729 in [#6267](https://github.com/jdx/mise/pull/6267)\n\n## [2025.9.8](https://github.com/jdx/mise/compare/v2025.9.7..v2025.9.8) - 2025-09-10\n\n### 🐛 Bug Fixes\n\n- **(tasks)** prevent hang when task fails in sequence by @jdx in [#6260](https://github.com/jdx/mise/pull/6260)\n- **(version)** fetch mise version if cached version is older than the current by @risu729 in [#6252](https://github.com/jdx/mise/pull/6252)\n\n### 📦️ Dependency Updates\n\n- update rhysd/action-setup-vim action to v1.4.3 by @renovate[bot] in [#6249](https://github.com/jdx/mise/pull/6249)\n\n## [2025.9.7](https://github.com/jdx/mise/compare/v2025.9.6..v2025.9.7) - 2025-09-09\n\n### 🐛 Bug Fixes\n\n- **(env)** allow mixed map for env._.file by @risu729 in [#6148](https://github.com/jdx/mise/pull/6148)\n- **(tasks)** restore parallel starts with poetry via list_paths cache and stable exec-env cache by @jdx in [#6237](https://github.com/jdx/mise/pull/6237)\n- add 'unknown' to the list of OS patterns by @efussi in [#6235](https://github.com/jdx/mise/pull/6235)\n- propagate errors from backend installs by @jdx in [#6236](https://github.com/jdx/mise/pull/6236)\n\n### 📦️ Dependency Updates\n\n- update taiki-e/install-action digest to 0c5db7f by @renovate[bot] in [#6244](https://github.com/jdx/mise/pull/6244)\n- update golang docker tag to v1.25.1 by @renovate[bot] in [#6247](https://github.com/jdx/mise/pull/6247)\n- update dependency vitepress to v1.6.4 by @renovate[bot] in [#6246](https://github.com/jdx/mise/pull/6246)\n\n### New Contributors\n\n- @efussi made their first contribution in [#6235](https://github.com/jdx/mise/pull/6235)\n\n## [2025.9.6](https://github.com/jdx/mise/compare/v2025.9.5..v2025.9.6) - 2025-09-08\n\n### 🚀 Features\n\n- **(backend)** add Backend trait methods for metadata fetching by @jdx in [#6228](https://github.com/jdx/mise/pull/6228)\n- **(core)** implement metadata fetching for Node.js and Bun by @jdx in [#6230](https://github.com/jdx/mise/pull/6230)\n- **(mise-test-tool)** add release scripts for automated GitHub releases by @jdx in [bd0eadd](https://github.com/jdx/mise/commit/bd0eadde5fff3897cda47d533c02cfe8e2b20048)\n- **(platform)** implement platform parsing and CLI integration by @jdx in [#6227](https://github.com/jdx/mise/pull/6227)\n- migrate tools from ubi to github backend which work by @jdx in [#6232](https://github.com/jdx/mise/pull/6232)\n\n### 🐛 Bug Fixes\n\n- **(task)** use terminal width instead of hardcoded 60-char limit for task display by @jdx in [#6218](https://github.com/jdx/mise/pull/6218)\n- **(task)** use terminal width instead of hardcoded 60-char limit for task display by @jdx in [#6220](https://github.com/jdx/mise/pull/6220)\n- nix flake build failure on macOS by @okuuva in [#6223](https://github.com/jdx/mise/pull/6223)\n- only use multi-version syntax in mise.lock by @jdx in [#6224](https://github.com/jdx/mise/pull/6224)\n\n### 🧪 Testing\n\n- **(e2e)** add comprehensive parallel task execution test for issue #5451 by @jdx in [#6221](https://github.com/jdx/mise/pull/6221)\n\n### Chore\n\n- added .cursor/environment.json by @jdx in [dc6b145](https://github.com/jdx/mise/commit/dc6b1455967c650b4f960316830b63072998977c)\n- init agent-os by @jdx in [81af40e](https://github.com/jdx/mise/commit/81af40ece5a8e1481b3a4ebf0de8a401fb7685ad)\n- agent-os analyze by @jdx in [9625f58](https://github.com/jdx/mise/commit/9625f58112d4f22d299c1352a3e85f036435f21c)\n\n## [2025.9.5](https://github.com/jdx/mise/compare/v2025.9.4..v2025.9.5) - 2025-09-06\n\n### 🚀 Features\n\n- **(task)** add timeout support for task execution by @jdx in [#6216](https://github.com/jdx/mise/pull/6216)\n- **(task)** sub-tasks in run lists by @jdx in [#6212](https://github.com/jdx/mise/pull/6212)\n\n### 🐛 Bug Fixes\n\n- **(task)** remove MISE_TASK_UNNEST functionality by @jdx in [#6217](https://github.com/jdx/mise/pull/6217)\n\n### Chore\n\n- fix npm publish action by @jdx in [14f4b09](https://github.com/jdx/mise/commit/14f4b09982cfa09139f172f302939f46d2cb0872)\n- fix cloudflare release action by @jdx in [00afa25](https://github.com/jdx/mise/commit/00afa2563d4368963bcacce11ebddbe05f45b4d7)\n- fix git-cliff for release notes by @jdx in [15a9aed](https://github.com/jdx/mise/commit/15a9aede95c8ad953842c206df3b6c9a3960100f)\n\n## [2025.9.4](https://github.com/jdx/mise/compare/v2025.9.3..v2025.9.4) - 2025-09-06\n\n### Chore\n\n- fix git-cliff on release by @jdx in [3c388f2](https://github.com/jdx/mise/commit/3c388f28e6cce6084f86e1805ace3aede594405b)\n\n## [2025.9.3](https://github.com/jdx/mise/compare/v2025.9.2..v2025.9.3) - 2025-09-06\n\n### 🚀 Features\n\n- **(backend)** improve http error when platform url missing; list available platforms by @jdx in [#6200](https://github.com/jdx/mise/pull/6200)\n- **(cli)** support scoped packages for all backend types by @earlgray283 in [#6213](https://github.com/jdx/mise/pull/6213)\n- **(http)** add URL replacement feature for HTTP requests by @ThomasSteinbach in [#6207](https://github.com/jdx/mise/pull/6207)\n\n### 🐛 Bug Fixes\n\n- **(backend)** preserve arch underscores in platform keys by @jdx in [#6202](https://github.com/jdx/mise/pull/6202)\n- **(task)** resolve hanging issue with multiple depends_post by @jdx in [#6206](https://github.com/jdx/mise/pull/6206)\n- couldn't download node binary in Alpine, even if it exists in the mirror url by @Hazer in [#5972](https://github.com/jdx/mise/pull/5972)\n- **breaking** use config_root for env._.path by @jdx in [#6204](https://github.com/jdx/mise/pull/6204)\n- bugfix for paths that include spaces by @karim-elkholy in [#6210](https://github.com/jdx/mise/pull/6210)\n\n### 📚 Documentation\n\n- improve release notes generation by @jdx in [#6197](https://github.com/jdx/mise/pull/6197)\n- fix release changelog contributor reporting by @jdx in [#6201](https://github.com/jdx/mise/pull/6201)\n\n### Chore\n\n- use fine-grained gh token by @jdx in [#6208](https://github.com/jdx/mise/pull/6208)\n- use settings.local.json for claude config by @jdx in [fd0fba9](https://github.com/jdx/mise/commit/fd0fba9fadb5ea36371283dbcda9a4f6264f96cd)\n\n### New Contributors\n\n- @ThomasSteinbach made their first contribution in [#6207](https://github.com/jdx/mise/pull/6207)\n- @earlgray283 made their first contribution in [#6213](https://github.com/jdx/mise/pull/6213)\n- @karim-elkholy made their first contribution in [#6210](https://github.com/jdx/mise/pull/6210)\n- @Hazer made their first contribution in [#5972](https://github.com/jdx/mise/pull/5972)\n\n## [2025.9.2](https://github.com/jdx/mise/compare/v2025.9.1..v2025.9.2) - 2025-09-05\n\n### 🐛 Bug Fixes\n\n- **(ci)** set required environment variables for npm publishing by @jdx in [#6189](https://github.com/jdx/mise/pull/6189)\n- **(release)** clean up extra newlines in release notes formatting by @jdx in [#6190](https://github.com/jdx/mise/pull/6190)\n- **(release)** add proper newline after New Contributors section in cliff template by @jdx in [#6194](https://github.com/jdx/mise/pull/6194)\n- **(release)** fix changelog formatting to remove extra blank lines by @jdx in [#6195](https://github.com/jdx/mise/pull/6195)\n- **(release)** restore proper newline after New Contributors section by @jdx in [#6196](https://github.com/jdx/mise/pull/6196)\n\n### 🚜 Refactor\n\n- **(ci)** split release workflow into separate specialized workflows by @jdx in [#6193](https://github.com/jdx/mise/pull/6193)\n\n### Chore\n\n- **(release)** require GitHub Actions environment for release-plz script by @jdx in [#6191](https://github.com/jdx/mise/pull/6191)\n\n## [2025.9.1](https://github.com/jdx/mise/compare/v2025.9.0..v2025.9.1) - 2025-09-05\n\n### 🐛 Bug Fixes\n\n- python nested venv path order by @elvismacak in [#6124](https://github.com/jdx/mise/pull/6124)\n- resolve immutable release workflow and VERSION file timing issues by @jdx in [#6187](https://github.com/jdx/mise/pull/6187)\n\n### New Contributors\n\n- @elvismacak made their first contribution in [#6124](https://github.com/jdx/mise/pull/6124)\n\n## [2025.9.0](https://github.com/jdx/mise/compare/v2025.8.21..v2025.9.0) - 2025-09-05\n\n### 🚀 Features\n\n- allow set/unset backend aliases by @roele in [#6172](https://github.com/jdx/mise/pull/6172)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** respect order of asset_strs by @risu729 in [#6143](https://github.com/jdx/mise/pull/6143)\n- **(java)** treat freebsd as linux (assuming linux compatability) by @roele in [#6161](https://github.com/jdx/mise/pull/6161)\n- **(nushell/windows)** Fix $env.PATH getting converted to a string by @zackyancey in [#6157](https://github.com/jdx/mise/pull/6157)\n- **(sync)** create uv_versions_path dir if it doesn't exist by @risu729 in [#6142](https://github.com/jdx/mise/pull/6142)\n- **(ubi)** show relevent error messages for v-prefixed tags by @risu729 in [#6183](https://github.com/jdx/mise/pull/6183)\n- remove nodejs/golang alias migrate code by @risu729 in [#6141](https://github.com/jdx/mise/pull/6141)\n- mise activate not working on powershell v5 by @L0RD-ZER0 in [#6168](https://github.com/jdx/mise/pull/6168)\n\n### 📚 Documentation\n\n- **(task)** remove word \"additional\" to avoid confusions by @risu729 in [#6159](https://github.com/jdx/mise/pull/6159)\n\n### Chore\n\n- update Cargo.lock by @risu729 in [#6184](https://github.com/jdx/mise/pull/6184)\n\n### New Contributors\n\n- @zackyancey made their first contribution in [#6157](https://github.com/jdx/mise/pull/6157)\n\n## [2025.8.21](https://github.com/jdx/mise/compare/v2025.8.20..v2025.8.21) - 2025-08-27\n\n### 🚀 Features\n\n- allow use of templates in task confirmation by @roele in [#6129](https://github.com/jdx/mise/pull/6129)\n\n### 🐛 Bug Fixes\n\n- task confirmation does not handle SIGINT appropriately by @roele in [#6126](https://github.com/jdx/mise/pull/6126)\n\n### 📚 Documentation\n\n- Split run command so that copy button is useful by @anujdeshpande in [#6099](https://github.com/jdx/mise/pull/6099)\n\n### 📦 Registry\n\n- prefer 1password asdf plugin for ls-remote by @risu729 in [#6116](https://github.com/jdx/mise/pull/6116)\n\n### New Contributors\n\n- @anujdeshpande made their first contribution in [#6099](https://github.com/jdx/mise/pull/6099)\n\n## [2025.8.20](https://github.com/jdx/mise/compare/v2025.8.19..v2025.8.20) - 2025-08-22\n\n### 🐛 Bug Fixes\n\n- use fish_add_path when activating mise for fish shell by @roele in [#6074](https://github.com/jdx/mise/pull/6074)\n\n## [2025.8.19](https://github.com/jdx/mise/compare/v2025.8.18..v2025.8.19) - 2025-08-22\n\n### 🐛 Bug Fixes\n\n- **(aqua)** bake in aliased registries by @risu729 in [#6105](https://github.com/jdx/mise/pull/6105)\n\n### 📦 Registry\n\n- update kubectl aqua alias by @malept in [#6107](https://github.com/jdx/mise/pull/6107)\n- remove asdf plugin for watchexec by @risu729 in [#6106](https://github.com/jdx/mise/pull/6106)\n\n## [2025.8.18](https://github.com/jdx/mise/compare/v2025.8.17..v2025.8.18) - 2025-08-22\n\n### 🚀 Features\n\n- **(env)** add --redacted and --values flags to env command by @jdx in [#6103](https://github.com/jdx/mise/pull/6103)\n\n## [2025.8.17](https://github.com/jdx/mise/compare/v2025.8.16..v2025.8.17) - 2025-08-22\n\n### 🐛 Bug Fixes\n\n- **(aqua)** remove mise-versions aqua registry by @risu729 in [#6097](https://github.com/jdx/mise/pull/6097)\n\n### 📚 Documentation\n\n- fix invalid configuration by @kamontat in [#6088](https://github.com/jdx/mise/pull/6088)\n\n### 📦️ Dependency Updates\n\n- update apple-actions/import-codesign-certs digest to 95e84a1 by @renovate[bot] in [#6093](https://github.com/jdx/mise/pull/6093)\n- update taiki-e/install-action digest to 36fe651 by @renovate[bot] in [#6094](https://github.com/jdx/mise/pull/6094)\n\n### 📦 Registry\n\n- remove asdf plugin for zoxide by @risu729 in [#6100](https://github.com/jdx/mise/pull/6100)\n\n### Chore\n\n- remove submodules option for actions/checkout by @risu729 in [#6090](https://github.com/jdx/mise/pull/6090)\n- exclude aqua-registry from linguist stats by @risu729 in [#6098](https://github.com/jdx/mise/pull/6098)\n\n### New Contributors\n\n- @kamontat made their first contribution in [#6088](https://github.com/jdx/mise/pull/6088)\n\n## [2025.8.16](https://github.com/jdx/mise/compare/v2025.8.15..v2025.8.16) - 2025-08-21\n\n### Chore\n\n- **(aqua-registry)** replace subtree logic with simpler `git clone` method by @jdx in [dd4947c](https://github.com/jdx/mise/commit/dd4947c49591ef3c0ac8372465bbfd1cde4ca946)\n- remove vfox-npm submodule by @jdx in [c22f95b](https://github.com/jdx/mise/commit/c22f95b4c30a4415ee08830e17fa8bd5a7a59eb7)\n- add vfox-npm by @jdx in [78c0972](https://github.com/jdx/mise/commit/78c0972a690eaf86eb6f5bbf2eabbe8a247890ea)\n\n## [2025.8.15](https://github.com/jdx/mise/compare/v2025.8.14..v2025.8.15) - 2025-08-21\n\n### Chore\n\n- **(release-plz)** get `git status` by @jdx in [#6083](https://github.com/jdx/mise/pull/6083)\n- add libbz2-dev to e2e test dependencies by @jdx in [#6080](https://github.com/jdx/mise/pull/6080)\n- replace submodule with subtree by @risu729 in [#6082](https://github.com/jdx/mise/pull/6082)\n- fix aqua-registry subtree by @jdx in [522f7f5](https://github.com/jdx/mise/commit/522f7f591dbfa01e537c294647ffdc2a2357c32c)\n\n## [2025.8.14](https://github.com/jdx/mise/compare/v2025.8.13..v2025.8.14) - 2025-08-20\n\n### 🚀 Features\n\n- **(http)** auto-clean OS/arch suffixes from binary names by @jdx in [#6077](https://github.com/jdx/mise/pull/6077)\n- **(install)** add --dry-run flag to show what would be installed by @jdx in [#6078](https://github.com/jdx/mise/pull/6078)\n\n### 🐛 Bug Fixes\n\n- **(python)** patching sysconfig data fails for RC versions by @roele in [#6069](https://github.com/jdx/mise/pull/6069)\n- **(schema)** add missing `settings` type by @br3ndonland in [#6070](https://github.com/jdx/mise/pull/6070)\n\n### Chore\n\n- add liblzma-dev for e2e tests to avoid python-build warning by @jdx in [#6066](https://github.com/jdx/mise/pull/6066)\n\n## [2025.8.13](https://github.com/jdx/mise/compare/v2025.8.12..v2025.8.13) - 2025-08-18\n\n### 🐛 Bug Fixes\n\n- clean up install progress and error output by @jdx in [#6063](https://github.com/jdx/mise/pull/6063)\n- make header progress display at start of install by @jdx in [#6065](https://github.com/jdx/mise/pull/6065)\n\n### Chore\n\n- Upgrade ubi dependency by @suprememoocow in [#6061](https://github.com/jdx/mise/pull/6061)\n- replace install_or_update_python_build by @jdx in [#6064](https://github.com/jdx/mise/pull/6064)\n\n### New Contributors\n\n- @suprememoocow made their first contribution in [#6061](https://github.com/jdx/mise/pull/6061)\n\n## [2025.8.12](https://github.com/jdx/mise/compare/v2025.8.11..v2025.8.12) - 2025-08-17\n\n### 🚀 Features\n\n- respect PREFER_OFFLINE for aqua package metadata fetching by @jdx in [#6058](https://github.com/jdx/mise/pull/6058)\n\n### 📚 Documentation\n\n- fix backend_architecture docs by @risu729 in [#6027](https://github.com/jdx/mise/pull/6027)\n\n### 📦️ Dependency Updates\n\n- update amannn/action-semantic-pull-request digest to e32d7e6 by @renovate[bot] in [#6031](https://github.com/jdx/mise/pull/6031)\n- update actions/checkout digest to 08eba0b by @renovate[bot] in [#6030](https://github.com/jdx/mise/pull/6030)\n- update actions/cache digest to 0400d5f by @renovate[bot] in [#5957](https://github.com/jdx/mise/pull/5957)\n\n### 📦 Registry\n\n- support tenv idiomatic files by @risu729 in [#6050](https://github.com/jdx/mise/pull/6050)\n\n### Chore\n\n- check for warnings in gha with rust stable by @jdx in [#6055](https://github.com/jdx/mise/pull/6055)\n\n## [2025.8.11](https://github.com/jdx/mise/compare/v2025.8.10..v2025.8.11) - 2025-08-17\n\n### 🚀 Features\n\n- **(task)** allow more #MISE comments patterns by @risu729 in [#6011](https://github.com/jdx/mise/pull/6011)\n\n### 🐛 Bug Fixes\n\n- prevent panic with task tera errors by @jdx in [#6046](https://github.com/jdx/mise/pull/6046)\n\n### 📚 Documentation\n\n- **(settings)** use php as an example for `disable_default_registry` by @risu729 in [#6025](https://github.com/jdx/mise/pull/6025)\n- Update ide-integration.md by @jdx in [#6035](https://github.com/jdx/mise/pull/6035)\n- Update ide-integration.md by @jdx in [#6040](https://github.com/jdx/mise/pull/6040)\n- added openSUSE zypper install instructions by @lfromanini in [#6037](https://github.com/jdx/mise/pull/6037)\n- update `contributing.md` for discussions by @br3ndonland in [#6047](https://github.com/jdx/mise/pull/6047)\n\n### 📦 Registry\n\n- add container-use ([aqua:dagger/container-use](https://github.com/dagger/container-use)) by @TyceHerrman in [#6029](https://github.com/jdx/mise/pull/6029)\n- add prek ([aqua:j178/prek](https://github.com/j178/prek)) by @HenryZhang-ZHY in [#6023](https://github.com/jdx/mise/pull/6023)\n\n### Chore\n\n- fix warnings by @jdx in [#6043](https://github.com/jdx/mise/pull/6043)\n- remove unused permissions in registry test by @risu729 in [#6044](https://github.com/jdx/mise/pull/6044)\n- fix fish shell script in hk config by @jdx in [#6048](https://github.com/jdx/mise/pull/6048)\n\n### New Contributors\n\n- @br3ndonland made their first contribution in [#6047](https://github.com/jdx/mise/pull/6047)\n- @HenryZhang-ZHY made their first contribution in [#6023](https://github.com/jdx/mise/pull/6023)\n- @lfromanini made their first contribution in [#6037](https://github.com/jdx/mise/pull/6037)\n\n## [2025.8.10](https://github.com/jdx/mise/compare/v2025.8.9..v2025.8.10) - 2025-08-14\n\n### 🚀 Features\n\n- **(aqua)** make bin paths executable by @risu729 in [#6010](https://github.com/jdx/mise/pull/6010)\n- added header bar during `mise install` by @jdx in [#6022](https://github.com/jdx/mise/pull/6022)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** improve warnings for packages without repo_owner and repo_name  (2nd attempt) by @risu729 in [#6009](https://github.com/jdx/mise/pull/6009)\n- version prefix detection by @risu729 in [#5943](https://github.com/jdx/mise/pull/5943)\n- respect MISE_DEFAULT_CONFIG_FILENAME by @risu729 in [#5899](https://github.com/jdx/mise/pull/5899)\n\n### 📦 Registry\n\n- enable kubecolor test by @risu729 in [#6008](https://github.com/jdx/mise/pull/6008)\n- fix os specific backends for usage by @risu729 in [#6007](https://github.com/jdx/mise/pull/6007)\n- use aqua backend for restish by @risu729 in [#5986](https://github.com/jdx/mise/pull/5986)\n- add cfssljson ([aqua:cloudflare/cfssl/cfssljson](https://github.com/cloudflare/cfssl/cfssljson)) by @disintegrator in [#6013](https://github.com/jdx/mise/pull/6013)\n- add claude-squad ([aqua:smtg-ai/claude-squad](https://github.com/smtg-ai/claude-squad)) by @TyceHerrman in [#5894](https://github.com/jdx/mise/pull/5894)\n\n### New Contributors\n\n- @disintegrator made their first contribution in [#6013](https://github.com/jdx/mise/pull/6013)\n\n## [2025.8.9](https://github.com/jdx/mise/compare/v2025.8.8..v2025.8.9) - 2025-08-13\n\n### 🚀 Features\n\n- **(timeout)** show duration, URL, and config hint on timeouts; increase fetch timeout default to 10s by @jdx in [#5991](https://github.com/jdx/mise/pull/5991)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** add executable permissions for zip-extracted binaries by @itochan in [#5998](https://github.com/jdx/mise/pull/5998)\n- **(core)** auto-repair corrupted pyenv cache by recloning on update failure by @jdx in [#6003](https://github.com/jdx/mise/pull/6003)\n- **(uv_venv)** fixes PATH ordering with `mise x` by @jdx in [#6005](https://github.com/jdx/mise/pull/6005)\n- duplicate versions and validation in `mise tool` by @jdx in [#6001](https://github.com/jdx/mise/pull/6001)\n\n### 📚 Documentation\n\n- **(tools)** document per-tool postinstall option in [tools] by @jdx in [#5993](https://github.com/jdx/mise/pull/5993)\n- Update install instructions for nushell by @Joniator in [#5981](https://github.com/jdx/mise/pull/5981)\n- README.md typo by @jdx in [#5990](https://github.com/jdx/mise/pull/5990)\n\n### ◀️ Revert\n\n- Revert \"docs: Update install instructions for nushell\" by @jdx in [#5983](https://github.com/jdx/mise/pull/5983)\n- Revert \"fix(aqua): add executable permissions for zip-extracted binaries\" by @jdx in [#6004](https://github.com/jdx/mise/pull/6004)\n\n### 📦️ Dependency Updates\n\n- update taiki-e/install-action digest to 2c73a74 by @renovate[bot] in [#5962](https://github.com/jdx/mise/pull/5962)\n- update docker/metadata-action digest to c1e5197 by @renovate[bot] in [#5961](https://github.com/jdx/mise/pull/5961)\n- update docker/login-action digest to 184bdaa by @renovate[bot] in [#5958](https://github.com/jdx/mise/pull/5958)\n\n### 📦 Registry\n\n- add vfox-yarn as primary yarn backend by @jdx in [#5982](https://github.com/jdx/mise/pull/5982)\n- add missing description field for a lot of tools by @jylenhof in [#5966](https://github.com/jdx/mise/pull/5966)\n- rename benthos to redpanda-connect by @risu729 in [#5984](https://github.com/jdx/mise/pull/5984)\n- rename coq to rocq by @risu729 in [#5985](https://github.com/jdx/mise/pull/5985)\n\n### Chore\n\n- cargo up by @jdx in [#5992](https://github.com/jdx/mise/pull/5992)\n\n### New Contributors\n\n- @Joniator made their first contribution in [#5981](https://github.com/jdx/mise/pull/5981)\n- @jylenhof made their first contribution in [#5966](https://github.com/jdx/mise/pull/5966)\n\n## [2025.8.8](https://github.com/jdx/mise/compare/v2025.8.7..v2025.8.8) - 2025-08-11\n\n### 📚 Documentation\n\n- add documentation for os field in tool configuration by @jdx in [#5947](https://github.com/jdx/mise/pull/5947)\n\n### 📦 Registry\n\n- add bob ([aqua:MordechaiHadad/bob](https://github.com/MordechaiHadad/bob)) by @TyceHerrman in [#5914](https://github.com/jdx/mise/pull/5914)\n- support usage on FreeBSD by @risu729 in [#5973](https://github.com/jdx/mise/pull/5973)\n- filter out installer for podman by @risu729 in [#5974](https://github.com/jdx/mise/pull/5974)\n- use pipx aqua backend by @itochan in [#5971](https://github.com/jdx/mise/pull/5971)\n- only use aqua backend for yarn on windows by @jdx in [#5978](https://github.com/jdx/mise/pull/5978)\n\n### Chore\n\n- **(ci)** accept @ in regular expressions for new registry PR titles by @mst-mkt in [#5969](https://github.com/jdx/mise/pull/5969)\n- fix registry test filter by @risu729 in [#5942](https://github.com/jdx/mise/pull/5942)\n- fix registry test by @risu729 in [#5953](https://github.com/jdx/mise/pull/5953)\n\n### New Contributors\n\n- @itochan made their first contribution in [#5971](https://github.com/jdx/mise/pull/5971)\n- @mst-mkt made their first contribution in [#5969](https://github.com/jdx/mise/pull/5969)\n\n## [2025.8.7](https://github.com/jdx/mise/compare/v2025.8.6..v2025.8.7) - 2025-08-06\n\n### 🐛 Bug Fixes\n\n- **(lockfile)** fix multiple lockfile issues with version management by @jdx in [#5907](https://github.com/jdx/mise/pull/5907)\n- **(toolset)** properly handle MISE_ADD_PATH from plugins by @jdx in [#5937](https://github.com/jdx/mise/pull/5937)\n\n### 📦 Registry\n\n- add python to gcloud dependencies by @risu729 in [#5936](https://github.com/jdx/mise/pull/5936)\n\n## [2025.8.6](https://github.com/jdx/mise/compare/v2025.8.5..v2025.8.6) - 2025-08-06\n\n### 🚀 Features\n\n- **(tool-stub)** improve stub generation with bin inference, error handling, and fetch mode by @jdx in [#5932](https://github.com/jdx/mise/pull/5932)\n\n### 📦 Registry\n\n- add resvg ([aqua:linebender/resvg](https://github.com/linebender/resvg)) by @TyceHerrman in [#5926](https://github.com/jdx/mise/pull/5926)\n- add specstory ([aqua:specstoryai/getspecstory](https://github.com/specstoryai/getspecstory)) by @TyceHerrman in [#5927](https://github.com/jdx/mise/pull/5927)\n- add oxker ([aqua:mrjackwills/oxker](https://github.com/mrjackwills/oxker)) by @TyceHerrman in [#5929](https://github.com/jdx/mise/pull/5929)\n- add tssh ([aqua:trzsz/trzsz-ssh](https://github.com/trzsz/trzsz-ssh)) by @TyceHerrman in [#5928](https://github.com/jdx/mise/pull/5928)\n\n## [2025.8.5](https://github.com/jdx/mise/compare/v2025.8.4..v2025.8.5) - 2025-08-05\n\n### 🚀 Features\n\n- **(ci)** enhance registry PR validation with strict format checking by @jdx in [#5897](https://github.com/jdx/mise/pull/5897)\n- add Model Context Protocol (MCP) server command by @jdx in [#5920](https://github.com/jdx/mise/pull/5920)\n\n### 🐛 Bug Fixes\n\n- **(elixir)** support `.exenv-version` by @risu729 in [#5901](https://github.com/jdx/mise/pull/5901)\n- **(env)** improve PATH handling for env._.path directives by @jdx in [#5922](https://github.com/jdx/mise/pull/5922)\n- allow devcontainer creation without a git repository by @acesyde in [#5891](https://github.com/jdx/mise/pull/5891)\n\n### 📦 Registry\n\n- add tlrc ([aqua:tldr-pages/tlrc](https://github.com/tldr-pages/tlrc)) by @TyceHerrman in [#5895](https://github.com/jdx/mise/pull/5895)\n- support `.terragrunt-version` by @risu729 in [#5903](https://github.com/jdx/mise/pull/5903)\n- add lnav ([aqua:tstack/lnav](https://github.com/tstack/lnav)) by @TyceHerrman in [#5896](https://github.com/jdx/mise/pull/5896)\n- use aqua backend for yarn by @risu729 in [#5902](https://github.com/jdx/mise/pull/5902)\n- add dotenvx ([aqua:dotenvx/dotenvx](https://github.com/dotenvx/dotenvx)) by @TyceHerrman in [#5915](https://github.com/jdx/mise/pull/5915)\n- update kubecolor ([aqua:kubecolor/kubecolor](https://github.com/kubecolor/kubecolor)) by @Darwiner in [#5887](https://github.com/jdx/mise/pull/5887)\n- add oxlint ([aqua:oxc-project/oxc/oxlint](https://github.com/oxc-project/oxc/oxlint)) by @TyceHerrman in [#5919](https://github.com/jdx/mise/pull/5919)\n- add container ([aqua:apple/container](https://github.com/apple/container)) by @TyceHerrman in [#5917](https://github.com/jdx/mise/pull/5917)\n- support `.packer-version` by @risu729 in [#5900](https://github.com/jdx/mise/pull/5900)\n\n### Chore\n\n- add synchronize to registry_comment gha by @jdx in [cbb1429](https://github.com/jdx/mise/commit/cbb14294072e9cbd3b0b9f21b2cb0a993a71d5ff)\n- fix registry_comment gha by @jdx in [7ce513b](https://github.com/jdx/mise/commit/7ce513be3efe60372f667f76570e16ce0d4a013f)\n- run registry test only for changed tools by @risu729 in [#5905](https://github.com/jdx/mise/pull/5905)\n\n### New Contributors\n\n- @Darwiner made their first contribution in [#5887](https://github.com/jdx/mise/pull/5887)\n- @zekefast made their first contribution in [#5912](https://github.com/jdx/mise/pull/5912)\n\n## [2025.8.4](https://github.com/jdx/mise/compare/v2025.8.3..v2025.8.4) - 2025-08-03\n\n### 🚀 Features\n\n- **(tasks)** **breaking** Add environment variable directives for mise tasks by @jdx in [#5638](https://github.com/jdx/mise/pull/5638)\n\n## [2025.8.3](https://github.com/jdx/mise/compare/v2025.8.2..v2025.8.3) - 2025-08-03\n\n### 🚀 Features\n\n- **(registry)** add atuin package to registry by @TyceHerrman in [#5883](https://github.com/jdx/mise/pull/5883)\n- introduce registry commit type for new tool additions by @jdx in [#5884](https://github.com/jdx/mise/pull/5884)\n\n### 🐛 Bug Fixes\n\n- **(aqua,github)** make asset name matching case-insensitive by @jdx in [#5886](https://github.com/jdx/mise/pull/5886)\n\n### 🚜 Refactor\n\n- **(ci)** separate Alpine release into its own workflow by @jdx in [#5868](https://github.com/jdx/mise/pull/5868)\n\n### 📚 Documentation\n\n- **(changelog)** automate backend links in changelog by @jdx in [#5889](https://github.com/jdx/mise/pull/5889)\n\n### ⚡ Performance\n\n- reduce render env task calls by @jdx in [#5888](https://github.com/jdx/mise/pull/5888)\n\n### 📦 Registry\n\n- add git-lfs ([aqua:git-lfs/git-lfs](https://github.com/git-lfs/git-lfs)) by @TyceHerrman in [#5885](https://github.com/jdx/mise/pull/5885)\n\n## [2025.8.2](https://github.com/jdx/mise/compare/v2025.8.1..v2025.8.2) - 2025-08-02\n\n### 🚀 Features\n\n- **(registry)** add jjui by @TyceHerrman in [#5877](https://github.com/jdx/mise/pull/5877)\n- **(registry)** add trunk metalinter by @daveio in [#5875](https://github.com/jdx/mise/pull/5875)\n\n### 🐛 Bug Fixes\n\n- **(python)** Windows OS no longer suffixed with `-shared` by @malept in [#5879](https://github.com/jdx/mise/pull/5879)\n\n### New Contributors\n\n- @daveio made their first contribution in [#5875](https://github.com/jdx/mise/pull/5875)\n- @TyceHerrman made their first contribution in [#5877](https://github.com/jdx/mise/pull/5877)\n\n## [2025.8.1](https://github.com/jdx/mise/compare/v2025.8.0..v2025.8.1) - 2025-08-01\n\n### 🐛 Bug Fixes\n\n- node gpg keys by @jdx in [#5866](https://github.com/jdx/mise/pull/5866)\n\n## [2025.8.0](https://github.com/jdx/mise/compare/v2025.7.32..v2025.8.0) - 2025-08-01\n\n### 🚀 Features\n\n- **(registry)** use npm backend for yarn by @mrazauskas in [#5745](https://github.com/jdx/mise/pull/5745)\n- **(registry)** add codebuff tool by @zacheryph in [#5856](https://github.com/jdx/mise/pull/5856)\n\n### 🐛 Bug Fixes\n\n- **(go)** implement heuristic-based go module find logic by @risu729 in [#5851](https://github.com/jdx/mise/pull/5851)\n- **(node)** Add NodeJS maintainer Antoine du Hamel's new GPG key by @chadlwilson in [#5862](https://github.com/jdx/mise/pull/5862)\n- **(pipx)** align HTML backend with PEP 503 registry URL assignment by @acesyde in [#5853](https://github.com/jdx/mise/pull/5853)\n- **(registry)** fix balena ubi backend options by @risu729 in [#5861](https://github.com/jdx/mise/pull/5861)\n- **(registry)** add aqua backends to tools by @risu729 in [#5863](https://github.com/jdx/mise/pull/5863)\n\n### 📚 Documentation\n\n- fix uv_venv_create_args reference for python by @jasonraimondi in [#5854](https://github.com/jdx/mise/pull/5854)\n- expand on env directive examples and formats by @syhol in [#5857](https://github.com/jdx/mise/pull/5857)\n\n### ◀️ Revert\n\n- Revert \"docs: fix uv_venv_create_args reference for python\" by @jdx in [#5859](https://github.com/jdx/mise/pull/5859)\n\n### New Contributors\n\n- @zacheryph made their first contribution in [#5856](https://github.com/jdx/mise/pull/5856)\n- @chadlwilson made their first contribution in [#5862](https://github.com/jdx/mise/pull/5862)\n- @jasonraimondi made their first contribution in [#5854](https://github.com/jdx/mise/pull/5854)\n\n## [2025.7.32](https://github.com/jdx/mise/compare/v2025.7.31..v2025.7.32) - 2025-07-31\n\n### 🚀 Features\n\n- **(tool-stubs)** Add human readable comments to stub sizes by @jdx in [#5845](https://github.com/jdx/mise/pull/5845)\n- **(tool-stubs)** improve binary path detection in tool stub generator by @jdx in [#5847](https://github.com/jdx/mise/pull/5847)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** support `AND` operator in semver by @risu729 in [#5838](https://github.com/jdx/mise/pull/5838)\n- **(cli)** remove empty [platforms] section from generated tool stubs by @jdx in [#5844](https://github.com/jdx/mise/pull/5844)\n- **(tool-stubs)** remove comment line from tool stub generator by @jdx in [#5843](https://github.com/jdx/mise/pull/5843)\n- **(tool-stubs)** Remove latest version from tool stubs by @jdx in [#5846](https://github.com/jdx/mise/pull/5846)\n- **(tool-stubs)** allow -v flag to be passed through to tool stubs by @jdx in [#5848](https://github.com/jdx/mise/pull/5848)\n\n## [2025.7.31](https://github.com/jdx/mise/compare/v2025.7.30..v2025.7.31) - 2025-07-29\n\n### 🚀 Features\n\n- **(tool-stubs)** append to existing tool-stub files instead of overwriting by @jdx in [#5835](https://github.com/jdx/mise/pull/5835)\n- **(tool-stubs)** add auto-platform detection from URLs by @jdx in [#5836](https://github.com/jdx/mise/pull/5836)\n- Add sops.strict setting for non-strict decryption mode by @pepicrft in [#5378](https://github.com/jdx/mise/pull/5378)\n\n### 🐛 Bug Fixes\n\n- **(tool-stub)** use URL hash as version for HTTP backend with \"latest\" by @jdx in [#5828](https://github.com/jdx/mise/pull/5828)\n- **(tool-stubs)** fix -v and --help flags by @jdx in [#5829](https://github.com/jdx/mise/pull/5829)\n- **(tool-stubs)** use 'checksum' field instead of 'blake3' in generated stubs by @jdx in [#5834](https://github.com/jdx/mise/pull/5834)\n- dotnet SearchQueryService fallback by @acesyde in [#5824](https://github.com/jdx/mise/pull/5824)\n- registry.toml - Specify sbt dependency on java by @jatcwang in [#5827](https://github.com/jdx/mise/pull/5827)\n\n### 🧪 Testing\n\n- remove has test which is failing by @jdx in [4aa9cc9](https://github.com/jdx/mise/commit/4aa9cc973acb1bc34df51f27333a226df3256b69)\n\n### New Contributors\n\n- @jatcwang made their first contribution in [#5827](https://github.com/jdx/mise/pull/5827)\n\n## [2025.7.30](https://github.com/jdx/mise/compare/v2025.7.29..v2025.7.30) - 2025-07-29\n\n### 🚀 Features\n\n- **(registry)** add amp by @jahands in [#5814](https://github.com/jdx/mise/pull/5814)\n\n### 🐛 Bug Fixes\n\n- **(tool-stubs)** fix error messages when it can't find the bin by @jdx in [#5817](https://github.com/jdx/mise/pull/5817)\n- misidentifying built-in backend as a plugin backend by @syhol in [#5822](https://github.com/jdx/mise/pull/5822)\n\n### 📚 Documentation\n\n- **(troubleshooting)** path limits on Windows by @W1M0R in [#5815](https://github.com/jdx/mise/pull/5815)\n\n## [2025.7.29](https://github.com/jdx/mise/compare/v2025.7.28..v2025.7.29) - 2025-07-28\n\n### 🐛 Bug Fixes\n\n- **(cli)** stable path env for exec on windows by @W1M0R in [#5790](https://github.com/jdx/mise/pull/5790)\n- **(tool-stubs)** platform-specific bin fields by @jdx in [#5812](https://github.com/jdx/mise/pull/5812)\n- tool-stub generation with archive downloads by @jdx in [#5811](https://github.com/jdx/mise/pull/5811)\n\n### 📦️ Dependency Updates\n\n- update jdx/mise-action digest to c37c932 by @renovate[bot] in [#5784](https://github.com/jdx/mise/pull/5784)\n\n### New Contributors\n\n- @W1M0R made their first contribution in [#5790](https://github.com/jdx/mise/pull/5790)\n\n## [2025.7.28](https://github.com/jdx/mise/compare/v2025.7.27..v2025.7.28) - 2025-07-27\n\n### 🚀 Features\n\n- **(http)** show retry after for github rate limit by @risu729 in [#5803](https://github.com/jdx/mise/pull/5803)\n- **(registry)** add carapace by @jahands in [#5804](https://github.com/jdx/mise/pull/5804)\n- **(registry)** add `hatch` by @hasansezertasan in [#5788](https://github.com/jdx/mise/pull/5788)\n- tool-stubs by @jdx in [#5795](https://github.com/jdx/mise/pull/5795)\n- used shared cache for http backend by @jdx in [#5808](https://github.com/jdx/mise/pull/5808)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** avoid unnecessary head requests in version resolution by @risu729 in [#5800](https://github.com/jdx/mise/pull/5800)\n- **(toolset)** use join_paths for MISE_ADD_PATH by @risu729 in [#5785](https://github.com/jdx/mise/pull/5785)\n- check lib64 directories for .disable-self-update file by @jdx in [#5809](https://github.com/jdx/mise/pull/5809)\n\n### 🚜 Refactor\n\n- **(aqua)** move alternative backend suggestions into validate by @risu729 in [#5794](https://github.com/jdx/mise/pull/5794)\n\n### 📚 Documentation\n\n- **(tool-stubs)** added shebangs by @jdx in [2d37500](https://github.com/jdx/mise/commit/2d37500e309a61062fc0e821a38be98626176d5d)\n- **(tool-stubs)** corrected url syntax by @jdx in [32627be](https://github.com/jdx/mise/commit/32627bec8b3df5060ea9f93dc50003126585e572)\n- fix plugin-lua-modules docs to match the vfox lua_mod functions by @syhol in [#5792](https://github.com/jdx/mise/pull/5792)\n- fix http backend tool options example by @roele in [#5802](https://github.com/jdx/mise/pull/5802)\n\n### 📦️ Dependency Updates\n\n- update taiki-e/install-action digest to 7fbb30f by @renovate[bot] in [#5786](https://github.com/jdx/mise/pull/5786)\n- pin actions/checkout action to 11bd719 by @renovate[bot] in [#5783](https://github.com/jdx/mise/pull/5783)\n\n### New Contributors\n\n- @hasansezertasan made their first contribution in [#5788](https://github.com/jdx/mise/pull/5788)\n\n## [2025.7.27](https://github.com/jdx/mise/compare/v2025.7.26..v2025.7.27) - 2025-07-24\n\n### 🐛 Bug Fixes\n\n- **(copr)** disable self-update by @jdx in [#5780](https://github.com/jdx/mise/pull/5780)\n- **(link.md)** correct example comment in mise link documentation by @mmurdockk in [#5760](https://github.com/jdx/mise/pull/5760)\n- use github releases in install.sh for non-current version by @jdx in [c2b1ef1](https://github.com/jdx/mise/commit/c2b1ef1c53d736e14fb64365aa1339dc955d6c59)\n\n### New Contributors\n\n- @mmurdockk made their first contribution in [#5760](https://github.com/jdx/mise/pull/5760)\n\n## [2025.7.26](https://github.com/jdx/mise/compare/v2025.7.25..v2025.7.26) - 2025-07-24\n\n### Chore\n\n- use correct release dirname by @jdx in [c8e0b5b](https://github.com/jdx/mise/commit/c8e0b5b42f3d258ec977b68326461d2fc81c4724)\n\n## [2025.7.25](https://github.com/jdx/mise/compare/v2025.7.24..v2025.7.25) - 2025-07-24\n\n### Chore\n\n- updated deps by @jdx in [#5771](https://github.com/jdx/mise/pull/5771)\n\n## [2025.7.24](https://github.com/jdx/mise/compare/v2025.7.23..v2025.7.24) - 2025-07-24\n\n### Chore\n\n- add MISE_INSTALL_FROM_GITHUB option for mise.run by @jdx in [#5772](https://github.com/jdx/mise/pull/5772)\n\n## [2025.7.22](https://github.com/jdx/mise/compare/v2025.7.21..v2025.7.22) - 2025-07-24\n\n### 🚀 Features\n\n- **(doctor)** display # of baked-in aqua registry tools by @jdx in [#5756](https://github.com/jdx/mise/pull/5756)\n- **(lock)** `mise lock` enhancements by @jdx in [#5765](https://github.com/jdx/mise/pull/5765)\n- registry.toml: add SST by @juxuanu in [#5758](https://github.com/jdx/mise/pull/5758)\n\n### 🐛 Bug Fixes\n\n- **(copr)** fix remaining issues by @jdx in [#5755](https://github.com/jdx/mise/pull/5755)\n\n### 📚 Documentation\n\n- add descriptions for all the tasks by @jdx in [#5764](https://github.com/jdx/mise/pull/5764)\n\n### 📦️ Dependency Updates\n\n- update fedora docker tag to v43 by @renovate[bot] in [#5159](https://github.com/jdx/mise/pull/5159)\n\n### Chore\n\n- **(copr)** chmod +x by @jdx in [71cf6ee](https://github.com/jdx/mise/commit/71cf6eee0d1766bbc214c6cf307b3d7ae300cd33)\n- **(hyperfine)** temporarily remove uncached benchmarks since they are not reporting right by @jdx in [#5769](https://github.com/jdx/mise/pull/5769)\n- added `mise` shim for devcontainer by @jdx in [#5768](https://github.com/jdx/mise/pull/5768)\n\n### Task-configuration.md\n\n- typo by @mustafa0x in [#5216](https://github.com/jdx/mise/pull/5216)\n\n### New Contributors\n\n- @mustafa0x made their first contribution in [#5216](https://github.com/jdx/mise/pull/5216)\n- @juxuanu made their first contribution in [#5758](https://github.com/jdx/mise/pull/5758)\n\n## [2025.7.21](https://github.com/jdx/mise/compare/v2025.7.20..v2025.7.21) - 2025-07-23\n\n### 🚀 Features\n\n- **(packaging)** add COPR publishing workflow and documentation by @jdx in [#5719](https://github.com/jdx/mise/pull/5719)\n\n### 🐛 Bug Fixes\n\n- **(pwsh)** resolve issue caused by previous #5732 patch (hardcoded path) by @IMXEren in [#5753](https://github.com/jdx/mise/pull/5753)\n- copr docker building by @jdx in [#5748](https://github.com/jdx/mise/pull/5748)\n\n### 📚 Documentation\n\n- **(README)** mention project alexandria by @jdx in [681bc75](https://github.com/jdx/mise/commit/681bc751025a848411b7dff322cd14d9487dd59f)\n- Removes invalid array in redaction example by @EverlastingBugstopper in [#5752](https://github.com/jdx/mise/pull/5752)\n- document mise-versions app by @jdx in [785ef24](https://github.com/jdx/mise/commit/785ef24e65259b95f56ecccebe9463a8a0c37519)\n\n### 🧪 Testing\n\n- fix asset detector test on musl by @jdx in [#5744](https://github.com/jdx/mise/pull/5744)\n\n### Chore\n\n- use 302 redirects for curl installs by @jdx in [#5747](https://github.com/jdx/mise/pull/5747)\n\n### New Contributors\n\n- @EverlastingBugstopper made their first contribution in [#5752](https://github.com/jdx/mise/pull/5752)\n\n## [2025.7.20](https://github.com/jdx/mise/compare/v2025.7.19..v2025.7.20) - 2025-07-22\n\n### 🚀 Features\n\n- use mise.run for rosetta tip by @jdx in [#5739](https://github.com/jdx/mise/pull/5739)\n\n### 🐛 Bug Fixes\n\n- **(npm)** use bin/ as bin_paths when installed with bun on windows by @risu729 in [#5725](https://github.com/jdx/mise/pull/5725)\n\n### 📚 Documentation\n\n- remove curl instructions by @jdx in [785d2f2](https://github.com/jdx/mise/commit/785d2f2fe4795b23cb196a70a0b7956707d40437)\n- add back in supported os/arch combinations by @jdx in [87b86b0](https://github.com/jdx/mise/commit/87b86b0f4f756dd6b7116192214c25e2995e9939)\n\n### Chore\n\n- set redirect for curl installs by @jdx in [#5740](https://github.com/jdx/mise/pull/5740)\n- reduce binary size for linux by @jdx in [#5741](https://github.com/jdx/mise/pull/5741)\n\n## [2025.7.19](https://github.com/jdx/mise/compare/v2025.7.18..v2025.7.19) - 2025-07-22\n\n### 🐛 Bug Fixes\n\n- **(pwsh)** set console encoding to UTF-8 to prevent Unicode garbling by @IMXEren in [#5732](https://github.com/jdx/mise/pull/5732)\n- **(registry)** set matching_regex for glab on Windows to pick the correct asset by @risu729 in [#5727](https://github.com/jdx/mise/pull/5727)\n\n### 📚 Documentation\n\n- **(config)** fix alias section name by @malept in [#5736](https://github.com/jdx/mise/pull/5736)\n- fix typo in contributing commit message prefixes by @malept in [#5737](https://github.com/jdx/mise/pull/5737)\n\n### Chore\n\n- **(ppa)** wait for gh rate limit by @jdx in [#5721](https://github.com/jdx/mise/pull/5721)\n- **(vfox-test)** set GITHUB_TOKEN by @jdx in [cdbb62b](https://github.com/jdx/mise/commit/cdbb62b0f63bcb0a3b650c1d49aefb8c9798c6aa)\n\n### New Contributors\n\n- @malept made their first contribution in [#5736](https://github.com/jdx/mise/pull/5736)\n\n## [2025.7.18](https://github.com/jdx/mise/compare/v2025.7.17..v2025.7.18) - 2025-07-21\n\n### 🚀 Features\n\n- **(registry)** add `jsonschema` CLI tool by @mrazauskas in [#5714](https://github.com/jdx/mise/pull/5714)\n\n### 🐛 Bug Fixes\n\n- mise up parallel execution by @jdx in [#5591](https://github.com/jdx/mise/pull/5591)\n- ppa releases by @jdx in [#5717](https://github.com/jdx/mise/pull/5717)\n\n### 📚 Documentation\n\n- add comprehensive CLAUDE.md for Claude Code guidance by @jdx in [#5718](https://github.com/jdx/mise/pull/5718)\n\n### Chore\n\n- ubuntu ppa by @jdx in [#5715](https://github.com/jdx/mise/pull/5715)\n\n## [2025.7.17](https://github.com/jdx/mise/compare/v2025.7.16..v2025.7.17) - 2025-07-19\n\n### 🚀 Features\n\n- consolidate lockfile assets and add URL tracking by @jdx in [#5629](https://github.com/jdx/mise/pull/5629)\n\n### 🐛 Bug Fixes\n\n- **(registry)** use aqua backend for available tools by @risu729 in [#5707](https://github.com/jdx/mise/pull/5707)\n\n### 📚 Documentation\n\n- document auto_install behavior by @jdx in [#5697](https://github.com/jdx/mise/pull/5697)\n\n### 🧪 Testing\n\n- **(registry)** enable disabled tests by @risu729 in [#5708](https://github.com/jdx/mise/pull/5708)\n- **(registry)** comment out failing maven test in configuration by @jdx in [ae3e62b](https://github.com/jdx/mise/commit/ae3e62b232ab974058cf7b7c7a05d05086f48e48)\n\n## [2025.7.16](https://github.com/jdx/mise/compare/v2025.7.15..v2025.7.16) - 2025-07-18\n\n### 🐛 Bug Fixes\n\n- mise.run cloudflare worker publish by @jdx in [#5704](https://github.com/jdx/mise/pull/5704)\n\n### Chore\n\n- **(release)** increase timeout for macos tarballs by @jdx in [05e3a45](https://github.com/jdx/mise/commit/05e3a459982745f365d958501492430effab1fc0)\n- disable tests for 2025.7.16 by @jdx in [30d3b97](https://github.com/jdx/mise/commit/30d3b974dc3893158c10bfac500ac671407214b3)\n\n## [2025.7.15](https://github.com/jdx/mise/compare/v2025.7.14..v2025.7.15) - 2025-07-18\n\n### 🧪 Testing\n\n- added .release-skip-e2e functionality by @jdx in [#5698](https://github.com/jdx/mise/pull/5698)\n\n## [2025.7.14](https://github.com/jdx/mise/compare/v2025.7.13..v2025.7.14) - 2025-07-18\n\n### 🐛 Bug Fixes\n\n- mise.run cloudflare worker syntax by @jdx in [#5693](https://github.com/jdx/mise/pull/5693)\n\n### 📦️ Dependency Updates\n\n- update rust crate tabled to 0.20 by @renovate[bot] in [#5688](https://github.com/jdx/mise/pull/5688)\n- update rust crate indicatif to 0.18 by @renovate[bot] in [#5687](https://github.com/jdx/mise/pull/5687)\n\n## [2025.7.13](https://github.com/jdx/mise/compare/v2025.7.12..v2025.7.13) - 2025-07-18\n\n### 🚀 Features\n\n- https://mise.run/{bash,zsh,fish} by @jdx in [#5677](https://github.com/jdx/mise/pull/5677)\n- add opencode tool with description, backends, and test command by @nipuna-perera in [#5679](https://github.com/jdx/mise/pull/5679)\n\n### 🐛 Bug Fixes\n\n- don't follow symlink to ignore symlinks from deletion by @risu729 in [#5672](https://github.com/jdx/mise/pull/5672)\n- update completions by @risu729 in [#5682](https://github.com/jdx/mise/pull/5682)\n- NoMethodError with Bundler::Installer by @hsbt in [#5678](https://github.com/jdx/mise/pull/5678)\n\n### 📚 Documentation\n\n- fix typo in RUSTUP_TOOLCHAIN env variable name by @anderso in [#5673](https://github.com/jdx/mise/pull/5673)\n\n### 📦️ Dependency Updates\n\n- update jdx/mise-action digest to bfb9fa0 by @renovate[bot] in [#5681](https://github.com/jdx/mise/pull/5681)\n- pin dependencies by @renovate[bot] in [#5680](https://github.com/jdx/mise/pull/5680)\n- update rust crate console to 0.16 by @renovate[bot] in [#5685](https://github.com/jdx/mise/pull/5685)\n- update taiki-e/install-action digest to 4fd6bde by @renovate[bot] in [#5684](https://github.com/jdx/mise/pull/5684)\n\n### New Contributors\n\n- @nipuna-perera made their first contribution in [#5679](https://github.com/jdx/mise/pull/5679)\n- @hsbt made their first contribution in [#5678](https://github.com/jdx/mise/pull/5678)\n- @anderso made their first contribution in [#5673](https://github.com/jdx/mise/pull/5673)\n\n## [2025.7.12](https://github.com/jdx/mise/compare/v2025.7.11..v2025.7.12) - 2025-07-17\n\n### 🐛 Bug Fixes\n\n- **(file)** remove top level directories in strip_archive_path_components by @risu729 in [#5662](https://github.com/jdx/mise/pull/5662)\n- **(npm)** run bun in install_path instead of using --cwd flag of bun by @risu729 in [#5656](https://github.com/jdx/mise/pull/5656)\n- **(nushell)** fix `get -i` deprecation by @JoaquinTrinanes in [#5666](https://github.com/jdx/mise/pull/5666)\n\n### ◀️ Revert\n\n- Revert \"fix(aqua): improve warnings for packages without repo_owner and repo_name \" by @jdx in [#5668](https://github.com/jdx/mise/pull/5668)\n\n### Chore\n\n- update deps by @risu729 in [#5657](https://github.com/jdx/mise/pull/5657)\n- update usage by @risu729 in [#5661](https://github.com/jdx/mise/pull/5661)\n\n### New Contributors\n\n- @JoaquinTrinanes made their first contribution in [#5666](https://github.com/jdx/mise/pull/5666)\n\n## [2025.7.11](https://github.com/jdx/mise/compare/v2025.7.10..v2025.7.11) - 2025-07-16\n\n### 🚀 Features\n\n- support extracting 7z archives for static backends by @yjoer in [#5632](https://github.com/jdx/mise/pull/5632)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** improve warnings for packages without repo_owner and repo_name by @risu729 in [#5644](https://github.com/jdx/mise/pull/5644)\n- **(generate)** fix task docs inject by @risu729 in [#5651](https://github.com/jdx/mise/pull/5651)\n- **(static)** support `strip_components` for zip files by @risu729 in [#5631](https://github.com/jdx/mise/pull/5631)\n- private forges by @hamnis in [#5650](https://github.com/jdx/mise/pull/5650)\n\n### 🚜 Refactor\n\n- **(aqua)** move no_aset and error_message checks into validate by @risu729 in [#5649](https://github.com/jdx/mise/pull/5649)\n\n### 📚 Documentation\n\n- **(vfox)** replace deprecated asdf and vfox settings with disable_backends by @risu729 in [#5652](https://github.com/jdx/mise/pull/5652)\n- tweak static backend docs by @jdx in [#5627](https://github.com/jdx/mise/pull/5627)\n\n### 🧪 Testing\n\n- **(e2e)** move test_github_auto_detect to correct directory by @risu729 in [#5640](https://github.com/jdx/mise/pull/5640)\n\n### New Contributors\n\n- @hamnis made their first contribution in [#5650](https://github.com/jdx/mise/pull/5650)\n\n## [2025.7.10](https://github.com/jdx/mise/compare/v2025.7.9..v2025.7.10) - 2025-07-14\n\n### 🐛 Bug Fixes\n\n- **(backend)** avoid double untar by @jdx in [#5626](https://github.com/jdx/mise/pull/5626)\n- **(github)** handle missing \"v\" prefix by @jdx in [#5625](https://github.com/jdx/mise/pull/5625)\n\n### 📚 Documentation\n\n- add asset autodetection documentation to GitHub/GitLab backends by @jdx in [#5623](https://github.com/jdx/mise/pull/5623)\n\n## [2025.7.9](https://github.com/jdx/mise/compare/v2025.7.8..v2025.7.9) - 2025-07-14\n\n### 🚀 Features\n\n- **(shim)** prevent mise-specific flags from interfering with shim execution by @jdx in [#5616](https://github.com/jdx/mise/pull/5616)\n- github asset auto-detection by @jdx in [#5622](https://github.com/jdx/mise/pull/5622)\n\n### 🐛 Bug Fixes\n\n- resolve GitHub alias tool name parsing and add platform-specific asset support by @jdx in [#5621](https://github.com/jdx/mise/pull/5621)\n\n## [2025.7.8](https://github.com/jdx/mise/compare/v2025.7.7..v2025.7.8) - 2025-07-13\n\n### 🚀 Features\n\n- custom backends through plugins by @jdx in [#5579](https://github.com/jdx/mise/pull/5579)\n- nested tool options by @jdx in [#5614](https://github.com/jdx/mise/pull/5614)\n\n### 🐛 Bug Fixes\n\n- accept platform_ or platforms_ in http/github backends by @jdx in [#5608](https://github.com/jdx/mise/pull/5608)\n\n### 📚 Documentation\n\n- correct toml syntax by @jdx in [#5609](https://github.com/jdx/mise/pull/5609)\n- removed some markdownlint rules by @jdx in [#5615](https://github.com/jdx/mise/pull/5615)\n\n## [2025.7.7](https://github.com/jdx/mise/compare/v2025.7.4..v2025.7.7) - 2025-07-13\n\n### 🚀 Features\n\n- add static backends (Github, GitLab, and HTTP) by @jdx in [#5602](https://github.com/jdx/mise/pull/5602)\n- blake3 support by @jdx in [#5605](https://github.com/jdx/mise/pull/5605)\n\n### 🐛 Bug Fixes\n\n- **(e2e)** simplify test path handling logic by @jdx in [#5600](https://github.com/jdx/mise/pull/5600)\n- skip gh release edit on dry run in release workflow by @jdx in [#5603](https://github.com/jdx/mise/pull/5603)\n\n### 📚 Documentation\n\n- **(cursor)** fix conventional commits rule formatting by @jdx in [#5597](https://github.com/jdx/mise/pull/5597)\n- **(cursor)** add testing rule for mise codebase by @jdx in [#5598](https://github.com/jdx/mise/pull/5598)\n\n### 🧪 Testing\n\n- disable cmake test for now by @jdx in [d521c31](https://github.com/jdx/mise/commit/d521c31eff1675cd18333c5c258b5d41110fc81a)\n\n### 📦️ Dependency Updates\n\n- pin dependencies by @renovate[bot] in [#5511](https://github.com/jdx/mise/pull/5511)\n\n### Chore\n\n- **(release)** mark a release as draft until assets are added by @risu729 in [#5584](https://github.com/jdx/mise/pull/5584)\n- added reverts to git-cliff by @jdx in [#5577](https://github.com/jdx/mise/pull/5577)\n- reduce binary size for linux by @jdx in [#5587](https://github.com/jdx/mise/pull/5587)\n- `cargo check` fixes by @jdx in [#5589](https://github.com/jdx/mise/pull/5589)\n- Merge vfox.rs into jdx/mise monorepo by @jdx in [#5590](https://github.com/jdx/mise/pull/5590)\n- Add cursor rule for conventional commits by @jdx in [#5592](https://github.com/jdx/mise/pull/5592)\n- Create GitHub action for vfox.rs tests by @jdx in [#5593](https://github.com/jdx/mise/pull/5593)\n- tweak paths for test-vfox workflow by @jdx in [0189372](https://github.com/jdx/mise/commit/0189372aadad456cdac459317bb96ae3987cfd15)\n- set workspace resolver by @jdx in [#5606](https://github.com/jdx/mise/pull/5606)\n- add workspace resolver = 3 by @jdx in [304547a](https://github.com/jdx/mise/commit/304547a0b9a324b5d925c45e2841cadc3f6e938b)\n- fix release-plz with workspace by @jdx in [5b3be6e](https://github.com/jdx/mise/commit/5b3be6eb8f06c509964a2b030eccb2f6e006f398)\n- only bump mise version for release-plz by @jdx in [8f14d10](https://github.com/jdx/mise/commit/8f14d1014d217c91c36a96beaad4565a3aaf567e)\n- add cargo-release by @jdx in [f657db5](https://github.com/jdx/mise/commit/f657db512fdb7ea4f58ac98af729ac6495e61100)\n- mise up by @jdx in [4872ae6](https://github.com/jdx/mise/commit/4872ae6b4d63de54de4ac93e72e9a3cd51e20c2e)\n- fix release-plz with workspace by @jdx in [bdb7119](https://github.com/jdx/mise/commit/bdb71196d6930091c68a6198d445fa16e108f75e)\n- set-version by @jdx in [82fcd4f](https://github.com/jdx/mise/commit/82fcd4f22116bb92e1e615d9f1c03723d02aaaba)\n- set-version by @jdx in [54388a4](https://github.com/jdx/mise/commit/54388a419427c664e557aa4ea034e13a2443bb8e)\n- set-version by @jdx in [fe0a0a9](https://github.com/jdx/mise/commit/fe0a0a93b27219bd132b39f1f0b522bed1ad2b51)\n- set-version by @jdx in [d9f24e2](https://github.com/jdx/mise/commit/d9f24e2b45fb7a9f5c2b795b490ba64a8d9eb207)\n- set-version by @jdx in [97f6f4f](https://github.com/jdx/mise/commit/97f6f4febaf03f7c0d6d754701308edeb2287b53)\n- set-version by @jdx in [13296e1](https://github.com/jdx/mise/commit/13296e10947ea5a96768e07bd95d009e95bace32)\n- set-version by @jdx in [587a707](https://github.com/jdx/mise/commit/587a70744c4127f92cfe9381e7e273ac101c4a4f)\n- set-version by @jdx in [1e80d52](https://github.com/jdx/mise/commit/1e80d52144144aaebc804aeef17010980f3a0caf)\n\n## [2025.7.4](https://github.com/jdx/mise/compare/v2025.7.3..v2025.7.4) - 2025-07-11\n\n### 🐛 Bug Fixes\n\n- **(aqua)** align version resolution logic in list_bin_paths by @risu729 in [#5562](https://github.com/jdx/mise/pull/5562)\n- Xonsh integration by @jfmontanaro in [#5557](https://github.com/jdx/mise/pull/5557)\n\n### 📚 Documentation\n\n- create comprehensive architecture documentation suite and enhance development guides by @jdx in [d2b4a05](https://github.com/jdx/mise/commit/d2b4a050261b685279c502009f55a3e260b72ff9)\n\n### ◀️ Revert\n\n- Revert \"fix(aqua): align version resolution logic in list_bin_paths\" by @jdx in [#5574](https://github.com/jdx/mise/pull/5574)\n\n### 📦️ Dependency Updates\n\n- update rust crate bzip2 to 0.6 by @renovate[bot] in [#5568](https://github.com/jdx/mise/pull/5568)\n- update rust crate clap_mangen to v0.2.28 by @renovate[bot] in [#5566](https://github.com/jdx/mise/pull/5566)\n- update rust crate clap to v4.5.41 by @renovate[bot] in [#5565](https://github.com/jdx/mise/pull/5565)\n- update rust crate taplo to 0.14 by @renovate[bot] in [#5158](https://github.com/jdx/mise/pull/5158)\n\n### Chore\n\n- added xonsh for release builds by @jdx in [#5561](https://github.com/jdx/mise/pull/5561)\n- enable backtrace lines on panic by @jdx in [#5571](https://github.com/jdx/mise/pull/5571)\n- shfmt update by @jdx in [67ee245](https://github.com/jdx/mise/commit/67ee24556f1533c508e422513399ae04ecf6bdaa)\n\n### New Contributors\n\n- @jfmontanaro made their first contribution in [#5557](https://github.com/jdx/mise/pull/5557)\n\n## [2025.7.3](https://github.com/jdx/mise/compare/v2025.7.2..v2025.7.3) - 2025-07-10\n\n### 🚀 Features\n\n- **(registry)** add vfox by @risu729 in [#5551](https://github.com/jdx/mise/pull/5551)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** show other backends suggestion for unsupported package types by @risu729 in [#5547](https://github.com/jdx/mise/pull/5547)\n- **(registry)** use aqua and fix ubi options for yamlscript by @risu729 in [#5538](https://github.com/jdx/mise/pull/5538)\n- **(registry)** add java and yq to android-sdk dependencies by @risu729 in [#5545](https://github.com/jdx/mise/pull/5545)\n- **(schema)** broken $schema ref by @tpansino in [#5540](https://github.com/jdx/mise/pull/5540)\n- auto_install_disable_tools env var by @jdx in [#5543](https://github.com/jdx/mise/pull/5543)\n- do not overwrite github tokens environment variables by @risu729 in [#5546](https://github.com/jdx/mise/pull/5546)\n\n### Chore\n\n- update Cargo.lock by @risu729 in [#5549](https://github.com/jdx/mise/pull/5549)\n\n### New Contributors\n\n- @tpansino made their first contribution in [#5540](https://github.com/jdx/mise/pull/5540)\n\n## [2025.7.2](https://github.com/jdx/mise/compare/v2025.7.1..v2025.7.2) - 2025-07-09\n\n### 🚀 Features\n\n- **(registry)** add zizmor by @risu729 in [#5519](https://github.com/jdx/mise/pull/5519)\n- Add `self_update_available` to `mise doctor` output by @joehorsnell in [#5534](https://github.com/jdx/mise/pull/5534)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** use the version in url to verify and install by @risu729 in [#5537](https://github.com/jdx/mise/pull/5537)\n- **(registry)** use aqua for numbat, gokey, golines by @risu729 in [#5518](https://github.com/jdx/mise/pull/5518)\n- `self-update` on MITM firewall (attempt #2) by @joehorsnell in [#5459](https://github.com/jdx/mise/pull/5459)\n- mise panic in removed directory by @roele in [#5532](https://github.com/jdx/mise/pull/5532)\n\n### 📚 Documentation\n\n- update ubi tag_regex syntax by @grimm26 in [#5529](https://github.com/jdx/mise/pull/5529)\n\n### 🧪 Testing\n\n- disable yamlscript test by @jdx in [#5536](https://github.com/jdx/mise/pull/5536)\n\n### New Contributors\n\n- @grimm26 made their first contribution in [#5529](https://github.com/jdx/mise/pull/5529)\n\n## [2025.7.1](https://github.com/jdx/mise/compare/v2025.7.0..v2025.7.1) - 2025-07-06\n\n### 🚀 Features\n\n- **(aqua)** add support for zst compressed assets by @andreabedini in [#5495](https://github.com/jdx/mise/pull/5495)\n- **(registry)** import package descriptions from aqua and add os specifier for tuist by @matracey in [#5487](https://github.com/jdx/mise/pull/5487)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** handle hard links in aqua packages (attempt #2) by @risu729 in [#5486](https://github.com/jdx/mise/pull/5486)\n- **(aqua)** apply correct `version_override` by @risu729 in [#5474](https://github.com/jdx/mise/pull/5474)\n- **(erlang)** fix install_precompiled method signature for unsupported os by @roele in [#5503](https://github.com/jdx/mise/pull/5503)\n- **(java)** relax version filter regex for JetBrains builds by @roele in [#5508](https://github.com/jdx/mise/pull/5508)\n- **(registry)** use aqua backend for bat by @risu729 in [#5490](https://github.com/jdx/mise/pull/5490)\n- **(registry)** use pipx backend for aws-sam on windows by @risu729 in [#5491](https://github.com/jdx/mise/pull/5491)\n- enhance self-update for musl targets by @roele in [#5502](https://github.com/jdx/mise/pull/5502)\n- include arch and os settings in cache keys by @risu729 in [#5504](https://github.com/jdx/mise/pull/5504)\n\n### 🧪 Testing\n\n- **(registry)** enable youtube-dl test by @risu729 in [#5492](https://github.com/jdx/mise/pull/5492)\n\n### 📦️ Dependency Updates\n\n- update swatinem/rust-cache digest to 98c8021 by @renovate[bot] in [#5512](https://github.com/jdx/mise/pull/5512)\n\n### New Contributors\n\n- @matracey made their first contribution in [#5487](https://github.com/jdx/mise/pull/5487)\n- @andreabedini made their first contribution in [#5495](https://github.com/jdx/mise/pull/5495)\n\n## [2025.7.0](https://github.com/jdx/mise/compare/v2025.6.8..v2025.7.0) - 2025-07-01\n\n### 🚀 Features\n\n- **(registry)** adds gemini-cli by @risu729 in [#5447](https://github.com/jdx/mise/pull/5447)\n- **(registry)** adds npm backended tools by @risu729 in [#5446](https://github.com/jdx/mise/pull/5446)\n- **(registry)** add powershell alias by @risu729 in [#5449](https://github.com/jdx/mise/pull/5449)\n- **(registry)** add dagu by @yottahmd in [#5476](https://github.com/jdx/mise/pull/5476)\n- **(registry)** update aws-sam backends to include aqua source by @yashikota in [#5461](https://github.com/jdx/mise/pull/5461)\n- **(registry)** use ubi backend for youtube-dl nightly releases by @risu729 in [#5466](https://github.com/jdx/mise/pull/5466)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** update victoria-metrics package name casing by @shikharbhardwaj in [#5483](https://github.com/jdx/mise/pull/5483)\n- **(aqua)** handle hard links in aqua packages by @risu729 in [#5463](https://github.com/jdx/mise/pull/5463)\n- **(bun)** enhance architecture detection for musl targets by @roele in [#5450](https://github.com/jdx/mise/pull/5450)\n- **(erlang)** use precompiled ubuntu binaries on GHA by @paradox460 in [#5439](https://github.com/jdx/mise/pull/5439)\n- **(erlang)** add `install_precompiled` for unsupported os by @risu729 in [#5479](https://github.com/jdx/mise/pull/5479)\n- **(registry)** use aqua backend for cargo-make by @risu729 in [#5465](https://github.com/jdx/mise/pull/5465)\n- **(registry)** use aqua backends for all available tools by @risu729 in [#5467](https://github.com/jdx/mise/pull/5467)\n- `parse_command` passing `-c` flag to cmd.exe by @IMXEren in [#5441](https://github.com/jdx/mise/pull/5441)\n\n### 🧪 Testing\n\n- **(registry)** disable bitwarden test by @risu729 in [#5468](https://github.com/jdx/mise/pull/5468)\n\n### ◀️ Revert\n\n- Revert \"chore(deps): pin dependencies\" by @jdx in [#5453](https://github.com/jdx/mise/pull/5453)\n- Revert \"fix(aqua): handle hard links in aqua packages\" by @jdx in [#5485](https://github.com/jdx/mise/pull/5485)\n\n### 📦️ Dependency Updates\n\n- pin dependencies by @renovate[bot] in [#5443](https://github.com/jdx/mise/pull/5443)\n- update jdx/mise-action digest to 5cb1df6 by @renovate[bot] in [#5444](https://github.com/jdx/mise/pull/5444)\n\n### Chore\n\n- disable automatic cargo up due to windows build failure in homedir crate by @jdx in [7570d0a](https://github.com/jdx/mise/commit/7570d0a95498d7b5626645fe3065429e19d0b26e)\n\n### Ci\n\n- **(test)** run `apt-get update` before `apt-get install` by @risu729 in [#5448](https://github.com/jdx/mise/pull/5448)\n\n### New Contributors\n\n- @yashikota made their first contribution in [#5461](https://github.com/jdx/mise/pull/5461)\n- @yottahmd made their first contribution in [#5476](https://github.com/jdx/mise/pull/5476)\n- @IMXEren made their first contribution in [#5441](https://github.com/jdx/mise/pull/5441)\n\n## [2025.6.8](https://github.com/jdx/mise/compare/v2025.6.7..v2025.6.8) - 2025-06-26\n\n### 🚀 Features\n\n- **(java)** add support for tar.xz in Java core plugin to support RedHat JDKs by @roele in [#5354](https://github.com/jdx/mise/pull/5354)\n- **(registry)** add osv-scanner by @scop in [#5413](https://github.com/jdx/mise/pull/5413)\n- **(registry)** add scorecard by @scop in [#5410](https://github.com/jdx/mise/pull/5410)\n- **(registry)** add docker cli by @acesyde in [#5344](https://github.com/jdx/mise/pull/5344)\n- **(registry)** add claude code by @lelouvincx in [#5420](https://github.com/jdx/mise/pull/5420)\n- **(registry)** add aws `cfn-lint` by @garysassano in [#5434](https://github.com/jdx/mise/pull/5434)\n- added graphite by @jdx in [#5429](https://github.com/jdx/mise/pull/5429)\n\n### 🐛 Bug Fixes\n\n- **(erlang)** use precompiled binaries for linux ubuntu by @paradox460 in [#5402](https://github.com/jdx/mise/pull/5402)\n- **(ubi)** checksum generation might fail if extract_all option is used by @roele in [#5394](https://github.com/jdx/mise/pull/5394)\n- `self-update` on MITM firewall by @joehorsnell in [#5387](https://github.com/jdx/mise/pull/5387)\n- lint warning by @jdx in [#5425](https://github.com/jdx/mise/pull/5425)\n- only warn on toolset resolve errors by @jdx in [#5435](https://github.com/jdx/mise/pull/5435)\n\n### 🚜 Refactor\n\n- **(registry)** use pipx for semgrep by @scop in [#5423](https://github.com/jdx/mise/pull/5423)\n- **(registry)** add backends and tests by @risu729 in [#5388](https://github.com/jdx/mise/pull/5388)\n\n### ◀️ Revert\n\n- Revert \"fix: `self-update` on MITM firewall\" by @jdx in [#5427](https://github.com/jdx/mise/pull/5427)\n\n### Ci\n\n- unpin hyperfine by @risu729 in [#5411](https://github.com/jdx/mise/pull/5411)\n\n### New Contributors\n\n- @paradox460 made their first contribution in [#5402](https://github.com/jdx/mise/pull/5402)\n- @lelouvincx made their first contribution in [#5420](https://github.com/jdx/mise/pull/5420)\n\n## [2025.6.7](https://github.com/jdx/mise/compare/v2025.6.6..v2025.6.7) - 2025-06-23\n\n### 🐛 Bug Fixes\n\n- **(aqua)** fix versions order by @risu729 in [#5406](https://github.com/jdx/mise/pull/5406)\n\n### Ci\n\n- use pinnable tag of taiki-e/install-action by @risu729 in [#5405](https://github.com/jdx/mise/pull/5405)\n\n## [2025.6.6](https://github.com/jdx/mise/compare/v2025.6.5..v2025.6.6) - 2025-06-23\n\n### 🚀 Features\n\n- **(registry)** add wash by @jtakakura in [#5386](https://github.com/jdx/mise/pull/5386)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** parse consecutive pipes in aqua templates by @risu729 in [#5385](https://github.com/jdx/mise/pull/5385)\n- **(aqua)** use versions list to install correct version by @risu729 in [#5371](https://github.com/jdx/mise/pull/5371)\n- **(registry)** talosctl use aqua by @mangkoran in [#5348](https://github.com/jdx/mise/pull/5348)\n- **(registry)** use aqua backend for watchexec by @risu729 in [#5390](https://github.com/jdx/mise/pull/5390)\n- **(shim)** improve resolve_symlink for Windows by @qianlongzt in [#5361](https://github.com/jdx/mise/pull/5361)\n- add compression-zip-deflate feature on self_update crate for windows target by @roele in [#5391](https://github.com/jdx/mise/pull/5391)\n- suppress hint on 'cargo search mise' command by @roele in [#5400](https://github.com/jdx/mise/pull/5400)\n\n### 📚 Documentation\n\n- Fix typo in README.md - Install mise by @cytsai1008 in [#5366](https://github.com/jdx/mise/pull/5366)\n- Document trivial task syntax by @JayBazuzi in [#5352](https://github.com/jdx/mise/pull/5352)\n\n### 🧪 Testing\n\n- **(registry)** fix vultr test by @risu729 in [#5372](https://github.com/jdx/mise/pull/5372)\n\n### 📦️ Dependency Updates\n\n- update autofix-ci/action action to v1.3.2 by @renovate[bot] in [#5377](https://github.com/jdx/mise/pull/5377)\n- update docker/setup-buildx-action digest to e468171 by @renovate[bot] in [#5376](https://github.com/jdx/mise/pull/5376)\n\n### Chore\n\n- update expr-lang crate to v0.3.2 by @risu729 in [#5364](https://github.com/jdx/mise/pull/5364)\n- show curl error by @jdx in [729aa4a](https://github.com/jdx/mise/commit/729aa4a6279cbb8dd8b1d81e8726d252ad2ad2bc)\n- fix latest version fetch by @jdx in [729aadc](https://github.com/jdx/mise/commit/729aadc83e042b276e3ebd3ae378a7e647a54bc0)\n- update vfox.rs crate to v1.0.3 by @risu729 in [#5393](https://github.com/jdx/mise/pull/5393)\n- updated deps by @jdx in [#5403](https://github.com/jdx/mise/pull/5403)\n\n### Ci\n\n- use cargo info to retrieve latest mise version by @risu729 in [#5401](https://github.com/jdx/mise/pull/5401)\n\n### New Contributors\n\n- @jtakakura made their first contribution in [#5386](https://github.com/jdx/mise/pull/5386)\n- @JayBazuzi made their first contribution in [#5352](https://github.com/jdx/mise/pull/5352)\n- @cytsai1008 made their first contribution in [#5366](https://github.com/jdx/mise/pull/5366)\n\n## [2025.6.5](https://github.com/jdx/mise/compare/v2025.6.4..v2025.6.5) - 2025-06-16\n\n### 🚀 Features\n\n- **(registry)** add diffoci by @mangkoran in [#5350](https://github.com/jdx/mise/pull/5350)\n\n### 🐛 Bug Fixes\n\n- **(registry)** use mintoolkit/mint for docker-slim by @risu729 in [#5351](https://github.com/jdx/mise/pull/5351)\n- **(schema)** add missing tool options to schema by @risu729 in [#5356](https://github.com/jdx/mise/pull/5356)\n- only show deprecation if not using 'tools-version' by @timfallmk in [#5290](https://github.com/jdx/mise/pull/5290)\n\n### New Contributors\n\n- @timfallmk made their first contribution in [#5290](https://github.com/jdx/mise/pull/5290)\n\n## [2025.6.4](https://github.com/jdx/mise/compare/v2025.6.3..v2025.6.4) - 2025-06-13\n\n### 🐛 Bug Fixes\n\n- **(registry)** use aqua for checkov by @risu729 in [#5343](https://github.com/jdx/mise/pull/5343)\n\n### ◀️ Revert\n\n- fix(aqua): parse templates in version_filter by @risu729 in [#5345](https://github.com/jdx/mise/pull/5345)\n\n## [2025.6.3](https://github.com/jdx/mise/compare/v2025.6.2..v2025.6.3) - 2025-06-13\n\n### 🚀 Features\n\n- support matching_regex from the ubi backend by @yjoer in [#5320](https://github.com/jdx/mise/pull/5320)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** parse templates in version_filter by @risu729 in [#5341](https://github.com/jdx/mise/pull/5341)\n- **(registry)** use extract_all for docker-slim by @risu729 in [#5342](https://github.com/jdx/mise/pull/5342)\n\n### 🚜 Refactor\n\n- **(getting-started)** update powershell profile instructions by @Armaldio in [#5340](https://github.com/jdx/mise/pull/5340)\n\n### 📦️ Dependency Updates\n\n- update docker/build-push-action digest to 2634353 by @renovate[bot] in [#5338](https://github.com/jdx/mise/pull/5338)\n- update jdx/mise-action digest to 13abe50 by @renovate[bot] in [#5339](https://github.com/jdx/mise/pull/5339)\n\n### New Contributors\n\n- @yjoer made their first contribution in [#5320](https://github.com/jdx/mise/pull/5320)\n\n## [2025.6.2](https://github.com/jdx/mise/compare/v2025.6.1..v2025.6.2) - 2025-06-12\n\n### 🚀 Features\n\n- **(aqua)** support cosign bundle option by @risu729 in [#5314](https://github.com/jdx/mise/pull/5314)\n- **(registry)** add xcodes by @MontakOleg in [#5321](https://github.com/jdx/mise/pull/5321)\n- **(registry)** add typstyle by @3w36zj6 in [#5319](https://github.com/jdx/mise/pull/5319)\n\n### 🐛 Bug Fixes\n\n- **(cli/doctor)** reduce severity of new version to warnings by @risu729 in [#5317](https://github.com/jdx/mise/pull/5317)\n- **(doctor)** ignored config roots not displaying by @jdx in [#5336](https://github.com/jdx/mise/pull/5336)\n- ls command does not respect MISE_COLOR value by @roele in [#5322](https://github.com/jdx/mise/pull/5322)\n\n### 📚 Documentation\n\n- Update contributing.md by @GitToby in [#5332](https://github.com/jdx/mise/pull/5332)\n- add instructions to create/open pwsh profile file by @Armaldio in [#5316](https://github.com/jdx/mise/pull/5316)\n\n### New Contributors\n\n- @Armaldio made their first contribution in [#5316](https://github.com/jdx/mise/pull/5316)\n- @GitToby made their first contribution in [#5332](https://github.com/jdx/mise/pull/5332)\n\n## [2025.6.1](https://github.com/jdx/mise/compare/v2025.6.0..v2025.6.1) - 2025-06-09\n\n### 🚀 Features\n\n- **(aqua)** support no_asset and error_message by @risu729 in [#5303](https://github.com/jdx/mise/pull/5303)\n- **(registry)** use ubi backend for func-e by @risu729 in [#5273](https://github.com/jdx/mise/pull/5273)\n\n### 🐛 Bug Fixes\n\n- **(task)** use empty string for the default value of option by @risu729 in [#5309](https://github.com/jdx/mise/pull/5309)\n\n### 📚 Documentation\n\n- **(registry)** fix links of registry by @risu729 in [#5266](https://github.com/jdx/mise/pull/5266)\n- **(registry)** fix links to tools by @risu729 in [#5272](https://github.com/jdx/mise/pull/5272)\n- update example with `pnpm` by @mrazauskas in [#5306](https://github.com/jdx/mise/pull/5306)\n\n### 🧪 Testing\n\n- **(registry)** fix test typos by @risu729 in [#5269](https://github.com/jdx/mise/pull/5269)\n\n### 🛡️ Security\n\n- **(security)** prevent untarring outside expected path by @jdx in [#5279](https://github.com/jdx/mise/pull/5279)\n\n### New Contributors\n\n- @mrazauskas made their first contribution in [#5306](https://github.com/jdx/mise/pull/5306)\n\n## [2025.6.0](https://github.com/jdx/mise/compare/v2025.5.17..v2025.6.0) - 2025-06-02\n\n### 🐛 Bug Fixes\n\n- race condition with uv_venv by @jdx in [#5262](https://github.com/jdx/mise/pull/5262)\n- disable victoria-metrics test by @jdx in [11bda4b](https://github.com/jdx/mise/commit/11bda4bda97bd02f6a8cae2c7f345846769ff776)\n\n## [2025.5.17](https://github.com/jdx/mise/compare/v2025.5.16..v2025.5.17) - 2025-05-31\n\n### 🚀 Features\n\n- add railway cli by @jahands in [#5083](https://github.com/jdx/mise/pull/5083)\n\n### 🐛 Bug Fixes\n\n- **(zig)** exclude mach version from version list by @mangkoran in [#5240](https://github.com/jdx/mise/pull/5240)\n- refresh settings by @jdx in [#5252](https://github.com/jdx/mise/pull/5252)\n\n### ⚡ Performance\n\n- re-enable parallelism for `mise up` by @jdx in [#5249](https://github.com/jdx/mise/pull/5249)\n\n## [2025.5.16](https://github.com/jdx/mise/compare/v2025.5.15..v2025.5.16) - 2025-05-29\n\n### 🐛 Bug Fixes\n\n- ensure config is always wrapped in Result by @jdx in [#5223](https://github.com/jdx/mise/pull/5223)\n\n### ⚡ Performance\n\n- improve init performance by @jdx in [#5231](https://github.com/jdx/mise/pull/5231)\n\n### Chore\n\n- remove hyperfine from main builds by @jdx in [#5226](https://github.com/jdx/mise/pull/5226)\n\n## [2025.5.15](https://github.com/jdx/mise/compare/v2025.5.14..v2025.5.15) - 2025-05-28\n\n### 🚀 Features\n\n- **(registry)** add aqua backend for maven by @ZeroAurora in [#5219](https://github.com/jdx/mise/pull/5219)\n\n### 🐛 Bug Fixes\n\n- **(zig)** **breaking** get tarball url from download index by @mangkoran in [#5182](https://github.com/jdx/mise/pull/5182)\n- **(zig)** get version list from download index by @mangkoran in [#5217](https://github.com/jdx/mise/pull/5217)\n- use a better completion dir for more compatibility by @ken-kuro in [#5207](https://github.com/jdx/mise/pull/5207)\n- set handler for ctrlc on windows shell by @L0RD-ZER0 in [#5209](https://github.com/jdx/mise/pull/5209)\n- prevent go installation failure on go.mod version mismatch by @roele in [#5212](https://github.com/jdx/mise/pull/5212)\n- mise run --cd <dir> not working with latest mise by @roele in [#5221](https://github.com/jdx/mise/pull/5221)\n\n### 📚 Documentation\n\n- update dependencies section in contributing.md by @LuckyWindsck in [#5200](https://github.com/jdx/mise/pull/5200)\n\n### Chore\n\n- disable auto cargo up by @jdx in [3306f6e](https://github.com/jdx/mise/commit/3306f6ef726fe85d71163121497e1d5dd5cd73ca)\n\n### New Contributors\n\n- @L0RD-ZER0 made their first contribution in [#5209](https://github.com/jdx/mise/pull/5209)\n\n## [2025.5.14](https://github.com/jdx/mise/compare/v2025.5.13..v2025.5.14) - 2025-05-26\n\n### 🐛 Bug Fixes\n\n- installing tools with postinstall hooks fails by @roele in [#5191](https://github.com/jdx/mise/pull/5191)\n- prefer offline when executing shims by @jdx in [#5195](https://github.com/jdx/mise/pull/5195)\n- multi-line task output is shown in bold by @roele in [#5197](https://github.com/jdx/mise/pull/5197)\n\n### ⚡ Performance\n\n- improve tool loading performance in async code by @jdx in [#5198](https://github.com/jdx/mise/pull/5198)\n\n## [2025.5.13](https://github.com/jdx/mise/compare/v2025.5.12..v2025.5.13) - 2025-05-26\n\n### 🐛 Bug Fixes\n\n- output was silenced on task fail with keep-order by @artemisart in [#5175](https://github.com/jdx/mise/pull/5175)\n- avoid mapfile to run e2e tests on macOS (bash 3.2) by @artemisart in [#5170](https://github.com/jdx/mise/pull/5170)\n- flaky keep-order e2e test by @artemisart in [#5178](https://github.com/jdx/mise/pull/5178)\n- watch mise.lock for changes by @jdx in [#5184](https://github.com/jdx/mise/pull/5184)\n- remote task dependency does not work by @roele in [#5183](https://github.com/jdx/mise/pull/5183)\n- rayon -> tokio by @jdx in [#5172](https://github.com/jdx/mise/pull/5172)\n- cache results from version host by @jdx in [#5187](https://github.com/jdx/mise/pull/5187)\n- cache results from version host for aqua packages by @jdx in [#5188](https://github.com/jdx/mise/pull/5188)\n\n### 📚 Documentation\n\n- standardize subcommand format to 'u|use' for consistency by @LuckyWindsck in [#5167](https://github.com/jdx/mise/pull/5167)\n- clarify how to enable ideomatic version file reading for ruby by @amkisko in [#5163](https://github.com/jdx/mise/pull/5163)\n\n### 🧪 Testing\n\n- added perf test by @jdx in [#5179](https://github.com/jdx/mise/pull/5179)\n- skip benchmark errors for now by @jdx in [#5186](https://github.com/jdx/mise/pull/5186)\n\n### Chore\n\n- fix clippy issue in xonsh by @jdx in [#5180](https://github.com/jdx/mise/pull/5180)\n- improve shfmt linter by @jdx in [#5181](https://github.com/jdx/mise/pull/5181)\n- cargo up by @jdx in [3ece604](https://github.com/jdx/mise/commit/3ece60479bd8b8e6a00a02b83c0afdd544d95034)\n- fix hyperfine step summary by @jdx in [36ab4a1](https://github.com/jdx/mise/commit/36ab4a12ffed85f07ce918d1a21a6da9f7ebef2c)\n- adjust perf thresholds by @jdx in [4113a3b](https://github.com/jdx/mise/commit/4113a3b82c3fca4eae0dbe7845ec2d513f5b6c8b)\n\n### New Contributors\n\n- @amkisko made their first contribution in [#5163](https://github.com/jdx/mise/pull/5163)\n- @LuckyWindsck made their first contribution in [#5167](https://github.com/jdx/mise/pull/5167)\n\n## [2025.5.12](https://github.com/jdx/mise/compare/v2025.5.11..v2025.5.12) - 2025-05-25\n\n### 🐛 Bug Fixes\n\n- read global/system config file tasks properly by @jdx in [#5169](https://github.com/jdx/mise/pull/5169)\n- typo in time! parallelize_tasks by @artemisart in [#5171](https://github.com/jdx/mise/pull/5171)\n\n### 🧪 Testing\n\n- disable non-working zig test by @jdx in [2ffb7ea](https://github.com/jdx/mise/commit/2ffb7eaa22e3623363dd153d581bb1a17da78483)\n\n### New Contributors\n\n- @artemisart made their first contribution in [#5171](https://github.com/jdx/mise/pull/5171)\n\n## [2025.5.11](https://github.com/jdx/mise/compare/v2025.5.10..v2025.5.11) - 2025-05-23\n\n### 🚀 Features\n\n- **(registry)** add victoriametrics by @shikharbhardwaj in [#5161](https://github.com/jdx/mise/pull/5161)\n- added dotslash by @jdx in [#5165](https://github.com/jdx/mise/pull/5165)\n\n### 🐛 Bug Fixes\n\n- **(registry)** remove full from taplo by @risu729 in [#5160](https://github.com/jdx/mise/pull/5160)\n- mise registry links for ubi with exe selector by @mnm364 in [#5156](https://github.com/jdx/mise/pull/5156)\n- mise settings add idiomatic_version_file_enable_tools stores duplicates in config by @roele in [#5162](https://github.com/jdx/mise/pull/5162)\n- infinite sourcing loop on bash-completion by @ken-kuro in [#5150](https://github.com/jdx/mise/pull/5150)\n\n### 🧪 Testing\n\n- disable mockolo since linux does not work anymore by @jdx in [5387d70](https://github.com/jdx/mise/commit/5387d7012d65b3da3dde12cd0a0eb07288b2d8f6)\n\n### New Contributors\n\n- @ken-kuro made their first contribution in [#5150](https://github.com/jdx/mise/pull/5150)\n- @shikharbhardwaj made their first contribution in [#5161](https://github.com/jdx/mise/pull/5161)\n\n## [2025.5.10](https://github.com/jdx/mise/compare/v2025.5.9..v2025.5.10) - 2025-05-22\n\n### 🚀 Features\n\n- **(registry)** add process-compose by @evanleck in [#4788](https://github.com/jdx/mise/pull/4788)\n- **(registry)** add tailpipe by @pdecat in [#4858](https://github.com/jdx/mise/pull/4858)\n- mise search by @roele in [#5153](https://github.com/jdx/mise/pull/5153)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** windows exe fix by @jdx in [#5154](https://github.com/jdx/mise/pull/5154)\n\n### 🧪 Testing\n\n- disable failing edit test by @jdx in [8698bce](https://github.com/jdx/mise/commit/8698bce774eafa86afa9d5b56a225fa6cdbe6ea1)\n\n### Chore\n\n- disable failing docker dev build by @jdx in [496c1c9](https://github.com/jdx/mise/commit/496c1c91545ed7f013726cd48e746835bdf570d8)\n- temporarily disable cargo up to fix build by @jdx in [90c66b7](https://github.com/jdx/mise/commit/90c66b7b561e81efe7d951a0ce9574c11e7b91a7)\n\n### New Contributors\n\n- @evanleck made their first contribution in [#4788](https://github.com/jdx/mise/pull/4788)\n\n## [2025.5.9](https://github.com/jdx/mise/compare/v2025.5.8..v2025.5.9) - 2025-05-21\n\n### 🚀 Features\n\n- **(registry)** add microsoft `edit` by @garysassano in [#5145](https://github.com/jdx/mise/pull/5145)\n- added buildifier by @jdx in [#5142](https://github.com/jdx/mise/pull/5142)\n- add shims in REMOTE ENV by @acesyde in [#5139](https://github.com/jdx/mise/pull/5139)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** use complete_windows_ext by @jdx in [#5146](https://github.com/jdx/mise/pull/5146)\n- **(registry)** support editorconfig-checker in windows by @risu729 in [#5125](https://github.com/jdx/mise/pull/5125)\n- SSH remote tasks do not support organizations in repository path by @roele in [#5124](https://github.com/jdx/mise/pull/5124)\n- SSH remote tasks do not support organizations in repository path by @roele in [#5132](https://github.com/jdx/mise/pull/5132)\n\n### 📚 Documentation\n\n- squeeze spaces when migrating from asdf by @maximd in [#5131](https://github.com/jdx/mise/pull/5131)\n\n### Chore\n\n- pin github actions by @jdx in [bf18644](https://github.com/jdx/mise/commit/bf1864472c3ed587fbdb497722849cf6cfacca5c)\n- use renovate to pin github actions by @jdx in [b80d8e3](https://github.com/jdx/mise/commit/b80d8e3ffe73d315c4214f77dedcf4cce7a54032)\n- disable mold in ci by @jdx in [#5128](https://github.com/jdx/mise/pull/5128)\n- fix buildifier test by @jdx in [232a4c6](https://github.com/jdx/mise/commit/232a4c641fedc9dfb83ce048ad5b47253b139854)\n\n### New Contributors\n\n- @maximd made their first contribution in [#5131](https://github.com/jdx/mise/pull/5131)\n\n## [2025.5.8](https://github.com/jdx/mise/compare/v2025.5.7..v2025.5.8) - 2025-05-18\n\n### 🚀 Features\n\n- **(registry)** added astro by @mnm364 in [#5106](https://github.com/jdx/mise/pull/5106)\n\n### 🐛 Bug Fixes\n\n- **(registry)** use aqua for delta by @risu729 in [#5116](https://github.com/jdx/mise/pull/5116)\n- elixir bin name on windows by @arilence in [#5107](https://github.com/jdx/mise/pull/5107)\n\n### Chore\n\n- create a detached signature when signing the source tarball by @digital-wonderland in [#5108](https://github.com/jdx/mise/pull/5108)\n\n### New Contributors\n\n- @arilence made their first contribution in [#5107](https://github.com/jdx/mise/pull/5107)\n\n## [2025.5.7](https://github.com/jdx/mise/compare/v2025.5.6..v2025.5.7) - 2025-05-18\n\n### 🐛 Bug Fixes\n\n- using custom port with SSH based remote tasks by @roele in [#5110](https://github.com/jdx/mise/pull/5110)\n- update rabbitmq backend by @SerhiiFesenko in [#5115](https://github.com/jdx/mise/pull/5115)\n- maven-mvnd does not install with aqua by @roele in [#5117](https://github.com/jdx/mise/pull/5117)\n\n### New Contributors\n\n- @SerhiiFesenko made their first contribution in [#5115](https://github.com/jdx/mise/pull/5115)\n\n## [2025.5.6](https://github.com/jdx/mise/compare/v2025.5.5..v2025.5.6) - 2025-05-17\n\n### 🚀 Features\n\n- **(registry)** add oauth2c by @kklee998 in [#5056](https://github.com/jdx/mise/pull/5056)\n- use new Java metadata source by @roele in [#5089](https://github.com/jdx/mise/pull/5089)\n\n### 🐛 Bug Fixes\n\n- **(config)** project root for files in .config/ or mise/ by @scop in [#5102](https://github.com/jdx/mise/pull/5102)\n- Clarify some of the filters and fix the config_root filter example by @afranchuk in [#5086](https://github.com/jdx/mise/pull/5086)\n\n### 🚜 Refactor\n\n- **(registry)** use aqua for rclone by @scop in [#5096](https://github.com/jdx/mise/pull/5096)\n\n### 📚 Documentation\n\n- **(tasks)** point to `dir` config for task default cwd by @scop in [#5103](https://github.com/jdx/mise/pull/5103)\n- remove go.mod from idiomatic version files by @Gandem in [#5090](https://github.com/jdx/mise/pull/5090)\n- remove stray backquote from toml-tasks by @scop in [#5097](https://github.com/jdx/mise/pull/5097)\n- add some missing vue interpolation escapes by @scop in [#5099](https://github.com/jdx/mise/pull/5099)\n- remove some references to rtx by @jdx in [#5105](https://github.com/jdx/mise/pull/5105)\n\n### 📦️ Dependency Updates\n\n- update dependency node to v22 by @renovate[bot] in [#5093](https://github.com/jdx/mise/pull/5093)\n\n### Chore\n\n- sign source tarball by @digital-wonderland in [#5087](https://github.com/jdx/mise/pull/5087)\n\n### New Contributors\n\n- @digital-wonderland made their first contribution in [#5087](https://github.com/jdx/mise/pull/5087)\n- @kklee998 made their first contribution in [#5056](https://github.com/jdx/mise/pull/5056)\n- @afranchuk made their first contribution in [#5086](https://github.com/jdx/mise/pull/5086)\n- @Gandem made their first contribution in [#5090](https://github.com/jdx/mise/pull/5090)\n\n## [2025.5.5](https://github.com/jdx/mise/compare/v2025.5.4..v2025.5.5) - 2025-05-15\n\n### 🚀 Features\n\n- **(registry)** add pinact by @3w36zj6 in [#5061](https://github.com/jdx/mise/pull/5061)\n- **(registry)** add ghalint by @risu729 in [#5063](https://github.com/jdx/mise/pull/5063)\n- new \"enable-tools\" option by @zeitlinger in [#4784](https://github.com/jdx/mise/pull/4784)\n\n### 📚 Documentation\n\n- hide `ls --offline` flag that is a no-op by @jdx in [#5068](https://github.com/jdx/mise/pull/5068)\n\n### Chore\n\n- add pr comment for new tools by @jdx in [#5067](https://github.com/jdx/mise/pull/5067)\n- set comment-tag for registry pr comment by @jdx in [#5069](https://github.com/jdx/mise/pull/5069)\n- run multiple test-tool jobs by @jdx in [#5070](https://github.com/jdx/mise/pull/5070)\n- fix typo in registry comment by @jdx in [#5071](https://github.com/jdx/mise/pull/5071)\n- bump zip-rs version by @hkoosha in [#5073](https://github.com/jdx/mise/pull/5073)\n\n### New Contributors\n\n- @3w36zj6 made their first contribution in [#5061](https://github.com/jdx/mise/pull/5061)\n\n## [2025.5.4](https://github.com/jdx/mise/compare/v2025.5.3..v2025.5.4) - 2025-05-14\n\n### 🚀 Features\n\n- **(registry)** add sshi by @scop in [#5048](https://github.com/jdx/mise/pull/5048)\n- **(registry)** added Neon CLI by @joehorsnell in [#4994](https://github.com/jdx/mise/pull/4994)\n\n### 🐛 Bug Fixes\n\n- **(registry)** update glab ubi provider by @StingRayZA in [#5052](https://github.com/jdx/mise/pull/5052)\n- mise panics if CI env var isn't a boolean by @roele in [#5059](https://github.com/jdx/mise/pull/5059)\n- `aqua` version test by @joehorsnell in [#5038](https://github.com/jdx/mise/pull/5038)\n- run hook-env after trusting config file by @jdx in [#5062](https://github.com/jdx/mise/pull/5062)\n\n### 🚜 Refactor\n\n- **(hooks)** remove duplicated code by @risu729 in [#5036](https://github.com/jdx/mise/pull/5036)\n\n### 📚 Documentation\n\n- fix add_predicate handler in neovim cookbook by @okuuva in [#5044](https://github.com/jdx/mise/pull/5044)\n- improve treesitter queries in neovim cookbook by @okuuva in [#5045](https://github.com/jdx/mise/pull/5045)\n\n### New Contributors\n\n- @okuuva made their first contribution in [#5045](https://github.com/jdx/mise/pull/5045)\n\n## [2025.5.3](https://github.com/jdx/mise/compare/v2025.5.2..v2025.5.3) - 2025-05-09\n\n### 🚀 Features\n\n- **(registry)** add coreutils by @kit494way in [#5033](https://github.com/jdx/mise/pull/5033)\n\n### 🐛 Bug Fixes\n\n- unuse command does not support env, global and path options by @roele in [#5021](https://github.com/jdx/mise/pull/5021)\n\n### 🧪 Testing\n\n- disable aqua for now due to bad version output by @jdx in [fa3daa2](https://github.com/jdx/mise/commit/fa3daa2cab09ba7e0140fcf2112375eef8427a85)\n- fix python poetry test by @jdx in [c46a190](https://github.com/jdx/mise/commit/c46a190cb699b7700aa636a2bc888222ed7e9dbc)\n\n### ◀️ Revert\n\n- Revert \"fix(dotenv): properly escape values in generated dotenv \" by @jdx in [358c3da](https://github.com/jdx/mise/commit/358c3dab2dba7129ac115fc3414657dc39b2bd79)\n- Revert \"fix(env): fix dotenv files cascading (fix #4688) \" by @jdx in [b1ca323](https://github.com/jdx/mise/commit/b1ca3235ffc9635f17dac0896c3c07b975d65819)\n\n### 📦️ Dependency Updates\n\n- update rust crate nix to 0.30 by @renovate[bot] in [#5032](https://github.com/jdx/mise/pull/5032)\n- update rust crate built to 0.8 by @renovate[bot] in [#5031](https://github.com/jdx/mise/pull/5031)\n\n## [2025.5.2](https://github.com/jdx/mise/compare/v2025.5.1..v2025.5.2) - 2025-05-07\n\n### 🐛 Bug Fixes\n\n- **(dotenv)** properly escape values in generated dotenv by @noirbizarre in [#5010](https://github.com/jdx/mise/pull/5010)\n- **(registry)** use full version of taplo by @risu729 in [#5017](https://github.com/jdx/mise/pull/5017)\n\n### 📚 Documentation\n\n- hide rtx docs by @jdx in [90ae2ce](https://github.com/jdx/mise/commit/90ae2ce5abf4faa65ef2414385e587d97ff0ca2c)\n- describe cache auto-prune by @jdx in [#5013](https://github.com/jdx/mise/pull/5013)\n- mark idiomatic_version_file_disable_tools as deprecated by @jdx in [9bb80f3](https://github.com/jdx/mise/commit/9bb80f301e29fcc668f51de8e0a168a32c9ac8db)\n\n### Chore\n\n- remove homebrew bump step by @jdx in [1625608](https://github.com/jdx/mise/commit/1625608c0025ec21a49eedcc85533facde52a8a7)\n- simplify git logs by @jdx in [#5012](https://github.com/jdx/mise/pull/5012)\n\n## [2025.5.1](https://github.com/jdx/mise/compare/v2025.5.0..v2025.5.1) - 2025-05-05\n\n### 🚀 Features\n\n- **(registry)** use aqua for taplo by @risu729 in [#4991](https://github.com/jdx/mise/pull/4991)\n- add mise_env tera variable for templates by @auxesis in [#5002](https://github.com/jdx/mise/pull/5002)\n\n### 🐛 Bug Fixes\n\n- **(env)** fix dotenv files cascading (fix #4688) by @noirbizarre in [#4996](https://github.com/jdx/mise/pull/4996)\n\n### Ci\n\n- **(registry)** increaset timeout to 30 mins by @risu729 in [#5006](https://github.com/jdx/mise/pull/5006)\n\n## [2025.5.0](https://github.com/jdx/mise/compare/v2025.4.12..v2025.5.0) - 2025-05-03\n\n### 🚀 Features\n\n- **(registry)** add luau by @rhanneken in [#4993](https://github.com/jdx/mise/pull/4993)\n- **(registry)** add numbat by @risu729 in [#4980](https://github.com/jdx/mise/pull/4980)\n- **(status)** add setting to control status message truncation by @rarescosma in [#4986](https://github.com/jdx/mise/pull/4986)\n- add check flag for the fmt command by @roele in [#4972](https://github.com/jdx/mise/pull/4972)\n- use aqua for btop by @jdx in [#4979](https://github.com/jdx/mise/pull/4979)\n\n### 🐛 Bug Fixes\n\n- **(java)** filter out JetBrains releases with features by @roele in [#4970](https://github.com/jdx/mise/pull/4970)\n- fix deadlocks caused by uv_venv_auto by @risu729 in [#4900](https://github.com/jdx/mise/pull/4900)\n\n### 📚 Documentation\n\n- Put dot in dotfile example by @ryanbrainard in [#4965](https://github.com/jdx/mise/pull/4965)\n\n### Chore\n\n- only use mold when available by @jdx in [#4978](https://github.com/jdx/mise/pull/4978)\n- enable clearing screen for confirm and dialog by @roele in [#4990](https://github.com/jdx/mise/pull/4990)\n\n### New Contributors\n\n- @rarescosma made their first contribution in [#4986](https://github.com/jdx/mise/pull/4986)\n- @rhanneken made their first contribution in [#4993](https://github.com/jdx/mise/pull/4993)\n- @ryanbrainard made their first contribution in [#4965](https://github.com/jdx/mise/pull/4965)\n\n## [2025.4.12](https://github.com/jdx/mise/compare/v2025.4.11..v2025.4.12) - 2025-04-29\n\n### 🐛 Bug Fixes\n\n- **(aqua)** fix bin_path of tools in monorepo by @risu729 in [#4954](https://github.com/jdx/mise/pull/4954)\n- **(schema)** allow array of objects for hooks by @risu729 in [#4955](https://github.com/jdx/mise/pull/4955)\n- store tool version opts in .mise.backend by @roele in [#4960](https://github.com/jdx/mise/pull/4960)\n\n### 📚 Documentation\n\n- add information about the DNF repository by @acesyde in [#4956](https://github.com/jdx/mise/pull/4956)\n\n### 🧪 Testing\n\n- fix registry tools by @jdx in [#4959](https://github.com/jdx/mise/pull/4959)\n\n### Chore\n\n- **(deny)** added CDLA-Permissive-2.0 by @jdx in [#4961](https://github.com/jdx/mise/pull/4961)\n\n## [2025.4.11](https://github.com/jdx/mise/compare/v2025.4.10..v2025.4.11) - 2025-04-27\n\n### 🚀 Features\n\n- **(cargo)** allow customizable registry by @acesyde in [#4948](https://github.com/jdx/mise/pull/4948)\n- **(doctor)** show error if tool not installed by @jdx in [#4952](https://github.com/jdx/mise/pull/4952)\n- added sd by @jdx in [#4950](https://github.com/jdx/mise/pull/4950)\n- MISE_LOG_HTTP by @jdx in [#4951](https://github.com/jdx/mise/pull/4951)\n\n### 🐛 Bug Fixes\n\n- set prune age to 10y in dockerfile by @jdx in [9a521dc](https://github.com/jdx/mise/commit/9a521dc1e93e57567dcb262482a6a8d382fbebe8)\n\n### Chore\n\n- brew update by @jdx in [641f3b3](https://github.com/jdx/mise/commit/641f3b3ef1c8c7b2e4931c5012c2b8dc94533070)\n- brew sync repos by @jdx in [3318e98](https://github.com/jdx/mise/commit/3318e98d78af8a11e36f13574abe4f1cce181a92)\n- bump usage by @jdx in [#4949](https://github.com/jdx/mise/pull/4949)\n\n## [2025.4.10](https://github.com/jdx/mise/compare/v2025.4.9..v2025.4.10) - 2025-04-26\n\n### 🚀 Features\n\n- **(registry)** add `cli53` backend by @garysassano in [#4937](https://github.com/jdx/mise/pull/4937)\n- pipx custom repository url by @acesyde in [#4945](https://github.com/jdx/mise/pull/4945)\n\n### 🐛 Bug Fixes\n\n- **(hook-env)** path order by @jdx in [#4946](https://github.com/jdx/mise/pull/4946)\n- **(unuse)** allow unusing any version if version not specified by @jdx in [#4944](https://github.com/jdx/mise/pull/4944)\n- Always use env::MISE_BIN when calling mise from itself by @hverlin in [#4943](https://github.com/jdx/mise/pull/4943)\n\n### 📚 Documentation\n\n- remove outdated note about automatic shim activation with Scoop by @jgutierrezre in [#4941](https://github.com/jdx/mise/pull/4941)\n\n### Chore\n\n- checkout for homebrew bump by @jdx in [6d7b0f6](https://github.com/jdx/mise/commit/6d7b0f6fdf83ee9d7be29a61b5b5be202ac0526a)\n- mise.lock by @jdx in [05c9a24](https://github.com/jdx/mise/commit/05c9a241744fa330677402a365344b8430a4984c)\n- updated deps by @jdx in [ac5cf5d](https://github.com/jdx/mise/commit/ac5cf5d840dc3a997dce0b1d3a1af963ef456ac2)\n- brew developer by @jdx in [445e313](https://github.com/jdx/mise/commit/445e313985cb948cf2a7cb57d896055b898a0f67)\n\n### New Contributors\n\n- @garysassano made their first contribution in [#4937](https://github.com/jdx/mise/pull/4937)\n- @jgutierrezre made their first contribution in [#4941](https://github.com/jdx/mise/pull/4941)\n\n## [2025.4.9](https://github.com/jdx/mise/compare/v2025.4.8..v2025.4.9) - 2025-04-25\n\n### 🚀 Features\n\n- **(registry)** added tusd by @mnm364 in [#4928](https://github.com/jdx/mise/pull/4928)\n- **(registry)** added fastfetch by @sassdavid in [#4932](https://github.com/jdx/mise/pull/4932)\n\n### 🐛 Bug Fixes\n\n- remove missing symlinks on unuse when pruning by @roele in [#4930](https://github.com/jdx/mise/pull/4930)\n\n### 📚 Documentation\n\n- typo by @jdx in [314657f](https://github.com/jdx/mise/commit/314657fb6ee69646464c35ed4d8b72f0f2d551da)\n\n### ⚡ Performance\n\n- turn several of the list functions into parallel iters by @lespea in [#4924](https://github.com/jdx/mise/pull/4924)\n\n### 🧪 Testing\n\n- fix kwok by @jdx in [4516335](https://github.com/jdx/mise/commit/451633512b67d26f2b3263094826da7c7406c1da)\n- increase windows-e2e timeout by @jdx in [ce4f734](https://github.com/jdx/mise/commit/ce4f73462b10979f3721400393c4d3ba782c3bb4)\n\n### 📦️ Dependency Updates\n\n- update apple-actions/import-codesign-certs action to v5 by @renovate[bot] in [#4936](https://github.com/jdx/mise/pull/4936)\n- update rust crate tabled to 0.19 by @renovate[bot] in [#4935](https://github.com/jdx/mise/pull/4935)\n\n### Chore\n\n- use macos-latest in GHA by @jdx in [05b5d49](https://github.com/jdx/mise/commit/05b5d49eaa3c4e78f1102dd2d9cfbca63c276ec0)\n- attempt to fix brew bump by @jdx in [043f97f](https://github.com/jdx/mise/commit/043f97f23e9af914772474ee0379b5a7d9399f3e)\n- mise up by @jdx in [ee7436d](https://github.com/jdx/mise/commit/ee7436d65c89416ee39ee424e296ae329f747323)\n\n### New Contributors\n\n- @lespea made their first contribution in [#4924](https://github.com/jdx/mise/pull/4924)\n\n## [2025.4.8](https://github.com/jdx/mise/compare/v2025.4.7..v2025.4.8) - 2025-04-23\n\n### 🐛 Bug Fixes\n\n- hide idiomatic warning if no versions in idiomatic file by @jdx in [#4922](https://github.com/jdx/mise/pull/4922)\n\n### 📚 Documentation\n\n- clean up idiomatic deprecation message by @jdx in [c31aa2c](https://github.com/jdx/mise/commit/c31aa2cbd07a1f74049a0c6b72dfb91632ff5816)\n- punctuation improvements to idiomatic deprecation message by @glasser in [#4915](https://github.com/jdx/mise/pull/4915)\n\n## [2025.4.7](https://github.com/jdx/mise/compare/v2025.4.6..v2025.4.7) - 2025-04-23\n\n### 🚀 Features\n\n- **(registry)** added oxipng by @ldrouard in [#4452](https://github.com/jdx/mise/pull/4452)\n- `mise tasks --local|--global` by @jdx in [#4907](https://github.com/jdx/mise/pull/4907)\n\n### 🐛 Bug Fixes\n\n- added lockfile for pyenv by @jdx in [#4906](https://github.com/jdx/mise/pull/4906)\n- move idiomatic version breaking change from 2026.1.1 to 2025.10.0 by @jdx in [#4909](https://github.com/jdx/mise/pull/4909)\n- allow setting lists to be empty by @jdx in [#4912](https://github.com/jdx/mise/pull/4912)\n\n### 🧪 Testing\n\n- test registry changes by themselves by @jdx in [#4910](https://github.com/jdx/mise/pull/4910)\n- test registry changes by themselves by @jdx in [#4911](https://github.com/jdx/mise/pull/4911)\n\n### 📦️ Dependency Updates\n\n- update rust crate tabled to 0.18 by @renovate[bot] in [#4873](https://github.com/jdx/mise/pull/4873)\n\n### Chore\n\n- use hk for linting by @jdx in [#4908](https://github.com/jdx/mise/pull/4908)\n- prefer ubi for shellcheck by @jdx in [c805f39](https://github.com/jdx/mise/commit/c805f399a0987db2ce812f2bd6ff66beb53de989)\n\n## [2025.4.6](https://github.com/jdx/mise/compare/v2025.4.5..v2025.4.6) - 2025-04-22\n\n### 🚀 Features\n\n- **(aqua)** support github_release minisign type by @risu729 in [#4897](https://github.com/jdx/mise/pull/4897)\n- **(go)** support build tags by @bamorim in [#4863](https://github.com/jdx/mise/pull/4863)\n- **(registry)** added Signadot by @joehorsnell in [#4868](https://github.com/jdx/mise/pull/4868)\n- added `idiomatic_version_file_enable_tools` and deprecated `idiomatic_version_file_disable_tools` by @jdx in [#4902](https://github.com/jdx/mise/pull/4902)\n\n### 🐛 Bug Fixes\n\n- **(doctor)** redact gitlab/enterprise tokens by @risu729 in [#4888](https://github.com/jdx/mise/pull/4888)\n- **(task)** enable templates in shell and tools of tasks by @risu729 in [#4887](https://github.com/jdx/mise/pull/4887)\n- allow interactive upgrade to select nothing by @risu729 in [#4891](https://github.com/jdx/mise/pull/4891)\n- enable templates for shell of hooks by @risu729 in [#4893](https://github.com/jdx/mise/pull/4893)\n\n### 📚 Documentation\n\n- fix typo in go backend tags option title by @bamorim in [#4884](https://github.com/jdx/mise/pull/4884)\n- update link to faq in use_versions_host by @risu729 in [#4890](https://github.com/jdx/mise/pull/4890)\n\n### 🧪 Testing\n\n- remove flaky bazel-watcher by @jdx in [9e95e6a](https://github.com/jdx/mise/commit/9e95e6afd04a43cc7d43e2f2280c7880bb481507)\n\n### New Contributors\n\n- @joehorsnell made their first contribution in [#4868](https://github.com/jdx/mise/pull/4868)\n- @bamorim made their first contribution in [#4884](https://github.com/jdx/mise/pull/4884)\n\n## [2025.4.5](https://github.com/jdx/mise/compare/v2025.4.4..v2025.4.5) - 2025-04-18\n\n### 🐛 Bug Fixes\n\n- **(ubi)** API URL for GitHub should not have /repos segement by @roele in [#4848](https://github.com/jdx/mise/pull/4848)\n- **(ubi)** URL syntax fails by @roele in [#4859](https://github.com/jdx/mise/pull/4859)\n- allow to install non-numeric elixir versions by @roele in [#4850](https://github.com/jdx/mise/pull/4850)\n- removed possible single-point-of-failure while running `mise upgrade` by @hitblast in [#4847](https://github.com/jdx/mise/pull/4847)\n- `#MISE tools=` in task header by @jdx in [#4860](https://github.com/jdx/mise/pull/4860)\n\n### 🧪 Testing\n\n- fix aqua tool test by @jdx in [4f2c050](https://github.com/jdx/mise/commit/4f2c0505502c1e3c7bf3478d61a2c352591f281c)\n\n### New Contributors\n\n- @hitblast made their first contribution in [#4847](https://github.com/jdx/mise/pull/4847)\n\n## [2025.4.4](https://github.com/jdx/mise/compare/v2025.4.3..v2025.4.4) - 2025-04-15\n\n### 🧪 Testing\n\n- remove kpt test by @jdx in [b9d35ac](https://github.com/jdx/mise/commit/b9d35ac57936291a0a4629f9c200dfdb500a7efb)\n\n## [2025.4.3](https://github.com/jdx/mise/compare/v2025.4.2..v2025.4.3) - 2025-04-15\n\n### 🚀 Features\n\n- **(aqua)** support SLSA source_uri setting by @scop in [#4833](https://github.com/jdx/mise/pull/4833)\n- **(aqua)** use source tag in SLSA verification by @scop in [#4836](https://github.com/jdx/mise/pull/4836)\n- **(ubi)** add support for self-hosted GitHub/GitLab by @roele in [#4765](https://github.com/jdx/mise/pull/4765)\n\n### 📚 Documentation\n\n- Update configuration.md by @jdx in [#4829](https://github.com/jdx/mise/pull/4829)\n- correct `mise use` paths by @jdx in [c8374c0](https://github.com/jdx/mise/commit/c8374c00ca68e5722c28f9abfd2425b9722bdd83)\n\n## [2025.4.2](https://github.com/jdx/mise/compare/v2025.4.1..v2025.4.2) - 2025-04-11\n\n### 🚀 Features\n\n- **(registry)** update aws-nuke backend by @StingRayZA in [#4815](https://github.com/jdx/mise/pull/4815)\n\n### 🐛 Bug Fixes\n\n- do not default to writing to mise.$MISE_ENV.toml by @jdx in [#4817](https://github.com/jdx/mise/pull/4817)\n- mise watch forward --exts and --filter to watchexec by @cmhms in [#4826](https://github.com/jdx/mise/pull/4826)\n\n### 📚 Documentation\n\n- Fixing typo in code for flags in toml-tasks.md by @arafays in [#4820](https://github.com/jdx/mise/pull/4820)\n- branding by @jdx in [9ad2c17](https://github.com/jdx/mise/commit/9ad2c17ec75b7460ebea09a9f0601a561349cc7f)\n- remove references to not-working docker: tasks by @jdx in [2c2fd27](https://github.com/jdx/mise/commit/2c2fd272e3d76329a7c67e4070bfb122ae1e1120)\n- document some dependencies by @jdx in [6e8bd51](https://github.com/jdx/mise/commit/6e8bd518757c5e49624fc2bef5777a2f2339c304)\n- simplify mise.toml example by @jdx in [66d927b](https://github.com/jdx/mise/commit/66d927ba4db81ba70de261cd76e399e9f4fe35da)\n\n### 📦️ Dependency Updates\n\n- update dependency vitepress-plugin-tabs to ^0.7.0 by @renovate[bot] in [#4822](https://github.com/jdx/mise/pull/4822)\n- update rust crate petgraph to 0.8 by @renovate[bot] in [#4823](https://github.com/jdx/mise/pull/4823)\n- update rust crate strum to 0.27 by @renovate[bot] in [#4780](https://github.com/jdx/mise/pull/4780)\n\n### New Contributors\n\n- @cmhms made their first contribution in [#4826](https://github.com/jdx/mise/pull/4826)\n- @StingRayZA made their first contribution in [#4815](https://github.com/jdx/mise/pull/4815)\n\n## [2025.4.1](https://github.com/jdx/mise/compare/v2025.4.0..v2025.4.1) - 2025-04-09\n\n### 🚀 Features\n\n- **(registry)** added localstack by @mnm364 in [#4785](https://github.com/jdx/mise/pull/4785)\n- **(registry)** added skeema by @mnm364 in [#4786](https://github.com/jdx/mise/pull/4786)\n- **(registry)** add television by @mangkoran in [#4778](https://github.com/jdx/mise/pull/4778)\n\n### 🐛 Bug Fixes\n\n- show gh rate limit reset time in local time by @someoneinjd in [#4799](https://github.com/jdx/mise/pull/4799)\n\n### 📚 Documentation\n\n- all experimental note for lockfile by @zeitlinger in [#4781](https://github.com/jdx/mise/pull/4781)\n- Include post about Mise secrets in the context of Swift app dev by @pepicrft in [#4809](https://github.com/jdx/mise/pull/4809)\n\n### Chore\n\n- update deps to fix deny check by @jdx in [432023b](https://github.com/jdx/mise/commit/432023b2cd04d2ea7f590d7b338054944512abd0)\n- pin zip to avoid issue with ubi by @jdx in [315deb4](https://github.com/jdx/mise/commit/315deb4e24177408c598d22951adb95f3e841683)\n\n### New Contributors\n\n- @someoneinjd made their first contribution in [#4799](https://github.com/jdx/mise/pull/4799)\n- @mnm364 made their first contribution in [#4786](https://github.com/jdx/mise/pull/4786)\n- @zeitlinger made their first contribution in [#4781](https://github.com/jdx/mise/pull/4781)\n\n## [2025.4.0](https://github.com/jdx/mise/compare/v2025.3.11..v2025.4.0) - 2025-04-02\n\n### 🐛 Bug Fixes\n\n- s/runtimes/tools by @jdx in [#4754](https://github.com/jdx/mise/pull/4754)\n- add clarification on RUSTUP_HOME and CARGO_HOME by @lachieh in [#4759](https://github.com/jdx/mise/pull/4759)\n- enhance confirmation logic to respect SETTINGS.yes by @roele in [#4764](https://github.com/jdx/mise/pull/4764)\n\n### 🚜 Refactor\n\n- **(registry)** use aqua for ubi by @scop in [#4745](https://github.com/jdx/mise/pull/4745)\n- **(registry)** use aqua for ksops by @scop in [#4746](https://github.com/jdx/mise/pull/4746)\n\n### 📚 Documentation\n\n- mark code block for dnf5 install as shell code by @sina-hide in [#4747](https://github.com/jdx/mise/pull/4747)\n- update demo by @hverlin in [#4350](https://github.com/jdx/mise/pull/4350)\n- move demo to top-level by @jdx in [2b6f45a](https://github.com/jdx/mise/commit/2b6f45ac73d6f59542f9c7b401042ad5c75e37e2)\n- Update config.ts by @jdx in [05ad4bc](https://github.com/jdx/mise/commit/05ad4bc9b2243737c0551fd36de1e37dc57ea578)\n- Update walkthrough.md by @jdx in [89904b4](https://github.com/jdx/mise/commit/89904b46d8649a66bf960b1e5c7c0364dad8f94f)\n- Update index.md by @jdx in [#4750](https://github.com/jdx/mise/pull/4750)\n- Update walkthrough.md by @jdx in [#4751](https://github.com/jdx/mise/pull/4751)\n- Update README.md by @jdx in [4f38142](https://github.com/jdx/mise/commit/4f38142bd3d822c3eafd78a74aa7a8d31791d2e3)\n\n### New Contributors\n\n- @lachieh made their first contribution in [#4759](https://github.com/jdx/mise/pull/4759)\n- @sina-hide made their first contribution in [#4747](https://github.com/jdx/mise/pull/4747)\n\n## [2025.3.11](https://github.com/jdx/mise/compare/v2025.3.10..v2025.3.11) - 2025-03-28\n\n### 🚀 Features\n\n- **(registry)** add protoc-gen-validate by @akanter in [#4703](https://github.com/jdx/mise/pull/4703)\n\n### 🚜 Refactor\n\n- **(registry)** use aqua for swiftlint by @scop in [#4726](https://github.com/jdx/mise/pull/4726)\n- **(registry)** use ubi for opensearch-cli by @scop in [#4725](https://github.com/jdx/mise/pull/4725)\n- **(registry)** use ubi for mdbook-linkcheck by @scop in [#4724](https://github.com/jdx/mise/pull/4724)\n- **(registry)** use ubi for velad by @scop in [#4727](https://github.com/jdx/mise/pull/4727)\n\n## [2025.3.10](https://github.com/jdx/mise/compare/v2025.3.9..v2025.3.10) - 2025-03-26\n\n### ◀️ Revert\n\n- Revert \"chore: make awscli compatible with R2\" by @jdx in [83e8c16](https://github.com/jdx/mise/commit/83e8c164ec78cab4325b4489d9cc5d1fa466ec3f)\n\n## [2025.3.9](https://github.com/jdx/mise/compare/v2025.3.8..v2025.3.9) - 2025-03-26\n\n### 🚀 Features\n\n- Set usage arguments and flag as environment variables before running the command by @gturi in [#4700](https://github.com/jdx/mise/pull/4700)\n\n### 🚜 Refactor\n\n- **(registry)** use ubi for assh by @scop in [#4713](https://github.com/jdx/mise/pull/4713)\n- **(registry)** use ubi for opsgenie-lamp by @scop in [#4712](https://github.com/jdx/mise/pull/4712)\n- **(registry)** use ubi for auto-doc by @scop in [#4714](https://github.com/jdx/mise/pull/4714)\n- **(registry)** use ubi for getenvoy by @scop in [#4715](https://github.com/jdx/mise/pull/4715)\n- **(registry)** use ubi for mockolo by @scop in [#4705](https://github.com/jdx/mise/pull/4705)\n- **(registry)** use ubi for haxe by @scop in [#4716](https://github.com/jdx/mise/pull/4716)\n- **(registry)** use ubi for helm-diff by @scop in [#4717](https://github.com/jdx/mise/pull/4717)\n- **(registry)** use ubi for grain by @scop in [#4718](https://github.com/jdx/mise/pull/4718)\n\n## [2025.3.8](https://github.com/jdx/mise/compare/v2025.3.7..v2025.3.8) - 2025-03-24\n\n### 🚀 Features\n\n- **(registry)** add aichat by @kit494way in [#4691](https://github.com/jdx/mise/pull/4691)\n\n### 🐛 Bug Fixes\n\n- Update flake to fix nix build by @akanter in [#4686](https://github.com/jdx/mise/pull/4686)\n\n### 📚 Documentation\n\n- fix bash completion setup instructions by @bestagi in [#3920](https://github.com/jdx/mise/pull/3920)\n- small tidy of shims docs by @AlecRust in [#4693](https://github.com/jdx/mise/pull/4693)\n\n### Chore\n\n- remove broken ripsecrets test by @jdx in [bb382aa](https://github.com/jdx/mise/commit/bb382aa783a2a1bfc44f02a5bb34f9397efb2e57)\n- make awscli compatible with R2 by @jdx in [cad7fa2](https://github.com/jdx/mise/commit/cad7fa285e96483ba8d6aeb22f83de10e92700b2)\n- enable workflow_dispatch for docs task by @jdx in [b0578db](https://github.com/jdx/mise/commit/b0578db141decc63992ebb0f74e29a53238611ba)\n\n### New Contributors\n\n- @akanter made their first contribution in [#4686](https://github.com/jdx/mise/pull/4686)\n- @bestagi made their first contribution in [#3920](https://github.com/jdx/mise/pull/3920)\n\n## [2025.3.7](https://github.com/jdx/mise/compare/v2025.3.6..v2025.3.7) - 2025-03-21\n\n### 🐛 Bug Fixes\n\n- **(node)** skip gpg verification of sig file not found by @jdx in [#4663](https://github.com/jdx/mise/pull/4663)\n- **(task)** allow args to be used with tera tests by @risu729 in [#4605](https://github.com/jdx/mise/pull/4605)\n- Fix syntax error on `activate nu` when PATH contains shims by @atty303 in [#4349](https://github.com/jdx/mise/pull/4349)\n\n### 🚜 Refactor\n\n- **(registry)** use ubi for yamlscript by @scop in [#4670](https://github.com/jdx/mise/pull/4670)\n\n### 📚 Documentation\n\n- Fix typo in java.md by @hverlin in [#4672](https://github.com/jdx/mise/pull/4672)\n\n### ◀️ Revert\n\n- \"chore: temporarily disable bootstrap test\" by @jdx in [#4658](https://github.com/jdx/mise/pull/4658)\n\n### 📦️ Dependency Updates\n\n- update rust crate ctor to 0.4 by @renovate[bot] in [#4553](https://github.com/jdx/mise/pull/4553)\n\n### Chore\n\n- **(registry)** declare copier by @looztra in [#4669](https://github.com/jdx/mise/pull/4669)\n- Update to the latest version of ubi by @autarch in [#4648](https://github.com/jdx/mise/pull/4648)\n- bump expr by @jdx in [#4666](https://github.com/jdx/mise/pull/4666)\n- added android-sdk by @jdx in [#4668](https://github.com/jdx/mise/pull/4668)\n- rename mise-php to asdf-php by @jdx in [#4674](https://github.com/jdx/mise/pull/4674)\n\n### New Contributors\n\n- @atty303 made their first contribution in [#4349](https://github.com/jdx/mise/pull/4349)\n- @looztra made their first contribution in [#4669](https://github.com/jdx/mise/pull/4669)\n\n## [2025.3.6](https://github.com/jdx/mise/compare/v2025.3.5..v2025.3.6) - 2025-03-18\n\n### Chore\n\n- unpin aws-cli by @jdx in [7fabed5](https://github.com/jdx/mise/commit/7fabed5c70fccfe095647c7b2220965ca2f1c07d)\n- temporarily disable bootstrap test by @jdx in [599258a](https://github.com/jdx/mise/commit/599258aa4f5c0ab0b5581740b0c9eec17f1c7318)\n\n## [2025.3.5](https://github.com/jdx/mise/compare/v2025.3.4..v2025.3.5) - 2025-03-18\n\n### 🚀 Features\n\n- **(registry)** use ubi for glab by @scop in [#4643](https://github.com/jdx/mise/pull/4643)\n- ubi forge option support by @scop in [#4642](https://github.com/jdx/mise/pull/4642)\n\n### 🐛 Bug Fixes\n\n- **(tera)** use default inline shell to parse exec template by @risu729 in [#4645](https://github.com/jdx/mise/pull/4645)\n\n## [2025.3.4](https://github.com/jdx/mise/compare/v2025.3.3..v2025.3.4) - 2025-03-18\n\n### 🐛 Bug Fixes\n\n- Failed to create venv at the same time by multiple uv processes by @NavyD in [#4640](https://github.com/jdx/mise/pull/4640)\n\n## [2025.3.3](https://github.com/jdx/mise/compare/v2025.3.2..v2025.3.3) - 2025-03-14\n\n### 🚀 Features\n\n- **(env)** support env files in toml by @risu729 in [#4618](https://github.com/jdx/mise/pull/4618)\n- **(registry)** add harper-ls and harper-cli by @kit494way in [#4615](https://github.com/jdx/mise/pull/4615)\n- **(registry)** add curlie by @reitzig in [#4599](https://github.com/jdx/mise/pull/4599)\n- cleanup the mutex use. by @boris-smidt-klarrio in [#4540](https://github.com/jdx/mise/pull/4540)\n- Add flag to fmt command to read from stdin by @erickgnavar in [#4594](https://github.com/jdx/mise/pull/4594)\n\n### 🐛 Bug Fixes\n\n- **(uv)** avoid deadlocks while initializing UV_VENV by @risu729 in [#4609](https://github.com/jdx/mise/pull/4609)\n- handle error when getting modified duration in file::modified_duration by @roele in [#4624](https://github.com/jdx/mise/pull/4624)\n- SwiftPM backend not working with the Swift 6 toolchain by @pepicrft in [#4632](https://github.com/jdx/mise/pull/4632)\n- quiet in file task not working by @roele in [#4588](https://github.com/jdx/mise/pull/4588)\n- Unable to find uv when first creating py venv by @NavyD in [#4591](https://github.com/jdx/mise/pull/4591)\n\n### 🚜 Refactor\n\n- migrate humantime to jiff by @risu729 in [#4616](https://github.com/jdx/mise/pull/4616)\n- use method to get the default inline shell instead of accessing the fields by @risu729 in [#4621](https://github.com/jdx/mise/pull/4621)\n\n### 📚 Documentation\n\n- **(settings)** clarify the usage of disable_default_registry by @gbloquel in [#4589](https://github.com/jdx/mise/pull/4589)\n\n### ⚡ Performance\n\n- speed up self-update by calling /releases/latest api instead of /releases by @vemoo in [#4619](https://github.com/jdx/mise/pull/4619)\n\n### 🧪 Testing\n\n- **(registry)** fix test of lazyjournal by @risu729 in [#4610](https://github.com/jdx/mise/pull/4610)\n\n### Chore\n\n- deny fixes by @jdx in [17d7c6e](https://github.com/jdx/mise/commit/17d7c6ee5e035272a8dc1b93c8fc7ac9cffb7f80)\n- ignore humantime unmaintained advisory by @risu729 in [#4612](https://github.com/jdx/mise/pull/4612)\n- remove rustup update in github actions by @risu729 in [#4617](https://github.com/jdx/mise/pull/4617)\n\n### New Contributors\n\n- @erickgnavar made their first contribution in [#4594](https://github.com/jdx/mise/pull/4594)\n- @vemoo made their first contribution in [#4619](https://github.com/jdx/mise/pull/4619)\n- @gbloquel made their first contribution in [#4589](https://github.com/jdx/mise/pull/4589)\n\n## [2025.3.1](https://github.com/jdx/mise/compare/v2025.3.0..v2025.3.1) - 2025-03-06\n\n### 🚀 Features\n\n- **(registry)** added sampler by @tony-sol in [#4577](https://github.com/jdx/mise/pull/4577)\n- **(registry)** added lazyjournal by @tony-sol in [#4584](https://github.com/jdx/mise/pull/4584)\n- add support for components property in rust-toolchain.toml by @roele in [#4579](https://github.com/jdx/mise/pull/4579)\n- add --local flag for ls by @tony-sol in [#4565](https://github.com/jdx/mise/pull/4565)\n\n### 🐛 Bug Fixes\n\n- favor aqua backend over asdf by @dud225 in [#4558](https://github.com/jdx/mise/pull/4558)\n\n### 📚 Documentation\n\n- continuous-integration.md: fix gitlab caching example by @nafg in [#4576](https://github.com/jdx/mise/pull/4576)\n\n### Chore\n\n- edition 2024 by @jdx in [#4541](https://github.com/jdx/mise/pull/4541)\n\n### New Contributors\n\n- @nafg made their first contribution in [#4576](https://github.com/jdx/mise/pull/4576)\n- @dud225 made their first contribution in [#4558](https://github.com/jdx/mise/pull/4558)\n\n## [2025.3.0](https://github.com/jdx/mise/compare/v2025.2.9..v2025.3.0) - 2025-03-01\n\n### 🚀 Features\n\n- **(registry)** added helmwave by @tony-sol in [#4542](https://github.com/jdx/mise/pull/4542)\n- **(registry)** added doggo by @tony-sol in [#4545](https://github.com/jdx/mise/pull/4545)\n- **(registry)** Add Boilerplate by @ZachGoldberg in [#4530](https://github.com/jdx/mise/pull/4530)\n- **(registry)** added htmlq by @tony-sol in [#4548](https://github.com/jdx/mise/pull/4548)\n- **(registry)** added gokey by @tony-sol in [#4546](https://github.com/jdx/mise/pull/4546)\n- **(registry)** added octosql by @tony-sol in [#4549](https://github.com/jdx/mise/pull/4549)\n- **(registry)** added hexyl by @tony-sol in [#4547](https://github.com/jdx/mise/pull/4547)\n- **(registry)** added kubeone by @tony-sol in [#4550](https://github.com/jdx/mise/pull/4550)\n- task confirmation by @roele in [#4328](https://github.com/jdx/mise/pull/4328)\n\n### 🐛 Bug Fixes\n\n- remote tasks and devcontainer by @acesyde in [#4557](https://github.com/jdx/mise/pull/4557)\n\n### 📚 Documentation\n\n- **(shim)** add faq for vscode windows spawn EINVAL & format value to list by @qianlongzt in [#4544](https://github.com/jdx/mise/pull/4544)\n\n### New Contributors\n\n- @ZachGoldberg made their first contribution in [#4530](https://github.com/jdx/mise/pull/4530)\n\n## [2025.2.9](https://github.com/jdx/mise/compare/v2025.2.8..v2025.2.9) - 2025-02-26\n\n### 🚀 Features\n\n- **(registry)** add cocogitto by @reitzig in [#4513](https://github.com/jdx/mise/pull/4513)\n- **(registry)** Added foundry by @suicide in [#4455](https://github.com/jdx/mise/pull/4455)\n- **(registry)** added ast-grep by @tony-sol in [#4519](https://github.com/jdx/mise/pull/4519)\n\n### 🐛 Bug Fixes\n\n- non-utf8 external process handling by @jdx in [#4538](https://github.com/jdx/mise/pull/4538)\n\n### 📚 Documentation\n\n- **(cookbook)** add shell powerline-go config env recipe by @scop in [#4532](https://github.com/jdx/mise/pull/4532)\n- update mise.el repo link by @tecoholic in [#4534](https://github.com/jdx/mise/pull/4534)\n\n### Chore\n\n- bump rust version for releases by @jdx in [f4e5970](https://github.com/jdx/mise/commit/f4e5970f00bf56d9be16a7e7e83289085c0e5cce)\n- bump rust version for releases by @jdx in [52cff1c](https://github.com/jdx/mise/commit/52cff1c00b452b93b3ca1e4fc01fd21de73569e5)\n- bump rust version for releases by @jdx in [9121c5e](https://github.com/jdx/mise/commit/9121c5e9270fae59ce753226ecbbe2939c4661e4)\n- bump msrv for edition compatibility by @jdx in [3a222dd](https://github.com/jdx/mise/commit/3a222ddf272eef655b50796f34634fcedc3f1288)\n- remove unused deny rule by @jdx in [053f5c1](https://github.com/jdx/mise/commit/053f5c1c0746e363c24b19577b958621ea91c40c)\n\n### New Contributors\n\n- @tony-sol made their first contribution in [#4519](https://github.com/jdx/mise/pull/4519)\n- @tecoholic made their first contribution in [#4534](https://github.com/jdx/mise/pull/4534)\n- @suicide made their first contribution in [#4455](https://github.com/jdx/mise/pull/4455)\n- @reitzig made their first contribution in [#4513](https://github.com/jdx/mise/pull/4513)\n\n## [2025.2.8](https://github.com/jdx/mise/compare/v2025.2.7..v2025.2.8) - 2025-02-25\n\n### 🚀 Features\n\n- **(registry)** add checkmake to registry by @eread in [#4466](https://github.com/jdx/mise/pull/4466)\n- **(registry)** added sops from aqua registry by @ldrouard in [#4457](https://github.com/jdx/mise/pull/4457)\n- **(registry)** added k9s from aqua registry by @ldrouard in [#4460](https://github.com/jdx/mise/pull/4460)\n- **(registry)** added hadolint from aqua registry by @ldrouard in [#4456](https://github.com/jdx/mise/pull/4456)\n- **(shim)** Windows shim add hardlink & symlink mode by @qianlongzt in [#4409](https://github.com/jdx/mise/pull/4409)\n- **(ubi)** add option `rename_exe` by @wlmitch in [#4512](https://github.com/jdx/mise/pull/4512)\n- use aqua for hk by @jdx in [f68de38](https://github.com/jdx/mise/commit/f68de3849c5ceb20475f2f30224abaa5f3f7441d)\n- add bazel-watcher to registry by @betaboon in [#4296](https://github.com/jdx/mise/pull/4296)\n\n### 🐛 Bug Fixes\n\n- behavior of .disable-self-update by @ZeroAurora in [#4476](https://github.com/jdx/mise/pull/4476)\n- devcontainer by @acesyde in [#4483](https://github.com/jdx/mise/pull/4483)\n- mise outdated --json does not return json if all tools are up-to-date by @roele in [#4493](https://github.com/jdx/mise/pull/4493)\n- bug when using mise use -g when MISE_ENV is filled by @roele in [#4494](https://github.com/jdx/mise/pull/4494)\n- config of symlink tracked on windows is not respected by @NavyD in [#4501](https://github.com/jdx/mise/pull/4501)\n- pruning unused tool leaves broken symlinks by @roele in [#4507](https://github.com/jdx/mise/pull/4507)\n\n### 📚 Documentation\n\n- Fixes typo in lang/zig by @carldaws in [#4497](https://github.com/jdx/mise/pull/4497)\n- Fix activation on PowerShell by @kit494way in [#4498](https://github.com/jdx/mise/pull/4498)\n\n### Chore\n\n- remove aur job by @jdx in [fe5a71d](https://github.com/jdx/mise/commit/fe5a71dc486e6e585167d9d97018f2b467bc43fe)\n- remove reference to aur in release script by @jdx in [0824490](https://github.com/jdx/mise/commit/0824490c14d17cd93c7d68930b514eb11635c451)\n- deny ring sec by @jdx in [08e334c](https://github.com/jdx/mise/commit/08e334cb1209471d9c18b289473925ff0931053f)\n\n### New Contributors\n\n- @betaboon made their first contribution in [#4296](https://github.com/jdx/mise/pull/4296)\n- @ldrouard made their first contribution in [#4456](https://github.com/jdx/mise/pull/4456)\n- @qianlongzt made their first contribution in [#4409](https://github.com/jdx/mise/pull/4409)\n- @wlmitch made their first contribution in [#4512](https://github.com/jdx/mise/pull/4512)\n- @carldaws made their first contribution in [#4497](https://github.com/jdx/mise/pull/4497)\n- @ZeroAurora made their first contribution in [#4476](https://github.com/jdx/mise/pull/4476)\n\n## [2025.2.7](https://github.com/jdx/mise/compare/v2025.2.6..v2025.2.7) - 2025-02-19\n\n### 🚀 Features\n\n- **(registry)** add lychee to registry by @eread in [#4181](https://github.com/jdx/mise/pull/4181)\n- Install latest nominated zig from https://machengine.org/zig/index.json by @tamadamas in [#4451](https://github.com/jdx/mise/pull/4451)\n\n### 🐛 Bug Fixes\n\n- **(cli/run)** inherit stdio by --raw even when redactions are enabled by @risu729 in [#4446](https://github.com/jdx/mise/pull/4446)\n- **(task)** Running programs on windows without cmd.exe by @NavyD in [#4459](https://github.com/jdx/mise/pull/4459)\n- bugs with grep in tar_supports_zstd in mise.run script by @glasser in [#4453](https://github.com/jdx/mise/pull/4453)\n\n### 📚 Documentation\n\n- fix watch files hook example by @rsyring in [#4427](https://github.com/jdx/mise/pull/4427)\n- Fix run-on sentence by @henrebotha in [#4429](https://github.com/jdx/mise/pull/4429)\n- mention hk by @jdx in [1a58e86](https://github.com/jdx/mise/commit/1a58e86ce2ce16d848755df8feccf514000053fd)\n- discord link by @jdx in [b586085](https://github.com/jdx/mise/commit/b58608521cccee812adaa642145f061ccbcbac43)\n- Add a section on how to use environment variables by @hverlin in [#4435](https://github.com/jdx/mise/pull/4435)\n- Update installation for archLinux by @Nicknamely in [#4449](https://github.com/jdx/mise/pull/4449)\n- Fix typo in getting-started by @alefteris in [#4448](https://github.com/jdx/mise/pull/4448)\n\n### 🧪 Testing\n\n- always set experimental = true in tests by @jdx in [#4443](https://github.com/jdx/mise/pull/4443)\n\n### Chore\n\n- fixed new clippy lints by @jdx in [#4463](https://github.com/jdx/mise/pull/4463)\n\n### New Contributors\n\n- @alefteris made their first contribution in [#4448](https://github.com/jdx/mise/pull/4448)\n- @tamadamas made their first contribution in [#4451](https://github.com/jdx/mise/pull/4451)\n- @Nicknamely made their first contribution in [#4449](https://github.com/jdx/mise/pull/4449)\n- @eread made their first contribution in [#4181](https://github.com/jdx/mise/pull/4181)\n- @rsyring made their first contribution in [#4427](https://github.com/jdx/mise/pull/4427)\n\n## [2025.2.6](https://github.com/jdx/mise/compare/v2025.2.5..v2025.2.6) - 2025-02-16\n\n### 🚀 Features\n\n- add devcontainer generator by @acesyde in [#4355](https://github.com/jdx/mise/pull/4355)\n- added hk by @jdx in [#4422](https://github.com/jdx/mise/pull/4422)\n\n### 🐛 Bug Fixes\n\n- short flag with value and var=#true bug by @jdx in [#4419](https://github.com/jdx/mise/pull/4419)\n- regression with env overriding by @jdx in [#4421](https://github.com/jdx/mise/pull/4421)\n\n### 📚 Documentation\n\n- **(shims)** clarify `activate` only removes shims from `PATH` by @risu729 in [#4418](https://github.com/jdx/mise/pull/4418)\n- Update shims page by @hverlin in [#4414](https://github.com/jdx/mise/pull/4414)\n\n## [2025.2.5](https://github.com/jdx/mise/compare/v2025.2.4..v2025.2.5) - 2025-02-16\n\n### 🐛 Bug Fixes\n\n- properly replace non set flags with \"false\" by @IxDay in [#4410](https://github.com/jdx/mise/pull/4410)\n- path env order with subdirs by @jdx in [#4412](https://github.com/jdx/mise/pull/4412)\n\n### ◀️ Revert\n\n- \"feat: set usage arguments and flags as environment variables for toml tasks\" by @jdx in [#4413](https://github.com/jdx/mise/pull/4413)\n\n## [2025.2.4](https://github.com/jdx/mise/compare/v2025.2.3..v2025.2.4) - 2025-02-14\n\n### 🚀 Features\n\n- **(registry)** add e1s by @kiwamizamurai in [#4363](https://github.com/jdx/mise/pull/4363)\n- **(registry)** add 'marksman' via 'aqua:artempyanykh/marksman' backend by @iamoeg in [#4357](https://github.com/jdx/mise/pull/4357)\n- use `machengine.org` for downloading nominated zig versions by @hadronomy in [#4356](https://github.com/jdx/mise/pull/4356)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** apply override of version_prefix by @risu729 in [#4338](https://github.com/jdx/mise/pull/4338)\n- **(env_directive)** apply redactions only to env with redact by @risu729 in [#4388](https://github.com/jdx/mise/pull/4388)\n- **(hook_env)** don't exit early if watching files are deleted by @risu729 in [#4390](https://github.com/jdx/mise/pull/4390)\n- **(rubygems_plugin)** Replace which ruby check for Windows compatibility by @genskyff in [#4358](https://github.com/jdx/mise/pull/4358)\n- lowercase desired shim names by @KevSlashNull in [#4333](https://github.com/jdx/mise/pull/4333)\n- allow cosign opts to be empty in aqua by @IxDay in [#4396](https://github.com/jdx/mise/pull/4396)\n\n### 📚 Documentation\n\n- update Fedora install for dnf5 by @rkben in [#4387](https://github.com/jdx/mise/pull/4387)\n- fix links to idiomatic version file option by @pietrodn in [#4382](https://github.com/jdx/mise/pull/4382)\n- add mise bootstrap example in CI docs by @hverlin in [#4351](https://github.com/jdx/mise/pull/4351)\n- Update link in comparison-to-asdf.md by @hverlin in [#4401](https://github.com/jdx/mise/pull/4401)\n\n### 📦️ Dependency Updates\n\n- update rust crate bzip2 to v0.5.1 by @renovate[bot] in [#4392](https://github.com/jdx/mise/pull/4392)\n- update rust crate built to v0.7.6 by @renovate[bot] in [#4391](https://github.com/jdx/mise/pull/4391)\n\n### Chore\n\n- issue closer by @jdx in [bee1f55](https://github.com/jdx/mise/commit/bee1f5557b829b9a637a28af90b519fdfa74b8dd)\n\n### New Contributors\n\n- @iamoeg made their first contribution in [#4357](https://github.com/jdx/mise/pull/4357)\n- @hadronomy made their first contribution in [#4356](https://github.com/jdx/mise/pull/4356)\n- @pietrodn made their first contribution in [#4382](https://github.com/jdx/mise/pull/4382)\n- @genskyff made their first contribution in [#4358](https://github.com/jdx/mise/pull/4358)\n- @kiwamizamurai made their first contribution in [#4363](https://github.com/jdx/mise/pull/4363)\n- @rkben made their first contribution in [#4387](https://github.com/jdx/mise/pull/4387)\n- @IxDay made their first contribution in [#4396](https://github.com/jdx/mise/pull/4396)\n- @KevSlashNull made their first contribution in [#4333](https://github.com/jdx/mise/pull/4333)\n\n## [2025.2.3](https://github.com/jdx/mise/compare/v2025.2.2..v2025.2.3) - 2025-02-09\n\n### ◀️ Revert\n\n- Revert \"feat: add support for idiomatic go.mod file \" by @jdx in [7fc9beb](https://github.com/jdx/mise/commit/7fc9bebd02abfee4b622a211b86c516df9bd4f6d)\n\n## [2025.2.2](https://github.com/jdx/mise/compare/v2025.2.1..v2025.2.2) - 2025-02-08\n\n### 🚀 Features\n\n- **(registry)** add jd by @risu729 in [#4318](https://github.com/jdx/mise/pull/4318)\n- **(registry)** add jc by @risu729 in [#4317](https://github.com/jdx/mise/pull/4317)\n- **(registry)** Add qsv cli by @vjda in [#4334](https://github.com/jdx/mise/pull/4334)\n- add support for idiomatic go.mod file by @roele in [#4312](https://github.com/jdx/mise/pull/4312)\n- add -g short version for unuse cmd by @kimle in [#4330](https://github.com/jdx/mise/pull/4330)\n- add git remote task provider by @acesyde in [#4233](https://github.com/jdx/mise/pull/4233)\n- set usage arguments and flags as environment variables for toml tasks by @gturi in [#4159](https://github.com/jdx/mise/pull/4159)\n\n### 🐛 Bug Fixes\n\n- **(aqua)** trim prefix before comparing versions by @risu729 in [#4340](https://github.com/jdx/mise/pull/4340)\n- wrong config file type for rust-toolchain.toml files by @roele in [#4321](https://github.com/jdx/mise/pull/4321)\n\n### 🚜 Refactor\n\n- **(registry)** use aqua for yq by @scop in [#4326](https://github.com/jdx/mise/pull/4326)\n\n### 📚 Documentation\n\n- **(schema)** fix description of task.dir default by @risu729 in [#4324](https://github.com/jdx/mise/pull/4324)\n- Add PowerShell example by @jahanson in [#3857](https://github.com/jdx/mise/pull/3857)\n- Include \"A Mise guide for Swift developers\" by @pepicrft in [#4329](https://github.com/jdx/mise/pull/4329)\n- Update documentation for core tools by @hverlin in [#4341](https://github.com/jdx/mise/pull/4341)\n- Update vitepress to fix search by @hverlin in [#4342](https://github.com/jdx/mise/pull/4342)\n\n### Chore\n\n- **(bun.lock)** migrate bun lockfiles to text-based by @risu729 in [#4319](https://github.com/jdx/mise/pull/4319)\n\n### New Contributors\n\n- @vjda made their first contribution in [#4334](https://github.com/jdx/mise/pull/4334)\n- @kimle made their first contribution in [#4330](https://github.com/jdx/mise/pull/4330)\n- @pepicrft made their first contribution in [#4329](https://github.com/jdx/mise/pull/4329)\n- @jahanson made their first contribution in [#3857](https://github.com/jdx/mise/pull/3857)\n\n## [2025.2.1](https://github.com/jdx/mise/compare/v2025.2.0..v2025.2.1) - 2025-02-03\n\n### Chore\n\n- fix winget releaser job by @jdx in [e67c653](https://github.com/jdx/mise/commit/e67c653de35ff83d4ee280bf5cb2381741a2108e)\n\n## [2025.2.0](https://github.com/jdx/mise/compare/v2025.1.17..v2025.2.0) - 2025-02-02\n\n### 🚀 Features\n\n- **(registry)** add kwokctl by @mangkoran in [#4282](https://github.com/jdx/mise/pull/4282)\n- add biome to registry by @kit494way in [#4283](https://github.com/jdx/mise/pull/4283)\n- add gittool/gitversion by @acesyde in [#4289](https://github.com/jdx/mise/pull/4289)\n\n### 📚 Documentation\n\n- add filtering support to registry docs page by @roele in [#4285](https://github.com/jdx/mise/pull/4285)\n- improve registry filtering performance by @roele in [#4287](https://github.com/jdx/mise/pull/4287)\n- fix registry table rendering for mobile by @roele in [#4288](https://github.com/jdx/mise/pull/4288)\n\n### Chore\n\n- updated deps by @jdx in [#4290](https://github.com/jdx/mise/pull/4290)\n- do not run autofix on renovate PRs by @jdx in [41c5ce4](https://github.com/jdx/mise/commit/41c5ce4c6581f856bf0d756e3fe99ec2fae2e7bd)\n\n### New Contributors\n\n- @ELLIOTTCABLE made their first contribution in [#4280](https://github.com/jdx/mise/pull/4280)\n\n## [2025.1.17](https://github.com/jdx/mise/compare/v2025.1.16..v2025.1.17) - 2025-01-31\n\n### 🚀 Features\n\n- **(registry)** use aqua for duckdb by @mangkoran in [#4270](https://github.com/jdx/mise/pull/4270)\n\n### 🐛 Bug Fixes\n\n- mise does not operate well under Git Bash on Windows by @roele in [#4048](https://github.com/jdx/mise/pull/4048)\n- mise rm removes/reports wrong version of tool by @roele in [#4272](https://github.com/jdx/mise/pull/4272)\n\n### 📚 Documentation\n\n- Update python documentation by @hverlin in [#4260](https://github.com/jdx/mise/pull/4260)\n- fix postinstall typo in nodejs cookbook by @arafays in [#4251](https://github.com/jdx/mise/pull/4251)\n- Fix typo by @henrebotha in [#4277](https://github.com/jdx/mise/pull/4277)\n\n### Hooks.md\n\n- MISE_PROJECT_DIR -> MISE_PROJECT_ROOT by @jubr in [#4269](https://github.com/jdx/mise/pull/4269)\n\n### New Contributors\n\n- @mangkoran made their first contribution in [#4270](https://github.com/jdx/mise/pull/4270)\n- @jubr made their first contribution in [#4269](https://github.com/jdx/mise/pull/4269)\n- @arafays made their first contribution in [#4251](https://github.com/jdx/mise/pull/4251)\n\n## [2025.1.16](https://github.com/jdx/mise/compare/v2025.1.15..v2025.1.16) - 2025-01-29\n\n### 🚀 Features\n\n- **(registry)** add duckdb by @swfz in [#4248](https://github.com/jdx/mise/pull/4248)\n\n### 🐛 Bug Fixes\n\n- Swift on Ubuntu 24.04 arm64 generates the incorrect download URL by @spyder-ian in [#4235](https://github.com/jdx/mise/pull/4235)\n- Do not attempt to parse directories by @adamcohen2 in [#4256](https://github.com/jdx/mise/pull/4256)\n- path option should take precedence over global configuration by @roele in [#4249](https://github.com/jdx/mise/pull/4249)\n\n### 📚 Documentation\n\n- Add devtools.fm episode about mise to external-resources.md by @CanRau in [#4253](https://github.com/jdx/mise/pull/4253)\n- Update sections about idiomatic version files by @hverlin in [#4252](https://github.com/jdx/mise/pull/4252)\n\n### Chore\n\n- make self_update optional by @jdx in [#4230](https://github.com/jdx/mise/pull/4230)\n- added some defaul reqwest features by @jdx in [#4232](https://github.com/jdx/mise/pull/4232)\n\n### New Contributors\n\n- @adamcohen2 made their first contribution in [#4256](https://github.com/jdx/mise/pull/4256)\n- @CanRau made their first contribution in [#4253](https://github.com/jdx/mise/pull/4253)\n- @spyder-ian made their first contribution in [#4235](https://github.com/jdx/mise/pull/4235)\n\n## [2025.1.15](https://github.com/jdx/mise/compare/v2025.1.14..v2025.1.15) - 2025-01-26\n\n### 🚀 Features\n\n- add http cache by @acesyde in [#4160](https://github.com/jdx/mise/pull/4160)\n- expose `test-tool` command by @jdx in [#4224](https://github.com/jdx/mise/pull/4224)\n\n### 🐛 Bug Fixes\n\n- elixir installation failed by @roele in [#4144](https://github.com/jdx/mise/pull/4144)\n- re-run tasks when files removed or permissions change by @jdx in [#4223](https://github.com/jdx/mise/pull/4223)\n\n### 🚜 Refactor\n\n- use builder pattern by @acesyde in [#4220](https://github.com/jdx/mise/pull/4220)\n\n### 📚 Documentation\n\n- **(how-i-use-mise)** switch to discussion by @risu729 in [#4225](https://github.com/jdx/mise/pull/4225)\n- add hint about environment variable parsing by @roele in [#4219](https://github.com/jdx/mise/pull/4219)\n\n### Chore\n\n- added vscode workspace by @jdx in [a0d181f](https://github.com/jdx/mise/commit/a0d181f8d60270d09d06156ebc500a2fa85f74db)\n- switch from git2 to gix by @jdx in [#4226](https://github.com/jdx/mise/pull/4226)\n- remove git2 from built by @jdx in [#4227](https://github.com/jdx/mise/pull/4227)\n- use mise-plugins/mise-jib by @jdx in [#4228](https://github.com/jdx/mise/pull/4228)\n\n### New Contributors\n\n- @vgnh made their first contribution in [#4216](https://github.com/jdx/mise/pull/4216)\n\n## [2025.1.14](https://github.com/jdx/mise/compare/v2025.1.13..v2025.1.14) - 2025-01-24\n\n### 🚀 Features\n\n- **(registry)** add gron by @MontakOleg in [#4204](https://github.com/jdx/mise/pull/4204)\n\n### 🐛 Bug Fixes\n\n- spurious semver warning on `mise outdated` by @jdx in [#4199](https://github.com/jdx/mise/pull/4199)\n\n### Chore\n\n- lint issue in Dockerfile by @jdx in [47ad5d6](https://github.com/jdx/mise/commit/47ad5d67890188478cf8c8f2e6796b6752546e6c)\n- fix some typos in markdown file by @chuangjinglu in [#4198](https://github.com/jdx/mise/pull/4198)\n- pin aws-cli by @jdx in [f7311fd](https://github.com/jdx/mise/commit/f7311fd8fc85b6920c5a484862865adc9ef7261d)\n- use arm64 runners for docker by @jdx in [#4200](https://github.com/jdx/mise/pull/4200)\n\n### New Contributors\n\n- @chuangjinglu made their first contribution in [#4198](https://github.com/jdx/mise/pull/4198)\n\n## [2025.1.13](https://github.com/jdx/mise/compare/v2025.1.12..v2025.1.13) - 2025-01-24\n\n### Chore\n\n- fixing aws-cli in release.sh by @jdx in [5b4a65a](https://github.com/jdx/mise/commit/5b4a65a84e07141de9ed69798921b4b0ef69aa02)\n- fixing aws-cli in release.sh by @jdx in [4c67db5](https://github.com/jdx/mise/commit/4c67db59ecfb55eb724dc05bca7eb7281a625929)\n\n## [2025.1.12](https://github.com/jdx/mise/compare/v2025.1.11..v2025.1.12) - 2025-01-24\n\n### Chore\n\n- setup mise for release task by @jdx in [78d3dfb](https://github.com/jdx/mise/commit/78d3dfb164776cfb39a1920485c21fcd6ecd3ebe)\n\n## [2025.1.11](https://github.com/jdx/mise/compare/v2025.1.10..v2025.1.11) - 2025-01-23\n\n### Chore\n\n- pin aws-cli by @jdx in [ca16daf](https://github.com/jdx/mise/commit/ca16daf5e5dbb9159d853570528087b24f63500b)\n\n## [2025.1.10](https://github.com/jdx/mise/compare/v2025.1.9..v2025.1.10) - 2025-01-23\n\n### 🚀 Features\n\n- **(registry)** use aqua for periphery by @MontakOleg in [#4157](https://github.com/jdx/mise/pull/4157)\n- split remote task by @acesyde in [#4156](https://github.com/jdx/mise/pull/4156)\n\n### 🐛 Bug Fixes\n\n- **(docs)** environment variable MISE_OVERRIDE_TOOL_VERSIONS_FILENAME should be plural by @roele in [#4183](https://github.com/jdx/mise/pull/4183)\n- completions were missing non-asdf tools by @jdx in [55b31a4](https://github.com/jdx/mise/commit/55b31a452b807ada4e2ba40c8b5588b77b79642e)\n- broken link for `/tasks/task-configuration` by @134130 in [#4155](https://github.com/jdx/mise/pull/4155)\n- whitespace in mise.run script by @jdx in [#4153](https://github.com/jdx/mise/pull/4153)\n- confusing error in fish_command_not_found by @MrGreenTea in [#4162](https://github.com/jdx/mise/pull/4162)\n- use correct python path for venv creation in windows by @tisoft in [#4164](https://github.com/jdx/mise/pull/4164)\n\n### 📚 Documentation\n\n- neovim cookbook by @EricDriussi in [#4161](https://github.com/jdx/mise/pull/4161)\n\n### 🧪 Testing\n\n- fix a couple of tool tests by @jdx in [#4186](https://github.com/jdx/mise/pull/4186)\n\n### Chore\n\n- added issue auto-closer by @jdx in [3c831c1](https://github.com/jdx/mise/commit/3c831c19a644fbb2f393f969ebaa5137f9415793)\n\n### New Contributors\n\n- @tisoft made their first contribution in [#4164](https://github.com/jdx/mise/pull/4164)\n- @MrGreenTea made their first contribution in [#4162](https://github.com/jdx/mise/pull/4162)\n- @EricDriussi made their first contribution in [#4161](https://github.com/jdx/mise/pull/4161)\n- @134130 made their first contribution in [#4155](https://github.com/jdx/mise/pull/4155)\n\n## [2025.1.9](https://github.com/jdx/mise/compare/v2025.1.8..v2025.1.9) - 2025-01-17\n\n### 🚀 Features\n\n- **(aqua)** pass --verbose flag down to cosign and added aqua.cosign_extra_args setting by @jdx in [#4148](https://github.com/jdx/mise/pull/4148)\n- **(doctor)** display redacted github token by @jdx in [#4149](https://github.com/jdx/mise/pull/4149)\n\n### 🐛 Bug Fixes\n\n- **(ruby)** remove ruby/gem tests by @jdx in [#4130](https://github.com/jdx/mise/pull/4130)\n- Fixes fish_command_not_found glob error by @halostatue in [#4133](https://github.com/jdx/mise/pull/4133)\n- completions for `mise use` by @jdx in [#4147](https://github.com/jdx/mise/pull/4147)\n\n### 📦️ Dependency Updates\n\n- update dependency bun to v1.1.44 by @renovate[bot] in [#4134](https://github.com/jdx/mise/pull/4134)\n\n### Chore\n\n- add install.sh.sig to releases by @jdx in [1b6ea86](https://github.com/jdx/mise/commit/1b6ea8644edcf3a6ff68fc6d511622c44f1f1f9a)\n\n### New Contributors\n\n- @halostatue made their first contribution in [#4133](https://github.com/jdx/mise/pull/4133)\n\n## [2025.1.8](https://github.com/jdx/mise/compare/v2025.1.7..v2025.1.8) - 2025-01-17\n\n### 🚀 Features\n\n- upgrade ubi by @jdx in [#4078](https://github.com/jdx/mise/pull/4078)\n- enable erlang for Windows by @roele in [#4128](https://github.com/jdx/mise/pull/4128)\n- use aqua for opentofu by @jdx in [#4129](https://github.com/jdx/mise/pull/4129)\n\n### 🐛 Bug Fixes\n\n- **(spm)** install from annotated tag by @MontakOleg in [#4120](https://github.com/jdx/mise/pull/4120)\n- Fixes infinite loop in auto install not found bash function by @bnorick in [#4094](https://github.com/jdx/mise/pull/4094)\n- installing with empty version fails by @roele in [#4123](https://github.com/jdx/mise/pull/4123)\n\n### 📚 Documentation\n\n- correct link to gem.rs source by @petrblaho in [#4119](https://github.com/jdx/mise/pull/4119)\n- fix {{config_root}} got interpolated by vitepress by @peter50216 in [#4122](https://github.com/jdx/mise/pull/4122)\n\n### Chore\n\n- remove minisign from mise.toml by @jdx in [b115ba9](https://github.com/jdx/mise/commit/b115ba962fce4e63e0d6ce85f41704f302ef3e9a)\n\n### New Contributors\n\n- @peter50216 made their first contribution in [#4122](https://github.com/jdx/mise/pull/4122)\n- @petrblaho made their first contribution in [#4119](https://github.com/jdx/mise/pull/4119)\n\n## [2025.1.7](https://github.com/jdx/mise/compare/v2025.1.6..v2025.1.7) - 2025-01-15\n\n### 🚀 Features\n\n- **(registry)** add gup by @scop in [#4107](https://github.com/jdx/mise/pull/4107)\n- **(registry)** add aqua and cmdx by @scop in [#4106](https://github.com/jdx/mise/pull/4106)\n- use aqua for eza on linux by @jdx in [#4075](https://github.com/jdx/mise/pull/4075)\n- allow to specify Rust profile by @roele in [#4101](https://github.com/jdx/mise/pull/4101)\n\n### 🐛 Bug Fixes\n\n- use vars in [env] templates by @hverlin in [#4100](https://github.com/jdx/mise/pull/4100)\n- panic when directory name contains japanese characters by @roele in [#4104](https://github.com/jdx/mise/pull/4104)\n- incorrect config_root for project/.mise/config.toml by @roele in [#4108](https://github.com/jdx/mise/pull/4108)\n\n### 🚜 Refactor\n\n- **(registry)** alias protobuf to protoc by @scop in [#4087](https://github.com/jdx/mise/pull/4087)\n- **(registry)** use aqua for go-getter and kcl by @scop in [#4088](https://github.com/jdx/mise/pull/4088)\n- **(registry)** use aqua for powerline-go by @scop in [#4105](https://github.com/jdx/mise/pull/4105)\n\n### 📚 Documentation\n\n- clean up activation instructions by @jdx in [e235c74](https://github.com/jdx/mise/commit/e235c74daa8f5e5f9e1bb89c70a6cff96c08956e)\n- correct urls for crawler by @jdx in [21cb77b](https://github.com/jdx/mise/commit/21cb77b1f79a57e6ebd3fec367bd5b223239a3ed)\n- added sitemap meta tag by @jdx in [033aa14](https://github.com/jdx/mise/commit/033aa149e8b7a45ea750c09c31438709420214c8)\n\n## [2025.1.6](https://github.com/jdx/mise/compare/v2025.1.5..v2025.1.6) - 2025-01-12\n\n### 🐛 Bug Fixes\n\n- Panic when run without arguments with bootstrapped script by @jdx in [#4065](https://github.com/jdx/mise/pull/4065)\n\n### 🚜 Refactor\n\n- use better rust syntax by @jdx in [#4072](https://github.com/jdx/mise/pull/4072)\n\n### 📚 Documentation\n\n- fix TOML-based Tasks usage spec example by @gturi in [#4067](https://github.com/jdx/mise/pull/4067)\n- eza by @jdx in [5a80cbf](https://github.com/jdx/mise/commit/5a80cbf9e0b37be800bc6f6f0404bcf86cbe3bd9)\n- removed bit about verifying with asdf by @jdx in [d505486](https://github.com/jdx/mise/commit/d505486fbbe49af0f7bf6029569812441c1e3fdc)\n- added more getting started installers by @jdx in [b310e11](https://github.com/jdx/mise/commit/b310e118b00d2b0a64cf2d423d20ece6dc9692f6)\n- clean up activation instructions by @jdx in [3df60dd](https://github.com/jdx/mise/commit/3df60dd9cbecf3086b1755d4e397159379d27b27)\n- clean up activation instructions by @jdx in [8ab4bce](https://github.com/jdx/mise/commit/8ab4bcef77c4bc1e07951dbb8b5787df4a4b15bf)\n- clean up activation instructions by @jdx in [d4a67e8](https://github.com/jdx/mise/commit/d4a67e8ec72fed064cc776ab643f41da1ae01caa)\n- clean up activation instructions by @jdx in [d208418](https://github.com/jdx/mise/commit/d208418a5f63803185c4aa5f06afecd9e8832496)\n- clean up activation instructions by @jdx in [b9f581d](https://github.com/jdx/mise/commit/b9f581d644295f372eb0cd026560e9c97dcb8091)\n\n### New Contributors\n\n- @gturi made their first contribution in [#4067](https://github.com/jdx/mise/pull/4067)\n\n## [2025.1.5](https://github.com/jdx/mise/compare/v2025.1.4..v2025.1.5) - 2025-01-11\n\n### 🚀 Features\n\n- added gdu and dua to registry by @sassdavid in [#4052](https://github.com/jdx/mise/pull/4052)\n- added prefix-dev/pixi by @jdx in [#4056](https://github.com/jdx/mise/pull/4056)\n- added `mise cfg --tracked-configs` by @jdx in [#4059](https://github.com/jdx/mise/pull/4059)\n- added `mise version --json` flag by @jdx in [#4061](https://github.com/jdx/mise/pull/4061)\n- added `mise ls --prunable` flag by @jdx in [#4062](https://github.com/jdx/mise/pull/4062)\n\n### 🐛 Bug Fixes\n\n- switch jib back to asdf by @jdx in [#4055](https://github.com/jdx/mise/pull/4055)\n- `mise unuse` bug not pruning if not in config file by @jdx in [#4058](https://github.com/jdx/mise/pull/4058)\n\n### 📚 Documentation\n\n- explain pipx better by @jdx in [42dcb3b](https://github.com/jdx/mise/commit/42dcb3bc5a6547d3d148c391ceccfd9228e34669)\n\n### 🧪 Testing\n\n- added test case for `mise rm` by @jdx in [f7511b6](https://github.com/jdx/mise/commit/f7511b696c2ada7af878074e89b0dfc1edb73197)\n\n### New Contributors\n\n- @sassdavid made their first contribution in [#4052](https://github.com/jdx/mise/pull/4052)\n\n## [2025.1.4](https://github.com/jdx/mise/compare/v2025.1.3..v2025.1.4) - 2025-01-10\n\n### 🚀 Features\n\n- update JSON output for task info/ls by @hverlin in [#4034](https://github.com/jdx/mise/pull/4034)\n- **breaking** bump usage to 2.x by @jdx in [#4049](https://github.com/jdx/mise/pull/4049)\n\n### 🐛 Bug Fixes\n\n- ignore github releases marked as draft by @jdx in [#4030](https://github.com/jdx/mise/pull/4030)\n- `mise run` shorthand with tasks that have an extension by @jdx in [#4029](https://github.com/jdx/mise/pull/4029)\n- use consistent casing by @jdx in [a4d4133](https://github.com/jdx/mise/commit/a4d41338139355b0dd86a068fd89790eb7e34584)\n- support latest ansible packages by @jdx in [#4045](https://github.com/jdx/mise/pull/4045)\n- use go backend for goconvey/ginkgo by @jdx in [#4047](https://github.com/jdx/mise/pull/4047)\n- Improve fig spec with better generators by @miguelmig in [#3762](https://github.com/jdx/mise/pull/3762)\n\n### 📚 Documentation\n\n- set prose-wrap with prettier by @jdx in [#4038](https://github.com/jdx/mise/pull/4038)\n- Fix \"Example of a NodeJS file task with arguments\" by @highb in [#4046](https://github.com/jdx/mise/pull/4046)\n\n### 🧪 Testing\n\n- disable some non-working plugins by @jdx in [106ee40](https://github.com/jdx/mise/commit/106ee40b463923bb5c6444e0c0127dabc502d9ee)\n- remove test for flarectl by @jdx in [a63b449](https://github.com/jdx/mise/commit/a63b44910d55ad2cdc801a472f0c196c605cce25)\n\n### ◀️ Revert\n\n- Revert \"docs: set prose-wrap with prettier \" by @jdx in [065dd8f](https://github.com/jdx/mise/commit/065dd8fa917b6097fb168b631b506455af3e1d28)\n\n### Chore\n\n- added `cargo check` to pre-commit by @jdx in [73eb25a](https://github.com/jdx/mise/commit/73eb25a88bbfe1b979bb5483ca3c81a689be184f)\n- fix release-plz pr creation by @jdx in [8299c6b](https://github.com/jdx/mise/commit/8299c6b943119ffda94d18445c5b789948b6f9c0)\n- use -q in pre-commit:check by @jdx in [099b2d8](https://github.com/jdx/mise/commit/099b2d88d3ed31ace30c67be816170dc50f87b6d)\n- fix release-plz pr creation by @jdx in [c2accc5](https://github.com/jdx/mise/commit/c2accc5f7192202d0a8249ae7f3ab0ea7f100e1b)\n- make prettier/pre-commit much faster by @jdx in [#4036](https://github.com/jdx/mise/pull/4036)\n- fix release-plz edit command by @jdx in [86b5816](https://github.com/jdx/mise/commit/86b5816660f5a13d45c1795132a29e881645e271)\n\n## [2025.1.3](https://github.com/jdx/mise/compare/v2025.1.2..v2025.1.3) - 2025-01-09\n\n### 🐛 Bug Fixes\n\n- **(rust)** respect RUSTUP_HOME/CARGO_HOME by @jdx in [#4026](https://github.com/jdx/mise/pull/4026)\n- mise fails to install kubectl on windows from aqua registry by @roele in [#4006](https://github.com/jdx/mise/pull/4006)\n- aliases with aqua by @jdx in [#4007](https://github.com/jdx/mise/pull/4007)\n- issue with enter hook and subdirs by @jdx in [#4008](https://github.com/jdx/mise/pull/4008)\n- allow using depends and depends_post on separate tasks by @jdx in [#4010](https://github.com/jdx/mise/pull/4010)\n- mise fails to install kubectl on windows from aqua registry by @roele in [#4024](https://github.com/jdx/mise/pull/4024)\n\n### 📚 Documentation\n\n- Add default description to github token link by @hverlin in [#4019](https://github.com/jdx/mise/pull/4019)\n- fix source code links by @jdx in [#4025](https://github.com/jdx/mise/pull/4025)\n\n### Chore\n\n- make pre-commit faster by @jdx in [70dfdd0](https://github.com/jdx/mise/commit/70dfdd0b874a5292b4b20fa72c9c341a13900bde)\n- added commented out paths config by @jdx in [c1f25ac](https://github.com/jdx/mise/commit/c1f25ac4cdaf74219d700fcaf37d3341971a3120)\n\n## [2025.1.2](https://github.com/jdx/mise/compare/v2025.1.1..v2025.1.2) - 2025-01-08\n\n### 🚀 Features\n\n- migrate asdf plugins to aqua/ubi by @jdx in [#3962](https://github.com/jdx/mise/pull/3962)\n- migrate asdf plugins to aqua/ubi by @jdx in [#3978](https://github.com/jdx/mise/pull/3978)\n- migrate asdf plugins to aqua/ubi by @jdx in [#3991](https://github.com/jdx/mise/pull/3991)\n- replace asdf-spark plugin with mise-spark plugin by @benberryallwood in [#3994](https://github.com/jdx/mise/pull/3994)\n- add kubectx/kubens to registry by @roele in [#3992](https://github.com/jdx/mise/pull/3992)\n- added ktlint from aqua by @jdx in [#4004](https://github.com/jdx/mise/pull/4004)\n\n### 🐛 Bug Fixes\n\n- **(schema)** fix task sources and outputs schema by @risu729 in [#3988](https://github.com/jdx/mise/pull/3988)\n- **(schema)** update task schema by @risu729 in [#3999](https://github.com/jdx/mise/pull/3999)\n- correct age keyname by @jdx in [e28c293](https://github.com/jdx/mise/commit/e28c293bc5a241b043d0b72ec9aa0559e888f97b)\n- mise install rust failed on windows by @roele in [#3969](https://github.com/jdx/mise/pull/3969)\n- maven-mvnd does not install with aqua by @roele in [#3982](https://github.com/jdx/mise/pull/3982)\n- maven-mvnd does not install with aqua by @roele in [#3993](https://github.com/jdx/mise/pull/3993)\n- use friendly error in `mise run` by @jdx in [#3998](https://github.com/jdx/mise/pull/3998)\n- use task display_name in more places by @hverlin in [#3997](https://github.com/jdx/mise/pull/3997)\n- aqua:apache/spark doesn't work by @roele in [#3995](https://github.com/jdx/mise/pull/3995)\n\n### 📚 Documentation\n\n- style on rustup settings by @jdx in [da91716](https://github.com/jdx/mise/commit/da91716c856b0bb1e8bdf70f9f97f74fe09f15ac)\n- Escape template examples by @henrebotha in [#3987](https://github.com/jdx/mise/pull/3987)\n- update SECURITY.md by @jdx in [6372f10](https://github.com/jdx/mise/commit/6372f101639386e94cd8df400c78962eab1dbdd5)\n\n### 🧪 Testing\n\n- fix test-plugins CI job for ubuntu-24 by @jdx in [492f6ac](https://github.com/jdx/mise/commit/492f6acc99014cb70f97efdd12700ee365a418ea)\n- remove postgres test-plugins test by @jdx in [e93bc80](https://github.com/jdx/mise/commit/e93bc80a780fd0f7b4619af37c3f646dd622bed4)\n\n### Chore\n\n- remove deprecated tar syntax by @jdx in [322735a](https://github.com/jdx/mise/commit/322735a75bef9c602ffcec4d81914662cac00647)\n- fix tar/gzip syntax by @jdx in [cd0a049](https://github.com/jdx/mise/commit/cd0a049ecace47354a931cd364ac2f5915812658)\n- fork remaining asdf plugins to mise-plugins by @jdx in [#3996](https://github.com/jdx/mise/pull/3996)\n\n### New Contributors\n\n- @henrebotha made their first contribution in [#3987](https://github.com/jdx/mise/pull/3987)\n\n## [2025.1.1](https://github.com/jdx/mise/compare/v2025.1.0..v2025.1.1) - 2025-01-06\n\n### 🚀 Features\n\n- add databricks-cli to registry by @benberryallwood in [#3937](https://github.com/jdx/mise/pull/3937)\n- add navi to registry by @kit494way in [#3943](https://github.com/jdx/mise/pull/3943)\n- added allurectl to registry by @MontakOleg in [#3918](https://github.com/jdx/mise/pull/3918)\n- Add setting description to mise settings --json-extended output by @hverlin in [#3919](https://github.com/jdx/mise/pull/3919)\n\n### 🐛 Bug Fixes\n\n- improve mise generate bootstrap by @hverlin in [#3939](https://github.com/jdx/mise/pull/3939)\n- update year in copyright to dynamic with current year by @nexckycort in [#3957](https://github.com/jdx/mise/pull/3957)\n\n### 📚 Documentation\n\n- Fix broken link to environment variables doc by @xcapaldi in [#3938](https://github.com/jdx/mise/pull/3938)\n- Add usage property to mise schema by @hverlin in [#3942](https://github.com/jdx/mise/pull/3942)\n- clarity on relative paths vs config_root in _.path by @glasser in [#3923](https://github.com/jdx/mise/pull/3923)\n\n### 📦️ Dependency Updates\n\n- update rust crate itertools to 0.14 by @renovate[bot] in [#3926](https://github.com/jdx/mise/pull/3926)\n- update rust crate petgraph to 0.7 by @renovate[bot] in [#3927](https://github.com/jdx/mise/pull/3927)\n- update rust crate self_update to 0.42 by @renovate[bot] in [#3931](https://github.com/jdx/mise/pull/3931)\n\n### Chore\n\n- upgrade expr by @jdx in [c06a415](https://github.com/jdx/mise/commit/c06a41544e2cb09912244efe6a8f5bcc03eb24d7)\n- mise up by @jdx in [678f648](https://github.com/jdx/mise/commit/678f6489a9501b32bf3c36771977771d933f2466)\n- cargo-show by @jdx in [69d44fd](https://github.com/jdx/mise/commit/69d44fd064d2fdaae08ff9ea3300a42e560630cd)\n- remove cargo-show dependency by @jdx in [ab8e9e9](https://github.com/jdx/mise/commit/ab8e9e9e429beeb23731c356537525f64bc59b28)\n- remove cargo-show dependency by @jdx in [ca2f89c](https://github.com/jdx/mise/commit/ca2f89c6cd36d828a9eab2884a3f8c9cc1fe2c19)\n- remove cargo-show dependency by @jdx in [82e3390](https://github.com/jdx/mise/commit/82e3390c5fc9a97c942dc407b2073edfcb3974bc)\n- fix release-plz by @jdx in [52ac62a](https://github.com/jdx/mise/commit/52ac62a7d7e8439d32b84c4247ee366c28901863)\n- fix release-plz by @jdx in [dba7044](https://github.com/jdx/mise/commit/dba7044b4dcce808fd4734e9a284ab2174758be0)\n\n### New Contributors\n\n- @nexckycort made their first contribution in [#3957](https://github.com/jdx/mise/pull/3957)\n- @MontakOleg made their first contribution in [#3918](https://github.com/jdx/mise/pull/3918)\n- @kit494way made their first contribution in [#3943](https://github.com/jdx/mise/pull/3943)\n- @benberryallwood made their first contribution in [#3937](https://github.com/jdx/mise/pull/3937)\n- @xcapaldi made their first contribution in [#3938](https://github.com/jdx/mise/pull/3938)\n- @auxesis made their first contribution in [#3914](https://github.com/jdx/mise/pull/3914)\n\n## [2025.1.0](https://github.com/jdx/mise/compare/v2024.12.24..v2025.1.0) - 2025-01-01\n\n### 🚀 Features\n\n- use aqua for gradle by @jdx in [#3903](https://github.com/jdx/mise/pull/3903)\n- added completions to more commands by @jdx in [#3910](https://github.com/jdx/mise/pull/3910)\n\n### 🐛 Bug Fixes\n\n- panic when setting config value by @roele in [#3823](https://github.com/jdx/mise/pull/3823)\n- add hidden settings/task --complete option by @jdx in [#3902](https://github.com/jdx/mise/pull/3902)\n- handle panic when task contains invalid template by @jdx in [#3904](https://github.com/jdx/mise/pull/3904)\n- missing checksums in mise.run script by @jdx in [#3906](https://github.com/jdx/mise/pull/3906)\n- active flag for symlinked tools in `mise ls --json` by @jdx in [#3907](https://github.com/jdx/mise/pull/3907)\n\n### 📚 Documentation\n\n- Update LICENSE by @jdx in [156db11](https://github.com/jdx/mise/commit/156db1130c2757aaaf6e53686148d8b9b0791ae7)\n- updated roadmap by @jdx in [f8916d4](https://github.com/jdx/mise/commit/f8916d4cbd09fbbc8142bf25b4d586e146d19a21)\n\n## [2024.12.24](https://github.com/jdx/mise/compare/v2024.12.23..v2024.12.24) - 2024-12-31\n\n### 🐛 Bug Fixes\n\n- switch back to asdf for gradle by @jdx in [cc88dca](https://github.com/jdx/mise/commit/cc88dca50e8e0dac94dbb83d0ce1ebcfc38a1ec4)\n\n### Chore\n\n- add commented out cleanup of old CLIs by @jdx in [bb7e022](https://github.com/jdx/mise/commit/bb7e022240c0e7019a595d093a33b414119e975f)\n\n## [2024.12.23](https://github.com/jdx/mise/compare/v2024.12.22..v2024.12.23) - 2024-12-30\n\n### 🐛 Bug Fixes\n\n- winget release PRs by @jdx in [9dec542](https://github.com/jdx/mise/commit/9dec542188e731ef357fd74339dd08ac005cb9e3)\n- mise settings unset does not seem to work by @roele in [#3867](https://github.com/jdx/mise/pull/3867)\n- gradle aqua package by @jdx in [#3880](https://github.com/jdx/mise/pull/3880)\n- **breaking** remove `root` env var in tasks by @jdx in [#3884](https://github.com/jdx/mise/pull/3884)\n\n### 📚 Documentation\n\n- syntax in `mise watch` by @jdx in [beab480](https://github.com/jdx/mise/commit/beab48029b3e7a91047012b655f3efe4fd722acf)\n- Update registry link by @bmulholland in [#3864](https://github.com/jdx/mise/pull/3864)\n- clarify shims behaviour by @syhol in [#3881](https://github.com/jdx/mise/pull/3881)\n\n### Chore\n\n- remove unused versioned tarballs from mise.jdx.dev by @jdx in [48f1021](https://github.com/jdx/mise/commit/48f1021048646061e7cd85d9f9969946b00962a6)\n- trim newline in banner by @jdx in [c8f2c90](https://github.com/jdx/mise/commit/c8f2c90111c5d20fe4586d59eb66f3bb2f8cfd9a)\n\n### New Contributors\n\n- @bmulholland made their first contribution in [#3864](https://github.com/jdx/mise/pull/3864)\n\n## [2024.12.22](https://github.com/jdx/mise/compare/v2024.12.21..v2024.12.22) - 2024-12-30\n\n### 🚀 Features\n\n- colorize banner by @jdx in [ad3a5f0](https://github.com/jdx/mise/commit/ad3a5f040013bad046f2ca3abb9eebc941301368)\n\n### 🐛 Bug Fixes\n\n- add `:` escaping for tasks with multiple colons by @eitamal in [#3853](https://github.com/jdx/mise/pull/3853)\n- type issue in docs/JSON schema for python_create_args and uv_create_args by @roele in [#3855](https://github.com/jdx/mise/pull/3855)\n\n### 📚 Documentation\n\n- **(settings)** fix link to precompiled python binaries by @scop in [#3851](https://github.com/jdx/mise/pull/3851)\n- Fix cargo install examples by @orf in [#3862](https://github.com/jdx/mise/pull/3862)\n\n### New Contributors\n\n- @orf made their first contribution in [#3862](https://github.com/jdx/mise/pull/3862)\n- @eitamal made their first contribution in [#3853](https://github.com/jdx/mise/pull/3853)\n\n## [2024.12.21](https://github.com/jdx/mise/compare/v2024.12.20..v2024.12.21) - 2024-12-27\n\n### 🐛 Bug Fixes\n\n- **(python)** force precompiled setting warning message syntax by @scop in [#3850](https://github.com/jdx/mise/pull/3850)\n- zstd detection false positive on MacOS by @roele in [#3845](https://github.com/jdx/mise/pull/3845)\n\n### 📚 Documentation\n\n- fix incorrect examples that were causing 'expected a sequence' error by @ssbarnea in [#3839](https://github.com/jdx/mise/pull/3839)\n\n### 📦️ Dependency Updates\n\n- update rust crate ubi to 0.3 by @renovate[bot] in [#3836](https://github.com/jdx/mise/pull/3836)\n\n## [2024.12.20](https://github.com/jdx/mise/compare/v2024.12.19..v2024.12.20) - 2024-12-25\n\n### 🚀 Features\n\n- **(hugo)** add extended registry from aqua and keep only one registry with all aliases by @kilianpaquier in [#3813](https://github.com/jdx/mise/pull/3813)\n- build erlang with all cores by @jdx in [#3802](https://github.com/jdx/mise/pull/3802)\n- Modify install_rubygems_hook to place plugin in site_ruby directory by @zkhadikov in [#3812](https://github.com/jdx/mise/pull/3812)\n\n### 🐛 Bug Fixes\n\n- do not require \"v\" prefix in mise.run by @jdx in [#3800](https://github.com/jdx/mise/pull/3800)\n- add checksum for macos-x86 by @jdx in [#3815](https://github.com/jdx/mise/pull/3815)\n\n### 📚 Documentation\n\n- Correct link to aqua registry by @jesse-c in [#3803](https://github.com/jdx/mise/pull/3803)\n\n### 🧪 Testing\n\n- skip dotnet if not installed by @jdx in [1a663dd](https://github.com/jdx/mise/commit/1a663dd63e17cc08a961b86b5b0b6a1d7e9b2a1f)\n\n### New Contributors\n\n- @zkhadikov made their first contribution in [#3812](https://github.com/jdx/mise/pull/3812)\n- @kilianpaquier made their first contribution in [#3813](https://github.com/jdx/mise/pull/3813)\n- @jesse-c made their first contribution in [#3803](https://github.com/jdx/mise/pull/3803)\n\n## [2024.12.19](https://github.com/jdx/mise/compare/v2024.12.18..v2024.12.19) - 2024-12-23\n\n### 🚀 Features\n\n- use zstd in mise.run by @jdx in [#3798](https://github.com/jdx/mise/pull/3798)\n- verify zig with minisign by @jdx in [#3793](https://github.com/jdx/mise/pull/3793)\n\n### Chore\n\n- increase tarball compression by @jdx in [a899155](https://github.com/jdx/mise/commit/a8991551bd7c61d1f75a800906d2f718b4bdf7c0)\n- use max threads for zstd compression by @jdx in [a3f792a](https://github.com/jdx/mise/commit/a3f792a1eb0a395c7a82a063b96d30282b6343de)\n- print all tarball sizes by @jdx in [29fbc04](https://github.com/jdx/mise/commit/29fbc04e52c76b16c9a72385ead4edbfaff984fb)\n\n## [2024.12.18](https://github.com/jdx/mise/compare/v2024.12.17..v2024.12.18) - 2024-12-23\n\n### 🚀 Features\n\n- allow dotnet prerelease by @acesyde in [#3753](https://github.com/jdx/mise/pull/3753)\n- added minisign to registry by @jdx in [#3788](https://github.com/jdx/mise/pull/3788)\n- `mise g bootstrap` by @jdx in [#3792](https://github.com/jdx/mise/pull/3792)\n- `mise g bootstrap` by @jdx in [f79ce71](https://github.com/jdx/mise/commit/f79ce719f9121eb6e0e821cf271af306f2a9d6c8)\n\n### 🐛 Bug Fixes\n\n- hide task file extension in completions by @jdx in [#3772](https://github.com/jdx/mise/pull/3772)\n- settings completions by @jdx in [#3787](https://github.com/jdx/mise/pull/3787)\n\n### 📚 Documentation\n\n- update IDE integration page by @hverlin in [#3765](https://github.com/jdx/mise/pull/3765)\n- add powershell sample by @acesyde in [#3771](https://github.com/jdx/mise/pull/3771)\n- add missing dotnet left menu by @acesyde in [#3770](https://github.com/jdx/mise/pull/3770)\n\n### 🧪 Testing\n\n- added stubbed test for https://github.com/jdx/mise/discussions/3783 by @jdx in [f79a3a4](https://github.com/jdx/mise/commit/f79a3a41ebf833d2c49bdc91ae4026c46498d9f7)\n\n### ◀️ Revert\n\n- Revert \"fix: Use arguments for to pass staged filenames to pre-commit task (#…\" by @jdx in [#3791](https://github.com/jdx/mise/pull/3791)\n\n### Chore\n\n- add shell to user-agent by @jdx in [#3786](https://github.com/jdx/mise/pull/3786)\n- sign releases with minisign by @jdx in [#3789](https://github.com/jdx/mise/pull/3789)\n- create minisign secret key by @jdx in [dea4676](https://github.com/jdx/mise/commit/dea4676f53ee4d1a905ae17b004131c6dee3b385)\n- create minisign secret key by @jdx in [ecebebe](https://github.com/jdx/mise/commit/ecebebee13cc20773eaefda706bad4e5ac8cc25f)\n- fix minisign signing by @jdx in [6401ff8](https://github.com/jdx/mise/commit/6401ff84e0dcbdb890dd037aff6fbcf3edc51af5)\n- added install.sh to releases by @jdx in [2946d58](https://github.com/jdx/mise/commit/2946d5864cffb65a1ee1260f3c38070531743854)\n- install minisign by @jdx in [f22272c](https://github.com/jdx/mise/commit/f22272c3838fcb8de0365a4022f8aefc00c46f4c)\n- use ubuntu-24 for release by @jdx in [40a13f8](https://github.com/jdx/mise/commit/40a13f8e7088ba13762178eccc5eb8438bc9ce6b)\n- set minisign pub key by @jdx in [fd6aa1e](https://github.com/jdx/mise/commit/fd6aa1eccf23f97e82ff166ff8950721c236239b)\n- age encrypt minisign key by @jdx in [02c30e2](https://github.com/jdx/mise/commit/02c30e2c9167d3f4bf5ac05a82a43bc82b703123)\n- apt install age by @jdx in [769a088](https://github.com/jdx/mise/commit/769a08875b3651c3edd63fd4387497ce6b16cd4b)\n- switch back to MINISIGN_KEY by @jdx in [66dc8cf](https://github.com/jdx/mise/commit/66dc8cf199adb57c22ac398b3333ba12abaaf106)\n- fix minisign signing by @jdx in [a3f8173](https://github.com/jdx/mise/commit/a3f81738bb4ab0827eb6bfae4a1639c29f29da36)\n- add zst tarballs by @jdx in [85a1192](https://github.com/jdx/mise/commit/85a1192091b7f37ab7c3712e4100c8b43d587857)\n- add zst tarballs by @jdx in [5238124](https://github.com/jdx/mise/commit/5238124dbda89fe32380beab9b64d31cb2cb4ddb)\n- add zst tarballs by @jdx in [2a4d0bf](https://github.com/jdx/mise/commit/2a4d0bf0ee78dfe672d97bc763643300516d5a9b)\n- add zst tarballs by @jdx in [285d777](https://github.com/jdx/mise/commit/285d777b3f33bfa587070b3d15cd904fc83e111f)\n- extract artifact with zstd by @jdx in [ba66d46](https://github.com/jdx/mise/commit/ba66d4659c6d8f3ffa589dacfe402d6988e46d9a)\n\n## [2024.12.17](https://github.com/jdx/mise/compare/v2024.12.16..v2024.12.17) - 2024-12-21\n\n### 🚀 Features\n\n- added a banner to `mise --version` by @jdx in [#3748](https://github.com/jdx/mise/pull/3748)\n- add usage field to tasks by @jdx in [#3746](https://github.com/jdx/mise/pull/3746)\n- added keep-order task output type by @jdx in [#3763](https://github.com/jdx/mise/pull/3763)\n- `replacing` task output type by @jdx in [#3764](https://github.com/jdx/mise/pull/3764)\n- added timed task output type by @jdx in [#3766](https://github.com/jdx/mise/pull/3766)\n\n### 🐛 Bug Fixes\n\n- dotnet backend doc by @acesyde in [#3752](https://github.com/jdx/mise/pull/3752)\n- include full env in toolset tera_ctx by @risu729 in [#3751](https://github.com/jdx/mise/pull/3751)\n- set env vars in task templates by @jdx in [#3758](https://github.com/jdx/mise/pull/3758)\n\n### 📚 Documentation\n\n- update mise-action version in tips and tricks by @scop in [#3749](https://github.com/jdx/mise/pull/3749)\n- Small cookbooks fixes by @hverlin in [#3754](https://github.com/jdx/mise/pull/3754)\n\n### 🧪 Testing\n\n- fix elixir release test by @jdx in [b4f11da](https://github.com/jdx/mise/commit/b4f11dabf7a16a875f9d7ab3ded6a516b481f6f8)\n- add some test cases for env var templates by @jdx in [c938977](https://github.com/jdx/mise/commit/c938977ccc265c9530200e0b19bb0cce5f73ddbb)\n\n### Chore\n\n- updated usage by @jdx in [dad7857](https://github.com/jdx/mise/commit/dad785727c80efeb4bf498995ed5237f6cd94d79)\n\n## [2024.12.16](https://github.com/jdx/mise/compare/v2024.12.15..v2024.12.16) - 2024-12-20\n\n### 🚀 Features\n\n- add dotnet backend by @acesyde in [#3737](https://github.com/jdx/mise/pull/3737)\n- added ignored_config_paths to `mise dr` by @jdx in [#3742](https://github.com/jdx/mise/pull/3742)\n\n### 🐛 Bug Fixes\n\n- **(ruby)** fix Ruby plugin to use `ruby_install` option correctly by @yuhr in [#3732](https://github.com/jdx/mise/pull/3732)\n- `mise run` shorthand with options by @jdx in [#3719](https://github.com/jdx/mise/pull/3719)\n- zig on windows by @jdx in [#3739](https://github.com/jdx/mise/pull/3739)\n- allow using previously defined vars by @jdx in [#3741](https://github.com/jdx/mise/pull/3741)\n- make --help consistent with `mise run` and `mise <task>` by @jdx in [#3723](https://github.com/jdx/mise/pull/3723)\n- use implicit keys for `mise config set` by @jdx in [#3744](https://github.com/jdx/mise/pull/3744)\n\n### 📚 Documentation\n\n- update cookbook by @hverlin in [#3718](https://github.com/jdx/mise/pull/3718)\n- remove reference to deprecated asdf_compat functionality by @jdx in [03a2afb](https://github.com/jdx/mise/commit/03a2afb4f8c738e3b172d0f5e1ca1465bf1d6a5c)\n- describe behavior of `run --output` better by @jdx in [#3740](https://github.com/jdx/mise/pull/3740)\n\n### 📦️ Dependency Updates\n\n- update dependency bun to v1.1.40 by @renovate[bot] in [#3729](https://github.com/jdx/mise/pull/3729)\n\n### Chore\n\n- lint fix by @jdx in [118b8de](https://github.com/jdx/mise/commit/118b8de645712ff1d78c33b9a2c094a1f92c5b20)\n- switch from home -> homedir crate by @jdx in [#3743](https://github.com/jdx/mise/pull/3743)\n\n### New Contributors\n\n- @acesyde made their first contribution in [#3737](https://github.com/jdx/mise/pull/3737)\n- @ssbarnea made their first contribution in [#3735](https://github.com/jdx/mise/pull/3735)\n- @yuhr made their first contribution in [#3732](https://github.com/jdx/mise/pull/3732)\n\n## [2024.12.15](https://github.com/jdx/mise/compare/v2024.12.14..v2024.12.15) - 2024-12-19\n\n### 🚀 Features\n\n- unnest output when `mise run` is nested by @jdx in [#3686](https://github.com/jdx/mise/pull/3686)\n- `mise rm` by @jdx in [#3627](https://github.com/jdx/mise/pull/3627)\n- added *:_default task name by @jdx in [#3690](https://github.com/jdx/mise/pull/3690)\n- `mise run --continue-on-error by @jdx in [#3692](https://github.com/jdx/mise/pull/3692)\n- added .tool-versions -> mise.toml converter by @jdx in [#3693](https://github.com/jdx/mise/pull/3693)\n- get mise sync python --uv to work by @jdx in [#3706](https://github.com/jdx/mise/pull/3706)\n- `mise install-into` by @jdx in [#3711](https://github.com/jdx/mise/pull/3711)\n- added `mise dr --json` by @jdx in [#3715](https://github.com/jdx/mise/pull/3715)\n\n### 🐛 Bug Fixes\n\n- retain \"os\" options in `mise up --bump` by @jdx in [#3688](https://github.com/jdx/mise/pull/3688)\n- unnest task cmd output by @jdx in [#3691](https://github.com/jdx/mise/pull/3691)\n- ensure MISE_PROJECT_ROOT is set with no mise.toml by @jdx in [#3695](https://github.com/jdx/mise/pull/3695)\n- create venv uses absolute tool paths by @syhol in [#3698](https://github.com/jdx/mise/pull/3698)\n- jj repository moved to an organization by @phyrog in [#3703](https://github.com/jdx/mise/pull/3703)\n- disable reverse uv syncing by @jdx in [#3704](https://github.com/jdx/mise/pull/3704)\n- add full tera context to tasks by @jdx in [#3708](https://github.com/jdx/mise/pull/3708)\n- powershell warning by @jdx in [#3713](https://github.com/jdx/mise/pull/3713)\n\n### 🚜 Refactor\n\n- **(registry)** use aqua for more tools by @scop in [#3614](https://github.com/jdx/mise/pull/3614)\n- **(registry)** use aqua:skaji/relocatable-perl for perl by @scop in [#3716](https://github.com/jdx/mise/pull/3716)\n- switch to std::sync::LazyLock by @jdx in [#3707](https://github.com/jdx/mise/pull/3707)\n\n### 📚 Documentation\n\n- fix some broken anchor links by @hverlin in [#3694](https://github.com/jdx/mise/pull/3694)\n- note hooks require `mise activate` by @jdx in [211d3d3](https://github.com/jdx/mise/commit/211d3d3b91c52e418a3e25af4a021da93c64ed4d)\n\n### 🧪 Testing\n\n- fix conduit test for new structure by @jdx in [8691331](https://github.com/jdx/mise/commit/86913318f7705e6cabb999970475c958605219d1)\n\n### Chore\n\n- hide non-functioning docker tasks by @jdx in [40fd3f6](https://github.com/jdx/mise/commit/40fd3f60ebde1d549503a6d9927b79b37622b1b0)\n\n### New Contributors\n\n- @highb made their first contribution in [#3696](https://github.com/jdx/mise/pull/3696)\n\n## [2024.12.14](https://github.com/jdx/mise/compare/v2024.12.13..v2024.12.14) - 2024-12-18\n\n### 🚀 Features\n\n- **(registry)** Add lazydocker by @hverlin in [#3655](https://github.com/jdx/mise/pull/3655)\n- **(registry)** Add btop by @hverlin in [#3667](https://github.com/jdx/mise/pull/3667)\n- Allows control of config_root for global config by @bnorick in [#3670](https://github.com/jdx/mise/pull/3670)\n- allow inserting PATH in env._.source by @jdx in [#3685](https://github.com/jdx/mise/pull/3685)\n\n### 🐛 Bug Fixes\n\n- Can not find the bin files when using python venv on windows by @NavyD in [#3664](https://github.com/jdx/mise/pull/3664)\n- render tasks in task files by @risu729 in [#3666](https://github.com/jdx/mise/pull/3666)\n- dont require run script for `task add` by @jdx in [#3675](https://github.com/jdx/mise/pull/3675)\n- auto-trust on `task add` by @jdx in [#3676](https://github.com/jdx/mise/pull/3676)\n- completions getting wrapped in quotes by @jdx in [#3679](https://github.com/jdx/mise/pull/3679)\n- pass pristine env to tera in final_env by @risu729 in [#3682](https://github.com/jdx/mise/pull/3682)\n- trap panics in task resolving by @jdx in [#3677](https://github.com/jdx/mise/pull/3677)\n\n### 📚 Documentation\n\n- mark new features as experimental by @syhol in [#3659](https://github.com/jdx/mise/pull/3659)\n\n### 🧪 Testing\n\n- add test cases for venv templates by @jdx in [#3683](https://github.com/jdx/mise/pull/3683)\n\n### New Contributors\n\n- @NavyD made their first contribution in [#3664](https://github.com/jdx/mise/pull/3664)\n\n## [2024.12.13](https://github.com/jdx/mise/compare/v2024.12.12..v2024.12.13) - 2024-12-17\n\n### 🚀 Features\n\n- `mise task add` by @jdx in [#3616](https://github.com/jdx/mise/pull/3616)\n- elixir core tool by @jdx in [#3620](https://github.com/jdx/mise/pull/3620)\n- elixir on windows by @jdx in [#3623](https://github.com/jdx/mise/pull/3623)\n- added install_env tool option by @jdx in [#3622](https://github.com/jdx/mise/pull/3622)\n- Add Powershell support by @fgilcc in [#3506](https://github.com/jdx/mise/pull/3506)\n- improve redactions by @jdx in [#3647](https://github.com/jdx/mise/pull/3647)\n\n### 🐛 Bug Fixes\n\n- run venv after tools are loaded by @jdx in [#3612](https://github.com/jdx/mise/pull/3612)\n- some improvements to `mise fmt` by @jdx in [#3615](https://github.com/jdx/mise/pull/3615)\n- always run postinstall hook by @jdx in [#3618](https://github.com/jdx/mise/pull/3618)\n- move bat from aqua to ubi by @jdx in [60d0c79](https://github.com/jdx/mise/commit/60d0c798f695199bdc81f8beec737f0e2a8589e0)\n- do not require version for `mise sh --unset` by @jdx in [#3628](https://github.com/jdx/mise/pull/3628)\n- back nomad with nomad, not levant by @rliebz in [#3633](https://github.com/jdx/mise/pull/3633)\n- correct python precompiled urls for freebsd by @jdx in [#3637](https://github.com/jdx/mise/pull/3637)\n- bug fixes with tools=true in env by @jdx in [#3639](https://github.com/jdx/mise/pull/3639)\n- sort keys in `__MISE_DIFF` to make the serialised value deterministic by @joshbode in [#3640](https://github.com/jdx/mise/pull/3640)\n- resolve config_root for dir tasks option by @risu729 in [#3649](https://github.com/jdx/mise/pull/3649)\n\n### 📚 Documentation\n\n- add getting-started carousel by @hverlin in [#3613](https://github.com/jdx/mise/pull/3613)\n- Fix Sops URL by @matthew-snyder in [#3619](https://github.com/jdx/mise/pull/3619)\n- add elixir to sidebar by @risu729 in [#3650](https://github.com/jdx/mise/pull/3650)\n- update task documentation by @hverlin in [#3651](https://github.com/jdx/mise/pull/3651)\n\n### Chore\n\n- format toml with taplo by @jdx in [#3625](https://github.com/jdx/mise/pull/3625)\n- add platform field to registry backends by @jdx in [#3626](https://github.com/jdx/mise/pull/3626)\n\n### New Contributors\n\n- @fgilcc made their first contribution in [#3506](https://github.com/jdx/mise/pull/3506)\n- @rliebz made their first contribution in [#3633](https://github.com/jdx/mise/pull/3633)\n- @matthew-snyder made their first contribution in [#3619](https://github.com/jdx/mise/pull/3619)\n\n## [2024.12.12](https://github.com/jdx/mise/compare/v2024.12.11..v2024.12.12) - 2024-12-16\n\n### 🚀 Features\n\n- Add upx,actionlint and correct ripsecret error by @boris-smidt-klarrio in [#3601](https://github.com/jdx/mise/pull/3601)\n- aqua:argo-cd by @boris-smidt-klarrio in [#3600](https://github.com/jdx/mise/pull/3600)\n- task tools by @jdx in [#3599](https://github.com/jdx/mise/pull/3599)\n- lazy env eval by @jdx in [#3598](https://github.com/jdx/mise/pull/3598)\n- added cache feature to templates by @jdx in [#3608](https://github.com/jdx/mise/pull/3608)\n\n### 🐛 Bug Fixes\n\n- added MISE_SOPS_ROPS setting by @jdx in [#3603](https://github.com/jdx/mise/pull/3603)\n- respect CLICOLOR_FORCE by @jdx in [#3607](https://github.com/jdx/mise/pull/3607)\n- only create 1 venv by @jdx in [#3610](https://github.com/jdx/mise/pull/3610)\n- set bash --noprofile for env._.source by @jdx in [#3611](https://github.com/jdx/mise/pull/3611)\n\n### 📚 Documentation\n\n- improve settings a bit by @jdx in [d53d011](https://github.com/jdx/mise/commit/d53d01195e88e82d9a88a410e8feb991c1e8179d)\n- Install on Windows - Update doc on install on Windows with Scoop and WinGet + fix NOTE section by @o-l-a-v in [#3604](https://github.com/jdx/mise/pull/3604)\n- remove note about winget by @jdx in [9c0c1ce](https://github.com/jdx/mise/commit/9c0c1ce943c6fb54ca049d6cdfb81c1122987d05)\n\n### Chore\n\n- disable automatic cargo up on release by @jdx in [3f0d91a](https://github.com/jdx/mise/commit/3f0d91a40928df8ed10cef1837730d8c3a15efea)\n\n### New Contributors\n\n- @o-l-a-v made their first contribution in [#3604](https://github.com/jdx/mise/pull/3604)\n\n## [2024.12.11](https://github.com/jdx/mise/compare/v2024.12.10..v2024.12.11) - 2024-12-15\n\n### 🚀 Features\n\n- added selector for `mise use` with no args by @jdx in [#3570](https://github.com/jdx/mise/pull/3570)\n- added tool descriptions by @jdx in [#3571](https://github.com/jdx/mise/pull/3571)\n- added `mise sync python --uv` by @jdx in [#3575](https://github.com/jdx/mise/pull/3575)\n- `sync ruby --brew` by @jdx in [#3577](https://github.com/jdx/mise/pull/3577)\n- encrypted configs by @jdx in [#3584](https://github.com/jdx/mise/pull/3584)\n- added `mise --no-config` by @jdx in [#3590](https://github.com/jdx/mise/pull/3590)\n- allow _.file in vars by @jdx in [#3593](https://github.com/jdx/mise/pull/3593)\n\n### 🐛 Bug Fixes\n\n- **(python)** reduce network usage for python precompiled manifests by @jdx in [#3568](https://github.com/jdx/mise/pull/3568)\n- **(python)** check only if first or specified python is installed for _.venv by @jdx in [#3576](https://github.com/jdx/mise/pull/3576)\n- **(swift)** prevent swift from using linux platforms that are not available by @jdx in [#3583](https://github.com/jdx/mise/pull/3583)\n- correct headers on `mise ls` by @jdx in [5af3b17](https://github.com/jdx/mise/commit/5af3b17a41decd2d7368f5985f2cb5d3e3b341e8)\n- correct message truncation in `mise run` by @jdx in [c668857](https://github.com/jdx/mise/commit/c6688571cfb0eca70a55377b70ec6b9cd0cb6a68)\n- include uv in path for hook-env by @jdx in [#3572](https://github.com/jdx/mise/pull/3572)\n- correct subtitle in `mise use` selector by @jdx in [4be6d79](https://github.com/jdx/mise/commit/4be6d798f9398f9e072d4067a56e134463e71b41)\n- some bugs with status.show_tools and status.show_env by @jdx in [#3586](https://github.com/jdx/mise/pull/3586)\n- use task.display_name for `mise run` by @jdx in [a009de1](https://github.com/jdx/mise/commit/a009de13ffa4319de89b0fcaf1ba54ae2524a9b6)\n- path is treated differently in nushell by @samuelallan72 in [#3592](https://github.com/jdx/mise/pull/3592)\n- allow number/bool in .env.json by @jdx in [#3594](https://github.com/jdx/mise/pull/3594)\n\n### 🚜 Refactor\n\n- break up env_directive by @jdx in [#3587](https://github.com/jdx/mise/pull/3587)\n\n### 📚 Documentation\n\n- better warning when venv auto create is skipped by @syhol in [#3573](https://github.com/jdx/mise/pull/3573)\n- added rendered go settings by @jdx in [b41c3dd](https://github.com/jdx/mise/commit/b41c3dd8cfd97f97352900a9d856194185347e8d)\n\n### New Contributors\n\n- @fhalim made their first contribution in [#3595](https://github.com/jdx/mise/pull/3595)\n\n## [2024.12.10](https://github.com/jdx/mise/compare/v2024.12.9..v2024.12.10) - 2024-12-14\n\n### 🚀 Features\n\n- **(python)** add other indygreg flavors by @jdx in [#3565](https://github.com/jdx/mise/pull/3565)\n- redactions by @jdx in [#3529](https://github.com/jdx/mise/pull/3529)\n- show unload messages/run leave hook by @jdx in [#3532](https://github.com/jdx/mise/pull/3532)\n- update demand and default `mise run` to filtering by @jdx in [48c366d](https://github.com/jdx/mise/commit/48c366d4d2256f6b12aabcbe82abe429622b120e)\n\n### 🐛 Bug Fixes\n\n- **(go)** only use \"v\" prefix if version is semver-like by @jdx in [#3556](https://github.com/jdx/mise/pull/3556)\n- **(go)** fix non-v installs by @jdx in [36e7631](https://github.com/jdx/mise/commit/36e7631e26445f9f2bc34fd09a93ba9a15363c98)\n- disable libgit2 for updating plugin repos for now by @jdx in [#3533](https://github.com/jdx/mise/pull/3533)\n- rename kubelogin to azure-kubelogin and add replace it with more popular kubelogin cli by @jdx in [#3534](https://github.com/jdx/mise/pull/3534)\n- add backend to lockfile by @jdx in [#3535](https://github.com/jdx/mise/pull/3535)\n- parse task env vars as templates by @jdx in [#3536](https://github.com/jdx/mise/pull/3536)\n- do not add ignore file if not tty by @jdx in [#3558](https://github.com/jdx/mise/pull/3558)\n- improve output of `mise tasks` by @jdx in [#3562](https://github.com/jdx/mise/pull/3562)\n\n### 📚 Documentation\n\n- add installation via zinit by @Finkregh in [#3563](https://github.com/jdx/mise/pull/3563)\n\n### Chore\n\n- added comfy-table by @jdx in [#3561](https://github.com/jdx/mise/pull/3561)\n- pitchfork by @jdx in [2c47f72](https://github.com/jdx/mise/commit/2c47f721c03e8fed57a8ae5ed2f63a0649ffaa9b)\n- updated usage by @jdx in [#3564](https://github.com/jdx/mise/pull/3564)\n- added install-dev task by @jdx in [0c351a8](https://github.com/jdx/mise/commit/0c351a83d952cff8b953fd5c244698a14d74c305)\n\n### New Contributors\n\n- @Finkregh made their first contribution in [#3563](https://github.com/jdx/mise/pull/3563)\n\n## [2024.12.9](https://github.com/jdx/mise/compare/v2024.12.8..v2024.12.9) - 2024-12-14\n\n### 🚀 Features\n\n- **(tasks)** optional automatic outputs by @jdx in [#3528](https://github.com/jdx/mise/pull/3528)\n- added quiet field to tasks by @jdx in [#3514](https://github.com/jdx/mise/pull/3514)\n- show instructions for updating when min_version does not match by @jdx in [#3520](https://github.com/jdx/mise/pull/3520)\n- several enhancements to tasks by @jdx in [#3526](https://github.com/jdx/mise/pull/3526)\n\n### 🐛 Bug Fixes\n\n- make bash_completions lib optional by @jdx in [#3516](https://github.com/jdx/mise/pull/3516)\n- make plugin update work with libgit2 by @jdx in [#3519](https://github.com/jdx/mise/pull/3519)\n- bug with `mise task edit` and new tasks by @jdx in [#3521](https://github.com/jdx/mise/pull/3521)\n- correct self-update message by @jdx in [eff0cff](https://github.com/jdx/mise/commit/eff0cffca079ee58fc2297396604b96e0253c324)\n- task source bug fixes by @jdx in [#3522](https://github.com/jdx/mise/pull/3522)\n\n### 📚 Documentation\n\n- add explanation about shebang by @hverlin in [#3501](https://github.com/jdx/mise/pull/3501)\n- add vitepress-plugin-group-icons by @hverlin in [#3527](https://github.com/jdx/mise/pull/3527)\n\n### 🧪 Testing\n\n- pin swift version by @jdx in [2b966a4](https://github.com/jdx/mise/commit/2b966a4945851b35be593182527bd40a80279fe4)\n- skip firebase by @jdx in [e5714bc](https://github.com/jdx/mise/commit/e5714bcfe9cd45f173aecefcbd3c95fbeab83417)\n\n### 📦️ Dependency Updates\n\n- update rust crate bzip2 to 0.5 by @renovate[bot] in [#3511](https://github.com/jdx/mise/pull/3511)\n\n## [2024.12.8](https://github.com/jdx/mise/compare/v2024.12.7..v2024.12.8) - 2024-12-12\n\n### 🚀 Features\n\n- **(registry)** use pipx for pdm by @risu729 in [#3504](https://github.com/jdx/mise/pull/3504)\n- added pitchfork by @jdx in [bac731e](https://github.com/jdx/mise/commit/bac731e47f00245ce13e7eec5716509704519d71)\n\n### 🐛 Bug Fixes\n\n- Adds support for multi-use args by @bnorick in [#3505](https://github.com/jdx/mise/pull/3505)\n- make task completion script POSIX by @jdx in [b92b560](https://github.com/jdx/mise/commit/b92b5603bb23d55b58e7ee8effe8d6293036c5a9)\n\n### 📚 Documentation\n\n- Add more examples for toml tasks by @hverlin in [#3491](https://github.com/jdx/mise/pull/3491)\n\n### Chore\n\n- use main branch for winget by @jdx in [b4036cf](https://github.com/jdx/mise/commit/b4036cf0d10f6ccd8758b0bebc341963c8777d2e)\n\n### New Contributors\n\n- @bnorick made their first contribution in [#3505](https://github.com/jdx/mise/pull/3505)\n- @elchocarrero made their first contribution in [#3502](https://github.com/jdx/mise/pull/3502)\n\n## [2024.12.7](https://github.com/jdx/mise/compare/v2024.12.6..v2024.12.7) - 2024-12-12\n\n### 🚀 Features\n\n- add the users PATH to `mise doctor` by @syhol in [#3474](https://github.com/jdx/mise/pull/3474)\n- feat : Add superfile with aqua backend to registery by @yodatak in [#3479](https://github.com/jdx/mise/pull/3479)\n- added `task_auto_install` setting by @jdx in [#3481](https://github.com/jdx/mise/pull/3481)\n- Add yazi with aqua backend to registery by @yodatak in [#3485](https://github.com/jdx/mise/pull/3485)\n- Migrating Terragrunt asdf plugin over to gruntwork-io by @yhakbar in [#3486](https://github.com/jdx/mise/pull/3486)\n- add settings for python venv creation by @jdx in [#3489](https://github.com/jdx/mise/pull/3489)\n- added MISE_ARCH setting by @jdx in [#3490](https://github.com/jdx/mise/pull/3490)\n- add jj to registry by @phyrog in [#3495](https://github.com/jdx/mise/pull/3495)\n- add task descriptions to completions by @jdx in [#3497](https://github.com/jdx/mise/pull/3497)\n\n### 🐛 Bug Fixes\n\n- mise upgrade with rust by @jdx in [#3475](https://github.com/jdx/mise/pull/3475)\n- improve arg parsing for mise watch by @jdx in [#3478](https://github.com/jdx/mise/pull/3478)\n- skip reading ignored config dirs by @jdx in [#3480](https://github.com/jdx/mise/pull/3480)\n- deprecated attribute in json schema by @jdx in [#3482](https://github.com/jdx/mise/pull/3482)\n- simplify auto_install settings by @jdx in [#3483](https://github.com/jdx/mise/pull/3483)\n- use config_root for env._.source by @jdx in [#3484](https://github.com/jdx/mise/pull/3484)\n- allow directories as task source by @jdx in [#3488](https://github.com/jdx/mise/pull/3488)\n- Use arguments for to pass staged filenames to pre-commit task by @joshbode in [#3492](https://github.com/jdx/mise/pull/3492)\n\n### 📚 Documentation\n\n- updated `mise watch` docs to drop the `-t` by @jdx in [8ea6226](https://github.com/jdx/mise/commit/8ea622688cb01a0a0a2805692b38a4a7f1340ce5)\n\n### Chore\n\n- move debug log to trace by @jdx in [5c6c884](https://github.com/jdx/mise/commit/5c6c884cf51e704d1c8c347790ec30b30b0f401e)\n\n### New Contributors\n\n- @yhakbar made their first contribution in [#3486](https://github.com/jdx/mise/pull/3486)\n\n## [2024.12.6](https://github.com/jdx/mise/compare/v2024.12.5..v2024.12.6) - 2024-12-11\n\n### 🚀 Features\n\n- added descriptions to `mise run` by @jdx in [#3460](https://github.com/jdx/mise/pull/3460)\n- `mise format` by @jdx in [#3461](https://github.com/jdx/mise/pull/3461)\n- `mise fmt` (renamed from `mise format`) by @jdx in [#3465](https://github.com/jdx/mise/pull/3465)\n- `mise format` by @jdx in [d18b040](https://github.com/jdx/mise/commit/d18b040b8ae8eea16ed98b7f7b884a6f52797edc)\n\n### 🐛 Bug Fixes\n\n- **(swift)** remove clang bins by @jdx in [#3468](https://github.com/jdx/mise/pull/3468)\n- use 7zip for windows zip by @jdx in [475ae62](https://github.com/jdx/mise/commit/475ae62d209795cf8fe9cc846f258755e1092918)\n- disable filtering by default on `mise run` by @jdx in [507ee27](https://github.com/jdx/mise/commit/507ee27a736b8cd57714a8365fc88855edf62507)\n- deprecate direnv integration by @jdx in [#3464](https://github.com/jdx/mise/pull/3464)\n- remove hidden commands from docs by @jdx in [42a9a05](https://github.com/jdx/mise/commit/42a9a0567fbd8ef61550cf2bfe956074777c7d76)\n- improve hook-env by @jdx in [#3466](https://github.com/jdx/mise/pull/3466)\n- deprecate @system versions by @jdx in [#3467](https://github.com/jdx/mise/pull/3467)\n- do not reuse local tool options for `mise use -g` by @jdx in [#3469](https://github.com/jdx/mise/pull/3469)\n- allow \"~\" in python.default_packages_file by @jdx in [#3472](https://github.com/jdx/mise/pull/3472)\n- read all config files for `mise set` by @jdx in [#3473](https://github.com/jdx/mise/pull/3473)\n\n### 📚 Documentation\n\n- fixing elvish install instructions by @ejrichards in [#3459](https://github.com/jdx/mise/pull/3459)\n- remove bad formatting in setting by @jdx in [f33813b](https://github.com/jdx/mise/commit/f33813bde40cf65e946a3c1773a4275fce3cb0ef)\n- added external links by @jdx in [8271e7b](https://github.com/jdx/mise/commit/8271e7ba0fa8628279cff0460715ec9c80a1c6bd)\n\n### Chore\n\n- fix windows zip structure by @jdx in [195039f](https://github.com/jdx/mise/commit/195039ff2bbe702c7e80ace3fcaeb95cb02d018b)\n\n### New Contributors\n\n- @ejrichards made their first contribution in [#3459](https://github.com/jdx/mise/pull/3459)\n\n## [2024.12.5](https://github.com/jdx/mise/compare/v2024.12.4..v2024.12.5) - 2024-12-10\n\n### 🚀 Features\n\n- make `mise trust` act on directories instead of files by @jdx in [#3454](https://github.com/jdx/mise/pull/3454)\n\n### 🐛 Bug Fixes\n\n- correctly lowercase \"zsh\" for shell hooks by @jdx in [035ae59](https://github.com/jdx/mise/commit/035ae59bd898a16be4fcd55b708ae8ba620c60fe)\n- read MISE_CONFIG_DIR/conf.d/*.toml configs by @jdx in [#3439](https://github.com/jdx/mise/pull/3439)\n- retains spm artifacts by @jdx in [#3441](https://github.com/jdx/mise/pull/3441)\n- add env var for MISE_NPM_BUN setting by @jdx in [b3c57e2](https://github.com/jdx/mise/commit/b3c57e29bd26d772e2f708351a3c61bf04ee3d65)\n- hide hidden tasks in `mise run` selector UI by @jdx in [#3449](https://github.com/jdx/mise/pull/3449)\n- trim run scripts whitespace by @jdx in [#3450](https://github.com/jdx/mise/pull/3450)\n- shell-escape arg() in tasks by @jdx in [#3453](https://github.com/jdx/mise/pull/3453)\n- use shebang in run script to determine how arg escaping should work by @jdx in [#3455](https://github.com/jdx/mise/pull/3455)\n\n### 📚 Documentation\n\n- example with required version by @felixhummel in [#3448](https://github.com/jdx/mise/pull/3448)\n- document new windows installers by @jdx in [#3452](https://github.com/jdx/mise/pull/3452)\n\n### Chore\n\n- added winget workflow by @jdx in [901e048](https://github.com/jdx/mise/commit/901e04865842f765188dd687584f9120ad4e5519)\n\n### New Contributors\n\n- @felixhummel made their first contribution in [#3448](https://github.com/jdx/mise/pull/3448)\n\n## [2024.12.4](https://github.com/jdx/mise/compare/v2024.12.3..v2024.12.4) - 2024-12-09\n\n### 🚀 Features\n\n- add staged files to `mise generate git-pre-commit` by @jdx in [#3410](https://github.com/jdx/mise/pull/3410)\n- shell hooks by @jdx in [#3414](https://github.com/jdx/mise/pull/3414)\n- added cowsay by @jdx in [#3420](https://github.com/jdx/mise/pull/3420)\n- add openbao by @phyrog in [#3426](https://github.com/jdx/mise/pull/3426)\n- add gocryptfs by @phyrog in [#3427](https://github.com/jdx/mise/pull/3427)\n- use aqua for flyctl by @jdx in [f7ed363](https://github.com/jdx/mise/commit/f7ed363b3eebb82e6242061e78f9ebfdf050d154)\n\n### 🐛 Bug Fixes\n\n- do not set debug mode when calling `mise -v` by @jdx in [#3418](https://github.com/jdx/mise/pull/3418)\n- issue with usage and arg completions by @jdx in [#3433](https://github.com/jdx/mise/pull/3433)\n\n### 📚 Documentation\n\n- Small documentation improvements by @hverlin in [#3413](https://github.com/jdx/mise/pull/3413)\n- updated demo.gif by @jdx in [#3419](https://github.com/jdx/mise/pull/3419)\n\n### Build\n\n- update default.nix by @minhtrancccp in [#3430](https://github.com/jdx/mise/pull/3430)\n\n### New Contributors\n\n- @will-ockmore made their first contribution in [#3435](https://github.com/jdx/mise/pull/3435)\n- @minhtrancccp made their first contribution in [#3430](https://github.com/jdx/mise/pull/3430)\n- @phyrog made their first contribution in [#3427](https://github.com/jdx/mise/pull/3427)\n\n## [2024.12.3](https://github.com/jdx/mise/compare/v2024.12.2..v2024.12.3) - 2024-12-08\n\n### 🚀 Features\n\n- add danger-swift by @msnazarow in [#3406](https://github.com/jdx/mise/pull/3406)\n\n### 📚 Documentation\n\n- **(backend)** fix git url syntax example by @risu729 in [#3404](https://github.com/jdx/mise/pull/3404)\n- update dev-tools overview documentation by @hverlin in [#3400](https://github.com/jdx/mise/pull/3400)\n\n### ⚡ Performance\n\n- increase performance of watch_files by @jdx in [#3407](https://github.com/jdx/mise/pull/3407)\n- make `ls --offline` default behavior by @jdx in [#3409](https://github.com/jdx/mise/pull/3409)\n\n### New Contributors\n\n- @msnazarow made their first contribution in [#3406](https://github.com/jdx/mise/pull/3406)\n\n## [2024.12.2](https://github.com/jdx/mise/compare/v2024.12.1..v2024.12.2) - 2024-12-07\n\n### 🚀 Features\n\n- **(registry)** add zls to registry by @hverlin in [#3392](https://github.com/jdx/mise/pull/3392)\n- Add --json-extended option to mise env by @hverlin in [#3389](https://github.com/jdx/mise/pull/3389)\n\n### 🐛 Bug Fixes\n\n- **(config)** set config_root for tasks defined in included toml files by @risu729 in [#3388](https://github.com/jdx/mise/pull/3388)\n- global hooks by @jdx in [#3393](https://github.com/jdx/mise/pull/3393)\n- only run watch_file hook when it has changed file by @jdx in [#3394](https://github.com/jdx/mise/pull/3394)\n- bug with aliasing core tools by @jdx in [#3395](https://github.com/jdx/mise/pull/3395)\n- remove shims directory before activating by @jdx in [#3396](https://github.com/jdx/mise/pull/3396)\n\n### 🚜 Refactor\n\n- use github crate to list zig releases by @risu729 in [#3386](https://github.com/jdx/mise/pull/3386)\n\n### 📚 Documentation\n\n- add zig to core tools by @risu729 in [#3385](https://github.com/jdx/mise/pull/3385)\n\n### Chore\n\n- debug log by @jdx in [0075db0](https://github.com/jdx/mise/commit/0075db05a24a9bc2e3015b8a48bcfe730fe80d07)\n\n## [2024.12.1](https://github.com/jdx/mise/compare/v2024.12.0..v2024.12.1) - 2024-12-06\n\n### 🚀 Features\n\n- **(registry)** use aqua for some tools by @risu729 in [#3375](https://github.com/jdx/mise/pull/3375)\n- allow filtering `mise bin-paths` on tools by @jdx in [#3367](https://github.com/jdx/mise/pull/3367)\n- added aws-cli from aqua by @jdx in [#3370](https://github.com/jdx/mise/pull/3370)\n- multiple MISE_ENV environments by @jdx in [#3371](https://github.com/jdx/mise/pull/3371)\n- add mise-task.json schema by @hverlin in [#3374](https://github.com/jdx/mise/pull/3374)\n- automatically call `hook-env` by @jdx in [#3373](https://github.com/jdx/mise/pull/3373)\n\n### 🐛 Bug Fixes\n\n- **(docs)** correct syntax error in IDE integration examples by @EricGusmao in [#3360](https://github.com/jdx/mise/pull/3360)\n- ensure version check message is displayed by @jdx in [#3358](https://github.com/jdx/mise/pull/3358)\n- show warning if no precompiled pythons found by @jdx in [#3359](https://github.com/jdx/mise/pull/3359)\n- allow compilation not on macOS, Linux, or Windows by @avysk in [#3363](https://github.com/jdx/mise/pull/3363)\n- make hook-env compatible with zsh auto_name_dirs by @jdx in [#3366](https://github.com/jdx/mise/pull/3366)\n- skip optional env._.file files by @jdx in [#3381](https://github.com/jdx/mise/pull/3381)\n- .terraform-version by @jdx in [#3380](https://github.com/jdx/mise/pull/3380)\n\n### 📚 Documentation\n\n- update auto-completion docs by @hverlin in [#3355](https://github.com/jdx/mise/pull/3355)\n- fix `Environment variables passed to tasks` section by @hverlin in [#3378](https://github.com/jdx/mise/pull/3378)\n\n### 🧪 Testing\n\n- try to fix coverage rate limits by @jdx in [#3384](https://github.com/jdx/mise/pull/3384)\n\n### New Contributors\n\n- @avysk made their first contribution in [#3363](https://github.com/jdx/mise/pull/3363)\n- @EricGusmao made their first contribution in [#3360](https://github.com/jdx/mise/pull/3360)\n\n## [2024.12.0](https://github.com/jdx/mise/compare/v2024.11.37..v2024.12.0) - 2024-12-04\n\n### 🚀 Features\n\n- **(erlang)** use precompiled binaries for macos by @jdx in [#3353](https://github.com/jdx/mise/pull/3353)\n- add upctl by @scop in [#3309](https://github.com/jdx/mise/pull/3309)\n- Add `json-with-sources` option to settings ls by @hverlin in [#3307](https://github.com/jdx/mise/pull/3307)\n- add ripsecrets to registry.toml by @boris-smidt-klarrio in [#3334](https://github.com/jdx/mise/pull/3334)\n- Add kyverno-cli by @boris-smidt-klarrio in [#3336](https://github.com/jdx/mise/pull/3336)\n\n### 🐛 Bug Fixes\n\n- add exec to `mise g git-pre-commit` by @jdx in [27a3aef](https://github.com/jdx/mise/commit/27a3aefa767c8ef142009dd54c4d7dcc19c235b2)\n- bake gpg keys in by @jdx in [#3318](https://github.com/jdx/mise/pull/3318)\n- deprecate `mise local|global` by @jdx in [#3350](https://github.com/jdx/mise/pull/3350)\n\n### 🚜 Refactor\n\n- use aqua for ruff by @scop in [#3316](https://github.com/jdx/mise/pull/3316)\n\n### 📚 Documentation\n\n- add terraform recipe to the cookbook by @AliSajid in [#3305](https://github.com/jdx/mise/pull/3305)\n- fix git examples for cargo backend by @tmeijn in [#3335](https://github.com/jdx/mise/pull/3335)\n\n### 🧪 Testing\n\n- remove non-working maven test by @jdx in [5a3ed16](https://github.com/jdx/mise/commit/5a3ed16efb29dbf80f5ac251eec39e3a462d2219)\n- remove gleam by @jdx in [fdfe20b](https://github.com/jdx/mise/commit/fdfe20b32b16b835655551d3f12b5d6e90856b2e)\n- use latest golang in e2e test by @jdx in [#3349](https://github.com/jdx/mise/pull/3349)\n\n### Chore\n\n- upgrade usage-lib by @jdx in [554d533](https://github.com/jdx/mise/commit/554d533a253a137c27c5cdac6da2ae09629029dc)\n- use asdf:mise-plugins/mise-nim by @jdx in [#3352](https://github.com/jdx/mise/pull/3352)\n\n### New Contributors\n\n- @leogurja made their first contribution in [#3341](https://github.com/jdx/mise/pull/3341)\n- @tmeijn made their first contribution in [#3335](https://github.com/jdx/mise/pull/3335)\n- @boris-smidt-klarrio made their first contribution in [#3336](https://github.com/jdx/mise/pull/3336)\n- @AliSajid made their first contribution in [#3305](https://github.com/jdx/mise/pull/3305)\n\n## [2024.11.37](https://github.com/jdx/mise/compare/v2024.11.36..v2024.11.37) - 2024-11-30\n\n### 🚀 Features\n\n- add black by @scop in [#3292](https://github.com/jdx/mise/pull/3292)\n- migrate more tools away from asdf by @jdx in [40f92c6](https://github.com/jdx/mise/commit/40f92c6b0e1fefd171dd44ee9f62f1f597ee352c)\n\n### 🐛 Bug Fixes\n\n- handle General/Complex Versioning in --bump by @liskin in [#2889](https://github.com/jdx/mise/pull/2889)\n- broken path example by @minddust in [#3296](https://github.com/jdx/mise/pull/3296)\n- swift path on macos by @jdx in [#3299](https://github.com/jdx/mise/pull/3299)\n- do not auto-install on `mise x` if some tools are passed by @jdx in [35d31a1](https://github.com/jdx/mise/commit/35d31a1baf96fe6f0e764e26228c1b03ba24ddce)\n- fix: also make certain we are not auto installing inside shims by checking by @jdx in [b0c4a74](https://github.com/jdx/mise/commit/b0c4a749309064825852041d8d72c7eac9fb116c)\n- cache github release information for 24 hours by @jdx in [#3300](https://github.com/jdx/mise/pull/3300)\n\n### 🚜 Refactor\n\n- use aqua for snyk by @scop in [#3290](https://github.com/jdx/mise/pull/3290)\n\n### ◀️ Revert\n\n- Revert \"fix: always prefer glibc to musl in mise run \" by @jdx in [#3298](https://github.com/jdx/mise/pull/3298)\n\n### Chore\n\n- bump expr-lang by @jdx in [#3297](https://github.com/jdx/mise/pull/3297)\n- mise up --bump by @jdx in [6872b54](https://github.com/jdx/mise/commit/6872b5469622140335a12131dfa4acf310fc0c2a)\n- update mise.lock by @jdx in [4c12502](https://github.com/jdx/mise/commit/4c12502c459ba2e214689c3f55d964b8f75966af)\n- disable tool tests until I can sort out gh rate limit issues by @jdx in [f42f010](https://github.com/jdx/mise/commit/f42f010f03a57cab128290c0b9d936fd7a90c785)\n\n### New Contributors\n\n- @minddust made their first contribution in [#3296](https://github.com/jdx/mise/pull/3296)\n\n## [2024.11.36](https://github.com/jdx/mise/compare/v2024.11.35..v2024.11.36) - 2024-11-29\n\n### Chore\n\n- mise i by @jdx in [8150732](https://github.com/jdx/mise/commit/81507327e7f1c9f2137b3dadcf35a8245d43a8ba)\n\n## [2024.11.35](https://github.com/jdx/mise/compare/v2024.11.34..v2024.11.35) - 2024-11-29\n\n### 🚀 Features\n\n- migrate more tools away from asdf by @jdx in [#3279](https://github.com/jdx/mise/pull/3279)\n\n### 🐛 Bug Fixes\n\n- remove conflicting MISE_SHELL setting by @jdx in [#3284](https://github.com/jdx/mise/pull/3284)\n\n### 🚜 Refactor\n\n- simplify __MISE_WATCH variable to only contain the most recent timestamp by @jdx in [#3282](https://github.com/jdx/mise/pull/3282)\n\n### 🧪 Testing\n\n- remove unnecessary cargo-binstall test by @jdx in [0a4da7a](https://github.com/jdx/mise/commit/0a4da7a023b1cb969b732afd3ad4b3cf02c42530)\n\n### Chore\n\n- dont require build-windows before unit-windows by @jdx in [c85e2ec](https://github.com/jdx/mise/commit/c85e2ec77193d73ff20d4ce8fb7e3787a6db223d)\n\n## [2024.11.34](https://github.com/jdx/mise/compare/v2024.11.33..v2024.11.34) - 2024-11-29\n\n### 🚀 Features\n\n- fragmented configs by @jdx in [#3273](https://github.com/jdx/mise/pull/3273)\n- hooks by @jdx in [#3256](https://github.com/jdx/mise/pull/3256)\n- added MISE_TASK_DISABLE_PATHS setting by @jdx in [9c2e6e4](https://github.com/jdx/mise/commit/9c2e6e40f3a98f352fbf03107e1901dec445a7f5)\n- gpg verification for node by @jdx in [#3277](https://github.com/jdx/mise/pull/3277)\n\n### 🐛 Bug Fixes\n\n- make _.file and _.source optional if the file is missing by @jdx in [#3275](https://github.com/jdx/mise/pull/3275)\n- prevent deadlock when resetting by @jdx in [8e6d093](https://github.com/jdx/mise/commit/8e6d09377de81c65203684725fa9dfc2140db520)\n- prevent deadlock when resetting by @jdx in [201ba90](https://github.com/jdx/mise/commit/201ba904052379595e399672d1657ed0e3c3a138)\n- prevent deadlock when resetting by @jdx in [169338a](https://github.com/jdx/mise/commit/169338a2debb99ee4dd885376c4123740237af23)\n\n### 🚜 Refactor\n\n- clean up arcs by @jdx in [f49d330](https://github.com/jdx/mise/commit/f49d330b6f97b08e72b1a448af0021708b2a2417)\n\n### 📚 Documentation\n\n- added hooks to sidebar by @jdx in [4bbc340](https://github.com/jdx/mise/commit/4bbc3403e46aa817450e6936f37b5d4c983b43d4)\n- added swift to sidebar by @jdx in [bc06cbf](https://github.com/jdx/mise/commit/bc06cbf240cc7aae2173575cfa83289ae526dad1)\n\n### Chore\n\n- skip checkov test by @jdx in [2ae18a3](https://github.com/jdx/mise/commit/2ae18a3e8329eb9913dc43ae94432f8f75b36a94)\n- added timeout for release-plz by @jdx in [dae4bc3](https://github.com/jdx/mise/commit/dae4bc32bbb7de7873e3fa047a785c70f02a5c05)\n- remove coverage by @jdx in [#3278](https://github.com/jdx/mise/pull/3278)\n\n## [2024.11.33](https://github.com/jdx/mise/compare/v2024.11.32..v2024.11.33) - 2024-11-28\n\n### 🚀 Features\n\n- respect --quiet in `mise run` by @jdx in [#3257](https://github.com/jdx/mise/pull/3257)\n- added special \"_\" portion of mise.toml for custom data by @jdx in [#3259](https://github.com/jdx/mise/pull/3259)\n- **breaking** added MISE_OVERRIDE_CONFIG_FILENAMES config by @jdx in [#3266](https://github.com/jdx/mise/pull/3266)\n- added swift by @jdx in [#3271](https://github.com/jdx/mise/pull/3271)\n\n### 🐛 Bug Fixes\n\n- **(spm)** git proxy config by @jdx in [#3264](https://github.com/jdx/mise/pull/3264)\n- clean up some windows error cases by @jdx in [#3255](https://github.com/jdx/mise/pull/3255)\n- run `hook-env` on directory change by @jdx in [#3258](https://github.com/jdx/mise/pull/3258)\n- always prefer glibc to musl in mise run by @jdx in [#3261](https://github.com/jdx/mise/pull/3261)\n- issue with non-default backends not getting tool options by @jdx in [#3265](https://github.com/jdx/mise/pull/3265)\n- explicitly stop progress bars when exiting by @jdx in [#3272](https://github.com/jdx/mise/pull/3272)\n\n### 🚜 Refactor\n\n- use aqua for shellcheck by @scop in [#3270](https://github.com/jdx/mise/pull/3270)\n- use aqua for goreleaser by @scop in [#3269](https://github.com/jdx/mise/pull/3269)\n- use aqua for golangci-lint by @scop in [#3268](https://github.com/jdx/mise/pull/3268)\n\n### 📚 Documentation\n\n- describe mise behavior when mise version is lower than min_version by @erickguan in [#2994](https://github.com/jdx/mise/pull/2994)\n\n### Chore\n\n- wait for gh rate limit if expended by @jdx in [#3251](https://github.com/jdx/mise/pull/3251)\n- set github token for docs job by @jdx in [908dd18](https://github.com/jdx/mise/commit/908dd18fe3ddf19d1531c93695ee3ff98d0995c5)\n- skip hyperfine unless on release pr by @jdx in [#3253](https://github.com/jdx/mise/pull/3253)\n- move tasks dir so it doesnt show up in unrelated projects by @jdx in [#3254](https://github.com/jdx/mise/pull/3254)\n\n## [2024.11.32](https://github.com/jdx/mise/compare/v2024.11.31..v2024.11.32) - 2024-11-27\n\n### 🚀 Features\n\n- allow running tasks without `mise run`, e.g.: `mise test` as shorthand for `mise run test` by @jdx in [#3235](https://github.com/jdx/mise/pull/3235)\n- default task directory config by @jdx in [#3238](https://github.com/jdx/mise/pull/3238)\n- standalone tasks by @jdx in [#3240](https://github.com/jdx/mise/pull/3240)\n- automatic uv venv activation by @jdx in [#3239](https://github.com/jdx/mise/pull/3239)\n- migrate more tools away from asdf by @jdx in [#3242](https://github.com/jdx/mise/pull/3242)\n- add committed by @scop in [#3247](https://github.com/jdx/mise/pull/3247)\n- use ubi for figma-export by @jdx in [19dbeac](https://github.com/jdx/mise/commit/19dbeac16a68248bb780a2de1056d16409714204)\n- add vacuum by @scop in [#3249](https://github.com/jdx/mise/pull/3249)\n\n### 🐛 Bug Fixes\n\n- skip _.source files if not present by @jdx in [#3236](https://github.com/jdx/mise/pull/3236)\n- rust idiomatic file parsing by @jdx in [#3241](https://github.com/jdx/mise/pull/3241)\n- automatic reinstall of uvx tools during python upgrades by @jdx in [#3243](https://github.com/jdx/mise/pull/3243)\n\n### 🚜 Refactor\n\n- use aqua for shfmt by @scop in [#3244](https://github.com/jdx/mise/pull/3244)\n- use aqua for lefthook by @scop in [#3246](https://github.com/jdx/mise/pull/3246)\n- use aqua for nfpm by @scop in [#3248](https://github.com/jdx/mise/pull/3248)\n\n### 📚 Documentation\n\n- correction in aqua by @jdx in [b7de2f3](https://github.com/jdx/mise/commit/b7de2f32e6a23458bbd3573372f9c49733b80e62)\n- typo by @jdx in [98aa6bd](https://github.com/jdx/mise/commit/98aa6bd7b2631a5904243cbf9aeb2eaf218c9c64)\n\n### Chore\n\n- bump tabled by @jdx in [#3245](https://github.com/jdx/mise/pull/3245)\n- fix tools tests on release branch by @jdx in [675a2b0](https://github.com/jdx/mise/commit/675a2b086116f0afb431189c51136255b6f6c434)\n- fix tools tests on release branch by @jdx in [130c3a4](https://github.com/jdx/mise/commit/130c3a4de60edfbed98642bc6dc71e67ba9b6ce1)\n- fix tools tests on release branch by @jdx in [9feb3b6](https://github.com/jdx/mise/commit/9feb3b638ef634d320f576921b3e366f6cd73075)\n\n### New Contributors\n\n- @rmacklin made their first contribution in [#2295](https://github.com/jdx/mise/pull/2295)\n\n## [2024.11.31](https://github.com/jdx/mise/compare/v2024.11.30..v2024.11.31) - 2024-11-27\n\n### 🚀 Features\n\n- rust in core by @jdx in [#3219](https://github.com/jdx/mise/pull/3219)\n\n### 🐛 Bug Fixes\n\n- use tv.pathname() in `mise ls` by @jdx in [#3217](https://github.com/jdx/mise/pull/3217)\n- show gh rate limit reset time by @jdx in [#3221](https://github.com/jdx/mise/pull/3221)\n- add @version back into show_tools by @jdx in [fd7d8d1](https://github.com/jdx/mise/commit/fd7d8d10395f8c80a80c60c0de89bf78e31fd762)\n- use pipx for yamllint by @jdx in [#3227](https://github.com/jdx/mise/pull/3227)\n- remove shims directory in `mise activate` by @jdx in [#3232](https://github.com/jdx/mise/pull/3232)\n\n### 🚜 Refactor\n\n- remove duplicate remote_versions_caches by @jdx in [#3220](https://github.com/jdx/mise/pull/3220)\n\n### 📚 Documentation\n\n- rename legacy version files to idiomatic version files by @jdx in [#3216](https://github.com/jdx/mise/pull/3216)\n- document aqua better by @jdx in [#3234](https://github.com/jdx/mise/pull/3234)\n\n### 🎨 Styling\n\n- spelling and grammar fixes by @scop in [#3225](https://github.com/jdx/mise/pull/3225)\n\n### 🧪 Testing\n\n- move some unit tests to e2e by @jdx in [#3218](https://github.com/jdx/mise/pull/3218)\n- migrate tests from unit to e2e by @jdx in [#3231](https://github.com/jdx/mise/pull/3231)\n\n## [2024.11.30](https://github.com/jdx/mise/compare/v2024.11.29..v2024.11.30) - 2024-11-26\n\n### 🚀 Features\n\n- migrate wren-cli to ubi by @jdx in [#3193](https://github.com/jdx/mise/pull/3193)\n- migrate more tools away from asdf by @jdx in [#3202](https://github.com/jdx/mise/pull/3202)\n- automatically set `set -e` in toml tasks by @jdx in [#3215](https://github.com/jdx/mise/pull/3215)\n- added MISE_ORIGINAL_CWD to tasks by @jdx in [#3214](https://github.com/jdx/mise/pull/3214)\n- add ruby backend by @andrewthauer in [#1657](https://github.com/jdx/mise/pull/1657)\n- migrate more tools away from asdf by @jdx in [#3205](https://github.com/jdx/mise/pull/3205)\n\n### 🐛 Bug Fixes\n\n- Make Rebar backend depend on Erlang by @eproxus in [#3197](https://github.com/jdx/mise/pull/3197)\n- trust system/global config by default by @jdx in [#3201](https://github.com/jdx/mise/pull/3201)\n- use tv.short in show_tools by @jdx in [#3213](https://github.com/jdx/mise/pull/3213)\n\n### 📚 Documentation\n\n- flatten tools in sidebar by @jdx in [0556024](https://github.com/jdx/mise/commit/0556024b5abdb2d5f1cb025d105494c71aa79647)\n\n### 🧪 Testing\n\n- remove flaky maven test by @jdx in [65f6eb4](https://github.com/jdx/mise/commit/65f6eb48880b6322439c33b3cd53eab7b8b97439)\n- added test for vault by @jdx in [#3194](https://github.com/jdx/mise/pull/3194)\n\n### Chore\n\n- bump expr-lang by @jdx in [#3199](https://github.com/jdx/mise/pull/3199)\n- add aqua-registry as submodule by @jdx in [#3204](https://github.com/jdx/mise/pull/3204)\n\n### New Contributors\n\n- @eproxus made their first contribution in [#3197](https://github.com/jdx/mise/pull/3197)\n\n## [2024.11.29](https://github.com/jdx/mise/compare/v2024.11.28..v2024.11.29) - 2024-11-25\n\n### 🚀 Features\n\n- **(env)** Allow exporting env vars as dotenv format by @miguelmig in [#3185](https://github.com/jdx/mise/pull/3185)\n- move more tools away from asdf by @jdx in [#3184](https://github.com/jdx/mise/pull/3184)\n- use aqua for cargo-binstall by @jdx in [#3182](https://github.com/jdx/mise/pull/3182)\n\n### 🐛 Bug Fixes\n\n- use shift_remove by @jdx in [#3188](https://github.com/jdx/mise/pull/3188)\n- pass boolean tool options as strings by @jdx in [#3191](https://github.com/jdx/mise/pull/3191)\n- move semver cmp errors to debug by @jdx in [ab4e638](https://github.com/jdx/mise/commit/ab4e638cdeda9845f3b7421a22a0d3bf71d81eae)\n- show more accurate error if no tasks are available by @jdx in [e1b1b48](https://github.com/jdx/mise/commit/e1b1b48840b8c96e45a567a47922138544ab9f59)\n- move semver cmp errors to debug by @jdx in [#3172](https://github.com/jdx/mise/pull/3172)\n- use aqua for terraform by @jdx in [#3192](https://github.com/jdx/mise/pull/3192)\n\n### 🧪 Testing\n\n- disable cargo-binstall test by @jdx in [8fee82e](https://github.com/jdx/mise/commit/8fee82e652031a1c9a31dbb05437478c961b6107)\n\n### Chore\n\n- include aqua-registry yaml files in crate by @jdx in [#3186](https://github.com/jdx/mise/pull/3186)\n- gitignore aqua-registry by @jdx in [1c38bca](https://github.com/jdx/mise/commit/1c38bca434cfc17792eb3053be2f4271a9e92fdd)\n- gitignore aqua-registry by @jdx in [644cb6d](https://github.com/jdx/mise/commit/644cb6dfa762d6360b5aaa7fce0502fe61ac1067)\n\n## [2024.11.28] - 2024-11-24\n\n### 🚀 Features\n\n- migrate more tools away from asdf by @jdx in [#3170](https://github.com/jdx/mise/pull/3170)\n- auto-install tools on `mise run` by @jdx in [#3181](https://github.com/jdx/mise/pull/3181)\n- move more tools away from asdf by @jdx in [#3179](https://github.com/jdx/mise/pull/3179)\n\n### 🐛 Bug Fixes\n\n- allow passing integers to task env by @jdx in [#3177](https://github.com/jdx/mise/pull/3177)\n- remove __MISE_WATCH,__MISE_DIFF env vars on `mise deactivate` by @jdx in [#3178](https://github.com/jdx/mise/pull/3178)\n\n### 📚 Documentation\n\n- **(security)** added information about checksums/cosign/slsa verification by @jdx in [1faef6e](https://github.com/jdx/mise/commit/1faef6ecbb48692955f4ce424d77d03472aa4617)\n- **(security)** added release gpg key by @jdx in [8f5dfd6](https://github.com/jdx/mise/commit/8f5dfd6dd2903c55fd792aeecd8ec97ef9f7f7ba)\n- typos by @jdx in [#3173](https://github.com/jdx/mise/pull/3173)\n\n### Chore\n\n- clean up CHANGELOG by @jdx in [8ec0ca2](https://github.com/jdx/mise/commit/8ec0ca20fce57d07d769209fd9043a129daa86f1)\n\n<!-- generated by git-cliff -->\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Development Commands\n\n### Building and Testing\n- `mise run build` or `mise run b` - Build the project with cargo\n- `target/debug/mise` - Run the built binary directly\n- `mise run test` or `mise run t` - Run all tests (unit + e2e)\n- `mise run test:unit` - Run unit tests only\n- `mise run test:e2e` - Run end-to-end tests only\n- `mise run snapshots` - Update test snapshots with `cargo insta`\n\n### Debugging\n- Use `MISE_DEBUG=1` or `MISE_TRACE=1` environment variables to enable debug output (not `RUST_LOG`)\n\n### Code Quality and Testing\n- `mise run lint` - Run all linting tasks\n- `mise run lint-fix` - Run linting and automatically fix issues\n- `mise run format` - Format code (part of CI task)\n- `mise run ci` - Run format, build, and test\n- `mise run test:e2e [test_filename]...` - Run specific e2e tests (use this instead of executing test files directly)\n- `mise --cd crates/vfox run test` - Run tests for the vfox crate\n- `mise --cd crates/vfox run lint` - Run linting for the vfox crate\n- `mise --cd crates/vfox run lint-fix` - Run linting and fix issues for the vfox crate\n- `mise task ls` - List all available tasks\n\n### Documentation and Generation\n- `mise run render` - Generate all documentation and completions\n- `mise run render:usage` - Generate CLI usage documentation\n- `mise run render:completions` - Generate shell completions\n- `mise run docs` - Start documentation dev server\n- `mise run docs:build` - Build documentation\n\n### Development\n- `mise run install-dev` - Install development version locally\n- `mise run clean` - Clean cargo build artifacts\n\n## Code Architecture\n\n### High-Level Structure\nMise is a Rust CLI tool that manages development environments, tools, tasks, and environment variables. The codebase follows a modular architecture:\n\n**Core Components:**\n- `src/main.rs` - Entry point and CLI initialization\n- `src/cli/` - Command-line interface implementation with subcommands\n- `src/config/` - Configuration file parsing and management\n- `src/backend/` - Tool backend implementations (asdf, vfox, cargo, npm, etc.)\n- `src/toolset/` - Tool version management and installation logic\n- `src/task/` - Task execution system\n- `src/plugins/` - Plugin system for extending tool support\n\n**Key Backend Systems:**\n- `src/backend/asdf.rs` - ASDF plugin compatibility\n- `src/backend/vfox.rs` - VersionFox plugin system\n- `src/backend/cargo.rs` - Rust Cargo tool backend\n- `src/backend/npm.rs` - Node.js/npm tool backend\n- `src/backend/github.rs` - GitHub releases backend\n- `src/backend/aqua.rs` - Aqua tool registry integration\n\n**Core Tools (Built-in):**\n- `src/plugins/core/` - Built-in tool implementations (Node, Python, Go, Ruby, etc.)\n\n**Configuration System:**\n- `mise.toml` files for project configuration\n- `.tool-versions` files for ASDF compatibility\n- Environment variable management and templating\n- Task definition and execution\n\n### Key Design Patterns\n1. **Backend Architecture**: Tools are implemented through a unified backend interface, allowing multiple sources (ASDF plugins, vfox plugins, cargo, npm, etc.)\n2. **Toolset Management**: The `Toolset` manages collections of tool versions and their installation state\n3. **Configuration Layering**: Config files are loaded hierarchically from system → global → local with environment-specific overrides\n4. **Task System**: Tasks can be defined in TOML files with dependencies, environment variables, and multiple execution modes\n\n### Configuration Files\n- `mise.toml` - Main configuration file format\n- `settings.toml` - Global settings definitions (generates code/docs)\n- `registry/` - Tool registry mappings\n- `tasks.toml` - Project task definitions\n\n### Test Structure\n- Unit tests within source files\n- E2E tests in `e2e/` directory organized by feature area (e.g., `e2e/cli/`, `e2e/backend/`)\n- E2E tests are bash scripts using assertion helpers from `e2e/assert.sh` (e.g., `assert`, `assert_contains`, `assert_fail`)\n- Snapshot tests using `insta` crate for CLI output verification\n- Windows-specific tests in `e2e-win/`\n\n### Build System\n- Rust project using Cargo with workspace for `crates/vfox`\n- Custom build script in `build.rs` for generating metadata\n- Multiple build profiles including `release` and `serious` (with LTO)\n- Cross-compilation support via `Cross.toml`\n\n## Development Guidelines\n\n### Conventional Commits (REQUIRED)\nAll commit messages and PR titles MUST follow conventional commit format:\n\n**Format:** `<type>(<scope>): <description>`\n\n**Types:**\n- `feat:` - New features\n- `fix:` - Bug fixes that affect the CLI behavior (not CI, docs, or infrastructure)\n- `refactor:` - Code refactoring\n- `docs:` - Documentation changes\n- `style:` - Code style/formatting (no logic changes)\n- `perf:` - Performance improvements\n- `test:` - Testing changes\n- `chore:` - Maintenance tasks, releases, dependency updates, CI/infrastructure changes\n- `security:` - Security-related changes\n- `registry:` - Any changes to `registry/` (no scope needed, use for both new tools and fixes)\n\n**Scopes:**\n- For command-specific changes, use the command name: `install`, `activate`, `use`, `exec`, etc.\n- For subsystem changes: `config`, `backend`, `env`, `task`, `vfox`, `python`, `github`, `release`, `completions`, `http`, `schema`, `doctor`, `shim`, `core`, `deps`, `ci`\n- Use `task` (not `run`) for task-related changes, even if the code lives in `src/cli/run.rs` or `src/cmd.rs`\n\n**Description Style:**\n- Use lowercase after the colon\n- Use imperative mood (\"add feature\" not \"added feature\")\n- Keep it concise but descriptive\n\n**Examples:**\n- `fix(install): resolve version mismatch for previously installed tools`\n- `feat(activate): add fish shell support`\n- `feat(vfox): add semver Lua module for version sorting`\n- `feat(env): add environment caching with module cacheability support`\n- `docs(contributing): update hk usages`\n- `chore: release 2026.1.6`\n- `chore(ci): add FORGEJO_TOKEN for API authentication`\n- `registry: add miller`\n\n### Pre-commit Process\n1. Run `hk install --mise` once to set up pre-commit hooks (runs `hk fix` automatically on commit)\n2. Run `mise run lint-fix` and `git add` any lint fixes before committing\n3. Use `mise run test:e2e [test_filename]...` for running specific e2e tests\n4. Never run e2e tests by executing them directly - always use the mise task\n\n## Important Implementation Notes\n\n### Backend System\nWhen implementing new tool backends, follow the pattern in `src/backend/mod.rs`. Each backend must implement the `Backend` trait with methods for listing versions, installing tools, and managing tool metadata.\n\n### Plugin Development\n- Core tools are implemented in `src/plugins/core/`\n- External plugins use ASDF or vfox compatibility layers\n- Plugin metadata is defined in `mise.plugin.toml` files\n\n### Configuration Parsing\nThe configuration system supports multiple file formats and environment-specific configs. Changes to settings require updating `settings.toml` and running `mise run render:schema`.\n\n### Testing Strategy\n- E2E tests are organized by feature area (cli/, config/, backend/, etc.)\n- Use snapshot testing for CLI output verification\n- Backend-specific tests verify tool installation and version management\n- Slow tests (marked with `_slow` suffix) test actual tool compilation/installation\n\n### Cross-Platform Considerations\n- Windows-specific implementations in files ending with `_windows.rs`\n- Platform-specific tool installation logic in core plugins\n- Shim system varies by platform (especially Windows)\n- we don't chmod mise e2e tests to be executable\n\n## GitHub Interactions\n\nWhen posting comments on GitHub PRs or discussions, always include a note that the comment was AI-generated (e.g., \"*This comment was generated by Claude Code.*\").\n\n## Documentation\n\n### URL Structure\nWhen referencing mise documentation URLs, use the correct path structure based on the `docs/` directory layout:\n\n- **Dev tools & backends**: `mise.jdx.dev/dev-tools/backends/<backend>.html` (e.g., `mise.jdx.dev/dev-tools/backends/s3.html`)\n- **Configuration**: `mise.jdx.dev/configuration/...`\n- **Tasks**: `mise.jdx.dev/tasks/...`\n- **Environments**: `mise.jdx.dev/environments/...`\n- **CLI reference**: `mise.jdx.dev/cli/...`\n\nDo NOT use shortened paths like `mise.jdx.dev/backends/...` - always include the full path matching the `docs/` directory structure.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "<https://mise.jdx.dev/contributing.html>\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n  \"crates/vfox\",\n  \"crates/aqua-registry\",\n  \"crates/mise-interactive-config\",\n  \"crates/mise-shim\",\n]\n\n[package]\nname = \"mise\"\nversion = \"2026.3.9\"\nedition = \"2024\"\ndescription = \"The front-end to your dev env\"\nauthors = [\"Jeff Dickey (@jdx)\"]\nhomepage = \"https://mise.jdx.dev\"\ndocumentation = \"https://mise.jdx.dev\"\nrepository = \"https://github.com/jdx/mise\"\nreadme = \"README.md\"\nlicense = \"MIT\"\nkeywords = [\"mise\"]\ncategories = [\"command-line-utilities\"]\ninclude = [\n  \"/Cargo.lock\",\n  \"/LICENSE\",\n  \"/README.md\",\n  \"/build.rs\",\n  \"/completions/*\",\n  \"/minisign.pub\",\n  \"/registry/*.toml\",\n  \"/settings.toml\",\n  \"/zipsign.pub\",\n  \"/src/**/*.rs\",\n  \"/src/assets/**\",\n  \"/src/plugins/core/assets/**\",\n]\nbuild = \"build.rs\"\nrust-version = \"1.88\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[[bin]]\nname = \"mise\"\npath = \"src/main.rs\"\n\n#[[bench]]\n#name = \"config_bench\"\n#harness = false\n\n[profile.release]\n# debug = 0 # note that higher levels greatly increase the binary size for linux\n\n[profile.serious]\ninherits = \"release\"\nlto = true\n\n[profile.dev.package.backtrace]\nopt-level = 3\n\n[dependencies]\nage = { version = \"0.11\", features = [\"ssh\"] }\naho-corasick = \"1\"\nanyhow = \"1\"\nasync-backtrace = \"0.2\"\nasync-trait = \"0.1\"\naws-config = { version = \"1.5\", default-features = false, features = [\n  \"behavior-version-latest\",\n  \"rustls\",\n  \"rt-tokio\",\n] }\naws-lc-rs = { version = \"1\", optional = true, features = [\n  \"bindgen\",\n] } # TODO: this is only for armv7 currently\naws-sdk-s3 = { version = \"1\", default-features = false, features = [\n  \"behavior-version-latest\",\n  \"rustls\",\n] }\nbase64 = \"0.22\"\nbzip2 = \"0.6\"\ncalm_io = \"0.1\"\nchrono = { version = \"0.4\", default-features = false, features = [\n  \"std\",\n  \"clock\",\n] }\nci_info = \"0.14\"\nclap = { version = \"4\", features = [\"env\", \"derive\", \"string\"] }\ncolor-eyre = \"0.6\"\ncolor-print = \"0.3\"\ncomfy-table = \"7\"\nconfique = { version = \"0.3\", default-features = false }\nconsole = \"0.16\"\ncontracts = \"0.6\"\ndashmap = \"6\"\ndemand = \"1\"\ndigest = \"0.10.7\"\ndotenvy = \"0.15\"\nduct = \"0.13\"\nhomedir = \"0.3\"\nexpr-lang = \"1\"\neyre = \"0.6\"\nfiletime = \"0.2\"\nflate2 = \"1\"\nsigstore-verification = { version = \"0.2\", default-features = false }\nfslock = \"0.2.1\"\nfuzzy-matcher = \"0.3\"\ngix = { version = \"<1\", features = [\"worktree-mutation\"] }\nglob = \"0.3\"\nglobset = \"0.4\"\nignore = { version = \"0.4\", features = [] }\nheck = \"0.5\"\nhex = \"0.4\"\nhumansize = \"2\"\nindenter = \"0.3\"\nindexmap = { version = \"2\", features = [\"serde\"] }\nclx = \"1\"\nindoc = \"2\"\nitertools = \"0.14\"\njiff = \"0.2\"\njunction = \"1\"\nlog = \"0.4\"\nminisign-verify = \"0.2\"\nmd-5 = \"0.10\"\nmiette = { version = \"7\", features = [\"fancy\"] }\nnetrc-rs = \"0.1\"\nnum_cpus = \"1\"\nnumber_prefix = \"0.4\"\nonce_cell = \"1\"\nopenssl = { version = \"0.10\", optional = true }\nos-release = \"0.1\"\npath-absolutize = { version = \"3\", features = [\"unsafe_cache\"] }\npetgraph = \"0.8\"\nrand = \"0.9\"\nrattler = { version = \"0.39\", default-features = false }\nrattler_conda_types = { version = \"0.43\", default-features = false }\nrattler_repodata_gateway = { version = \"0.26\", default-features = false, features = [\n  \"gateway\",\n] }\nrattler_solve = { version = \"4\", default-features = false, features = [\n  \"resolvo\",\n] }\nrattler_package_streaming = { version = \"0.24\", default-features = false }\nrattler_virtual_packages = { version = \"2\", default-features = false }\nregex = \"1\"\nreqwest = { version = \"0.12\", default-features = false, features = [\n  \"json\",\n  \"gzip\",\n  \"zstd\",\n  \"charset\",\n  \"http2\",\n  \"socks\",\n  \"macos-system-configuration\",\n] }\nrmcp = { version = \"0.3\", features = [\"server\", \"transport-io\", \"schemars\"] }\nrmcp-macros = \"0.3\"\nrmp-serde = \"1\"\nrops = { version = \"0.1\", default-features = false, features = [\n  \"aes-gcm\",\n  \"sha2\",\n  \"yaml\",\n  \"json\",\n  \"age\",\n] }\nserde = \"1\"\nserde_derive = \"1\"\nserde_ignored = \"0.1\"\nserde_json = \"1\"\nserde_yaml = \"0.9\"\nsha1 = \"0.10\"\nsha2 = \"0.10\"\nblake3 = \"1\"\nchacha20poly1305 = \"0.10\"\nshell-escape = \"0.1\"\nshell-words = \"1\"\nshellexpand = \"3\"\nsignal-hook = \"0.3\"\nsiphasher = \"1\"\nstrum = { version = \"0.27\", features = [\"derive\"] }\nsys-info = \"0.9\"\ntabled = { version = \"0.20\", features = [\"ansi\"] }\ntaplo = \"0.14\"\ntar = \"0.4\"\ntempfile = \"3\"\ntera = \"1\"\nterminal_size = \"0.4\"\nthiserror = \"2\"\ntokio = { version = \"1\", features = [\"full\"] }\ntokio-retry = \"0.3\"\ntoml = { version = \"0.9\", features = [\"parse\", \"preserve_order\"] }\ntoml_edit = { version = \"0.24\", features = [\"parse\"] }\nubi = { version = \"0.8\", default-features = false }\nurl = \"2\"\nurlencoding = \"2\"\nusage-lib = { version = \"2\", features = [\"clap\", \"docs\"] }\nversions = { version = \"6\", features = [\"serde\"] }\nvfox = { path = \"crates/vfox\", default-features = false }\naqua-registry = { path = \"crates/aqua-registry\" }\nmise-interactive-config = { path = \"crates/mise-interactive-config\", version = \"2026.1.12\" }\nwalkdir = \"2\"\nwhich = \"7\"\nxx = { version = \"2.5\", default-features = false, features = [\"glob\"] }\nxz2 = \"0.1\"\nzip = { version = \"3\", default-features = false, features = [\"deflate\"] }\nzstd = \"0.13\"\n\n[target.'cfg(unix)'.dependencies]\nexec = \"0.3\"\nnix = { version = \"0.30\", features = [\"signal\", \"term\", \"user\"] }\nself_update = { version = \"0.42\", optional = true, default-features = false, features = [\n  \"archive-tar\",\n  \"compression-flate2\",\n  \"signatures\",\n  \"rustls\",\n] }\n\n[target.'cfg(windows)'.dependencies]\nself_update = { version = \"0.42\", optional = true, default-features = false, features = [\n  \"archive-zip\",\n  \"compression-zip-deflate\",\n  \"signatures\",\n  \"rustls\",\n] }\nzipsign-api = \"0.1\"\nsevenz-rust = \"0.6\"\nwinapi = { version = \"0.3.9\", features = [\"consoleapi\", \"minwindef\"] }\n\n[build-dependencies]\nbuilt = { version = \"0.8\", features = [\"chrono\"] }\ncfg_aliases = \"0.2\"\nheck = \"0.5\"\ntoml = \"0.9\"\nindexmap = \"2\"\nserde_yaml = \"0.9\"\n\n[dev-dependencies]\nclap-sort = \"1\"\nctor = \"0.4\"\ninsta = { version = \"1\", features = [\"filters\", \"json\"] }\nmockito = \"1\"\npretty_assertions = \"1\"\ntest-log = \"0.2\"\n\n[features]\ndefault = [\"native-tls\", \"vfox/vendored-lua\", \"self_update\"]\nnative-tls = [\n  \"gix/blocking-http-transport-reqwest-native-tls\",\n  \"reqwest/native-tls\",\n  \"rattler/native-tls\",\n  \"rattler_repodata_gateway/native-tls\",\n  \"sigstore-verification/native-tls\",\n  \"ubi/native-tls\",\n  \"vfox/native-tls\",\n  \"xx/native-tls\",\n]\nrustls = [\n  \"gix/blocking-http-transport-reqwest-rust-tls\",\n  \"reqwest/rustls-tls\",\n  \"rattler/rustls-tls\",\n  \"rattler_repodata_gateway/rustls-tls\",\n  \"self_update/rustls\",\n  \"sigstore-verification/rustls\",\n  \"ubi/rustls-tls\",\n  \"vfox/rustls\",\n  \"xx/rustls\",\n]\nrustls-native-roots = [\n  \"gix/blocking-http-transport-reqwest-rust-tls\",\n  \"reqwest/rustls-tls-native-roots\",\n  \"rattler/rustls-tls\",\n  \"rattler_repodata_gateway/rustls-tls\",\n  \"self_update/rustls\",\n  \"sigstore-verification/rustls-native-roots\",\n  \"ubi/rustls-tls-native-roots\",\n  \"vfox/rustls-native-roots\",\n  \"xx/rustls-native-roots\",\n]\n\n[package.metadata.binstall]\nbin-dir = \"mise/bin/mise\"\n[package.metadata.binstall.overrides.aarch64-apple-darwin]\npkg-url = \"{ repo }/releases/download/v{ version }/mise-v{version}-macos-arm64{ archive-suffix }\"\n[package.metadata.binstall.overrides.x86_64-apple-darwin]\npkg-url = \"{ repo }/releases/download/v{ version }/mise-v{version}-macos-x64{ archive-suffix }\"\n[package.metadata.binstall.overrides.aarch64-unknown-linux-gnu]\npkg-url = \"{ repo }/releases/download/v{ version }/mise-v{version}-linux-arm64{ archive-suffix }\"\n[package.metadata.binstall.overrides.x86_64-unknown-linux-gnu]\npkg-url = \"{ repo }/releases/download/v{ version }/mise-v{version}-linux-x64{ archive-suffix }\"\n[package.metadata.binstall.overrides.armv7-unknown-linux-gnueabihf]\npkg-url = \"{ repo }/releases/download/v{ version }/mise-v{version}-linux-armv7{ archive-suffix }\"\n\n[package.metadata.cargo-machete]\nignored = [\"aws-lc-rs\", \"built\", \"cfg_aliases\", \"openssl\", \"rmcp-macros\"]\n\n[package.metadata.release]\npre-release-replacements = [\n  { file = \"docs/installing-mise.md\", search = \"MISE_VERSION=v[0-9]+\\\\.[0-9]+\\\\.[0-9]+\", replace = \"MISE_VERSION=v{{version}}\" },\n  { file = \"docs/installing-mise.md\", search = \"/download/v[0-9]+\\\\.[0-9]+\\\\.[0-9]+/mise-v[0-9]+\\\\.[0-9]+\\\\.[0-9]+-linux-x64\", replace = \"/download/v{{version}}/mise-v{{version}}-linux-x64\" },\n]\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = [\n  'cfg(coverage,coverage_nightly)',\n] }\n\n[lints.clippy]\nborrowed_box = \"allow\"\n"
  },
  {
    "path": "Cross.toml",
    "content": "# Cross configuration for mise\n# Use cross 0.2.5 images which are based on Ubuntu 16.04 (glibc 2.23)\n# This ensures compatibility with Amazon Linux 2 (glibc 2.26) and other older systems\n\n[build.env]\npassthrough = [\n  \"RUST_BACKTRACE\",\n  \"CARGO_TERM_COLOR\",\n  \"AWS_LC_SYS_EXTERNAL_BINDGEN\",\n  \"BINDGEN_EXTRA_CLANG_ARGS\",\n]\n\n# Explicitly use 0.2.5 images for GNU targets (Ubuntu 16.04, glibc 2.23)\n[target.x86_64-unknown-linux-gnu]\nimage = \"ghcr.io/cross-rs/x86_64-unknown-linux-gnu:0.2.5\"\n\n[target.aarch64-unknown-linux-gnu]\n# Use newer image for aarch64 to get assembler that supports ARMv8.2-A crypto instructions\n# This is based on Ubuntu 20.04 (glibc 2.31) but should still be compatible with Amazon Linux 2\nimage = \"ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main\"\npre-build = [\n  \"apt-get update && apt-get install --assume-yes --no-install-recommends libclang-dev clang curl\",\n  \"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable\",\n  \". ~/.cargo/env && cargo install --force --locked bindgen-cli\",\n  \"ln -s ~/.cargo/bin/bindgen /usr/local/bin/bindgen\",\n]\n\n[target.armv7-unknown-linux-gnueabi]\nimage = \"ghcr.io/cross-rs/armv7-unknown-linux-gnueabi:0.2.5\"\npre-build = [\n  \"dpkg --add-architecture armhf\",\n  \"apt-get update && apt-get install -y libclang-dev clang llvm-dev pkg-config\",\n]\n\n\n# Musl targets for static linking\n[target.x86_64-unknown-linux-musl]\nimage = \"ghcr.io/cross-rs/x86_64-unknown-linux-musl:0.2.5\"\n\n[target.aarch64-unknown-linux-musl]\nimage = \"ghcr.io/cross-rs/aarch64-unknown-linux-musl:0.2.5\"\n\n[target.armv7-unknown-linux-musleabi]\nimage = \"ghcr.io/cross-rs/armv7-unknown-linux-musleabi:0.2.5\"\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2025 Jeff Dickey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n\n<h1 align=\"center\">\n  <a href=\"https://mise.jdx.dev\">\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"docs/public/logo-dark.svg\" />\n      <img src=\"docs/public/logo-light.svg\" alt=\"mise\" width=\"256\" height=\"256\" />\n    </picture>\n    <br>\n    mise-en-place\n  </a>\n</h1>\n\n<p>\n  <a href=\"https://crates.io/crates/mise\"><img alt=\"Crates.io\" src=\"https://img.shields.io/crates/v/mise?style=for-the-badge&color=8B2252\"></a>\n  <a href=\"https://github.com/jdx/mise/blob/main/LICENSE\"><img alt=\"GitHub\" src=\"https://img.shields.io/github/license/jdx/mise?style=for-the-badge&color=6B7F4E\"></a>\n  <a href=\"https://github.com/jdx/mise/actions/workflows/test.yml\"><img alt=\"GitHub Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/jdx/mise/test.yml?style=for-the-badge&color=C5975B\"></a>\n  <a href=\"https://discord.gg/mABnUDvP57\"><img alt=\"Discord\" src=\"https://img.shields.io/discord/1066429325269794907?style=for-the-badge&color=8B2252\"></a>\n</p>\n\n<p><b>The front-end to your dev env</b></p>\n\n<p align=\"center\">\n  <a href=\"https://mise.jdx.dev/getting-started.html\">Getting Started</a> •\n  <a href=\"https://mise.jdx.dev\">Documentation</a> •\n  <a href=\"https://mise.jdx.dev/dev-tools/\">Dev Tools</a> •\n  <a href=\"https://mise.jdx.dev/environments/\">Environments</a> •\n  <a href=\"https://mise.jdx.dev/tasks/\">Tasks</a>\n</p>\n\n<hr />\n\n</div>\n\n## What is it?\n\n- Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm) or [pyenv](https://github.com/pyenv/pyenv) but for any language) it manages [dev tools](https://mise.jdx.dev/dev-tools/) like node, python, cmake, terraform, and [hundreds more](https://mise.jdx.dev/registry.html).\n- Like [direnv](https://github.com/direnv/direnv) it manages [environment variables](https://mise.jdx.dev/environments/) for different project directories.\n- Like [make](https://www.gnu.org/software/make/manual/make.html) it manages [tasks](https://mise.jdx.dev/tasks/) used to build and test projects.\n\n## Demo\n\nThe following demo shows how to install and use `mise` to manage multiple versions of `node` on the same system.\nNote that calling `which node` gives us a real path to node, not a shim.\n\nIt also shows that you can use `mise` to install and many other tools such as `jq`, `terraform`, or `go`.\n\n[![demo](./docs/tapes/demo.gif)](https://mise.jdx.dev/demo.html)\n\nSee [demo transcript](https://mise.jdx.dev/demo.html).\n\n## Quickstart\n\n### Install mise\n\nSee [Getting started](https://mise.jdx.dev/getting-started.html) for more options.\n\n```sh-session\n$ curl https://mise.run | sh\n$ ~/.local/bin/mise --version\n              _                                        __\n   ____ ___  (_)_______        ___  ____        ____  / /___ _________\n  / __ `__ \\/ / ___/ _ \\______/ _ \\/ __ \\______/ __ \\/ / __ `/ ___/ _ \\\n / / / / / / (__  )  __/_____/  __/ / / /_____/ /_/ / / /_/ / /__/  __/\n/_/ /_/ /_/_/____/\\___/      \\___/_/ /_/     / .___/_/\\__,_/\\___/\\___/\n                                            /_/                 by @jdx\n2026.3.9 macos-arm64 (2026-03-13)\n```\n\nHook mise into your shell (pick the right one for your shell):\n\n```sh-session\n# note this assumes mise is located at ~/.local/bin/mise\n# which is what https://mise.run does by default\necho 'eval \"$(~/.local/bin/mise activate bash)\"' >> ~/.bashrc\necho 'eval \"$(~/.local/bin/mise activate zsh)\"' >> ~/.zshrc\necho '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish\necho '~/.local/bin/mise activate pwsh | Out-String | Invoke-Expression' >> ~/.config/powershell/Microsoft.PowerShell_profile.ps1\n```\n\n### Execute commands with specific tools\n\n```sh-session\n$ mise exec node@24 -- node -v\nmise node@24.x.x ✓ installed\nv24.x.x\n```\n\n### Install tools\n\n```sh-session\n$ mise use --global node@24 go@1\n$ node -v\nv24.x.x\n$ go version\ngo version go1.x.x macos/arm64\n```\n\nSee [dev tools](https://mise.jdx.dev/dev-tools/) for more examples.\n\n### Manage environment variables\n\n```toml\n# mise.toml\n[env]\nSOME_VAR = \"foo\"\n```\n\n```sh-session\n$ mise set SOME_VAR=bar\n$ echo $SOME_VAR\nbar\n```\n\nNote that `mise` can also [load `.env` files](https://mise.jdx.dev/environments/#env-directives).\n\n### Run tasks\n\n```toml\n# mise.toml\n[tasks.build]\ndescription = \"build the project\"\nrun = \"echo building...\"\n```\n\n```sh-session\n$ mise run build\nbuilding...\n```\n\nSee [tasks](https://mise.jdx.dev/tasks/) for more information.\n\n### Example mise project\n\nHere is a combined example to give you an idea of how you can use mise to manage your a project's tools, environment, and tasks.\n\n```toml\n# mise.toml\n[tools]\nterraform = \"1\"\naws-cli = \"2\"\n\n[env]\nTF_WORKSPACE = \"development\"\nAWS_REGION = \"us-west-2\"\nAWS_PROFILE = \"dev\"\n\n[tasks.plan]\ndescription = \"Run terraform plan with configured workspace\"\nrun = \"\"\"\nterraform init\nterraform workspace select $TF_WORKSPACE\nterraform plan\n\"\"\"\n\n[tasks.validate]\ndescription = \"Validate AWS credentials and terraform config\"\nrun = \"\"\"\naws sts get-caller-identity\nterraform validate\n\"\"\"\n\n[tasks.deploy]\ndescription = \"Deploy infrastructure after validation\"\ndepends = [\"validate\", \"plan\"]\nrun = \"terraform apply -auto-approve\"\n```\n\nRun it with:\n\n```sh-session\nmise install # install tools specified in mise.toml\nmise run deploy\n```\n\nFind more examples in the [mise cookbook](https://mise.jdx.dev/mise-cookbook/).\n\n## Full Documentation\n\nSee [mise.jdx.dev](https://mise.jdx.dev)\n\n## GitHub Issues & Discussions\n\nDue to the volume of issue submissions mise received, using GitHub Issues became unsustainable for\nthe project. Instead, mise uses GitHub Discussions which provide a more community-centric platform\nfor communication and require less management on the part of the maintainers.\n\nPlease note the following discussion categories, which match how issues are often used:\n\n- [Announcements](https://github.com/jdx/mise/discussions/categories/announcements)\n- [Ideas](https://github.com/jdx/mise/discussions/categories/ideas): for feature requests, etc.\n- [Troubleshooting & Bug Reports](https://github.com/jdx/mise/discussions/categories/troubleshooting-and-bug-reports)\n\n## Special Thanks\n\nWe're grateful for Cloudflare's support through [Project Alexandria](https://www.cloudflare.com/lp/project-alexandria/).\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=jdx/mise)](https://github.com/jdx/mise/graphs/contributors)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nmise is a convenient tool to manage developer tools, however its model is also open to potential risks. The following\nare major areas of mise and the security considerations currently being made and what needs to be made in the future.\n\nPlease open a ticket or send me an email if you have thoughts on how mise can be made more secure.\n\n## Core CLI Security\n\nDevelopment of the \"core CLI\" is done on jdx/mise which only a single developer (me, @jdx) has access to.\nOther contributors may only submit contributions via public Pull Requests. Reducing the number\nof developers with access down to 1 minimizes the chance of keys being leaked.\n\nThis does create a [bus factor](https://en.wikipedia.org/wiki/Bus_factor) problem. If I suddenly died one day\nor otherwise wasn't able to continue development at all there are some successors listed in my GitHub account\nthat can take over my account if need be.\n\nThe dependencies in the core CLI are a security vector. I've tried to be judicious about what dependencies make it into\nthe project. I only select dependencies with broad usage across the Rust community where possible.\nI'm open to PRs or suggestions on reducing dependency count even at the cost of functionality because it will make\nmise more secure.\n\n## mise.jdx.dev\n\nmise.jdx.dev is the asset host for mise. It's used to host precompiled mise CLI binaries, and hosts a \"[VERSION](https://mise.jdx.dev/VERSION)\"\nwhich mise uses to occasionally check for a new version being released. Everything hosted there uses a single\nvendor to reduce surface area.\n\n## Native Security Verification\n\nmise provides **native Rust implementation** for security verification of tools, eliminating the need for external dependencies like `cosign`, `slsa-verifier`, `minisign`, or `gh` CLI tools. This applies to tools using the aqua backend.\n\n### Supported Verification Methods\n\n- **Cosign signatures**: Keyless and key-based signature verification\n- **SLSA provenance**: Verification of Supply-chain Levels for Software Artifacts (SLSA) attestations\n- **GitHub Artifact Attestations**: Verification of GitHub's artifact attestation system\n- **Minisign verification**: Verification of minisign signatures\n- **Checksum verification**: Always enabled for supported backends\n\n### Configuration\n\nAll verification methods are enabled by default and can be configured via environment variables:\n\n```bash\n# Enable/disable specific verification methods\nexport MISE_AQUA_COSIGN=true                 # Default: true\nexport MISE_AQUA_SLSA=true                   # Default: true\nexport MISE_AQUA_GITHUB_ATTESTATIONS=true    # Default: true\nexport MISE_AQUA_MINISIGN=true               # Default: true\n```\n\n### How it Works\n\nYou will see this verification happen automatically when aqua tools are installed. The verification status is displayed during installation with progress indicators. If any verification fails, the installation will be aborted.\n\nSee the [aqua docs](https://aquaproj.github.io/docs/reference/security/cosign-slsa) for more on how verification is configured in the [aqua registry](https://github.com/aquaproj/aqua-registry).\n\nIf you notice a tool offers security verification methods (gpg/slsa/cosign/minisign/etc), consider making a PR to the aqua registry to enable verification for that tool.\n\n## `mise.lock`\n\nmise has support for [lockfiles](https://mise.jdx.dev/configuration/settings.html#lockfile) which will\nstore/verify the checksum of tool tarballs. Committing this into your repository is a good way to ensure\nthat the exact same version of a tool is installed across all developers and CI/CD systems.\n\nNot all backends support this—notably asdf plugins do not.\n\n## asdf plugins\n\nasdf plugins in asdf (but not with mise's default tools) are dangerous. They are typically owned by random developers\nunconnected to either asdf or the tool vendor. They may get hacked or maliciously inject code into\ntheir plugin that could trivially execute code on your machine.\n\nasdf plugins are not used for tools inside the [registry](https://github.com/jdx/mise/blob/main/registry/) whenever possible.\nSometimes it is not possible to use more secure backends like aqua/ubi because tools have complex install\nsetups or need to export env vars. As of 2025-01-08, <25% of tools use asdf plugins as the default backend.\nAll of these are hosted in the [mise-plugins org](https://github.com/mise-plugins) to secure the supply\nchain so you do not need to rely on plugins maintained by anyone except me.\n\nOf course if you _manually_ add plugins not from the mise-plugins org you will want to ensure they\nare coming from a trusted source.\n\nPlease contribute to this effort to migrate away from asdf plugins by checking if a tool works in ubi or aqua and submitting a PR to\n[registry/](https://github.com/jdx/mise/blob/main/registry/) to add it. If it doesn't work\nin ubi or is missing from aqua, submit an issue or PR to the respective project to add it. New tools\nusing asdf are **not** likely to be accepted unless they cannot be supported with any other backend.\n\n## Supported Versions\n\nThe only supported version is the most recent one.\n\n## Reporting a Vulnerability\n\nSend an email to security@<MISE_JDX_DOMAIN_IN_README>\n\nIf you want, you may encrypt the message with GPG:\n\n<details>\n  <summary>@jdx's public key</summary>\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGQfPjUBEADAtjLxcoJlHYNwvN8xYEai/waWZpnKvNWP86kYuX5xqb/GR1wZ\nTQ4usQPcpTj60XQaF3jUwtW8/1PH/gQv0516qAIlqHVvvMyGD/u2iwr+U8JtIGWf\nB87mL2aMvg6GqXoR3dgCtYkHd839Z0wVFOvgkzWdx3jOWE73KQpN0PeunBNsCw/K\n4wR/gEBNfiAbi0i3RIbpSKHTtRZ1e/1+1o2jxz48a/IdCzFzN9zOplfhASo0C/AB\nPSjlFnvlB5jjWqyGln6ycunEn0dhdzi7f1MdfNmj19tqqQYKYIy3AOFiRNqKLlWo\ndOPTJMYdCD8CkLh5GTOWq0xZZ/s5bHiw2KuQxyZsm2eo4MH7pOEHuH1yFjyrbli7\n/8/iLfaGx89aK7Krt+dd60XMPQh8rGjClVdC8GQS8XMjerjdk5g22dd7s5n7shGm\ngZalidw3CFppO2po1YR8yNc5UJz7gzGCZsQfyC1Ao376BFM/cXlnje6RG2Unsy8O\nuKE2O5vFOmppoWmaM5KcCFLa7NP2Wu8Y8CaoDZaBZeGFHffvxSKh/J69ECVvTM91\nXn8B0COiiqkYKpqNf+KgGXzQvj3ABKG0Q27T5VUHW3F1jdPKjbMmdbqorRDr7v0a\nPZSwqrlTenZVCVdEsRHsHevIZ6+neZ3hHEk66EtaG45Qkna2EahhS+IPGQARAQAB\ntCBKZWZmcmV5IERpY2tleSA8Z3BnQGpkeGNvZGUuY29tPokCVAQTAQgAPhYhBDFB\nttCiFJlyWolR/FCs4PPr5+BHBQJkHz41AhsDBQkHhh9cBQsJCAcCBhUKCQgLAgQW\nAgMBAh4BAheAAAoJEFCs4PPr5+BHUsIP/0AL/lTNZ22yynIE7EXwWsLTolrNHiaz\n79s/MH04i1IazkElvY7MVL0iTqozYnSaEJ7BhtNPUkoCX79cLHKv/nD9CJF8qwcK\nGgYCirXGEol30P1s2K2c1Rr4wcul+SamQ2vHrBes+/0ksuvK9yAZV6y8nWCukO4Z\n5B4DVHuvQ0UmJ6tWf53sFpRnLWB+8VB1n931uZXeHjxo2s5/x3E2FknH6/l8/+Ey\nd9T44RzlOwkZYTrw08O1PLLNGkOxdD3sGi7Q/JSPHmlhBBqpnqxT4wOFJQnluJji\ned4qlB4oXa2CM2VkbSdmQ6ls67Qju0/LKsYwd7QNpo/fODXR3MLIQDUo9ZzKmvgB\nr9L2BQDz4vOKdYSm2MLyGsB6W9GsVHVjnGnZWhiKOOH1jxnI2y6btJZNQYemMtLo\nY7DlTogRaq1h62WHkm3cbPqXYpfEBH9AJRAZgyUbc703BJfr5i8epoRajP/jxTVi\nPtIak2/kJu6adxJ+nutz+1ycc8XBlfAnSTj87wKXM0nsboK3Kyd5cZ2m7CFF7tIY\ny/Ti7jVbVNMH6OugoCLYXnINIW3QFBKhM7/uouukN3ww5zJ58w0mqkySzxiY4jr8\nOOLW9oARmq4gvevRmnd97hmmu1h0A3TPOzbr97zF8xCjKkf04IpdfMPEccNg1jWK\nQEqn+1m3XNdDuQINBGQfPjUBEACu7zv4/gNxUDCwbnkkK7wQL3sX7yZKkhGZgpXR\nH9h+mAf/DlhKo8yqJiR0C6z+QcsSM1a3RvHHBdRnsun/jEzScP2o5ShQKLCq68qb\nJlSh/FSQQTYTEjC/t4ccMLIYbsccJd+Xg9cRuqGN/jE/SWNwUGrf2FuKQQkTTcrN\ntiHwXHLxUlIHYckyKq4UggL8icaONSpwAWLEwi0u2muMMZHzFnHT33W8+iFHmjCd\nosHZaArWXiQlYQFeoxvnT2hkUK/uQC7ZANup4ebuQr4ZLgo7kWUOKlwpucNFscFy\noIVuNeVYq0ijz1urNMnzGF6Pz0SVjr91lyHGmAdODpYz6vZZ5ipDDrXXDHTyET5c\nj8zUYkbbtxEaE0+MpAN8wrtxmtXt3QMV4MfncJzvKmhFcaRFjvgG+PtC4cxVsmLK\nBD9WKxni0e1jcWPtoRw5LvAinqgTzCF4iw9rUwITWBVg+T2d6kTokTW7J2mrGNSp\nWiE/Gq2+3kzs0BOIPc9h2tzTkhHbsZz9ZTFXLzutxKzfamBVGr0B7MR9wnOyVgQW\ncohmCEhcEIgKiPnmcobXiWE/NpvbtyE7KBVXVFEDvIdpWUf9OaUZNau5gwg6MJRF\nzdWLj2Y7LYK1NbmJWrzg8V3KeBCMxKlVS463DPWMQzfmpMYYravpW1gkekXqxMP6\ngBvRfwARAQABiQI8BBgBCAAmFiEEMUG20KIUmXJaiVH8UKzg8+vn4EcFAmQfPjUC\nGwwFCQeGH1wACgkQUKzg8+vn4EdAbxAAr4SMo8VvAhFlJd/WQlifgREj0On6UFee\nYCKNA8/1cJnXCxb+kQJXLCcYBHGq07NV9OkzCZBLiGM13f0DF/YfcDbUq1ISivoo\nJwTUII48Q1aQseWc3JxkgLPi9CjxE48ynEeFi582Bsz0auzUGk1dbVfJbbpDKd83\n/vZImxN+sfa9no/7l5wsNVIOhPSQrv3BDjMAuqkUIZHNYsp6i3Fo4cj7e6qy4HpG\nXaUnyTsivI2ifr3AYgbg6sgcXmgi0WRipnrX9D99usXfNxi5PNEI3mJF8Tq8bOjy\nJDZd5duJ2Or4yH/LrAOmrCQxC5nNmsHm2uGHRcab4lUDMoPWkDFOzbtY/iAJtQGZ\nVg9o7cVhAXFSgHzSwC8bjGwPwNdmL719wzAvpOB0qmeHo5oqrKcCyz7qgryYvOhH\nZjHmfc++FDuQGhYv8yNAMpPkg2ZfZSD7AM0KigNp0bsOYPhM6n0EqCzoX5SjzSp3\nv+asbUPbVC5G7/YbkNhyohf9iNXqyMrWnYL86LnXIMTi6Sto01BLfRs0QiqztahQ\nJuSHoeBpoXY/yMoHYQCd/O7D12Ha5XDdYfXP0Yf9glS+r+YaVYXxcJ6O/DfV6QEk\nMFPobhR7zlCShd7TdY1a41uxTGB+Wmn4DO0s/wzSgdgxIzG+TM1X47owe7l5RiI1\n1wxfuzN2+ao=\n=/CHf\n-----END PGP PUBLIC KEY BLOCK-----\n\n```\n\n</details>\n\n## Release gpg key\n\nThis is the gpg key used to sign deb releases and the SHASUMS files\ncontained within releases.\n\n<details>\n  <summary>Release gpg key</summary>\n\n```\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nmQINBGWUNRYBEAC1Sz9QTV039Kxez3Olzf0bLPKFjyRovwx1sTCUZUfkYid9qlSw\n4VyWb5M51Og3mSwwD+p55aMMESapqIAer16Mh+rVy2TfYcQ42HfYjoDrgrBlV8Cw\nFutPowt7FpdmUEH4I4ax4fE4gvlHzRXksHQHqDNFcBxSKGnwakknLEOQqW0FEIMH\nBJSPyFTOp8tPqvOXlYXWuL1Kk4dc0MQujk5NbKznWP4VSTBEJgamTDlOg9FEYBQq\nH/zSN7X8X2GBA+D9LqHX+ZBzlvQen2LSD4nl4EhKNOZy7C/bfaOKt4olxhGSrw9+\nd7s/LfqmgjN508Wnzih3PS8VwvfDI04ch0s0SDUfYh8z8atEddc9mXCv9/YSNtl3\n/QAHIEX4E5arqY7OYlRyazR7otCihPeL5rjTSfhw/g1In6IfZsY+CmobvCuBQj9B\nSDJQR+mOawV4T758oDkOtbg1Got0vXGog9yXKulYgzC6/8eX7rcXIsK7qdQTrjy5\nN/vwjevcZB2Y7rpD+9GZzMj112W9X6eFDxMrV+Os6DsS7FRPtCzUlm8Yth/BQoSr\nFx90eBTSxCeEtpDDnpUtcYX0jTJHChenoxNnTTCeQVdtcJPcZL8Kf5yVq/JFu/07\nZD4LlvPIzpI1myjQyDlXWdsn/N10xDEFl067dkpLvF01fayI7A2UbUOl9QARAQAB\ntCRtaXNlIHJlbGVhc2VzIDxyZWxlYXNlQG1pc2UuamR4LmRldj6JAlQEEwEIAD4W\nIQQkhT7J9lXOgLSObDqLgcnRdBOgbQUCZZQ1FgIbAwUJB4YfbAULCQgHAgYVCgkI\nCwIEFgIDAQIeAQIXgAAKCRCLgcnRdBOgbSpGEACYUWzLT0rJU+BB4K8qF80l5GCz\npffI2CkTVgmrdIVIlDnKFjNYFDd3RJsFx5oK77cnyHzKhQzZ0vsm9Q7EGgTMPC7t\n2m2dNMo8t8YGMveUO9JNhr5GE9OuXGWkxW0FC5lOkkzR1CqsqBAGRa/962t6TAdI\nWjxB0U/Dw/CI7Mx59hRDi4em7Fal366DkBw2didyz8xnRatCsBuua+tgIklAawfl\ny4kVO99ezGveFElAizns1h7GwANyw5OSQWRDiqXuqnsvC3jMC35aYJmbyBDYgzdD\nMQke/uxqvvAWLmmZLEO66urkvDPcgVtC1RJyLVqLSybq6eyBgCs7GwPugKq+T9Gx\ncW/LPodyWzCqXSua1yC/JXAivbcHOyO//hhwNVtaSSfkV6jqQJwiXizFSFiEvhRj\ntD8tWo2Ivq4j/77J8gpWw0ca/PUPu5hSSSSp/HH89/8S/o67IeqK5t9EpiIBF0j8\nilX2k0veGA1bOgHuMoB6HYOSlEObhDcCqqNcrRPYBhWH2V2U6u4iQptahOTRGO0d\nTU+oLDAo+bwB8Xo8ZTEm3QaZVhK/FWzJLVj2lxQodAf0NRbu2JtMdNnovLjI8Czm\n/7N/0rvtcWOu2fCKE5NtEgVZzN4GC1KNSnc4M1ml6KyRDI+/ooIdUiKKfkqmSeih\nXHj/dpbh3RKIaDuzErkCDQRllDUWARAAxZLN856RxZH4FbPQDZZQn/TgGfrLZehu\ng1M5DyEP5UNj2r+/l2dWybWzkE7jVK2sbaqHeGUuH18e0jpWIWCNHg0Y4aqZc8HK\n/Sgn7APWzNOSbl2ZAjXwoEtKpP7RyOSPr+1f3t1S5qy0DjdGCeCbnnQ2Ju5//lR5\nN2QdiuM+XtBW7oW0g5qkmsonCLpjqrAaQwnHJUw5TUTlQODz3OX6ZG1gIksI4kdw\nwmTGqzpxDx58gfptYHQ+U55k4qUDG4d7XGOo4KAiJ990s+W3D+O6I//z7eKQMfbC\n30+K/sizvi46QICuj44BtCA9fy6h9fRiK1f0gDqBopUNR9QHIP5RPvQtVjAtaYFl\nAD5ZWcnFyrF79dzCC/SbGtAwi249UdCbuVwTH1U+csjkp11K0KMzcD60RQXEKi0U\nISF4STqsPyN0Dp08M6qS8i5334f4AZN61piFkrxDiEsvGE11WsWDDXzkvNNGLN1f\npG+O58pBHbAVsUxDmuUrbHXAtXhxiXsqU1PA9l6QZnB0qe6/i2EjCXM+/0eF2jfP\ndfRGCJEb9SdBR2fBZufbE7ytCBwTSNpN7h5GyMPCIq4vLluEQVRm3izwU5RMrvj6\nBaNgE9gnCspmRmpVABodRbzAflBrGb4Bole5iUwT7puB1J87rkxe+8m6XcJFAGJN\niX0CLLUEKHkAEQEAAYkCPAQYAQgAJhYhBCSFPsn2Vc6AtI5sOouBydF0E6BtBQJl\nlDUWAhsMBQkHhh9sAAoJEIuBydF0E6BtoV4P/193pUjxgyojg0G2ELaxrBqtKAVN\ng1FJABox/C2Lx334W1UyoMiSFkMIdky6xl8zzz3HciQHVeGzRvW//eM810LxLkVK\nWNkVoTgyJV5Voo+TmXyfjaghFQqygCv/MboTcRE3mJh2P0ND+aEJKaXs/2l5suyB\nlq/yOWPFYxR5DhVpQLfuctTUAoxQsi6gYu1b7h3d4x22RFo3RL4g/fDvNGIeDpmQ\nBEOfUDrHfoFt5jZiYmW9E+yrP4hMeV4ujiIb3a0iSx0u4NBGHmGVg+QQ6E6knF6w\niz4LPL6Ze/F8eg7b9gvqeDMh7sJ0eJIkBKly/0OUKWedH+FSZASdTK183QuPB3x3\nsgna2IHECprmdWPWdnGet+8cbQB5R59Qs8WgV9k2JOzUOjzKkl5mQv2uHcSRGGze\n8Uosc4bAr0dDtCUsIY6w8E7lq2V75EV/BWtbyySWjt1ZXHsykNh1QBUZw7e/krBZ\nj4Mt0KoL2YxkI4qnqoVAEqd20Rxvisd+RyeA7L3AnxGlaPVj7iibu4XW9P5stUom\njLQEDnl7ewfTeBbeIH7+EXuTGZttnKN7BOestODBGsD1r7zTKrJfL+MvGO4rG9KT\n9/Q4udpmXDdm4Lze+xm7bLfl3wkXpLLoVs2fndegkj/sSBL2IbhtMjOerEbafK6K\nS1GIqgTqW7TRaQRg\n=yIM2\n-----END PGP PUBLIC KEY BLOCK-----\n```\n\n</details>\n"
  },
  {
    "path": "age.pub",
    "content": "age1y5mxeyps7vjthl8ea59uecmdycflfny8s9fuj620dfyjvl3y3qksqa565h\n"
  },
  {
    "path": "build.rs",
    "content": "use heck::ToUpperCamelCase;\nuse indexmap::IndexMap;\nuse std::path::Path;\nuse std::{env, fs};\n\nfn main() {\n    cfg_aliases::cfg_aliases! {\n        asdf: { any(feature = \"asdf\", not(target_os = \"windows\")) },\n        macos: { target_os = \"macos\" },\n        linux: { target_os = \"linux\" },\n        vfox: { any(feature = \"vfox\", target_os = \"windows\") },\n    }\n    built::write_built_file().expect(\"Failed to acquire build-time information\");\n\n    codegen_settings();\n    codegen_registry();\n}\n\n/// Generate a raw string literal that safely contains the given content.\n/// Dynamically determines the minimum number of '#' needed.\nfn raw_string_literal(s: &str) -> String {\n    // Find the longest sequence of '#' characters following a '\"' in the string\n    let mut max_hashes = 0;\n    let mut current_hashes = 0;\n    let mut after_quote = false;\n\n    for c in s.chars() {\n        if after_quote {\n            if c == '#' {\n                current_hashes += 1;\n                max_hashes = max_hashes.max(current_hashes);\n            } else {\n                after_quote = false;\n                current_hashes = 0;\n            }\n        }\n        if c == '\"' {\n            after_quote = true;\n            current_hashes = 0;\n        }\n    }\n\n    // Use one more '#' than the longest sequence found\n    let hashes = \"#\".repeat(max_hashes + 1);\n    format!(\"r{hashes}\\\"{s}\\\"{hashes}\")\n}\n\n/// Parse options from a TOML value into a Vec of (key, value) pairs\nfn parse_options(opts: Option<&toml::Value>) -> Vec<(String, String)> {\n    opts.map(|opts| {\n        if let Some(table) = opts.as_table() {\n            table\n                .iter()\n                .map(|(k, v)| {\n                    let value = match v {\n                        toml::Value::String(s) => s.clone(),\n                        toml::Value::Table(t) => {\n                            // Serialize nested tables back to TOML string\n                            toml::to_string(t).unwrap_or_default()\n                        }\n                        _ => v.to_string(),\n                    };\n                    (k.clone(), value)\n                })\n                .collect::<Vec<_>>()\n        } else {\n            vec![]\n        }\n    })\n    .unwrap_or_default()\n}\n\nfn load_registry_tools() -> toml::map::Map<String, toml::Value> {\n    let mut tools = toml::map::Map::new();\n    let registry_dir = Path::new(\"registry\");\n\n    println!(\"cargo:rerun-if-changed=registry\");\n\n    let mut files: Vec<_> = fs::read_dir(registry_dir)\n        .expect(\"registry directory not found\")\n        .filter_map(|e| e.ok())\n        .map(|e| e.path())\n        .filter(|p| p.extension().is_some_and(|e| e == \"toml\"))\n        .collect();\n    files.sort();\n\n    for file in files {\n        println!(\"cargo:rerun-if-changed={}\", file.display());\n        let tool_name = file\n            .file_stem()\n            .expect(\"file has no stem\")\n            .to_str()\n            .expect(\"filename is not valid UTF-8\")\n            .to_string();\n        let content = fs::read_to_string(&file)\n            .unwrap_or_else(|e| panic!(\"Failed to read {}: {}\", file.display(), e));\n        let tool_info: toml::Value = toml::de::from_str(&content)\n            .unwrap_or_else(|e| panic!(\"Failed to parse {}: {}\", file.display(), e));\n        tools.insert(tool_name, tool_info);\n    }\n    tools\n}\n\nfn codegen_registry() {\n    let out_dir = env::var_os(\"OUT_DIR\").unwrap();\n    let dest_path = Path::new(&out_dir).join(\"registry.rs\");\n    let mut lines = vec![\n        \"{\".to_string(),\n        \"    let mut m = std::collections::BTreeMap::new();\".to_string(),\n    ];\n\n    let tools = load_registry_tools();\n    for (short, info) in &tools {\n        let info = info.as_table().unwrap();\n        let aliases = info\n            .get(\"aliases\")\n            .cloned()\n            .unwrap_or(toml::Value::Array(vec![]))\n            .as_array()\n            .unwrap()\n            .iter()\n            .map(|v| v.as_str().unwrap().to_string())\n            .collect::<Vec<_>>();\n        let test = info.get(\"test\").map(|t| {\n            let t = t\n                .as_table()\n                .unwrap_or_else(|| panic!(\"[{short}] 'test' field must be a table\"));\n            let cmd = t\n                .get(\"cmd\")\n                .and_then(|v| v.as_str())\n                .unwrap_or_else(|| panic!(\"[{short}] 'test.cmd' must be a string\"))\n                .to_string();\n            let expected = t\n                .get(\"expected\")\n                .and_then(|v| v.as_str())\n                .unwrap_or_else(|| panic!(\"[{short}] 'test.expected' must be a string\"))\n                .to_string();\n            (cmd, expected)\n        });\n        let mut backends = vec![];\n        for backend in info.get(\"backends\").unwrap().as_array().unwrap() {\n            match backend {\n                toml::Value::String(backend) => {\n                    backends.push(format!(\n                        r##\"RegistryBackend{{\n                            full: r#\"{backend}\"#,\n                            platforms: &[],\n                            options: &[],\n                        }}\"##\n                    ));\n                }\n                toml::Value::Table(backend) => {\n                    let full = backend.get(\"full\").unwrap().as_str().unwrap();\n                    let platforms = backend\n                        .get(\"platforms\")\n                        .map(|p| {\n                            p.as_array()\n                                .unwrap()\n                                .iter()\n                                .map(|p| p.as_str().unwrap().to_string())\n                                .collect::<Vec<_>>()\n                        })\n                        .unwrap_or_default();\n                    let backend_options = parse_options(backend.get(\"options\"));\n                    backends.push(format!(\n                        r##\"RegistryBackend{{\n                            full: r#\"{full}\"#,\n                            platforms: &[{platforms}],\n                            options: &[{options}],\n                        }}\"##,\n                        platforms = platforms\n                            .into_iter()\n                            .map(|p| format!(\"\\\"{p}\\\"\"))\n                            .collect::<Vec<_>>()\n                            .join(\", \"),\n                        options = backend_options\n                            .iter()\n                            .map(|(k, v)| format!(\n                                \"({}, {})\",\n                                raw_string_literal(k),\n                                raw_string_literal(v)\n                            ))\n                            .collect::<Vec<_>>()\n                            .join(\", \")\n                    ));\n                }\n                _ => panic!(\"Unknown backend type\"),\n            }\n        }\n        let os = info\n            .get(\"os\")\n            .map(|os| {\n                let os = os.as_array().unwrap();\n                let mut os = os\n                    .iter()\n                    .map(|o| o.as_str().unwrap().to_string())\n                    .collect::<Vec<_>>();\n                os.sort();\n                os\n            })\n            .unwrap_or_default();\n        let description = info\n            .get(\"description\")\n            .map(|d| d.as_str().unwrap().to_string());\n        let depends = info\n            .get(\"depends\")\n            .map(|depends| {\n                let depends = depends.as_array().unwrap();\n                let mut depends = depends\n                    .iter()\n                    .map(|d| d.as_str().unwrap().to_string())\n                    .collect::<Vec<_>>();\n                depends.sort();\n                depends\n            })\n            .unwrap_or_default();\n        let idiomatic_files = info\n            .get(\"idiomatic_files\")\n            .map(|idiomatic_files| {\n                idiomatic_files\n                    .as_array()\n                    .unwrap()\n                    .iter()\n                    .map(|f| f.as_str().unwrap().to_string())\n                    .collect::<Vec<_>>()\n            })\n            .unwrap_or_default();\n        let detect = info\n            .get(\"detect\")\n            .map(|detect| {\n                detect\n                    .as_array()\n                    .unwrap()\n                    .iter()\n                    .map(|f| f.as_str().unwrap().to_string())\n                    .collect::<Vec<_>>()\n            })\n            .unwrap_or_default();\n        let overrides = info\n            .get(\"overrides\")\n            .map(|overrides| {\n                overrides\n                    .as_array()\n                    .unwrap()\n                    .iter()\n                    .map(|f| f.as_str().unwrap().to_string())\n                    .collect::<Vec<_>>()\n            })\n            .unwrap_or_default();\n        let rt = format!(\n            r#\"RegistryTool{{short: \"{short}\", description: {description}, backends: &[{backends}], aliases: &[{aliases}], test: &{test}, os: &[{os}], depends: &[{depends}], idiomatic_files: &[{idiomatic_files}], detect: &[{detect}], overrides: &[{overrides}]}}\"#,\n            description = description\n                .map(|d| format!(\"Some({})\", raw_string_literal(&d)))\n                .unwrap_or(\"None\".to_string()),\n            backends = backends.into_iter().collect::<Vec<_>>().join(\", \"),\n            aliases = aliases\n                .iter()\n                .map(|a| format!(\"\\\"{a}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n            test = test\n                .map(|(t, v)| format!(\n                    \"Some(({}, {}))\",\n                    raw_string_literal(&t),\n                    raw_string_literal(&v)\n                ))\n                .unwrap_or(\"None\".to_string()),\n            os = os\n                .iter()\n                .map(|o| format!(\"\\\"{o}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n            depends = depends\n                .iter()\n                .map(|d| format!(\"\\\"{d}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n            idiomatic_files = idiomatic_files\n                .iter()\n                .map(|f| format!(\"\\\"{f}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n            detect = detect\n                .iter()\n                .map(|f| format!(\"\\\"{f}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n            overrides = overrides\n                .iter()\n                .map(|f| format!(\"\\\"{f}\\\"\"))\n                .collect::<Vec<_>>()\n                .join(\", \"),\n        );\n        lines.push(format!(r#\"    m.insert(\"{short}\", {rt});\"#));\n        for alias in aliases {\n            lines.push(format!(r#\"    m.insert(\"{alias}\", {rt});\"#));\n        }\n    }\n    lines.push(\"    m\".to_string());\n    lines.push(\"}\".to_string());\n\n    fs::write(&dest_path, lines.join(\"\\n\")).unwrap();\n}\n\nfn codegen_settings() {\n    let out_dir = env::var_os(\"OUT_DIR\").unwrap();\n    let dest_path = Path::new(&out_dir).join(\"settings.rs\");\n    let mut lines = vec![\n        r#\"#[derive(Config, Default, Debug, Clone, Serialize)]\n#[config(partial_attr(derive(Clone, Serialize, Default)))]\npub struct Settings {\"#\n            .to_string(),\n    ];\n\n    println!(\"cargo:rerun-if-changed=settings.toml\");\n    let settings_toml = fs::read_to_string(\"settings.toml\").expect(\"Failed to read settings.toml\");\n    let settings: toml::Table =\n        toml::de::from_str(&settings_toml).expect(\"Failed to parse settings.toml\");\n    let props_to_code = |key: &str, props: &toml::Value| {\n        let mut lines = vec![];\n        let props = props.as_table().unwrap();\n        if let Some(description) = props.get(\"description\") {\n            lines.push(format!(\"    /// {}\", description.as_str().unwrap()));\n        }\n        let type_ = props\n            .get(\"rust_type\")\n            .map(|rt| rt.as_str().unwrap())\n            .or_else(|| {\n                props.get(\"type\").map(|t| match t.as_str().unwrap() {\n                    \"Bool\" => \"bool\",\n                    \"String\" => \"String\",\n                    \"Integer\" => \"i64\",\n                    \"Url\" => \"String\",\n                    \"Path\" => \"PathBuf\",\n                    \"Duration\" => \"String\",\n                    \"ListString\" => \"Vec<String>\",\n                    \"ListPath\" => \"Vec<PathBuf>\",\n                    \"SetString\" => \"BTreeSet<String>\",\n                    \"IndexMap<String, String>\" => \"IndexMap<String, String>\",\n                    \"BoolOrString\" => {\n                        panic!(r#\"type \\\"BoolOrString\\\" requires a `rust_type` to be specified\"#)\n                    }\n                    t => panic!(\"Unknown type: {t}\"),\n                })\n            });\n        if let Some(type_) = type_ {\n            let type_ = if props.get(\"optional\").is_some_and(|v| v.as_bool().unwrap()) {\n                format!(\"Option<{type_}>\")\n            } else {\n                type_.to_string()\n            };\n            let mut opts = IndexMap::new();\n            if let Some(env) = props.get(\"env\") {\n                opts.insert(\"env\".to_string(), env.to_string());\n            }\n            if let Some(default) = props.get(\"default\") {\n                opts.insert(\"default\".to_string(), default.to_string());\n            } else if type_ == \"bool\" {\n                opts.insert(\"default\".to_string(), \"false\".to_string());\n            }\n            if let Some(parse_env) = props.get(\"parse_env\") {\n                opts.insert(\n                    \"parse_env\".to_string(),\n                    parse_env.as_str().unwrap().to_string(),\n                );\n            }\n            if let Some(deserialize_with) = props.get(\"deserialize_with\") {\n                opts.insert(\n                    \"deserialize_with\".to_string(),\n                    deserialize_with.as_str().unwrap().to_string(),\n                );\n            }\n            lines.push(format!(\n                \"    #[config({})]\",\n                opts.iter()\n                    .map(|(k, v)| format!(\"{k} = {v}\"))\n                    .collect::<Vec<_>>()\n                    .join(\", \")\n            ));\n            lines.push(format!(\"    pub {key}: {type_},\"));\n        } else {\n            lines.push(\"    #[config(nested)]\".to_string());\n            lines.push(format!(\n                \"    pub {}: Settings{},\",\n                key,\n                key.to_upper_camel_case()\n            ));\n        }\n        lines.join(\"\\n\")\n    };\n    for (key, props) in &settings {\n        lines.push(props_to_code(key, props));\n    }\n    lines.push(\"}\".to_string());\n\n    let nested_settings = settings\n        .iter()\n        .filter(|(_, v)| !v.as_table().unwrap().contains_key(\"type\"))\n        .collect::<Vec<_>>();\n    for (child, props) in &nested_settings {\n        lines.push(format!(\n            r#\"\n#[derive(Config, Default, Debug, Clone, Serialize)]\n#[config(partial_attr(derive(Clone, Serialize, Default)))]\n#[config(partial_attr(serde(deny_unknown_fields)))]\npub struct Settings{name} {{\"#,\n            name = child.to_upper_camel_case()\n        ));\n\n        for (key, props) in props.as_table().unwrap() {\n            lines.push(props_to_code(key, props));\n        }\n        lines.push(\"}\".to_string());\n    }\n\n    lines.push(\n        r#\"\npub static SETTINGS_META: Lazy<IndexMap<&'static str, SettingsMeta>> = Lazy::new(|| {\n    indexmap!{\"#\n            .to_string(),\n    );\n    let push_deprecated_fields = |lines: &mut Vec<String>, props: &toml::Table| {\n        let deprecated = props\n            .get(\"deprecated\")\n            .map(|v| v.as_str().unwrap().to_string());\n        let warn_at = props\n            .get(\"deprecated_warn_at\")\n            .map(|v| v.as_str().unwrap().to_string());\n        let remove_at = props\n            .get(\"deprecated_remove_at\")\n            .map(|v| v.as_str().unwrap().to_string());\n        match deprecated {\n            Some(msg) => lines.push(format!(\n                \"        deprecated: Some({}),\",\n                raw_string_literal(&msg)\n            )),\n            None => lines.push(\"        deprecated: None,\".to_string()),\n        }\n        match warn_at {\n            Some(v) => lines.push(format!(\"        deprecated_warn_at: Some({v:?}),\")),\n            None => lines.push(\"        deprecated_warn_at: None,\".to_string()),\n        }\n        match remove_at {\n            Some(v) => lines.push(format!(\"        deprecated_remove_at: Some({v:?}),\")),\n            None => lines.push(\"        deprecated_remove_at: None,\".to_string()),\n        }\n    };\n    for (name, props) in &settings {\n        let props = props.as_table().unwrap();\n        if let Some(type_) = props.get(\"type\").map(|v| v.as_str().unwrap()) {\n            // We could shadow the 'type_' variable, but its a best practice to avoid shadowing.\n            // Thus, we introduce 'meta_type' here.\n            let meta_type = match type_ {\n                \"IndexMap<String, String>\" => \"IndexMap\",\n                other => other,\n            };\n            lines.push(format!(\n                r#\"    \"{name}\" => SettingsMeta {{\n        type_: SettingsType::{meta_type},\"#,\n            ));\n            if let Some(description) = props.get(\"description\") {\n                let description = description.as_str().unwrap().to_string();\n                lines.push(format!(\n                    \"        description: {},\",\n                    raw_string_literal(&description)\n                ));\n            }\n            push_deprecated_fields(&mut lines, props);\n            lines.push(\"    },\".to_string());\n        }\n    }\n    for (name, props) in &nested_settings {\n        for (key, props) in props.as_table().unwrap() {\n            let props = props.as_table().unwrap();\n            if let Some(type_) = props.get(\"type\").map(|v| v.as_str().unwrap()) {\n                // We could shadow the 'type_' variable, but its a best practice to avoid shadowing.\n                // Thus, we introduce 'meta_type' here.\n                let meta_type = match type_ {\n                    \"IndexMap<String, String>\" => \"IndexMap\",\n                    other => other,\n                };\n                lines.push(format!(\n                    r#\"    \"{name}.{key}\" => SettingsMeta {{\n        type_: SettingsType::{meta_type},\"#,\n                ));\n            }\n            if let Some(description) = props.get(\"description\") {\n                let description = description.as_str().unwrap().to_string();\n                lines.push(format!(\n                    \"        description: {},\",\n                    raw_string_literal(&description)\n                ));\n            }\n            push_deprecated_fields(&mut lines, props);\n            lines.push(\"    },\".to_string());\n        }\n    }\n    lines.push(\n        r#\"    }\n});\n    \"#\n        .to_string(),\n    );\n\n    // Generate MisercSettings struct for early initialization settings\n    lines.push(\n        r#\"\n/// Settings that can be set in .miserc.toml for early initialization.\n/// These settings affect config file discovery and must be loaded before\n/// the main config files are parsed.\n#[derive(Debug, Clone, Default, serde::Deserialize)]\npub struct MisercSettings {\"#\n            .to_string(),\n    );\n\n    for (key, props) in &settings {\n        let props = props.as_table().unwrap();\n        // Only include settings with rc = true\n        if props\n            .get(\"rc\")\n            .is_some_and(|v| v.as_bool().unwrap_or(false))\n        {\n            if let Some(description) = props.get(\"description\") {\n                lines.push(format!(\"    /// {}\", description.as_str().unwrap()));\n            }\n            let type_ = props\n                .get(\"rust_type\")\n                .map(|rt| rt.as_str().unwrap())\n                .or_else(|| {\n                    props.get(\"type\").map(|t| match t.as_str().unwrap() {\n                        \"Bool\" => \"bool\",\n                        \"String\" => \"String\",\n                        \"Integer\" => \"i64\",\n                        \"Url\" => \"String\",\n                        \"Path\" => \"PathBuf\",\n                        \"Duration\" => \"String\",\n                        \"ListString\" => \"Vec<String>\",\n                        \"ListPath\" => \"Vec<PathBuf>\",\n                        \"SetString\" => \"BTreeSet<String>\",\n                        \"IndexMap<String, String>\" => \"IndexMap<String, String>\",\n                        \"BoolOrString\" => panic!(\n                            r#\"type \\\"BoolOrString\\\" requires a `rust_type` to be specified\"#\n                        ),\n                        t => panic!(\"Unknown type: {t}\"),\n                    })\n                });\n            if let Some(type_) = type_ {\n                // All miserc settings are optional\n                let type_ = format!(\"Option<{type_}>\");\n                lines.push(format!(\"    pub {key}: {type_},\"));\n            }\n        }\n    }\n    lines.push(\"}\".to_string());\n\n    fs::write(&dest_path, lines.join(\"\\n\")).unwrap();\n}\n"
  },
  {
    "path": "cliff.toml",
    "content": "# git-cliff ~ default configuration file\n# https://git-cliff.org/docs/configuration\n#\n# Lines starting with \"#\" are comments.\n# Configuration options are organized into tables and keys.\n# See documentation for more information on available options.\n\n[changelog]\n# changelog header\nheader = \"\"\"\n# Changelog\\n\n\"\"\"\n# template for the changelog body\n# https://keats.github.io/tera/docs/#introduction\nbody = \"\"\"\n{% if version %}\\\n    {% if previous.version %}\\\n        ## [{{ version | trim_start_matches(pat=\"v\") }}]($REPO/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format=\"%Y-%m-%d\") }}\n    {% else %}\\\n        ## [{{ version | trim_start_matches(pat=\"v\") }}] - {{ timestamp | date(format=\"%Y-%m-%d\") }}\n    {% endif %}\\\n{% else %}\\\n    ## [unreleased]\n{% endif %}\\\n{% for group, commits in commits | group_by(attribute=\"group\") %}\n    ### {{ group | striptags | trim | upper_first }}\n\n    {% for commit in commits\n    | filter(attribute=\"scope\")\n    | sort(attribute=\"scope\") -%}\n        {% if commit.scope -%}\n    - {{self::commit(commit=commit)}}\\\n        {% endif -%}\n    {% endfor -%}\n    {% for commit in commits -%}\n        {% if commit.scope -%}\n        {% else -%}\n    - {{self::commit(commit=commit)}}\\\n        {% endif -%}\n    {% endfor -%}\n{% endfor -%}\n{% if github.contributors | filter(attribute=\"is_first_time\", value=true) | length != 0 %}\n### New Contributors\n{% for contributor in github.contributors | filter(attribute=\"is_first_time\", value=true) %}\n  - @{{ contributor.username }} made their first contribution\n    {%- if contributor.pr_number %} in \\\n      [#{{ contributor.pr_number }}]($REPO/pull/{{ contributor.pr_number }})\\\n    {% endif %}\\\n{% endfor %}\n{% endif %}\n{% macro commit(commit) -%}\n{% if commit.scope %}**({{commit.scope}})** {% endif -%}\n{% if commit.breaking %}**breaking** {% endif -%}\n{{ commit.message | split(pat=\"\\n\") | first | trim }} by\\\n{% if commit.remote.username %} @{{commit.remote.username}}\\\n{% else %} {{commit.author.name}}{% endif %} in\\\n{% if commit.remote.pr_number %} [#{{ commit.remote.pr_number }}]($REPO/pull/{{ commit.remote.pr_number }})\\\n{% else %} [{{ commit.id | truncate(length=7, end=\"\") }}]($REPO/commit/{{ commit.id }})\\\n{%- endif %}\n{% endmacro commit -%}\n\"\"\"\n# template for the changelog footer\nfooter = \"\"\"\n<!-- generated by git-cliff -->\n\"\"\"\n# remove the leading and trailing whitespace from the template\ntrim = true\npostprocessors = [\n  { pattern = '\\$REPO', replace = \"https://github.com/jdx/mise\" },\n  { pattern = '\\(gitlab:([^/\\)]+/[^\\)]+)\\)', replace = \"([gitlab:$1](https://gitlab.com/$1))\" },\n  { pattern = '\\((aqua|github|ubi):([^/\\)]+/[^\\)]+)\\)', replace = \"([$1:$2](https://github.com/$2))\" },\n]\n\n[git]\n# parse the commits based on https://www.conventionalcommits.org\nconventional_commits = true\n# filter out the commits that are not conventional\nfilter_unconventional = false\n# process each line of a commit as an individual commit\nsplit_commits = false\n# regex for preprocessing the commit messages\ncommit_preprocessors = [\n  # remove PR labels from commits\n  { pattern = '\\(#([0-9]+)\\)', replace = \"\" },\n  # Check spelling of the commit with https://github.com/crate-ci/typos\n  # If the spelling is incorrect, it will be automatically fixed.\n  #{ pattern = '.*', replace_command = 'typos --write-changes -' },\n]\n# regex for parsing and grouping commits\ncommit_parsers = [\n  { message = '^chore\\(release\\): prepare for', skip = true },\n  { message = '^chore\\(pr\\)', skip = true },\n  { message = '^chore\\(pull\\)', skip = true },\n  { message = '^chore: (release|Release)', skip = true },\n  { message = '^Release', skip = true },\n  { message = \"^Merge commit\", skip = true },\n  { message = '^registry:', group = \"<!-- 99 -->📦 Registry\" },\n  { message = '^(chore|fix)\\(deps\\):', group = \"<!-- 98 -->📦️ Dependency Updates\", scope = \"\" },\n  { message = '^(chore|fix)\\(security\\):', group = \"<!-- 08 -->🛡️ Security\" },\n  { message = '^feat', group = \"<!-- 01 -->🚀 Features\" },\n  { message = '^fix', group = \"<!-- 02 -->🐛 Bug Fixes\" },\n  { message = '^refactor', group = \"<!-- 03 -->🚜 Refactor\" },\n  { message = '^doc', group = \"<!-- 04 -->📚 Documentation\" },\n  { message = '^style', group = \"<!-- 06 -->🎨 Styling\" },\n  { message = '^perf', group = \"<!-- 05 -->⚡ Performance\" },\n  { message = '^test', group = \"<!-- 07 -->🧪 Testing\" },\n  { message = '^[Rr]evert', group = \"<!-- 09 -->◀️ Revert\" },\n]\n# protect breaking changes from being skipped due to matching a skipping commit_parser\nprotect_breaking_commits = false\n# filter out the commits that are not matched by commit parsers\nfilter_commits = false\n# regex for matching git tags\ntag_pattern = '^v\\d+\\.\\d+\\.\\d+$'\n# regex for skipping tags\nskip_tags = '^v(1|2023|2024\\.0|2024\\.11\\.27)'\n# regex for ignoring tags\n# ignore_tags = \"\"\n# sort the tags topologically\ntopo_order = false\n# sort the commits inside sections by oldest/newest order\nsort_commits = \"oldest\"\n# limit the number of commits included in the changelog.\n# limit_commits = 42\n\n[bump]\nfeatures_always_bump_minor = false\nbreaking_always_bump_major = false\n\n[remote.github]\nowner = \"jdx\"\nrepo = \"mise\"\n"
  },
  {
    "path": "cloudflare/workers/mise-run.js",
    "content": "addEventListener(\"fetch\", (event) => {\n  event.respondWith(handleRequest(event.request));\n});\n\nasync function handleRequest(request) {\n  async function MethodNotAllowed(request) {\n    return new Response(`Method ${request.method} not allowed.`, {\n      status: 405,\n      headers: {\n        Allow: \"GET\",\n      },\n    });\n  }\n  // Only GET requests work with this proxy.\n  if (request.method !== \"GET\") return MethodNotAllowed(request);\n\n  const url = new URL(request.url);\n  const path = url.pathname;\n\n  let targetUrl;\n\n  // Route based on path\n  switch (path) {\n    case \"/\":\n      targetUrl = \"https://mise.jdx.dev/install.sh\";\n      break;\n    case \"/zsh\":\n      targetUrl = \"https://mise.jdx.dev/mise.run/zsh\";\n      break;\n    case \"/bash\":\n      targetUrl = \"https://mise.jdx.dev/mise.run/bash\";\n      break;\n    case \"/fish\":\n      targetUrl = \"https://mise.jdx.dev/mise.run/fish\";\n      break;\n    default:\n      return new Response(\"Not found\", { status: 404 });\n  }\n\n  const r = await fetch(targetUrl);\n  const response = new Response(r.body, r);\n  response.headers.set(\n    \"cache-control\",\n    \"public, max-age=3600, s-maxage=3600, immutable\",\n  );\n  response.headers.set(\"content-type\", \"text/plain\");\n  return response;\n}\n"
  },
  {
    "path": "communique.toml",
    "content": "context = \"mise is a polyglot runtime manager (like asdf, nvm, pyenv, etc), environment manager, and task runner.\"\n\n[defaults]\nemoji = false\n"
  },
  {
    "path": "completions/_mise",
    "content": "#compdef mise\n# @generated by usage-cli from usage spec\nlocal curcontext=\"$curcontext\"\n\n# caching config\n_usage_mise_cache_policy() {\n  if [[ -z \"${lifetime}\" ]]; then\n    lifetime=$((60*60*4)) # 4 hours\n  fi\n  local -a oldp\n  oldp=( \"$1\"(Nms+${lifetime}) )\n  (( $#oldp ))\n}\n\n_mise() {\n  typeset -A opt_args\n  local curcontext=\"$curcontext\" cache_policy\n\n  if ! type -p usage &> /dev/null; then\n      echo >&2\n      echo \"Error: usage CLI not found. This is required for completions to work in mise.\" >&2\n      echo \"See https://usage.jdx.dev for more information.\" >&2\n      return 1\n  fi\n\n  local spec_file=\"${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_3_9.spec\"\n  if [[ ! -f \"$spec_file\" ]]; then\n    mise usage >| \"$spec_file\"\n  fi\n  _arguments \"*: :(($(command usage complete-word --shell zsh -f \"$spec_file\" -- \"${words[@]}\" )))\"\n  return 0\n}\n\nif [ \"$funcstack[1]\" = \"_mise\" ]; then\n    _mise \"$@\"\nelse\n    compdef _mise mise\nfi\n\n# vim: noet ci pi sts=0 sw=4 ts=4\n"
  },
  {
    "path": "completions/mise.bash",
    "content": "# @generated by usage-cli from usage spec\n_mise() {\n    if ! type -p usage &> /dev/null; then\n        echo >&2\n        echo \"Error: usage CLI not found. This is required for completions to work in mise.\" >&2\n        echo \"See https://usage.jdx.dev for more information.\" >&2\n        return 1\n    fi\n\n\tlocal cur prev words cword was_split comp_args\n    _comp_initialize -n : -- \"$@\" || return\n    local spec_file=\"${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_3_9.spec\"\n    if [[ ! -f \"$spec_file\" ]]; then\n        mise usage >| \"$spec_file\"\n    fi\n    # shellcheck disable=SC2207\n\t_comp_compgen -- -W \"$(command usage complete-word --shell bash -f \"$spec_file\" --cword=\"$cword\" -- \"${words[@]}\")\"\n\t_comp_ltrim_colon_completions \"$cur\"\n    # shellcheck disable=SC2181\n    if [[ $? -ne 0 ]]; then\n        unset COMPREPLY\n    fi\n    return 0\n}\n\nif [[ \"${BASH_VERSINFO[0]}\" -eq 4 && \"${BASH_VERSINFO[1]}\" -ge 4 || \"${BASH_VERSINFO[0]}\" -gt 4 ]]; then\n    shopt -u hostcomplete && complete -o nospace -o bashdefault -o nosort -F _mise mise\nelse\n    shopt -u hostcomplete && complete -o nospace -o bashdefault -F _mise mise\nfi\n# vim: noet ci pi sts=0 sw=4 ts=4 ft=sh\n"
  },
  {
    "path": "completions/mise.fish",
    "content": "# @generated by usage-cli from usage spec\n\n# if \"usage\" is not installed show an error\nif ! type -p usage &> /dev/null\n    echo >&2\n    echo \"Error: usage CLI not found. This is required for completions to work in mise.\" >&2\n    echo \"See https://usage.jdx.dev for more information.\" >&2\n    return 1\nend\nset -l tmpdir (if set -q TMPDIR; echo $TMPDIR; else; echo /tmp; end)\nset -l spec_file \"$tmpdir/usage__usage_spec_mise_2026_3_9.spec\"\nif not test -f \"$spec_file\"\n    mise usage | string collect > \"$spec_file\"\nend\n\nset -l tokens\nif commandline -x >/dev/null 2>&1\n    complete -xc mise -a \"(command usage complete-word --shell fish -f \\\"$spec_file\\\" -- (commandline -xpc) (commandline -t))\"\nelse\n    complete -xc mise -a \"(command usage complete-word --shell fish -f \\\"$spec_file\\\" -- (commandline -opc) (commandline -t))\"\nend\n"
  },
  {
    "path": "completions/mise.ps1",
    "content": "# @generated by usage-cli from usage spec\n\nif (-not (Get-Command 'usage' -ErrorAction SilentlyContinue)) {\n    Write-Warning \"Error: usage CLI not found. This is required for completions to work in mise.\"\n    Write-Warning \"See https://usage.jdx.dev for more information.\"\n    return\n}\n\nRegister-ArgumentCompleter -Native -CommandName 'mise' -ScriptBlock {\n    param($wordToComplete, $commandAst, $cursorPosition)\n\n    $tmpDir = if ($env:TEMP) { $env:TEMP } else { [System.IO.Path]::GetTempPath() }\n    $specFile = Join-Path $tmpDir \"usage__usage_spec_mise_2026_3_9.kdl\"\n\n    if (-not (Test-Path $specFile)) {\n    mise usage | Out-File -FilePath $specFile -Encoding utf8\n}\n\n    $words = $commandAst.CommandElements | ForEach-Object { $_.ToString() }\n    if ($words.Count -lt 1) {\n        $words = @('mise')\n    }\n\n    $completions = & 'usage' complete-word --shell powershell -f \"$specFile\" -- @words $wordToComplete 2>$null\n\n    if ($completions) {\n        $completions | ForEach-Object {\n            $parts = $_ -split \"`t\", 2\n            $completion = $parts[0]\n            $description = if ($parts.Count -gt 1) { $parts[1] } else { '' }\n\n            [System.Management.Automation.CompletionResult]::new(\n                $completion,\n                $completion,\n                'ParameterValue',\n                $description\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "crates/aqua-registry/Cargo.toml",
    "content": "[package]\nname = \"aqua-registry\"\nversion = \"2026.3.6\"\nedition = \"2024\"\ndescription = \"Aqua registry backend for mise\"\nauthors = [\"Jeff Dickey (@jdx)\"]\nlicense = \"MIT\"\nrepository = \"https://github.com/jdx/mise\"\nhomepage = \"https://mise.jdx.dev\"\nreadme = \"README.md\"\nkeywords = [\"mise\", \"aqua\", \"registry\", \"package-manager\"]\ncategories = [\"development-tools\"]\nbuild = \"build.rs\"\ninclude = [\n  \"/README.md\",\n  \"/build.rs\",\n  \"/src/**/*.rs\",\n  \"/aqua-registry/pkgs/**/registry.yaml\",\n]\n\n[package.metadata.cargo-machete]\nignored = [\"serde\"]\n\n[features]\ndefault = []\n\n[dependencies]\n# Core dependencies\nserde = { version = \"1\", features = [\"derive\"] }\nserde_derive = \"1\"\nserde_yaml = \"0.9\"\nthiserror = \"2\"\neyre = \"0.6\"\nindexmap = { version = \"2\", features = [\"serde\"] }\nitertools = \"0.14\"\nstrum = { version = \"0.27\", features = [\"derive\"] }\n\n# Template parsing and evaluation\nexpr-lang = \"1\"\nversions = { version = \"6\", features = [\"serde\"] }\nheck = \"0.5\"\n\n# Async runtime\ntokio = { version = \"1\", features = [\"sync\"] }\n\n# Logging\nlog = \"0.4\"\n\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\"rt\", \"macros\"] }\n\n[build-dependencies]\nserde_yaml = \"0.9\"\n"
  },
  {
    "path": "crates/aqua-registry/README.md",
    "content": "# aqua-registry\n\nAqua registry backend for [mise](https://mise.jdx.dev).\n\nThis crate provides support for the [Aqua](https://aquaproj.github.io/) registry format, allowing mise to install tools from the Aqua ecosystem.\n\n## Features\n\n- Parse and validate Aqua registry YAML files\n- Resolve package versions and platform-specific assets\n- Template string evaluation for dynamic asset URLs\n- Support for checksums, signatures, and provenance verification\n- Platform-aware asset resolution for cross-platform tool installation\n\n## Usage\n\nThis crate is primarily used internally by mise. For more information about mise, visit [mise.jdx.dev](https://mise.jdx.dev).\n\n## License\n\nMIT\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Shunsuke Suzuki\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/01mf02/jaq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: 01mf02\n    repo_name: jaq\n    description: A jq clone focussed on correctness, speed, and simplicity\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-beta\")\n        no_asset: true\n      - version_constraint: Version == \"v1.0.0-gamma\"\n        asset: jaq-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: jaq-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n      - version_constraint: semver(\"<= 2.0.0-alpha.1\")\n        asset: jaq-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: \"true\"\n        asset: jaq-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/1password/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    name: 1password/cli\n    url: https://cache.agilebits.com/dist/1P/op2/pkg/{{.Version}}/op_{{.OS}}_{{.Arch}}_{{.Version}}.zip\n    description: Password manager developed by AgileBits Inc\n    windows_arm_emulation: true\n    files:\n      - name: op\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/1xyz/pryrite/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: 1xyz\n    repo_name: pryrite\n    description: Pryrite, interactively execute shell code blocks in a markdown file\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.16\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: pryrite-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/8051Enthusiast/biodiff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: 8051Enthusiast\n    repo_name: biodiff\n    description: Hex diff viewer using alignment algorithms from biology\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: biodiff-{{.OS}}-latest-x86.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v0.2.0\"\n        asset: biodiff-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v0.2.1\"\n        asset: biodiff-{{.OS}}-0-2-1.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: biodiff-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/99designs/aws-vault/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: 99designs\n    repo_name: aws-vault\n    description: A vault for securely storing and accessing AWS credentials in development environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.3.2\"\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v2.3.3\"\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 2.3.1\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 2.4.1\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 3.4.0\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 4.6.4\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 5.0.1\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: dmg\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: raw\n            asset: aws-vault-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 5.1.2\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: dmg\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: raw\n            asset: aws-vault-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 6.2.0\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: dmg\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: raw\n            asset: aws-vault-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 6.4.0\")\n        asset: aws-vault-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: dmg\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: raw\n            asset: aws-vault-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: dmg\n            asset: aws-vault-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n          - windows/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/AGWA/git-crypt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: AGWA\n    repo_name: git-crypt\n    description: Transparent file encryption in git\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.8.0\"\n        asset: git-crypt-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            asset: git-crypt-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: git-crypt-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            asset: git-crypt-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux/amd64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Adembc/lazyssh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Adembc\n    repo_name: lazyssh\n    description: \"A terminal-based SSH manager inspired by lazydocker and k9s - Written in go\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lazyssh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/AlexNabokikh/tfsort/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: AlexNabokikh\n    repo_name: tfsort\n    description: A CLI utility to sort Terraform variables and outputs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfsort_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tfsort_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/AlexanderGrooff/mermaid-ascii/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: AlexanderGrooff\n    repo_name: mermaid-ascii\n    description: Render Mermaid graphs inside your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: mermaid-ascii_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"0.3.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: mermaid-ascii_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: mermaid-ascii_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Aloxaf/silicon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Aloxaf\n    repo_name: silicon\n    description: Create beautiful image of your source code\n    asset: silicon-{{.Version}}-{{.Arch}}-{{.OS}}.tar.gz\n    rosetta2: true\n    replacements:\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n      linux: unknown-linux-gnu\n      amd64: x86_64\n    version_constraint: semver(\"> 0.5.0\")\n    supported_envs:\n      - darwin\n      - amd64\n    version_overrides:\n      - version_constraint: semver(\"= 0.5.0\")\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: \"true\"\n        replacements:\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n          linux: unknown-linux-gnu\n          amd64: x86_64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Arriven/db1000n/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Arriven\n    repo_name: db1000n\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.15\"\n        asset: db1000n-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.8.6\"\n        asset: db1000n_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: db1000n_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: db1000n-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: db1000n-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.8.3\")\n        asset: db1000n-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.8.5\")\n        asset: db1000n_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: db1000n_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.12\")\n        asset: db1000n_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: db1000n_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.8.19\")\n        asset: db1000n_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: db1000n_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.23\")\n        asset: db1000n_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: db1000n_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: db1000n-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Automattic/harper/harper-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: Automattic/harper/harper-cli\n    type: github_release\n    repo_owner: Automattic\n    repo_name: harper\n    description: The Grammar Checker for Developers\n    version_filter: semver(\">= 0.13.0\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.13.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: harper-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        # harper-cli-aarch64-apple-darwin.tar.gz\n        # harper-cli-aarch64-unknown-linux-gnu.tar.gz\n        # harper-cli-x86_64-apple-darwin.tar.gz\n        # harper-cli-x86_64-pc-windows-msvc.zip\n        # harper-cli-x86_64-unknown-linux-gnu.tar.gz\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Automattic/harper/harper-ls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: Automattic/harper/harper-ls\n    aliases:\n      - name: elijah-potter/harper/harper-ls\n    type: github_release\n    repo_owner: Automattic\n    repo_name: harper\n    description: The Grammar Checker for Developers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: harper-ls-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: harper-ls-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/AvitalTamir/cyphernetes/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: AvitalTamir\n    repo_name: cyphernetes\n    description: A Kubernetes Query Language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1\")\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: cyphernetes-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.2\"\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.4-fix.0\")\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: cyphernetes-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/aks-engine/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: aks-engine\n    description: AKS Engine deploys and manages Kubernetes clusters in Azure\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: aks-engine-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: aks-engine\n        src: aks-engine-{{.Version}}-{{.OS}}-{{.Arch}}/aks-engine\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/aztfexport/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: aztfexport\n    aliases:\n      - name: Azure/aztfy\n    description: A tool to bring existing Azure resources under Terraform's management\n    asset: aztfexport_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: aztfexport_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 0.11.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.7.0\")\n        asset: aztfy_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: aztfy\n        checksum:\n          type: github_release\n          asset: aztfy_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.0.6\")\n        asset: aztfy_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: aztfy\n        checksum:\n          type: github_release\n          asset: aztfy_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.0.6\")\n        asset: aztfy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        files:\n          - name: aztfy\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/azure-dev/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: azure-dev\n    asset: azd-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    description: The Azure Developer CLI is a developer-centric command-line interface tool for creating Azure applications\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: azd\n        src: azd-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/bicep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: bicep\n    description: Bicep is a declarative language for describing and deploying Azure resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: bicep-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1008\")\n        asset: bicep-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: linux\n            asset: bicep-{{.OS}}-musl-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bicep-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: bicep-{{.OS}}-musl-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/draft/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: draft\n    description: A day 0 tool for getting your app on k8s fast\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: draftv2-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: draftv2\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: draft-v2{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: draftv2-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: draftv2\n      - version_constraint: semver(\"<= 0.0.21\")\n        asset: draft-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: draft-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/kubelogin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Azure\n    repo_name: kubelogin\n    description: A Kubernetes credential (exec) plugin implementing azure authentication\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.8\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.10\"\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.9\"\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.0.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.26\")\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.2.6\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kubelogin-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: kubelogin\n            src: bin/{{.OS}}_{{.Arch}}/kubelogin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubelogin-win-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Azure/mapotf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: Azure\n    repo_name: mapotf\n    description: mapotf stands for MetA PrOgramming for TerraForm. mapotf is a meta programming tool designed to work with Terraform\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BeaconBay/ck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BeaconBay\n    repo_name: ck\n    description: Local first semantic and hybrid BM25 grep / search tool for use by AI and humans\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ck-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha256\"\n              file_format: regexp\n              algorithm: sha256\n              pattern:\n                checksum: \"([a-f0-9]{64})\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Bearer/gon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Bearer\n    repo_name: gon\n    description: Sign, notarize, and package macOS CLI tools and applications written in any language. Available as both a CLI and a Go library\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.13\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gon_{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BeryJu/korb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BeryJu\n    repo_name: korb\n    description: Move Kubernetes PVCs between Storage Classes and Namespaces\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: korb_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: korb\n            src: korb_v1.0.0\n        checksum:\n          type: github_release\n          asset: korb_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: korb_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: korb_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: korb_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: korb_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BetterDiscord/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BetterDiscord\n    repo_name: cli\n    description: CLI for installing and managing BetterDiscord\n    files:\n      - name: bdcli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: bdcli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bdcli_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: bdcli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bdcli_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BishopFox/cloudfox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BishopFox\n    repo_name: cloudfox\n    description: Automating situational awareness for cloud penetration tests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cloudfox-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: cloudfox\n            src: cloudfox/cloudfox\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Boeing/config-file-validator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Boeing\n    repo_name: config-file-validator\n    description: Cross Platform tool to validate configuration files\n    asset: validator-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        goarch: amd64\n        format: zip\n      - goos: windows\n        goarch: arm64\n        type: go_install\n        path: github.com/Boeing/config-file-validator/cmd/validator\n    files:\n      - name: validator\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.md5\"\n      algorithm: md5\n    version_constraint: semver(\">= 1.5.0\")\n    version_overrides:\n      - version_constraint: Version == \"v1.4.0\"\n        asset: validator-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          enabled: false\n        overrides:\n          - goos: windows\n            goarch: amd64\n            asset: validator-{{trimV .Version}}\n          - goos: linux\n            goarch: arm64\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n          - goos: windows\n            goarch: arm64\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n        files:\n          - name: validator\n        replacements:\n          darwin: macos\n        rosetta2: true\n      - version_constraint: Version == \"v1.3.0\"\n        asset: validator.{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        rosetta2: true\n        checksum:\n          enabled: false\n        overrides:\n          - goos: windows\n            goarch: amd64\n            asset: validator\n          - goos: linux\n            goarch: arm64\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n          - goos: windows\n            goarch: arm64\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n      - version_constraint: semver(\">= 1.0.1\")\n        asset: validator.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements: {}\n        checksum:\n          enabled: false\n        overrides:\n          - goos: windows\n            goarch: amd64\n            asset: validator\n          - goarch: arm64\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n          - goos: darwin\n            type: go_install\n            path: github.com/Boeing/config-file-validator/cmd/validator\n      - version_constraint: Version == \"v1.0.0\"\n        asset: validator.{{.OS}}-{{.Arch}}\n        format: raw\n        replacements: {}\n        rosetta2: true\n        checksum:\n          enabled: false\n        overrides:\n          - goos: windows\n            goarch: amd64\n            asset: validator\n          - goarch: arm64\n            type: go_build\n            files:\n              - name: validator\n                src: ./cmd/validator\n                dir: config-file-validator-{{trimV .Version}}\n          - goos: darwin\n            type: go_build\n            files:\n              - name: validator\n                src: ./cmd/validator\n                dir: config-file-validator-{{trimV .Version}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Builditluc/wiki-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Builditluc\n    repo_name: wiki-tui\n    description: A simple and easy to use Wikipedia Text User Interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.8\")\n        asset: wiki-tui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: wiki-tui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: wiki-tui-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: wiki-tui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: wiki-tui-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BurntSushi/ripgrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BurntSushi\n    repo_name: ripgrep\n    description: ripgrep recursively searches directories for a regex pattern while respecting your gitignore\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: xrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: xrep\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.11\")\n        asset: xrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: xrep\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.0.12\"\n        asset: rg-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            files:\n              - name: rg\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"0.0.13\"\n        asset: xrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: xrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            asset: rg-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      # 0.0.15\n      # update project name. xrep => ripgrep\n      # https://github.com/BurntSushi/ripgrep/commit/48878bbb8f5f18586ebf73fcafed46de7dc82da4\n      - version_constraint: Version == \"0.0.14\"\n        asset: xrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rg\n            src: \"{{.AssetWithoutExt}}/rg\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.0.15\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.1.2\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.10\")\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.1.11\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.1.12\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.16\")\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.1.17\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: rg\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"<= 13.0.0\")\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: rg\n            src: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rg\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/BurntSushi/xsv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: BurntSushi\n    repo_name: xsv\n    description: A fast CSV command line toolkit written in Rust\n    asset: xsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    version_constraint: semver(\">= 0.10.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.10.0\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"< 0.10.0\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        rosetta2: false\n        files:\n          - name: xsv\n            src: xsv-{{.Version}}-{{.Arch}}-{{.OS}}/xsv\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Byron/dua-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Byron\n    repo_name: dua-cli\n    description: View disk space usage and delete unwanted data, fast\n    files:\n      - name: dua\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v2.12.0\", \"v2.14.9\", \"v2.18.1\", \"v2.29.3\"]\n        no_asset: true\n      - version_constraint: Version == \"v2.10.3\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.20.0\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v2.21.0\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v2.28.0\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: tar\n            asset: dua-v2.28.3-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.5.0\")\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.27.2\")\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.31.0\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: \"true\"\n        asset: dua-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dua\n            src: \"{{.AssetWithoutExt}}/dua\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ByteNess/aws-vault/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ByteNess\n    repo_name: aws-vault\n    description: A vault for securely storing and accessing AWS credentials in development environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v7.3.5\"\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: aws-vault_sha256_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 7.3.4\")\n        asset: aws-vault_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: aws-vault_{{trimV .Version}}_sha256_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: aws-vault_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: aws-vault-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: aws-vault_sha256_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CAFxX/mgo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: CAFxX\n    repo_name: mgo\n    description: Build and bundle multiple GOAMD64 variants in a single executable\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CQLabs/homebrew-dcm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CQLabs\n    repo_name: homebrew-dcm\n    description: Homebrew formula for DCM\n    files:\n      - name: dcm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0.0\"\n        asset: dcm-{{.OS}}-{{.Arch}}-release.{{.Format}}\n        format: zip\n        files:\n          - name: dcm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm\n          - goos: windows\n            asset: dcm-{{.OS}}-release.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dcm-{{.OS}}-{{.Arch}}-release.{{.Format}}\n        format: zip\n        files:\n          - name: dcm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm\n          - goos: windows\n            asset: dcm-{{.OS}}-release.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Canop/dysk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Canop\n    repo_name: dysk\n    description: A linux utility to get information on filesystems, like df but better\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.10.0\")\n        asset: dysk_{{trimV .Version}}.{{.Format}}\n        format: zip\n        files:\n          - name: dysk\n            src: build/{{.Arch}}-{{.OS}}/dysk\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: dysk_{{trimV .Version}}.{{.Format}}\n        format: zip\n        files:\n          - name: dysk\n            src: build/{{.Arch}}-{{.OS}}/dysk\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Canop/rhit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Canop\n    repo_name: rhit\n    description: A nginx log explorer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: rhit_{{trimV .Version}}.{{.Format}}\n        format: zip\n        files:\n          - name: rhit\n            src: build/{{.Arch}}-{{.OS}}/rhit\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-gnu\n        overrides:\n          - envs:\n              - darwin\n              - windows\n            type: cargo\n            crate: rhit\n            cargo:\n              locked: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Checkmarx/kics/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Checkmarx\n    repo_name: kics\n    description: Find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle of your infrastructure-as-code with KICS by Checkmarx\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.2\")\n        asset: kics_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: kics_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.2.3\")\n        asset: kics_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: kics_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.4\")\n        asset: kics_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: kics_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: kics_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: kics_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        type: go_build\n        files:\n          - name: kics\n            src: ./cmd/console\n            dir: kics-{{trimV .Version}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Cian911/switchboard/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Cian911\n    repo_name: switchboard\n    description: \"Automated file organisation and routing for all your machines. :open_file_folder:\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: switchboard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: switchboard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CircleCI-Public/circleci-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CircleCI-Public\n    repo_name: circleci-cli\n    description: Use CircleCI from the command line\n    rosetta2: true\n    asset: circleci-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: circleci\n        src: circleci-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}/circleci\n    version_constraint: semver(\">= 0.1.17554\")\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - amd64\n    checksum:\n      type: github_release\n      asset: circleci-cli_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ClementTsang/bottom/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ClementTsang\n    repo_name: bottom\n    description: Yet another cross-platform graphical process/system monitor\n    files:\n      - name: btm\n    version_filter: not (Version == \"nightly\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.1.0-alpha-1\", \"0.1.0-alpha-4\"]\n        asset: \"{{.OS}}-bottom-{{.Version}}\"\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"0.1.0-alpha-3\"\n        asset: bottom\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"0.2.0\"\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.5.0\"\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.1.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.7\")\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.8\")\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 0.10.0\")\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: bottom_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: ClementTsang/bottom/.github/workflows/build_releases.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Code-Hex/gqldoc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Code-Hex\n    repo_name: gqldoc\n    description: The easiest way to make API documents for GraphQL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: gqldoc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gqldoc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CrociDB/bulletty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CrociDB\n    repo_name: bulletty\n    description: bulletty is a pretty feed reader for the terminal that stores the articles as Markdown\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.7\"\n        asset: bulletty-{{.Version}}-{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.1.8\"\n        error_message: This version is unavailable because the asset format is invalid.\n      - version_constraint: Version == \"v0.1.9\"\n        asset: bulletty-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n      - version_constraint: \"true\"\n        asset: bulletty-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Crocmagnon/fatcontext/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Crocmagnon\n    repo_name: fatcontext\n    description: detects nested contexts in loops\n    version_constraint: \"false\"\n    version_overrides:\n      # foreshadow is used instead of fatcontext\n      - version_constraint: semver(\"<= 0.1.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: fatcontext_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: fatcontext_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CrunchyData/postgres-operator-client/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CrunchyData\n    repo_name: postgres-operator-client\n    description: the Command Line Interface (CLI) for the Crunchy Postgres Operator\n    files:\n      - name: kubectl-pgo\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: kubectl-pgo-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubectl-pgo-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CyberAgent/reminder-lint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CyberAgent\n    repo_name: reminder-lint\n    description: Code remind tool for any languages and any config files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: reminder-lint-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        files:\n          - name: reminder-lint\n            src: \"{{.AssetWithoutExt}}/reminder-lint\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: reminder-lint\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/CycloneDX/cyclonedx-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: CycloneDX\n    repo_name: cyclonedx-cli\n    description: CycloneDX CLI tool for SBOM analysis, merging, diffs and format conversions\n    files:\n      - name: cyclonedx\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: cyclonedx-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n      - version_constraint: \"true\"\n        asset: cyclonedx-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Darth-Tech/samwise-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Darth-Tech\n    repo_name: samwise-cli\n    description: A CLI application to accompany on your terraform module journey and sharing your burden of module dependency updates, just as one brave Hobbit helped Frodo carry his :)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: samwise-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: samwise-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: samwise-cli_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/gh-action/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/gh-action\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: Binary for GitHub Actions of DeNA/unity-meta-check\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: gh-action-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: gh-action-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/gh-action-yaml-gen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/gh-action-yaml-gen\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: A cli tool to automatically generate action.yaml for DeNA/unity-meta-check\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: gh-action-yaml-gen-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        asset: gh-action-yaml-gen-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - linux\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/unity-meta-autofix/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/unity-meta-autofix\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: Autofix for meta files problems. It need a result of unity-meta-check via stdin.\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: unity-meta-autofix-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        asset: unity-meta-autofix-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - linux\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/unity-meta-check/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/unity-meta-check\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: Checker for missing/dangling meta files. The result print to stdout.\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: unity-meta-check-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        asset: unity-meta-check-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - linux\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/unity-meta-check-github-pr-comment/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/unity-meta-check-github-pr-comment\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: Reporter for GitHub comments of GitHub issues or pull requests. It need a result of unity-meta-check from stdin.\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: unity-meta-check-github-pr-comment-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        asset: unity-meta-check-github-pr-comment-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - linux\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DeNA/unity-meta-check/unity-meta-check-junit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: DeNA/unity-meta-check/unity-meta-check-junit\n    type: github_release\n    repo_owner: DeNA\n    repo_name: unity-meta-check\n    description: Reporter for Jenkins compatible XML based JUnit reports. It need a result of unity-meta-check from stdin.\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: unity-meta-check-junit-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        checksum:\n          enabled: false\n      - version_constraint: \"true\"\n        asset: unity-meta-check-junit-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - linux\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/DelineaXPM/dsv-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: DelineaXPM\n    repo_name: dsv-cli\n    aliases:\n      - name: thycotic/dsv-cli\n    link: https://docs.delinea.com/dsv/current/cli-ref\n    description: Delinea DevOps Secrets Vault is a secret vault automation tool for the management of credentials for applications, databases, CI/CD tools, and services\n    search_words:\n      - secrets\n      - vault\n    files:\n      - name: dsv\n    supported_envs:\n      - darwin\n      - amd64\n    asset: dsv-{{.OS}}-{{.Arch}}\n    format: raw\n    replacements:\n      amd64: x64\n      windows: win\n    version_constraint: semver(\">= 1.39.9\")\n    checksum:\n      type: github_release\n      asset: checksums-sha256.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\">= 1.39.5\")\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.39.1\")\n        checksum:\n          enabled: false\n        replacements:\n          windows: win\n      - version_constraint: semver(\">= 1.33.0\")\n        checksum:\n          enabled: false\n      - version_constraint: \"true\"\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/EdJoPaTo/mqttui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: EdJoPaTo\n    repo_name: mqttui\n    description: Subscribe to a MQTT Topic or publish something quickly from the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: quick-mqtt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        files:\n          - name: mqttui\n            src: quick-mqtt\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: mqtt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        files:\n          - name: mqttui\n            src: mqtt\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: mqttui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: Version == \"v0.11.0\"\n        asset: mqttui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: mqttui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.16.2\")\n        asset: mqttui-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: mqttui-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/EdenEast/repo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: EdenEast\n    repo_name: repo\n    asset: repo-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: Repository Management utility\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/EmbarkStudios/cargo-deny/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: EmbarkStudios\n    repo_name: cargo-deny\n    description: Cargo plugin for linting your dependencies\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.4\")\n        asset: cargo-deny-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-deny\n            src: \"{{.AssetWithoutExt}}/cargo-deny\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.6.5\"\n        asset: cargo-deny-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: cargo-deny\n            src: \"{{.AssetWithoutExt}}/cargo-deny\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: cargo-deny-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-deny\n            src: \"{{.AssetWithoutExt}}/cargo-deny\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.22\")\n        asset: cargo-deny-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-deny\n            src: \"{{.AssetWithoutExt}}/cargo-deny\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cargo-deny-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-deny\n            src: \"{{.AssetWithoutExt}}/cargo-deny\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/EnvCLI/EnvCLI/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: EnvCLI\n    repo_name: EnvCLI\n    description: \"Don't install Node, Go, ... locally - use containers you define within your project. If you have a new machine / other contributors you just have to install docker and envcli to get started\"\n    files:\n      - name: envcli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.4\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_{{.Arch}}\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Epistates/treemd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Epistates\n    repo_name: treemd\n    description: A (TUI/CLI) markdown navigator with tree-based structural navigation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.4\")\n        asset: treemd-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: treemd\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: treemd-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: treemd-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: treemd\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            asset: treemd-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/F1bonacc1/process-compose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: F1bonacc1\n    repo_name: process-compose\n    description: Process Compose is a simple and flexible scheduler and orchestrator to manage non-containerized applications\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.55.0\"\n        asset: process-compose_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: process-compose_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: process-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: process-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: process-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.29.0\")\n        asset: process-compose-{{.OS}}-{{.Arch}}\n        format: raw\n      - version_constraint: semver(\"<= 0.29.4\")\n        asset: process-compose_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: process-compose_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.45.0\")\n        asset: process-compose_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: process-compose_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.69.0\")\n        asset: process-compose_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: process-compose_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: process-compose_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: process-compose_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FairwindsOps/gonogo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FairwindsOps\n    repo_name: gonogo\n    description: \"[alpha] Tool to evaluate upgrade confidence for Kubernetes cluster addons\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: gonogo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://artifacts.fairwinds.com/cosign.pub\n              - --signature\n              - https://github.com/FairwindsOps/gonogo/releases/download/{{.Version}}/checksums.txt.sig\n              - --insecure-ignore-tlog\n      - version_constraint: \"true\"\n        asset: gonogo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://artifacts.fairwinds.com/cosign.pub\n              - --signature\n              - https://github.com/FairwindsOps/gonogo/releases/download/{{.Version}}/checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FairwindsOps/nova/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FairwindsOps\n    repo_name: nova\n    description: Find outdated or deprecated Helm charts running in your cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v3.6.2\"\n        asset: nova_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.0.1\")\n        asset: Nova_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: nova\n            src: Nova\n      - version_constraint: semver(\"<= 2.3.2\")\n        asset: nova_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 3.6.4\")\n        asset: nova_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: nova_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FairwindsOps/pluto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FairwindsOps\n    repo_name: pluto\n    description: A cli tool to help discover deprecated apiVersions in Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.4.1\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: pluto_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 4.2.0\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: pluto_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 5.0.0\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pluto_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 5.1.0\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pluto_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.19.0\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pluto_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.21.4\")\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://artifacts.fairwinds.com/cosign.pub\n              - --signature\n              - https://github.com/FairwindsOps/pluto/releases/download/{{.Version}}/checksums.txt.sig\n      - version_constraint: \"true\"\n        asset: pluto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://artifacts.fairwinds.com/cosign-p256.pub\n              - --signature\n              - https://github.com/FairwindsOps/pluto/releases/download/{{.Version}}/checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FairwindsOps/polaris/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FairwindsOps\n    repo_name: polaris\n    asset: polaris_{{.OS}}_{{.Arch}}.tar.gz\n    description: Validation of best practices in your Kubernetes clusters\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FairwindsOps/rbac-lookup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FairwindsOps\n    repo_name: rbac-lookup\n    description: Easily find roles and cluster roles attached to any user, service account, or group name in your Kubernetes cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.5\")\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.8.3\")\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rbac-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://artifacts.fairwinds.com/cosign.pub\n              - --signature\n              - https://github.com/FairwindsOps/rbac-lookup/releases/download/{{.Version}}/checksums.txt.sig\n              - --insecure-ignore-tlog\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FalconForceTeam/FalconHound/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FalconForceTeam\n    repo_name: FalconHound\n    description: FalconHound is a blue team multi-tool. It allows you to utilize and enhance the power of BloodHound in a more automated fashion. It is designed to be used in conjunction with a SIEM or other log aggregation tool\n    asset: FalconHound_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    files:\n      - name: falconhound\n        src: FalconHound\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FeLvi-zzz/tentez/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FeLvi-zzz\n    repo_name: tentez\n    description: Tentez helps you switching traffic\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tentez-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FiloSottile/age/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FiloSottile\n    repo_name: age\n    description: A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability\n    files:\n      - name: age\n        src: age/age\n      - name: age-keygen\n        src: age/age-keygen\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0-beta1\"\n        no_asset: true\n      - version_constraint: Version == \"v1.0.0-beta2\"\n        asset: age-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.0-beta5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.0-rc.1\")\n        asset: age-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: age-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: age-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n        github_artifact_attestations:\n          signer_workflow: FiloSottile/age/.github/workflows/build.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/FiloSottile/mkcert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: FiloSottile\n    repo_name: mkcert\n    description: A simple zero-config tool to make locally trusted development certificates with any names you'd like\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: mkcert-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: mkcert-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.3\")\n        asset: mkcert-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: mkcert-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Fusion/gogo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Fusion\n    repo_name: gogo\n    description: This is not a package manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gogo-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Gaurav-Gosain/tuios/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Gaurav-Gosain\n    repo_name: tuios\n    description: Terminal UI OS (Terminal Multiplexer)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.5\"\n        asset: tuios_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tuios_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.6\"\n        asset: tuios_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tuios_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Getdeck/getdeck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Getdeck\n    repo_name: getdeck\n    description: A CLI that creates reproducible Kubernetes environments for development and testing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: deck-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: deck\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: deck-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: darwin\n            asset: deck-{{.Version}}-{{.OS}}-universal.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: deck\n      - version_constraint: \"true\"\n        asset: deck-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: deck-{{.Version}}-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            replacements:\n              amd64: x86_64\n            files:\n              - name: deck\n                src: dist/deck\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: deck\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GhostTroops/scan4all/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GhostTroops\n    repo_name: scan4all\n    aliases:\n      - name: hktalent/scan4all\n    description: \"Official repository vuls Scan: 15000+PoCs; 23 kinds of application password crack; 7000+Web fingerprints; 146 protocols and 90000+ rules Port scanning; Fuzz, HW, awesome BugBounty\"\n    asset: scan4all_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    checksum:\n      type: github_release\n      asset: scan4all-{{.OS}}-checksums.txt\n      algorithm: sha256\n    overrides:\n      - goos: darwin\n        checksum:\n          type: github_release\n          asset: scan4all-mac-checksums.txt\n          algorithm: sha256\n    version_constraint: semver(\">= 2.8.7\")\n    version_overrides:\n      - version_constraint: semver(\">= 2.8.6\")\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\">= 2.6.9\")\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            checksum:\n              type: github_release\n              asset: scan4all-mac-checksums.txt\n              algorithm: sha256\n          - goos: darwin\n            goarch: arm64\n            checksum:\n              type: github_release\n              asset: scan4all-mac-arm64-checksums.txt\n              algorithm: sha256\n      - version_constraint: semver(\"< 2.6.9\")\n        replacements:\n          darwin: macOS\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GitGuardian/ggshield/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GitGuardian\n    repo_name: ggshield\n    description: Detect and validate 500+ types of hardcoded secrets with advanced checks. Use it as a pre-commit hook, GitHub Action, or CLI for proactive secret detection and security\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.26.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.28.0\")\n        asset: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: pkg\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: ggshield\n                src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield\n          - goos: darwin\n            format: pkg\n            files:\n              - name: ggshield\n                src: Payload/opt/gitguardian/ggshield-{{trimV .Version}}/ggshield\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.30.2\")\n        asset: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: ggshield\n                src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield\n          - goos: darwin\n            format: pkg\n            files:\n              - name: ggshield\n                src: Payload/opt/gitguardian/ggshield-{{trimV .Version}}/ggshield\n          - goos: windows\n            format: zip\n            files:\n              - name: ggshield\n                src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield.exe\n        supported_envs:\n          - darwin\n          - windows/amd64\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ggshield\n            src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: ggshield\n                src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield.exe\n          - goos: linux\n            files:\n              - name: ggshield\n                src: ggshield-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ggshield\n        supported_envs:\n          - darwin\n          - windows/amd64\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoTestTools/gotestfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoTestTools\n    repo_name: gotestfmt\n    description: go test output for humans\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gotestfmt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestfmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoodwayGroup/gwvault/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoodwayGroup\n    repo_name: gwvault\n    description: ansible-vault CLI reimplemented in go\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: gwvault_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: gwvault\n        src: gwvault_{{trimV .Version}}_{{.OS}}_{{.Arch}}/gwvault\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/alloydb-auth-proxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: GoogleCloudPlatform\n    repo_name: alloydb-auth-proxy\n    description: A utility for connecting securely to your AlloyDB instances\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.8.0\"\n        url: https://storage.googleapis.com/alloydb-auth-proxy/{{.Version}}/alloydb-auth-proxy.{{.OS}}.{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            url: https://storage.googleapis.com/alloydb-auth-proxy/{{.Version}}/alloydb-auth-proxy.x64.exe\n      - version_constraint: \"true\"\n        url: https://storage.googleapis.com/alloydb-auth-proxy/{{.Version}}/alloydb-auth-proxy.{{.OS}}.{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            url: https://storage.googleapis.com/alloydb-auth-proxy/{{.Version}}/alloydb-auth-proxy-x64.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/berglas/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoogleCloudPlatform\n    repo_name: berglas\n    description: A tool for managing secrets on Google Cloud\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: berglas_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: berglas_{{trimV .Version}}_SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/cloud-sql-proxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: GoogleCloudPlatform\n    repo_name: cloud-sql-proxy\n    description: A utility for connecting securely to your Cloud SQL instances\n    format: raw\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    version_constraint: semver(\">= 2.0.0\")\n    url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/{{.Version}}/cloud-sql-proxy.{{.OS}}.{{.Arch}}\n    overrides:\n      - goos: windows\n        url: https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/{{.Version}}/cloud-sql-proxy.x64.exe\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://storage.googleapis.com/cloudsql-proxy/{{.Version}}/cloud_sql_proxy.{{.OS}}.{{.Arch}}\n        overrides:\n          - goos: windows\n            url: https://storage.googleapis.com/cloudsql-proxy/{{.Version}}/cloud_sql_proxy_x64.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/kubectl-ai/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoogleCloudPlatform\n    repo_name: kubectl-ai\n    description: AI powered Kubernetes Assistant\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubectl-ai_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubectl-ai_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/terraformer/aws/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: GoogleCloudPlatform/terraformer/aws\n    description: CLI tool to generate terraform files from existing infrastructure (reverse Terraform). Infrastructure to Code\n    type: github_release\n    repo_owner: GoogleCloudPlatform\n    repo_name: terraformer\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    asset: terraformer-aws-{{.OS}}-{{.Arch}}\n    files:\n      - name: terraformer\n        src: terraformer-aws-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleCloudPlatform/terraformer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoogleCloudPlatform\n    repo_name: terraformer\n    description: CLI tool to generate terraform files from existing infrastructure (reverse Terraform). Infrastructure to Code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.12\")\n        asset: terraformer-all-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.18\")\n        asset: terraformer-all-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.24\")\n        asset: terraformer-all-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: terraformer-all-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleContainerTools/container-diff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: GoogleContainerTools\n    repo_name: container-diff\n    url: https://storage.googleapis.com/container-diff/{{.Version}}/container-diff-{{.OS}}-amd64\n    description: \"container-diff: Diff your Docker containers\"\n    files:\n      - name: container-diff\n        src: container-diff-{{.OS}}-amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleContainerTools/container-structure-test/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: GoogleContainerTools\n    repo_name: container-structure-test\n    description: validate the structure of your container images\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.16.0\")\n        type: http\n        rosetta2: true\n        url: https://storage.googleapis.com/container-structure-test/{{.Version}}/container-structure-test-{{.OS}}-{{.Arch}}\n        files:\n          - name: container-structure-test\n            src: container-structure-test-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - linux\n          - windows/amd64\n      # v1.17.0 https://github.com/GoogleContainerTools/container-structure-test/releases/tag/v1.17.0\n      # > Important\n      # > Releases are no longer published to GCS, use the github release asset to access the binary.\n      - version_constraint: semver(\"<= 1.17.0\")\n        asset: container-structure-test-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      # v1.18.0 https://github.com/GoogleContainerTools/container-structure-test/pull/427\n      - version_constraint: \"true\"\n        asset: container-structure-test-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/GoogleContainerTools/skaffold/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: GoogleContainerTools\n    repo_name: skaffold\n    description: Easy and Repeatable Kubernetes Development\n    url: https://storage.googleapis.com/skaffold/releases/{{.Version}}/skaffold-{{.OS}}-{{.Arch}}\n    files:\n      - name: skaffold\n        src: skaffold-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/IBM-Cloud/redli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: IBM-Cloud\n    repo_name: redli\n    description: \"Redli - A humane alternative to the Redis-cli and TLS\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: redli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: redli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: redli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: redli\n            src: redli_{{.OS}}_{{.Arch}}\n        checksum:\n          type: github_release\n          asset: redli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            goarch: amd64\n            files:\n              - name: redli\n          - goos: windows\n            goarch: arm64\n            files:\n              - name: redli\n                src: redli_{{.Arch}}.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/IvanIsCoding/celq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: IvanIsCoding\n    repo_name: celq\n    description: \"celq - A Common Expression Language (CEL) CLI Tool\"\n    version_filter: not (Version matches \"-(alpha|beta)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1-alpha.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.2-alpha.1\")\n        asset: celq-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.2.0-alpha.1\")\n        asset: celq-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.0-beta.1\")\n        asset: celq-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: celq-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: celq-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: IvanIsCoding/celq/.github/workflows/release_github.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/IxDay/mruby/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: IxDay\n    repo_name: mruby\n    description: Lightweight Ruby\n    files:\n      - name: mruby\n      - name: mrake\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mruby-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: mruby\n          - name: mrake\n        overrides:\n          - goos: windows\n            files:\n              - name: mruby\n              - name: mrake\n                src: mrake.bat\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/JFryy/qq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: JFryy\n    repo_name: qq\n    description: jq inspired interoperable config format transcoder with interactive querying\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: qq-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/JanDeDobbeleer/oh-my-posh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: JanDeDobbeleer\n    repo_name: oh-my-posh\n    description: The most customisable and low-latency cross platform/shell prompt renderer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v5.6.5\"\n        asset: posh-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n      - version_constraint: Version == \"v6.41.1\"\n        asset: posh-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - windows\n          - linux\n      - version_constraint: semver(\"<= 7.52.1\")\n        asset: posh-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 24.10.1\")\n        asset: posh-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: posh-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/JohnnyMorganz/StyLua/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: JohnnyMorganz\n    repo_name: StyLua\n    description: A Lua code formatter\n    files:\n      - name: stylua\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.12.5\")\n        asset: stylua-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          windows: win64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.1\")\n        asset: stylua-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          windows: win64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.3\")\n        asset: stylua-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: stylua-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.19.1\")\n        asset: stylua-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n      - version_constraint: \"true\"\n        asset: stylua-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stylua-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Julien-R44/fast-ssh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Julien-R44\n    repo_name: fast-ssh\n    description: FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: fast-ssh-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Kampfkarren/selene/light/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: Kampfkarren/selene/light\n    type: github_release\n    repo_owner: Kampfkarren\n    repo_name: selene\n    asset: selene-light-{{.Version}}-{{.OS}}.zip\n    description: A blazing-fast modern Lua linter written in Rust\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: selene\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Kampfkarren/selene/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Kampfkarren\n    repo_name: selene\n    description: A blazing-fast modern Lua linter written in Rust\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    version_constraint: semver(\">= 0.6.0\")\n    asset: selene-{{.Version}}-{{.OS}}.zip\n    version_overrides:\n      - version_constraint: semver(\">= 0.4.3\")\n        asset: selene-{{.OS}}\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: windows\n            asset: selene.exe\n      - version_constraint: \"true\"\n        asset: selene\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        overrides:\n          - goos: windows\n            asset: selene.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/KeisukeYamashita/commitlint-rs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: KeisukeYamashita\n    repo_name: commitlint-rs\n    description: Lint commit messages  with conventional commit messages\n    files:\n      - name: commitlint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.8\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: commitlint-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: commitlint-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/KhronosGroup/KTX-Software/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: KhronosGroup\n    repo_name: KTX-Software\n    description: KTX (Khronos Texture) Library and Tools\n    search_words:\n      - Linux Only\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v4.0.0\"\n        asset: KTX-Software-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: tar.bz2\n            files:\n              - name: ktx2check\n                src: \"{{.AssetWithoutExt}}/bin/ktx2check\"\n              - name: ktxinfo\n                src: \"{{.AssetWithoutExt}}/bin/ktxinfo\"\n              - name: ktx2ktx2\n                src: \"{{.AssetWithoutExt}}/bin/ktx2ktx2\"\n              - name: ktxsc\n                src: \"{{.AssetWithoutExt}}/bin/ktxsc\"\n              - name: toktx\n                src: \"{{.AssetWithoutExt}}/bin/toktx\"\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha1\"\n              algorithm: sha1\n            replacements:\n              linux: Linux\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v4.1.0\"\n        asset: KTX-Software-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            format: tar.bz2\n            files:\n              - name: ktx2check\n                src: \"{{.AssetWithoutExt}}/bin/ktx2check\"\n              - name: ktxinfo\n                src: \"{{.AssetWithoutExt}}/bin/ktxinfo\"\n              - name: ktx2ktx2\n                src: \"{{.AssetWithoutExt}}/bin/ktx2ktx2\"\n              - name: ktxsc\n                src: \"{{.AssetWithoutExt}}/bin/ktxsc\"\n              - name: toktx\n                src: \"{{.AssetWithoutExt}}/bin/toktx\"\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha1\"\n              algorithm: sha1\n            replacements:\n              linux: Linux\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 4.2.1\")\n        asset: KTX-Software-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            format: tar.bz2\n            files:\n              - name: ktx2check\n                src: \"{{.AssetWithoutExt}}/bin/ktx2check\"\n              - name: ktxinfo\n                src: \"{{.AssetWithoutExt}}/bin/ktxinfo\"\n              - name: ktx2ktx2\n                src: \"{{.AssetWithoutExt}}/bin/ktx2ktx2\"\n              - name: ktxsc\n                src: \"{{.AssetWithoutExt}}/bin/ktxsc\"\n              - name: toktx\n                src: \"{{.AssetWithoutExt}}/bin/toktx\"\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha1\"\n              algorithm: sha1\n            replacements:\n              linux: Linux\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: KTX-Software-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            format: tar.bz2\n            files:\n              - name: ktx\n                src: \"{{.AssetWithoutExt}}/bin/ktx\"\n              - name: ktx2check\n                src: \"{{.AssetWithoutExt}}/bin/ktx2check\"\n              - name: ktxinfo\n                src: \"{{.AssetWithoutExt}}/bin/ktxinfo\"\n              - name: ktx2ktx2\n                src: \"{{.AssetWithoutExt}}/bin/ktx2ktx2\"\n              - name: ktxsc\n                src: \"{{.AssetWithoutExt}}/bin/ktxsc\"\n              - name: toktx\n                src: \"{{.AssetWithoutExt}}/bin/toktx\"\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha1\"\n              algorithm: sha1\n            replacements:\n              linux: Linux\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Kitware/CMake/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Kitware\n    repo_name: CMake\n    description: Mirror of CMake upstream repository\n    asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: macos\n    files:\n      - name: cmake\n        src: \"{{.AssetWithoutExt}}/bin/cmake\"\n      - name: ccmake\n        src: \"{{.AssetWithoutExt}}/bin/ccmake\"\n      - name: cmake-gui\n        src: \"{{.AssetWithoutExt}}/bin/cmake-gui\"\n      - name: cpack\n        src: \"{{.AssetWithoutExt}}/bin/cpack\"\n      - name: ctest\n        src: \"{{.AssetWithoutExt}}/bin/ctest\"\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: cmake\n            src: \"{{.AssetWithoutExt}}/bin/cmake\"\n          - name: cmake-gui\n            src: \"{{.AssetWithoutExt}}/bin/cmake-gui\"\n          - name: cpack\n            src: \"{{.AssetWithoutExt}}/bin/cpack\"\n          - name: ctest\n            src: \"{{.AssetWithoutExt}}/bin/ctest\"\n      - goos: linux\n        replacements:\n          arm64: aarch64\n      - goos: darwin\n        format: tar.gz\n        asset: cmake-{{trimV .Version}}-{{.OS}}-universal.{{.Format}}\n        files:\n          - name: cmake\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n          - name: ccmake\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n          - name: cmake-gui\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n          - name: cpack\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n          - name: ctest\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v3.1.0\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: linux\n            asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: cmake-{{trimV .Version}}-{{.OS}}-universal.{{.Format}}\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n              - name: ccmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v3.19.2\"\n        asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          linux: Linux\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: cmake-{{trimV .Version}}-{{.OS}}-universal.{{.Format}}\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n              - name: ccmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n          - goos: windows\n            format: zip\n            replacements:\n              amd64: x64\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/bin/cmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/bin/ctest\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.2\")\n        asset: cmake-{{trimV .Version}}-{{.OS}}-universal.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n        supported_envs:\n          - darwin\n        files:\n          - name: cmake\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n          - name: ccmake\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n          - name: cmake-gui\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n          - name: cpack\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n          - name: ctest\n            src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n      - version_constraint: semver(\"<= 3.5.2\")\n        asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        overrides:\n          - goos: darwin\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n              - name: ccmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n      - version_constraint: semver(\"<= 3.19.1\")\n        asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: win64\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              amd64: x64\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/bin/cmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/bin/ctest\"\n          - goos: darwin\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n              - name: ccmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.19.8\")\n        asset: cmake-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          linux: Linux\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            format: tar.gz\n            asset: cmake-{{trimV .Version}}-{{.OS}}-universal.{{.Format}}\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake\"\n              - name: ccmake\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ccmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/CMake.app/Contents/bin/ctest\"\n          - goos: windows\n            format: zip\n            replacements:\n              amd64: x64\n            files:\n              - name: cmake\n                src: \"{{.AssetWithoutExt}}/bin/cmake\"\n              - name: cmake-gui\n                src: \"{{.AssetWithoutExt}}/bin/cmake-gui\"\n              - name: cpack\n                src: \"{{.AssetWithoutExt}}/bin/cpack\"\n              - name: ctest\n                src: \"{{.AssetWithoutExt}}/bin/ctest\"\n      - version_constraint: semver(\"<= 3.23.5\")\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Kong/deck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Kong\n    repo_name: deck\n    description: \"decK: Configuration management and drift detection for Kong\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.20.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.1\")\n        asset: deck_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.10.0\")\n        asset: deck_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: deck_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: deck_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Kotlin/kotlin-interactive-shell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Kotlin\n    repo_name: kotlin-interactive-shell\n    description: Kotlin Language Interactive Shell\n    files:\n      - name: ki\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.3\")\n        no_asset: true\n      - version_constraint: Version in [\"v0.3.2\", \"v0.4.0\"]\n        asset: ki-archive.{{.Format}}\n        format: zip\n        files:\n          - name: ki\n            src: ki/bin/ki.sh\n        overrides:\n          - goos: windows\n            files:\n              - name: ki\n                src: ki/bin/ki.bat\n      - version_constraint: Version == \"v0.3.3\"\n        asset: ki-archive.{{.Format}}\n        format: zip\n        files:\n          - name: ki\n            src: ki/bin/ki.sh\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            files:\n              - name: ki\n                src: ki/bin/ki.bat\n      - version_constraint: \"true\"\n        asset: ki-archive.{{.Format}}\n        format: zip\n        files:\n          - name: ki\n            src: ki/bin/ki.sh\n        checksum:\n          type: github_release\n          asset: checksums_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            files:\n              - name: ki\n                src: ki/bin/ki.bat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/KusionStack/kusion/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: KusionStack\n    repo_name: kusion\n    description: Deliver intentions to Kubernetes and Clouds\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: kusion-{{.OS}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        files:\n          - name: kusion\n            src: bin/kusion\n        checksum:\n          type: github_release\n          asset: kusion-{{.OS}}.tgz.md5.txt\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.3\")\n        asset: kusion-{{.OS}}.{{.Format}}\n        format: tgz\n        files:\n          - name: kusion\n            src: bin/kusion\n        checksum:\n          type: github_release\n          asset: kusion-{{.OS}}.tgz.md5.txt\n          algorithm: md5\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: kusion-{{.OS}}-{{.Arch}}.{{.Format}}\n            checksum:\n              type: github_release\n              asset: kusion-{{.OS}}-{{.Arch}}.tgz.md5.txt\n              algorithm: md5\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: kusion-{{.OS}}.{{.Format}}\n        format: tgz\n        files:\n          - name: kusion\n            src: bin/kusion\n        checksum:\n          type: github_release\n          asset: kusion-{{.OS}}.{{.Format}}.md5.txt\n          algorithm: md5\n        replacements:\n          linux: ubuntu\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: kusion-{{.OS}}-{{.Arch}}.{{.Format}}\n            checksum:\n              type: github_release\n              asset: kusion-{{.OS}}-{{.Arch}}.{{.Format}}.md5.txt\n              algorithm: md5\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: kusion_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kusion_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/LGUG2Z/komorebi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: LGUG2Z\n    repo_name: komorebi\n    description: A tiling window manager for Windows\n    files:\n      - name: komorebi.exe # https://github.com/aquaproj/aqua-registry/pull/16647\n      - name: komorebi\n      - name: komorebic\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.29\")\n        asset: komorebi-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - windows\n      - version_constraint: \"true\"\n        asset: komorebi-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/LGUG2Z/whkd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: LGUG2Z\n    repo_name: whkd\n    description: A simple hotkey daemon for Windows\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: whkd-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: whkd-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Ladicle/kubectl-rolesum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Ladicle\n    repo_name: kubectl-rolesum\n    description: Summarize Kubernetes RBAC roles for the specified subjects\n    supported_envs:\n      - windows\n      - darwin\n      - linux/amd64\n    rosetta2: true\n    asset: kubectl-rolesum_{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: kubectl-rolesum\n        src: kubectl-rolesum_{{.OS}}-{{.Arch}}/kubectl-rolesum\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Lallassu/gorss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Lallassu\n    repo_name: gorss\n    description: Go Terminal Feed Reader\n    rosetta2: true\n    asset: gorss_{{.OS}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux/amd64\n    replacements:\n      darwin: osx\n    files:\n      - name: gorss\n        src: dist/gorss_{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Lifailon/lazyjournal/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Lifailon\n    repo_name: lazyjournal\n    description: TUI for journalctl, file system logs, as well Docker and Podman containers for quick viewing and filtering with fuzzy find, regex support (like fzf and grep) and coloring the output, written in Go with the gocui library\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: lazyjournal-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: lazyjournal-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/LuaLS/lua-language-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: LuaLS\n    repo_name: lua-language-server\n    aliases:\n      - name: sumneko/lua-language-server\n    description: A language server that offers Lua language support - programmed in Lua\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: lua-language-server-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      windows: win32\n      amd64: x64\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: lua-language-server\n        src: bin/lua-language-server\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/LucasPickering/slumber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: LucasPickering\n    repo_name: slumber\n    description: Terminal-based HTTP/REST client\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: slumber-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: slumber\n            src: \"{{.AssetWithoutExt}}/slumber\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: slumber-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: slumber\n            src: \"{{.AssetWithoutExt}}/slumber\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: slumber\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/LukeChannings/deno-arm64/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: LukeChannings\n    repo_name: deno-arm64\n    asset: deno-linux-arm64.zip\n    supported_envs:\n      - linux/arm64\n    description: A Docker image for Deno\n    files:\n      - name: deno\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Macchina-CLI/macchina/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Macchina-CLI\n    repo_name: macchina\n    description: A system information frontend with an emphasis on performance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.9\") or Version == \"0.6.5\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: macchina-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.0\")\n        asset: macchina-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: macchina-{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 6.1.8\")\n        asset: macchina-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          arm64: aarch64\n      - version_constraint: \"true\"\n        asset: macchina-{{.Version}}-{{.OS}}-gnu-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: macchina-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: raw\n            asset: macchina-{{.Version}}-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Macmod/godap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Macmod\n    repo_name: godap\n    description: A complete terminal user interface (TUI) for LDAP\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: godap-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Madh93/tpm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Madh93\n    repo_name: tpm\n    description: A package manager for Terraform providers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tpm_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/MaybeJustJames/zephyr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: MaybeJustJames\n    repo_name: zephyr\n    description: Tree shaking breeze for PureScript CoreFn AST\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        checksum:\n          type: github_release\n          asset: \"{{.OS}}.sha\"\n          algorithm: sha1\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: \"{{.OS}}.sha\"\n              file_format: regexp\n              algorithm: sha1\n              pattern:\n                checksum: (\\b[A-Fa-f0-9]{40}\\b)\n        files:\n          - name: zephyr\n            src: zephyr/zephyr\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.2\"\n        asset: \"{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        files:\n          - name: zephyr\n            src: zephyr/zephyr\n        checksum:\n          type: github_release\n          asset: \"{{.Arch}}-{{.OS}}.sha\"\n          algorithm: sha1\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: \"{{.Arch}}-{{.OS}}.sha\"\n              file_format: regexp\n              algorithm: sha1\n              pattern:\n                checksum: (\\b[A-Fa-f0-9]{40}\\b)\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        files:\n          - name: zephyr\n            src: zephyr/zephyr\n        checksum:\n          type: github_release\n          asset: \"{{.OS}}.sha\"\n          algorithm: sha1\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: \"{{.OS}}.sha\"\n              file_format: regexp\n              algorithm: sha1\n              pattern:\n                checksum: (\\b[A-Fa-f0-9]{40}\\b)\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Melkeydev/go-blueprint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Melkeydev\n    repo_name: go-blueprint\n    description: Go-blueprint allows users to spin up a quick Go project using a popular framework\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.4\"\n        asset: go-blueprint-{{.Arch}}\n        replacements:\n          amd64: x86\n          arm64: arm\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.2.11\")\n        asset: go-blueprint-{{.OS}}_{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\"<= 0.2.13\")\n        asset: go-blueprint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: go-blueprint_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.3.0\"\n        asset: go-blueprint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: go-blueprint_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: go-blueprint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: go-blueprint_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/MiSawa/xq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: MiSawa\n    repo_name: xq\n    asset: xq-{{.Version}}-{{.Arch}}-{{.OS}}.tar.gz\n    description: Pure rust implementation of jq\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: xq\n        src: xq-{{.Version}}-{{.Arch}}-{{.OS}}/xq\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Mic-U/ecsher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Mic-U\n    repo_name: ecsher\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: ecsher_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: ecsher_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.14.2\")\n        asset: ecsher_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ecsher_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Mikescher/better-docker-ps/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Mikescher\n    repo_name: better-docker-ps\n    description: Because `docker ps` is annoying and does not fit my monitor/terminal width\n    asset: dops_{{.OS}}-{{.Arch}}\n    format: raw\n    replacements:\n      darwin: macos\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: dops\n    rosetta2: true\n    version_constraint: semver(\">= 1.5\")\n    version_overrides:\n      - version_constraint: semver(\"< 1.5\")\n        asset: dops\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/MordechaiHadad/bob/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: MordechaiHadad\n    repo_name: bob\n    description: A version manager for neovim\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: bob-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: bob-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.6.0\")\n        asset: bob-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            replacements:\n              arm64: arm\n      - version_constraint: semver(\"<= 4.0.3\")\n        asset: bob-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: bob\n            src: \"{{.AssetWithoutExt}}/bob\"\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            replacements:\n              arm64: arm\n      - version_constraint: \"true\"\n        asset: bob-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: bob\n            src: \"{{.AssetWithoutExt}}/bob\"\n        replacements:\n          amd64: x86_64\n          arm64: arm\n          darwin: macos\n        overrides:\n          - goos: windows\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/MusicDin/kubitect/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: MusicDin\n    repo_name: kubitect\n    description: Kubitect provides a simple way to set up a highly available Kubernetes cluster across multiple hosts\n    asset: kubitect-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    version_constraint: semver(\">= 2.1.0\")\n    supported_envs:\n      - darwin\n      - linux\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Myriad-Dreamin/tinymist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Myriad-Dreamin\n    repo_name: tinymist\n    description: Tinymist [ˈtaɪni mɪst] is an integrated language service for Typst [taɪpst]\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tinymist-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/NathanBaulch/rainbow-roads/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: NathanBaulch\n    repo_name: rainbow-roads\n    description: Animate your exercise maps\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: rainbow-roads-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/NetApp/trident/tridentctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: NetApp\n    repo_name: trident\n    name: NetApp/trident/tridentctl\n    description: Storage orchestrator for containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        asset: trident-installer-{{trimV .Version}}.tar.gz\n        files:\n          - name: tridentctl\n            src: trident-installer/tridentctl\n        overrides:\n          - goos: darwin\n            files:\n              - name: tridentctl\n                src: trident-installer/extras/macos/bin/tridentctl\n        supported_envs:\n          - darwin\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/NikitaCOEUR/dirvana/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: NikitaCOEUR\n    repo_name: dirvana\n    description: \"Reach directory nirvana - per-project aliases, functions, and env vars that auto-load when you cd. Zero friction, zero pollution\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dirvana_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/NimbleArchitect/kubectl-ice/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: NimbleArchitect\n    repo_name: kubectl-ice\n    description: A kubectl plugin that allows you to easily view advanced configuration of all containers that are running inside pods\n    asset: kubectl-ice_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: kubectl-ice_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.0.2\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.0.2\")\n        asset: ice_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kubectl-ice\n            src: ice\n          - name: ice\n        checksum:\n          type: github_release\n          asset: ice_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Nukesor/pueue/pueue/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: Nukesor/pueue/pueue\n    type: github_release\n    repo_owner: Nukesor\n    repo_name: pueue\n    description: |-\n      Pueue is a command-line task management tool for sequential and parallel execution of long-running tasks.\n\n      *Client version*\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.11.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.2\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.29.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 3.4.1\")\n        asset: pueue-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: macos\n          - goos: windows\n            replacements: {}\n      - version_constraint: \"true\"\n        asset: pueue-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Nukesor/pueue/pueued/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: Nukesor/pueue/pueued\n    type: github_release\n    repo_owner: Nukesor\n    repo_name: pueue\n    description: |-\n      Pueue is a command-line task management tool for sequential and parallel execution of long-running tasks.\n\n      *Daemon version*\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.11.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.2\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.29.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 3.4.1\")\n        asset: pueued-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: macos\n          - goos: windows\n            replacements: {}\n      - version_constraint: \"true\"\n        asset: pueued-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Orange-OpenSource/hurl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Orange-OpenSource\n    repo_name: hurl\n    description: Hurl, run and test HTTP requests with plain text\n    files:\n      - name: hurl\n      - name: hurlfmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}/hurlfmt\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}/hurlfmt\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: windows\n            format: zip\n            asset: hurl-{{.Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: hurl\n              - name: hurlfmt\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.6.1\"\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}/hurlfmt\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: windows\n            format: zip\n            asset: hurl-{{.Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: hurl\n              - name: hurlfmt\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}/hurlfmt\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: windows\n            format: zip\n            asset: hurl-{{.Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: hurl\n              - name: hurlfmt\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.2.0\")\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}-{{.Arch}}-{{.OS}}/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}-{{.Arch}}-{{.OS}}/hurlfmt\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: hurl\n              - name: hurlfmt\n      - version_constraint: \"true\"\n        asset: hurl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: hurl\n            src: hurl-{{.Version}}-{{.Arch}}-{{.OS}}/bin/hurl\n          - name: hurlfmt\n            src: hurl-{{.Version}}-{{.Arch}}-{{.OS}}/bin/hurlfmt\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: hurl\n              - name: hurlfmt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Owloops/updo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Owloops\n    repo_name: updo\n    description: Uptime monitoring CLI tool with alerting and advanced settings\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.2\"\n        no_asset: true\n      - version_constraint: Version == \"v0.3.7\"\n        asset: updo_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: updo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: updo_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: updo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: updo_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/PaddiM8/kalker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: PaddiM8\n    repo_name: kalker\n    description: Kalker is a calculator program that supports user-defined variables, functions, differentiation, and integration\n    asset: kalker-{{.OS}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: raw\n        asset: kalker-{{.OS}}\n    replacements:\n      darwin: macOS\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    files:\n      - name: kalker\n        src: target/release/kalker\n    version_constraint: semver(\">= 1.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.3.4\")\n        asset: kalk-{{.OS}}.{{.Format}}\n        overrides:\n          - goos: linux\n            format: raw\n            asset: kalk-{{.OS}}\n        files:\n          - name: kalker\n            src: target/release/kalk\n      - version_constraint: semver(\">= 0.3.3\")\n        asset: kalk-{{.OS}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: kalk\n        replacements:\n          darwin: macOS\n          linux: Linux\n        supported_envs:\n          - darwin\n          - amd64\n        files:\n          - name: kalker\n            src: target/release/kalk\n      - version_constraint: semver(\">= 0.2.0\")\n        asset: kalk_cli_{{.OS}}64\n        format: raw\n        overrides: []\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false\n      - version_constraint: semver(\"< 0.2.0\")\n        asset: kalk_cli\n        format: raw\n        overrides: []\n        supported_envs:\n          - linux/amd64\n        rosetta2: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/PaulJuliusMartinez/jless/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: PaulJuliusMartinez\n    repo_name: jless\n    description: jless is a command-line JSON viewer designed for reading, exploring, and searching through JSON data\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: jless-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: jless-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Percona-Lab/mysql_random_data_load/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Percona-Lab\n    repo_name: mysql_random_data_load\n    asset: mysql_random_data_load_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: MySQL random data loader\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Phantas0s/devdash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Phantas0s\n    repo_name: devdash\n    description: \":bento: Highly Configurable Terminal Dashboard for Developers and Creators\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: devdash_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: devdash_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Piturnah/gex/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Piturnah\n    repo_name: gex\n    description: \"Git Explorer: cross-platform git workflow improvement tool inspired by Magit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.5\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gex-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Pluralith/pluralith-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Pluralith\n    repo_name: pluralith-cli\n    asset: pluralith_cli_tap_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n    format: tar.gz\n    description: A tool for Terraform state visualisation and automated generation of infrastructure documentation\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: pluralith\n        src: \"{{.OS}}/pluralith\"\n    checksum:\n      type: github_release\n      asset: pluralith_checksums_{{.Version}}.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/PowerShell/PowerShell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: PowerShell\n    repo_name: PowerShell\n    description: PowerShell for every system\n    files:\n      - name: pwsh\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 6.1.6\")\n        asset: powershell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            asset: PowerShell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 7.0.13\")\n        asset: powershell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            asset: PowerShell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: >-\n          semver(\"<= 7.4.7\") ||\n          (semver(\">= 7.5.0-preview.1, <= 7.5.1\")) ||\n          (semver(\">= 7.6.0-preview.1, <= 7.6.0-preview.4\"))\n        asset: powershell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        checksum:\n          type: github_release\n          asset: hashes.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: PowerShell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: powershell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            asset: PowerShell-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Qovery/Replibyte/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Qovery\n    repo_name: Replibyte\n    description: Seed your development database with real data\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: replibyte\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: replibyte\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - linux/amd64\n          - windows\n        checksum:\n          type: github_release\n          asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n      - version_constraint: Version == \"v0.4.2\"\n        asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: replibyte\n            src: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.{{.Format}}\n            checksum:\n              type: github_release\n              asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.sha256sum\n              algorithm: sha256\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.sha256sum\n          algorithm: sha256\n      - version_constraint: Version == \"v0.4.3\"\n        asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: replibyte\n            src: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-gnu\n        supported_envs:\n          - windows/amd64\n        checksum:\n          type: github_release\n          asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.{{.Format}}.sha256sum\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: replibyte\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.{{.Format}}\n            checksum:\n              type: github_release\n              asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.exe.{{.Format}}.sha256sum\n              algorithm: sha256\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: replibyte_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Rigellute/spotify-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Rigellute\n    repo_name: spotify-tui\n    asset: spotify-tui-{{.OS}}.tar.gz\n    description: Spotify for the terminal written in Rust\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: spt\n    checksum:\n      type: github_release\n      asset: spotify-tui-{{.OS}}.sha256\n      algorithm: sha256\n    overrides:\n      - goos: windows\n        checksum:\n          type: github_release\n          asset: spotify-tui-{{.OS}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/RoseSecurity/Kuzco/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: RoseSecurity\n    repo_name: Kuzco\n    description: Kuzco reviews your Terraform resources, compares them to the provider schema to detect unused parameters, and uses AI to suggest improvements\n    files:\n      - name: kuzco\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: Kuzco_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kuzco\n            src: Kuzco\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: Kuzco_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/RyuyaIshibashi/aws-s3-siggy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: RyuyaIshibashi\n    repo_name: aws-s3-siggy\n    files:\n      - name: siggy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.7\"\n        asset: aws-s3-siggy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: aws-s3-siggy\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: aws-s3-siggy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.9\"\n        asset: siggy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: siggy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.0\"\n        asset: siggy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: siggy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: siggy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SUPERCILEX/fuc/cpz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: SUPERCILEX/fuc/cpz\n    type: github_release\n    repo_owner: SUPERCILEX\n    repo_name: fuc\n    description: Modern, performance focused unix commands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: cpz-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: cpz-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: \"true\"\n        asset: \"{{.Arch}}-{{.OS}}-cpz\"\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SUPERCILEX/fuc/rmz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: SUPERCILEX/fuc/rmz\n    type: github_release\n    repo_owner: SUPERCILEX\n    repo_name: fuc\n    description: Modern, performance focused unix commands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: rmz-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: rmz-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: \"true\"\n        asset: \"{{.Arch}}-{{.OS}}-rmz\"\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Scalingo/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Scalingo\n    repo_name: cli\n    description: Command Line client for Scalingo PaaS\n    asset: scalingo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: scalingo\n        src: scalingo_{{.Version}}_{{.OS}}_{{.Arch}}/scalingo\n    overrides:\n      - goos: windows\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums_windows.txt\n          algorithm: sha256\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.26.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.24.1\")\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\">= 1.24.0\")\n        overrides: []\n      - version_constraint: semver(\">= 1.21.0\")\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.20.1\")\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 1.20.1\")\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: scalingo\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Schniz/fnm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Schniz\n    repo_name: fnm\n    description: Fast and simple Node.js version manager, built in Rust\n    asset: fnm-linux.zip\n    overrides:\n      - goos: darwin\n        asset: fnm-macos.zip\n      - goos: windows\n        asset: fnm-windows.zip\n      - goos: linux\n        goarch: arm64\n        asset: fnm-arm64.zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SecureAuthCorp/oauth2c/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: SecureAuthCorp\n    repo_name: oauth2c\n    aliases:\n      - name: cloudentity/oauth2c\n    description: User-friendly OAuth2 CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: oauth2c_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Shopify/ejson/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Shopify\n    repo_name: ejson\n    description: EJSON is a small library to manage encrypted secrets using asymmetric encryption\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 1.3.0\")\n        error_message: Please use v1.3.0 or later\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: Version == \"v1.3.3\"\n        asset: ejson_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        checksum:\n          type: github_release\n          asset: ejson_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: Version == \"v1.4.0\"\n        asset: ejson_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: ejson_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: \"true\"\n        asset: ejson_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        checksum:\n          type: github_release\n          asset: ejson_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Shopify/kubeaudit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Shopify\n    repo_name: kubeaudit\n    description: kubeaudit helps you audit your Kubernetes clusters against common security controls\n    files:\n      - name: kubeaudit\n      - name: kubectl-audit\n        src: kubeaudit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubeaudit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        checksum:\n          type: github_release\n          asset: kubeaudit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Shopify/shadowenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Shopify\n    repo_name: shadowenv\n    description: reversible directory-local environment variable manipulations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.2.1\"\n        asset: shadowenv-{{.OS}}-10.14\n        format: raw\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"2.1.0\"\n        asset: shadowenv-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"2.1.1\"\n        asset: shadowenv-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: shadowenv-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 2.0.5\")\n        asset: shadowenv-{{.OS}}-latest\n        format: raw\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 2.0.7\")\n        asset: shadowenv-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: shadowenv-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Shopify/toxiproxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Shopify\n    repo_name: toxiproxy\n    description: A TCP proxy to simulate network and system conditions for chaos and resiliency testing\n    files:\n      - name: toxiproxy-cli\n      - name: toxiproxy-server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: toxiproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SimonTheLeg/konf-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: SimonTheLeg\n    repo_name: konf-go\n    description: konf is a lightweight kubeconfig manager. With konf you can use different kubeconfigs at the same time. And because it does not need subshells, konf is blazing fast\n    files:\n      - name: konf-go\n      - name: konf\n        src: konf-go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: konf-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: konf-go_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Skardyy/mcat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Skardyy\n    repo_name: mcat\n    description: Terminal image, video, directory, and Markdown viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.3\"\n        asset: mcat-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: mcat\n            src: mcat-{{.Arch}}-{{.OS}}/mcat\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: mcat\n      - version_constraint: \"true\"\n        asset: mcat-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: mcat\n            src: mcat-{{.Arch}}-{{.OS}}/mcat\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n            files:\n              - name: mcat\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Skarlso/crd-to-sample-yaml/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Skarlso\n    repo_name: crd-to-sample-yaml\n    description: Generate a sample YAML file from a CRD and view it rendered on a nice website\n    files:\n      - name: cty\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.8\")\n        asset: crd-to-yaml_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: crd-to-yaml\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: crd-to-yaml_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.4\")\n        asset: cty_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: cty\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cty_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cty_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: cty\n        checksum:\n          type: github_release\n          asset: cty_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SonarSource/sonar-scanner-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: SonarSource\n    repo_name: sonar-scanner-cli\n    description: Scanner CLI for SonarQube (Server, Cloud)\n    files:\n      - name: sonar-scanner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"< 6.1.0\")\n        url: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-{{.SemVer}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: sonar-scanner\n            src: sonar-scanner-{{.SemVer}}-{{.OS}}-{{.Arch}}/bin/sonar-scanner\n        replacements:\n          darwin: macosx\n        overrides:\n          - goos: windows\n            files:\n              - name: sonar-scanner.bat\n                src: sonar-scanner-{{.SemVer}}-{{.OS}}-{{.Arch}}/bin/sonar-scanner.bat\n      - version_constraint: \"true\"\n        url: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-{{.SemVer}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: sonar-scanner\n            src: sonar-scanner-{{.SemVer}}-{{.OS}}-{{.Arch}}/bin/sonar-scanner\n        replacements:\n          darwin: macosx\n          amd64: x64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            files:\n              - name: sonar-scanner.bat\n                src: sonar-scanner-{{.SemVer}}-{{.OS}}-{{.Arch}}/bin/sonar-scanner.bat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/ecschedule/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: ecschedule\n    description: ecschedule is a tool to manage ECS Scheduled Tasks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.1\"\n        asset: ecschedule_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: ecschedule\n            src: \"{{.AssetWithoutExt}}/ecschedule\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: ecsched_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: ecsched\n            src: \"{{.AssetWithoutExt}}/ecsched\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: ecschedule_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: ecschedule\n            src: \"{{.AssetWithoutExt}}/ecschedule\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: ecschedule_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: ecschedule\n            src: \"{{.AssetWithoutExt}}/ecschedule\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.11.4\")\n        asset: ecschedule_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: ecschedule\n            src: \"{{.AssetWithoutExt}}/ecschedule\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: ecschedule_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: ecschedule\n            src: \"{{.AssetWithoutExt}}/ecschedule\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/gh2changelog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: gh2changelog\n    asset: gh2changelog_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: gh2changelog\n        src: gh2changelog_{{.Version}}_{{.OS}}_{{.Arch}}/gh2changelog\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/ghch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: ghch\n    description: Generate changelog from git history, tags and merged pull requests\n    rosetta2: true\n    asset: ghch_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: ghch\n        src: ghch_{{.Version}}_{{.OS}}_amd64/ghch\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/ghg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: ghg\n    description: Get the executable from github releases easily\n    rosetta2: true\n    asset: ghg_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    files:\n      - name: ghg\n        src: ghg_{{.Version}}_{{.OS}}_amd64/ghg\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/gitsemvers/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: gitsemvers\n    description: Retrieve semvers from git tags\n    asset: gitsemvers_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: git-semvers\n        src: gitsemvers_{{.Version}}_{{.OS}}_{{.Arch}}/git-semvers\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/gocredits/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: gocredits\n    description: creates CREDITS file from LICENSE files of dependencies\n    rosetta2: true\n    asset: gocredits_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: gocredits\n        src: gocredits_{{.Version}}_{{.OS}}_amd64/gocredits\n    format: tar.gz\n    overrides:\n      - goos: darwin\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/godzil/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: godzil\n    asset: godzil_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: A Go Authoring tool\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: godzil\n        src: godzil_{{.Version}}_{{.OS}}_{{.Arch}}/godzil\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/gotesplit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: gotesplit\n    asset: gotesplit_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Splits the testing in Go into a subset and run it. It is useful for the CI environment\n    files:\n      - name: gotesplit\n        src: gotesplit_{{.Version}}_{{.OS}}_{{.Arch}}/gotesplit\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/goxz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: goxz\n    asset: goxz_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Just do cross building and archiving go tools conventionally\n    files:\n      - name: goxz\n        src: goxz_{{.Version}}_{{.OS}}_{{.Arch}}/goxz\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/horenso/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: horenso\n    description: Command wrapper for reporting the result. It is useful for cron jobs\n    rosetta2: true\n    asset: horenso_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: horenso\n        src: horenso_{{.Version}}_{{.OS}}_amd64/horenso\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/laminate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: laminate\n    description: A command-line bridge tool that orchestrates external image generation commands to convert text/code strings to images\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: laminate_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        files:\n          - name: laminate\n            src: laminate_{{.Version}}_{{.OS}}_{{.Arch}}/laminate\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/make2help/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: make2help\n    description: Utility for self-documented Makefile\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: make2help_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: make2help\n            src: make2help_{{.Version}}_{{.OS}}_{{.Arch}}/make2help\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: make2help_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: make2help\n            src: make2help_{{.Version}}_{{.OS}}_{{.Arch}}/make2help\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: make2help_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: make2help\n            src: make2help_{{.Version}}_{{.OS}}_{{.Arch}}/make2help\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/maltmill/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: maltmill\n    asset: maltmill_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: create and update Homebrew thrid party Formulae\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: maltmill\n        src: maltmill_{{.Version}}_{{.OS}}_{{.Arch}}/maltmill\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/podbard/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: podbard\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: primcast_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: primcast\n            src: primcast_{{.Version}}_{{.OS}}_{{.Arch}}/primcast\n      - version_constraint: \"true\"\n        asset: podbard_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: podbard\n            src: podbard_{{.Version}}_{{.OS}}_{{.Arch}}/podbard\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/r2sync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: r2sync\n    description: r2sync is a command-line tool for synchronizing files between a local directory and Cloudflare R2\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: r2sync_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: r2sync\n            src: r2sync_{{.Version}}_{{.OS}}_{{.Arch}}/r2sync\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/tagpr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: tagpr\n    description: The tagpr automatically creates and updates a pull request for unreleased items, tag them when they are merged, and create releases\n    asset: tagpr_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: tagpr\n        src: tagpr_{{.Version}}_{{.OS}}_{{.Arch}}/tagpr\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Songmu/timeout/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Songmu\n    repo_name: timeout\n    asset: timeout_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Timeout invocation. Go porting of GNU timeout and able to use as Go package\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: go-timeout\n        src: timeout_{{.Version}}_{{.OS}}_{{.Arch}}/go-timeout\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Stranger6667/jsonschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Stranger6667\n    repo_name: jsonschema\n    description: A high-performance JSON Schema validator for Rust\n    version_prefix: cli-\n    files:\n      - name: jsonschema-cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: jsonschema-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/SuperCuber/dotter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: SuperCuber\n    repo_name: dotter\n    description: A dotfile manager and templater written in rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.12.15\")\n        asset: dotter\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: dotter\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: dotter.arm\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: \"true\"\n        asset: dotter-{{.OS}}-{{.Arch}}-musl\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: dotter-{{.OS}}-{{.Arch}}.arm\n            replacements:\n              amd64: amd64\n          - goos: windows\n            asset: dotter-{{.OS}}-{{.Arch}}-msvc\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TaKO8Ki/frum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TaKO8Ki\n    repo_name: frum\n    asset: frum-{{.Version}}-{{.Arch}}-{{.OS}}.tar.gz\n    description: A little bit fast and modern Ruby version manager written in Rust\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    files:\n      - name: frum\n        src: frum-{{.Version}}-{{.Arch}}-{{.OS}}/frum\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TaKO8Ki/gobang/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TaKO8Ki\n    repo_name: gobang\n    asset: gobang-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A cross-platform TUI database management tool written in Rust\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: gobang\n        src: gobang-{{trimV .Version}}-{{.Arch}}-{{.OS}}/gobang\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TekWizely/bingo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: TekWizely\n    repo_name: bingo\n    description: The missing package manager for golang binaries (its homebrew for \"go install\")\n    path: bingo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TekWizely/run/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TekWizely\n    repo_name: run\n    description: Task runner that helps you easily manage and invoke small scripts and wrappers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: run_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: run_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: run_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Telemaco019/kubesafe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Telemaco019\n    repo_name: kubesafe\n    description: Safely manage multiple Kubernetes clusters by defining safe contexts and protected commands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubesafe_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubesafe_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TheZoraiz/ascii-image-converter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TheZoraiz\n    repo_name: ascii-image-converter\n    asset: ascii-image-converter_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: A cross-platform command-line tool to convert images into ascii art and print them on the console. Now supports braille art\n    files:\n      - name: ascii-image-converter\n        src: ascii-image-converter_{{.OS}}_{{.Arch}}/ascii-image-converter\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      linux: Linux\n      windows: Windows\n      darwin: macOS\n      amd64: amd64_64bit\n      arm64: arm64_64bit\n      386: i386_32bit\n      arm: armv6_32bit\n    checksum:\n      type: github_release\n      asset: sha256_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TimothyYe/skm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TimothyYe\n    repo_name: skm\n    description: A simple and powerful SSH keys manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.6\"\n        asset: skm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.0\")\n        version_prefix: V\n        asset: skm-{{.OS}}64-{{.SemVer}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.1\")\n        version_prefix: V\n        asset: skm-{{.OS}}64-{{.SemVer}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n          - goos: windows\n            asset: skm-{{.OS}}-{{.SemVer}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.5\")\n        asset: skm-{{.OS}}64-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n          - goos: windows\n            asset: skm-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: skm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/TomWright/dasel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: TomWright\n    repo_name: dasel\n    rosetta2: true\n    asset: dasel_{{.OS}}_{{.Arch}}\n    format: raw\n    description: Select, put and delete data from JSON, TOML, YAML, XML and CSV files with a single tool. Supports conversion between formats and can be used as a Go package\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Traackr/binnacle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Traackr\n    repo_name: binnacle\n    description: An opinionated tool to interact with Kubernetes' Helm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: binnacle-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUM.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: binnacle-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUM.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: binnacle-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUM.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Trendyol/kink/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Trendyol\n    repo_name: kink\n    description: KinK is a helper CLI that facilitates to manage KinD clusters as Kubernetes pods. Designed to ease clusters up for fast testing with batteries included in mind\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.2.1\")\n        asset: kink_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kink_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://raw.githubusercontent.com/Trendyol/kink/refs/tags/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/Trendyol/kink/releases/download/{{.Version}}/kink_checksums.txt.sig\n              - --insecure-ignore-tlog\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.1\"\n        asset: kink_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kink_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://raw.githubusercontent.com/Trendyol/kink/refs/tags/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/Trendyol/kink/releases/download/{{.Version}}/kink_checksums.txt.sig\n              - --insecure-ignore-tlog\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kink_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kink_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://raw.githubusercontent.com/Trendyol/kink/refs/tags/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/Trendyol/kink/releases/download/{{.Version}}/kink_checksums.txt.sig\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Tyrrrz/FFmpegBin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Tyrrrz\n    repo_name: FFmpegBin\n    description: Pre-built FFmpeg binaries for every platform\n    files:\n      - name: ffmpeg\n      - name: ffplay\n      - name: ffprobe\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"7.1.1\"\n        asset: ffmpeg-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            checksum:\n              type: github_release\n              asset: ffmpeg-{{.OS}}-{{.Arch}}.sha256\n              algorithm: sha256\n      - version_constraint: semver(\"<= 7.1.0\")\n        asset: ffmpeg-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: ffmpeg-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          darwin: osx\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/UpCloudLtd/upcloud-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: UpCloudLtd\n    repo_name: upcloud-cli\n    description: UpCloud command line client (upctl)\n    files:\n      - name: upctl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: upctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: upcloud-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 3.16.0\")\n        asset: upcloud-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: upcloud-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: UpCloudLtd/upcloud-cli/.github/workflows/publish.yml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Versent/saml2aws/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Versent\n    repo_name: saml2aws\n    description: CLI tool which enables you to login and retrieve AWS temporary credentials using a SAML IDP\n    asset: saml2aws_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n      - goos: darwin\n        checksum:\n          type: github_release\n          asset: saml2aws_{{trimV .Version}}_darwin_checksums.txt\n          algorithm: sha256\n    checksum:\n      type: github_release\n      asset: saml2aws_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.36.5\")\n    version_overrides:\n      - version_constraint: semver(\">= 2.34.0\")\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\">= 2.28.3\")\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 2.28.1\")\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 2.1.0\")\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: saml2aws_{{trimV .Version}}_{{.OS}}_{{.Arch}}.sha512\n          algorithm: sha512\n      - version_constraint: semver(\">= 2.0.2\")\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: saml2aws_{{trimV .Version}}_{{.OS}}_{{.Arch}}.sha512\n          algorithm: sha512\n      - version_constraint: semver(\">= 1.3.1\")\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: saml2aws_{{trimV .Version}}_{{.OS}}_{{.Arch}}.sha512\n          algorithm: sha512\n      - version_constraint: semver(\"< 1.3.1\")\n        format: tgz\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ViRb3/wgcf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ViRb3\n    repo_name: wgcf\n    description: Cross-platform, unofficial CLI for Cloudflare Warp\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.2.6\"\n        asset: wgcf_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.2.2\")\n        asset: wgcf_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.2.5\")\n        asset: wgcf_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: wgcf_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/VictoriaMetrics/VictoriaMetrics/victoria-metrics/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: VictoriaMetrics/VictoriaMetrics/victoria-metrics\n    type: github_release\n    repo_owner: VictoriaMetrics\n    repo_name: VictoriaMetrics\n    description: \"VictoriaMetrics: fast, cost-effective monitoring solution and time series database\"\n    version_filter: not (Version endsWith \"-victorialogs\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 1.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.29.4\")\n        asset: victoria-metrics-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.52.0\")\n        asset: victoria-metrics-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        checksum:\n          type: github_release\n          asset: victoria-metrics-{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.72.0\")\n        asset: victoria-metrics-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        checksum:\n          type: github_release\n          asset: victoria-metrics-{{.Arch}}-{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.78.1\")\n        asset: victoria-metrics-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        overrides:\n          - goos: darwin\n            asset: victoria-metrics-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.89.1\")\n        asset: victoria-metrics-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        checksum:\n          type: github_release\n          asset: victoria-metrics-{{.OS}}-{{.Arch}}-{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"> 1.97.1, <= 1.97.17\") or semver(\"> 1.102.1, <= 1.102.21\") or semver(\"> 1.110.0, <= 1.110.8\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: victoria-metrics-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: victoria-metrics\n            src: victoria-metrics-prod\n        checksum:\n          type: github_release\n          asset: victoria-metrics-{{.OS}}-{{.Arch}}-{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: victoria-metrics\n                src: victoria-metrics-{{.OS}}-{{.Arch}}-prod.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/VictoriaMetrics/VictoriaMetrics/vmutils/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: VictoriaMetrics/VictoriaMetrics/vmutils\n    type: github_release\n    repo_owner: VictoriaMetrics\n    repo_name: VictoriaMetrics\n    description: \"VictoriaMetrics: fast, cost-effective monitoring solution and time series database\"\n    files:\n      - name: vmalert-tool\n        src: vmalert-tool-prod\n    version_filter: semver(\"> 1.78.1\") and not (Version endsWith \"-victorialogs\") and (Version endsWith \".0\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.103.0\"\n        asset: vmutils-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: vmutils-{{.OS}}-{{.Arch}}-{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: vmutils-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vmutils-{{.OS}}-{{.Arch}}-{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: vmalert-tool\n                src: vmalert-tool-windows-{{.Arch}}-prod.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/WebAssembly/binaryen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: WebAssembly\n    repo_name: binaryen\n    description: Optimizer and compiler/toolchain library for WebAssembly\n    asset: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    version_prefix: version_\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    files:\n      - name: binaryen-unittests\n        src: binaryen-{{.Version}}/bin/binaryen-unittests\n      - name: wasm-as\n        src: binaryen-{{.Version}}/bin/wasm-as\n      - name: wasm-ctor-eval\n        src: binaryen-{{.Version}}/bin/wasm-ctor-eval\n      - name: wasm-dis\n        src: binaryen-{{.Version}}/bin/wasm-dis\n      - name: wasm-emscripten-finalize\n        src: binaryen-{{.Version}}/bin/wasm-emscripten-finalize\n      - name: wasm-fuzz-types\n        src: binaryen-{{.Version}}/bin/wasm-fuzz-types\n      - name: wasm-metadce\n        src: binaryen-{{.Version}}/bin/wasm-metadce\n      - name: wasm-opt\n        src: binaryen-{{.Version}}/bin/wasm-opt\n      - name: wasm-reduce\n        src: binaryen-{{.Version}}/bin/wasm-reduce\n      - name: wasm-shell\n        src: binaryen-{{.Version}}/bin/wasm-shell\n      - name: wasm-split\n        src: binaryen-{{.Version}}/bin/wasm-split\n      - name: wasm2js\n        src: binaryen-{{.Version}}/bin/wasm2js\n    version_constraint: semver(\">= 108\")\n    version_overrides:\n      - version_constraint: semver(\">= 106\")\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\">= 105\")\n        files:\n          - name: wasm-as\n            src: binaryen-{{.Version}}/bin/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/bin/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/bin/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/bin/wasm-emscripten-finalize\n          - name: wasm-fuzz-types\n            src: binaryen-{{.Version}}/bin/wasm-fuzz-types\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/bin/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/bin/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/bin/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/bin/wasm-shell\n          - name: wasm-split\n            src: binaryen-{{.Version}}/bin/wasm-split\n          - name: wasm2js\n            src: binaryen-{{.Version}}/bin/wasm2js\n      - version_constraint: semver(\">= 100\")\n        rosetta2: true\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n        files:\n          - name: wasm-as\n            src: binaryen-{{.Version}}/bin/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/bin/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/bin/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/bin/wasm-emscripten-finalize\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/bin/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/bin/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/bin/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/bin/wasm-shell\n          - name: wasm-split\n            src: binaryen-{{.Version}}/bin/wasm-split\n          - name: wasm2js\n            src: binaryen-{{.Version}}/bin/wasm2js\n      - version_constraint: semver(\">= 98\")\n        supported_envs:\n          - darwin\n          - windows/amd64\n        rosetta2: true\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n        files:\n          - name: wasm-as\n            src: binaryen-{{.Version}}/bin/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/bin/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/bin/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/bin/wasm-emscripten-finalize\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/bin/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/bin/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/bin/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/bin/wasm-shell\n          - name: wasm2js\n            src: binaryen-{{.Version}}/bin/wasm2js\n      - version_constraint: semver(\">= 93\")\n        rosetta2: true\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n        files: &webassembly_binaryen_files_3\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/wasm-emscripten-finalize\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2js\n            src: binaryen-{{.Version}}/wasm2js\n      - version_constraint: semver(\">= 92\")\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n            files: &webassembly_binaryen_files_windows_3\n              - name: asm2wasm\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/asm2wasm\n              - name: wasm-as\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-as\n              - name: wasm-ctor-eval\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-ctor-eval\n              - name: wasm-dis\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-dis\n              - name: wasm-emscripten-finalize\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-emscripten-finalize\n              - name: wasm-metadce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-metadce\n              - name: wasm-opt\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-opt\n              - name: wasm-reduce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-reduce\n              - name: wasm-shell\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-shell\n              - name: wasm2js\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm2js\n      - version_constraint: semver(\">= 91\")\n        overrides:\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n            checksum:\n              enabled: false\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 90\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: binaryen-{{.Version}}-x86-{{.OS}}.{{.Format}}\n            checksum:\n              enabled: false\n            files: &webassembly_binaryen_files_windows_2\n              - name: asm2wasm\n                src: binaryen-{{.Version}}-x86-{{.OS}}/asm2wasm\n              - name: wasm-as\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-as\n              - name: wasm-ctor-eval\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-ctor-eval\n              - name: wasm-dis\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-dis\n              - name: wasm-emscripten-finalize\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-emscripten-finalize\n              - name: wasm-metadce\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-metadce\n              - name: wasm-opt\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-opt\n              - name: wasm-reduce\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-reduce\n              - name: wasm-shell\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm-shell\n              - name: wasm2js\n                src: binaryen-{{.Version}}-x86-{{.OS}}/wasm2js\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 89\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 88\")\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - windows/amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n      - version_constraint: semver(\">= 84\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 82\")\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - windows/amd64\n        checksum:\n          enabled: false\n        files: *webassembly_binaryen_files_3\n        overrides:\n          - goos: windows\n            files: *webassembly_binaryen_files_windows_3\n      - version_constraint: semver(\">= 77\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 76\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: binaryen-{{.Version}}-x86-{{.OS}}.{{.Format}}\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_2\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 75\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_3\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 74\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files:\n              - name: asm2wasm\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/asm2wasm\n              - name: wasm-as\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-as\n              - name: wasm-ctor-eval\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-ctor-eval\n              - name: wasm-dis\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-dis\n              - name: wasm-emscripten-finalize\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-emscripten-finalize\n              - name: wasm-metadce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-metadce\n              - name: wasm-opt\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-opt\n              - name: wasm-reduce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-reduce\n              - name: wasm-shell\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-shell\n              - name: wasm2js\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm2js\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - windows/amd64\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 44\")\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files: &webassembly_binaryen_files_4\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/wasm-emscripten-finalize\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n      - version_constraint: semver(\">= 42\")\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n      - version_constraint: semver(\">= 38\")\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n      - version_constraint: semver(\">= 1.39.1\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: &webassembly_binaryen_files_windows_1\n              - name: asm2wasm\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/asm2wasm\n              - name: wasm-as\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-as\n              - name: wasm-ctor-eval\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-ctor-eval\n              - name: wasm-dis\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-dis\n              - name: wasm-emscripten-finalize\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-emscripten-finalize\n              - name: wasm-metadce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-metadce\n              - name: wasm-opt\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-opt\n              - name: wasm-reduce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-reduce\n              - name: wasm-shell\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-shell\n              - name: wasm2js\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm2js\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        version_prefix: \"\"\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 1.38.48\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_1\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - windows/amd64\n        version_prefix: \"\"\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 1.38.47\")\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - windows/amd64\n        version_prefix: \"\"\n        checksum:\n          enabled: false\n        files: *webassembly_binaryen_files_3\n        overrides:\n          - goos: windows\n            files: *webassembly_binaryen_files_windows_1\n      - version_constraint: semver(\">= 1.38.32\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            checksum:\n              enabled: false\n            files: *webassembly_binaryen_files_windows_1\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        version_prefix: \"\"\n        rosetta2: true\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 1.38.31\")\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - windows/amd64\n        version_prefix: \"\"\n        checksum:\n          enabled: false\n        files: *webassembly_binaryen_files_3\n        overrides:\n          - goos: windows\n            files:\n              - name: asm2wasm\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/asm2wasm\n              - name: wasm-as\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-as\n              - name: wasm-ctor-eval\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-ctor-eval\n              - name: wasm-dis\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-dis\n              - name: wasm-emscripten-finalize\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-emscripten-finalize\n              - name: wasm-metadce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-metadce\n              - name: wasm-opt\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-opt\n              - name: wasm-reduce\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-reduce\n              - name: wasm-shell\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm-shell\n              - name: wasm2js\n                src: binaryen-{{.Version}}-{{.Arch}}-{{.OS}}/wasm2js\n      - version_constraint: semver(\">= 1.38.30\")\n        asset: binaryen-{{.Version}}-x86-{{.OS}}.{{.Format}}\n        replacements: {}\n        supported_envs:\n          - linux/amd64\n        version_prefix: \"\"\n        files: *webassembly_binaryen_files_3\n      - version_constraint: semver(\">= 1.37.34\")\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        version_prefix: \"\"\n        files:\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/wasm-emscripten-finalize\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n      - version_constraint: semver(\">= 1.37.29\")\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        version_prefix: \"\"\n        files:\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-emscripten-finalize\n            src: binaryen-{{.Version}}/wasm-emscripten-finalize\n          - name: wasm-link-metadata\n            src: binaryen-{{.Version}}/wasm-link-metadata\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-metadce\n            src: binaryen-{{.Version}}/wasm-metadce\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-reduce\n            src: binaryen-{{.Version}}/wasm-reduce\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n      - version_constraint: semver(\"< 1.37.29\")\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        version_prefix: \"\"\n        files:\n          - name: asm2wasm\n            src: binaryen-{{.Version}}/asm2wasm\n          - name: s2wasm\n            src: binaryen-{{.Version}}/s2wasm\n          - name: wasm-as\n            src: binaryen-{{.Version}}/wasm-as\n          - name: wasm-ctor-eval\n            src: binaryen-{{.Version}}/wasm-ctor-eval\n          - name: wasm-dis\n            src: binaryen-{{.Version}}/wasm-dis\n          - name: wasm-merge\n            src: binaryen-{{.Version}}/wasm-merge\n          - name: wasm-opt\n            src: binaryen-{{.Version}}/wasm-opt\n          - name: wasm-shell\n            src: binaryen-{{.Version}}/wasm-shell\n          - name: wasm2asm\n            src: binaryen-{{.Version}}/wasm2asm\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/WebAssembly/wabt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: WebAssembly\n    repo_name: wabt\n    description: The WebAssembly Binary Toolkit\n    asset: wabt-{{.Version}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      darwin: macos-12\n      linux: ubuntu\n    supported_envs:\n      - amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    files:\n      - name: spectest-interp\n        src: wabt-{{.Version}}/bin/spectest-interp\n      - name: wasm-decompile\n        src: wabt-{{.Version}}/bin/wasm-decompile\n      - name: wasm-interp\n        src: wabt-{{.Version}}/bin/wasm-interp\n      - name: wasm-objdump\n        src: wabt-{{.Version}}/bin/wasm-objdump\n      - name: wasm-stats\n        src: wabt-{{.Version}}/bin/wasm-stats\n      - name: wasm-strip\n        src: wabt-{{.Version}}/bin/wasm-strip\n      - name: wasm-validate\n        src: wabt-{{.Version}}/bin/wasm-validate\n      - name: wasm2c\n        src: wabt-{{.Version}}/bin/wasm2c\n      - name: wasm2wat\n        src: wabt-{{.Version}}/bin/wasm2wat\n      - name: wast2json\n        src: wabt-{{.Version}}/bin/wast2json\n      - name: wat-desugar\n        src: wabt-{{.Version}}/bin/wat-desugar\n      - name: wat2wasm\n        src: wabt-{{.Version}}/bin/wat2wasm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.35\")\n        asset: wabt-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: wabt-{{.Version}}-{{.OS}}.{{.Format}}\n        replacements:\n          darwin: macos-14\n          linux: ubuntu-20.04\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"1.0.34\"\n      - version_constraint: Version == \"1.0.33\"\n        files: &wabt_files_1\n          - name: spectest-interp\n            src: wabt-{{.Version}}/bin/spectest-interp\n          - name: wasm-interp\n            src: wabt-{{.Version}}/bin/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/bin/wasm-objdump\n          - name: wasm-opcodecnt\n            src: wabt-{{.Version}}/bin/wasm-opcodecnt\n          - name: wasm-validate\n            src: wabt-{{.Version}}/bin/wasm-validate\n          - name: wasm2c\n            src: wabt-{{.Version}}/bin/wasm2c\n          - name: wasm2wat\n            src: wabt-{{.Version}}/bin/wasm2wat\n          - name: wast2json\n            src: wabt-{{.Version}}/bin/wast2json\n          - name: wat-desugar\n            src: wabt-{{.Version}}/bin/wat-desugar\n          - name: wat2wasm\n            src: wabt-{{.Version}}/bin/wat2wasm\n      - version_constraint: semver(\">= 1.0.17\")\n        files: *wabt_files_1\n        replacements:\n          darwin: macos\n          linux: ubuntu\n      - version_constraint: semver(\">= 1.0.15\")\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: wasm-decompile\n              - name: wasm-interp\n              - name: wasm-objdump\n              - name: wasm-opcodecnt\n              - name: wasm-strip\n              - name: wasm-validate\n              - name: wasm2c\n              - name: wasm2wat\n              - name: wast2json\n              - name: wat-desugar\n              - name: wat2wasm\n        replacements:\n          darwin: osx\n          windows: win64\n        files:\n          - name: wasm-decompile\n            src: wabt-{{.Version}}/wasm-decompile\n          - name: wasm-interp\n            src: wabt-{{.Version}}/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/wasm-objdump\n      - version_constraint: semver(\">= 1.0.14\")\n        format: zip\n        replacements:\n          windows: win64\n        supported_envs:\n          - windows/amd64\n        rosetta2: false # https://github.com/aquaproj/aqua-registry/pull/15753#issuecomment-1736713576\n        files:\n          - name: wasm-decompile\n          - name: wasm-interp\n          - name: wasm-objdump\n          - name: wasm-opcodecnt\n          - name: wasm-strip\n          - name: wasm-validate\n          - name: wasm2c\n          - name: wasm2wat\n          - name: wast2json\n          - name: wat-desugar\n          - name: wat2wasm\n      - version_constraint: semver(\">= 1.0.13\")\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: wasm-decompile\n              - name: wasm-interp\n              - name: wasm-objdump\n              - name: wasm-opcodecnt\n              - name: wasm-strip\n              - name: wasm-validate\n              - name: wasm2c\n              - name: wasm2wat\n              - name: wast2json\n              - name: wat-desugar\n              - name: wat2wasm\n        replacements:\n          windows: win64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false # https://github.com/aquaproj/aqua-registry/pull/15753#issuecomment-1736713576\n        files:\n          - name: wasm-decompile\n            src: wabt-{{.Version}}/wasm-decompile\n          - name: wasm-interp\n            src: wabt-{{.Version}}/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/wasm-objdump\n      - version_constraint: semver(\">= 1.0.5\")\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: spectest-interp\n              - name: wabt-unittests\n              - name: wasm-interp\n              - name: wasm-objdump\n              - name: wasm-opcodecnt\n              - name: wasm-validate\n              - name: wasm2c\n              - name: wasm2wat\n              - name: wast2json\n              - name: wat-desugar\n              - name: wat2wasm\n        replacements:\n          darwin: osx\n          windows: win64\n        files:\n          - name: spectest-interp\n            src: wabt-{{.Version}}/spectest-interp\n          - name: wasm-interp\n            src: wabt-{{.Version}}/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/wasm-objdump\n          - name: wasm-opcodecnt\n            src: wabt-{{.Version}}/wasm-opcodecnt\n          - name: wasm-validate\n            src: wabt-{{.Version}}/wasm-validate\n          - name: wasm2c\n            src: wabt-{{.Version}}/wasm2c\n          - name: wasm2wat\n            src: wabt-{{.Version}}/wasm2wat\n          - name: wast2json\n            src: wabt-{{.Version}}/wast2json\n          - name: wat-desugar\n            src: wabt-{{.Version}}/wat-desugar\n          - name: wat2wasm\n            src: wabt-{{.Version}}/wat2wasm\n      - version_constraint: semver(\">= 1.0.3\")\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: spectest-interp\n            src: wabt-{{.Version}}/spectest-interp\n          - name: wasm-interp\n            src: wabt-{{.Version}}/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/wasm-objdump\n          - name: wasm-opcodecnt\n            src: wabt-{{.Version}}/wasm-opcodecnt\n          - name: wasm-validate\n            src: wabt-{{.Version}}/wasm-validate\n          - name: wasm2c\n            src: wabt-{{.Version}}/wasm2c\n          - name: wasm2wat\n            src: wabt-{{.Version}}/wasm2wat\n          - name: wast2json\n            src: wabt-{{.Version}}/wast2json\n          - name: wat-desugar\n            src: wabt-{{.Version}}/wat-desugar\n          - name: wat2wasm\n            src: wabt-{{.Version}}/wat2wasm\n      - version_constraint: semver(\"< 1.0.3\")\n        replacements: {}\n        supported_envs:\n          - linux/amd64\n        rosetta2: false # https://github.com/aquaproj/aqua-registry/pull/15753#issuecomment-1736713576\n        files:\n          - name: spectest-interp\n            src: wabt-{{.Version}}/spectest-interp\n          - name: wasm-interp\n            src: wabt-{{.Version}}/wasm-interp\n          - name: wasm-objdump\n            src: wabt-{{.Version}}/wasm-objdump\n          - name: wasm-opcodecnt\n            src: wabt-{{.Version}}/wasm-opcodecnt\n          - name: wasm-validate\n            src: wabt-{{.Version}}/wasm-validate\n          - name: wasm2c\n            src: wabt-{{.Version}}/wasm2c\n          - name: wasm2wat\n            src: wabt-{{.Version}}/wasm2wat\n          - name: wast2json\n            src: wabt-{{.Version}}/wast2json\n          - name: wat-desugar\n            src: wabt-{{.Version}}/wat-desugar\n          - name: wat2wasm\n            src: wabt-{{.Version}}/wat2wasm\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Wilfred/difftastic/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Wilfred\n    repo_name: difftastic\n    description: a structural diff that understands syntax\n    files:\n      - name: difft\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.51.0\"\n        no_asset: true\n      - version_constraint: Version == \"0.36.0\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.51.1\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.52.0\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.53.0\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.56.0\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.26.2\")\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.50.0\")\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.62.0\")\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: difft-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: difft\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/WoozyMasta/kube-dump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: WoozyMasta\n    repo_name: kube-dump\n    description: Backup a Kubernetes cluster as a yaml manifest\n    path: kube-dump\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/XAMPPRocky/tokei/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: XAMPPRocky\n    repo_name: tokei\n    description: Count your code, quickly\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 9.1.0\")\n        asset: tokei-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 10.0.1\")\n        asset: tokei-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v10.1.0\"\n        asset: tokei-{{.Version}}-i686-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            asset: tokei-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n      - version_constraint: Version == \"v10.1.1\"\n        asset: tokei-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v10.1.2\"\n        asset: tokei-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 11.1.1\")\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 12.0.3\")\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: tokei-{{.Arch}}-{{.OS}}\n      - version_constraint: Version == \"v12.0.4a\"\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: raw\n            asset: tokei-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v12.0.4\"\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: tokei-{{.Arch}}-{{.OS}}\n      - version_constraint: Version == \"v12.1.0\"\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 13.0.0-alpha.0\")\n        asset: tokei-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: tokei-{{.Arch}}-{{.OS}}\n      - version_constraint: \"true\"\n        type: cargo\n        crate: tokei\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/XcodesOrg/xcodes/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: XcodesOrg\n    repo_name: xcodes\n    description: The best command-line tool to install and switch between multiple versions of Xcode\n    asset: xcodes.zip\n    supported_envs:\n      - darwin\n    version_overrides:\n      - version_constraint: Version == \"1.4.0\"\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/YS-L/csvlens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: YS-L\n    repo_name: csvlens\n    description: Command line csv viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.10.0\")\n        asset: csvlens-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csvlens\n            src: csvlens-{{.Arch}}-{{.OS}}/csvlens\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csvlens\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: csvlens-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csvlens\n            src: csvlens-{{.Arch}}-{{.OS}}/csvlens\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csvlens\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/Zxilly/go-size-analyzer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: Zxilly\n    repo_name: go-size-analyzer\n    description: A tool for analyzing the size of compiled Go binaries, offering cross-platform support, detailed breakdowns, and multiple output formats\n    files:\n      - name: gsa\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"< 1.2.3\")\n        asset: go-size-analyzer_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 1.3.4\")\n        asset: go-size-analyzer_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: Zxilly/go-size-analyzer/.github/workflows/build-gsa.yml\n      - version_constraint: semver(\"<= 1.9.1\")\n        asset: go-size-analyzer_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        # Disable slsa_provenance\n        # FAILED: SLSA verification failed: untrusted reusable workflow: https://github.com/Zxilly/go-size-analyzer/.github/workflows/release.yml with builderID provided: false\n        github_artifact_attestations:\n          signer_workflow: Zxilly/go-size-analyzer/.github/workflows/release.yml\n      - version_constraint: \"true\"\n        asset: go-size-analyzer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: Zxilly/go-size-analyzer/.github/workflows/release.yml\n        # Disable slsa_provenance\n        # FAILED: SLSA verification failed: untrusted reusable workflow: https://github.com/Zxilly/go-size-analyzer/.github/workflows/release.yml with builderID provided: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-key/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-key\n    type: go_install\n    description: One of Sigsum command line tools. Generate new keys, create and verify signatures, and convert between different key formats.\n    path: sigsum.org/sigsum-go/cmd/sigsum-key\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-monitor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-monitor\n    type: go_install\n    description: One of Sigsum command line tools\n    path: sigsum.org/sigsum-go/cmd/sigsum-monitor\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-submit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-submit\n    type: go_install\n    description: |\n      One of Sigsum command line tools.\n      The sigsum-submit tool is used to create and/or submit add-leaf requests to a Sigsum log\n    path: sigsum.org/sigsum-go/cmd/sigsum-submit\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-token/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-token\n    type: go_install\n    description: |\n      One of Sigsum command line tools.\n      The sigsum-token tool is used to manage the Sigsum \"submit tokens\" that are used for domain based rate limiting\n    path: sigsum.org/sigsum-go/cmd/sigsum-token\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-verify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-verify\n    type: go_install\n    description: One of Sigsum command line tools. sigsum-verify tool verifies a Sigsum proof, as created by sigsum-submit\n    path: sigsum.org/sigsum-go/cmd/sigsum-verify\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/_go/sigsum.org/sigsum-go/cmd/sigsum-witness/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: _go/sigsum.org/sigsum-go#cmd/sigsum-witness\n    type: go_install\n    description: One of Sigsum command line tools\n    path: sigsum.org/sigsum-go/cmd/sigsum-witness\n    go_version_path: sigsum.org/sigsum-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/a-h/templ/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: a-h\n    repo_name: templ\n    description: A language for writing HTML user interfaces in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.126\")\n        asset: templ_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.148\")\n        asset: templ_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.194\")\n        asset: templ_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.2.639\")\n        asset: templ_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: templ_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --signature\n              - https://github.com/a-h/templ/releases/download/{{.Version}}/checksums.txt.sig\n              - --key\n              - https://raw.githubusercontent.com/a-h/templ/refs/tags/{{.Version}}/cosign.pub\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/a8m/envsubst/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: a8m\n    repo_name: envsubst\n    description: Environment variables substitution for Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: envsubst-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.0\"\n        asset: envsubst-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            asset: envsubst.exe.exec\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.2.0\"\n        asset: envsubst-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            asset: envsubst\n      - version_constraint: Version == \"v1.4.1\"\n        asset: envsubst-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: envsubst-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            asset: envsubst\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aakso/ssh-inscribe/sshi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: aakso/ssh-inscribe/sshi\n    repo_owner: aakso\n    repo_name: ssh-inscribe\n    description: SSH CA Client/Server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: sshi-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: sshi-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.10.0\"\n        asset: sshi-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: sshi-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aandrew-me/tgpt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aandrew-me\n    repo_name: tgpt\n    description: AI Chatbots in terminal without needing API keys\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: tgpt-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: tgpt-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.2.1\")\n        asset: tgpt-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: tgpt-{{.Arch}}\n      - version_constraint: \"true\"\n        asset: tgpt-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: tgpt-{{.Arch}}.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/abhimanyu003/sttr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: abhimanyu003\n    repo_name: sttr\n    description: cross-platform, cli app to perform various operations on string\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.11\")\n        asset: sttr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sttr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.23\")\n        asset: sttr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sttr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: sttr_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n      - version_constraint: Version == \"v0.2.24\"\n        asset: sttr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sttr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/abhimanyu003/sttr/.github/workflows/goreleaser.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/abhimanyu003/sttr/releases/download/{{.Version}}/sttr_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/abhimanyu003/sttr/releases/download/{{.Version}}/sttr_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: darwin\n            asset: sttr_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.28\")\n        asset: sttr_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sttr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/abhimanyu003/sttr/releases/download/{{.Version}}/sttr_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/abhimanyu003/sttr/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/abhimanyu003/sttr/releases/download/{{.Version}}/sttr_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: darwin\n            asset: sttr_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: sttr_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sttr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: sttr_{{trimV .Version}}_checksums.txt.sigstore.json\n            opts:\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/abhimanyu003/sttr/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n        overrides:\n          - goos: darwin\n            asset: sttr_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/abhinav/doc2go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: abhinav\n    repo_name: doc2go\n    description: Your Go project's documentation, to-go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: doc2go-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/abice/go-enum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: abice\n    repo_name: go-enum\n    description: An enum generator for go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.5.9-beta-1\", \"v0.5.9\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.3.5\"\n        asset: go-enum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.3.6\"\n        asset: go-enum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: go-enum_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.5.9-beta-2\"\n        asset: go-enum_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: go-enum_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.11\")\n        asset: go-enum_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: go-enum_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: go-enum_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: go-enum_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/abiosoft/colima/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: abiosoft\n    repo_name: colima\n    description: Container runtimes on macOS (and Linux) with minimal setup\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.7.1\"\n        # https://github.com/abiosoft/colima/issues/1106\n        asset: colima-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: colima-{{.OS}}-{{.Arch}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            checksum:\n              enabled: false\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: colima-amd64\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: colima-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: colima-{{.OS}}-{{.Arch}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/abs-lang/abs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: abs-lang\n    repo_name: abs\n    description: \"Home of the ABS programming language: the joy of shell scripting\"\n    rosetta2: true\n    format: raw\n    asset: abs-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/acheronfail/repgrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: acheronfail\n    repo_name: repgrep\n    description: An interactive replacer for ripgrep that makes it easy to find and replace across files on the command line\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.2.0\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.3\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\"<= 0.4.5\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"<= 0.4.7\")\n        no_asset: true\n      - version_constraint: Version == \"v0.4.8\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"v0.7.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"0.10.2\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: Version == \"0.10.3\"\n        no_asset: true\n      - version_constraint: Version == \"0.10.4\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: Version == \"0.10.5\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"0.10.6\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rgr\n            src: repgrep-{{.Version}}-{{.Arch}}-{{.OS}}/rgr\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/achristmascarl/rainfrog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: achristmascarl\n    repo_name: rainfrog\n    description: a database management tui for postgres\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: rainfrog-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: rainfrog-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rainfrog-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: rainfrog-{{.Version}}-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/acorn-io/runtime/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: acorn-io\n    repo_name: runtime\n    aliases:\n      - name: acorn-io/acorn\n    description: A simple application deployment framework for Kubernetes\n    asset: acorn-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: acorn\n    format: tar.gz\n    replacements:\n      darwin: macOS\n    overrides:\n      - goos: darwin\n        asset: acorn-{{.Version}}-{{.OS}}-universal.{{.Format}}\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/actions/go-versions/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: actions\n    repo_name: go-versions\n    description: Go releases for Actions Runner Images\n    files:\n      - name: go\n        src: bin/go\n      - name: gofmt\n        src: bin/gofmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: go-{{.Version | regexFind \"^[^-]+\"}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x64\n          windows: win32\n        checksum:\n          type: github_release\n          asset: hashes.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/adhocteam/ssm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: adhocteam\n    repo_name: ssm\n    description: AWS SSM Paramater Store CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: ssm-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: ssm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        # linux/amd64 doesn't match hash\n        overrides:\n          - goos: linux\n            goarch: amd64\n            checksum:\n              enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: ssm-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n        # darwin/arm64 doesn't match hash\n        # https://github.com/adhocteam/ssm/pull/41\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            checksum:\n              enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        # https://github.com/adhocteam/ssm/pull/41\n        asset: ssm-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aduros/wasm4/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aduros\n    repo_name: wasm4\n    description: Build retro games using WebAssembly for a fantasy console\n    files:\n      - name: w4\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.9\"\n        asset: wasm4-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: w4\n            src: wasm4-{{.OS}}/w4\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: w4-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: w4\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aereal/jsondiff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aereal\n    repo_name: jsondiff\n    description: functions to calculate JSON objects differences with gojq filter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: jsondiff_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: jsondiff_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: jsondiff_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: jsondiff_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/afnanenayet/diffsitter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: afnanenayet\n    repo_name: diffsitter\n    description: A tree-sitter based AST difftool to get meaningful semantic diffs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.1\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: diffsitter\n            src: target/release/diffsitter\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.5\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.6\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.0-2\")\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: diffsitter\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.0-3\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: diffsitter\n            checksum:\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        checksum:\n          type: github_release\n          asset: diffsitter-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.0\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: diffsitter\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.3.0-1\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: diffsitter\n            checksum:\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.3.0\"\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.4\")\n        asset: diffsitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/diffsitter\n          - name: git-diffsitter\n            src: diffsitter-{{.OS}}-{{.Arch}}/git-diffsitter\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: diffsitter\n              - name: git-diffsitter\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.6.5\"\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/diffsitter\n          - name: git-diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/git-diffsitter\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: diffsitter\n              - name: git-diffsitter\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.6.6\"\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/diffsitter\n          - name: git-diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/git-diffsitter\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: diffsitter\n              - name: git-diffsitter\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/diffsitter\n          - name: git-diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/git-diffsitter\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: diffsitter\n              - name: git-diffsitter\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.7.2\"\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/diffsitter\n          - name: git-diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/git-diffsitter\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.7.3\"\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: diffsitter\n            src: diffsitter-{{.Arch}}-{{.OS}}/diffsitter\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: diffsitter\n              - name: git-diffsitter\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: diffsitter-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        complete_windows_ext: false\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: diffsitter-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ahmetb/kubectl-tree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ahmetb\n    repo_name: kubectl-tree\n    description: kubectl plugin to browse Kubernetes object hierarchies as a tree  (star the repo if you are using)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: kubectl-tree_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-tree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: kubectl-tree_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kubectl-tree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: kubectl-tree_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-tree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubectl-tree_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-tree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ahmetb/kubectx/kubens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: ahmetb/kubectx/kubens\n    type: github_release\n    repo_owner: ahmetb\n    repo_name: kubectx\n    aliases:\n      - name: ahmetb/kubens\n    description: Faster way to switch between clusters and namespaces in kubectl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0\"\n        asset: kubens_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: kubens_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.4\")\n        asset: kubens_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubens_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ahmetb/kubectx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ahmetb\n    repo_name: kubectx\n    description: Faster way to switch between clusters and namespaces in kubectl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0\"\n        asset: kubectx_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: kubectx_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.4\")\n        asset: kubectx_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubectx_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/air-verse/air/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: air-verse\n    repo_name: air\n    aliases:\n      - name: cosmtrek/air\n    description: Live reload for Go apps\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.12.2\"\n        asset: air_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: air_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.12.3\"\n        asset: air_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: air_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.12.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.15.1\")\n        asset: air_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: air_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.27.3\")\n        asset: air_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: air_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: air_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: air_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/airbytehq/abctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: airbytehq\n    repo_name: abctl\n    description: Airbyte's CLI for managing local Airbyte installations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2\"\n        asset: abctl-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: abctl\n            src: \"{{.AssetWithoutExt}}/abctl\"\n        overrides:\n          - envs:\n              - linux\n              - darwin/amd64\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.13.1\")\n        asset: abctl-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: abctl\n            src: \"{{.AssetWithoutExt}}/abctl\"\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: abctl-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: abctl\n            src: \"{{.AssetWithoutExt}}/abctl\"\n        checksum:\n          type: github_release\n          asset: abctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ajeetdsouza/zoxide/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ajeetdsouza\n    repo_name: zoxide\n    description: A smarter cd command. Supports all major shells\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      windows: pc-windows-msvc\n      linux: unknown-linux-musl\n      darwin: apple-darwin\n      amd64: x86_64\n      arm64: aarch64\n    version_constraint: semver(\">= 0.8.2\")\n    asset: zoxide-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: zoxide-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/akiomik/mado/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: akiomik\n    repo_name: mado\n    description: A fast Markdown linter written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mado-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux-gnu\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: mado-{{.OS}}-msvc-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alajmo/mani/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alajmo\n    repo_name: mani\n    description: CLI tool to help you manage repositories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mani_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alcideio/rbac-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alcideio\n    repo_name: rbac-tool\n    description: Rapid7 | insightCloudSec | Kubernetes RBAC Power Toys - Visualize, Analyze, Generate & Query\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: rbac-tool-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rbac-tool\n            src: \"{{.OS}}-{{.Arch}}/rbac-tool\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: rbac-tool_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rbac-tool_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: rbac-tool_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rbac-tool_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.4\")\n        asset: rbac-tool_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rbac-tool_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rbac-tool_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rbac-tool_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alebeck/boring/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alebeck\n    repo_name: boring\n    description: The `boring`  SSH tunnel manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: boring-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alexellis/arkade/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alexellis\n    repo_name: arkade\n    description: Open Source Marketplace For Developer Tools\n    files:\n      - name: ark\n      - name: arkade\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.6.6\", \"0.6.26\", \"0.6.32\", \"0.6.34\", \"0.7.2\"]\n        no_asset: true\n      - version_constraint: Version == \"0.1.0\"\n        asset: bazaar\n        format: raw\n        files:\n          - name: bazaar\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: bazaar-arm64\n          - goos: darwin\n            asset: bazaar-darwin\n      - version_constraint: semver(\"<= 0.8.12\")\n        asset: arkade\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: arkade-arm64\n          - goos: darwin\n            asset: arkade-darwin\n      - version_constraint: \"true\"\n        asset: arkade\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: arkade-arm64\n          - goos: darwin\n            goarch: amd64\n            asset: arkade-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: arkade-darwin-arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alexellis/k3sup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alexellis\n    repo_name: k3sup\n    description: bootstrap K3s over SSH in < 60s\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.3.2\", \"0.4.4\", \"0.5.9\", \"0.12.9\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: k3sup\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: k3sup-arm64\n          - goos: darwin\n            asset: k3sup-darwin\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: semver(\"<= 0.5.8\")\n        asset: k3sup\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: k3sup-arm64\n          - goos: darwin\n            asset: k3sup-darwin\n      - version_constraint: semver(\"<= 0.9.7\")\n        asset: k3sup\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: k3sup-arm64\n          - goos: darwin\n            asset: k3sup-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: k3sup\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: k3sup-arm64\n          - goos: darwin\n            asset: k3sup-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: k3sup\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: k3sup-arm64\n          - goos: darwin\n            goarch: amd64\n            asset: k3sup-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: k3sup-darwin-arm64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alexellis/kubetrim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alexellis\n    repo_name: kubetrim\n    description: Trim  your KUBECONFIG automatically\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1-rc1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.1-rc3\")\n        asset: kubetrim\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: kubetrim-arm64\n          - goos: darwin\n            goarch: amd64\n            asset: kubetrim-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: kubetrim-darwin-arm64\n      - version_constraint: \"true\"\n        asset: kubetrim.tgz\n        format: tgz\n        files:\n          - name: kubetrim\n            src: '{{trimSuffix \".tgz\" .Asset}}'\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: kubetrim-arm64.tgz\n          - goos: darwin\n            goarch: amd64\n            asset: kubetrim-darwin.tgz\n          - goos: darwin\n            goarch: arm64\n            asset: kubetrim-darwin-arm64.tgz\n          - goos: windows\n            asset: kubetrim.exe.tgz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alexhallam/tv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alexhallam\n    repo_name: tv\n    description: (tv) Tidy Viewer is a cross-platform CLI csv pretty printer that uses column styling to maximize viewer enjoyment\n    files:\n      - name: tidy-viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.18\")\n        error_message: The version is too old. Please upgrade to a newer version.\n      - version_constraint: semver(\"<= 1.4.6\")\n        asset: tidy-viewer--{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tidy-viewer\n            src: \"{{.AssetWithoutExt}}/tidy-viewer\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.30\")\n        asset: tidy-viewer-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tidy-viewer\n            src: \"{{.AssetWithoutExt}}/tidy-viewer\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.5.2\")\n        asset: tidy-viewer-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tidy-viewer\n            src: \"{{.AssetWithoutExt}}/tidy-viewer\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n            asset: tidy-viewer-{{.Version}}.{{.Format}}\n            files:\n              - name: tidy-viewer\n                src: usr/bin/tidy-viewer\n          - goos: darwin\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.6.5\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tidy-viewer-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            format: tar.gz\n          - goos: linux\n            format: tgz\n            asset: tidy-viewer-{{.Version}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alexpasmantier/television/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alexpasmantier\n    repo_name: television\n    description: The revolution will (not) be televised\n    files:\n      - name: tv\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.15\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.9\")\n        asset: tv-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"tv-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.11.3\")\n        asset: tv-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: tv\n            src: \"{{.AssetWithoutExt}}/tv\"\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"tv-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: tv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: tv\n            src: \"{{.AssetWithoutExt}}/tv\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: tv-{{.Version}}-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/allero-io/allero/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: allero-io\n    repo_name: allero\n    description: By scanning CI/CD misconfigurations, Allero helps reduce production issues, harden your security posture and shift-left CI/CD from DevOps to developers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: allero_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/allyring/pvw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: allyring\n    repo_name: pvw\n    description: A port viewer TUI made with BubbleTea in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.1\")\n        asset: pvw_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pvw_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: pvw_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pvw_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: pvw_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pvw_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alpkeskin/mosint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: alpkeskin\n    repo_name: mosint\n    description: An automated e-mail OSINT tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.3.1\"\n        type: go_build\n        files:\n          - name: mosint\n            src: .\n            dir: mosint-{{trimV .Version}}\n      - version_constraint: \"true\"\n        path: github.com/alpkeskin/mosint/v{{(semver .Version).Major}}/cmd/mosint\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/altsem/gitu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: altsem\n    repo_name: gitu\n    description: A TUI Git client inspired by Magit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.17.1\")\n        asset: gitu-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: gitu\n            src: \"{{.AssetWithoutExt}}/gitu\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.18.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.19.1\")\n        asset: gitu-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gitu\n            src: \"{{.AssetWithoutExt}}/gitu\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.29.0\")\n        asset: gitu-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: gitu\n            src: \"{{.AssetWithoutExt}}/gitu\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gitu-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: gitu\n            src: \"{{.AssetWithoutExt}}/gitu\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/alvinunreal/tmuxai/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: alvinunreal\n    repo_name: tmuxai\n    aliases:\n      - name: alvinunreal/tmuxai\n      - name: BoringDystopiaDevelopment/tmuxai\n    description: AI-Powered, Non-Intrusive Terminal Assistant\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: tmuxai_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tmuxai_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/amacneil/dbmate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: amacneil\n    repo_name: dbmate\n    description: A lightweight, framework-agnostic database migration tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.13.0\"\n        asset: dbmate-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: dbmate-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.9.1\")\n        asset: dbmate-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.11.0\")\n        asset: dbmate-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n      - version_constraint: \"true\"\n        asset: dbmate-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/amalshaji/portr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: amalshaji\n    repo_name: portr\n    description: Open source ngrok alternative designed for teams. Tunnel http, tcp or websocket connections\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: portr_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/amber-lang/amber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: amber-lang\n    repo_name: amber\n    aliases:\n      - name: Ph0enixKM/Amber\n    description: Amber the programming language compiled to bash\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1-alpha\")\n        asset: amber_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: amber-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: amber\n            src: \"{{.AssetWithoutExt}}/amber\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: amber\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/amir20/dtop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: amir20\n    repo_name: dtop\n    description: Terminal dashboard for Docker monitoring across multiple hosts with Dozzle integration\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: dtop_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: dtop_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: dtop_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: dtop_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.3.8\")\n        asset: dtop-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: dtop\n            src: \"{{.AssetWithoutExt}}/dtop\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: dtop-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: dtop\n            src: \"{{.AssetWithoutExt}}/dtop\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ampcode/zvelte-check/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ampcode\n    repo_name: zvelte-check\n    description: A fast diagnostic tool for Svelte projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: zvelte-check-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anchore/grype/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: anchore\n    repo_name: grype\n    description: A vulnerability scanner for container images and filesystems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: grype_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: grype_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.23.0\")\n        asset: grype_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: grype_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            checksum:\n              # checksum not included in checksums.txt\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.31.1\")\n        asset: grype_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: grype_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            checksum:\n              # checksum not included in checksums.txt\n              enabled: false\n          - goos: windows\n            checksum:\n              # checksum not included in checksums.txt\n              enabled: false\n      - version_constraint: semver(\"<= 0.71.0\")\n        asset: grype_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: grype_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: grype_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: grype_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/anchore/grype/releases/download/{{.Version}}/grype_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/anchore/grype/.github/workflows/release.yaml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/anchore/grype/releases/download/{{.Version}}/grype_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anchore/quill/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: anchore\n    repo_name: quill\n    description: Simple mac binary signing from any platform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: quill_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: quill_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: quill_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: quill_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anchore/syft/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: anchore\n    repo_name: syft\n    description: CLI tool and library for generating a Software Bill of Materials from container images and filesystems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.26.0\"\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.27.0\"\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n          - goos: windows\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.36.0\"\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n          - goos: windows\n            format: zip\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.25.0\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.35.1\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n      - version_constraint: semver(\"< 0.37.10\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              # checksum isn't included in checksums.txt\n              enabled: false\n      - version_constraint: semver(\"<= 0.103.1\")\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: syft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: syft_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/anchore/syft/releases/download/{{.Version}}/syft_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/anchore/syft/.github/workflows/release.yaml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/anchore/syft/releases/download/{{.Version}}/syft_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/andreazorzetto/yh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: andreazorzetto\n    repo_name: yh\n    description: YAML syntax highlighter to bring colours to kubectl output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        asset: yh-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: yh-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/andrewkroh/gvm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: andrewkroh\n    repo_name: gvm\n    description: Go Version Manager (written in Go for cross-platform usability)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.1-rc1\"\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v0.3.1\"\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: gvm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gvm_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/andreybleme/lazycontainer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: andreybleme\n    repo_name: lazycontainer\n    description: Fancy terminal UI for Apple Containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lazycontainer_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ankitpokhrel/jira-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ankitpokhrel\n    repo_name: jira-cli\n    description: Feature-rich interactive Jira command line\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: jira_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: jira\n            src: jira_{{trimV .Version}}_{{.OS}}_{{.Arch}}/bin/jira\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: jira\n                src: bin/jira\n            replacements:\n              amd64: amd64\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: jira_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: jira\n            src: jira_{{trimV .Version}}_{{.OS}}_{{.Arch}}/bin/jira\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: jira\n                src: bin/jira\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anomalyco/opencode/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: anomalyco\n    repo_name: opencode\n    aliases:\n      - name: sst/opencode\n    description: The AI coding agent built for the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.84\", \"v0.1.92\", \"v0.1.115\", \"v0.1.124\"]\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"v0.1.139\", \"v0.1.142\"]\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"v0.1.150\", \"v0.1.156\", \"v0.1.159\", \"v0.1.167\", \"v0.1.170\", \"v0.1.180\", \"v0.2.5\"]\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: Version in [\"v0.3.11\", \"v0.3.25\"]\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.0.92\"\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v1.0.93\"\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.0.52\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.61\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n      - version_constraint: semver(\"<= 0.1.129\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.18\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n      - version_constraint: semver(\"<= 0.3.20\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.31\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n      - version_constraint: semver(\"<= 0.3.34\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.91\")\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n      - version_constraint: \"true\"\n        asset: opencode-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anordal/shellharden/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: anordal\n    repo_name: shellharden\n    aliases:\n      # The registry had registered this name when this tool was first registered.\n      # https://github.com/aquaproj/aqua-registry/pull/13784\n      - name: crates.io/shellharden\n    description: The corrective bash syntax highlighter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.3.0\")\n        type: cargo\n        crate: shellharden\n      - version_constraint: \"true\"\n        asset: shellharden-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: shellharden-{{.Arch}}-{{.OS}}.sha512\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/antham/gommit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: antham\n    repo_name: gommit\n    description: Enforce git message commit consistency\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.3.0\")\n        asset: gommit_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.4.0\"\n        asset: gommit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.5.0\"\n        no_asset: true\n      - version_constraint: Version == \"v2.6.0\"\n        asset: gommit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gommit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gommit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/anthropics/claude-code/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: anthropics\n    repo_name: claude-code\n    description: Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands\n    files:\n      - name: claude\n    version_source: github_tag\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        format: raw\n        url: https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/{{trimV .Version}}/{{.OS}}-{{.Arch}}/claude\n        files:\n          - name: claude\n        replacements:\n          amd64: x64\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/antonmedv/fx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: antonmedv\n    repo_name: fx\n    description: Command-line tool and terminal JSON viewer\n    version_constraint: semver(\">= 21.0.0\")\n    asset: fx_{{.OS}}_{{.Arch}}\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: fx-{{.OS}}.zip\n        replacements:\n          darwin: macos\n          windows: win.exe\n        files:\n          - name: fx\n            src: fx-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/antonmedv/walk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: antonmedv\n    repo_name: walk\n    description: Terminal file manager\n    aliases:\n      - name: antonmedv/llama\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.5.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: llama_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: llama\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: llama_{{.OS}}_{{.Arch}}\n        format: raw\n        files:\n          - name: llama\n      - version_constraint: \"true\"\n        asset: walk_{{.OS}}_{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/ant/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: ant\n    description: Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other\n    version_source: github_tag\n    version_prefix: rel/\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.10.0\")\n        error_message: Please use 1.10.1 or later\n      - version_constraint: \"true\"\n        url: https://archive.apache.org/dist/ant/binaries/apache-ant-{{.SemVer}}-bin.{{.Format}}\n        format: tar.xz\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/ant/binaries/apache-ant-{{.SemVer}}-bin.{{.Format}}.sha512\n          file_format: regexp\n          algorithm: sha512\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{128}\\b)\n        files:\n          - name: ant\n            src: apache-ant-{{.SemVer}}/bin/ant\n        overrides:\n          - goos: windows\n            files:\n              - name: ant\n                src: apache-ant-{{.SemVer}}/bin/ant.bat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/camel-k/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: apache\n    repo_name: camel-k\n    description: Apache Camel K is a lightweight integration platform, born on Kubernetes, with serverless superpowers\n    asset: camel-k-client-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: kamel\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 2.0.0-nightly\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.9.0\")\n        replacements:\n          amd64: 64bit\n          arm64: arm64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 1.9.0-nightly\")\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 1.6.1\")\n        replacements:\n          amd64: 64bit\n          arm64: arm64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 1.0.0-M1\")\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.3.4\")\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n      - version_constraint: semver(\"< 0.3.4\")\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/jena/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: jena\n    description: A free and open source Java framework for building Semantic Web and Linked Data applications (CLI tools)\n    version_source: github_tag\n    version_prefix: jena-\n    version_filter: Version matches \"^jena-\\\\d+\"\n    files:\n      - name: arq\n        src: apache-jena-{{.SemVer}}/bin/arq\n      - name: infer\n        src: apache-jena-{{.SemVer}}/bin/infer\n      - name: iri\n        src: apache-jena-{{.SemVer}}/bin/iri\n      - name: juuid\n        src: apache-jena-{{.SemVer}}/bin/juuid\n      - name: nquads\n        src: apache-jena-{{.SemVer}}/bin/nquads\n      - name: ntriples\n        src: apache-jena-{{.SemVer}}/bin/ntriples\n      - name: qparse\n        src: apache-jena-{{.SemVer}}/bin/qparse\n      - name: rdfcat\n        src: apache-jena-{{.SemVer}}/bin/rdfcat\n      - name: rdfcompare\n        src: apache-jena-{{.SemVer}}/bin/rdfcompare\n      - name: rdfcopy\n        src: apache-jena-{{.SemVer}}/bin/rdfcopy\n      - name: rdfdiff\n        src: apache-jena-{{.SemVer}}/bin/rdfdiff\n      - name: rdfparse\n        src: apache-jena-{{.SemVer}}/bin/rdfparse\n      - name: rdfxml\n        src: apache-jena-{{.SemVer}}/bin/rdfxml\n      - name: riot\n        src: apache-jena-{{.SemVer}}/bin/riot\n      - name: rset\n        src: apache-jena-{{.SemVer}}/bin/rset\n      - name: rsparql\n        src: apache-jena-{{.SemVer}}/bin/rsparql\n      - name: rupdate\n        src: apache-jena-{{.SemVer}}/bin/rupdate\n      - name: schemagen\n        src: apache-jena-{{.SemVer}}/bin/schemagen\n      - name: shacl\n        src: apache-jena-{{.SemVer}}/bin/shacl\n      - name: sparql\n        src: apache-jena-{{.SemVer}}/bin/sparql\n      - name: tdb2.tdbbackup\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbbackup\n      - name: tdb2.tdbcompact\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbcompact\n      - name: tdb2.tdbdump\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbdump\n      - name: tdb2.tdbloader\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbloader\n      - name: tdb2.tdbquery\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbquery\n      - name: tdb2.tdbstats\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbstats\n      - name: tdb2.tdbupdate\n        src: apache-jena-{{.SemVer}}/bin/tdb2.tdbupdate\n      - name: tdbbackup\n        src: apache-jena-{{.SemVer}}/bin/tdbbackup\n      - name: tdbdump\n        src: apache-jena-{{.SemVer}}/bin/tdbdump\n    overrides:\n      - goos: windows\n        files:\n          - name: arq\n            src: apache-jena-{{.SemVer}}/bat/arq.bat\n          - name: infer\n            src: apache-jena-{{.SemVer}}/bat/infer.bat\n          - name: iri\n            src: apache-jena-{{.SemVer}}/bat/iri.bat\n          - name: juuid\n            src: apache-jena-{{.SemVer}}/bat/juuid.bat\n          - name: nquads\n            src: apache-jena-{{.SemVer}}/bat/nquads.bat\n          - name: ntriples\n            src: apache-jena-{{.SemVer}}/bat/ntriples.bat\n          - name: qparse\n            src: apache-jena-{{.SemVer}}/bat/qparse.bat\n          - name: rdfcat\n            src: apache-jena-{{.SemVer}}/bat/rdfcat.bat\n          - name: rdfcompare\n            src: apache-jena-{{.SemVer}}/bat/rdfcompare.bat\n          - name: rdfcopy\n            src: apache-jena-{{.SemVer}}/bat/rdfcopy.bat\n          - name: rdfdiff\n            src: apache-jena-{{.SemVer}}/bat/rdfdiff.bat\n          - name: rdfparse\n            src: apache-jena-{{.SemVer}}/bat/rdfparse.bat\n          - name: rdfxml\n            src: apache-jena-{{.SemVer}}/bat/rdfxml.bat\n          - name: riot\n            src: apache-jena-{{.SemVer}}/bat/riot.bat\n          - name: rset\n            src: apache-jena-{{.SemVer}}/bat/rset.bat\n          - name: rsparql\n            src: apache-jena-{{.SemVer}}/bat/rsparql.bat\n          - name: rupdate\n            src: apache-jena-{{.SemVer}}/bat/rupdate.bat\n          - name: schemagen\n            src: apache-jena-{{.SemVer}}/bat/schemagen.bat\n          - name: shacl\n            src: apache-jena-{{.SemVer}}/bat/shacl.bat\n          - name: sparql\n            src: apache-jena-{{.SemVer}}/bat/sparql.bat\n          - name: tdb2.tdbbackup\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbbackup.bat\n          - name: tdb2.tdbcompact\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbcompact.bat\n          - name: tdb2.tdbdump\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbdump.bat\n          - name: tdb2.tdbloader\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbloader.bat\n          - name: tdb2.tdbquery\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbquery.bat\n          - name: tdb2.tdbstats\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbstats.bat\n          - name: tdb2.tdbupdate\n            src: apache-jena-{{.SemVer}}/bat/tdb2_tdbupdate.bat\n          - name: tdbbackup\n            src: apache-jena-{{.SemVer}}/bat/tdbbackup.bat\n          - name: tdbdump\n            src: apache-jena-{{.SemVer}}/bat/tdbdump.bat\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://archive.apache.org/dist/jena/binaries/apache-jena-{{.SemVer}}.tar.gz\n        format: tgz\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/jena/binaries/apache-jena-{{.SemVer}}.tar.gz.sha512\n          file_format: regexp\n          algorithm: sha512\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{128}\\b)\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/maven/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: maven\n    description: Apache Maven core\n    version_prefix: maven-\n    version_constraint: \"false\"\n    version_filter: not (Version matches \"-(rc|alpha|beta)\")\n    version_overrides:\n      - version_constraint: semver(\"<= 3.2.5\")\n        url: https://archive.apache.org/dist/maven/maven-{{(semver .SemVer).Major}}/{{.SemVer}}/binaries/apache-maven-{{.SemVer}}-bin.{{.Format}}\n        format: tar.gz\n        files:\n          - name: mvn\n            src: apache-maven-{{.SemVer}}/bin/mvn\n        overrides:\n          - goos: windows\n            files:\n              - name: mvn\n                src: apache-maven-{{.SemVer}}/bin/mvn.bat\n      - version_constraint: \"true\"\n        url: https://archive.apache.org/dist/maven/maven-{{(semver .SemVer).Major}}/{{.SemVer}}/binaries/apache-maven-{{.SemVer}}-bin.{{.Format}}\n        format: tar.gz\n        files:\n          - name: mvn\n            src: apache-maven-{{.SemVer}}/bin/mvn\n        overrides:\n          - goos: windows\n            files:\n              - name: mvn\n                src: apache-maven-{{.SemVer}}/bin/mvn.cmd\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/maven-mvnd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: apache\n    repo_name: maven-mvnd\n    description: Apache Maven Daemon\n    files:\n      - name: mvnd\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.1\"\n        asset: mvnd-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.0.2\"\n        asset: mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"1.0-m6\", \"1.0-m8\"]\n        asset: maven-mvnd-{{.Version}}-m39-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        replacements:\n          arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.0-m7\"\n        # Maven Daemon comes into two different flavours: m39 which embeds Maven 3.9.x, and m40 which embeds Maven 4.0.0-alpha-x.\n        asset: maven-mvnd-{{.Version}}-m39-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        replacements:\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.0.2\"\n        asset: maven-mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        replacements:\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.8\")\n        asset: mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: maven-mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: maven-mvnd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mvnd\n            src: \"{{.AssetWithoutExt}}/bin/mvnd\"\n        replacements:\n          arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/pulsar/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: pulsar\n    description: Apache Pulsar - distributed pub-sub messaging system\n    url: https://dist.apache.org/repos/dist/release/pulsar/pulsar-{{trimV .Version}}/apache-pulsar-{{trimV .Version}}-bin.tar.gz\n    format: tar.gz\n    files:\n      - name: pulsar\n        src: apache-pulsar-{{trimV .Version}}/bin/pulsar\n      - name: pulsar-admin\n        src: apache-pulsar-{{trimV .Version}}/bin/pulsar-admin\n      - name: pulsar-client\n        src: apache-pulsar-{{trimV .Version}}/bin/pulsar-client\n      - name: pulsar-perf\n        src: apache-pulsar-{{trimV .Version}}/bin/pulsar-perf\n      - name: pulsar-shell\n        src: apache-pulsar-{{trimV .Version}}/bin/pulsar-shell\n      - name: bookkeeper\n        src: apache-pulsar-{{trimV .Version}}/bin/bookkeeper\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/spark/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: spark\n    description: Apache Spark - A unified analytics engine for large-scale data processing\n    files:\n      # https://github.com/aquaproj/aqua-registry/issues/1174#issuecomment-2577475188\n      - name: pyspark\n        src: spark-{{trimV .Version}}-bin-hadoop3/bin/pyspark\n      - name: spark-shell\n        src: spark-{{trimV .Version}}-bin-hadoop3/bin/spark-shell\n      - name: spark-sql\n        src: spark-{{trimV .Version}}-bin-hadoop3/bin/spark-sql\n      - name: sparkR\n        src: spark-{{trimV .Version}}-bin-hadoop3/bin/sparkR\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://archive.apache.org/dist/spark/spark-{{trimV .Version}}/spark-{{trimV .Version}}-bin-hadoop3.tgz\n        format: tgz\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/spark/spark-{{trimV .Version}}/spark-{{trimV .Version}}-bin-hadoop3.tgz.sha512\n          algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apache/tomcat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: apache\n    repo_name: tomcat\n    description: Apache Tomcat\n    version_source: github_tag\n    format: tar.gz\n    files:\n      - name: catalina.sh\n        src: apache-tomcat-{{.SemVer}}/bin/catalina.sh\n    overrides:\n      - envs:\n          - windows\n        files:\n          - name: catalina.bat\n            src: apache-tomcat-{{.SemVer}}/bin/catalina.bat\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 9.0.0\")\n        no_asset: true\n      - version_constraint: semver(\"< 9.0.2\")\n        url: https://archive.apache.org/dist/tomcat/tomcat-9/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/tomcat/tomcat-9/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}.md5\n          file_format: regexp\n          algorithm: md5\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{32}\\b)\n      - version_constraint: semver(\"< 10.0.0\")\n        url: https://archive.apache.org/dist/tomcat/tomcat-9/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/tomcat/tomcat-9/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}.sha512\n          file_format: regexp\n          algorithm: sha512\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{128}\\b)\n      - version_constraint: semver(\"< 11.0.0\")\n        url: https://archive.apache.org/dist/tomcat/tomcat-10/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/tomcat/tomcat-10/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}.sha512\n          file_format: regexp\n          algorithm: sha512\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{128}\\b)\n      - version_constraint: semver(\"< 12.0.0\")\n        url: https://archive.apache.org/dist/tomcat/tomcat-11/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}\n        checksum:\n          type: http\n          url: https://archive.apache.org/dist/tomcat/tomcat-11/v{{.SemVer}}/bin/apache-tomcat-{{.SemVer}}.{{.Format}}.sha512\n          file_format: regexp\n          algorithm: sha512\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{128}\\b)\n      - version_constraint: \"true\"\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aporia-ai/kubesurvival/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aporia-ai\n    repo_name: kubesurvival\n    description: Significantly reduce Kubernetes costs by finding the cheapest machine types that can run your workloads\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: KubeSurvival_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubesurvival_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apple/container/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: apple\n    repo_name: container\n    description: A tool for creating and running Linux containers using lightweight virtual machines on a Mac. It is written in Swift, and optimized for Apple silicon\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: container-{{.Version}}-installer-signed.{{.Format}}\n        format: pkg\n        files:\n          - name: container\n            src: Payload/bin/container\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: container-installer-signed.{{.Format}}\n        format: pkg\n        files:\n          - name: container\n            src: Payload/bin/container\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: container-{{.Version}}-installer-signed.{{.Format}}\n        format: pkg\n        files:\n          - name: container\n            src: Payload/bin/container\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apple/pkl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: apple\n    repo_name: pkl\n    description: A configuration as code language with rich validation and tooling\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.25.3\")\n        asset: pkl-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: pkl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          arm64: aarch64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apple/pkl-go/pkl-gen-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: apple/pkl-go/pkl-gen-go\n    type: github_release\n    repo_owner: apple\n    repo_name: pkl-go\n    description: Generates Go bindings for a Pkl module\n    version_filter: 'Version startsWith \"v\"'\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pkl-gen-go-{{.OS}}-{{.Arch}}.bin\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: pkl-gen-go-{{.OS}}.bin\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apstndb/execspansql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: apstndb\n    repo_name: execspansql\n    description: Yet another gcloud spanner databases execute-sql replacement for better composability\n    version_source: github_tag\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/apstndb/spannerplanviz/rendertree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: apstndb/spannerplanviz/rendertree\n    type: go_install\n    repo_owner: apstndb\n    repo_name: spannerplanviz\n    path: github.com/apstndb/spannerplanviz/cmd/rendertree\n    description: This tool render YAML or JSON representation of Cloud Spanner query plan as ascii format\n    version_source: github_tag\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aptly-dev/aptly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aptly-dev\n    repo_name: aptly\n    description: aptly - Debian repository management tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: aptly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: aptly\n            src: \"{{.AssetWithoutExt}}/aptly\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: aptly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: aptly\n            src: \"{{.AssetWithoutExt}}/aptly\"\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquaproj/aqua-installer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: aquaproj\n    repo_name: aqua-installer\n    path: aqua-installer\n    description: Install aqua quickly\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquaproj/aqua-registry-updater/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquaproj\n    repo_name: aqua-registry-updater\n    description: Renovate alternative specific to aqua-registry. Overcome Renovate's scalability issue\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: aqua-registry-updater_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: aqua-registry-updater_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/aquaproj/aqua-registry-updater/releases/download/{{.Version}}/aqua-registry-updater_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/aquaproj/aqua-registry-updater/releases/download/{{.Version}}/aqua-registry-updater_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: aqua-registry-updater_{{.OS}}_{{.Arch}}.tar.gz.intoto.jsonl\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquaproj/example-go-slsa-provenance/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquaproj\n    repo_name: example-go-slsa-provenance\n    description: Example Go Application with SLSA Provenance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: example-go-slsa-provenance_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: example-go-slsa-provenance_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: example-go-slsa-provenance_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: example-go-slsa-provenance_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/aquaproj/example-go-slsa-provenance/releases/download/{{.Version}}/example-go-slsa-provenance_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/aquaproj/example-go-slsa-provenance/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/aquaproj/example-go-slsa-provenance/releases/download/{{.Version}}/example-go-slsa-provenance_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquaproj/registry-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquaproj\n    repo_name: registry-tool\n    description: CLI to develop aqua Registry\n    asset: registry-tool_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: aqua-registry\n    checksum:\n      type: github_release\n      asset: registry-tool_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n      cosign:\n        opts:\n          - --certificate-identity-regexp\n          - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n          - --certificate-oidc-issuer\n          - \"https://token.actions.githubusercontent.com\"\n          - --signature\n          - https://github.com/aquaproj/registry-tool/releases/download/{{.Version}}/registry-tool_{{trimV .Version}}_checksums.txt.sig\n          - --certificate\n          - https://github.com/aquaproj/registry-tool/releases/download/{{.Version}}/registry-tool_{{trimV .Version}}_checksums.txt.pem\n    slsa_provenance:\n      type: github_release\n      asset: multiple.intoto.jsonl\n    version_constraint: semver(\">= 0.1.6\")\n    version_overrides:\n      - version_constraint: \"true\"\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: registry-tool_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/chain-bench/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: chain-bench\n    description: An open-source tool for auditing your software supply chain stack for security compliance based on a new CIS Software Supply Chain benchmark\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: chain-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: chain-bench_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/kube-bench/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: kube-bench\n    description: Checks whether Kubernetes is deployed according to security best practices as defined in the CIS Kubernetes Benchmark\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.0.12\", \"v0.6.4\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.11\"\n        asset: kube-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kube-bench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.8\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.29\")\n        asset: kube-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kube-bench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.32\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: kube-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kube-bench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.13-rc2\")\n        asset: kube-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kube-bench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: kube-bench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kube-bench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/kubectl-who-can/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: kubectl-who-can\n    description: Show who has RBAC permissions to perform actions on different resources in Kubernetes\n    files:\n      # https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/#naming-a-plugin\n      # https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/#names-with-dashes-and-underscores\n      # Rename kubectl-who-can to kubectl-who_can.\n      # kubectl-who-can becomes `kubectl who can` because - is command separator.\n      # To include - in the command name, use _.\n      - name: kubectl-who_can\n        src: kubectl-who-can\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: kubectl-who-can_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubectl-who-can_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/starboard/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: starboard\n    description: Superseded by https://github.com/aquasecurity/trivy-operator\n    files:\n      - name: starboard\n      - name: kubectl-starboard\n        src: starboard\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: starboard_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.19\")\n        asset: starboard_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: ARM64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: starboard_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: ARM64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: ARM\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/tfsec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: tfsec\n    description: Security scanner for your Terraform code\n    asset: tfsec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: tfsec_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.26.2\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.26.2\")\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 1.24.4\")\n      - version_constraint: semver(\">= 1.23.2\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 1.18.0\")\n      - version_constraint: semver(\">= 1.16.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 1.0.0-rc.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: false\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.63.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: false\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.58.7\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: false\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.51.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: false\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.39.35\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: tfsec_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.9.0\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.8.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.8.1\")\n        asset: tfsec-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aquasecurity/trivy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aquasecurity\n    repo_name: trivy\n    description: Find vulnerabilities, misconfigurations, secrets, SBOM in containers, Kubernetes, code repositories, clouds and more\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.20.0\"\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.31.3\")\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{trimV .Version}}_checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.67.2\")\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/aquasecurity/trivy/releases/download/{{.Version}}/trivy_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n      - version_constraint: \"true\"\n        asset: trivy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: trivy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: trivy_{{trimV .Version}}_checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arcanist-sh/hx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arcanist-sh\n    repo_name: hx\n    aliases:\n      - name: raskell-io/hx\n    description: An extremely fast Haskell package and project manager, written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.0\"\n        asset: hx-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.3.0\"\n        asset: hx-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: hx\n            src: \"{{.AssetWithoutExt}}/hx\"\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin/arm64\n      - version_constraint: Version == \"v0.3.5\"\n        asset: hx-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.4.0\"\n        asset: hx-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hx-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arch-go/arch-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arch-go\n    repo_name: arch-go\n    description: Architecture checks for Go projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: arch-go_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: arch-go_{{.Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - \"https://github.com/arch-go/arch-go/.github/workflows/ci.yml@refs/heads/main\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/arch-go/arch-go/releases/download/{{.Version}}/arch-go_{{.Version}}_checksums.txt-keyless.sig\n              - --certificate\n              - https://github.com/arch-go/arch-go/releases/download/{{.Version}}/arch-go_{{.Version}}_checksums.txt-keyless.pem\n        overrides:\n          - goos: windows\n            format: zip\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/arch-go/arch-go/.github/workflows/ci.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/arch-go/arch-go/releases/download/{{.Version}}/{{.Asset}}-keyless.sig\n            - --certificate\n            - https://github.com/arch-go/arch-go/releases/download/{{.Version}}/{{.Asset}}-keyless.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arduino/arduino-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arduino\n    repo_name: arduino-cli\n    description: Arduino command line tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1-alpha.preview\")\n        no_asset: true\n      - version_constraint: Version == \"0.4.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20190805-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.5.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20190905-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.6.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20191024-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.7.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20191220-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20191231-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.7.2\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200109-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200214-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.9.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200226-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200416-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.11.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200625-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.12.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200824-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.12.1\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200826-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.13.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20200914-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: Version == \"0.14.0\"\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-20201210-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.28.0\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.31.0\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.34.2\")\n        asset: arduino-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: arduino-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{trimV .Version}}-checksums.txt\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arduino/arduino-language-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arduino\n    repo_name: arduino-language-server\n    description: An Arduino Language Server based on Clangd to Arduino code autocompletion\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: arduino-language-server_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: arduino-language-server_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-checksums.txt\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/argoproj/argo-cd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: argoproj\n    repo_name: argo-cd\n    description: Declarative continuous deployment for Kubernetes\n    asset: argocd-{{.OS}}-{{.Arch}}\n    format: raw\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: cli_checksums.txt\n      algorithm: sha256\n    files:\n      - name: argocd\n    slsa_provenance:\n      type: github_release\n      asset: argocd-cli.intoto.jsonl\n    version_constraint: semver(\">= 2.7.0-rc1\")\n    version_overrides:\n      - version_constraint: semver(\">= 2.5.0-rc3\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: argocd-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.5.0-rc1\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.4.15\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: argocd-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.4.0-rc1\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.3.11\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: argocd-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.3.10\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\">= 2.3.0-rc1\")\n        slsa_provenance:\n          enabled: false\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 2.2.15\")\n        slsa_provenance:\n          enabled: false\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: argocd-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 1.4.3\")\n        slsa_provenance:\n          enabled: false\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 1.4.3\")\n        slsa_provenance:\n          enabled: false\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/argoproj/argo-rollouts/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: argoproj\n    repo_name: argo-rollouts\n    description: Progressive Delivery for Kubernetes\n    files:\n      - name: kubectl-argo-rollouts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.7\")\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.1\")\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= 1.3.3\")\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: argo-rollouts-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: argo-rollouts-checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubectl-argo-rollouts-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: argo-rollouts-checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: argo-rollouts.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/argoproj/argo-workflows/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: argoproj\n    repo_name: argo-workflows\n    rosetta2: true\n    asset: argo-{{.OS}}-{{.Arch}}.gz\n    description: Argo Worfkflows CLI. Workflow engine for Kubernetes\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    overrides:\n      - goos: windows\n        asset: argo-{{.OS}}-{{.Arch}}.exe.gz\n    files:\n      - name: argo\n        src: argo-{{.OS}}-{{.Arch}}\n    version_constraint: semver(\">= 3.4.4\")\n    checksum:\n      type: github_release\n      asset: argo-workflows-cli-checksums.txt\n      algorithm: sha256\n      # TODO enable cosign https://github.com/argoproj/argo-workflows/discussions/12828\n      # cosign:\n      #   opts:\n      #     - --certificate-identity-regexp\n      #     - \"https://github\\\\.com/argoproj/argo-workflows/\\\\.github/workflows/release\\\\.yaml@.*\"\n      #     - --certificate-oidc-issuer\n      #     - \"https://token.actions.githubusercontent.com\"\n      #     - --signature\n      #     - https://github.com/argoproj/argo-workflows/releases/download/{{.Version}}/argo-workflows-cli-checksums.sig\n      #     - --key\n      #     - https://github.com/argoproj/argo-workflows/releases/download/{{.Version}}/argo-workflows-cosign.pub\n    version_overrides:\n      - version_constraint: \"true\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/argoproj-labs/argocd-autopilot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: argoproj-labs\n    repo_name: argocd-autopilot\n    description: Argo-CD Autopilot\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: argocd-autopilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: argocd-autopilot\n            src: argocd-autopilot-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: argocd-autopilot-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.7\")\n        asset: argocd-autopilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: argocd-autopilot\n            src: argocd-autopilot-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: argocd-autopilot-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: argocd-autopilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: argocd-autopilot\n            src: argocd-autopilot-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: argocd-autopilot-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/argoproj-labs/argocd-image-updater/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: argoproj-labs\n    repo_name: argocd-image-updater\n    description: Automatic container image update for Argo CD\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.1\"\n        asset: argocd-image-updater_{{.Version}}_{{.OS}}-{{.Arch}}.1-linux_amd64\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.3\")\n        asset: argocd-image-updater_{{.Version}}_{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: argocd-image-updater-{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          windows: win64\n        checksum:\n          type: github_release\n          asset: release-{{.Version}}.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: argocd-image-updater-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ariga/atlas/community/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: ariga/atlas/community\n    type: http\n    repo_owner: ariga\n    repo_name: atlas\n    url: https://release.ariga.io/atlas/atlas-community-{{.OS}}-{{.Arch}}-{{.Version}}\n    description: A modern tool for managing database schemas (Community Edition)\n    link: https://atlasgo.io/community-edition\n    format: raw\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: atlas\n    checksum:\n      type: http\n      url: https://release.ariga.io/atlas/atlas-community-{{.OS}}-{{.Arch}}-{{.Version}}.sha256\n      file_format: raw\n      algorithm: sha256\n    version_constraint: semver(\">= 0.22.0\")\n    # https://github.com/ariga/atlas/issues/3296#issuecomment-2574924728\n    # > Old Versions of Atlas\n    # > As part of our Supported Version Policy mentioned above, binaries for versions that were published more than 6 months ago will be removed from the CDN and Docker Hub.\n    version_overrides:\n      - version_constraint: semver(\"< 0.21.0\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ariga/atlas/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: ariga\n    repo_name: atlas\n    url: https://release.ariga.io/atlas/atlas-{{.OS}}-{{.Arch}}-{{.Version}}\n    description: A modern tool for managing database schemas\n    format: raw\n    windows_arm_emulation: true\n    supported_envs:\n      - darwin\n      - linux\n      - windows\n    checksum:\n      type: http\n      url: https://release.ariga.io/atlas/atlas-{{.OS}}-{{.Arch}}-{{.Version}}.sha256\n      file_format: raw\n      algorithm: sha256\n    overrides:\n      - goos: windows\n        checksum:\n          type: http\n          url: https://release.ariga.io/atlas/atlas-{{.OS}}-{{.Arch}}-{{.Version}}.exe.sha256\n          file_format: raw\n          algorithm: sha256\n    version_constraint: semver(\">= 0.22.0\")\n    # https://github.com/ariga/atlas/issues/3296#issuecomment-2574924728\n    # > Old Versions of Atlas\n    # > As part of our Supported Version Policy mentioned above, binaries for versions that were published more than 6 months ago will be removed from the CDN and Docker Hub.\n    version_overrides:\n      - version_constraint: semver(\"< 0.21.0\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aristocratos/btop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aristocratos\n    repo_name: btop\n    description: A monitor of resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.7\")\n        asset: btop-{{trimV .Version}}-{{.OS}}-armel.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: btop-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.0.16\")\n        asset: btop-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.0.24\")\n        asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n      - version_constraint: Version == \"v1.1.0\"\n        asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.1.1\"\n        asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-monterey.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.1.2\"\n        asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: bin/btop\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: btop-{{trimV .Version}}-{{.Arch}}-{{.OS}}-monterey.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.2.13\")\n        asset: btop-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: btop/bin/btop\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: btop-{{.Arch}}-{{.OS}}-monterey.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.2.13\"\n        asset: btop-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: btop/bin/btop\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: btop-{{.Arch}}-{{.OS}}-ventura.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.4.5\")\n        asset: btop-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: btop/bin/btop\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: btop-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tbz\n        files:\n          - name: btop\n            src: btop/bin/btop\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arl/gitmux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arl\n    repo_name: gitmux\n    description: Git in your tmux status bar\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.4\")\n        asset: gitmux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.7.10\")\n        asset: gitmux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: gitmux_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arrow2nd/nekome/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arrow2nd\n    repo_name: nekome\n    description: TUI な Twitter クライアント\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: nekome_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: nekome_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arrow2nd/nimotsu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arrow2nd\n    repo_name: nimotsu\n    description: CLI tool to tracking packages in Japan\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: nimotsu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.3\")\n        asset: nimotsu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: nimotsu_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/artempyanykh/marksman/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: artempyanykh\n    repo_name: marksman\n    description: Write Markdown with code assist and intelligence in the comfort of your favourite editor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2022-03-26\")\n        asset: zeta-note-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2023-04-12\")\n        asset: marksman-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: marksman\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: marksman-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n          - goos: darwin\n            asset: marksman-{{.OS}}\n          - goos: windows\n            asset: marksman\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/artemsalimov/jenkins-job-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: artemsalimov\n    repo_name: jenkins-job-cli\n    aliases:\n      - name: gocruncher/jenkins-job-cli\n    description: \"Jenkins-job-CLI - Runs Jenkins job from the Command Line\"\n    files:\n      - name: jj\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.0\"\n        asset: jenkins-job-ctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: jbuilder-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: jenkins-job-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arttor/helmify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arttor\n    repo_name: helmify\n    description: Creates Helm chart from Kubernetes yaml\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.0\"\n        asset: helmify-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: helmify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: helmify_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/arxanas/git-branchless/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: arxanas\n    repo_name: git-branchless\n    description: High-velocity, monorepo-scale workflow for Git\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.10\") || Version in [\"v0.4.0\", \"v0.6.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.10.0\"\n        asset: git-branchless-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        asset: git-branchless-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/asciidoctor/asciidoctor-reveal.js/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: asciidoctor\n    repo_name: asciidoctor-reveal.js\n    description: \"A reveal.js converter for Asciidoctor and Asciidoctor.js. Write your slides in AsciiDoc\"\n    files:\n      - name: asciidoctor-revealjs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: asciidoctor-revealjs-{{.OS}}\n        format: raw\n        files:\n          - name: asciidoctor-revealjs\n            src: asciidoctor-reveal.js\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/asciimoo/wuzz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: asciimoo\n    repo_name: wuzz\n    description: Interactive cli tool for HTTP inspection\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wuzz_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/asciinema/agg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: asciinema\n    repo_name: agg\n    description: asciinema gif generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: agg-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/asciinema/asciinema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: asciinema\n    repo_name: asciinema\n    description: Terminal session recorder, streamer and player\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 3.0.0\")\n        error_message: \"asciinema v3.0.0 or later is required\"\n      - version_constraint: \"true\"\n        asset: asciinema-{{.Arch}}-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/assetnote/surf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: assetnote\n    repo_name: surf\n    description: Escalate your SSRF vulnerabilities on Modern Cloud Environments. `surf` allows you to filter a list of hosts, returning a list of viable SSRF candidates\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: surf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: surf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ast-grep/ast-grep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ast-grep\n    repo_name: ast-grep\n    description: A CLI tool for code structural search, lint and rewriting. Written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.6\")\n        asset: sg-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: sg\n      - version_constraint: semver(\"<= 0.13.2\")\n        asset: sg-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        files:\n          - name: sg\n      - version_constraint: Version == \"0.14.0\"\n        asset: sg-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n        files:\n          - name: sg\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: sg-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        files:\n          - name: sg\n      - version_constraint: \"true\"\n        asset: app-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: sg\n          - name: ast-grep\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/astefanutti/kubebox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: astefanutti\n    repo_name: kubebox\n    description: Terminal and Web console for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: kubebox-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: kubebox-{{.OS}}\n        format: raw\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubebox-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/astral-sh/ruff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: astral-sh\n    repo_name: ruff\n    description: An extremely fast Python linter and code formatter, written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.246\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: ruff-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.10\")\n        asset: ruff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: ruff-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ruff\n            src: \"{{.AssetWithoutExt}}/ruff\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: ruff\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ruff-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ruff\n            src: \"{{.AssetWithoutExt}}/ruff\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: ruff\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: astral-sh/ruff/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/astral-sh/rye/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: astral-sh\n    repo_name: rye\n    aliases:\n      - name: mitsuhiko/rye\n    description: a Hassle-Free Python Experience\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: rye-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: rye\n            src: rye-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: raw\n            asset: rye-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: rye-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: rye\n            src: rye-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: raw\n            asset: rye-{{.Arch}}-{{.OS}}\n      - version_constraint: \"true\"\n        asset: rye-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: rye\n            src: rye-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: raw\n            asset: rye-{{.Arch}}-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/astral-sh/ty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: astral-sh\n    repo_name: ty\n    description: An extremely fast Python type checker and language server, written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ty-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ty\n            src: ty-{{.Arch}}-{{.OS}}/ty\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: ty\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/astral-sh/uv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: astral-sh\n    repo_name: uv\n    description: An extremely fast Python package installer and resolver, written in Rust\n    version_constraint: \"false\"\n    files:\n      - name: uv\n      - name: uvx\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.19\")\n        asset: uv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: uv\n            src: \"{{.AssetWithoutExt}}/uv\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: uv\n      - version_constraint: Version == \"0.2.20\"\n        asset: uv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: uv\n            src: \"{{.AssetWithoutExt}}/uv\"\n          - name: uvx\n            src: \"{{.AssetWithoutExt}}/uvx\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: uv\n      - version_constraint: semver(\"<= 0.9.7\") || Version == \"0.9.11\"\n        asset: uv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: uv\n            src: \"{{.AssetWithoutExt}}/uv\"\n          - name: uvx\n            src: \"{{.AssetWithoutExt}}/uvx\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: uv\n              - name: uvx\n      - version_constraint: \"true\"\n        asset: uv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: uv\n            src: \"{{.AssetWithoutExt}}/uv\"\n          - name: uvx\n            src: \"{{.AssetWithoutExt}}/uvx\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: uv\n              - name: uvx\n        github_artifact_attestations:\n          signer_workflow: astral-sh/uv/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/atc0005/send2teams/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: atc0005\n    repo_name: send2teams\n    description: Small CLI tool used to submit messages to Microsoft Teams\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.7\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.3\")\n        error_message: |\n          Versions 0.10.3 and earlier include a random string in the asset, making it difficult to predict the filename.\n          To avoid maintaining a registry with numerous overrides, we have decided not to support versions up to and including 0.10.3.\n          Please use a version later than 0.10.3.\n      - version_constraint: \"true\"\n        asset: send2teams-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: xz\n        files:\n          - name: send2teams\n            src: send2teams-{{.OS}}-{{.Arch}}\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: send2teams-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/atuinsh/atuin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: atuinsh\n    repo_name: atuin\n    description: Magical shell history\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: atuin-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 13.0.1\")\n        asset: atuin-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 14.0.1\")\n        asset: atuin-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v15.0.0\"\n        asset: atuin-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        rosetta2: true # asset for darwin/arm64 is unavailable\n        format: tar.gz\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          linux: unknown-linux-musl\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - linux/amd64 # linux/arm64 is unavailable\n          - darwin\n      - version_constraint: semver(\"<= 18.2.0\")\n        asset: atuin-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"< 18.4.0\")\n        asset: atuin-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 18.10.0\")\n        asset: atuin-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: atuinsh/atuin/.github/workflows/release.yml\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: atuin-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: atuin\n            src: \"{{.AssetWithoutExt}}/atuin\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n            files:\n              - name: atuin\n        github_artifact_attestations:\n          signer_workflow: atuinsh/atuin/.github/workflows/release.yml\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aurc/loggo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aurc\n    repo_name: loggo\n    description: A powerful terminal app for structured log streaming\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: loggo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: loggo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/auth0/auth0-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: auth0\n    repo_name: auth0-cli\n    description: Build, manage and test your Auth0 integrations from the command line\n    files:\n      - name: auth0\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: auth0-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: auth0-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.8\")\n        asset: auth0-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: auth0-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/authzed/zed/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: authzed\n    repo_name: zed\n    description: Official command-line tool for managing SpiceDB\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: zed_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.7.4\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: zed_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          # NOTE:\n          # musl version exists for linux,\n          # but it is dynamically linked to musl libc\n          # and therefore doesn't work on glibc systems\n          - goos: linux\n            asset: zed_{{trimV .Version}}_{{.OS}}_{{.Arch}}_gnu.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/autobrr/mkbrr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: autobrr\n    repo_name: mkbrr\n    description: mkbrr is a tool to create, modify and inspect torrent files. Fast\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mkbrr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: mkbrr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/amazon-ec2-instance-selector/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aws\n    repo_name: amazon-ec2-instance-selector\n    description: A CLI tool and go library which recommends instance types based on resource criteria like vcpus and memory\n    files:\n      - name: ec2-instance-selector\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.0\"\n        asset: ec2-instance-selector-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= 0.8.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: ec2-instance-selector-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= 2.0.2\")\n        asset: ec2-instance-selector-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: ec2-instance-selector-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/amazon-ec2-spot-interrupter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aws\n    repo_name: amazon-ec2-spot-interrupter\n    description: The ec2-spot-interrupter is a simple CLI tool that triggers Amazon EC2 Spot Interruption Notifications and Rebalance Recommendations\n    files:\n      - name: ec2-spot-interrupter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: ec2-spot-interrupter_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ec2-spot-interrupter_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: ec2-spot-interrupter_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/amazon-ecs-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: aws\n    repo_name: amazon-ecs-cli\n    description: The Amazon ECS CLI enables users to run their applications on ECS/Fargate using the Docker Compose file format, quickly provision resources, push/pull images in ECR, and monitor running applications on ECS/Fargate\n    format: raw\n    url: https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-{{.OS}}-{{.Arch}}-{{.Version}}\n    supported_envs:\n      - darwin\n      - linux\n    rosetta2: true\n    files:\n      - name: ecs-cli\n    checksum:\n      type: http\n      algorithm: md5\n      url: https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-{{.OS}}-{{.Arch}}-{{.Version}}.md5\n    version_constraint: semver(\">= 1.20.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.0\")\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/aws-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: aws\n    repo_name: aws-cli\n    description: The AWS Command Line Interface (AWS CLI) is a unified tool that provides a consistent interface for interacting with all parts of Amazon Web Services\n    version_source: github_tag\n    url: https://awscli.amazonaws.com/awscli-exe-{{.OS}}-{{.Arch}}-{{.Version}}.zip\n    overrides:\n      - goos: darwin\n        url: https://awscli.amazonaws.com/AWSCLIV2-{{.Version}}.{{.Format}}\n        format: pkg\n        files:\n          - name: aws\n            src: aws-cli.pkg/Payload/aws-cli/aws\n          - name: aws_completer\n            src: aws-cli.pkg/Payload/aws-cli/aws_completer\n    files:\n      - name: aws\n        src: aws/dist/aws\n      - name: aws_completer\n        src: aws/dist/aws_completer\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/aws-sam-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aws\n    repo_name: aws-sam-cli\n    description: CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM\n    files:\n      - name: sam\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.65.0\")\n        asset: aws-sam-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: sam\n            src: dist/sam\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.103.0\")\n        asset: aws-sam-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: sam\n            src: dist/sam\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            format: pkg\n            files:\n              - name: sam\n                src: aws-sam-cli.pkg/Payload/aws-sam-cli/sam\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: aws-sam-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: sam\n            src: dist/sam\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            format: pkg\n            files:\n              - name: sam\n                src: aws-sam-cli.pkg/Payload/aws-sam-cli/sam\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/copilot-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aws\n    repo_name: copilot-cli\n    description: The AWS Copilot CLI is a tool for developers to build, release and operate production ready containerized applications on AWS App Runner, Amazon ECS, and AWS Fargate\n    asset: copilot_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    overrides:\n      - goos: windows\n        asset: copilot-windows.exe\n    replacements:\n      darwin: macOS\n    files:\n      - name: copilot\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/eks-hybrid/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: aws\n    repo_name: eks-hybrid\n    description: Use your on-premises and edge infrastructure as nodes in EKS clusters with EKS Hybrid Nodes\n    version_source: github_tag\n    format: raw\n    url: https://hybrid-assets.eks.amazonaws.com/releases/{{.Version}}/bin/{{.OS}}/{{.Arch}}/nodeadm\n    files:\n      - name: nodeadm\n    checksum:\n      type: http\n      url: https://hybrid-assets.eks.amazonaws.com/releases/{{.Version}}/bin/{{.OS}}/{{.Arch}}/nodeadm.sha256\n      algorithm: sha256\n    supported_envs:\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws/session-manager-plugin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: aws\n    repo_name: session-manager-plugin\n    description: This plugin helps you to use the AWS Command Line Interface (AWS CLI) to start and end sessions to your managed instances Resources\n    url: https://s3.amazonaws.com/session-manager-downloads/plugin/{{.Version}}/mac/sessionmanager-bundle.zip\n    overrides:\n      - goos: darwin\n        goarch: arm64\n        url: https://s3.amazonaws.com/session-manager-downloads/plugin/{{.Version}}/mac_{{.Arch}}/sessionmanager-bundle.zip\n    files:\n      - name: session-manager-plugin\n        src: sessionmanager-bundle/bin/session-manager-plugin\n    supported_envs:\n      - darwin\n    search_words:\n      - macOS Only\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws-cloudformation/rain/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: aws-cloudformation\n    repo_name: rain\n    description: A development workflow tool for working with AWS CloudFormation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: Version == \"v0.1.1\"\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.1\"\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"dist/{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.5.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"dist/{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n      - version_constraint: semver(\"<= 1.3.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.6.0\"\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.7.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: rain-{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: rain\n            src: \"{{.AssetWithoutExt}}/rain\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/aws-containers/amazon-ecs-exec-checker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: aws-containers\n    repo_name: amazon-ecs-exec-checker\n    description: Pre-flight checks for ECS Exec\n    supported_envs:\n      - darwin\n      - linux\n    format: raw\n    path: check-ecs-exec.sh\n    files:\n      - name: check-ecs-exec\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/amazon-ecr-credential-helper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: awslabs\n    repo_name: amazon-ecr-credential-helper\n    description: Automatically gets credentials for Amazon ECR on docker push/docker pull\n    format: raw\n    url: https://amazon-ecr-credential-helper-releases.s3.us-east-2.amazonaws.com/{{trimV .Version}}/{{.OS}}-{{.Arch}}/docker-credential-ecr-login\n    supported_envs:\n      - linux\n      - darwin\n      - amd64\n    files:\n      - name: docker-credential-ecr-login\n    checksum:\n      type: http\n      algorithm: sha256\n      url: https://amazon-ecr-credential-helper-releases.s3.us-east-2.amazonaws.com/{{trimV .Version}}/{{.OS}}-{{.Arch}}/docker-credential-ecr-login.sha256\n    overrides:\n      - goos: windows\n        checksum:\n          type: http\n          algorithm: sha256\n          url: https://amazon-ecr-credential-helper-releases.s3.us-east-2.amazonaws.com/{{trimV .Version}}/{{.OS}}-{{.Arch}}/docker-credential-ecr-login.exe.sha256\n    version_constraint: semver(\">= 0.6.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.3.1\")\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/dynein/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: dynein\n    description: DynamoDB CLI written in Rust\n    files:\n      - name: dy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: dynein-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: dynein-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          linux/amd64: linux\n          linux/arm64: linux-arm\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: dynein-{{.OS}}.{{.Format}}\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/eks-auto-mode-ebs-migration-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: eks-auto-mode-ebs-migration-tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: eks-auto-mode-ebs-migration-tool_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: eks-auto-mode-ebs-migration-tool_{{trimV .Version}}_sha256_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: eks-auto-mode-ebs-migration-tool_{{.OS}}_all\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/eks-node-viewer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: eks-node-viewer\n    description: EKS Node Viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: eks-node-viewer_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: eks-node-viewer_{{.OS}}_all\n          - goos: windows\n            format: zip\n            asset: eks-node-viewer_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: eks-node-viewer_{{trimV .Version}}_sha256_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: eks-node-viewer_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: eks-node-viewer_{{.OS}}_all\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: eks-node-viewer_{{trimV .Version}}_sha256_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/git-secrets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: awslabs\n    repo_name: git-secrets\n    description: Prevents you from committing secrets and credentials into git repositories\n    supported_envs:\n      - darwin\n      - linux\n    version_source: github_tag\n    path: git-secrets\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/kubernetes-iteration-toolkit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: kubernetes-iteration-toolkit\n    version_filter: not (Version startsWith \"kit-operator-\")\n    files:\n      - name: kitctl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kitctl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/mountpoint-s3/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: awslabs\n    repo_name: mountpoint-s3\n    description: A simple, high-throughput file client for mounting an Amazon S3 bucket as a local file system\n    version_source: github_tag\n    version_prefix: mountpoint-s3-\n    version_filter: |\n      Version matches \"^mountpoint-s3-\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    url: https://s3.amazonaws.com/mountpoint-s3-release/{{.SemVer}}/{{.Arch}}/mount-s3-{{.SemVer}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - linux\n    files:\n      - name: mount-s3\n        src: bin/mount-s3\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/soci-snapshotter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: soci-snapshotter\n    version_constraint: \"false\"\n    files:\n      - name: soci\n      - name: soci-snapshotter-grpc\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: soci-snapshotter-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        files:\n          - name: soci\n          - name: soci-snapshotter-grpc\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: soci-snapshotter-{{trimV .Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        files:\n          - name: soci\n          - name: soci-snapshotter-grpc\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/ssosync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: ssosync\n    description: Populate AWS SSO directly with your G Suite users and groups using either a CLI or AWS Lambda\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0-rc.9\"\n        asset: ssosync_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ssosync_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.0-rc.8\")\n        asset: ssosync_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ssosync_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ssosync_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ssosync_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/awslabs/yesiscan/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: awslabs\n    repo_name: yesiscan\n    description: Automatic license scanning and reports\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yesiscan_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/axllent/mailpit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: axllent\n    repo_name: mailpit\n    description: An email and SMTP testing tool with API for developers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.6.15\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: mailpit-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: mailpit-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/axodotdev/cargo-dist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: axodotdev\n    repo_name: cargo-dist\n    description: shippable application packaging\n    files:\n      - name: dist\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4-prerelease.1\")\n        asset: cargo-dist-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.6-prerelease.7\")\n        asset: cargo-dist-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.0-prerelease.2\")\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.0-prerelease.2\")\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.0-prerelease.2\")\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0-prerelease.5\")\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n      - version_constraint: semver(\"<= 0.23.0\")\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-dist\n            src: \"{{.AssetWithoutExt}}/cargo-dist\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-dist\n        github_artifact_attestations:\n          signer_workflow: axodotdev/cargo-dist/.github/workflows/release.yml\n      - version_constraint: Version == \"v0.28.1-prerelease.1\"\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: dist\n            src: \"{{.AssetWithoutExt}}/dist\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: dist\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\">= 1.0.0-rc.1\")\n        asset: dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: dist\n            src: \"{{.AssetWithoutExt}}/dist\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: dist\n        github_artifact_attestations:\n          signer_workflow: axodotdev/cargo-dist/.github/workflows/release.yml\n      - version_constraint: \"true\"\n        asset: cargo-dist-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: dist\n            src: \"{{.AssetWithoutExt}}/dist\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: dist\n        github_artifact_attestations:\n          signer_workflow: axodotdev/cargo-dist/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ayoisaiah/f2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ayoisaiah\n    repo_name: f2\n    description: F2 is a cross-platform command-line tool for batch renaming files and directories quickly and safely. Written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: goname-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.9.1\")\n        asset: f2_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: f2_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/b3nj5m1n/xdg-ninja/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: b3nj5m1n\n    repo_name: xdg-ninja\n    description: A shell script which checks your $HOME for unwanted files and directories\n    supported_envs:\n      - darwin\n      - linux\n    version_source: github_tag\n    files:\n      - name: xdg-ninja\n        src: xdg-ninja-{{trimV .Version}}/xdg-ninja.sh\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/afx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: afx\n    aliases:\n      - name: b4b4r07/afx\n    description: Package manager to provide declaretive way to manage CLI commands and shell plugins as code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: afx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: afx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.25\")\n        asset: afx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: afx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: afx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: afx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: afx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: afx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/changed-objects/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: changed-objects\n    aliases:\n      - name: b4b4r07/changed-objects\n    description: Get changed objects in Git commit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: get-changed-objects_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        files:\n          - name: get-changed-objects\n        checksum:\n          type: github_release\n          asset: get-changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.1\"\n        asset: get-changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: get-changed-objects\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: get-changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.2\"\n        asset: get-changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: get-changed-objects\n        checksum:\n          type: github_release\n          asset: get-changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.11\"\n        asset: changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.16\")\n        asset: changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.7\")\n        asset: changed-objects-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: changed-objects_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: changed-objects_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/gist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: gist\n    aliases:\n      - name: b4b4r07/gist\n    asset: gist_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: A simple gist editor for CLI\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      386: i386\n      amd64: x86_64\n    version_constraint: semver(\">= 1.2.6\")\n    supported_envs:\n      - darwin\n      - linux\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n    checksum:\n      type: github_release\n      asset: gist_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/git-bump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: git-bump\n    aliases:\n      - name: b4b4r07/git-bump\n    description: Bump version (git tag) to next one with semver\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: git-bump_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: git-bump_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/github-labeler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: github-labeler\n    aliases:\n      - name: b4b4r07/github-labeler\n    rosetta2: true\n    asset: github-labeler_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Declarative way to configure GitHub labels\n    supported_envs:\n      - darwin\n      - linux/amd64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: github-labeler_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/gomi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: gomi\n    description: Replacement for UNIX rm command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: gomi_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: gomi_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gomi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.3\"\n        asset: gomi_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gomi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.1.6\")\n        asset: gomi_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gomi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gomi_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gomi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/iap_curl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: iap_curl\n    aliases:\n      - name: b4b4r07/iap_curl\n    description: A CLI that is curl wrapper for making HTTP request to IAP-protected app, more easier than curl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: iap_curl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: iap_curl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: iap_curl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: iap_curl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/stein/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: stein\n    aliases:\n      - name: b4b4r07/stein\n    description: A linter for config files with a customizable rule set\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: stein_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: stein_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: stein_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: stein_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/babarot/vtest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: babarot\n    repo_name: vtest\n    aliases:\n      - name: b4b4r07/vtest\n    description: Unix `test` command for Version comparison\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: vtest_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: vtest_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bahdotsh/mdterm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bahdotsh\n    repo_name: mdterm\n    description: A terminal-based Markdown browser\n    search_words:\n      - markdown\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mdterm-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bahdotsh/wrkflw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bahdotsh\n    repo_name: wrkflw\n    description: Validate and execute GitHub Actions workflows locally\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wrkflw-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/banzaicloud/banzai-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: banzaicloud\n    repo_name: banzai-cli\n    description: CLI for Banzai Cloud Pipeline platform\n    files:\n      - name: banzai\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.0.2-preview\", \"0.15.0\"]\n        no_asset: true\n      - version_constraint: Version == \"0.0.3\"\n        asset: banzai-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: banzai-cli_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: banzai_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: banzai_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: banzai_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: banzai_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.21.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: banzai_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: banzai_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/barnybug/cli53/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: barnybug\n    repo_name: cli53\n    description: Command line tool for Amazon Route 53\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.6.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: cli53-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.10\")\n        asset: cli53-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.19\")\n        asset: cli53-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: cli53_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.23\")\n        asset: cli53-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: cli53_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: cli53-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: cli53_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/barthr/redo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: barthr\n    repo_name: redo\n    description: Redo is the ultimate tool to create reusable functions from your history in an interactive way\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: redo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bats-core/bats-core/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: bats-core\n    repo_name: bats-core\n    description: Bash Automated Testing System\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: bats\n        src: bats-core-{{trimV .Version}}/bin/bats\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bazelbuild/bazel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bazelbuild\n    repo_name: bazel\n    description: a fast, scalable, multi-language and extensible build system\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 3.3.1\")\n        asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 5.0.0\")\n        asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: bazel-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bazelbuild/bazel-watcher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bazelbuild\n    repo_name: bazel-watcher\n    description: Tools for building Bazel targets when source files change\n    files:\n      - name: ibazel\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\") || Version in [\"v0.15.1\", \"v0.26.0\", \"v0.26.3\", \"v0.26.5\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.10\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"v0.16.0\", \"v0.21.1\"]\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.21.2\"\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.23.1\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.25.1\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"V0.25.1\"\n        version_prefix: V\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"V0.26.4\"\n        version_prefix: V\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n          - windows\n      - version_constraint: Version == \"V0.26.6\"\n        version_prefix: V\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: semver(\"<= 0.26.7\")\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: \"true\"\n        asset: ibazel_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bazelbuild/bazelisk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bazelbuild\n    repo_name: bazelisk\n    description: A user-friendly launcher for Bazel\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: bazelisk-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"v0.0.6\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: bazelisk-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: bazelisk-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"v1.7.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.1\")\n        asset: bazelisk-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: bazelisk-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bazelbuild/buildtools/buildifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: bazelbuild/buildtools/buildifier\n    type: github_release\n    repo_owner: bazelbuild\n    repo_name: buildtools\n    description: Format BUILD, BUILD.bazel and BUCK files in a standard way\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.4.3\"\n        asset: buildifier.{{.OS}}\n        format: raw\n        replacements:\n          darwin: OSX\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.25.0\"\n        asset: buildifier.{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"4.0.0\"\n        asset: buildifier-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"4.0.1\"\n        asset: buildifier-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: buildifier.{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 3.5.0\")\n        asset: buildifier.{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: buildifier\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: buildifier-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bazelbuild/buildtools/buildozer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: bazelbuild/buildtools/buildozer\n    type: github_release\n    repo_owner: bazelbuild\n    repo_name: buildtools\n    description: Buildozer is a command line tool to rewrite multiple Bazel BUILD files using standard commands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.4.3\"\n        asset: buildozer.{{.OS}}\n        format: raw\n        replacements:\n          darwin: OSX\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.25.0\"\n        asset: buildozer.{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"4.0.0\"\n        asset: buildozer-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"4.0.1\"\n        asset: buildozer-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: buildozer.{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 3.5.0\")\n        asset: buildozer.{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: buildozer\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: buildozer-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bcicen/ctop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bcicen\n    repo_name: ctop\n    description: Top-like interface for container metrics\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.1-deps\"\n        no_asset: true\n      - version_constraint: Version == \"v0.6.0\"\n        asset: ctop-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.6.1\"\n        asset: ctop-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"0.7.6\"\n        asset: ctop-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: ctop-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ctop-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bcicen/slackcat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bcicen\n    repo_name: slackcat\n    description: CLI utility to post files and command output to slack\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0\"\n        asset: slackcat-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: windows\n            asset: slackcat-{{trimV .Version}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: slackcat-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: slackcat-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/becheran/mlc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: becheran\n    repo_name: mlc\n    description: Check for broken links in markup files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.13.2\", \"v0.13.10\", \"v0.15.1\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.13.5\")\n        asset: mlc\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.14.3\")\n        asset: mlc-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.4\")\n        asset: mlc-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: mlc\n            src: builds/becheran/mlc_ci/target/{{.Arch}}-{{.OS}}/release/mlc\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            format: raw\n            asset: mlc-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: mlc-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mlc-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin/arm64\n          - windows\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/becheran/roumon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: becheran\n    repo_name: roumon\n    description: Universal goroutine monitor using pprof and termui\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.3\")\n        asset: roumon_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.2\")\n        asset: roumon_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: roumon_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: roumon_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/benbjohnson/litestream/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: benbjohnson\n    repo_name: litestream\n    description: Streaming replication for SQLite\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.3\"\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            asset: litestream-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.3.8-beta0\"\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n      - version_constraint: Version == \"v0.3.10\"\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.3.11-beta1\"\n        asset: litestream-v0.3.11-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.3.11-beta2\"\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.7\")\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: windows\n            asset: litestream-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.3.9\")\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.10-beta2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.13\")\n        asset: litestream-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: litestream-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/benchkram/bob/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: benchkram\n    repo_name: bob\n    description: Bob is a high-level build tool for multi-language projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: bob_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bengadbois/pewpew/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bengadbois\n    repo_name: pewpew\n    description: Flexible HTTP command line stress tester for websites and web services\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: pewpew\n            src: pewpew/pewpew\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bensadeh/tailspin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bensadeh\n    repo_name: tailspin\n    aliases:\n      - name: crates.io/tailspin # https://github.com/aquaproj/aqua-registry/pull/17534#issuecomment-1818510758\n    description: A log file highlighter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: tailspin_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.1.0\")\n        type: cargo\n        repo_owner: bensadeh\n        repo_name: tailspin\n        crate: tailspin\n        files:\n          - name: tspin\n      - version_constraint: Version == \"2.2.0\"\n        asset: tspin-{{.Arch}}-{{.OS}}.{{.Format}}\n        windows_arm_emulation: true\n        files:\n          - name: tspin\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: \"true\"\n        asset: tailspin-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: tspin\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bep/s3deploy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bep\n    repo_name: s3deploy\n    description: A simple tool to deploy static websites to Amazon S3 and CloudFront with Gzip and custom headers support (e.g. \"Cache-Control\")\n    asset: s3deploy_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n      - goos: darwin\n        format: pkg\n        asset: s3deploy_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n        files:\n          - name: s3deploy\n            src: Payload/s3deploy\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: s3deploy_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.11.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 2.10.1\")\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            format: pkg\n            asset: s3deploy_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n            files:\n              - name: s3deploy\n                src: Payload/s3deploy\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\">= 2.9.0\")\n      - version_constraint: semver(\">= 2.5.0\")\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        rosetta2: false\n      - version_constraint: semver(\">= 2.4.0\")\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: arm64\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: false\n      - version_constraint: semver(\">= 1.1.1\")\n        format: tar.gz\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 1.0.2\")\n        format: tar.gz\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: s3deploy_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 1.0.2\")\n        asset: s3deploy_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: s3deploy_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/betterleaks/betterleaks/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: betterleaks\n    repo_name: betterleaks\n    description: A Better Secrets Scanner built for configurability and speed\n    search_words:\n      - gitleaks\n      - secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: betterleaks_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bflad/tfproviderdocs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bflad\n    repo_name: tfproviderdocs\n    description: Terraform Provider Documentation Tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: tfproviderdocs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfproviderdocs_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tfproviderdocs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfproviderdocs_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bflad/tfproviderlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bflad\n    repo_name: tfproviderlint\n    description: Terraform Provider Lint Tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.28.1\")\n        asset: tfproviderlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfproviderlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tfproviderlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfproviderlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/binwiederhier/ntfy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: binwiederhier\n    repo_name: ntfy\n    description: Send push notifications to your phone or desktop using PUT/POST\n    asset: ntfy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: ntfy\n        src: ntfy_{{trimV .Version}}_{{.OS}}_{{.Arch}}/ntfy\n    overrides:\n      - goos: darwin\n        asset: ntfy_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        files:\n          - name: ntfy\n            src: ntfy_{{trimV .Version}}_{{.OS}}_all/ntfy\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.6.2\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.23.0\")\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n      - version_constraint: semver(\">= 1.4.4\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n        rosetta2: false\n      - version_constraint: semver(\">= 1.2.1\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        rosetta2: false\n      - version_constraint: semver(\"< 1.2.1\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/biomejs/biome/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: biomejs\n    repo_name: biome\n    description: A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP\n    version_filter: |\n      let words = [\"lsp\", \"js-api\", \"nightly\"];\n      not any(words, {Version matches #})\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"@biomejs/biome@2.0.1\"\n        no_asset: true\n      - version_constraint: semver(\"< 2.0.0\")\n        version_prefix: cli/v\n        asset: biome-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: semver(\"<= 2.3.8\")\n        version_prefix: \"@biomejs/biome@\"\n        asset: biome-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: \"true\"\n        version_prefix: \"@biomejs/biome@\"\n        asset: biome-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n        github_artifact_attestations:\n          signer_workflow: biomejs/biome/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/birdayz/kaf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: birdayz\n    repo_name: kaf\n    description: Modern CLI for Apache Kafka, written in Go\n    asset: kaf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.2.6\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.2.5\")\n        asset: kaf_.{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.2.4\")\n        asset: kaf_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\">= 0.1.44\")\n      - version_constraint: semver(\">= 0.1.43\")\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.1.6\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"< 0.1.6\")\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bitnami/charts-syncer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bitnami\n    repo_name: charts-syncer\n    aliases:\n      - name: bitnami-labs/charts-syncer\n    description: Tool for synchronizing Helm Chart repositories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: c3tsyncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: c3tsyncer\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: charts-syncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: charts-syncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: charts-syncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.20.1\")\n        asset: charts-syncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: charts-syncer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bitnami-labs/sealed-secrets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bitnami-labs\n    repo_name: sealed-secrets\n    description: A Kubernetes controller and tool for one-way encrypted Secrets\n    files:\n      - name: kubeseal\n    version_filter: |\n      not (Version startsWith \"helm-\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.0.1\", \"v0.1.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: ksonnet-seal-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: kubeseal-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: kubeseal-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: windows\n            asset: kubeseal\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.3\"\n        asset: kubeseal-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubeseal\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: kubeseal-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: windows\n            asset: kubeseal\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.17.0\"\n        asset: sealed-secrets_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sealed-secrets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.17.3\")\n        asset: kubeseal-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sealed-secrets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.17.5\")\n        asset: kubeseal-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sealed-secrets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubeseal-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sealed-secrets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/bitnami-labs/sealed-secrets/releases/download/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/bitnami-labs/sealed-secrets/releases/download/{{.Version}}/sealed-secrets_{{trimV .Version}}_checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bitwarden/clients/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bitwarden\n    repo_name: clients\n    asset: bw-{{.OS}}-{{.SemVer}}.zip\n    version_prefix: cli-v\n    files:\n      - name: bw\n    description: Bitwarden CLI\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2025.5.0\")\n        checksum:\n          type: github_release\n          asset: bw-{{.OS}}-sha256-{{.SemVer}}.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bitwarden/sdk-sm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bitwarden\n    repo_name: sdk-sm\n    description: Bitwarden Secrets Manager\n    version_prefix: bws-v\n    search_words:\n      - secret manager\n    files:\n      - name: bws\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"bws-v0.2.1\", \"bws-v0.3.0\"]\n        asset: bws-{{.Arch}}-{{.OS}}-{{.SemVer}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: bws-sha256-checksums-{{.SemVer}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bws-{{.Arch}}-{{.OS}}-{{.SemVer}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: bws-sha256-checksums-{{.SemVer}}.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bjesus/pipet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bjesus\n    repo_name: pipet\n    description: a swiss-army tool for scraping and extracting data from online assets, made for hackers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pipet-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: pipet\n            src: pipet-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/blacknon/hwatch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: blacknon\n    repo_name: hwatch\n    description: A modern alternative to the watch command, records the differences in execution results and can check this differences at after\n    supported_envs:\n      - darwin\n      - linux/amd64\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n    version_constraint: semver(\">= 0.3.1\")\n    asset: hwatch-{{.Version}}.{{.Arch}}-{{.OS}}.tar.gz\n    files:\n      - name: hwatch\n        src: bin/hwatch\n    version_overrides:\n      - version_constraint: semver(\"= 0.3.0\")\n        asset: hwatch_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n        replacements:\n          amd64: amd64\n          darwin: darwin\n          linux: linux\n        files:\n          - name: hwatch\n            src: hwatch/hwatch\n      - version_constraint: semver(\"= 0.2.1\") || semver(\"= 0.1.6\")\n        supported_envs: []\n      - version_constraint: semver(\"= 0.1.0\")\n        asset: hwatch_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        replacements:\n          amd64: amd64\n          darwin: darwin\n          linux: linux\n        files:\n          - name: hwatch\n            src: hwatch_{{.Version}}_{{.OS}}_{{.Arch}}/hwatch\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: hwatch_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        replacements:\n          amd64: amd64\n          darwin: darwin\n          linux: linux\n        files:\n          - name: hwatch\n            src: hwatch\n      - version_constraint: semver(\"< 0.3.1\")\n        asset: hwatch_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        replacements:\n          amd64: amd64\n          darwin: darwin\n          linux: linux\n        files:\n          - name: hwatch\n            src: hwatch/hwatch\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/blender/blender/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: blender\n    repo_name: blender\n    description: Blender is a free and open-source 3D computer graphics software\n    version_source: github_tag\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://download.blender.org/release/Blender{{(semver .Version).Major}}.{{(semver .Version).Minor}}/blender-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - windows\n          - darwin/arm64\n        files:\n          - name: blender\n            src: blender-{{trimV .Version}}-{{.OS}}-{{.Arch}}/blender\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: blender\n                src: blender-{{trimV .Version}}-{{.OS}}-{{.Arch}}/blender.exe\n          - goos: darwin\n            format: dmg\n            files:\n              - name: blender\n                src: Blender.app/Contents/MacOS/Blender\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/block/goose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: block\n    repo_name: goose\n    description: \"an open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 1.0.0\")\n        error_message: |\n          Please use a version later than v1.0.\n      - version_constraint: semver(\"<= 1.25.0\")\n        asset: goose-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: goose-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n        github_artifact_attestations:\n          signer_workflow: block/goose/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/blopker/codebook/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: blopker\n    repo_name: codebook\n    description: Spell Checker for Code\n    files:\n      - name: codebook-lsp\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.11\")\n        asset: codebook-lsp-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: codebook-lsp-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bloznelis/typioca/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bloznelis\n    repo_name: typioca\n    description: Cozy typing speed tester in terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: typioca-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: typioca-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/blst-security/cherrybomb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: blst-security\n    repo_name: cherrybomb\n    description: Stop half-done APIs! Cherrybomb is a CLI tool that helps you avoid undefined user behaviour by auditing your API specifications, validating them and running API security tests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: cherrybomb_{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: cherrybomb_{{.OS}}_gnu\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: darwin\n            asset: cherrybomb_{{.OS}}_{{.Arch}}\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: cherrybomb_{{.OS}}_gnu\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: darwin\n            asset: cherrybomb_{{.OS}}_{{.Arch}}\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.0.1\"\n        asset: cherrybomb\n        format: raw\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: cherrybomb_{{.OS}}_gnu\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: darwin\n            asset: cherrybomb_{{.OS}}_{{.Arch}}\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bmf-san/ggc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bmf-san\n    repo_name: ggc\n    description: A modern Git CLI tool with both traditional command-line and interactive incremental-search UI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: ggc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ggc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bodaay/HuggingFaceModelDownloader/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bodaay\n    repo_name: HuggingFaceModelDownloader\n    description: Simple go utility to download HuggingFace Models and Datasets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: hfdownloader_{{.OS}}_{{.Arch}}_{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: hfdownloader\n      - version_constraint: \"true\"\n        asset: hfdownloader_{{.OS}}_{{.Arch}}_{{.Version}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: hfdownloader\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bojand/ghz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bojand\n    repo_name: ghz\n    asset: ghz-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Simple gRPC benchmarking and load testing tool\n    replacements:\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: ghz-{{.OS}}-{{.Arch}}.{{.Format}}.sha256\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bomctl/bomctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bomctl\n    repo_name: bomctl\n    description: Format agnostic SBOM tooling\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: bomctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bomctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - \"https://github.com/bomctl/bomctl/.github/workflows/goreleaser.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/bomctl/bomctl/releases/download/{{.Version}}/bomctl_{{trimV .Version}}_checksums.txt-keyless.sig\n              - --certificate\n              - https://github.com/bomctl/bomctl/releases/download/{{.Version}}/bomctl_{{trimV .Version}}_checksums.txt-keyless.pem\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: bomctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bomctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - \"https://github.com/bomctl/bomctl/.github/workflows/goreleaser.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/bomctl/bomctl/releases/download/{{.Version}}/bomctl_{{trimV .Version}}_checksums.txt-keyless.sig\n              - --certificate\n              - https://github.com/bomctl/bomctl/releases/download/{{.Version}}/bomctl_{{trimV .Version}}_checksums.txt-keyless.pem\n        github_artifact_attestations:\n          signer_workflow: bomctl/bomctl/.github/workflows/goreleaser.yml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bonnefoa/kubectl-fzf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bonnefoa\n    repo_name: kubectl-fzf\n    asset: kubectl-fzf_{{.OS}}_{{.Arch}}.tar.gz\n    description: A fast kubectl autocompletion with fzf\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    files:\n      - name: kubectl-fzf-server\n      - name: kubectl-fzf-completion\n    checksum:\n      type: github_release\n      asset: kubectl-fzf_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bootandy/dust/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bootandy\n    repo_name: dust\n    description: A more intuitive version of du in rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.1\", \"v0.4.0\", \"v0.4.1.1\", \"v0.7.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.4.0.1\"\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dust\n            src: \"{{.AssetWithoutExt}}/dust\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dust\n            src: \"{{.AssetWithoutExt}}/dust\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dust-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dust\n            src: \"{{.AssetWithoutExt}}/dust\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/borgbackup/borg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: borgbackup\n    repo_name: borg\n    description: Deduplicating archiver with compression and authenticated encryption\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.28.0\", \"0.28.1\", \"0.30.1\"] || semver(\">= 1.2.0-a2, <= 1.2.0-a5\")\n        no_asset: true\n      - version_constraint: Version in [\"1.0.1\", \"1.1.15b1\"]\n        asset: borg-{{.OS}}64\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"1.0.3\"\n        asset: borg-{{.OS}}64\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"0.26.1\", \"0.27.0\"] || semver(\"<= 1.2.0b3\")\n        asset: borg-{{.OS}}64\n        format: raw\n        replacements:\n          darwin: macosx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.0\") || Version == \"1.3.0a1\"\n        asset: borg-{{.OS}}64\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"1.2.7\", \"1.2.8\", \"1.2.9\"]\n        asset: borg-{{.OS}}64\n        format: raw\n        replacements:\n          linux: linuxnewer\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.6\") || semver(\">= 2.0.0a2, <= 2.0.0-b1\") || Version in [\"2.0.0b2\", \"2.0.0b3\", \"2.0.0b6\", \"2.0.0b7\"]\n        asset: borg-{{.OS}}64\n        format: raw\n        replacements:\n          linux: linuxnew\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"2.0.0b4\"\n        asset: borg-{{.OS}}64\n        format: raw\n        replacements:\n          linux: linuxnew\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"2.0.0b5\"\n        asset: borg-{{.OS}}{{.Arch}}\n        format: raw\n        replacements:\n          linux: linuxnew\n          darwin: macos\n          amd64: \"64\"\n          arm64: -arm\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.0-rc1\") || Version == \"2.0.0b8\"\n        asset: borg-{{.OS}}\n        format: raw\n        replacements:\n          linux: linux-glibc236\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"2.0.0b12\", \"2.0.0b13\", \"2.0.0b14\", \"2.0.0b19\"]\n        asset: borg-{{.OS}}-glibc236\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.4.1\") || semver(\">= 2.0.0b10, <= 2.0.0b18\") || Version == \"2.0.0b9\"\n        asset: borg-{{.OS}}\n        format: raw\n        replacements:\n          linux: linux-glibc236\n          darwin: macos1012\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.2\") || Version == \"2.0.0b19\"\n        asset: borg-{{.OS}}-{{.Arch}}-gh\n        format: raw\n        replacements:\n          linux: linux-glibc235\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: macos-13\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              darwin: macos-14\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.4.3\")\n        asset: borg-{{.OS}}-{{.Arch}}-gh\n        format: raw\n        replacements:\n          linux: linux-glibc235\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: macos-13\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              darwin: macos-14\n        supported_envs:\n          - linux\n          - darwin\n        github_artifact_attestations:\n          signer_workflow: borgbackup/borg/.github/workflows/ci.yml\n      - version_constraint: \"true\"\n        asset: borg-{{.OS}}-{{.Arch}}-gh\n        format: raw\n        replacements:\n          linux: linux-glibc235\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: macos-15\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              darwin: macos-15\n        supported_envs:\n          - linux\n          - darwin\n        github_artifact_attestations:\n          signer_workflow: borgbackup/borg/.github/workflows/ci.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/boyter/scc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: boyter\n    repo_name: scc\n    description: \"Sloc, Cloc and Code: scc is a very fast accurate code counter with complexity calculations and COCOMO estimates written in pure Go\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v\"\n        no_asset: true\n      - version_constraint: Version == \"untagged-928286b8064e2cf6dd35\"\n        asset: \"scc-1.3.0-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows\n          linux: unknown-linux\n        supported_envs:\n          - amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v1.0.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.1.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: scc-1.0.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.9.0\")\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.10.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: scc-1.0.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.11.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.12.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: scc-1.0.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.13.0\")\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v3.0.0\"\n        asset: scc-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n      - version_constraint: Version == \"v3.1.0\"\n        asset: scc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: scc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/boz/kail/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: boz\n    repo_name: kail\n    description: kubernetes log viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.17.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.15.1\"\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kail_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kail_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.5\")\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kail_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kail_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: kail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.16.1\")\n        asset: kail_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: kail_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/br0xen/boltbrowser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: br0xen\n    repo_name: boltbrowser\n    description: A CLI Browser for BoltDB Files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: boltbrowser.{{.OS}}64\n        format: raw\n        replacements:\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: boltbrowser.linuxarm\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/breml/tfreveal/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: breml\n    repo_name: tfreveal\n    description: tfreveal shows a Terraform plan with all the secret (sensitive) values revealed\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfreveal_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tfreveal_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bridgecrewio/checkov/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bridgecrewio\n    repo_name: checkov\n    description: Prevent cloud misconfigurations and find vulnerabilities during build-time in infrastructure as code, container images and open source packages with Checkov by Bridgecrew\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"2.3.321\"\n        asset: checkov_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n      - version_constraint: Version == \"2.3.340\"\n        no_asset: true\n      - version_constraint: Version == \"2.5.15\"\n        asset: checkov_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"3.2.317\"\n        asset: checkov_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"3.2.322\"\n        asset: checkov_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 2.3.314\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.3.318\")\n        asset: checkov_{{.OS}}_{{.Version}}\n        format: raw\n        complete_windows_ext: false\n        files:\n          - name: checkov\n            src: dist/checkov\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.3.334\")\n        asset: checkov_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.2.51\")\n        asset: checkov_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n      - version_constraint: \"true\"\n        asset: checkov_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: checkov\n            src: dist/checkov\n        replacements:\n          amd64: X86_64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bridgecrewio/yor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bridgecrewio\n    repo_name: yor\n    asset: yor_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Extensible auto-tagger for your IaC files. The ultimate way to link entities in the cloud back to the codified resource which created it\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: yor_{{.Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/brigadecore/brigade/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: brigadecore\n    repo_name: brigade\n    format: raw\n    asset: brig-{{.OS}}-{{.Arch}}\n    description: Brigade CLI. Event-driven scripting for Kubernetes\n    files:\n      - name: brig\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bronze1man/yaml2json/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bronze1man\n    repo_name: yaml2json\n    description: a command line tool convert from yaml to json\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: yaml2json_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: yaml2json_{{.OS}}_{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/brumhard/krewfile/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: brumhard\n    repo_name: krewfile\n    description: Declarative krew plugin management\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.1\")\n        type: go_install\n      - version_constraint: \"true\"\n        asset: krewfile_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: krewfile_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: darwin\n            asset: krewfile_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/budimanjojo/talhelper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: budimanjojo\n    repo_name: talhelper\n    description: A tool to help creating Talos kubernetes cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.4\")\n        asset: talhelper_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: talhelper_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bufbuild/buf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bufbuild\n    repo_name: buf\n    description: The best way of working with Protocol Buffers\n    files:\n      - name: buf\n      - name: protoc-gen-buf-breaking\n      - name: protoc-gen-buf-lint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.41.0\")\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.42.0\"\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.45.0\")\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.53.0\")\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n          minisign:\n            type: github_release\n            asset: sha256.txt.minisig\n            public_key: RWQ/i9xseZwBVE7pEniCNjlNOeeyp4BQgdZDLQcAohxEAH5Uj5DEKjv6\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"< 1.36.0\")\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n          minisign:\n            type: github_release\n            asset: sha256.txt.minisig\n            public_key: RWQ/i9xseZwBVE7pEniCNjlNOeeyp4BQgdZDLQcAohxEAH5Uj5DEKjv6\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: raw\n            asset: buf-{{.OS}}-{{.Arch}}\n      - version_constraint: \"true\"\n        asset: buf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: buf\n            src: buf/bin/buf\n          - name: protoc-gen-buf-breaking\n            src: buf/bin/protoc-gen-buf-breaking\n          - name: protoc-gen-buf-lint\n            src: buf/bin/protoc-gen-buf-lint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sha256.txt\n          algorithm: sha256\n          minisign:\n            type: github_release\n            asset: sha256.txt.minisig\n            public_key: RWQ/i9xseZwBVE7pEniCNjlNOeeyp4BQgdZDLQcAohxEAH5Uj5DEKjv6\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bufbuild/connect-go/protoc-gen-connect-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: bufbuild/connect-go/protoc-gen-connect-go\n    repo_owner: bufbuild\n    repo_name: connect-go\n    description: A better gRPC\n    path: github.com/bufbuild/connect-go/cmd/protoc-gen-connect-go\n    files:\n      - name: protoc-gen-connect-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bufbuild/protoc-gen-validate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bufbuild\n    repo_name: protoc-gen-validate\n    description: \"Protocol Buffer Validation - Being replaced by github.com/bufbuild/protovalidate\"\n    files:\n      - name: protoc-gen-validate\n      - name: protoc-gen-validate-cpp\n      - name: protoc-gen-validate-go\n      - name: protoc-gen-validate-java\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.13\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: protoc-gen-validate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: protoc-gen-validate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: protoc-gen-validate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: protoc-gen-validate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: protoc-gen-validate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: protoc-gen-validate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/buildkite/agent/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: buildkite\n    repo_name: agent\n    description: The Buildkite Agent is an open-source toolkit written in Golang for securely running build jobs on any device or network\n    asset: buildkite-agent-{{.OS}}-{{.Arch}}-{{.Version|trimV}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: buildkite-agent\n    supported_envs:\n      - linux\n      - darwin\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/buildkite/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: buildkite\n    repo_name: cli\n    description: A command line interface for Buildkite\n    files:\n      - name: bk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: bk-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.2.0\"\n        asset: cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v2.0.0\"\n        asset: cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: Version == \"v3.0.0-beta.20240202\"\n        asset: bk_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n      - version_constraint: Version == \"v3.0.0-beta.20240326\"\n        asset: bk_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n      - version_constraint: Version == \"v3.0.0-beta.20240418\"\n        asset: \"{{.Version}}_{{.OS}}_{{.Arch}}\"\n        format: raw\n      - version_constraint: \"true\"\n        asset: bk_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: bk\n            src: \"{{.AssetWithoutExt}}/bk\"\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: bk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: bk\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/buildpacks/pack/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: buildpacks\n    repo_name: pack\n    description: CLI for building apps using Cloud Native Buildpacks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: pack-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.0.3\"\n        asset: pack-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.4\"\n        asset: pack-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.5\"\n        asset: pack-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: pack-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.1\")\n        asset: pack-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: pack-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.24.1\")\n        asset: pack-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: pack-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pack-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: pack-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: pack-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/busser/murmur/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: busser\n    repo_name: murmur\n    description: Pass secrets as environment variables to a process\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: whisper_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        # https://github.com/busser/murmur#changes-from-v04-to-v05\n        files:\n          - name: whisper\n      - version_constraint: \"true\"\n        asset: murmur_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/busser/tfautomv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: busser\n    repo_name: tfautomv\n    description: Generate Terraform moved blocks automatically for painless refactoring\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: tfautomv_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: tfautomv_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tfautomv_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/busser/tftree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: busser\n    repo_name: tftree\n    description: Display your Terraform module call stack in your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: tftree_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tftree_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bvaisvil/zenith/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bvaisvil\n    repo_name: zenith\n    description: \"Zenith - sort of like top or htop but with zoom-able charts, CPU, GPU, network, and disk usage\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.6\"\n        asset: \"{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          darwin: MacOS\n        files:\n          - name: zenith\n            src: \"{{.AssetWithoutExt}}/zenith\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: \"{{.OS}}.{{.Format}}\"\n            files:\n              - name: zenith\n                src: macos/zenith\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.13.1\"\n        asset: zenith.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.14.0\"\n        asset: zenith.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.14.1\"\n        asset: zenith.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: zenith\n                src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: zenith.{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.5\")\n        asset: zenith.{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: MacOS\n        overrides:\n          - goos: linux\n            format: tgz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: zenith.{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: MacOS\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: zenith.{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: MacOS\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: zenith.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: MacOS\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: zenith.{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: zenith.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: zenith.{{.Arch}}_{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: zenith-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: Linux-gnu\n          - goos: linux\n            goarch: arm64\n            asset: zenith-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n            replacements:\n              linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bytecodealliance/wasm-pkg-tools/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bytecodealliance\n    repo_name: wasm-pkg-tools\n    files:\n      - name: wkg\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.7.0\", \"v0.7.1\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: wkg-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bytecodealliance/wasm-tools/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bytecodealliance\n    repo_name: wasm-tools\n    description: CLI and Rust libraries for low-level manipulation of WebAssembly modules\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.60\")\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        version_prefix: wasm-tools-\n        files:\n          - name: wasm-tools\n            src: \"{{.AssetWithoutExt}}/wasm-tools\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n      - version_constraint: semver(\"<= 1.202.0\")\n        asset: wasm-tools-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: wasm-tools\n            src: \"{{.AssetWithoutExt}}/wasm-tools\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.239.0\")\n        asset: wasm-tools-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: wasm-tools\n            src: \"{{.AssetWithoutExt}}/wasm-tools\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n      - version_constraint: \"true\"\n        asset: wasm-tools-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: wasm-tools\n            src: \"{{.AssetWithoutExt}}/wasm-tools\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n        github_artifact_attestations:\n          signer_workflow: bytecodealliance/wasm-tools/.github/workflows/publish.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bytecodealliance/wasmtime/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: bytecodealliance\n    repo_name: wasmtime\n    description: A lightweight WebAssembly runtime that is fast, secure, and standards-compliant\n    files:\n      - name: wasmtime\n        src: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}/wasmtime\n    version_filter: not (Version == \"dev\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.34.1\"\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"cranelift-v0.60.0\"\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.36.0\")\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 21.0.2\")\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n      - version_constraint: semver(\"<= 25.0.3\")\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 28.0.0\")\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: wasmtime-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        github_artifact_attestations:\n          signer_workflow: bytecodealliance/wasmtime/.github/workflows/publish-artifacts.yml\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/bytecodealliance/wrpc/wit-bindgen-wrpc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: bytecodealliance/wrpc/wit-bindgen-wrpc\n    type: github_release\n    repo_owner: bytecodealliance\n    repo_name: wrpc\n    description: Wasm component-native RPC framework\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wit-bindgen-wrpc-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/c-bata/kube-prompt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: c-bata\n    repo_name: kube-prompt\n    description: An interactive kubernetes client featuring auto-complete\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: kube-prompt_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kube-prompt_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/c1982/bomberman/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: c1982\n    repo_name: bomberman\n    description: SMTP Performance and Load Test Tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: bomberman_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/caarlos0/fork-cleaner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: caarlos0\n    repo_name: fork-cleaner\n    description: Quickly clean up unused forks on your github account\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.0\"\n        asset: fork-cleaner_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{.OS}}_{{.Arch}}.tar.gz.checksums\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v2.1.0\"\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.2.0\"\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.2.1\"\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.8\")\n        asset: fork-cleaner_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: fork-cleaner_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: fork-cleaner_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.3\")\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.3.1\")\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fork-cleaner_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/caarlos0/fork-cleaner/\\\\.github/workflows/build\\\\.yml@.*\"\n        overrides:\n          - goos: darwin\n            asset: fork-cleaner_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: caarlos0/fork-cleaner/.github/workflows/build.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/caarlos0/mdtree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: caarlos0\n    repo_name: mdtree\n    description: Convert markdown lists into ASCII trees\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mdtree_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: mdtree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: mdtree_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/caarlos0/svu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: caarlos0\n    repo_name: svu\n    description: semantic version utility\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.8.0\"\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: svu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.7.0\")\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: svu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.1.0\")\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/caarlos0/svu/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: darwin\n            asset: svu_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n      - version_constraint: semver(\"<= 3.2.1\")\n        asset: svu_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/caarlos0/svu/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.sig\n        github_artifact_attestations:\n          signer_workflow: caarlos0/svu/.github/workflows/release.yml\n        overrides:\n          - goos: darwin\n            asset: svu_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.2.4\")\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/caarlos0/svu/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/caarlos0/svu/releases/download/{{.Version}}/checksums.txt.sig\n        github_artifact_attestations:\n          signer_workflow: caarlos0/svu/.github/workflows/release.yml\n        overrides:\n          - goos: darwin\n            asset: svu_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: svu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/caarlos0/svu/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        github_artifact_attestations:\n          signer_workflow: caarlos0/svu/.github/workflows/release.yml\n        overrides:\n          - goos: darwin\n            asset: svu_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/caddyserver/caddy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: caddyserver\n    repo_name: caddy\n    description: Fast, multi-platform web server with automatic HTTPS\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.5.2\")\n        asset: caddy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: caddy_{{trimV .Version}}_checksums.txt\n          algorithm: sha512\n      - version_constraint: \"true\"\n        asset: caddy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: caddy_{{trimV .Version}}_checksums.txt\n          algorithm: sha512\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/caddyserver/caddy/\\\\.github/workflows/release\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/caddyserver/caddy/releases/download/v{{trimV .Version}}/caddy_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/caddyserver/caddy/releases/download/v{{trimV .Version}}/caddy_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/callumalpass/mdbase-lsp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: callumalpass\n    repo_name: mdbase-lsp\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mdbase-lsp-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win32\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cameron-martin/bazel-lsp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cameron-martin\n    repo_name: bazel-lsp\n    description: A language server implementation for Bazel\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.0\"\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.3.1\"\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bazel-lsp-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cantino/mcfly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cantino\n    repo_name: mcfly\n    description: Fly through your shell history. Great Scott\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.6\")\n        asset: mcfly-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: mcfly-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.5\")\n        asset: mcfly-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mcfly-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carapace-sh/carapace-bin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carapace-sh\n    repo_name: carapace-bin\n    description: A multi-shell completion binary\n    files:\n      - name: carapace\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: carapace\n            src: carapace-bin\n        checksum:\n          type: github_release\n          asset: carapace-bin_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: carapace\n            src: carapace-bin\n        checksum:\n          type: github_release\n          asset: carapace-bin_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.9\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: carapace\n            src: carapace-bin\n        checksum:\n          type: github_release\n          asset: carapace-bin_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.4.11\")\n        asset: example_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.18.1\")\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: carapace-bin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.7\")\n        asset: carapace-bin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: carapace-bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: carapace-bin_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cargo-bins/cargo-binstall/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cargo-bins\n    repo_name: cargo-binstall\n    description: Binary installation for rust projects\n    version_filter: Version matches \"^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"install-cargo-binstall-1.0.0\", \"v1.4.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: cargo-binstall-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.3.0\"\n        asset: cargo-binstall-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: cargo-binstall-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.18.1\")\n        asset: cargo-binstall-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n      - version_constraint: \"true\"\n        asset: cargo-binstall-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carthage-software/mago/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carthage-software\n    repo_name: mago\n    description: Mago is a toolchain for PHP that aims to provide a set of tools to help developers write better code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.12\"\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.13.0\"\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"1.2.0\"\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-gnu\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        supported_envs:\n          - windows\n      - version_constraint: Version == \"1.2.1\"\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 0.0.11\")\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86-64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: linux-gnu\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 1.5.0\")\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: mago-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        files:\n          - name: mago\n            src: mago-{{.Version}}-{{.Arch}}-{{.OS}}/mago\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: carthage-software/mago/.github/workflows/cd.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/imgpkg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: imgpkg\n    aliases:\n      - name: vmware-tanzu/carvel-imgpkg\n    description: Store application configuration files in Docker/OCI registries\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.17.0\"\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.27.1\"\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.27.3\"\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.35.0\"\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.27.0\")\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 0.40.0\")\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: imgpkg-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/carvel-dev/imgpkg/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/carvel-dev/imgpkg/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/carvel-dev/imgpkg/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/kapp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: kapp\n    aliases:\n      - name: vmware-tanzu/carvel-kapp\n    description: kapp is a simple deployment tool focused on the concept of \"Kubernetes application\" — a set of resources with the same label\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.34.0\")\n        asset: kapp-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.38.0\")\n        asset: kapp-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.45.0\")\n        asset: kapp-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"< 0.60.0\")\n        asset: kapp-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kapp-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/carvel-dev/kapp/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/carvel-dev/kapp/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/carvel-dev/kapp/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/kbld/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: kbld\n    aliases:\n      - name: vmware-tanzu/carvel-kbld\n    description: kbld seamlessly incorporates image building and image pushing into your development and deployment workflows\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.31.0\"\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v0.32.0\"\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.32.2\"\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.30.0\")\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 0.39.0\")\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kbld-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/carvel-dev/kbld/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/carvel-dev/kbld/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/carvel-dev/kbld/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/kwt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: kwt\n    aliases:\n      - name: vmware-tanzu/carvel-kwt\n    description: Kubernetes Workstation Tools CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.6\")\n        asset: kwt-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kwt-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/vendir/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: vendir\n    aliases:\n      - name: vmware-tanzu/carvel-vendir\n    description: Easy way to vendor portions of git repos, github releases, helm charts, docker image contents, etc. declaratively\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: vendir-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: vendir-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.38.0\")\n        asset: vendir-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: vendir-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/carvel-dev/vendir/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/carvel-dev/vendir/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/carvel-dev/vendir/releases/download/{{.Version}}/checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/carvel-dev/ytt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: carvel-dev\n    repo_name: ytt\n    aliases:\n      - name: vmware-tanzu/carvel-ytt\n    description: YAML templating tool that works on YAML structure instead of text\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.31.0\")\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.37.0\")\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.46.6\")\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ytt-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/carvel-dev/ytt/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/carvel-dev/ytt/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/carvel-dev/ytt/releases/download/{{.Version}}/checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/casey/just/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: casey\n    repo_name: just\n    description: Just a command runner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.25\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: just\n            src: \"{{.AssetWithoutExt}}/just\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.2.28\"\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.2.32\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.3\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.4\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.10.5\"\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.10.6\"\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/arm64\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.25.0\")\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"1.25.1\"\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: just-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/catenacyber/perfsprint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: catenacyber\n    repo_name: perfsprint\n    description: Golang linter to use strconv\n    version_source: github_tag\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cbroglie/mustache/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cbroglie\n    repo_name: mustache\n    description: The mustache template language in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.0.0\", \"v1.1.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v1.0.1\"\n        asset: mustache_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: mustache_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.1\")\n        asset: mustache_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: mustache_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mustache_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: mustache_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cea-hpc/sshproxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cea-hpc\n    repo_name: sshproxy\n    asset: sshproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Proxy SSH connections on a gateway\n    replacements:\n      amd64: x86_64\n      linux: Linux\n    supported_envs:\n      - linux/amd64\n    files:\n      - name: sshproxy\n        src: sshproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}/sshproxy\n      - name: sshproxy-dumpd\n        src: sshproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}/sshproxy-dumpd\n      - name: sshproxy-replay\n        src: sshproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}/sshproxy-replay\n      - name: sshproxyctl\n        src: sshproxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}/sshproxyctl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cert-manager/cert-manager/cmctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: cert-manager/cert-manager/cmctl\n    repo_owner: cert-manager\n    repo_name: cert-manager\n    aliases:\n      - name: jetstack/cert-manager/cmctl\n    description: cmctl is a CLI tool that can help you to manage cert-manager resources inside your cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.14.4\")\n        asset: cmctl-{{.OS}}-{{.Arch}}.tar.gz\n        files:\n          - name: cmctl\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: \"true\"\n        error_message: |\n          Please use the package cert-manager/cmctl instead.\n          The code of cmctl was moved from cert-manager/cert-manager to cert-manager/cmctl.\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cert-manager/cmctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cert-manager\n    repo_name: cmctl\n    description: the command line utility that makes cert-manager'ing easier\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cmctl_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.cosign.bundle\n            opts:\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --certificate-identity\n              - https://github.com/cert-manager/cmctl/.github/workflows/release.yaml@refs/tags/{{.Version}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chaaz/versio/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chaaz\n    repo_name: versio\n    description: A version number manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.5\")\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.5.2\"\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: windows\n            asset: versio.exe\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v0.5.3\"\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.6\")\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: versio__{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chainguard-dev/apko/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chainguard-dev\n    repo_name: apko\n    description: Build OCI images from APK packages directly without Dockerfile\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: apko\n            src: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}/apko\n        format: tar.gz\n        supported_envs:\n          - linux\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.crt\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: apko\n            src: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}/apko\n        supported_envs:\n          - linux\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.crt\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: apko\n            src: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}/apko\n        supported_envs:\n          - linux\n          - darwin\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.crt\n      - version_constraint: \"true\"\n        asset: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: apko\n            src: apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}/apko\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/apko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/apko/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/apko/releases/download/{{.Version}}/checksums.txt.crt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chainguard-dev/melange/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chainguard-dev\n    repo_name: melange\n    description: build APKs from source code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: melange\n            src: melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}/melange\n        supported_envs:\n          - linux\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/melange/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/melange/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/checksums.txt.crt\n      - version_constraint: \"true\"\n        asset: melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: melange\n            src: melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}/melange\n        supported_envs:\n          - linux\n          - darwin\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/chainguard-dev/melange/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.sig\n            - --certificate\n            - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/melange_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}.crt\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/chainguard-dev/melange/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/chainguard-dev/melange/releases/download/{{.Version}}/checksums.txt.crt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chainloop-dev/chainloop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chainloop-dev\n    repo_name: chainloop\n    description: SDLC evidence store and policy engine for your Software Supply Chain attestations, SBOMs, VEX, SARIF, QA reports, and more\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-rc.3\")\n        asset: chainloop-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/chainloop-dev/chainloop/releases/download/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/chainloop-dev/chainloop/releases/download/{{.Version}}/checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: chainloop-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/chainloop-dev/chainloop/releases/download/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/chainloop-dev/chainloop/releases/download/{{.Version}}/checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chanzuckerberg/fogg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chanzuckerberg\n    repo_name: fogg\n    description: Manage Infrastructure as Code with less pain\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.67.1\", \"v0.68.0\", \"v0.92.2\"]\n        no_asset: true\n      - version_constraint: Version in [\"v0.58.5-pre+0939c083\", \"v0.67.2\"]\n        asset: fogg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fogg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.58.5\"\n        asset: fogg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: fogg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.42.3\")\n        asset: fogg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fogg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.58.3\")\n        asset: fogg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: fogg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: fogg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fogg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chaqchase/lla/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chaqchase\n    repo_name: lla\n    aliases:\n      - name: triyanox/lla\n    description: A modern alternative to ls\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.1\"\n        asset: lla-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.2.7\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: lla-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/charm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: charm\n    asset: charm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: The Charm Tool and Library\n    replacements:\n      amd64: x86_64\n      linux: Linux\n      darwin: Darwin\n      windows: Windows\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.12.5\")\n    # 0.12.5: linux was capitalized. linux => Linux\n    version_overrides:\n      - version_constraint: semver(\"< 0.12.5\")\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/crush/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: crush\n    description: The glamourous AI coding agent for your favourite terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: crush_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: crush\n            src: crush_{{trimV .Version}}_{{.OS}}_{{.Arch}}/crush\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/charmbracelet/crush/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/charmbracelet/meta/.github/workflows/goreleaser.yml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/charmbracelet/crush/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: crush_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: crush\n            src: crush_{{trimV .Version}}_{{.OS}}_{{.Arch}}/crush\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/charmbracelet/meta/.github/workflows/goreleaser.yml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/freeze/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: freeze\n    description: Generate images of code and terminal output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: freeze_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: freeze\n            src: \"{{.AssetWithoutExt}}/freeze\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/charmbracelet/meta/\\\\.github/workflows/goreleaser\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/charmbracelet/freeze/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/charmbracelet/freeze/releases/download/{{.Version}}/checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/glow/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: glow\n    description: Render markdown on the CLI, with pizzazz\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v1.5.0\"\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v1.5.1\"\n        asset: glow_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: glow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: glow\n            src: \"{{.AssetWithoutExt}}/glow\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/gum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: gum\n    description: A tool for glamorous shell scripts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: gum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: gum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: gum\n            src: \"{{.AssetWithoutExt}}/gum\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/mods/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: mods\n    description: AI on the command line\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: mods_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: mods_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: mods_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        complete_windows_ext: false\n        files:\n          - name: mods\n            src: \"{{.AssetWithoutExt}}/mods\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/skate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: skate\n    description: A personal key value store\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: skate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: skate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.2\"\n        asset: skate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: skate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: skate\n            src: \"{{.AssetWithoutExt}}/skate\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/charmbracelet/vhs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: charmbracelet\n    repo_name: vhs\n    description: Your CLI home video recorder\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: vhs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.7.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.7.1\"\n        asset: vhs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: vhs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: vhs\n            src: \"{{.AssetWithoutExt}}/vhs\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chatwork/kibertas/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chatwork\n    repo_name: kibertas\n    description: kibertas is a CLI tool for achieving end-to-end (E2E) testing of Kubernetes environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.4\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kibertas_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kibertas_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/che-incubator/chectl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: che-incubator\n    repo_name: chectl\n    description: CLI to manage Eclipse Che server and workspaces\n    rosetta2: true\n    asset: chectl-{{.OS}}-{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux/amd64\n    replacements:\n      amd64: x64\n    files:\n      - name: chectl\n        src: chectl/bin/chectl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cheat/cheat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cheat\n    repo_name: cheat\n    description: cheat allows you to create and view interactive cheatsheets on the command-line. It was designed to help remind *nix system administrators of options for commands that they use frequently, but not frequently enough to remember\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: cheat-{{.OS}}-{{.Arch}}.gz\n    files:\n      - name: cheat\n        src: cheat-{{.OS}}-{{.Arch}}\n    overrides:\n      - goos: windows\n        asset: cheat-windows-amd64.exe.zip\n    version_constraint: semver(\">= 4.2.4\")\n    version_overrides:\n      - version_constraint: \"true\"\n        overrides:\n          - goos: windows\n            asset: cheat-windows-amd64.exe.zip\n            files:\n              - name: cheat\n                src: dist/cheat-windows-amd64.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/checkmake/checkmake/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: checkmake\n    repo_name: checkmake\n    aliases:\n      - name: mrtazz/checkmake\n    description: Linter/analyzer for Makefiles\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.2.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: checkmake-{{.Version}}.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: checkmake-{{.Version}}.{{.OS}}.{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chenjiandongx/kubectl-images/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chenjiandongx\n    repo_name: kubectl-images\n    description: Show container images used in the cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.3\"\n        asset: kubectl-images_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.3.4\"\n        asset: kubectl-images_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: kubectl-images_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubectl-images_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-images_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chevdor/tera-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chevdor\n    repo_name: tera-cli\n    description: A command line utility on top of the tera templating engine. Takes json|yaml|toml as input and can merge ENV in. You may see it as envsubst on steroid\n    files:\n      - name: tera\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: tera-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        files:\n          - name: tera\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: tera-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        files:\n          - name: tera\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tera-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        files:\n          - name: tera\n        checksum:\n          type: github_release\n          asset: tera-cli-{{.Arch}}-{{.OS}}.sha512\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chime/mani-diffy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chime\n    repo_name: mani-diffy\n    description: mani-diffy walks a hierarchy of Argo CD Application templates, renders Kubernetes manifests from the input templates, and posts the rendered files back for the user to review and validate\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mani-diffy\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: mani-diffy-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chmln/handlr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chmln\n    repo_name: handlr\n    asset: handlr\n    format: raw\n    description: A better xdg-utils\n    supported_envs:\n      - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chmln/sd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chmln\n    repo_name: sd\n    description: Intuitive find & replace CLI (sed alternative)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.5\")\n        asset: sd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: sd\n            src: \"{{.Arch}}-{{.OS}}/sd\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v0.7.2\"\n        asset: sd-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: sd\n            src: b/{{.Arch}}-{{.OS}}/release/sd\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"<= 0.7.4\")\n        asset: sd-{{trimV .Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        windows_arm_emulation: true\n        format: zip\n        files:\n          - name: sd\n            src: b/{{.Arch}}-{{.OS}}/release/sd\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"v0.7.5\"\n        asset: sd.{{trimV .Version}}-.{{.Arch}}-{{.OS}}.{{.Format}}\n        windows_arm_emulation: true\n        format: zip\n        files:\n          - name: sd\n            src: b/{{.Arch}}-{{.OS}}/release/sd\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: Version == \"v0.7.6\"\n        asset: sd-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: sd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: sd\n            src: sd-{{.Version}}-{{.Arch}}-{{.OS}}/sd\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chmouel/snazy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chmouel\n    repo_name: snazy\n    description: a snazzy json log viewer (with one z)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.51.2\")\n        asset: snazy_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        overrides:\n          - goos: darwin\n            asset: snazy_{{.Version}}_{{.OS}}_all.{{.Format}}\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.52.0\")\n        asset: snazy_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: snazy_{{.Version}}_{{.OS}}_all.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.52.16\")\n        error_message: There is no GitHub Releases\n      - version_constraint: \"true\"\n        asset: snazy-v{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: snazy-v{{.Version}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: snazy-v{{.Version}}-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/chriswalz/bit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: chriswalz\n    repo_name: bit\n    description: Bit is a modern Git CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.14\")\n        asset: bit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: bit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: bit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: bit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: bit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cilium/cilium-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cilium\n    repo_name: cilium-cli\n    description: CLI to install, manage & troubleshoot Kubernetes clusters running Cilium\n    files:\n      - name: cilium\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        asset: cilium-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.8.6\")\n        asset: cilium-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: cilium-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.16.4\")\n        asset: cilium-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: cilium-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cilium/hubble/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cilium\n    repo_name: hubble\n    description: \"Hubble - Network, Service & Security Observability for Kubernetes using eBPF\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.1\"\n        asset: hubble-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: hubble-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: hubble-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: hubble-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: hubble-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: hubble-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.16.2\")\n        asset: hubble-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hubble-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: hubble-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hubble-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cirruslabs/cirrus-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cirruslabs\n    repo_name: cirrus-cli\n    description: CLI for executing Cirrus tasks locally and in any CI\n    files:\n      - name: cirrus\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.94.0\")\n        error_message: Please use v0.94.0 or later\n      - version_constraint: Version in [\"v0.140.1\", \"v0.140.2\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: cirrus-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: cirrus_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cirruslabs/tart/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cirruslabs\n    repo_name: tart\n    description: macOS and Linux VMs on Apple Silicon to use in CI and other automations\n    asset: tart.tar.gz\n    files:\n      - name: tart\n        src: tart.app/Contents/MacOS/tart\n    checksum:\n      type: github_release\n      asset: tart_{{.Version}}_checksums.txt\n      algorithm: sha256\n    supported_envs:\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/citrusframework/yaks/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: citrusframework\n    repo_name: yaks\n    asset: yaks-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: YAKS is a platform to enable Cloud Native BDD testing on Kubernetes\n    replacements:\n      amd64: 64bit\n      darwin: mac\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/civo/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: civo\n    repo_name: cli\n    description: Our Command Line Interface (CLI) for interacting with your Civo resources\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: civo-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: civo\n    checksum:\n      type: github_release\n      asset: civo-{{trimV .Version}}-checksums.sha256\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ck-zhang/reddix/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ck-zhang\n    repo_name: reddix\n    description: Reddix – Reddit, refined for the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: reddix-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: reddix\n            src: \"{{.AssetWithoutExt}}/reddix\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: reddix\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/clamoriniere/crd-to-markdown/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: clamoriniere\n    repo_name: crd-to-markdown\n    description: util to generate a markdown file from a Kubernetes CRD go struct definition\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: crd-to-markdown_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cli/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cli\n    repo_name: cli\n    description: GitHub’s official command line tool\n    files:\n      - name: gh\n        src: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}/bin/gh\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: raw\n            asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n            checksum:\n              enabled: false\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.5\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.20.0\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.23.0\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.27.0\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 2.50.0\")\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gh\n                src: bin/gh.exe\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: gh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: cli/cli/.github/workflows/deployment.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/climech/grit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: climech\n    repo_name: grit\n    asset: grit_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Multitree-based personal task manager\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: grit\n        src: grit_{{.Version}}_{{.OS}}_{{.Arch}}/grit\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/clog-tool/clog-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: clog-tool\n    repo_name: clog-cli\n    description: Generate beautiful changelogs from your Git commit history\n    rosetta2: true\n    asset: clog-{{.Version}}-{{.Arch}}-{{.OS}}.tar.gz\n    replacements:\n      arm64: aarch64\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: clog\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/clok/sm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: clok\n    repo_name: sm\n    asset: sm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: AWS Secrets Manager CLI Tool\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: sm\n        src: sm_{{trimV .Version}}_{{.OS}}_{{.Arch}}/sm\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloud-hypervisor/cloud-hypervisor/ch-remote/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloud-hypervisor/cloud-hypervisor/ch-remote\n    type: github_release\n    repo_owner: cloud-hypervisor\n    repo_name: cloud-hypervisor\n    description: Remotely control a cloud-hypervisor VMM\n    format: raw\n    supported_envs:\n      - linux\n    files:\n      - name: ch-remote\n    asset: ch-remote-static\n    overrides:\n      - goarch: arm64\n        asset: ch-remote-static-aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloud-hypervisor/cloud-hypervisor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloud-hypervisor\n    repo_name: cloud-hypervisor\n    description: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM hypervisor and Microsoft Hypervisor (MSHV)\n    format: raw\n    supported_envs:\n      - linux\n    asset: cloud-hypervisor-static\n    overrides:\n      - goarch: arm64\n        asset: cloud-hypervisor-static-aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloud66-oss/copper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloud66-oss\n    repo_name: copper\n    description: A configuration file validator for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.7\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_{{.Arch}}_{{.Version}}\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cf-terraforming/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudflare\n    repo_name: cf-terraforming\n    description: A command line utility to facilitate terraforming your existing Cloudflare resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.19.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: cf-terraforming_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: cf-terraforming_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssl\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    aliases:\n      - name: cloudflare/cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: cfssl_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: cfssl_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssl_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssl_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssl-bundle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssl-bundle\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"1.2.0\"\n        asset: cfssl-bundle_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssl-bundle_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssl-bundle_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssl-certinfo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssl-certinfo\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"1.2.0\"\n        asset: cfssl-certinfo_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssl-certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssl-certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssl-newkey/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssl-newkey\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"1.2.0\"\n        asset: cfssl-newkey_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssl-newkey_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssl-newkey_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssl-scan/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssl-scan\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"1.2.0\"\n        asset: cfssl-scan_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssl-scan_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssl-scan_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/cfssljson/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/cfssljson\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: cfssljson_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: cfssljson_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cfssljson_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/mkbundle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/mkbundle\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: mkbundle_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: mkbundle_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mkbundle_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cfssl/multirootca/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudflare/cfssl/multirootca\n    type: github_release\n    repo_owner: cloudflare\n    repo_name: cfssl\n    description: \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"1.2.0\"\n        asset: multirootca_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.3\")\n        asset: multirootca_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: multirootca_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cfssl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/cloudflared/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudflare\n    repo_name: cloudflared\n    description: Cloudflare Tunnel client\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2021.3.4\")\n        error_message: This version is too old. Please update.\n      - version_constraint: Version in [\"2021.6.0\"]\n        asset: cloudflared-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: Version == \"2021.8.0\"\n        asset: cloudflared-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: arm\n          - goos: darwin\n            format: tgz\n            asset: cloudflared-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: Version in [\"2021.8.5\", \"2021.10.2\"]\n        asset: cloudflared-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: Version == \"2022.12.0\"\n        asset: cloudflared-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: raw\n            asset: cloudflared-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2024.6.1\")\n        asset: cloudflared-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            format: tgz\n            asset: cloudflared-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: cloudflared-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            format: tgz\n            asset: cloudflared-{{.OS}}-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/gokey/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudflare\n    repo_name: gokey\n    description: A simple vaultless password manager in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gokey-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudflare/pint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudflare\n    repo_name: pint\n    description: Prometheus rule linter/validator\n    asset: pint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: pint\n        src: pint-{{.GOOS}}-{{.GOARCH}}\n    format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.31.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.16.0\")\n        replacements:\n          amd64: x86_64\n      - version_constraint: semver(\">= 0.1.5\")\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\"< 0.1.5\")\n        asset: pint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudfoundry/bosh-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudfoundry\n    repo_name: bosh-cli\n    description: The bosh CLI is the command line tool used for interacting with all things BOSH, from deployment operations to software release management\n    rosetta2: true\n    format: raw\n    supported_envs:\n      - darwin\n      - amd64\n    asset: bosh-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n    files:\n      - name: bosh\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudfoundry/credhub-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudfoundry\n    repo_name: credhub-cli\n    description: CredHub CLI provides a command line interface to interact with CredHub servers\n    asset: credhub-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n    format: tgz\n    files:\n      - name: credhub\n    supported_envs:\n      - darwin\n      - amd64\n    version_constraint: semver(\">= 2.9.21\")\n    version_overrides:\n      - version_constraint: semver(\"< 2.9.21\")\n        asset: credhub-{{.OS}}-{{.Version}}.{{.Format}}\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudfoundry/uaa-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudfoundry\n    repo_name: uaa-cli\n    description: CLI for UAA written in Go\n    files:\n      - name: uaa\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: uaa-{{.OS}}-{{.Arch}}-{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: uaa\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: uaa-{{.OS}}-{{.Arch}}-{{.Version}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: uaa\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudnative-pg/cloudnative-pg/kubectl-cnpg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: cloudnative-pg/cloudnative-pg/kubectl-cnpg\n    type: github_release\n    repo_owner: cloudnative-pg\n    repo_name: cloudnative-pg\n    description: CloudNativePG is a comprehensive platform designed to seamlessly manage PostgreSQL databases within Kubernetes environments, covering the entire operational lifecycle from initial deployment to ongoing maintenance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubectl-cnpg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: cnpg-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudposse/atmos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudposse\n    repo_name: atmos\n    description: Workflow automation tool for DevOps. Keep configuration DRY with hierarchical imports of configurations, inheritance, and WAY more. Native support for Terraform and Helmfile\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: atmos\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.10.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: atmos\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"0.14.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: atmos\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: atmos_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: atmos_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: atmos_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: atmos_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.6\")\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: atmos_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.27\")\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: atmos_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: Version == \"1.3.28\"\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: atmos_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: Version == \"v1.3.28\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.4.20\")\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: atmos_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.18.0\")\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: atmos_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: Version == \"v1.19.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: atmos_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudposse/github-commenter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudposse\n    repo_name: github-commenter\n    description: Command line utility for creating GitHub comments on Commits, Pull Request Reviews or Issues\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.11.1\", \"0.11.3\", \"0.11.4\"]\n        no_asset: true\n      - version_constraint: Version == \"0.6.0\"\n        asset: github-commenter_.{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.10.0\"\n        asset: github-commenter_{{.OS}}_{{.Arch}}-r0\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version in [\"0.11.5\"]\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"0.16.0\"\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.16.1\")\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.16.2\"\n        asset: github-commenter_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: github-commenter_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: github-commenter_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.27.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: github-commenter_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: github-commenter_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudposse/slack-notifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudposse\n    repo_name: slack-notifier\n    description: Command line utility to send messages with attachments to Slack channels via Incoming Webhooks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: slack-notifier_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.5.0\"\n        asset: slack-notifier_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"0.5.1\"\n        asset: slack-notifier_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: slack-notifier_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.0\")\n        no_asset: true\n      - version_constraint: Version == \"0.8.0\"\n        asset: slack-notifier_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: slack-notifier_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: slack-notifier_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: slack-notifier\n            src: slack-notifier_v{{.Version}}\n        checksum:\n          type: github_release\n          asset: slack-notifier_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudquery/cloudquery/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudquery\n    repo_name: cloudquery\n    description: The open source high performance data integration platform built for developers\n    asset: cloudquery_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_prefix: cli-\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.32.7\")\n        version_prefix: cli/\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          amd64: x86_64\n          windows: Windows\n      - version_constraint: semver(\">= 0.32.5\")\n        version_prefix: cli/\n        asset: cli_{{.OS}}_{{.Arch}}.zip\n        files:\n          - name: cloudquery\n            src: cli\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          amd64: x86_64\n          windows: Windows\n      - version_constraint: semver(\"< 0.32.5\")\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          amd64: x86_64\n          windows: Windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudspannerecosystem/spanner-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: cloudspannerecosystem\n    repo_name: spanner-cli\n    description: Interactive command line tool for Cloud Spanner\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudspannerecosystem/spanner-dump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: cloudspannerecosystem\n    repo_name: spanner-dump\n    description: Command line tool for exporting a Cloud Spanner database in text format\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudspannerecosystem/spool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudspannerecosystem\n    repo_name: spool\n    description: A CLI tool to manage Cloud Spanner databases for testing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: spool-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudspannerecosystem/wrench/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudspannerecosystem\n    repo_name: wrench\n    description: \"wrench - Schema management tool for Cloud Spanner -\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.9.0\"\n        no_asset: true\n      - version_constraint: Version == \"v1.1.0\"\n        asset: wrench_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.3.0\"\n        asset: wrench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: wrench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.4\")\n        asset: wrench_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.3.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: wrench_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: wrench_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: wrench-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloudspannerecosystem/yo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloudspannerecosystem\n    repo_name: yo\n    asset: yo-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: yo is a command-line tool to generate Go code for Google Cloud Spanner\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: yo\n        src: yo-{{trimV .Version}}-{{.OS}}-{{.Arch}}/yo\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloverrose/connectnew/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloverrose\n    repo_name: connectnew\n    description: |\n      Go linter checking if &connect.Request or &connect.Response are used.\n      Instead connect.NewRequest or connect.NewResponse should be used\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: connectnew_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: connectnew\n            src: connectnew_{{.OS}}_{{.Arch}}/connectnew\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: connectnew_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloverrose/mockguard/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloverrose\n    repo_name: mockguard\n    description: mockguard checks if mockgen is used in conventional filename and options\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mockguard_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: mockguard\n            src: mockguard_{{.OS}}_{{.Arch}}/mockguard\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: mockguard_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloverrose/pkgdep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloverrose\n    repo_name: pkgdep\n    description: pkgdep checks if package dependency follows rule\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pkgdep_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: pkgdep\n            src: \"pkgdep_{{.OS}}_{{.Arch}}/pkgdep\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: pkgdep_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloverrose/unusedinterface/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloverrose\n    repo_name: unusedinterface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: unusedinterface_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: unusedinterface\n            src: \"unusedinterface_{{.OS}}_{{.Arch}}/unusedinterface\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: unusedinterface_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cloverstd/tcping/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cloverstd\n    repo_name: tcping\n    description: ping over a tcp connection\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: tcping-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: tcping-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/clowdhaus/eksup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: clowdhaus\n    repo_name: eksup\n    description: EKS cluster upgrade guidance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0-alpha\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: eksup-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: eksup\n            src: \"{{.AssetWithoutExt}}/eksup\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            asset: eksup-{{.Version}}-{{.Arch}}-{{.OS}}eabihf.{{.Format}}\n            replacements:\n              arm64: arm\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: eksup-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: eksup\n            src: \"{{.AssetWithoutExt}}/eksup\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cnosuke/kushi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cnosuke\n    repo_name: kushi\n    description: Auto SSH port-fowarding agent which gets forwarding configs from URL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: kushi-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kushi-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cnrancher/autok3s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cnrancher\n    repo_name: autok3s\n    description: Run K3s Everywhere\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.7-rc2\")\n        asset: autok3s_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: autok3s_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cockroachdb/cockroach/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: cockroachdb\n    repo_name: cockroach\n    version_source: github_tag\n    description: A distributed SQL database designed for speed, scale, and survival\n    url: https://binaries.cockroachdb.com/cockroach-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tgz\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    overrides:\n      - goos: darwin\n        goarch: amd64\n        replacements:\n          darwin: darwin-10.9\n      - goos: darwin\n        goarch: arm64\n        replacements:\n          darwin: darwin-11.0\n      - goos: windows\n        format: zip\n        replacements:\n          windows: windows-6.2\n    files:\n      - name: cockroach\n        src: cockroach-{{.Version}}.{{.OS}}-{{.Arch}}/cockroach\n    checksum:\n      type: http\n      url: https://binaries.cockroachdb.com/cockroach-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}.sha256sum\n      algorithm: sha256\n    version_constraint: semver(\">= 22.2.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 22.2.0\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows/amd64\n        overrides:\n          - goos: darwin\n            replacements:\n              darwin: darwin-10.9\n          - goos: windows\n            format: zip\n            replacements:\n              windows: windows-6.2\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cococonscious/koji/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cococonscious\n    repo_name: koji\n    aliases:\n      - name: its-danny/koji\n    description: An interactive CLI for creating conventional commits\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: koji-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: koji-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: koji-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: koji\n            src: \"{{.AssetWithoutExt}}/koji\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: koji-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cocogitto/cocogitto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cocogitto\n    repo_name: cocogitto\n    description: The Conventional Commits toolbox\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 5.3.1\")\n        asset: cocogitto-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: cog\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 5.6.0\")\n        asset: cocogitto-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: cog\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"6.0.0\"\n        asset: cocogitto-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cog\n            src: \"{{.Arch}}-{{.OS}}/cog/cog\"\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            files:\n              - name: cog\n                src: \"{{.Arch}}-{{.OS}}/cog.exe/cog.exe\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 6.3.0\")\n        asset: cocogitto-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cog\n            src: \"{{.Arch}}-{{.OS}}/cog\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            files:\n              - name: cog\n                src: \"{{.Arch}}-{{.OS}}/cog.exe\"\n      - version_constraint: \"true\"\n        asset: cocogitto-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: cog\n            src: \"{{.Arch}}-{{.OS}}/cog\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            files:\n              - name: cog\n                src: \"{{.Arch}}-{{.OS}}/cog.exe\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/codeberg.org/mergiraf/mergiraf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    name: codeberg.org/mergiraf/mergiraf\n    description: A syntax-aware git merge driver for a growing collection of programming languages and file formats\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        url: https://codeberg.org/mergiraf/mergiraf/releases/download/{{.Version}}/mergiraf_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: \"true\"\n        url: https://codeberg.org/mergiraf/mergiraf/releases/download/{{.Version}}/mergiraf_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/codeclimate/test-reporter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: codeclimate\n    repo_name: test-reporter\n    description: Code Climate Test Reporter\n    format: raw\n    url: https://codeclimate.com/downloads/test-reporter/test-reporter-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: cc-test-reporter\n        src: test-reporter\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/coder/coder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: coder\n    repo_name: coder\n    description: Provision remote development environments via Terraform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: coder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: coder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: coder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: coder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.5.9\")\n        asset: coder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: coder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar\n      - version_constraint: \"true\"\n        asset: coder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: coder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/coder3101/protols/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: coder3101\n    repo_name: protols\n    description: Language Server for protocol buffers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: protols-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/codesenberg/bombardier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: codesenberg\n    repo_name: bombardier\n    description: Fast cross-platform HTTP benchmarking tool written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.5\"\n        asset: bombardier-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: bombardier-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.2.4\")\n        asset: bombardier-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bombardier-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/commercialhaskell/stack/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: commercialhaskell\n    repo_name: stack\n    description: The Haskell Tool Stack\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.0-beta\")\n        asset: stack-0.0.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.2-beta\"\n        asset: stack-0.0.2-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.3-beta\"\n        asset: stack-0.0.3-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.1.0\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.3.1\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.5.0\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: stack\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: stack\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.1.2\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: stack\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.6.0.20171022\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.6.0.20171202\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.6.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.5\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.9.3\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 2.1.0.3\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.1.3\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 2.3.1\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.5.1\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"rc/v2.7.0.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"rc/v2.7.0.3\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.7.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 2.7.5\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"rc/v2.9.0.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-2.9.0.1-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"v2.9.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"rc/v2.9.2.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-2.9.2.1-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"v2.9.3\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n      - version_constraint: Version == \"rc/v2.11.0.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-2.11.0.1-{{.OS}}-{{.Arch}}-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"v2.11.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n      - version_constraint: Version == \"rc/v2.13.0.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v2.13.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"rc/v2.15.0.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.15.3\")\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"rc/v2.15.4.1\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: stack-{{trimPrefix \"rc/\" .Version | trimV}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: stack\n            src: \"{{.AssetWithoutExt}}/stack\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/compose/transporter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: compose\n    repo_name: transporter\n    description: Sync data between persistence engines, like ETL only not stodgy\n    format: raw\n    complete_windows_ext: false\n    asset: transporter-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/comtrya/comtrya/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: comtrya\n    repo_name: comtrya\n    format: raw\n    description: Configuration Management for Localhost / dotfiles\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.3.19\")\n    asset: comtrya-{{.Arch}}-{{.OS}}\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: comtrya\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/concourse/concourse/concourse/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: concourse/concourse/concourse\n    type: github_release\n    repo_owner: concourse\n    repo_name: concourse\n    asset: concourse-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tgz\n    description: Concourse is a container-based continuous thing-doer written in Go\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: concourse\n        src: concourse/bin/concourse\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha1\"\n      file_format: regexp\n      algorithm: sha1\n      pattern:\n        checksum: ^(\\b[A-Fa-f0-9]{40}\\b)\n        file: \"^\\\\b[A-Fa-f0-9]{40}\\\\b\\\\s+(\\\\S+)$\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/concourse/concourse/fly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: concourse/concourse/fly\n    type: github_release\n    repo_owner: concourse\n    repo_name: concourse\n    asset: fly-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tgz\n    description: Concourse is a container-based continuous thing-doer written in Go\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    # TODO checksum: support sha1\n    # https://github.com/aquaproj/aqua/issues/1216\n    files:\n      - name: fly\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/connectrpc/connect-go/protoc-gen-connect-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: connectrpc/connect-go/protoc-gen-connect-go\n    search_words:\n      - bufbuild\n    type: go_install\n    repo_owner: connectrpc\n    repo_name: connect-go\n    description: Simple, reliable, interoperable. A better gRPC\n    path: connectrpc.com/connect/cmd/protoc-gen-connect-go\n    files:\n      - name: protoc-gen-connect-go\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/container-tools/spectrum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: container-tools\n    repo_name: spectrum\n    description: A lightweight super-fast container image builder\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: spectrum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"v0.3.7\", \"v0.6.44\"]\n        asset: spectrum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.6.42\")\n        asset: spectrum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: spectrum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/container2wasm/container2wasm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: container2wasm\n    repo_name: container2wasm\n    aliases:\n      - name: ktock/container2wasm\n    description: Container to WASM converter\n    files:\n      - name: c2w\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: container2wasm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containerd/containerd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containerd\n    repo_name: containerd\n    description: An open and reliable container runtime\n    files:\n      - name: containerd\n        src: bin/{{.FileName}}\n      - name: containerd-shim-runc-v2\n        src: bin/{{.FileName}}\n      - name: containerd-stress\n        src: bin/{{.FileName}}\n      - name: ctr\n        src: bin/{{.FileName}}\n    overrides:\n      - goos: windows\n        files:\n          - name: containerd\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runhcs-v1\n            src: bin/{{.FileName}}\n          - name: containerd-stress\n            src: bin/{{.FileName}}\n          - name: ctr\n            src: bin/{{.FileName}}\n    version_filter: Version matches \"^v[0-9]+.[0-9]+.[0-9]+$\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.11\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.9\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.13\")\n        asset: containerd-{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: containerd\n            src: bin/{{.FileName}}\n          - name: containerd-shim\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runc-v1\n            src: bin/{{.FileName}}\n          - name: ctr\n            src: bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.3.4\")\n        asset: containerd-{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: containerd\n            src: bin/{{.FileName}}\n          - name: containerd-shim\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runc-v1\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runc-v2\n            src: bin/{{.FileName}}\n          - name: containerd-stress\n            src: bin/{{.FileName}}\n          - name: ctr\n            src: bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.5.18\")\n        asset: containerd-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        files:\n          - name: containerd\n            src: bin/{{.FileName}}\n          - name: containerd-shim\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runc-v1\n            src: bin/{{.FileName}}\n          - name: containerd-shim-runc-v2\n            src: bin/{{.FileName}}\n          - name: ctr\n            src: bin/{{.FileName}}\n        overrides:\n          - goos: windows\n            files:\n              - name: containerd\n                src: bin/{{.FileName}}\n              - name: containerd-shim-runhcs-v1\n                src: bin/{{.FileName}}\n              - name: ctr\n                src: bin/{{.FileName}}\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: containerd-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: containerd-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        github_artifact_attestations:\n          signer_workflow: containerd/containerd/.github/workflows/release.yml\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containerd/containerd/static/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: containerd/containerd/static\n    type: github_release\n    repo_owner: containerd\n    repo_name: containerd\n    description: An open and reliable container runtime (static binary)\n    files:\n      - name: containerd\n        src: bin/{{.FileName}}\n      - name: containerd-shim-runc-v2\n        src: bin/{{.FileName}}\n      - name: containerd-stress\n        src: bin/{{.FileName}}\n      - name: ctr\n        src: bin/{{.FileName}}\n    version_filter: Version matches \"^v[0-9]+.[0-9]+.[0-9]+$\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.38\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: containerd-static-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: containerd-static-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        github_artifact_attestations:\n          signer_workflow: containerd/containerd/.github/workflows/release.yml\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containerd/fuse-overlayfs-snapshotter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containerd\n    repo_name: fuse-overlayfs-snapshotter\n    description: fuse-overlayfs plugin for rootless containerd on old Linux (not needed on modern Linux)\n    files:\n      - name: containerd-fuse-overlayfs-grpc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.2\")\n        asset: containerd-fuse-overlayfs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 2.1.4\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: containerd-fuse-overlayfs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: containerd/fuse-overlayfs-snapshotter/.github/workflows/release.yml\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containerd/nerdctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containerd\n    repo_name: nerdctl\n    description: \"contaiNERD CTL - Docker-compatible CLI for containerd, with support for Compose, Rootless, eStargz, OCIcrypt, IPFS, \"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: nerdctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: nerdctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 2.0.4\")\n        asset: nerdctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: nerdctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: containerd/nerdctl/.github/workflows/release.yml\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containerd/stargz-snapshotter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containerd\n    repo_name: stargz-snapshotter\n    description: |-\n      Fast container image distribution plugin with lazy pulling\n\n      ## How to set up\n\n      Please see:\n\n      https://github.com/containerd/stargz-snapshotter/blob/main/docs/INSTALL.md\n      https://github.com/containerd/stargz-snapshotter/blob/main/docs/rootless.md\n    files:\n      - name: containerd-stargz-grpc\n      - name: ctr-remote\n      - name: stargz-store\n      - name: stargz-store-helper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: stargz-snapshotter-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: stargz-snapshotter-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: containerd-stargz-grpc\n          - name: ctr-remote\n      - version_constraint: \"true\"\n        asset: stargz-snapshotter-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: stargz-snapshotter-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/conmon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containers\n    repo_name: conmon\n    description: An OCI container runtime monitor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.0.9\") || Version in [\"v2.1.1\", \"v2.0.29\", \"v2.0.28\", \"v2.0.21\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 2.0.17\") || Version in [\"v2.0.20\", \"v2.0.24\"]\n        asset: conmon\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.0.19\")\n        asset: conmon-{{trimV .Version}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.0.23\") || Version == \"v2.0.25\"\n        asset: conmon-{{trimV .Version}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n        files:\n          - name: conmon\n            src: result/bin/conmon\n      - version_constraint: semver(\"<= 2.0.32\") && semver(\">= 2.0.30\")\n        asset: conmon-{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n        replacements:\n          amd64: x86\n          arm64: arm\n        files:\n          - name: conmon\n            src: bin/conmon\n      - version_constraint: \"true\"\n        asset: conmon.{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/crun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containers\n    repo_name: crun\n    asset: crun-{{.Version}}-{{.OS}}-{{.Arch}}\n    format: raw\n    description: A fast and lightweight fully featured OCI runtime and C library for running containers\n    supported_envs:\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/fuse-overlayfs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containers\n    repo_name: fuse-overlayfs\n    description: FUSE implementation for overlayfs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: fuse-overlayfs-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/gvisor-tap-vsock/gvproxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: containers/gvisor-tap-vsock/gvproxy\n    type: github_release\n    repo_owner: containers\n    repo_name: gvisor-tap-vsock\n    description: A new network stack based on gVisor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.2\"\n        asset: gvproxy-{{.OS}}\n        format: raw\n        overrides:\n          - goos: darwin\n            asset: gvproxy-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.7.0\"\n        asset: gvproxy-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: gvproxy-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: gvproxy-{{.OS}}\n        format: raw\n        overrides:\n          - goos: darwin\n            asset: gvproxy-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: gvproxy-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.3\")\n        asset: gvproxy-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            asset: gvproxy-{{.OS}}-{{.Arch}}\n      - version_constraint: \"true\"\n        asset: gvproxy-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sha256sums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: gvproxy-{{.OS}}-{{.Arch}}\n          - goos: windows\n            goarch: arm64\n            asset: gvproxy-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/gvisor-tap-vsock/qemu-wrapper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: containers/gvisor-tap-vsock/qemu-wrapper\n    type: github_release\n    repo_owner: containers\n    repo_name: gvisor-tap-vsock\n    description: A new network stack based on gVisor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: qemu-wrapper\n        format: raw\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/kubernetes-mcp-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containers\n    repo_name: kubernetes-mcp-server\n    description: Model Context Protocol (MCP) server for Kubernetes and OpenShift\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubernetes-mcp-server-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containers/podlet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containers\n    repo_name: podlet\n    description: Generate Podman Quadlet files from a Podman command, compose file, or existing object\n    files:\n      - name: podlet\n        src: \"{{.AssetWithoutExt}}/podlet\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: podlet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: podlet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: podlet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: podlet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: podlet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: podlet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: podlet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            files:\n              - name: podlet\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/containrrr/shoutrrr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: containrrr\n    repo_name: shoutrrr\n    description: Notification library for gophers and their furry friends\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: shoutrrr_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: shoutrrr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: shoutrrr_{{.OS}}_{{.Arch}}v8.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: shoutrrr_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: shoutrrr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        replacements:\n          arm64: arm64v8\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: \"true\"\n        asset: shoutrrr_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: shoutrrr_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/context-labs/mactop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: context-labs\n    repo_name: mactop\n    search_words:\n      - goasitop\n    description: mactop - Apple Silicon Monitor Top written in pure Golang! Under 1,000 lines of code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: goasitop_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: goasitop\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin/arm64\n      - version_constraint: \"true\"\n        asset: mactop_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/controlplaneio/kubectl-kubesec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: controlplaneio\n    repo_name: kubectl-kubesec\n    description: Security risk analysis for Kubernetes resources\n    asset: kubectl-kubesec_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: kubectl-kubesec_checksums.txt\n      algorithm: sha256\n    files:\n      - name: kubectl-kubesec_scan\n        src: kubectl-scan\n    version_constraint: semver(\">= 1.1.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.2\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 1.0.1\")\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\"< 1.0.1\")\n        asset: kubectl-kubesec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        files:\n          - name: kubectl-kubesec_scan\n            src: scan\n        checksum:\n          type: github_release\n          asset: kubectl-kubesec_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/controlplaneio/kubesec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: controlplaneio\n    repo_name: kubesec\n    description: Security risk analysis for Kubernetes resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.9.0\")\n        asset: kubesec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kubesec_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.11.0\")\n        asset: kubesec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kubesec_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubesec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubesec_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/coreos/butane/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: coreos\n    repo_name: butane\n    description: Butane translates human-readable Butane Configs into machine-readable Ignition Configs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: fcct-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fcct\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: butane-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: butane-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/corneliusweig/ketall/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: corneliusweig\n    repo_name: ketall\n    description: Like `kubectl get all`, but get really all resources\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: ketall\n        src: ketall-{{.Arch}}-{{.OS}}\n      - name: kubectl-get_all\n        src: ketall-{{.Arch}}-{{.OS}}\n    asset: ketall-{{.Arch}}-{{.OS}}.tar.gz\n    overrides:\n      - goos: windows\n        asset: ketall-amd64-windows.zip\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/corneliusweig/rakkess/access-matrix/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: corneliusweig/rakkess/access-matrix\n    type: github_release\n    repo_owner: corneliusweig\n    repo_name: rakkess\n    description: Review Access - kubectl plugin to show an access matrix for k8s server resources\n    supported_envs:\n      - darwin\n      - amd64\n    asset: access-matrix-{{.Arch}}-{{.OS}}.tar.gz\n    overrides:\n      - goos: windows\n        asset: access-matrix-amd64-windows.zip\n    files:\n      - name: kubectl-access_matrix\n        src: access-matrix-{{.Arch}}-{{.OS}}\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/corneliusweig/rakkess/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: corneliusweig\n    repo_name: rakkess\n    description: Review Access - kubectl plugin to show an access matrix for k8s server resources\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: rakkess\n        src: rakkess-{{.Arch}}-{{.OS}}\n    asset: rakkess-{{.Arch}}-{{.OS}}.tar.gz\n    overrides:\n      - goos: windows\n        asset: rakkess-amd64-windows.zip\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/corrupt952/closest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: corrupt952\n    repo_name: closest\n    description: The command that searches the current directory or parent directories for a specific file and returns the closest path\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: closest_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: closest_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cortesi/modd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cortesi\n    repo_name: modd\n    description: A flexible developer tool that runs processes and responds to filesystem changes\n    asset: modd-{{.Version|trimV}}-{{.OS}}{{.Arch}}.{{.Format}}\n    format: tgz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: osx\n      amd64: \"64\"\n    files:\n      - name: modd\n        src: modd-{{.Version|trimV}}-{{.OS}}{{.Arch}}/modd\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cpisciotta/xcbeautify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cpisciotta\n    repo_name: xcbeautify\n    description: A little beautifier tool for xcodebuild\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.5.0-beta.1\"\n        no_asset: true\n      - version_constraint: Version == \"0.9.0\"\n        asset: xcbeautify-{{.Version}}-universal-{{.OS}}-macosx.{{.Format}}\n        format: zip\n        replacements:\n          darwin: apple\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"0.9.1\"\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            format: tar.xz\n            asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.8\")\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx10.10.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx10.14.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.7.0\")\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            format: tar.xz\n            asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.0-beta.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}-macosx.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            format: tar.xz\n            asset: xcbeautify-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crate-ci/committed/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: crate-ci\n    repo_name: committed\n    description: Nitpicking commit history since beabf39\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\") || Version == \"v0.1.22\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.8\"\n        asset: committed-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: committed-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        supported_envs:\n          - windows\n      - version_constraint: semver(\"<= 0.1.15\")\n        asset: committed-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.20\")\n        no_asset: true\n      - version_constraint: Version == \"v0.1.21\"\n        asset: committed-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: committed\n            src: \"{{.AssetWithoutExt}}/committed\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: committed-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crate-ci/typos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: crate-ci\n    repo_name: typos\n    description: Source code spell checker\n    version_filter: not (Version startsWith \"varcon-\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.13.17\"\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.0.11\")\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.17.0\")\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.22.4\")\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.22.6\")\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            format: tar.gz\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.29.7\")\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: typos-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/bat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/bat\n    type: cargo\n    repo_owner: sharkdp\n    repo_name: bat\n    description: A cat(1) clone with wings\n    crate: bat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/broot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/broot\n    type: cargo\n    repo_owner: Canop\n    repo_name: broot\n    description: A new file manager\n    link: https://dystroy.org/broot\n    crate: broot\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/cargo-deb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/cargo-deb\n    type: cargo\n    repo_owner: kornelski\n    repo_name: cargo-deb\n    description: Make Debian packages (.deb) easily with a Cargo subcommand\n    link: https://lib.rs/crates/cargo-deb\n    crate: cargo-deb\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/cargo-expand/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/cargo-expand\n    type: cargo\n    repo_owner: dtolnay\n    repo_name: cargo-expand\n    description: \"Wrapper around rustc -Zunpretty=expanded. Shows the result of macro expansion and #[derive] expansion.\"\n    crate: cargo-expand\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/cargo-run-script/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/cargo-run-script\n    type: cargo\n    repo_owner: JoshMcguigan\n    repo_name: cargo-run-script\n    description: Bringing `npm run-script` to Rust\n    crate: cargo-run-script\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/dd-rust-license-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/dd-rust-license-tool\n    type: cargo\n    repo_owner: DataDog\n    repo_name: rust-license-tool\n    description: A tool for creating the `LICENSE-3rdparty.csv` file for DataDog open-source Rust projects\n    crate: dd-rust-license-tool\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/dskkato/rjo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/rjo\n    type: cargo\n    repo_owner: dskkato\n    repo_name: rjo\n    description: A small utility to create JSON objects, written in Rust\n    crate: rjo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/eza/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  # TODO: Merge this package with eza-community/eza\n  # https://github.com/aquaproj/aqua/issues/2649\n  - name: crates.io/eza\n    type: cargo\n    repo_owner: eza-community\n    repo_name: eza\n    description: A modern replacement for ls\n    crate: eza\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/fw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/fw\n    type: cargo\n    repo_owner: brocode\n    repo_name: fw\n    description: faster workspace management\n    crate: fw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/gitu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  # TODO: Consider merging this package with altsem/gitu pkgs/altsem/gitu.\n  # https://github.com/aquaproj/aqua-registry/issues/22840\n  - name: crates.io/gitu\n    type: cargo\n    repo_owner: altsem\n    repo_name: gitu\n    description: A TUI Git client inspired by Magit\n    crate: gitu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/skim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/skim\n    type: cargo\n    repo_owner: skim-rs\n    repo_name: skim\n    description: Fuzzy Finder in rust!\n    crate: skim\n    files:\n      - name: sk\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/tfocus/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/tfocus\n    type: cargo\n    repo_owner: nwiizo\n    repo_name: tfocus\n    description: Terminal UI for Terraform workspace management\n    crate: tfocus\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crates.io/zizmor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: crates.io/zizmor\n    type: cargo\n    repo_owner: zizmorcore\n    repo_name: zizmor\n    description: Finds security issues in GitHub Actions setups\n    crate: zizmor\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crazy-max/diun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: crazy-max\n    repo_name: diun\n    description: Receive notifications when an image is updated on a Docker registry\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v4.23.0\"\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.{{.Format}}\n        format: tgz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 4.9.0\")\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 4.14.0\")\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 4.16.1\")\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 4.19.0\")\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 4.22.0\")\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: diun_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crazy-max/ftpgrab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: crazy-max\n    repo_name: ftpgrab\n    asset: ftpgrab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Grab your files periodically from a remote FTP or SFTP server easily\n    overrides:\n      - goos: windows\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crazywhalecc/static-php-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: crazywhalecc\n    repo_name: static-php-cli\n    description: Build standalone PHP binaries on Linux, macOS, FreeBSD, Windows, with PHP project together, with popular extensions included\n    files:\n      - name: spc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"2.0.0-beta2\"\n        asset: spc-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: spc\n            src: spc-{{.OS}}-{{.Arch}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"2.0-rc3\"\n        asset: spc-{{.OS}}-{{.Arch}}-bin.{{.Format}}\n        format: tgz\n        files:\n          - name: spc\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.0.0-rc6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.0-beta.2\")\n        asset: spc-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: spc\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: spc-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: spc\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spc-{{.OS}}-{{.Arch}}\n            format: raw\n            replacements:\n              amd64: x64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/create-go-app/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: create-go-app\n    repo_name: cli\n    description: Create a new production-ready project with backend, frontend and deploy automation by running one CLI command\n    asset: cgapp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: cgapp\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 4.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.7.0\")\n        asset: cgapp_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 1.6.3\")\n        asset: cgapp_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 1.0.0\")\n        asset: cgapp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"< 1.0.0\")\n        asset: cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: cgapp\n            src: cli\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: cli_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cri-o/cri-o/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: cri-o\n    repo_name: cri-o\n    description: Open Container Initiative-based implementation of Kubernetes Container Runtime Interface\n    url: https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz\n    checksum:\n      type: http\n      url: https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sha256sum\n      algorithm: sha256\n    supported_envs:\n      - linux\n    files:\n      - name: conmon\n        src: cri-o/bin/{{.FileName}}\n      - name: conmonrs\n        src: cri-o/bin/{{.FileName}}\n      - name: crictl\n        src: cri-o/bin/{{.FileName}}\n      - name: crio\n        src: cri-o/bin/{{.FileName}}\n      - name: crun\n        src: cri-o/bin/{{.FileName}}\n      - name: pinns\n        src: cri-o/bin/{{.FileName}}\n      - name: runc\n        src: cri-o/bin/{{.FileName}}\n    version_filter: Version matches \"v[0-9]+.[0-9]+.[0-9]+$\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.24.6\"\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-status\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n        overrides:\n          - goarch: arm64\n            files:\n              - name: conmon\n                src: cri-o/bin/{{.FileName}}\n              - name: crictl\n                src: cri-o/bin/{{.FileName}}\n              - name: crio\n                src: cri-o/bin/{{.FileName}}\n              - name: crio-status\n                src: cri-o/bin/{{.FileName}}\n              - name: crun\n                src: cri-o/bin/{{.FileName}}\n              - name: pinns\n                src: cri-o/bin/{{.FileName}}\n      - version_constraint: Version == \"v1.25.4\"\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-status\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n        overrides:\n          - goarch: arm64\n            files:\n              - name: conmon\n                src: cri-o/bin/{{.FileName}}\n              - name: crictl\n                src: cri-o/bin/{{.FileName}}\n              - name: crio\n                src: cri-o/bin/{{.FileName}}\n              - name: crio-status\n                src: cri-o/bin/{{.FileName}}\n              - name: crun\n                src: cri-o/bin/{{.FileName}}\n              - name: pinns\n                src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.24.5\")\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-status\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n        overrides:\n          - goarch: arm64\n            files:\n              - name: conmon\n                src: cri-o/bin/{{.FileName}}\n              - name: crictl\n                src: cri-o/bin/{{.FileName}}\n              - name: crio\n                src: cri-o/bin/{{.FileName}}\n              - name: crio-status\n                src: cri-o/bin/{{.FileName}}\n              - name: crun\n                src: cri-o/bin/{{.FileName}}\n              - name: pinns\n                src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.28.1\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/cri-o/.github/workflows/test.yml@refs/tags/{{.Version}}\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-status\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: Version == \"v1.28.2\"\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.28.8\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-crun\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-runc\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.29.0\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.29.6\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-crun\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-runc\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.29.13\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crun\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n          - name: runc\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.30.3\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n        files:\n          - name: crictl\n            src: cri-o/bin/{{.FileName}}\n          - name: crio\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmon\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-conmonrs\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-crun\n            src: cri-o/bin/{{.FileName}}\n          - name: crio-runc\n            src: cri-o/bin/{{.FileName}}\n          - name: pinns\n            src: cri-o/bin/{{.FileName}}\n      - version_constraint: semver(\"<= 1.34.1\")\n        cosign:\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --certificate\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.cert\n            - --signature\n            - https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.sig\n      - version_constraint: \"true\"\n        cosign:\n          bundle:\n            type: http\n            url: https://storage.googleapis.com/cri-o/artifacts/cri-o.{{.Arch}}.{{.Version}}.tar.gz.bundle\n          opts:\n            - --certificate-identity\n            - \"https://github.com/cri-o/packaging/.github/workflows/obs.yml@refs/heads/main\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cross-rs/cross/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cross-rs\n    repo_name: cross\n    description: “Zero setup” cross compilation and “cross testing” of Rust crates\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2-rc1\"\n        asset: cross-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.5\"\n        asset: cross-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: cross-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.16\")\n        asset: cross-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: cross-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cross-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/crossplane/crossplane/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: crossplane\n    repo_name: crossplane\n    format: raw\n    url: https://releases.crossplane.io/stable/{{.Version}}/bin/{{.OS}}_{{.Arch}}/crank\n    description: The Crossplane CLI extends kubectl with functionality to build, push, and install Crossplane packages\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cswank/kcli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cswank\n    repo_name: kcli\n    description: A kafka command line browser\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"1.4.0\", \"1.8.1\", \"1.8.2\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kcli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ctron/oidc-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ctron\n    repo_name: oidc-cli\n    description: A command line tool to work with OIDC tokens\n    files:\n      - name: oidc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: oidc-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: oidc-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        github_artifact_attestations:\n          signer_workflow: ctron/oidc-cli/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cubefs/cubefs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cubefs\n    repo_name: cubefs\n    description: cloud-native distributed storage\n    files:\n      - name: cfs-authtool\n        src: cubefs/build/bin/cfs-authtool\n      - name: cfs-bcache\n        src: cubefs/build/bin/cfs-bcache\n      - name: cfs-cli\n        src: cubefs/build/bin/cfs-cli\n      - name: cfs-client\n        src: cubefs/build/bin/cfs-client\n      - name: cfs-deploy\n        src: cubefs/build/bin/cfs-deploy\n      - name: cfs-fsck\n        src: cubefs/build/bin/cfs-fsck\n      - name: cfs-preload\n        src: cubefs/build/bin/cfs-preload\n      - name: cfs-server\n        src: cubefs/build/bin/cfs-server\n    version_filter: not (Version matches \"-(beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.4.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.5.2\")\n        asset: cubefs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: cubefs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: cfs-authtool\n            src: cubefs/build/bin/cfs-authtool\n          - name: cfs-bcache\n            src: cubefs/build/bin/cfs-bcache\n          - name: cfs-cli\n            src: cubefs/build/bin/cfs-cli\n          - name: cfs-client\n            src: cubefs/build/bin/cfs-client\n          - name: cfs-deploy\n            src: cubefs/build/bin/cfs-deploy\n          - name: cfs-fsck\n            src: cubefs/build/bin/cfs-fsck\n          - name: cfs-server\n            src: cubefs/build/bin/cfs-server\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cubicdaiya/nginx-build/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cubicdaiya\n    repo_name: nginx-build\n    description: Seamless nginx builder\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.13\")\n        asset: nginx-build-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.12.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: nginx-build-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: nginx-build_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cue-lang/cue/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cue-lang\n    repo_name: cue\n    description: The home of the CUE language! Validate and define text-based and dynamic configuration\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0-beta.5\")\n        asset: cue_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: cue_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.15.0-alpha.2\")\n        asset: cue_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: cue_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cyberark/kubeletctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cyberark\n    repo_name: kubeletctl\n    description: A client for kubelet\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3\")\n        asset: kubeletctl_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 1.9\")\n        asset: kubeletctl_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.10\"\n        asset: kubeletctl_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: Version == \"v1.11\"\n        asset: kubeletctl_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubeletctl_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            replacements:\n              amd64: x64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cybozu/assam/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cybozu\n    repo_name: assam\n    description: Get a credential by AssumeRoleWithSAML for AWS CLI and SDK\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: assam_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.4\")\n        asset: assam_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.6\")\n        asset: assam_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: assam_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cycloidio/inframap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cycloidio\n    repo_name: inframap\n    description: Read your tfstate or HCL to generate a graph specific for each provider, showing only the resources that are most important/relevant\n    rosetta2: true\n    asset: inframap-{{.OS}}-{{.Arch}}.tar.gz\n    complete_windows_ext: false\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: inframap\n        src: inframap-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/cycloidio/terracognita/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: cycloidio\n    repo_name: terracognita\n    asset: terracognita-{{.OS}}-{{.Arch}}.tar.gz\n    description: Reads from existing public and private cloud providers (reverse Terraform) and generates your infrastructure as code on Terraform configuration\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: terracognita\n        src: terracognita-{{.OS}}-{{.Arch}}\n    rosetta2: true\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/d-kuro/gwq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: d-kuro\n    repo_name: gwq\n    description: \"Git worktree manager with fuzzy finder - Work on multiple branches simultaneously, perfect for parallel AI coding workflows\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gwq_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gwq_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dadav/helm-schema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dadav\n    repo_name: helm-schema\n    description: Generate jsonschemas from helm charts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: helm-schema_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.4.3\"\n        asset: helm-schema_.{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        # Checksum file is broken\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: helm-schema_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dag-andersen/argocd-diff-preview/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dag-andersen\n    repo_name: argocd-diff-preview\n    description: Tool for rendering manifest changes on pull requests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.6\"\n        asset: argocd-diff-preview-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: linux\n            asset: argocd-diff-preview-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.35\")\n        asset: argocd-diff-preview-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: darwin\n            asset: argocd-diff-preview-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: argocd-diff-preview-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dagger/container-use/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dagger\n    repo_name: container-use\n    description: Development environments for coding agents. Enable multiple agents to work safely and independently with your preferred stack\n    files:\n      - name: container-use\n      - name: cu\n        src: container-use\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: container-use_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: container-use_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dagger/dagger/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dagger\n    repo_name: dagger\n    description: A portable devkit for CI/CD pipelines\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.gz\n    asset: dagger_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dagu-org/dagu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dagu-org\n    repo_name: dagu\n    aliases:\n      - name: yohamta/dagu\n      - name: hotaruswarm/dagu\n      - name: dagu-dev/dagu\n      - name: daguflow/dagu\n    description: Yet another cron alternative with a Web UI, but with much more capabilities. It aims to solve greater problems\n    asset: dagu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.10.6\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.1.0\")\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n      - version_constraint: semver(\"< 1.1.0\")\n        # https://github.com/dagu-dev/dagu/pull/15\n        # Rename jobctl to dagu\n        asset: jobctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        files:\n          - name: jobctl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/daichirata/hammer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: daichirata\n    repo_name: hammer\n    description: hammer is a command-line tool to schema management for Google Cloud Spanner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: hammer_{{trimV .Version}}_{{.Arch}}_{{.OS}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.4\")\n        asset: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: hammer\n            src: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}/hammer\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.5.9\")\n        asset: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: hammer\n            src: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}/hammer\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: hammer\n            src: hammer-{{trimV .Version}}-{{.OS}}-{{.Arch}}/hammer\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/daixiang0/gci/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: daixiang0\n    repo_name: gci\n    description: GCI, a tool that control golang package import order and make it always deterministic\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dalance/procs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dalance\n    repo_name: procs\n    description: A modern replacement for ps written in Rust\n    replacements:\n      amd64: x86_64\n      darwin: mac\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    asset: procs-{{.Version}}-{{.Arch}}-{{.OS}}.zip\n    version_constraint: semver(\">= 0.13.3\")\n    version_overrides:\n      - version_constraint: \"true\"\n        # https://github.com/aquaproj/aqua-registry/pull/7156\n        # windows zip structure was changed from 0.13.3.\n        # https://github.com/dalance/procs/blob/master/CHANGELOG.md#v0133---2022-10-18\n        # > [Changed] Release zip for Windows has the exe at toplevel\n        overrides:\n          - goos: windows\n            files:\n              - name: procs\n                src: target/x86_64-pc-windows-msvc/release/procs.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dandavison/delta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dandavison\n    repo_name: delta\n    description: A syntax-highlighting pager for git, diff, and grep output\n    asset: delta-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: delta\n        src: delta-{{.Version}}-{{.Arch}}-{{.OS}}/delta\n    overrides:\n      - goos: linux\n        goarch: amd64\n        replacements:\n          linux: unknown-linux-musl\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n        replacements:\n          arm64: arm64\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.16.5\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.16.4\")\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 0.15.0\")\n      - version_constraint: semver(\">= 0.4.1\")\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        rosetta2: true\n      - version_constraint: semver(\">= 0.3.0\")\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.1.0\")\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.16\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.10\")\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.8\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.7\")\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.6\")\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            files:\n              - name: delta\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.5\")\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        rosetta2: true\n      - version_constraint: semver(\"< 0.0.5\")\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/danielfoehrKn/kubeswitch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: danielfoehrKn\n    repo_name: kubeswitch\n    description: The kubectx  for operators\n    files:\n      - name: switcher\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: switcher.tar.gz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: switcher_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: switcher\n            src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: switcher_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: switcher_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: switcher_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/danielfoehrKn/kubeswitch/switch-sh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: danielfoehrKn/kubeswitch/switch-sh\n    type: github_release\n    repo_owner: danielfoehrKn\n    repo_name: kubeswitch\n    asset: switch.sh\n    format: raw\n    description: The kubectx for operators\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: kubeswitch.sh\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/danvergara/dblab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: danvergara\n    repo_name: dblab\n    description: The database client every command line junkie deserves\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.0\"\n        asset: dblab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: dblab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: dblab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: dblab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: dblab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: dblab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dapr/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dapr\n    repo_name: cli\n    description: Command-line tools for Dapr\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: dapr_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: dapr\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/databricks/click/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: databricks\n    repo_name: click\n    description: The \"Command Line Interactive Controller for Kubernetes\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: click-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: click\n            src: click-{{.Version}}-{{.Arch}}-{{.OS}}/click\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datadog/managed-kubernetes-auditing-toolkit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datadog\n    repo_name: managed-kubernetes-auditing-toolkit\n    description: All-in-one auditing toolkit for identifying common security issues in managed Kubernetes environments. Currently supports Amazon EKS\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: managed-kubernetes-auditing-toolkit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: mkat\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: managed-kubernetes-auditing-toolkit_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: mkat\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datadog-labs/pup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datadog-labs\n    repo_name: pup\n    description: Give your AI agent a Pup — a CLI companion with 200+ commands across 33+ Datadog products\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: pup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: pup_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: pup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: pup_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/datadog-labs/pup/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n            bundle:\n              type: github_release\n              asset: pup_{{trimV .Version}}_checksums.txt.sigstore.json\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datanymizer/datanymizer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datanymizer\n    repo_name: datanymizer\n    asset: pg_datanymizer-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Powerful database anonymizer with flexible rules. Written in Rust\n    replacements:\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        replacements:\n          windows: win\n          amd64: x64\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: pg_datanymizer\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datarootsio/tf-profile/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datarootsio\n    repo_name: tf-profile\n    description: CLI tool to profile Terraform runs, written in Go\n    asset: tf-profile-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    version_constraint: semver(\">= 0.2.1\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.2.1\")\n        version_prefix: release/\n        asset: tf-profile-v{{.SemVer}}-{{.OS}}.{{.Format}}\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datastax-labs/astra-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datastax-labs\n    repo_name: astra-cli\n    description: DataStax Astra automation CLI\n    asset: astra-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: astra\n    checksum:\n      type: github_release\n      asset: astra-cli_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dathere/qsv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dathere\n    repo_name: qsv\n    description: Blazing-fast Data-Wrangling toolkit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.15.0\", \"0.24.0\", \"0.48.0\", \"0.61.3\", \"0.68.0\", \"0.93.0\", \"0.102.0\"]\n        no_asset: true\n      - version_constraint: Version in [\"publish-testing\"]\n        error_message: This version isn't supported.\n      - version_constraint: Version == \"0.108.0\"\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: Version == \"0.113.0\"\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: Version == \"7.1.0\"\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: Version in [\"8.0.0\", \"9.1.0\"]\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: Version == \"10.0.0\"\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 7.0.1\")\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: semver(\"<= 8.1.1\")\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 16.1.0\")\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: \"true\"\n        asset: qsv-{{.Version}}-{{.Arch}}-{{.OS}}-testing.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/datreeio/datree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: datreeio\n    repo_name: datree\n    description: \"Prevent Kubernetes misconfigurations from reaching production (again  )! From code to cloud, Datree provides an E2E policy enforcement solution to run automatic checks for rule violations. See our docs: https://hub.datree.io\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: datree-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/daveshanley/vacuum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: daveshanley\n    repo_name: vacuum\n    description: vacuum is the worlds fastest OpenAPI 3, OpenAPI 2 / Swagger linter and quality analysis tool. Built in go, it tears through API specs faster than you can think. vacuum is compatible with Spectral rulesets and generates compatible reports\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.1\"\n        asset: vacuum_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.13\")\n        asset: vacuum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: vacuum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ddddddO/gtree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ddddddO\n    repo_name: gtree\n    description: Generate directory trees and the directories itself using Markdown or Programmatically. Provide CLI, Golang library and Web (using WebAssembly)\n    asset: gtree_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: gtree_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.8.4\")\n    version_overrides:\n      - version_constraint: Version == \"v1.8.3\"\n        no_asset: true\n      - version_constraint: semver(\">= 1.2.0\")\n        replacements:\n          amd64: x86_64\n      - version_constraint: semver(\"< 1.2.0\")\n        asset: gentree_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: gentree\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: gentree_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ddev/ddev/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ddev\n    repo_name: ddev\n    aliases:\n      - name: drud/ddev\n    asset: ddev_{{.OS}}-{{.Arch}}.{{.Version}}.{{.Format}}\n    format: tar.gz\n    description: \"DDEV: a local web development environment system for PHP\"\n    replacements:\n      darwin: macos\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dduan/tre/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dduan\n    repo_name: tre\n    description: Tree command, improved\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: tre-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.3.0\"\n        asset: tre-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: tre-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tre-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/defenseunicorns/uds-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: defenseunicorns\n    repo_name: uds-cli\n    files:\n      - name: uds\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"nightly-unstable\"\n        error_message: \"nightly-unstable is not supported.\"\n      - version_constraint: \"true\"\n        asset: uds-cli_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        files:\n          - name: uds\n            src: \"uds-cli_{{.Version}}_{{.OS}}_{{.Arch}}\"\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/deggja/netfetch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: deggja\n    repo_name: netfetch\n    description: Kubernetes tool for scanning clusters for network policies and identifying unprotected workloads\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: netfetch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: netfetch\n            src: \"{{.AssetWithoutExt}}/netfetch\"\n        checksum:\n          type: github_release\n          asset: netfetch_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/denisidoro/navi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: denisidoro\n    repo_name: navi\n    description: An interactive cheatsheet tool for the command-line\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.15.0\"\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v2.15.1\"\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: osx\n          - goos: darwin\n            goarch: arm64\n            asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}-ios.{{.Format}}\n            replacements:\n              arm64: aarch64\n              darwin: apple\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.24.0\"\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.0.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.1\")\n        asset: navi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.14.0\")\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.19.0\")\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: apple-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}-ios.{{.Format}}\n            replacements:\n              arm64: aarch64\n              darwin: apple\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.20.1\")\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: apple-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}-ios.{{.Format}}\n            replacements:\n              darwin: apple\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: navi-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/denizgursoy/gotouch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: denizgursoy\n    repo_name: gotouch\n    description: Customizable Boilerplate Project Creator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gotouch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/denoland/deno/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: denoland\n    repo_name: deno\n    description: A modern runtime for JavaScript and TypeScript\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: deno_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: deno\n            src: deno_{{.OS}}_{{.Arch}}\n        replacements:\n          amd64: x64\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: deno\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: deno_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: deno\n            src: deno_{{.OS}}_{{.Arch}}\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: deno\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.38.0\")\n        asset: deno-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: gz\n            asset: deno_{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x64\n            files:\n              - name: deno\n                src: deno_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.5.4\")\n        asset: deno-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.40.2\")\n        asset: deno-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: deno-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dependabot/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dependabot\n    repo_name: cli\n    description: A tool for testing and debugging Dependabot update jobs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.25.0\", \"v1.33.0\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: dependabot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: dependabot\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/derailed/k9s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: derailed\n    repo_name: k9s\n    description: Kubernetes CLI To Manage Your Clusters In Style\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"0.3.3\"\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: 64-bit\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.6.4\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.6.6\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.13.8\")\n        asset: k9s_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.24.2\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.24.9\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.24.10\")\n        asset: k9s_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.24.15\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.26.7\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.27.3\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.27.4\")\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: k9s_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/derailed/popeye/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: derailed\n    repo_name: popeye\n    description: A Kubernetes cluster resource sanitizer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: popeye_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.7\")\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.20.5\")\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.21.3\")\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: popeye_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/deref/exo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: deref\n    repo_name: exo\n    description: A process manager & log viewer for dev\n    asset: exo_standalone_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dev.yorhel.nl/ncdu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    name: dev.yorhel.nl/ncdu\n    description: Ncdu is a disk usage analyzer with an ncurses interface\n    link: https://dev.yorhel.nl/ncdu\n    url: https://dev.yorhel.nl/download/ncdu-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      arm64: aarch64\n      amd64: x86_64\n    supported_envs:\n      - linux\n    search_words:\n      - Linux Only\n    files:\n      # https://github.com/aquaproj/aqua-registry/pull/15293#issuecomment-1712422083\n      - name: ncdu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/deviceinsight/kafkactl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: deviceinsight\n    repo_name: kafkactl\n    description: Command Line Tool for managing Apache Kafka\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: kafkactl_x64.tar.xz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: kafkactl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.14.0\")\n        asset: kafkactl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.16.0\")\n        asset: kafkactl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.4.0\")\n        asset: kafkactl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.0.5\")\n        asset: kafkactl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kafkactl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/devops-kung-fu/bomber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: devops-kung-fu\n    repo_name: bomber\n    description: Scans Software Bill of Materials (SBOMs) for security vulnerabilities\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: bomber_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: bomber_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: linux\n            files:\n              # https://github.com/devops-kung-fu/bomber/pull/27\n              - name: bomber\n                src: hookz\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: bomber_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: bomber_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.5\")\n        asset: bomber_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: bomber_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: bomber_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: bomber_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: bomber_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: bomber_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/devops-works/dw-query-digest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: devops-works\n    repo_name: dw-query-digest\n    description: MySQL slow log analyzer. Alternative to pt-query-digest\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.8\"\n        asset: dw-query-digest-{{.OS}}\n        format: raw\n        complete_windows_ext: false\n        replacements:\n          windows: win\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: dw-query-digest-{{.OS}}\n        format: raw\n        complete_windows_ext: false\n        replacements:\n          windows: win\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: dw-query-digest_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/devops-works/egress-auditor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: devops-works\n    repo_name: egress-auditor\n    description: \"Audit your egress connections and finally populate this OUTPUT chain \"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: egress-auditor_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/devspace-sh/devspace/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: devspace-sh\n    repo_name: devspace\n    aliases:\n      - name: loft-sh/devspace\n    description: \"DevSpace - The Fastest Developer Tool for Kubernetes  Automate your deployment workflow with DevSpace and develop software directly inside Kubernetes\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v6.2.0-alpha.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 5.7.4\")\n        asset: devspace-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 5.10.0\")\n        asset: devspace-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: devspace-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dex4er/tf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dex4er\n    repo_name: tf\n    description: Less verbose and more shell friendly Terraform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.7.0\")\n        type: github_content\n        format: raw\n        path: tf.sh\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tf-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dhall-lang/dhall-haskell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dhall-lang\n    repo_name: dhall-haskell\n    description: Maintainable configuration files\n    files:\n      - name: dhall\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.42.1\"\n        no_asset: true\n      - version_constraint: Version == \"1.40.0\"\n        error_message: \"tar.bz2.zip is not supported\"\n      - version_constraint: semver(\"<= 1.9.0-rc1\")\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.16.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.17.0\")\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.24.0\")\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: dhall\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 1.39.0\")\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: dhall\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.40.1\"\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.41.1\")\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.41.2\"\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.42.0\"\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dhall-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        files:\n          - name: dhall\n            src: bin/dhall\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dhth/bmm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dhth\n    repo_name: bmm\n    description: get to your bookmarks in a flash\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: bmm-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: dhth/bmm/.github/workflows/release.yml\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: bmm\n            src: \"{{.AssetWithoutExt}}/bmm\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/digitalocean/doctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: digitalocean\n    repo_name: doctl\n    asset: doctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    description: The official command line interface for the DigitalOcean API\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: doctl-{{trimV .Version}}-checksums.sha256\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dimo414/bkt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dimo414\n    repo_name: bkt\n    description: a subprocess caching utility, available as a command line binary and a Rust library\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.4\")\n        asset: bkt.v{{.Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bkt.v{{.Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dimonomid/nerdlog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dimonomid\n    repo_name: nerdlog\n    description: \"Nerdlog: fast, remote-first, multi-host TUI log viewer with timeline histogram and no central server\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: nerdlog_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: nerdlog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dineshba/tf-summarize/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dineshba\n    repo_name: tf-summarize\n    description: A command-line utility to print the summary of the terraform plan\n    asset: tf-summarize_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: tf-summarize_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 0.3.6\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.2.5\")\n        format: zip\n        overrides: []\n      - version_constraint: semver(\">= 0.2.0\")\n        format: zip\n        overrides: []\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 0.0.2\")\n        asset: terraform-plan-summary_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides: []\n        files:\n          - name: tf-plan-summarize\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: terraform-plan-summary_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.1\"\n        asset: terraform-plan-summary_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides: []\n        files:\n          - name: terraform-plan-summarize\n            src: terraform-plan-summary\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: terraform-plan-summary_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dinoDanic/diny/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dinoDanic\n    repo_name: diny\n    description: generate git commit messages\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: diny_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: diny_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/direnv/direnv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: direnv\n    repo_name: direnv\n    description: unclutter your .profile\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.3.0\") or Version in [\"v2.7.0\", \"v2.8.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 2.24.0\")\n        asset: direnv.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.27.0\")\n        asset: direnv.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 2.36.0\")\n        asset: direnv.{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: direnv.{{.OS}}-{{.Arch}}\n        format: raw\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dispatchrun/wzprof/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dispatchrun\n    repo_name: wzprof\n    aliases:\n      - name: stealthrocket/wzprof\n    description: WebAssembly Profiler based on Wazero\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.5\"\n        asset: wzprof_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: wzprof_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: wzprof_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: wzprof_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/distribution/distribution/registry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: distribution/distribution/registry\n    type: github_release\n    repo_owner: distribution\n    repo_name: distribution\n    description: The toolkit to pack, ship, store, and deliver container content\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.8.2-beta.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.7.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: registry_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dlvhdr/diffnav/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dlvhdr\n    repo_name: diffnav\n    description: A git diff pager based on delta but with a file tree, à la GitHub\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: diffnav_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: diffnav_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dlvhdr/gh-dash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dlvhdr\n    repo_name: gh-dash\n    description: A beautiful CLI dashboard for GitHub\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.2.2\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.0\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.1.3\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 3.7.0\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n      - version_constraint: Version == \"v3.7.3-next\"\n        asset: gh-dash_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v3.7.4\"\n        asset: gh-dash_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v3.7.5\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.14.0\")\n        asset: \"{{.OS}}-{{.Arch}}\"\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gh-dash_{{.Version}}_{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dmtrKovalenko/blendr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dmtrKovalenko\n    repo_name: blendr\n    description: The hacker's BLE (bluetooth low energy) browser terminal app\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: blendr-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dnnrly/abbreviate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dnnrly\n    repo_name: abbreviate\n    description: Supporting your devops by shortening your strings using common abbreviations and clever guesswork\n    rosetta2: true\n    asset: abbreviate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dnote/dnote/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: dnote/dnote/cli\n    repo_owner: dnote\n    repo_name: dnote\n    description: A simple command line notebook for programmers\n    asset: dnote_{{trimPrefix \"cli-v\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: dnote\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: dnote_{{trimPrefix \"cli-v\" .Version}}_checksums.txt\n      algorithm: sha256\n    rosetta2: true # pre built binary for darwin/arm64 doesn't work at the moment. https://github.com/dnote/dnote/issues/572#issuecomment-1465315535\n    version_filter: Version startsWith \"cli-\"\n    version_constraint: semverWithVersion(\">= 0.11.1\", trimPrefix(Version, \"cli-\"))\n    version_overrides:\n      - version_constraint: semverWithVersion(\">= 0.6.3\", trimPrefix(Version, \"cli-\"))\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.4.8\")\n        asset: dnote_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"= 0.4.7\")\n        asset: dnote_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - linux/amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.4.7\")\n        asset: dnote_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/buildx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: docker\n    repo_name: buildx\n    description: Docker CLI plugin for extended build capabilities with BuildKit\n    files:\n      - name: docker-cli-plugin-docker-buildx\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0-rc1\")\n        asset: buildx-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: buildx-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: buildx-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n      - version_constraint: semver(\"<= 0.10.0-rc1\")\n        asset: buildx-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              enabled: false # https://github.com/docker/buildx/issues/945\n      - version_constraint: \"true\"\n        asset: buildx-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              enabled: false # https://github.com/docker/buildx/issues/945\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/cagent/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: docker\n    repo_name: cagent\n    description: Agent Builder and Runtime by Docker Engineering\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.4\")\n        asset: cagent-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: cagent-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: docker\n    repo_name: cli\n    description: Docker CE CLI\n    version_source: github_tag\n    version_filter: not (Version contains \"beta\" or Version contains \"rc\")\n    url: https://download.docker.com/{{.OS}}/static/stable/{{.Arch}}/docker-{{trimV .Version}}.{{.Format}}\n    format: tgz\n    files:\n      - name: docker\n        src: docker/docker\n    overrides:\n      - goos: linux\n        files:\n          - name: containerd\n            src: docker/containerd\n          - name: containerd-shim-runc-v2\n            src: docker/containerd-shim-runc-v2\n          - name: ctr\n            src: docker/ctr\n          - name: docker\n            src: docker/docker\n          - name: docker-init\n            src: docker/docker-init\n          - name: docker-proxy\n            src: docker/docker-proxy\n          - name: dockerd\n            src: docker/dockerd\n          - name: runc\n            src: docker/runc\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: mac\n      windows: win\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 23.0.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 23.0.0\")\n        overrides:\n          - goos: linux\n            files:\n              - name: containerd\n                src: docker/containerd\n              - name: containerd-shim\n                src: docker/containerd-shim\n              - name: containerd-shim-runc-v2\n                src: docker/containerd-shim-runc-v2\n              - name: ctr\n                src: docker/ctr\n              - name: docker\n                src: docker/docker\n              - name: docker-init\n                src: docker/docker-init\n              - name: docker-proxy\n                src: docker/docker-proxy\n              - name: dockerd\n                src: docker/dockerd\n              - name: runc\n                src: docker/runc\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/cli/rootless/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: docker/cli/rootless\n    type: http\n    repo_owner: docker\n    repo_name: cli\n    description: Docker CE CLI for Rootless mode\n    version_source: github_tag\n    version_filter: not (Version contains \"beta\" or Version contains \"rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 28.0.0\")\n        url: https://download.docker.com/{{.OS}}/static/stable/{{.Arch}}/docker-rootless-extras-{{trimV .Version}}.tgz\n        files:\n          - name: rootlesskit\n            src: docker-rootless-extras/rootlesskit\n          - name: rootlesskit-docker-proxy\n            src: docker-rootless-extras/rootlesskit-docker-proxy\n          - name: vpnkit\n            src: docker-rootless-extras/vpnkit\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        url: https://download.docker.com/{{.OS}}/static/stable/{{.Arch}}/docker-rootless-extras-{{trimV .Version}}.tgz\n        files:\n          - name: rootlesskit\n            src: docker-rootless-extras/rootlesskit\n          - name: vpnkit\n            src: docker-rootless-extras/vpnkit\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/compose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: docker\n    repo_name: compose\n    description: Define and run multi-container applications with Docker\n    files:\n      - name: docker-cli-plugin-docker-compose\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: \"{{.OS}}\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: fig-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.17.1\")\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.29.2\")\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v2.0.0-rc.3\"\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v2.0.0\"\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.9.0\")\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v2.10.0\"\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: docker-compose-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/docker/hub-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: docker\n    repo_name: hub-tool\n    asset: hub-tool-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Docker Hub experimental CLI tool\n    files:\n      - name: hub-tool\n        src: hub-tool/hub-tool\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: hub-tool\n            src: hub-tool.exe\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.4.1\")\n    # darwin/arm64 was supported\n    version_overrides:\n      - version_constraint: semver(\">= 0.1.1\")\n        # linux/arm64 was supported\n        # asset name and format were changed\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: hub-tool_{{.OS}}_{{.Arch}}\n        overrides: []\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dodobrands/Peekie/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dodobrands\n    repo_name: Peekie\n    description: Swift package for parsing Xcode .xcresult files with support for XCTest and Swift Testing frameworks\n    files:\n      - name: peekie\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.0.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: peekie_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/doitintl/kube-no-trouble/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: doitintl\n    repo_name: kube-no-trouble\n    description: Easily check your clusters for use of deprecated APIs\n    asset: kubent-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: kubent\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dolthub/dolt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dolthub\n    repo_name: dolt\n    asset: dolt-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Dolt – It's Git for Data\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.40.29\")\n    files:\n      - name: dolt\n        src: dolt-{{.OS}}-{{.Arch}}/bin/dolt\n    version_overrides:\n      - version_constraint: semver(\">= 0.40.15\")\n        files:\n          - name: dolt\n            src: dolt-{{.OS}}-{{.Arch}}/bin/dolt\n          - name: git-dolt\n            src: dolt-{{.OS}}-{{.Arch}}/bin/git-dolt\n          - name: git-dolt-smudge\n            src: dolt-{{.OS}}-{{.Arch}}/bin/git-dolt-smudge\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - amd64\n        files:\n          - name: dolt\n            src: dolt-{{.OS}}-{{.Arch}}/bin/dolt\n          - name: git-dolt\n            src: dolt-{{.OS}}-{{.Arch}}/bin/git-dolt\n          - name: git-dolt-smudge\n            src: dolt-{{.OS}}-{{.Arch}}/bin/git-dolt-smudge\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dominikh/go-tools/staticcheck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: dominikh/go-tools/staticcheck\n    type: github_release\n    repo_owner: dominikh\n    repo_name: go-tools\n    description: Go static analysis, detecting bugs, performance issues, and much more\n    asset: staticcheck_{{.OS}}_{{.Arch}}.tar.gz\n    rosetta2: true\n    files:\n      - name: staticcheck\n        src: staticcheck/staticcheck\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    version_constraint: semver(\"< 2000.0.0\")\n    # versioning was changed from v0.3.3\n    # https://github.com/dominikh/go-tools/releases/tag/v0.3.3\n    # https://github.com/dominikh/go-tools/releases/tag/2022.1.2\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/domoritz/arrow-tools/csv2arrow/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: domoritz/arrow-tools/csv2arrow\n    type: github_release\n    repo_owner: domoritz\n    repo_name: arrow-tools\n    description: A collection of handy CLI tools to convert CSV and JSON to Apache Arrow and Parquet\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: csv2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.1\"\n        asset: csv2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: csv2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: csv2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.14.1\"\n        asset: csv2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.22.3\")\n        asset: csv2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: csv2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: csv2arrow\n            src: \"{{.AssetWithoutExt}}/csv2arrow\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin/arm64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/domoritz/arrow-tools/csv2parquet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: domoritz/arrow-tools/csv2parquet\n    type: github_release\n    repo_owner: domoritz\n    repo_name: arrow-tools\n    description: Convert CSV files to Apache Parquet. This package is part of Arrow CLI tools\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: csv2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.1\"\n        asset: csv2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: csv2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: csv2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.14.1\"\n        asset: csv2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.22.3\")\n        asset: csv2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: csv2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: csv2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: csv2parquet\n            src: \"{{.AssetWithoutExt}}/csv2parquet\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin/arm64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/domoritz/arrow-tools/json2arrow/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: domoritz/arrow-tools/json2arrow\n    type: github_release\n    repo_owner: domoritz\n    repo_name: arrow-tools\n    description: Convert JSON files to Apache Arrow. This package is part of Arrow CLI tools\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: json2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.1\"\n        asset: json2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: json2arrow-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: json2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.14.1\"\n        asset: json2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.22.3\")\n        asset: json2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2arrow\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: json2arrow-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: json2arrow\n            src: \"{{.AssetWithoutExt}}/json2arrow\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin/arm64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/domoritz/arrow-tools/json2parquet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: domoritz/arrow-tools/json2parquet\n    type: github_release\n    repo_owner: domoritz\n    repo_name: arrow-tools\n    description: Convert JSON files to Apache Parquet. This package is part of Arrow CLI tools\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: json2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.1\"\n        asset: json2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: json2parquet-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: json2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.14.1\"\n        asset: json2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.22.3\")\n        asset: json2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: json2parquet\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: json2parquet-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: json2parquet\n            src: \"{{.AssetWithoutExt}}/json2parquet\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin/arm64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dotenv-linter/dotenv-linter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dotenv-linter\n    repo_name: dotenv-linter\n    rosetta2: true\n    asset: dotenv-linter-{{.OS}}-{{.Arch}}.{{.Format}}\n    description: Lightning-fast linter for .env files. Written in Rust\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      windows: win\n    overrides:\n      - goos: linux\n        replacements:\n          arm64: aarch64\n      - goos: windows\n        format: zip\n        replacements:\n          amd64: x64\n    version_constraint: semver(\">= 2.1.0\")\n    supported_envs:\n      - darwin\n      - amd64\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dotenvx/dotenvx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dotenvx\n    repo_name: dotenvx\n    description: a better dotenv–from the creator of `dotenv`\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: git-dotenv-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: git-dotenv\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.18\")\n        asset: git-dotenv-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: git-dotenv\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.7\")\n        asset: dotenv-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: dotenv\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.8\"\n        asset: dotenv-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: dotenv\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.10\")\n        asset: dotenv-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: dotenv\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.19\")\n        asset: dotenv-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: dotenv\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.44.5\")\n        asset: dotenvx-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: dotenvx-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/doy/rbw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: doy\n    repo_name: rbw\n    description: unofficial bitwarden cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: rbw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dprint/dprint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dprint\n    repo_name: dprint\n    description: Pluggable and configurable code formatting platform written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.14.0\")\n        asset: dprint-{{.Arch}}-{{.OS}}.zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - amd64\n      - version_constraint: semver(\"< 0.34.0\")\n        asset: dprint-{{.Arch}}-{{.OS}}.zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.52.0\")\n        asset: dprint-{{.Arch}}-{{.OS}}.zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: dprint-{{.Arch}}-{{.OS}}.zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/drager/wasm-pack/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: drager\n    repo_name: wasm-pack\n    aliases:\n      - name: rustwasm/wasm-pack\n    description: your favorite rust -> wasm workflow tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: wasm-pack-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wasm-pack\n            src: \"{{.AssetWithoutExt}}/wasm-pack\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: wasm-pack-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: wasm-pack\n            src: \"{{.AssetWithoutExt}}/wasm-pack\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: wasm-pack-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: wasm-pack\n            src: \"{{.AssetWithoutExt}}/wasm-pack\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/drlau/akashi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: drlau\n    repo_name: akashi\n    asset: akashi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Validate \"terraform plan\" changes against a customizable ruleset\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: akashi_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.0.12\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.0.8\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dstotijn/hetty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dstotijn\n    repo_name: hetty\n    asset: hetty_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: An HTTP toolkit for security research\n    replacements:\n      amd64: x86_64\n      darwin: macOS\n      linux: Linux\n      windows: Windows\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dtan4/ghrls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dtan4\n    repo_name: ghrls\n    description: List & Describe GitHub Releases\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\"> 0.1.0\")\n    asset: ghrls_{{.OS}}_{{.Arch}}.{{.Format}}\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        asset: ghrls-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements: {}\n        files:\n          - name: ghrls\n            src: \"{{.OS}}-{{.Arch}}/ghrls\"\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dtan4/k8sec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dtan4\n    repo_name: k8sec\n    description: CLI tool to manage Kubernetes Secrets easily\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.0\"\n        asset: k8sec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: k8sec-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: k8sec\n            src: \"{{.OS}}-{{.Arch}}/k8sec\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: k8sec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: k8sec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dtan4/k8stail/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dtan4\n    repo_name: k8stail\n    asset: k8stail_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: tail -f experience for Kubernetes Pods\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dtan4/s3url/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dtan4\n    repo_name: s3url\n    asset: s3url_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Generate S3 object pre-signed URL in one command\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dthagard/tforganize/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dthagard\n    repo_name: tforganize\n    description: CLI tool to organize your Terraform code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        error_message: This version isn't support because assets are broken.\n      - version_constraint: \"true\"\n        asset: tforganize-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ducaale/xh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ducaale\n    repo_name: xh\n    description: Friendly and fast tool for sending HTTP requests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.7.0\"\n        asset: xh-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: xh\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: ht-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ht\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: ht-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ht\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: xh-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: xh\n            src: \"{{.AssetWithoutExt}}/xh\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: xh-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: xh\n            src: \"{{.AssetWithoutExt}}/xh\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: xh-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: xh\n            src: \"{{.AssetWithoutExt}}/xh\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/duckdb/duckdb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: duckdb\n    repo_name: duckdb\n    description: DuckDB is an analytical in-process SQL database management system\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.8\"\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version in [\"v1.2.0\", \"v1.2.1\", \"v1.2.2\"]\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: duckdb_cli-{{.OS}}-universal.{{.Format}}\n      - version_constraint: semver(\"<= 0.1.8\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: duckdb_cli-{{.OS}}-universal.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: duckdb_cli-{{.OS}}-universal.{{.Format}}\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: duckdb_cli-{{.OS}}-universal.{{.Format}}\n      - version_constraint: \"true\"\n        asset: duckdb_cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: duckdb_cli-{{.OS}}-universal.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dundee/gdu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dundee\n    repo_name: gdu\n    description: Fast disk usage analyzer with console interface written in Go\n    asset: gdu_{{.OS}}_{{.Arch}}.tgz\n    overrides:\n      - goos: windows\n        asset: gdu_windows_amd64.exe.zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: gdu\n        src: gdu_{{.OS}}_{{.Arch}}\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dustinblackman/oatmeal/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dustinblackman\n    repo_name: oatmeal\n    description: Terminal UI to chat with large language models (LLM) using different model backends, and integrations with your favourite editors\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: oatmeal_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dutchcoders/cloudman/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dutchcoders\n    repo_name: cloudman\n    description: Textual user interface to manage ec2 instances\n    rosetta2: true\n    asset: cloudman-{{.Version}}-{{.Arch}}-{{.OS}}.tar.gz\n    replacements:\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n      amd64: x86_64\n    supported_envs:\n      - linux/amd64\n      - darwin\n    files:\n      - name: cloudman\n        src: cloudman-{{.Version}}-{{.Arch}}-{{.OS}}/cloudman\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dwisiswant0/tlder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dwisiswant0\n    repo_name: tlder\n    description: TLDs finder — check domain name availability across all valid top-level domains\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: tlder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: tlder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tlder_{{.Version}}-{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: tlder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dylanaraps/neofetch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: dylanaraps\n    repo_name: neofetch\n    path: neofetch\n    description: A command-line system information tool written in bash 3.2+\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dyne/slangroom-exec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dyne\n    repo_name: slangroom-exec\n    description: Execute all Zencode from Zenroom and Slangroom plugins in one shot\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: slangroom-exec-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: slangroom-exec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: slangroom-exec\n          - name: slexfe\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/dyne/zenroom/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: dyne\n    repo_name: zenroom\n    description: Embedded no-code VM executing human-like language to manipulate data and process cryptographic operations\n    files:\n      - name: zenroom\n      - name: zencode-exec\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.10.0\")\n        error_message: |\n          Please update to 3.10.1 or newer.\n      - version_constraint: semver(\"<= 4.27.1\")\n        asset: zenroom\n        format: raw\n        files:\n          - name: zenroom\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: darwin\n            asset: zenroom.command\n      - version_constraint: semver(\"<= 5.10.4\")\n        asset: zenroom\n        format: raw\n        files:\n          - name: zenroom\n        supported_envs:\n          - darwin/arm64\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: darwin\n            asset: zenroom.command\n      - version_constraint: semver(\"<= 5.25.0\")\n        asset: zenroom-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: zenroom\n            src: zenroom-{{.OS}}/zenroom\n          - name: zencode-exec\n            src: zenroom-{{.OS}}/zencode-exec\n        replacements:\n          darwin: osx\n          windows: win64\n        supported_envs:\n          - darwin/arm64\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: darwin\n            files:\n              - name: zenroom\n                src: zenroom-{{.OS}}/zenroom.command\n              - name: zencode-exec\n                src: zenroom-{{.OS}}/zencode-exec.command\n      - version_constraint: semver(\"<= 5.25.3\")\n        asset: zenroom-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: zenroom\n            src: zenroom-{{.Arch}}-{{.OS}}/zenroom\n          - name: zencode-exec\n            src: zenroom-{{.Arch}}-{{.OS}}/zencode-exec\n        replacements:\n          darwin: osx\n          windows: win64\n          amd64: x86_64\n        supported_envs:\n          - darwin/arm64\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: zenroom\n                src: zenroom-{{.OS}}/zenroom\n              - name: zencode-exec\n                src: zenroom-{{.OS}}/zencode-exec\n          - goos: darwin\n            files:\n              - name: zenroom\n                src: zenroom-{{.OS}}/zenroom.command\n              - name: zencode-exec\n                src: zenroom-{{.OS}}/zencode-exec.command\n      - version_constraint: \"true\"\n        asset: zenroom-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: zenroom\n            src: zenroom-{{.Arch}}-{{.OS}}/zenroom\n          - name: zencode-exec\n            src: zenroom-{{.Arch}}-{{.OS}}/zencode-exec\n        replacements:\n          darwin: osx\n          windows: win64\n          amd64: x86_64\n        supported_envs:\n          - darwin/arm64\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: zenroom\n                src: zenroom-{{.OS}}/zenroom\n              - name: zencode-exec\n                src: zenroom-{{.OS}}/zencode-exec\n          - goos: darwin\n            files:\n              - name: zenroom\n                src: zenroom-{{.OS}}/zenroom\n              - name: zencode-exec\n                src: zenroom-{{.OS}}/zencode-exec\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/earthly/earthly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: earthly\n    repo_name: earthly\n    description: Repeatable builds\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: earthly-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ebi-yade/ecresolve/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ebi-yade\n    repo_name: ecresolve\n    description: Resolves AWS ECR images with prioritized tag-based lookup\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: ecresolve_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ecresolve_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/editorconfig-checker/editorconfig-checker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: editorconfig-checker\n    repo_name: editorconfig-checker\n    description: A tool to verify that your files are in harmony with your .editorconfig\n    files:\n      - name: ec\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 2.3.5\")\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            asset: ec-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n      - version_constraint: semver(\"<= 2.5.0\")\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            asset: ec-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n      - version_constraint: Version == \"2.6.0\"\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 3.0.3\")\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            asset: ec-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: ec-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ec\n            src: bin/ec-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/edoardottt/depsdev/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: edoardottt\n    repo_name: depsdev\n    description: CLI client (and Golang module) for deps.dev API. Free access to dependencies, licenses, advisories, and other critical health and security signals for open source package versions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.10\")\n        type: go_install\n      - version_constraint: \"true\"\n        asset: depsdev_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: depsdev_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/eficode/wait-for/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: eficode\n    repo_name: wait-for\n    description: ./wait-for is a script to wait for another service to become available\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wait-for\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ekalinin/github-markdown-toc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: ekalinin\n    repo_name: github-markdown-toc\n    description: Easy TOC creation for GitHub README.md\n    supported_envs:\n      - darwin\n      - linux\n    path: gh-md-toc\n    files:\n      - name: gh-md-toc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ekristen/aws-nuke/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ekristen\n    repo_name: aws-nuke\n    description: Remove all the resources from an AWS account\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v3.0.0-beta.25\", \"v3.0.0-beta.44\", \"v3.0.0-beta.56\", \"v3.46.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v2.17.0-ek.1\"\n        asset: aws-nuke-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v2.18.6\"\n        asset: aws-nuke-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.17.0-ek.4\")\n        asset: aws-nuke-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.0.0-beta.7\")\n        asset: aws-nuke-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/ekristen/aws-nuke/releases/download/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/ekristen/aws-nuke/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: aws-nuke-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/ekristen/aws-nuke/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/ekristen/aws-nuke/.github/workflows/goreleaser.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/ekristen/aws-nuke/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/eksctl-io/eksctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: eksctl-io\n    repo_name: eksctl\n    aliases:\n      - name: weaveworks/eksctl\n    description: The official CLI for Amazon EKS\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.80.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.30.0-rc.0\")\n        asset: eksctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: eksctl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.40.0\")\n        asset: eksctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: eksctl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.64.0\")\n        asset: eksctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: eksctl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: eksctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: eksctl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ekzhang/bore/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ekzhang\n    repo_name: bore\n    asset: bore-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: bore is a simple CLI tool for making tunnels to localhost\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/electric-saw/kafta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: electric-saw\n    repo_name: kafta\n    description: Kafta is a command line for managing Kafka clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: kafta_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kafta_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/elixir-lang/expert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: elixir-lang\n    repo_name: expert\n    description: Official Elixir Language Server Protocol implementation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: expert_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: expert_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/elkowar/pipr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: elkowar\n    repo_name: pipr\n    description: A tool to interactively write shell pipelines\n    asset: pipr\n    format: raw\n    supported_envs:\n      - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/elsesiy/kubectl-view-secret/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: elsesiy\n    repo_name: kubectl-view-secret\n    description: Kubernetes CLI plugin to decode Kubernetes secrets\n    files:\n      - name: kubectl-view_secret\n        src: kubectl-view-secret\n    version_constraint: semver(\">= 0.8.0\")\n    asset: kubectl-view-secret_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: kubectl-view-secret_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\"= 0.7.0\")\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: kubectl-view-secret_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        replacements:\n          darwin: Darwin\n          windows: Windows\n          linux: Linux\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/emirozer/kubectl-doctor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: emirozer\n    repo_name: kubectl-doctor\n    description: kubectl cluster triage plugin for k8s - (brew doctor equivalent)\n    version_constraint: semver(\">= 0.3.1\")\n    asset: kubectl-doctor_{{.OS}}_{{.Arch}}\n    supported_envs:\n      - darwin\n      - amd64\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        asset: kubectl-doctor_{{.OS}}_{{.Arch}}.zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/encoredev/encore/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: encoredev\n    repo_name: encore\n    description: Open Source Development Platform for building robust type-safe distributed systems with declarative infrastructure\n    url: https://d2f391esomvqpi.cloudfront.net/encore-{{trimV .Version}}-{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: encore\n        src: bin/encore\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/enokawa/taskdiff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: enokawa\n    repo_name: taskdiff\n    description: Diff tool for ECS Task Definition\n    asset: taskdiff_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: taskdiff\n        src: taskdiff_{{.Version}}_{{.OS}}_{{.Arch}}/taskdiff\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/entireio/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: entireio\n    repo_name: cli\n    description: Entire is a new developer platform that hooks into your git workflow to capture AI agent sessions on every push, unifying your code with its context and reasoning\n    files:\n      - name: entire\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.9\")\n        asset: cli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: entire_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/env0/terratag/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: env0\n    repo_name: terratag\n    asset: terratag_{{trimV .Version}}_{{.OS}}_amd64.tar.gz\n    description: Terratag is a CLI tool that enables users of Terraform to automatically create and maintain tags across their entire set of AWS, Azure, and GCP resources\n    checksum:\n      type: github_release\n      asset: terratag_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/equinix-labs/otel-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: equinix-labs\n    repo_name: otel-cli\n    description: OpenTelemetry command-line tool for sending events from shell scripts & similar environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: otel-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.19\")\n        asset: otel-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.20\"\n        asset: otel-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: otel-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/erebe/wstunnel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: erebe\n    repo_name: wstunnel\n    description: Tunnel all your traffic over Websocket or HTTP2 - Bypass firewalls/DPI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0\"\n        asset: wstunnel\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"1.1\", \"1.2\"]\n        asset: wstunnel_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: raw\n            asset: wstunnel_{{.OS}}_{{.Arch}}\n          - goos: windows\n            files:\n              - name: wstunnel\n                src: wstunnel_{{.OS}}_{{.Arch}}/wstunnel\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"2.0\"\n        asset: wstunnel_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: wstunnel-{{.OS}}\n          - goos: windows\n            format: zip\n            asset: wstunnel_{{.OS}}_{{.Arch}}.{{.Format}}\n            files:\n              - name: wstunnel\n                src: wstunnel_{{.OS}}_{{.Arch}}/wstunnel\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.5\"\n        asset: wstunnel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v3.0\"\n        asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: wstunnel-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v3.1\"\n        asset: wstunnel-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            format: raw\n            asset: wstunnel-{{.Arch}}-{{.OS}}\n          - goos: linux\n            goarch: arm64\n            asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n            files:\n              - name: wstunnel\n                src: wstunnel/wstunnel\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: wstunnel-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: Version == \"v4.0\"\n        asset: wstunnel-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: raw\n            asset: wstunnel-{{.Arch}}-{{.OS}}\n          - goos: windows\n            asset: wstunnel-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v4.1\"\n        asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            format: raw\n            asset: wstunnel-{{.Arch}}-{{.OS}}\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: wstunnel\n                src: wstunnel_{{.Arch}}\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: wstunnel-{{.OS}}.{{.Format}}\n          - goos: windows\n            asset: wstunnel-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: Version == \"v5.0\"\n        asset: wstunnel-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            format: raw\n            asset: wstunnel-{{.OS}}-{{.Arch}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: wstunnel-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: Version == \"v5.1\"\n        asset: wstunnel-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v6.0\"\n        asset: wstunnel-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: wstunnel-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n        replacements:\n          amd64: x64\n          arm64: aarch64\n          darwin: macos\n      - version_constraint: Version == \"v7.0-rc1\"\n        asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: Version == \"v7.0.0-rc2\"\n        asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: semver(\"<= 7.1.0\")\n        asset: wstunnel-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 8.4.2\")\n        asset: wstunnel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: wstunnel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ericchiang/pup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ericchiang\n    repo_name: pup\n    description: Parsing HTML at the command line\n    search_words:\n      - HTML\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: pup_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.9\")\n        asset: pup_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pup_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/erikjuhani/basalt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: erikjuhani\n    repo_name: basalt\n    description: TUI Application to manage Obsidian notes directly from the terminal\n    version_prefix: basalt/v\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        no_asset: true\n      - version_constraint: Version == \"basalt/v0.10.4\"\n        asset: basalt-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: basalt\n            src: target/{{.Arch}}-{{.OS}}/release/basalt\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: basalt-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: basalt\n            src: target/{{.Arch}}-{{.OS}}/release/basalt\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ernoaapa/kubectl-warp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ernoaapa\n    repo_name: kubectl-warp\n    description: Kubernetes CLI plugin for syncing and executing local files in Pod on Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubectl-warp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/errata-ai/vale/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: errata-ai\n    repo_name: vale\n    description: \":pencil: A markup-aware linter for prose built with speed and extensibility in mind\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        no_asset: true\n      - version_constraint: Version == \"v1.1.6-alpha\"\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: vale\n            src: bin/vale\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.23.1\"\n        asset: vale_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v2.23.2\"\n        asset: vale_.{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: \"{{.OS}}-{{.Arch}}.{{.Format}}\"\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: \"{{.OS}}-{{.Arch}}.{{.Format}}\"\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: vale_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.7.0\"\n        asset: vale_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.7.1\"\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: vale_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: vale_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.15.2\")\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.18.0\")\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.23.0\")\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.4.2\")\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: vale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: vale_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/estesp/manifest-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: estesp\n    repo_name: manifest-tool\n    description: Command line tool to create and query container image manifest list/indexes\n    format: tar.gz\n    asset: binaries-manifest-tool-{{trimV .Version}}.{{.Format}}\n    files:\n      - name: manifest-tool\n        src: manifest-tool-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    checksum:\n      type: github_release\n      asset: binaries-manifest-tool-{{trimV .Version}}.tar.gz.sha256sum\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/etcd-io/etcd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: etcd-io\n    repo_name: etcd\n    asset: etcd-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    description: Distributed reliable key-value store for the most critical data of a distributed system\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    files:\n      - name: etcdctl\n        src: etcd-{{.Version}}-{{.OS}}-{{.Arch}}/etcdctl\n      - name: etcd\n        src: etcd-{{.Version}}-{{.OS}}-{{.Arch}}/etcd\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/eth-p/bat-extras/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: eth-p\n    repo_name: bat-extras\n    description: Bash scripts that integrate bat with various command line tools\n    version_constraint: \"false\"\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: batdiff\n        src: bin/batdiff\n      - name: batgrep\n        src: bin/batgrep\n      - name: batman\n        src: bin/batman\n      - name: batpipe\n        src: bin/batpipe\n      - name: batwatch\n        src: bin/batwatch\n      - name: prettybat\n        src: bin/prettybat\n      - name: bat-modules\n        src: bin/bat-modules\n    version_overrides:\n      - version_constraint: semver(\"<= 2023.03.21\")\n        asset: bat-extras-{{ trimV .Version | replace \".\" \"\" }}.zip\n      - version_constraint: semver(\"<= 2024.02.12\")\n        asset: bat-extras-{{ index (splitList \".\" (trimV .Version)) 0 }}{{ index (splitList \".\" (trimV .Version)) 1 }}.{{ index (splitList \".\" (trimV .Version)) 2 }}.zip\n      - version_constraint: \"true\"\n        asset: bat-extras-{{ trimV .Version }}.zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/everstake/bip39/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: everstake\n    repo_name: bip39\n    description: CLI for generation and verification of mnemonics in BIP39 standard with hash in Argon2id\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: bip39_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bip39_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/evilmartians/lefthook/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: evilmartians\n    repo_name: lefthook\n    description: Fast and powerful Git hooks manager for any type of projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.5\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.0\"\n        asset: hookah_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: hookah_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: hookah\n      - version_constraint: Version == \"v0.5.3\"\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.6.3\"\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: lefthook\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: Version == \"v0.7.3\"\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: lefthook\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: hookah_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hookah_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: hookah\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: lefthook\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 0.7.7\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 1.6.18\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 1.10.1\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 2.0.4\")\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: \"true\"\n        asset: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lefthook_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        files:\n          - name: lefthook\n            src: lefthook_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        github_artifact_attestations:\n          signer_workflow: evilmartians/lefthook/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/exercism/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: exercism\n    repo_name: cli\n    description: A Go based command line tool for exercism.org\n    asset: exercism-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: exercism\n    replacements:\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: exercism_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 3.2.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 3.0.13\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 3.0.0\")\n        asset: exercism-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.7.3\")\n        asset: exercism-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.7.2\")\n        asset: exercism-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tgz\n        overrides: []\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 1.7.2\")\n        asset: exercism-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tgz\n        overrides: []\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/exoscale/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: exoscale\n    repo_name: cli\n    description: \"Command-line tool for everything at Exoscale: compute, storage, dns\"\n    version_constraint: \"false\"\n    files:\n      - name: exo\n    version_overrides:\n      - version_constraint: semver(\"<= 0.51.2\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n            files:\n              - name: exo\n                src: exoscale-cli\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.4\")\n        asset: cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.11.0\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.19.0\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v1.20.0-pre1\"\n        asset: exo-{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.24.0\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.40.5\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.44.0\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.72.2\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.76.2\")\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: exoscale-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: exoscale-cli_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/external-secrets/external-secrets/esoctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: external-secrets/external-secrets/esoctl\n    type: github_release\n    repo_owner: external-secrets\n    repo_name: external-secrets\n    description: External Secrets Operator reads information from a third-party service like AWS Secrets Manager and automatically injects the values as Kubernetes Secrets\n    version_filter: 'Version endsWith \"-esoctl\"'\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: esoctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: esoctl_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/eza-community/eza/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: eza-community\n    repo_name: eza\n    description: A modern, maintained replacement for ls\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.9\")\n        type: cargo\n        crate: eza\n      - version_constraint: Version == \"v0.11.0\"\n        asset: \"{{.Arch}}-{{.OS}}-eza\"\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - envs:\n              - darwin\n              - windows/arm64\n            type: cargo\n            crate: eza\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"v0.11.1\"\n        asset: eza_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - envs:\n              - darwin\n              - windows/arm64\n            type: cargo\n            crate: eza\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: eza_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-gnu\n        overrides:\n          - envs:\n              - darwin\n              - windows/arm64\n            type: cargo\n            crate: eza\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            asset: eza.exe_{{.Arch}}-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fabpot/local-php-security-checker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fabpot\n    repo_name: local-php-security-checker\n    description: PHP security vulnerabilities checker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: local-php-security-checker_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.0.6\")\n        asset: local-php-security-checker_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: local-php-security-checker_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/facebook/buck2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: facebook\n    repo_name: buck2\n    description: Build system, successor to Buck\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"latest\"\n        error_message: |\n          aqua doesn't support mutable versions such as \"latest\". Please change the version\n      - version_constraint: semver(\"<= 2023-07-11\")\n        asset: buck2-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zst\n        windows_arm_emulation: true\n        files:\n          - name: buck2\n            src: buck2-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: windows\n            asset: buck2-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: buck2-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zst\n        windows_arm_emulation: true\n        files:\n          - name: buck2\n            src: buck2-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            asset: buck2-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/facebook/ktfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: facebook\n    repo_name: ktfmt\n    description: A program that reformats Kotlin source code to comply with the common community standard for Kotlin code conventions\n    asset: ktfmt-{{trimV .Version}}-with-dependencies.jar\n    format: raw\n    complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fastfetch-cli/fastfetch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fastfetch-cli\n    repo_name: fastfetch\n    description: An actively maintained, feature-rich and performance oriented, neofetch like system information tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"1.10.2\", \"2.1.2\", \"2.7.0\"]\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            goarch: amd64\n            format: zip\n            replacements:\n              windows: Win64\n            files:\n              - name: fastfetch\n          - goos: windows\n            goarch: arm64\n            format: zip\n            replacements:\n              windows: WinArm64\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"2.0.2\", \"2.0.3\", \"2.2.0\", \"2.3.2\", \"2.7.1\"]\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Win64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"2.8.2\"\n        asset: fastfetch-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: fastfetch-{{.Version}}-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: Version == \"2.8.3\"\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: Version == \"1.2.1\"\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/bin/fastfetch\"\n        format: tar.zst\n        replacements:\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"1.8.0\"\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            format: raw\n            asset: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.8.1\"\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            format: zip\n            asset: fastfetch-{{.OS}}.{{.Format}}\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.8.2\"\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Win7\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"2.8.5\", \"2.8.7\", \"2.9.0\", \"2.13.0\"]\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: fastfetch\n        format: raw\n        files:\n          - name: fastfetch\n            src: fastfetch-{{.OS}}-{{.Arch}}/usr/bin/fastfetch\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.7.0\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.7.5\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.9.1\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.12.2\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Win64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.5\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            goarch: amd64\n            format: zip\n            replacements:\n              windows: Win64\n            files:\n              - name: fastfetch\n          - goos: windows\n            goarch: arm64\n            format: zip\n            files:\n              - name: fastfetch\n            replacements:\n              windows: WinArm64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.1.1\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Win64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.6.0\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        overrides:\n          - goos: windows\n            goarch: amd64\n            format: zip\n            files:\n              - name: fastfetch\n            replacements:\n              windows: Win64\n          - goos: windows\n            goarch: arm64\n            format: zip\n            files:\n              - name: fastfetch\n            replacements:\n              windows: WinArm64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.6.3\")\n        asset: fastfetch-{{.Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Win64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.9.2\")\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: semver(\"<= 2.11.4\")\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: semver(\"<= 2.40.0\")\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n      - version_constraint: semver(\"<= 2.45.0\")\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: fastfetch-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        replacements:\n          darwin: macos\n      - version_constraint: \"true\"\n        asset: fastfetch-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: fastfetch\n            src: \"{{.AssetWithoutExt}}/usr/bin/fastfetch\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fastfetch\n        replacements:\n          arm64: aarch64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fastly/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fastly\n    repo_name: cli\n    description: A CLI for interacting with the Fastly platform\n    asset: fastly_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: fastly\n    checksum:\n      type: github_release\n      asset: fastly_{{.Version}}_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 4.6.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fastly/terrctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fastly\n    repo_name: terrctl\n    description: A command-line client for Fastly Terrarium. https://wasm.fastlylabs.com\n    asset: terrctl-{{.OS}}_{{.Arch}}-{{.Version}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: macos\n      windows: win64\n    files:\n      - name: terrctl\n        src: \"{{.OS}}-{{.Arch}}/terrctl\"\n    overrides:\n      - goos: darwin\n        goarch: amd64\n        asset: terrctl-{{.OS}}-{{.Version}}.{{.Format}}\n        files:\n          - name: terrctl\n            src: \"{{.OS}}/terrctl\"\n      - goos: windows\n        format: zip\n        asset: terrctl-{{.OS}}-{{.Version}}.{{.Format}}\n        files:\n          - name: terrctl\n            src: \"{{.OS}}/terrctl.exe\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fatedier/frp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fatedier\n    repo_name: frp\n    description: A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet\n    asset: frp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: frpc\n        src: frp_{{trimV .Version}}_{{.OS}}_{{.Arch}}/frpc\n      - name: frps\n        src: frp_{{trimV .Version}}_{{.OS}}_{{.Arch}}/frps\n    checksum:\n      type: github_release\n      asset: frp_sha256_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fe3dback/go-arch-lint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fe3dback\n    repo_name: go-arch-lint\n    description: GoLang architecture linter (checker) tool. Will check all project import path and compare with arch rules defined in yml file. Useful for hexagonal / onion / ddd / mvc and other architectural patterns. Tool can by used in your CI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: go-arch-lint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.7.3\")\n        asset: go-arch-lint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.7.5\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: go-arch-lint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ffuf/ffuf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ffuf\n    repo_name: ffuf\n    description: Fast web fuzzer written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: ffuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ffuf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: ffuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: ffuf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ffuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: ffuf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fiatjaf/jiq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fiatjaf\n    repo_name: jiq\n    description: \"jid on jq - interactive JSON query tool using jq expressions\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.6.1\"\n        asset: jiq_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: jiq_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/filebrowser/filebrowser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: filebrowser\n    repo_name: filebrowser\n    asset: \"{{.OS}}-{{.Arch}}-filebrowser.{{.Format}}\"\n    format: tar.gz\n    description: Web File Browser\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: filebrowser_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/filhodanuvem/gitql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: filhodanuvem\n    repo_name: gitql\n    asset: gitql_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: A git query language\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fioncat/otree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fioncat\n    repo_name: otree\n    description: A command line tool to view objects (JSON/YAML/TOML) in TUI tree widget\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: otree-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: \"true\"\n        asset: otree-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/firebase/firebase-tools/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: firebase\n    repo_name: firebase-tools\n    description: The Firebase Command Line Tools\n    files:\n      - name: firebase\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 7.2.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: firebase-tools-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/firecow/gitlab-ci-local/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: firecow\n    repo_name: gitlab-ci-local\n    description: Tired of pushing to test your .gitlab-ci.yml\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.9.0\")\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gitlab-ci-local\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.9.7\")\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: gz\n        rosetta2: true\n        files:\n          - name: gitlab-ci-local\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<=4.65.1\")\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gitlab-ci-local\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gitlab-ci-local-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/firecracker-microvm/firecracker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: firecracker-microvm\n    repo_name: firecracker\n    asset: firecracker-{{.Version}}-{{.Arch}}.tgz\n    description: Secure and fast microVMs for serverless computing\n    files:\n      - name: firecracker\n        src: release-{{.Version}}-{{.Arch}}/firecracker-{{.Version}}-{{.Arch}}\n      - name: jailer\n        src: release-{{.Version}}-{{.Arch}}/jailer-{{.Version}}-{{.Arch}}\n      - name: rebase-snap\n        src: release-{{.Version}}-{{.Arch}}/rebase-snap-{{.Version}}-{{.Arch}}\n      - name: seccompiler-bin\n        src: release-{{.Version}}-{{.Arch}}/seccompiler-bin-{{.Version}}-{{.Arch}}\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - linux\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256.txt\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/firecracker-microvm/firectl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: firecracker-microvm\n    repo_name: firectl\n    description: firectl is a command-line tool to run Firecracker microVMs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: firectl-{{ .Version }}\n        format: raw\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fish-shell/fish-shell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fish-shell\n    repo_name: fish-shell\n    description: The user-friendly command line shell\n    files:\n      - name: fish\n      - name: fish_indent\n      - name: fish_key_reader\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 4.0.0\")\n        # https://github.com/fish-shell/fish-shell/releases/tag/4.0.0\n        # > fish’s core code has been ported from C++ to Rust\n        no_asset: true\n      - version_constraint: Version == \"4.0.1\"\n        asset: fish-static-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          arm64: aarch64\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            asset: fish-{{.Version}}.pkg\n            format: pkg\n            files:\n              - name: fish\n                src: fish.pkg/Payload/usr/local/bin/fish\n              - name: fish_indent\n                src: fish.pkg/Payload/usr/local/bin/fish_indent\n              - name: fish_key_reader\n                src: fish.pkg/Payload/usr/local/bin/fish_key_reader\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 4.0.2\")\n        asset: fish-static-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: darwin\n            asset: fish-{{.Version}}.pkg\n            format: pkg\n            files:\n              - name: fish\n                src: fish.pkg/Payload/usr/local/bin/fish\n              - name: fish_indent\n                src: fish.pkg/Payload/usr/local/bin/fish_indent\n              - name: fish_key_reader\n                src: fish.pkg/Payload/usr/local/bin/fish_key_reader\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: fish-{{.Version}}-linux-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: fish\n        replacements:\n          arm64: aarch64\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            asset: fish-{{.Version}}.pkg\n            format: pkg\n            files:\n              - name: fish\n                src: fish.pkg/Payload/usr/local/bin/fish\n              - name: fish_indent\n                src: fish.pkg/Payload/usr/local/bin/fish_indent\n              - name: fish_key_reader\n                src: fish.pkg/Payload/usr/local/bin/fish_key_reader\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fishi0x01/vsh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fishi0x01\n    repo_name: vsh\n    description: \"vsh - HashiCorp Vault interactive shell and cli tool\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: vsh_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: vsh_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fission/fission/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fission\n    repo_name: fission\n    description: Fast and Simple Serverless Functions for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.12.0\")\n        asset: fission-cli-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.14.1\")\n        asset: fission-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.17.0-rc2\")\n        asset: fission-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.20.5\")\n        asset: fission-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.21.0\")\n        asset: fission-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: fission_{{.Version}}.intoto.jsonl\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/fission/fission/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --certificate-identity\n            - https://github.com/fission/fission/.github/workflows/release.yaml@refs/tags/{{.Version}}\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --signature\n            - https://github.com/fission/fission/releases/download/{{.Version}}/{{.Asset}}.sig\n      - version_constraint: \"true\"\n        asset: fission-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sig.bundle\n            opts:\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --certificate-identity\n              - https://github.com/fission/fission/.github/workflows/release.yaml@refs/tags/{{.Version}}\n        cosign:\n          bundle:\n            type: github_release\n            asset: \"{{.Asset}}.sig.bundle\"\n          opts:\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --certificate-identity\n            - https://github.com/fission/fission/.github/workflows/release.yaml@refs/tags/{{.Version}}\n        github_artifact_attestations:\n          signer_workflow: fission/fission/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/flatt-security/shisho/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: flatt-security\n    repo_name: shisho\n    description: Lightweight static analyzer for several programming languages\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: build-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/flosell/iam-policy-json-to-terraform/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: flosell\n    repo_name: iam-policy-json-to-terraform\n    description: Small tool to convert an IAM Policy in JSON format into a Terraform aws_iam_policy_document\n    format: raw\n    supported_envs:\n      - darwin\n      - amd64\n    asset: iam-policy-json-to-terraform_{{.OS}}_{{.Arch}}\n    replacements:\n      arm64: arm\n    overrides:\n      - goos: windows\n        asset: iam-policy-json-to-terraform.exe\n      - goos: linux\n        asset: iam-policy-json-to-terraform_amd64\n      - goos: darwin\n        goarch: amd64\n        asset: iam-policy-json-to-terraform_darwin\n      - goos: darwin\n        goarch: arm64\n        asset: iam-policy-json-to-terraform_darwin_arm\n    version_constraint: semver(\">= 1.7.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        overrides:\n          - goos: windows\n            asset: iam-policy-json-to-terraform.exe\n          - goos: linux\n            asset: iam-policy-json-to-terraform_amd64\n          - goos: darwin\n            asset: iam-policy-json-to-terraform_darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/flutter/flutter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: flutter\n    repo_name: flutter\n    description: Flutter SDK - Google's UI toolkit for building beautiful, natively compiled applications\n    version_source: github_tag\n    version_filter: Version matches \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\"\n    files:\n      - name: flutter\n        src: flutter/bin/flutter\n      - name: dart\n        src: flutter/bin/dart\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://storage.googleapis.com/flutter_infra_release/releases/{{.Vars.channel}}/{{.OS}}/flutter_{{.OS}}_{{trimV .Version}}-{{.Vars.channel}}.{{.Format}}\n        vars:\n          - name: channel\n            default: stable\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.xz\n          - goos: windows\n            goarch: arm64\n            url: https://storage.googleapis.com/flutter_infra_release/releases/{{.Vars.channel}}/{{.OS}}/flutter_{{.OS}}_{{trimV .Version}}-{{.Vars.channel}}.{{.Format}}\n          - goarch: arm64\n            url: https://storage.googleapis.com/flutter_infra_release/releases/{{.Vars.channel}}/{{.OS}}/flutter_{{.OS}}_{{.Arch}}_{{trimV .Version}}-{{.Vars.channel}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/flux-iac/tofu-controller/tfctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: flux-iac/tofu-controller/tfctl\n    type: github_release\n    repo_owner: flux-iac\n    repo_name: tofu-controller\n    aliases:\n      - name: weaveworks/tf-controller\n    description: A GitOps OpenTofu and Terraform controller for Flux\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: tfctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: tf-controller_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tf-controller_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/weaveworks/tf-controller/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tf-controller_{{trimV .Version}}_checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.16.0-rc.4\")\n        asset: tfctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: tf-controller_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tf-controller_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/flux-iac/tofu-controller/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tf-controller_{{trimV .Version}}_checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.16.0-rc.7\")\n        asset: tfctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: tofu-controller_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tofu-controller_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/flux-iac/tofu-controller/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/flux-iac/tofu-controller/releases/download/{{.Version}}/tofu-controller_{{trimV .Version}}_checksums.txt.sig\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tfctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: tofu-controller_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: tofu-controller_{{trimV .Version}}_checksums.txt.sigstore.json\n            opts:\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --certificate-identity\n              - https://github.com/flux-iac/tofu-controller/.github/workflows/release.yaml@refs/tags/{{.Version}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fluxcd/flux2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fluxcd\n    repo_name: flux2\n    description: Open and extensible continuous delivery solution for Kubernetes. Powered by GitOps Toolkit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.25.2\")\n        asset: flux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: flux\n        checksum:\n          type: github_release\n          asset: flux_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: flux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: flux\n        checksum:\n          type: github_release\n          asset: flux_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/fluxcd/flux2/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/fluxcd/flux2/releases/download/{{.Version}}/flux_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/fluxcd/flux2/releases/download/{{.Version}}/flux_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: \"true\"\n        asset: flux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: flux\n        checksum:\n          type: github_release\n          asset: flux_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/fluxcd/flux2/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/fluxcd/flux2/releases/download/{{.Version}}/flux_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/fluxcd/flux2/releases/download/{{.Version}}/flux_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: provenance.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/folbricht/desync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: folbricht\n    repo_name: desync\n    description: Alternative casync implementation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: desync_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/foresterre/cargo-msrv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: foresterre\n    repo_name: cargo-msrv\n    description: Find the minimum supported Rust version (MSRV) for your project\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: cargo-msrv-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        supported_envs:\n          - windows\n      - version_constraint: Version == \"v0.11.1-testing.1\"\n        asset: cargo-msrv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: Windows\n        supported_envs:\n          - windows\n      - version_constraint: Version == \"v0.11.1-testing.2\"\n        asset: cargo-msrv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: linux\n            format: tar\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: Version == \"v0.11.1-testing.3\"\n        asset: cargo-msrv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\") or semver(\"> 0.10.0, <= 0.12.0\") or Version in [\"v0.11.0\", \"v0.15.0\", \"v0.16.0-beta.12\", \"v0.16.0-beta.16\", \"v0.16.0-beta.21\", \"v0.17.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.14.2\") or Version == \"v0.15.1\"\n        asset: cargo-msrv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0-beta.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.16.0-beta.5\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.16.0-beta.8\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0-beta.10\")\n        no_asset: true\n      - version_constraint: Version == \"v0.16.0-beta.11\"\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0-beta.15\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0-beta.20\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.1\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.3\")\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: cargo-msrv-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-msrv\n            src: \"{{.AssetWithoutExt}}/cargo-msrv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fortio/fortio/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fortio\n    repo_name: fortio\n    asset: fortio-{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n    format: tgz\n    description: Fortio load testing library, command line tool, advanced echo server and web UI in go (golang). Allows to specify a set query-per-second load and record latency histograms and other useful stats\n    replacements:\n      windows: win\n    overrides:\n      - goos: windows\n        format: zip\n        asset: fortio_{{.OS}}_{{trimV .Version}}.{{.Format}}\n        files:\n          - name: fortio\n    files:\n      - name: fortio\n        src: usr/bin/fortio\n    supported_envs:\n      - linux\n      - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/foundry-rs/foundry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: foundry-rs\n    repo_name: foundry\n    description: Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust\n    files:\n      - name: anvil\n      - name: cast\n      - name: chisel\n      - name: forge\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version startsWith \"nightly-\"\n        asset: foundry_nightly_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          windows: win32\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: foundry_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          windows: win32\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/freshautomations/stoml/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: freshautomations\n    repo_name: stoml\n    description: Simple TOML parser for Bash\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: stoml_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: stoml_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fsaintjacques/semver-tool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: fsaintjacques\n    repo_name: semver-tool\n    description: semver bash implementation\n    supported_envs:\n      - darwin\n      - linux\n    path: src/semver\n    files:\n      - name: semver\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiapple852/trippy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiapple852\n    repo_name: trippy\n    description: A network diagnostic tool\n    files:\n      - name: trip\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        no_asset: true\n      - version_constraint: Version == \"0.6.0\"\n        asset: trippy-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: trip\n            src: \"{{.AssetWithoutExt}}/trip\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"0.7.0\"\n        asset: trippy-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: trip\n            src: \"{{.AssetWithoutExt}}/trip\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.8.0\"\n        asset: trippy-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: trip\n            src: \"{{.AssetWithoutExt}}/trip\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: trippy-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: trip\n            src: \"{{.AssetWithoutExt}}/trip\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/apprun-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: apprun-cli\n    description: CLI for sakura AppRun\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: apprun-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: apprun-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: apprun-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/awslim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: awslim\n    aliases:\n      - name: fujiwara/aws-sdk-client-go\n    description: A simplified alternative to the AWS CLI for limited use cases\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: aws-sdk-client-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n        files:\n          - name: aws-sdk-client-go\n      - version_constraint: semver(\"<= 0.0.14\")\n        asset: aws-sdk-client-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: aws-sdk-client-go\n      - version_constraint: \"true\"\n        asset: awslim_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/cfft/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: cfft\n    description: cfft is a testing tool for CloudFront Functions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: cfft_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/ecrm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: ecrm\n    description: A command line tool for managing ECR repositories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ecrm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/ecsta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: ecsta\n    description: ECS Task Assistant tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: ecsta_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: ecsta_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/greenlight/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: greenlight\n    description: greenlight is a graceful health check agent\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: greenlight_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/grpcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: grpcp\n    description: gRPC stream file transfer server/client\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: grpcp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/iam-policy-finder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: iam-policy-finder\n    description: iam-policy-finder is finder of AWS IAM Policies\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: iam-policy-finder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/kinesis-tailf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: kinesis-tailf\n    description: tail -f command for Amazon Kinesis Stream\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: kinesis-tailf-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: kinesis-tailf\n            src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: kinesis-tailf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kinesis-tailf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/knockrd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: knockrd\n    description: HTTP knocker daemon\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: knockrd_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: knockrd_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/lambroll/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: lambroll\n    description: lambroll is a minimal deployment tool for AWS Lambda\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.12.7\")\n        asset: lambroll_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lambroll\n            src: lambroll_{{.Version}}_{{.OS}}_{{.Arch}}/lambroll\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.14.7\")\n        asset: lambroll_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lambroll\n            src: lambroll_{{.Version}}_{{.OS}}_{{.Arch}}/lambroll\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: lambroll_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/lamux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: lamux\n    description: Lamux is a HTTP multiplexer for AWS Lambda Function aliases\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lamux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/maprobe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: maprobe\n    description: Mackerel external probe agent\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: maprobe_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: maprobe\n            src: \"{{.AssetWithoutExt}}/maprobe\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: maprobe_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: maprobe\n            src: \"{{.AssetWithoutExt}}/maprobe\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.7\")\n        asset: maprobe_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: maprobe\n            src: \"{{.AssetWithoutExt}}/maprobe\"\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: maprobe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/riex/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: riex\n    description: AWS RI expiration detector\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: riex_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/s3mover/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: s3mover\n    description: s3mover is an agent for moving local files to Amazon S3\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: s3mover_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/stretcher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: stretcher\n    description: Deployment tool with consul/serf event notification\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: stretcher-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: stretcher\n            src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: stretcher-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: stretcher\n            src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/tfstate-lookup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: tfstate-lookup\n    description: Lookup resource attributes in tfstate\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: tfstate-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: tfstate-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.14\")\n        asset: tfstate-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: tfstate-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tfstate-lookup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/tncl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: tncl\n    description: tncl is a tiny \"nc -l\" implementation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tncl-{{.Arch}}-{{.OS}}-musl\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fujiwara/tracer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fujiwara\n    repo_name: tracer\n    description: ECS task event/log tracer CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tracer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fukubaka0825/tffmtmd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fukubaka0825\n    repo_name: tffmtmd\n    description: tffmtmd formats HCL source code block in Markdown. detects fenced code & formats code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tffmtmd_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tffmtmd_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fullstorydev/grpcui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fullstorydev\n    repo_name: grpcui\n    description: An interactive web UI for gRPC, along the lines of postman\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: grpcui_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcui_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: grpcui_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcui_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fullstorydev/grpcurl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: fullstorydev\n    repo_name: grpcurl\n    description: \"Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.3.2\", \"v1.5.1\"]\n        no_asset: true\n      - version_constraint: Version == \"v1.8.5\"\n        asset: grpcurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcurl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: grpcurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcurl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.8.2\")\n        asset: grpcurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcurl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.8.4\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: grpcurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        checksum:\n          type: github_release\n          asset: grpcurl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/funbiscuit/spacedisplay-rs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: funbiscuit\n    repo_name: spacedisplay-rs\n    description: Fast and lightweight tool to scan your disk space\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: spacedisplay-{{.Arch}}_{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: spacedisplay-{{.OS}}\n        replacements:\n          windows: win64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        files:\n          - name: spacedisplay\n            src: spacedisplay-rs\n      - version_constraint: \"true\"\n        asset: spacedisplay-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: spacedisplay-{{.Arch}}_{{.OS}}\n        replacements:\n          darwin: macos\n          windows: win64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: spacedisplay\n            src: spacedisplay-rs\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/future-architect/tftarget/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: future-architect\n    repo_name: tftarget\n    description: tftarget is a CLI tool for Terraform ( plan | apply | destroy ) with target option. You can interactivity select resource to ( plan | apply | destroy )  with target option\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.0.5\", \"v0.0.6\", \"v0.0.8\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: tftarget_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tftarget_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/fwdcloudsec/granted/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: fwdcloudsec\n    repo_name: granted\n    aliases:\n      - name: common-fate/granted\n    description: The easiest way to access your cloud\n    url: https://releases.commonfate.io/granted/{{.Version}}/granted_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: granted\n      - name: assume\n      - name: assumego\n    replacements:\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        format: zip\n      - goos: darwin\n        files:\n          - name: granted\n          - name: assume\n          - name: assumego\n            src: granted\n            link: assumego\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/g-plane/pnpm-shell-completion/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: g-plane\n    repo_name: pnpm-shell-completion\n    description: |\n      Complete your pnpm command fastly\n\n      ## Set up\n\n      You need to execute a script within the running shell's process.\n      For details, please see the document.\n\n      https://github.com/g-plane/pnpm-shell-completion#installation\n\n      Zsh:\n\n      ```sh\n      local plugin_path_dir=$(dirname $(aqua which pnpm-shell-completion))\n      local plugin_path=\"${plugin_path_dir}/pnpm-shell-completion.plugin.zsh\"\n      source $plugin_path\n      ```\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: pnpm-shell-completion_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.3.0\"\n        asset: pnpm-shell-completion_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pnpm-shell-completion_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            asset: pnpm-shell-completion_pwsh_{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gabeduke/kubectl-iexec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gabeduke\n    repo_name: kubectl-iexec\n    description: Kubectl plugin to interactively exec into a pod\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: kubectl-iexec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: kubectl-iexec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"1.5.0-alpha1\"\n        no_asset: true\n      - version_constraint: Version == \"v1.6.1\"\n        asset: kubectl-iexec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: kubectl-iexec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.18.0\")\n        asset: kubectl-iexec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.19.11\")\n        asset: kubectl-iexec_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"1.19.12\"\n        asset: kubectl-iexec_.{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          enabled: false # Disable as the checksum file is broken\n      - version_constraint: \"true\"\n        asset: kubectl-iexec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gabrie30/ghorg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gabrie30\n    repo_name: ghorg\n    description: Quickly clone an entire org/users repositories into one directory - Supports GitHub, GitLab, Bitbucket, and more\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.7.4\")\n        no_asset: true\n      - version_constraint: Version == \"v1.7.5\"\n        asset: ghorg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: ghorg_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ghorg_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gardener/docforge/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gardener\n    repo_name: docforge\n    asset: docforge-{{.OS}}-{{.Arch}}\n    format: raw\n    description: Scalable build tool for distributed documentation sources\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gcla/termshark/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gcla\n    repo_name: termshark\n    description: A terminal UI for tshark, inspired by Wireshark\n    asset: termshark_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x64\n      darwin: macOS\n    files:\n      - name: termshark\n        src: termshark_{{trimV .Version}}_{{.OS}}_{{.Arch}}/termshark\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gdubicki/ets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gdubicki\n    repo_name: ets\n    description: A maintained fork of zmwangx's command output timestamper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ets_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gefyrahq/gefyra/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gefyrahq\n    repo_name: gefyra\n    description: \"Blazingly-fast :rocket:, rock-solid, local application development :arrow_right: with Kubernetes\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.7\")\n        asset: gefyra-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.6.8\"\n        no_asset: true\n      - version_constraint: Version == \"0.6.9\"\n        asset: gefyra-0.6.7-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: gefyra-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.4\")\n        asset: gefyra-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            replacements:\n              amd64: x86_64\n            files:\n              - name: gefyra\n                src: dist/gefyra\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.3\")\n        asset: gefyra-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: gefyra-{{.Version}}-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            replacements:\n              amd64: x86_64\n            files:\n              - name: gefyra\n                src: dist/gefyra\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gefyra-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            asset: gefyra-{{.Version}}-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            replacements:\n              amd64: x86_64\n            files:\n              - name: gefyra\n                src: dist-exe/gefyra.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/genuinetools/amicontained/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: genuinetools\n    repo_name: amicontained\n    description: Container introspection tool. Find out what container runtime is being used as well as features available\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.5\")\n        asset: amicontained-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: amicontained-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/genuinetools/img/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: genuinetools\n    repo_name: img\n    description: Standalone, daemon-less, unprivileged Dockerfile and OCI compatible container image builder\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: img-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/genuinetools/reg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: genuinetools\n    repo_name: reg\n    description: Docker registry v2 command line client and repo listing generator with security checks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: reg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: Version == \"v0.15.4\"\n        asset: reg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: reg-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/geofffranks/spruce/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: geofffranks\n    repo_name: spruce\n    description: Standalone, daemon-less, unprivileged Dockerfile and OCI compatible container image builder\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: raw\n    version_constraint: semver(\">= 1.30.1\")\n    asset: spruce-{{.OS}}-{{.Arch}}\n    complete_windows_ext: false\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha1\"\n      algorithm: sha1\n    version_overrides:\n      - version_constraint: semver(\"= 1.30.0\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: \"true\"\n        complete_windows_ext: true\n        checksum:\n          enabled: false\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gesquive/git-user/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gesquive\n    repo_name: git-user\n    asset: git-user_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Git plugin that allows you to save multiple user profiles and set them as project defaults\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\">= 2.0.6\")\n    replacements:\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: git-user_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\">= 2.0.3\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: x64\n          darwin: osx\n        asset: git-user-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: git-user\n            src: \"git-user-{{.Version}}-{{.OS}}-{{.Arch}}/git-user\"\n        checksum:\n          enabled: false\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: amd64\n        asset: git-user-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: git-user\n            src: \"{{.OS}}-{{.Arch}}/git-user\"\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getanteon/anteon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getanteon\n    repo_name: anteon\n    description: Anteon (formerly Ddosify) - Effortless Kubernetes Monitoring and Performance Testing. Available on CLI, Self-Hosted, and Cloud\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: ddosify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: ddosify\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.3\")\n        asset: ddosify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: ddosify\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ddosify_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ddosify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: ddosify\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ddosify_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getgauge/gauge/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getgauge\n    repo_name: gauge\n    asset: gauge-{{trimV .Version}}-{{.OS}}.{{.Arch}}.zip\n    description: Light weight cross-platform test automation\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getporter/porter/porter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: getporter/porter/porter\n    type: github_release\n    repo_owner: getporter\n    repo_name: porter\n    description: Porter enables you to package your application artifact, client tools, configuration and deployment logic together as an installer that you can distribute, and install with a single command\n    asset: porter-{{.OS}}-{{.Arch}}\n    format: raw\n    complete_windows_ext: true\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getsavvyinc/savvy-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getsavvyinc\n    repo_name: savvy-cli\n    description: Create, share, and run runbooks from your terminal\n    files:\n      - name: savvy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: savvy_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: savvy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: savvy_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: savvy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getsentry/sentry-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getsentry\n    repo_name: sentry-cli\n    description: A command line utility to work with Sentry\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: sentry-cli-{{.OS}}-{{.Arch}}\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n      amd64: x86_64\n    overrides:\n      - goos: linux\n        replacements:\n          arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getsops/sops/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getsops\n    repo_name: sops\n    aliases:\n      - name: mozilla/sops\n    description: Simple and flexible tool for managing secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.7.1\")\n        asset: sops-{{.Version}}.{{.OS}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: sops-{{.Version}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.7.3\")\n        asset: sops-{{.Version}}.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: sops-{{.Version}}\n      - version_constraint: semver(\"<= 3.9.4\")\n        asset: sops-{{.Version}}.{{.OS}}.{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sops-{{.Version}}.checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/getsops/sops/releases/download/{{.Version}}/sops-{{.Version}}.checksums.pem\n              - --signature\n              - https://github.com/getsops/sops/releases/download/{{.Version}}/sops-{{.Version}}.checksums.sig\n              - --certificate-identity-regexp\n              - https://github.com/getsops\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        slsa_provenance:\n          type: github_release\n          asset: sops-{{.Version}}.intoto.jsonl\n        overrides:\n          - goos: windows\n            asset: sops-{{.Version}}\n      - version_constraint: \"true\"\n        asset: sops-{{.Version}}.{{.OS}}.{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sops-{{.Version}}.checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/getsops/sops/releases/download/{{.Version}}/sops-{{.Version}}.checksums.pem\n              - --signature\n              - https://github.com/getsops/sops/releases/download/{{.Version}}/sops-{{.Version}}.checksums.sig\n              - --certificate-identity-regexp\n              - https://github.com/getsops\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        slsa_provenance:\n          type: github_release\n          asset: sops-{{.Version}}.intoto.jsonl\n        overrides:\n          - goos: windows\n            asset: sops-{{.Version}}.{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/getzola/zola/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: getzola\n    repo_name: zola\n    description: A fast static site generator in a single binary with everything built-in. https://www.getzola.org\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.2\"\n        asset: gutenberg-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: gutenberg\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: gutenberg-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: gutenberg\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: gutenberg-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: gutenberg\n      - version_constraint: Version == \"v0.9.0\"\n        asset: zola-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.17.2\")\n        asset: zola-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 0.20.0\")\n        asset: zola-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: zola-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: getzola/zola/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ginuerzh/gost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ginuerzh\n    repo_name: gost\n    description: GO Simple Tunnel - a simple tunnel written in golang\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"2.1-rc1\", \"v2.3-dev\"]\n        no_asset: true\n      - version_constraint: Version in [\"2.0\", \"2.1\", \"v2.2\"]\n        asset: gost_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}/gost\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gost\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.4-dev\"\n        asset: gost_{{trimV .Version}}20170303_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}/gost\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gost\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.11.2\"\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-{{.OS}}-{{.Arch}}.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0\")\n        asset: gost_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}/gost\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gost\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.2-rc2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.8.1\")\n        asset: gost_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}/gost\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: gost\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.11.1\")\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-{{.OS}}-{{.Arch}}.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.11.5\")\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        files:\n          - name: gost\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-{{.OS}}-{{.Arch}}.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: gost_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/git-bug/git-bug/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: git-bug\n    repo_name: git-bug\n    aliases:\n      - name: MichaelMure/git-bug\n    description: Distributed, offline-first bug tracker embedded in git, with bridges\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: git-bug_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/git-chglog/git-chglog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: git-chglog\n    repo_name: git-chglog\n    description: CHANGELOG generator implemented in Go (Golang)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: git-chglog_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.2\")\n        asset: git-chglog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: git-chglog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: git-chglog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/git-lfs/git-lfs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: git-lfs\n    repo_name: git-lfs\n    asset: git-lfs-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n    description: Git extension for versioning large files\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    version_constraint: semver(\">= 3.2.0\")\n    files:\n      - name: git-lfs\n        src: git-lfs-{{trimV .Version}}/git-lfs\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: git-lfs\n            src: git-lfs\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/git-town/git-town/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: git-town\n    repo_name: git-town\n    description: Git workflow automation to keep branches in sync and reduce merge conflicts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 7.3.0\")\n        asset: git-town-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 7.6.0\")\n        asset: git-town_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: macos\n          amd64: intel_64\n          arm64: arm_64\n      - version_constraint: semver(\"<= 10.0.2\")\n        asset: git-town_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: macos\n          amd64: intel_64\n          arm64: arm_64\n      - version_constraint: \"true\"\n        asset: git-town_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: macos\n          arm64: arm_64\n          amd64: intel_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gitea.com/gitea/tea/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: gitea.com/gitea/tea\n    type: http\n    description: Command line tool to interact with Gitea servers\n    link: https://gitea.com/gitea/tea\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        format: xz\n        url: https://gitea.com/gitea/tea/releases/download/{{.Version}}/tea-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        windows_arm_emulation: true\n        files:\n          - name: tea\n            src: tea-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        checksum:\n          type: http\n          url: https://gitea.com/gitea/tea/releases/download/{{.Version}}/tea-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            url: https://gitea.com/gitea/tea/releases/download/{{.Version}}/tea-{{trimV .Version}}-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n            checksum:\n              type: http\n              url: https://gitea.com/gitea/tea/releases/download/{{.Version}}/tea-{{trimV .Version}}-{{.OS}}-{{.Arch}}.exe.{{.Format}}.sha256\n              algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/copilot-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: copilot-cli\n    description: GitHub Copilot CLI brings the power of Copilot coding agent directly to your terminal\n    files:\n      - name: copilot\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.366-3\")\n        no_asset: true\n      - version_constraint: Version == \"v0.0.366-5\"\n        asset: copilot-copilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: copilot\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: semver(\"<= 0.0.370-0\")\n        asset: copilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: copilot\n        replacements:\n          amd64: x64\n          windows: win32\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: copilot-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: copilot\n        replacements:\n          amd64: x64\n          windows: win32\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: SHA256SUMS.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/copilot-language-server-release/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: copilot-language-server-release\n    description: The Copilot Language Server enables any editor or IDE to integrate with GitHub Copilot via the language server protocol\n    files:\n      - name: copilot-language-server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.276.0\")\n        asset: copilot-language-server-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          windows: win32\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n        files:\n          - name: copilot-language-server\n      - version_constraint: \"true\"\n        asset: copilot-language-server-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          windows: win32\n          amd64: x64\n        files:\n          - name: copilot-language-server\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/gh-ost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: gh-ost\n    description: GitHub's Online Schema-migration Tool for MySQL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.48\")\n        error_message: \"Versions <= 1.0.48 are not supported. Please use version >= v1.0.49\"\n      - version_constraint: Version == \"v1.0.49\"\n        asset: gh-ost-binary-{{.OS}}-20200209110835.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: gh-ost-binary-{{.OS}}-20200209114711.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.0\"\n        asset: gh-ost-binary-{{.OS}}-20200828160625.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: gh-ost-binary-{{.OS}}-20200828140552.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.1\"\n        asset: gh-ost-binary-{{.OS}}-20210503150942.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: gh-ost-binary-{{.OS}}-20210503171035.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.2\"\n        asset: gh-ost-binary-{{.OS}}-20210617134741.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: gh-ost-binary-{{.OS}}-20210617155835.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.3\"\n        asset: gh-ost-binary-{{.OS}}-20220225143057.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.4\"\n        asset: gh-ost-binary-{{.OS}}-{{.Arch}}-20220225143506.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: gh-ost-binary-{{.OS}}-20220225143506.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: gh-ost-binary-{{.OS}}-{{.Arch}}-20220311164158.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.1.5\"\n        asset: gh-ost-binary-{{.OS}}-{{.Arch}}-20220707162303.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.1.6\"\n        asset: gh-ost-binary-{{.OS}}-{{.Arch}}-20231207144046.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: gh-ost-binary-{{.OS}}-{{.Arch}}-20241219160321.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/git-sizer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: git-sizer\n    description: Compute various size metrics for a Git repository, flagging those that might cause problems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: git-sizer-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: git-sizer-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/github-mcp-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: github-mcp-server\n    description: GitHub's official MCP Server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: github-mcp-server_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: github-mcp-server_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: github-mcp-server_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: github-mcp-server_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: github/github-mcp-server/.github/workflows/goreleaser.yml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github/licensed/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github\n    repo_name: licensed\n    asset: licensed-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: A Ruby gem to cache and verify the licenses of dependencies\n    replacements:\n      amd64: x64\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    version_constraint: semver(\"< 4.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 4.0.0\")\n        error_message: |\n          https://github.com/github/licensed/issues/585\n\n          Licensed v4 no longer provides a self-contained executable build of licensed\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github-release/github-release/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: github-release\n    repo_name: github-release\n    asset: \"{{.OS}}-{{.Arch}}-github-release.{{.Format}}\"\n    format: bz2\n    description: Commandline app to create and edit releases on Github (and upload artifacts)\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: github-release\n            src: bin/windows/{{.Arch}}/github-release.exe\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: github-release\n        src: \"{{.OS}}-{{.Arch}}-github-release\"\n    version_constraint: semver(\">= 0.8.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.5.0\")\n        format: tar.bz2\n        files:\n          - name: github-release\n            src: bin/{{.OS}}/{{.Arch}}/github-release\n      - version_constraint: \"true\"\n        supported_envs: []\n        rosetta2: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/github.com/zeromicro/go-zero/tools/goctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: github.com/zeromicro/go-zero/tools/goctl\n    type: go_install\n    repo_owner: zeromicro\n    repo_name: go-zero\n    description: A cloud-native Go microservices framework with cli tool for productivity\n    path: github.com/zeromicro/go-zero/tools/goctl\n    version_filter: Version startsWith \"tools/goctl/\"\n    files:\n      - name: goctl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gitlab.com/gitlab-org/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: gitlab.com/gitlab-org/cli\n    # TODO: Support GitLab\n    # repo_owner: gitlab-org\n    # repo_name: cli\n    aliases:\n      - name: profclems/glab\n    type: http\n    link: https://gitlab.com/gitlab-org/cli\n    description: A GitLab CLI tool bringing GitLab to your command line\n    files:\n      - name: glab\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.22.0\")\n        type: github_release\n        repo_owner: profclems\n        repo_name: glab\n        rosetta2: true\n        windows_arm_emulation: true\n        asset: glab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          darwin: macOS\n          linux: Linux\n          386: i386\n          amd64: x86_64\n          windows: Windows\n        files:\n          - name: glab\n            src: bin/glab\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.46.1\")\n        url: https://gitlab.com/gitlab-org/cli/-/releases/{{.Version}}/downloads/glab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: glab\n            src: bin/glab\n        replacements:\n          linux: Linux\n          windows: Windows\n          darwin: macOS\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        url: https://gitlab.com/gitlab-org/cli/-/releases/{{.Version}}/downloads/glab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: glab\n            src: bin/glab\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gitleaks/gitleaks/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gitleaks\n    repo_name: gitleaks\n    aliases:\n      - name: zricethezav/gitleaks\n    description: Find secrets with Gitleaks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\") || Version == \"v1.2.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.4.0\"\n        asset: gitleaks-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 7.6.1\")\n        asset: gitleaks-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 8.1.2\")\n        asset: gitleaks_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: gitleaks_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 8.2.7\")\n        asset: gitleaks_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: gitleaks_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 8.17.0\")\n        asset: gitleaks_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: gitleaks_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gitleaks_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: gitleaks_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gittools/gitversion/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gittools\n    repo_name: gitversion\n    description: From git log to SemVer in no time\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gitversion-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n          - windows\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gittower/git-flow-next/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gittower\n    repo_name: git-flow-next\n    description: A modern reimplementation of git-flow in Go that offers greater flexibility while maintaining backward compatibility with the original git-flow and git-flow-avh\n    files:\n      - name: git-flow\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0-alpha.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: git-flow-next-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: git-flow\n            src: git-flow-{{.Version}}-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: git-flow-next-{{.Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gittuf/gittuf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gittuf\n    repo_name: gittuf\n    description: A security layer for Git repositories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gittuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: gittuf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            cosign:\n              opts:\n                - --certificate-identity-regexp\n                - \"https://github\\\\.com/gittuf/gittuf/\\\\.github/workflows/release\\\\.ya?ml@.*\"\n                - --certificate-oidc-issuer\n                - \"https://token.actions.githubusercontent.com\"\n                - --signature\n                - https://github.com/gittuf/gittuf/releases/download/{{.Version}}/gittuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.exe.sig\n                - --certificate\n                - https://github.com/gittuf/gittuf/releases/download/{{.Version}}/gittuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.exe.pem\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/gittuf/gittuf/\\\\.github/workflows/release\\\\.ya?ml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/gittuf/gittuf/releases/download/{{.Version}}/gittuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.sig\n            - --certificate\n            - https://github.com/gittuf/gittuf/releases/download/{{.Version}}/gittuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gitui-org/gitui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gitui-org\n    repo_name: gitui\n    aliases:\n      - name: extrawurst/gitui\n    description: Blazing  fast terminal-ui for git written in rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.1.8\"\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.11\")\n        asset: gitui-{{.OS}}-musl.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.9.0\"\n        asset: gitui-{{.OS}}-musl.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.9.1\"\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.10.0\"\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v0.10.1\"\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.11.0-rc1\"\n        asset: gitui-{{.OS}}-musl.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.12.0-rc1\"\n        asset: gitui-{{.OS}}-musl.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.20.0\"\n        asset: gitui-{{.OS}}-musl.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.25.2\")\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: gitui-{{.OS}}-arm.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            asset: gitui-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n      - version_constraint: Version == \"v0.26.0\"\n        asset: gitui-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: gitui-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: gitui-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            asset: gitui-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gleam-lang/gleam/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gleam-lang\n    repo_name: gleam\n    description: A friendly language for building type-safe, scalable systems\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha512\"\n      algorithm: sha512\n    version_constraint: semver(\">= 0.23.0\")\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: gleam-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - amd64\n        asset: gleam-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: gleam-{{.Version}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            asset: gleam-{{.Version}}-windows-64bit.{{.Format}}\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/glossia.ai/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    name: glossia.ai/cli\n    description: Localize like you ship software\n    link: https://glossia.ai/docs/reference/cli\n    version_prefix: cli-v\n    windows_arm_emulation: true\n    url: https://glossia-releases.t3.storage.dev/cli/{{.SemVer}}/glossia-{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: glossia\n    replacements:\n      amd64: x64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: http\n      url: https://glossia-releases.t3.storage.dev/cli/{{.SemVer}}/SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-acme/lego/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-acme\n    repo_name: lego\n    description: Let's Encrypt/ACME client and library written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: lego_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: Version == \"v4.4.0\"\n        asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}v5.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: lego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: darwin\n            format: tar.gz\n            asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            goarch: amd64\n            asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            goarch: arm64\n            replacements:\n              arm64: arm\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: lego_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lego\n            src: lego/lego\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        overrides:\n          - goos: linux\n            format: tar.xz\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: lego_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lego\n            src: lego_{{.OS}}_{{.Arch}}\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.xz\n      - version_constraint: semver(\"<= 4.2.0\")\n        asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 4.3.1\")\n        asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 4.30.1\")\n        asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: lego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: lego_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: lego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: go-acme/lego/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-delve/delve/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: go-delve\n    repo_name: delve\n    description: Delve is a debugger for the Go programming language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        path: github.com/go-delve/delve/cmd/dlv\n        files:\n          - name: dlv\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-gost/gost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-gost\n    repo_name: gost\n    description: GO Simple Tunnel - a simple tunnel written in golang\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.0-beta.2\")\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: gost\n            src: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-windows-{{.Arch}}.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.0-beta.6\")\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        files:\n          - name: gost\n            src: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-windows-{{.Arch}}.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.0.0-rc.4\")\n        asset: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: gz\n        files:\n          - name: gost\n            src: gost-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n                src: gost-windows-{{.Arch}}.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: gost_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: gost\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-jira/jira/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-jira\n    repo_name: jira\n    description: simple jira command line client in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.12\")\n        asset: jira-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: jira-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.7\")\n        asset: jira-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.20\")\n        asset: jira-{{.OS}}-10.6-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: jira-{{.OS}}-{{.Arch}}\n          - goos: windows\n            asset: jira-{{.OS}}-4.0-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: jira-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-semantic-release/semantic-release/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-semantic-release\n    repo_name: semantic-release\n    description: semantic-release written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v2.14.0\", \"v2.22.0\", \"v2.22.1\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: semantic-release_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.13.0\")\n        asset: semantic-release_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: semantic-release_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.14.3\")\n        asset: semantic-release_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: semantic-release_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: semantic-release_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: semantic-release_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-simpler/goversion/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-simpler\n    repo_name: goversion\n    description: Easily switch between multiple Go versions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: goversion_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: goversion_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-simpler/sloglint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-simpler\n    repo_name: sloglint\n    description: Ensure consistent code style when using log/slog\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sloglint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sloglint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-swagger/go-swagger/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-swagger\n    repo_name: go-swagger\n    asset: swagger_{{.OS}}_{{.Arch}}\n    format: raw\n    description: Swagger 2.0 implementation for go\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: swagger\n    checksum:\n      type: github_release\n      asset: sha256sum.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-task/task/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-task\n    repo_name: task\n    description: A task runner / simpler Make alternative written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.3.0\"\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.3.1\"\n        asset: task_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.4\")\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: task_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.1\")\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.7.0\")\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: task_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: task_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-to-k/cls3/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-to-k\n    repo_name: cls3\n    description: The CLI tool \"cls3\" is to CLear S3 Buckets. It empties (so deletes all objects and versions/delete-markers in) S3 Buckets or deletes the buckets themselves\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cls3_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-to-k/delstack/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-to-k\n    repo_name: delstack\n    description: The CLI tool to force delete the entire AWS CloudFormation stack, even if it contains resources that fail to delete by the CloudFormation delete operation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: delstack_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/go-to-k/lamver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: go-to-k\n    repo_name: lamver\n    description: CLI tool to search AWS Lambda runtime and versions across regions\n    asset: lamver_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.4.2\")\n    version_overrides:\n      - version_constraint: Version == \"v0.4.1\"\n        asset: lamver_.{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.4.1\")\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goark/depm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goark\n    repo_name: depm\n    description: Visualize depndency packages and modules\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: depm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: depm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: depm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: depm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.6.5\")\n        asset: depm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: depm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: depm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: depm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goark/gimei-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goark\n    repo_name: gimei-cli\n    description: 姓名・住所データ生成ツール\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gimei-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gimei-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goark/gnkf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goark\n    repo_name: gnkf\n    description: Network Kanji Filter by Golang\n    asset: gnkf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: 64bit\n      arm64: ARM64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: gnkf_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.7.5\")\n    version_overrides:\n      - version_constraint: Version == \"v0.7.4\"\n        asset: gnkf_.{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        checksum:\n          enabled: false # checksum file was broken. https://github.com/aquaproj/aqua-registry/pull/10446#issuecomment-1455275091\n      - version_constraint: semver(\">= 0.6.0\")\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\">= 0.4.0\")\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: arm64\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\"< 0.4.0\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goccy/bigquery-emulator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goccy\n    repo_name: bigquery-emulator\n    description: BigQuery emulator server implemented in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2\"\n        asset: bigquery-emulator-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: bigquery-emulator-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goccy/go-yaml/ycat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: goccy/go-yaml/ycat\n    type: go_build\n    repo_owner: goccy\n    repo_name: go-yaml\n    description: Print yaml file with color\n    files:\n      - name: ycat\n        dir: go-yaml-{{trimV .Version}}/cmd/ycat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goccy/kubetest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: goccy\n    repo_name: kubetest\n    description: A CLI for distributed execution of tasks on Kubernetes\n    path: github.com/goccy/kubetest/cmd/kubetest\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/godotengine/godot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: godotengine\n    repo_name: godot\n    description: Godot Engine – Multi-platform 2D and 3D game engine\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0-stable\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.0.2-stable\")\n        asset: Godot_v{{replace \"-\" \"_\" .Version}}_{{.OS}}.exe.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          windows: win64\n        supported_envs:\n          - windows\n      - version_constraint: Version == \"2.0.3-stable\"\n        asset: Godot_v{{replace \"-\" \"_\" .Version}}_{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx64\n          windows: win64\n        overrides:\n          - goos: darwin\n            files:\n              - name: godot\n                src: Godot64.app/Contents/MacOS/Godot\n            replacements:\n              amd64: x64\n          - goos: windows\n            asset: Godot_v{{replace \"-\" \"_\" .Version}}_{{.OS}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: Version == \"2.0.4.1-stable\"\n        asset: Godot_v{{replace \"-\" \"_\" .Version}}_{{.OS}}.fat.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: windows\n            asset: Godot_v{{replace \"-\" \"_\" .Version}}_{{.OS}}.exe.{{.Format}}\n          - goos: darwin\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.0.6-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.fat.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: darwin\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.2.3-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.64.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx\n          windows: win64\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: darwin\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.5.3-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.universal.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx\n          windows: win64\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: darwin\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.6.1-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: osx\n          windows: win64\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: darwin\n            asset: Godot_v{{.Version}}_{{.OS}}.universal.{{.Format}}\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n        supported_envs:\n          - linux/arm64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 4.1.4-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n        format: zip\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n          windows: win64\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            asset: Godot_v{{.Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: Godot_v{{.Version}}_{{.OS}}.universal.{{.Format}}\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.2.2-stable\")\n        asset: Godot_v{{.Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        windows_arm_emulation: true\n        format: zip\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n          windows: win64\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: Godot_v{{.Version}}_{{.OS}}.universal.{{.Format}}\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: Godot_v{{.Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: godot\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: SHA512-SUMS.txt\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: Godot_v{{.Version}}_{{.OS}}.universal.{{.Format}}\n            files:\n              - name: godot\n                src: Godot.app/Contents/MacOS/Godot\n          - goos: windows\n            goarch: amd64\n            asset: Godot_v{{.Version}}_{{.OS}}.exe.{{.Format}}\n            replacements:\n              windows: win64\n          - goos: windows\n            goarch: arm64\n            asset: Godot_v{{.Version}}_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goforj/wire/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: goforj\n    repo_name: wire\n    description: Compile-time Dependency Injection for Go\n    path: github.com/goforj/wire/cmd/wire\n    version_constraint: \"false\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gogs/gogs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gogs\n    repo_name: gogs\n    description: Gogs is a painless self-hosted Git service\n    files:\n      - name: gogs\n        src: gogs/gogs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.12.4-rc.1\", \"v0.12.5-rc.1\", \"v0.12.6-rc.1\", \"v0.12.7-rc.1\", \"v0.12.8-rc.1\", \"v0.12.9-rc.1\", \"v0.12.10-rc.1\", \"v0.12.11-rc.1\", \"v0.13.0-rc.1\", \"v0.13.3-rc.1\", \"v0.14.0\", \"latest-commit-build\", \"release-archive-testing\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.3.1\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.5.11\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.12.0\"\n        type: http\n        url: https://dl.gogs.io/{{trimV .Version}}/gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.12.3\"\n        asset: gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: armv8\n      - version_constraint: Version in [\"v0.12.4\", \"v0.12.5\", \"v0.12.6\"]\n        asset: gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: armv8\n      - version_constraint: Version in [\"v0.12.7\", \"v0.12.8\", \"v0.12.9\", \"v0.12.10\", \"v0.12.11\", \"v0.13.0\", \"v0.13.2\", \"v0.13.3\", \"v0.13.4\"]\n        asset: gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: armv8\n      - version_constraint: Version in [\"v0.14.0-rc.1\", \"v0.14.1-rc.1\"]\n        asset: gogs_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.4.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.15\")\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.97\")\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.91\")\n        type: http\n        url: https://dl.gogs.io/{{trimV .Version}}/gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: armv5\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.12.2\")\n        asset: gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.4-rc.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gogs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: http\n          url: https://dl.gogs.io/{{trimV .Version}}/checksum_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goharbor/harbor-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goharbor\n    repo_name: harbor-cli\n    description: \"[Sandbox] Official Harbor CLI\"\n    files:\n      - name: harbor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.0.3\", \"v0.0.5\", \"v0.0.13\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.4\"\n        asset: harbor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: harbor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: harbor-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: harbor\n            src: harbor-cli\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gohugoio/hugo/hugo-extended/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: gohugoio/hugo/hugo-extended\n    type: github_release\n    repo_owner: gohugoio\n    repo_name: hugo\n    description: The world’s fastest framework for building websites\n    files:\n      - name: hugo\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.139.5\"\n        no_asset: true\n      - version_constraint: Version == \"v0.88.0\"\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.88.1\"\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.89.0\"\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: hugo_extended_{{trimV .Version}}_{{.OS}}-all.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.80.0\")\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.101.0\")\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.102.3\")\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n            asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.152.2\")\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: hugo_extended_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hugo_extended_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: pkg\n            asset: hugo_extended_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n            files:\n              - name: hugo\n                src: Payload/hugo\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gohugoio/hugo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gohugoio\n    repo_name: hugo\n    description: The world’s fastest framework for building websites\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.139.5\"\n        no_asset: true\n      - version_constraint: Version == \"v0.88.0\"\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: ARM\n      - version_constraint: Version == \"v0.88.1\"\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: ARM\n      - version_constraint: Version == \"v0.89.0\"\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: hugo_{{trimV .Version}}_{{.OS}}-all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.80.0\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.84.0\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.87.0\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: ARM\n      - version_constraint: semver(\"<= 0.101.0\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.102.3\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: hugo_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.152.2\")\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: hugo_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hugo_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hugo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: pkg\n            asset: hugo_{{trimV .Version}}_{{.OS}}-universal.{{.Format}}\n            files:\n              - name: hugo\n                src: Payload/hugo\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gojuno/minimock/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gojuno\n    repo_name: minimock\n    description: Powerful mock generation tool for Go programming language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.9.2\")\n        asset: minimock_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.1.4\")\n        asset: minimock_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.8\")\n        asset: minimock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.10\")\n        asset: minimock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.1.3\")\n        asset: minimock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.3.1\")\n        asset: minimock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: minimock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gokcehan/lf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gokcehan\n    repo_name: lf\n    description: Terminal file manager\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    asset: lf-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - repo_owner: golang\n    repo_name: go\n    type: http\n    url: https://golang.org/dl/go{{trimPrefix \"go\" .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n    description: The Go programming language\n    format: tar.gz\n    version_source: github_tag\n    version_filter: Version startsWith \"go\" and not (Version contains \"rc\" or Version contains \"beta\")\n    files:\n      - name: go\n        src: go/bin/go\n      - name: gofmt\n        src: go/bin/gofmt\n    overrides:\n      - goos: windows\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/mock/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: golang\n    repo_name: mock\n    asset: mock_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: GoMock is a mocking framework for the Go programming language\n    files:\n      - name: mockgen\n        src: mock_{{trimV .Version}}_{{.OS}}_{{.Arch}}/mockgen\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: mock_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/godoc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/godoc\n    repo_owner: golang\n    repo_name: tools\n    description: Godoc extracts and generates documentation for Go programs\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/godoc\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 0.37.0\")\n        error_message: |\n          Versions >= 0.37.0 are not supported.\n          Please use `go doc -http` instead.\n          https://github.com/golang/go/issues/59056#issuecomment-3254809429\n      - version_constraint: \"true\"\n        path: golang.org/x/tools/cmd/godoc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/goimports/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/goimports\n    aliases: # Set aliases to keep the compatibility\n      - name: golang.org/x/tools/cmd/goimports\n    path: golang.org/x/tools/cmd/goimports\n    repo_owner: golang\n    repo_name: tools\n    description: updates your Go import lines, adding missing ones and removing unreferenced ones\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/goimports\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    files:\n      - name: goimports\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/gomvpkg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/gomvpkg\n    path: golang.org/x/tools/cmd/gomvpkg\n    repo_owner: golang\n    repo_name: tools\n    description: The gomvpkg command moves go packages, updating import declarations\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/gomvpkg\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    files:\n      - name: gomvpkg\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/gorename/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/gorename\n    repo_owner: golang\n    repo_name: tools\n    description: The gorename command performs precise type-safe renaming of identifiers in Go source code\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/gorename\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\") and semver(\"<= 0.25.0\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.25.0\")\n        path: golang.org/x/tools/cmd/gorename\n      - version_constraint: \"true\"\n        error_message: |\n          gorename was deleted at v0.26.0. https://github.com/golang/go/issues/69360\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/goyacc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: golang/tools/goyacc\n    repo_owner: golang\n    repo_name: tools\n    type: go_install\n    path: golang.org/x/tools/cmd/goyacc\n    description: Goyacc is a version of yacc for Go. It is written in Go and generates parsers written in Go\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    files:\n      - name: goyacc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/guru/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/guru\n    path: golang.org/x/tools/cmd/guru\n    repo_owner: golang\n    repo_name: tools\n    description: A tool for answering questions about Go source code\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/guru\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 0.20.0\")\n        error_message: guru was deleted https://github.com/golang/go/issues/65880\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/tools/stringer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang/tools/stringer\n    path: golang.org/x/tools/cmd/stringer\n    repo_owner: golang\n    repo_name: tools\n    description: Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer interface\n    link: https://pkg.go.dev/golang.org/x/tools/cmd/stringer\n    version_source: github_tag\n    version_filter: not (Version startsWith \"gopls/\")\n    files:\n      - name: stringer\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang/vuln/govulncheck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: golang/vuln/govulncheck\n    type: go_install\n    path: golang.org/x/vuln/cmd/govulncheck\n    repo_owner: golang\n    repo_name: vuln\n    description: Go Vulnerability Management\n    link: https://go.dev/security/vuln/\n    version_source: github_tag\n    files:\n      - name: govulncheck\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang-migrate/migrate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: golang-migrate\n    repo_name: migrate\n    description: Database migrations. CLI and Golang library\n    asset: migrate.{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\">= 4.15.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        files:\n          - name: migrate\n            src: migrate.{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            format: tar.gz\n            asset: migrate.windows-amd64.exe.tar.gz\n            files:\n              - name: migrate\n                src: migrate.{{.OS}}-{{.Arch}}.exe\n    checksum:\n      type: github_release\n      asset: sha256sum.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang.org/x/perf/cmd/benchstat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    path: golang.org/x/perf/cmd/benchstat\n    description: Benchstat computes and compares statistics about benchmarks\n    link: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat\n    go_version_path: golang.org/x/perf\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golang.org/x/tools/gopls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: golang.org/x/tools/gopls\n    aliases:\n      - name: golang/tools/gopls\n    path: golang.org/x/tools/gopls\n    repo_owner: golang\n    repo_name: tools\n    description: Go language server\n    go_version_path: golang.org/x/tools/gopls\n    files:\n      - name: gopls\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golangci/golangci-lint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: golangci\n    repo_name: golangci-lint\n    description: Fast linters runner for Go\n    files:\n      - name: golangci-lint\n        src: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}/golangci-lint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.17.1\")\n        asset: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: golangci-lint-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.36.0\")\n        asset: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: golangci-lint-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.42.0\")\n        asset: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: golangci-lint-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 2.8.0\")\n        asset: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: golangci-lint-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: golangci-lint-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: golangci-lint-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: golangci/golangci-lint/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golangci/golines/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: golangci\n    repo_name: golines\n    description: A golang formatter that fixes long lines\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: golines-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: golines\n            src: \"{{.AssetWithoutExt}}/golines\"\n        checksum:\n          type: github_release\n          asset: golines_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: golines-{{trimV .Version}}-{{.OS}}-all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/golangci/misspell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: golangci\n    repo_name: misspell\n    description: Correct commonly misspelled English words in source files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: misspell_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: misspell_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: misspell_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: misspell_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: misspell_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: misspell\n            src: \"{{.AssetWithoutExt}}/misspell\"\n        checksum:\n          type: github_release\n          asset: misspell_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gomods/athens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gomods\n    repo_name: athens\n    description: A Go module datastore and proxy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.15.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: athens_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: athens_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goodwithtech/dockle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goodwithtech\n    repo_name: dockle\n    description: Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.12\")\n        asset: dockle_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: dockle_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.5\")\n        asset: dockle_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: dockle_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: dockle_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: dockle_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/addlicense/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: addlicense\n    description: A program which ensures source code files have copyright license headers by scanning directory patterns recursively\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: addlicense_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: addlicense_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: addlicense_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/gke-policy-automation/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: gke-policy-automation\n    description: Tool and policy library for reviewing Google Kubernetes Engine clusters against best practices\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: gke-policy-automation_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: gke-policy\n        checksum:\n          type: github_release\n          asset: gke-policy-automation_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gke-policy-automation_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: gke-policy\n        checksum:\n          type: github_release\n          asset: gke-policy-automation_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/go-containerregistry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: go-containerregistry\n    description: Go library and CLIs for working with container registries\n    files:\n      - name: crane\n      - name: gcrane\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.15.0\", \"v0.16.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: go-containerregistry_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.19.1\")\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: go-containerregistry_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/go-jsonnet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: go-jsonnet\n    files:\n      - name: jsonnet\n      - name: jsonnet-deps\n      - name: jsonnet-lint\n      - name: jsonnetfmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.16.0\")\n        no_asset: true\n      - version_constraint: Version == \"v0.17.0\"\n        asset: go-jsonnet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: jsonnet\n          - name: jsonnetfmt\n        replacements:\n          amd64: x86_64\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: Version == \"v0.18.0\"\n        asset: go-jsonnet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: jsonnet\n          - name: jsonnetfmt\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.20.0\")\n        asset: go-jsonnet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: jsonnet\n          - name: jsonnetfmt\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.20.0\"\n        asset: go-jsonnet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: go-jsonnet_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/go-licenses/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: google\n    repo_name: go-licenses\n    description: A lightweight tool to report on the licenses used by a Go package and its dependencies. Highlight! Versioned external URL to licenses can be found at the same time\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 2.0.0\")\n        path: github.com/google/go-licenses/v{{(semver .Version).Major}}\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/jsonnet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: jsonnet\n    asset: jsonnet-bin-{{.Version}}-linux.tar.gz\n    supported_envs:\n      - linux/amd64\n    description: Jsonnet - The data templating language\n    files:\n      - name: jsonnet\n      - name: jsonnetfmt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/keep-sorted/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: keep-sorted\n    description: keep-sorted is a language-agnostic formatter that sorts lines between two markers in a larger file\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: keep-sorted_{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/mtail/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: mtail\n    description: extract internal monitoring data from application logs for collection in a timeseries database\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.0-rc36\")\n        asset: mtail_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v3.0.0-rc38\"\n        asset: mtail_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 3.0.0-rc44\")\n        asset: mtail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.0.0-rc47\")\n        asset: mtail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.0.0-rc51\")\n        asset: mtail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.0.0-rc54\")\n        asset: mtail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: mtail_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/osv-scanner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: osv-scanner\n    description: Vulnerability scanner written in Go which uses the data provided by https://osv.dev\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: osv-scanner_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: osv-scanner_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.4.2\"\n        # https://github.com/google/osv-scanner/issues/611\n        asset: osv-scanner_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: osv-scanner_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.6.2\")\n        asset: osv-scanner_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: osv-scanner_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        # v1.7.0 https://github.com/google/osv-scanner/pull/831\n        asset: osv-scanner_{{.OS}}_{{.Arch}}\n        format: raw\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: osv-scanner_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/pprof/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: google\n    repo_name: pprof\n    description: pprof is a tool for visualization and analysis of profiling data\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/wire/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: google\n    repo_name: wire\n    description: Compile-time Dependency Injection for Go\n    path: github.com/google/wire/cmd/wire\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/google/yamlfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: google\n    repo_name: yamlfmt\n    description: An extensible command line tool or library to format yaml files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.14.0\")\n        asset: yamlfmt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: yamlfmt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/google/yamlfmt/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/google/yamlfmt/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/google/yamlfmt/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/googleapis/api-linter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: googleapis\n    repo_name: api-linter\n    description: A linter for APIs defined in protocol buffers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.55.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.35.0\")\n        asset: api-linter-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: api-linter-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gopasspw/gopass/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gopasspw\n    repo_name: gopass\n    description: The slightly more awesome standard unix password manager for teams\n    asset: gopass-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: gopass_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goph/licensei/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goph\n    repo_name: licensei\n    description: Library and various tools for working with project licenses\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: licensei_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: licensei_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gopinath-langote/1build/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gopinath-langote\n    repo_name: 1build\n    description: Frictionless way of managing project-specific commands\n    asset: 1build_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.2.0\")\n    # 1build was migrated from Python to Go at v1.2.0\n    # https://github.com/gopinath-langote/1build/commit/a692bdce2643c726915950622ec46fbf4ce02816\n    version_overrides:\n      - version_constraint: semver(\"< 1.2.0\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goreleaser/goreleaser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goreleaser\n    repo_name: goreleaser\n    description: Deliver Go binaries as fast and easily as possible\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.182.0\")\n        asset: goreleaser_{{title .OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: goreleaser_{{title .OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: goreleaser_{{title .OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 2.7.0\")\n        asset: goreleaser_{{title .OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/goreleaser/goreleaser/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/goreleaser/goreleaser/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/goreleaser/goreleaser/releases/download/{{.Version}}/checksums.txt.pem\n        overrides:\n          - goos: darwin\n            asset: goreleaser_{{title .OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.12.7\")\n        asset: goreleaser_{{title .OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/goreleaser/goreleaser/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/goreleaser/goreleaser/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/goreleaser/goreleaser/releases/download/{{.Version}}/checksums.txt.pem\n        github_artifact_attestations:\n          signer_workflow: goreleaser/goreleaser/.github/workflows/release.yml\n        overrides:\n          - goos: darwin\n            asset: goreleaser_{{title .OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: goreleaser_{{title .OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/goreleaser/goreleaser/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        github_artifact_attestations:\n          signer_workflow: goreleaser/goreleaser/.github/workflows/release.yml\n        overrides:\n          - goos: darwin\n            asset: goreleaser_{{title .OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goreleaser/nfpm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goreleaser\n    repo_name: nfpm\n    description: \"nFPM is Not FPM - a simple deb, rpm, apk, ipk, and arch linux packager written in Go\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.7.0\"\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v2.30.0\"\n        asset: nfpm_.{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        # checksum file is broken\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v2.36.0\"\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.1.1\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.2.4\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.4.0\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.6.0\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nfpm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.10.0\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.43.4\")\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/goreleaser/nfpm/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/goreleaser/nfpm/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/goreleaser/nfpm/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: nfpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/goreleaser/nfpm/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goss-org/goss/dcgoss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: goss-org/goss/dcgoss\n    type: github_content\n    repo_owner: goss-org\n    repo_name: goss\n    aliases:\n      - name: aelsabbahy/goss/dcgoss\n    description: dcgoss is a convenience wrapper around goss that aims to bring the simplicity of goss to docker-compose managed containers\n    supported_envs:\n      - darwin\n      - linux\n    path: extras/dcgoss/dcgoss\n    files:\n      - name: dcgoss\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goss-org/goss/dgoss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: goss-org/goss/dgoss\n    type: github_content\n    repo_owner: goss-org\n    repo_name: goss\n    aliases:\n      - name: aelsabbahy/goss/dgoss\n    description: dgoss is a convenience wrapper around goss that aims to bring the simplicity of goss to docker containers\n    supported_envs:\n      - darwin\n      - linux\n    path: extras/dgoss/dgoss\n    files:\n      - name: dgoss\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goss-org/goss/kgoss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: goss-org/goss/kgoss\n    type: github_content\n    repo_owner: goss-org\n    repo_name: goss\n    aliases:\n      - name: aelsabbahy/goss/kgoss\n    description: kgoss is a wrapper for goss that aims to bring the simplicity of testing with goss to containers running in pods in Kubernetes\n    supported_envs:\n      - darwin\n      - linux\n    path: extras/kgoss/kgoss\n    files:\n      - name: kgoss\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/goss-org/goss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: goss-org\n    repo_name: goss\n    aliases:\n      - name: aelsabbahy/goss\n    description: Quick and Easy server testing/validation\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: goss-{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    version_constraint: semver(\">= 0.4.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.4.0\")\n        replacements:\n          windows: alpha-windows\n          darwin: alpha-darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gotestyourself/gotestsum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gotestyourself\n    repo_name: gotestsum\n    description: \"'go test' runner with output optimized for humans, JUnit XML for CI integration, and a summary of the test results\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1\"\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.10.0\"\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.2\")\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.7.0\")\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gotestsum_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gotestsum-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gotify/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gotify\n    repo_name: cli\n    description: A command line interface for pushing messages to gotify/server\n    files:\n      - name: gotify\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: gotify-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: semver(\"<= 2.2.1\")\n        asset: gotify-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 2.2.4\")\n        asset: gotify-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 2.3.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gotify-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gptscript-ai/gptscript/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gptscript-ai\n    repo_name: gptscript\n    description: Natural Language Programming\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gptscript-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: gptscript-{{.Version}}-{{.OS}}-universal.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gradle/gradle-distributions/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gradle\n    repo_name: gradle-distributions\n    aliases:\n      - name: gradle/gradle\n    description: Adaptable, fast automation for all\n    files:\n      - name: gradle\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 9.0.0-M7\")\n        asset: gradle-{{trimV .Version | replace \".0-RC\" \"-rc-\" | replace \".0-M\" \"-milestone-\" | trimSuffix \".0\"}}-bin.zip\n        files:\n          - name: gradle\n            src: >-\n              {{.AssetWithoutExt | trimSuffix \"-bin\"}}/bin/gradle\n      - version_constraint: \"true\"\n        asset: gradle-{{trimV .Version | replace \"-RC\" \"-rc-\" | replace \"-M\" \"-milestone-\"}}-bin.zip\n        files:\n          - name: gradle\n            src: >-\n              {{.AssetWithoutExt | trimSuffix \"-bin\"}}/bin/gradle\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/graelo/pumas/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: graelo\n    repo_name: pumas\n    description: Power Usage Monitor for Apple Silicon\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pumas-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: pumas\n            src: target/release/pumas\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/alloy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: alloy\n    description: OpenTelemetry Collector distribution with programmable pipelines\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: alloy-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: alloy\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: alloy-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/grafana-kiosk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: grafana-kiosk\n    description: Kiosk Utility for Grafana\n    rosetta2: true\n    format: raw\n    asset: grafana-kiosk.{{.OS}}.{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/grafanactl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: grafanactl\n    description: The Grafana CLI. Command-line tool designed to simplify interaction with Grafana resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: grafanactl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: grafanactl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/grizzly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: grizzly\n    description: A utility for managing Jsonnet dashboards against the Grafana API\n    files:\n      - name: grr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: grr-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: grr-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/jsonnet-language-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: jsonnet-language-server\n    description: A Language Server Protocol (LSP) server for Jsonnet (https://jsonnet.org)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: jsonnet-language-server_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jsonnet-language-server_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: jsonnet-language-server_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: jsonnet-language-server_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/k6/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: k6\n    description: A modern load testing tool, using Go and JavaScript\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: k6-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: k6\n        src: k6-{{.Version}}-{{.OS}}-{{.Arch}}/k6\n    replacements:\n      darwin: macos\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    checksum:\n      type: github_release\n      asset: k6-{{.Version}}-checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/loki/logcli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grafana/loki/logcli\n    type: github_release\n    repo_owner: grafana\n    repo_name: loki\n    description: LogCLI is the command-line interface to Grafana Loki\n    supported_envs:\n      - linux\n      - darwin\n      - amd64\n    asset: logcli-{{.OS}}-{{.Arch}}.zip\n    overrides:\n      - goos: windows\n        asset: logcli-{{.OS}}-{{.Arch}}.exe.zip\n    files:\n      - name: logcli\n        src: logcli-{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/mcp-grafana/registry.yaml",
    "content": "packages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: mcp-grafana\n    description: MCP server for Grafana\n    asset: mcp-grafana_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: mcp-grafana_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    overrides:\n      - goos: windows\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/mimir/metaconvert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grafana/mimir/metaconvert\n    type: github_release\n    repo_owner: grafana\n    repo_name: mimir\n    description: Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus\n    asset: metaconvert-{{.OS}}-{{.Arch}}\n    format: raw\n    version_prefix: mimir-\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/mimir/mimir/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grafana/mimir/mimir\n    type: github_release\n    repo_owner: grafana\n    repo_name: mimir\n    description: Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"mimir-2.2.0-rc.0\"\n        asset: mimir-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mimir-{{.OS}}-{{.Arch}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: mimirtool-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/mimir/mimirtool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grafana/mimir/mimirtool\n    type: github_release\n    repo_owner: grafana\n    repo_name: mimir\n    description: Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus\n    asset: mimirtool-{{.OS}}-{{.Arch}}\n    format: raw\n    version_prefix: mimir-\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/mimir/query-tee/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grafana/mimir/query-tee\n    type: github_release\n    repo_owner: grafana\n    repo_name: mimir\n    description: Grafana Mimir provides horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus\n    asset: query-tee-{{.OS}}-{{.Arch}}\n    format: raw\n    supported_envs:\n      - linux\n      - darwin\n    version_prefix: mimir-\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/tanka/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: tanka\n    description: Flexible, reusable and concise configuration for Kubernetes\n    files:\n      - name: tk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.27.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: tk_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: tk-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: tk-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: tk-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grafana/xk6/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grafana\n    repo_name: xk6\n    asset: xk6_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Build k6 with extensions\n    replacements:\n      darwin: mac\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: xk6_{{trimV .Version}}_checksums.txt\n      algorithm: sha512\n    version_constraint: semver(\"< 0.9.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.9.0\")\n        error_message: |\n          From version xk6 v0.9.0 there are no more binaries published.\n\n          https://github.com/grafana/xk6/issues/60\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grampelberg/kty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grampelberg\n    repo_name: kty\n    description: The terminal for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: kuberift-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: kuberift-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: Version == \"v0.2.1\"\n        asset: kty-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            format: raw\n            asset: kuberift-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          # opening tar archive for reading: wrapping file reader: gzip: invalid header\n          # - darwin/arm64\n      - version_constraint: \"true\"\n        asset: kty-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gravitational/teleport/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: gravitational\n    repo_name: teleport\n    description: Client Tools for teleport - The easiest, and most secure way to access and protect all of your infrastructure\n    files:\n      - name: tbot\n      - name: tctl\n      - name: teleport\n      - name: tsh\n    overrides:\n      - goos: linux\n        url: https://cdn.teleport.dev/teleport-{{.Version}}-linux-{{.Arch}}-bin.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tbot\n            src: teleport/tbot\n          - name: tctl\n            src: teleport/tctl\n          - name: teleport\n            src: teleport/teleport\n          - name: tsh\n            src: teleport/tsh\n      - goos: darwin\n        url: https://cdn.teleport.dev/teleport-tools-{{trimV .Version}}.{{.Format}}\n        format: pkg\n        files:\n          - name: tctl\n            src: tctl-{{trimV .Version}}.pkg/Payload/tctl.app/Contents/MacOS/tctl\n          - name: tsh\n            src: tsh-{{trimV .Version}}.pkg/Payload/tsh.app/Contents/MacOS/tsh\n      - goos: windows\n        url: https://cdn.teleport.dev/teleport-{{.Version}}-windows-amd64-bin.{{.Format}}\n        format: zip\n        files:\n          - name: tbot\n          - name: tctl\n          - name: tsh\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/greymd/ojichat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: greymd\n    repo_name: ojichat\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/greymd/teip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: greymd\n    repo_name: teip\n    description: Masking tape to help commands \"do one thing well\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.3.1\"\n        asset: teip-{{trimV .Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: teip\n            src: bin/teip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: raw\n            asset: teip_installer-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: teip-{{trimV .Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: teip\n            src: bin/teip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: teip-{{trimV .Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: teip\n            src: bin/teip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: raw\n            asset: teip_installer-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: teip-{{trimV .Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: teip\n            src: bin/teip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: raw\n            asset: teip_installer-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grpc/grpc-go/protoc-gen-go-grpc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grpc/grpc-go/protoc-gen-go-grpc\n    type: github_release\n    repo_owner: grpc\n    repo_name: grpc-go\n    description: The Go language implementation of gRPC. HTTP/2 based RPC\n    version_prefix: cmd/protoc-gen-go-grpc/\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"cmd/protoc-gen-go-grpc/v1.0.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: protoc-gen-go-grpc.{{.SemVer}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: protoc-gen-go-grpc.{{.SemVer}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grpc/grpc-java/protoc-gen-grpc-java/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grpc/grpc-java/protoc-gen-grpc-java\n    type: http\n    repo_owner: grpc\n    repo_name: grpc-java\n    description: The Java gRPC implementation. HTTP/2 based RPC\n    url: https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/{{trimV .Version}}/protoc-gen-grpc-java-{{trimV .Version}}-{{.OS}}-{{.Arch}}.exe\n    format: raw\n    windows_arm_emulation: true\n    replacements:\n      darwin: osx\n      amd64: x86_64\n      arm64: aarch_64\n    checksum:\n      type: http\n      url: https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/{{trimV .Version}}/protoc-gen-grpc-java-{{trimV .Version}}-{{.OS}}-{{.Arch}}.exe.sha256\n      file_format: raw\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway\n    type: github_release\n    repo_owner: grpc-ecosystem\n    repo_name: grpc-gateway\n    description: Generate golang code to reverse proxy Protocol Buffer definitions to RESTful HTTP/1\n    version_constraint: \"false\"\n    version_overrides:\n      # v2.14.0 SLSA provenance https://github.com/aquaproj/aqua-registry/pull/31943#issuecomment-2649535381\n      - version_constraint: semver(\"<= 2.13.0\")\n        asset: protoc-gen-grpc-gateway-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - windows\n          - darwin\n          - linux/amd64\n        rosetta2: true\n        format: raw\n        replacements:\n          amd64: x86_64\n        files:\n          - name: protoc-gen-grpc-gateway\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: protoc-gen-grpc-gateway-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - windows\n          - darwin\n          - linux/amd64\n        rosetta2: true\n        format: raw\n        replacements:\n          amd64: x86_64\n        files:\n          - name: protoc-gen-grpc-gateway\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grpc-ecosystem/grpc-gateway/protoc-gen-openapiv2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: grpc-ecosystem/grpc-gateway/protoc-gen-openapiv2\n    type: github_release\n    repo_owner: grpc-ecosystem\n    repo_name: grpc-gateway\n    description: gRPC to JSON proxy generator following the gRPC HTTP spec\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 2.0.0\") || Version == \"v2.16.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.10.1\")\n        asset: protoc-gen-openapiv2-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.13.0\")\n        asset: protoc-gen-openapiv2-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.16.0\")\n        asset: protoc-gen-openapiv2-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: protoc-gen-openapiv2-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: grpc-gateway_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/grpc-ecosystem/grpc-health-probe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: grpc-ecosystem\n    repo_name: grpc-health-probe\n    description: A command-line tool to perform health-checks for gRPC applications in Kubernetes and elsewhere\n    files:\n      - name: grpc_health_probe\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.4.13\")\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: grpc_health_probe-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gruntwork-io/boilerplate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gruntwork-io\n    repo_name: boilerplate\n    description: A tool for generating files and folders (\"boilerplate\") from a set of templates\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: boilerplate_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: boilerplate_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gruntwork-io/fetch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gruntwork-io\n    repo_name: fetch\n    description: Download files, folders, and release assets from a specific git commit, branch, or tag of public and private GitHub repos\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: fetch_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: fetch_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: fetch_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gruntwork-io/git-xargs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gruntwork-io\n    repo_name: git-xargs\n    description: git-xargs is a command-line tool (CLI) for making updates across multiple Github repositories with a single command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: git-xargs_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: git-xargs_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.8\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: git-xargs_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gruntwork-io/kubergrunt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gruntwork-io\n    repo_name: kubergrunt\n    description: Kubergrunt is a standalone go binary with a collection of commands to fill in the gaps between Terraform, Helm, and Kubectl. https://www.gruntwork.io\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.12\")\n        asset: kubergrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.12\")\n        asset: kubergrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubergrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gruntwork-io/terragrunt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gruntwork-io\n    repo_name: terragrunt\n    description: Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.18.0\")\n        asset: terragrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.28.11\")\n        asset: terragrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.93.5\")\n        asset: terragrunt_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.97.2\")\n        asset: terragrunt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: terragrunt\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: terragrunt_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: terragrunt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: terragrunt\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/gruntwork-io/terragrunt/releases/download/{{.Version}}/SHA256SUMS.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/gruntwork-io/terragrunt/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\\\\Q{{.Version}}\\\\E$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/gruntwork-io/terragrunt/releases/download/{{.Version}}/SHA256SUMS.sig\n        overrides:\n          - goos: windows\n            asset: terragrunt_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gsamokovarov/jump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gsamokovarov\n    repo_name: jump\n    description: Jump helps you navigate faster by learning your habits\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.30.1\"\n        asset: jump_{{.OS}}_{{.Arch}}_binary\n        format: raw\n        overrides:\n          - goos: windows\n            asset: jump\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v0.40.0\"\n        asset: jump_{{.OS}}_{{.Arch}}_binary\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            asset: jump_{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.41.0\"\n        asset: jump_{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: jump_{{.OS}}_{{.Arch}}_binary\n          - goos: darwin\n            goarch: arm64\n            asset: jump_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.30.0\")\n        asset: jump_{{.OS}}_{{.Arch}}_binary\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.51.0\")\n        asset: jump_{{.OS}}_{{.Arch}}_binary\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: jump_{{.OS}}\n          - goos: darwin\n            goarch: arm64\n            asset: jump_{{.OS}}_{{.Arch}}\n          - goos: windows\n            asset: jump\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: jump_{{.OS}}_{{.Arch}}_binary\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/guptarohit/asciigraph/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: guptarohit\n    repo_name: asciigraph\n    description: Go package to make lightweight ASCII line graph ╭┈╯ in command line apps with no other dependencies\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.2\"\n        asset: asciigraph_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: asciigraph_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: asciigraph_{{trimV .Version}}_sha512-checksums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: asciigraph_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: asciigraph_{{trimV .Version}}_sha512-checksums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/gurgeous/tennis/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: gurgeous\n    repo_name: tennis\n    description: stylish CSV tables in your terminal\n    search_words:\n      - csv\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tennis_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tennis_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        files:\n          - name: tennis\n            src: tennis_{{trimV .Version}}_{{.OS}}_{{.Arch}}/tennis\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/guumaster/hostctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: guumaster\n    repo_name: hostctl\n    description: Your dev tool to manage /etc/hosts like a pro\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.6\")\n        asset: hostctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: hostctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.8\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: hostctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: hostctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.2\")\n        asset: hostctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: hostctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hostctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: hostctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hadolint/hadolint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hadolint\n    repo_name: hadolint\n    description: Dockerfile linter, validate inline bash, written in Haskell\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v2.7.0\"\n        asset: hadolint-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v2.10.0\"\n        asset: hadolint-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\"<= 1.2.2\")\n        asset: hadolint_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.9.3\")\n        asset: hadolint-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.12.1-beta\")\n        asset: hadolint-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: hadolint-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hairyhenderson/gomplate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hairyhenderson\n    repo_name: gomplate\n    description: A flexible commandline tool for template rendering. Supports lots of local and remote datasources\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: gomplate_{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: checksums-{{.Version}}_sha512.txt\n      algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/handlename/awsc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: handlename\n    repo_name: awsc\n    description: awsc (AWS cli with Caution) is wrapper for AWS CLI. It displays AWS account information before running any AWS CLI subcommands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: awsc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: awsc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/handlename/let-rds-sleep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: handlename\n    repo_name: let-rds-sleep\n    description: Keep sleeping AWS RDS/Aurora Cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: let-rds-sleep_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: let-rds-sleep_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: let-rds-sleep_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: let-rds-sleep_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/handlename/ssmwrap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: handlename\n    repo_name: ssmwrap\n    description: Exec command with environment variables loaded from AWS SSM\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: ssmwrap_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ssmwrap\n            src: \"{{.AssetWithoutExt}}/ssmwrap\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.1\")\n        asset: ssmwrap_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: ssmwrap\n            src: \"{{.AssetWithoutExt}}/ssmwrap\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: \"true\"\n        asset: ssmwrap_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ssmwrap_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/harelba/q/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: harelba\n    repo_name: q\n    description: q - Run SQL directly on CSV or TSV files\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    version_constraint: semver(\">= 3.1.6\")\n    asset: \"{{.OS}}-q\"\n    replacements:\n      windows: win\n      darwin: macos\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: q-{{.Arch}}-{{.OS}}\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            asset: q-AMD64-Windows.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/harness/drone-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: harness\n    repo_name: drone-cli\n    asset: drone_{{.OS}}_{{.Arch}}.tar.gz\n    description: Command Line Tools for Drone CI\n    files:\n      - name: drone\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: drone_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/boundary/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: boundary\n    description: Boundary enables identity-based access management for dynamic infrastructure\n    url: https://releases.hashicorp.com/boundary/{{trimV .Version}}/boundary_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/boundary/{{trimV .Version}}/boundary_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/consul/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: consul\n    description: Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure\n    url: https://releases.hashicorp.com/consul/{{trimV .Version}}/consul_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_filter: Version matches \"^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    version_constraint: semver(\">= 1.11.1\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/consul/{{trimV .Version}}/consul_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/copywrite/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hashicorp\n    repo_name: copywrite\n    description: Automate copyright headers and license files at scale\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.16.5\"\n        asset: copywrite_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: copywrite_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/go-getter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hashicorp\n    repo_name: go-getter\n    description: Package for downloading things from a string URL using a variety of protocols\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: go-getter_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    checksum:\n      type: github_release\n      asset: go-getter_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/hcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: hcp\n    description: HCP Command-Line Interface\n    url: https://releases.hashicorp.com/hcp/{{trimV .Version}}/hcp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/levant/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: levant\n    rosetta2: true\n    url: https://releases.hashicorp.com/levant/{{trimV .Version}}/levant_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: An open source templating and deployment tool for HashiCorp Nomad jobs\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/levant/{{trimV .Version}}/levant_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/nomad/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: nomad\n    description: Nomad is an easy-to-use, flexible, and performant workload orchestrator that can deploy a mix of microservice, batch, containerized, and non-containerized applications. Nomad is easy to operate and scale and has native Consul and Vault integrations\n    url: https://releases.hashicorp.com/nomad/{{trimV .Version}}/nomad_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_filter: Version matches \"^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/nomad/{{trimV .Version}}/nomad_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 1.2.7\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/packer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: packer\n    url: https://releases.hashicorp.com/packer/{{trimV .Version}}/packer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: Packer is a tool for creating identical machine images for multiple platforms from a single source configuration\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/packer/{{trimV .Version}}/packer_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/packer-plugin-sdk/packer-sdc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: hashicorp/packer-plugin-sdk/packer-sdc\n    type: go_install\n    path: github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc\n    repo_owner: hashicorp\n    repo_name: packer-plugin-sdk\n    description: The packer software development command is meant for plugin maintainers and Packer maintainers, it helps generate docs and code\n    files:\n      - name: packer-sdc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/terraform/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: terraform\n    url: https://releases.hashicorp.com/terraform/{{trimV .Version}}/terraform_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned\n    supported_envs:\n      - linux\n      - darwin\n      - amd64\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/terraform/{{trimV .Version}}/terraform_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 1.0.2\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/terraform-config-inspect/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: hashicorp\n    repo_name: terraform-config-inspect\n    description: A helper library for shallow inspection of Terraform configurations\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/terraform-ls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - repo_owner: hashicorp\n    repo_name: terraform-ls\n    description: Terraform Language Server\n    type: http\n    url: https://releases.hashicorp.com/terraform-ls/{{trimV .Version}}/terraform-ls_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/terraform-ls/{{trimV .Version}}/terraform-ls_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 0.23.0\")\n    # 0.23.0: Support windows/arm64\n    version_overrides:\n      - version_constraint: semver(\">= 0.14.0\")\n        # 0.14.0: Support darwin/arm64\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 0.12.0\")\n        # 0.12.0: Support linux/arm64\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 0.2.1\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\"< 0.2.1\")\n        # 0.1.0 and 0.2.0 were released only at GitHub Releases\n        type: github_release\n        asset: terraform-ls_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: terraform-ls_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/terraform-mcp-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: hashicorp\n    repo_name: terraform-mcp-server\n    description: The Terraform MCP Server provides seamless integration with Terraform ecosystem, enabling advanced automation and interaction capabilities for Infrastructure as Code (IaC) development\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        path: github.com/hashicorp/terraform-mcp-server/cmd/terraform-mcp-server\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/terraform-plugin-docs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hashicorp\n    repo_name: terraform-plugin-docs\n    description: Generate and validate Terraform plugin/provider documentation\n    asset: tfplugindocs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    files:\n      - name: tfplugindocs\n    checksum:\n      type: github_release\n      asset: tfplugindocs_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/vagrant/vagrant-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: hashicorp/vagrant/vagrant-go\n    type: github_release\n    repo_owner: hashicorp\n    repo_name: vagrant\n    description: Vagrant is a tool for building and distributing development environments\n    files:\n      - name: vagrant\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: vagrant-go_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: vagrant_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/vault/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: vault\n    description: A tool for secrets management, encryption as a service, and privileged access management\n    version_filter: Version matches \"^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    url: https://releases.hashicorp.com/vault/{{trimV .Version}}/vault_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    checksum:\n      type: http\n      url: https://releases.hashicorp.com/vault/{{trimV .Version}}/vault_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hashicorp/waypoint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: hashicorp\n    repo_name: waypoint\n    description: A tool to build, deploy, and release any application on any platform\n    version_filter: Version matches \"^v\\\\d+\\\\.\\\\d+\\\\.\\\\d+\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.10.0\")\n        url: https://releases.hashicorp.com/waypoint/{{trimV .Version}}/waypoint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n        checksum:\n          type: http\n          url: https://releases.hashicorp.com/waypoint/{{trimV .Version}}/waypoint_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: \"true\"\n        url: https://releases.hashicorp.com/waypoint/{{trimV .Version}}/waypoint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n        checksum:\n          type: http\n          url: https://releases.hashicorp.com/waypoint/{{trimV .Version}}/waypoint_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/haskell/cabal/cabal-install/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: haskell/cabal/cabal-install\n    type: http\n    repo_owner: haskell\n    repo_name: cabal\n    description: \"Cabal: Common Architecture for Building Applications and Libraries\"\n    version_prefix: cabal-install-v\n    files:\n      - name: cabal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.4.1.0\")\n        no_asset: true\n      - version_constraint: Version == \"cabal-install-v3.0.0.0\"\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-alpine-{{.OS}}-musl.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}17.7.0.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"cabal-install-v3.2.0.0\"\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-alpine-{{.OS}}-musl.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}17.7.0.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"cabal-install-v3.4.0.0\"\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: tar.xz\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-3.4.0.0-{{.Arch}}-{{.OS}}-sierra.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"<= 3.6.0.0\")\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-deb10.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n      - version_constraint: semver(\"<= 3.6.2.0\")\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine-static.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-deb10.{{.Format}}\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements: {}\n      - version_constraint: Version == \"cabal-install-v3.8.1.0\"\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-3.8.1.0-{{.Arch}}-{{.OS}}-alpine.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-3.8.1.0-{{.Arch}}-{{.OS}}-deb10.{{.Format}}\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-3.8.1.0-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-3.8.1.0-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements: {}\n      - version_constraint: semver(\"<= 3.10.1.0\")\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.10.3.0\")\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine3_12.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-deb10.{{.Format}}\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements: {}\n      - version_constraint: semver(\"<= 3.16.0.0\")\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine3_12.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine3_18.{{.Format}}\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements: {}\n      - version_constraint: \"true\"\n        url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine3_12.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}-alpine3_22.{{.Format}}\n          - goos: darwin\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            url: https://downloads.haskell.org/~cabal/cabal-install-{{.SemVer}}/cabal-install-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/haskell/ghcup-hs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: haskell\n    repo_name: ghcup-hs\n    url: https://downloads.haskell.org/~ghcup/{{trimV .Version}}/{{.Arch}}-{{.OS}}-ghcup-{{trimV .Version}}\n    format: raw\n    link: https://www.haskell.org/ghcup/\n    description: GHCup is an installer for the general purpose language Haskell\n    replacements:\n      arm64: aarch64\n      amd64: x86_64\n      darwin: apple-darwin\n    files:\n      - name: ghcup\n        src: \"{{.Arch}}-{{.OS}}-ghcup-{{trimV .Version}}\"\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hasura/graphql-engine/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hasura\n    repo_name: graphql-engine\n    description: Hasura GraphQL Engine CLI\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: raw\n    asset: cli-hasura-{{.OS}}-{{.Arch}}\n    files:\n      - name: hasura\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hatoo/oha/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hatoo\n    repo_name: oha\n    description: Ohayou(おはよう), HTTP load generator, inspired by rakyll/hey with tui animation\n    asset: oha-{{.OS}}-{{.Arch}}\n\n    # https://github.com/aquaproj/aqua-registry/pull/11995#issuecomment-1537367448\n    # Unfortunately, the prebuilt binary for darwin/arm64 doesn't work, so we enable rosetta2\n    rosetta2: true\n\n    format: raw\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.5.4\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.5.3\")\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 0.5.3-test\")\n      - version_constraint: semver(\"< 0.5.3-test\")\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hay-kot/scaffold/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hay-kot\n    repo_name: scaffold\n    description: A cookie cutter alternative with in-project scaffolding for generating components, controllers, or other common code patterns\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: scaffold_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/heartbeatsjp/check-tls-cert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: heartbeatsjp\n    repo_name: check-tls-cert\n    description: Check-tls-cert is a TLS certificate checker\n    asset: check-tls-cert-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tar.xz\n    supported_envs:\n      - linux\n      - darwin\n      - amd64\n    files:\n      - name: check-tls-cert\n        src: check-tls-cert-{{trimV .Version}}/check-tls-cert\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helix-editor/helix/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helix-editor\n    repo_name: helix\n    description: A post-modern modal text editor\n    files:\n      - name: hx\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: helix-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: hx\n            src: \"{{.AssetWithoutExt}}/hx\"\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 22.5.0\")\n        asset: helix-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: hx\n            src: \"{{.AssetWithoutExt}}/hx\"\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 22.8.1\")\n        asset: helix-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: hx\n            src: \"{{.AssetWithoutExt}}/hx\"\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: helix-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: hx\n            src: \"{{.AssetWithoutExt}}/hx\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hellux/jotdown/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hellux\n    repo_name: jotdown\n    description: A Djot parser library\n    search_words:\n      - djot\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: jotdown-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: jotdown\n            src: jotdown-{{.Version}}-{{.Arch}}-{{.OS}}/jotdown\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helm/chart-releaser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helm\n    repo_name: chart-releaser\n    description: Hosting Helm Charts via GitHub Pages and Releases\n    files:\n      - name: cr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.3.0\"\n        asset: chart-releaser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: chart-releaser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: chart-releaser\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: chart-releaser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: chart-releaser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/helm/chart-releaser/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/helm/chart-releaser/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/helm/chart-releaser/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helm/chart-testing/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helm\n    repo_name: chart-testing\n    description: CLI tool for linting and testing Helm charts\n    files:\n      - name: ct\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.5.0\"\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v3.5.1\"\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.0.0-rc.1\")\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.3.1\")\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.5.0\")\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: chart-testing_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/helm/chart-testing/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/helm/chart-testing/.github/workflows/release.yaml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/helm/chart-testing/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helm/helm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: helm\n    repo_name: helm\n    url: https://get.helm.sh/helm-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: The Kubernetes Package Manager\n    files:\n      - name: helm\n        src: \"{{.OS}}-{{.Arch}}/helm\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: http\n      url: https://get.helm.sh/helm-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n      algorithm: sha256\n    version_constraint: semver(\">= 3.6.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 3.1.0\")\n        rosetta2: true\n      - version_constraint: semver(\"< 3.1.0\")\n        rosetta2: true\n        checksum:\n          type: http\n          url: https://get.helm.sh/helm-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helmfile/helmfile/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helmfile\n    repo_name: helmfile\n    aliases:\n      - name: roboll/helmfile\n    description: Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases. Generate all-in-one manifests for use with ArgoCD\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: helmfile_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: helmfile_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helmfile/vals/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helmfile\n    repo_name: vals\n    aliases:\n      - name: variantdev/vals\n    description: Helm-like configuration values loader with support for various sources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.16.0\", \"v0.17.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.16.1\"\n        asset: vals_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: vals_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.16.2\"\n        asset: vals_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: vals_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: vals_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: vals_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: vals_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: vals_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: vals_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: vals_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/helmwave/helmwave/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: helmwave\n    repo_name: helmwave\n    description: New  wave for @helm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8.4\")\n        asset: helmwave-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.9.0\"\n        asset: helmwave_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.9.5\")\n        asset: helmwave_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: helmwave_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.19.7\")\n        asset: helmwave_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.20.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.35.3\")\n        asset: helmwave_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: helmwave_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hetznercloud/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hetznercloud\n    repo_name: cli\n    asset: hcloud-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: A command-line interface for Hetzner Cloud\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: hcloud\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hexdigest/gowrap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hexdigest\n    repo_name: gowrap\n    description: GoWrap is a command line tool for generating decorators for Go interfaces\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.10\")\n        asset: gowrap_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: gowrap_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: gowrap_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gowrap_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hhatto/gocloc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hhatto\n    repo_name: gocloc\n    description: A little fast cloc(Count Lines Of Code)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.6\"\n        no_asset: true\n      - version_constraint: Version == \"v0.4.0\"\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.4.3\"\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: gocloc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gocloc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gocloc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hherman1/gq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hherman1\n    repo_name: gq\n    description: jq but using go instead\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}-{{.Arch}}.{{.Format}}\"\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hickford/git-credential-azure/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hickford\n    repo_name: git-credential-azure\n    description: A Git credential helper for Azure Repos\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: git-credential-azure_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: git-credential-azure_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: git-credential-azure_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: git-credential-azure_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hickford/git-credential-oauth/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hickford\n    repo_name: git-credential-oauth\n    description: A Git credential helper that securely authenticates to GitHub, GitLab and BitBucket using OAuth\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: git-credential-oauth_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: git-credential-oauth_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: git-credential-oauth_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: git-credential-oauth_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: git-credential-oauth_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: git-credential-oauth_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hidetatz/kubecolor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hidetatz\n    repo_name: kubecolor\n    description: colorizes kubectl output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.17\"\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.20\")\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/high-moctane/mocword/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: high-moctane\n    repo_name: mocword\n    description: Predict next words (｀･ω･´)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: mocword-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mocword-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/high-moctane/nextword/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: high-moctane\n    repo_name: nextword\n    description: Predict next English words\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: nextword_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nextword_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hirosassa/ksnotify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hirosassa\n    repo_name: ksnotify\n    description: A CLI command to parse kubectl diff result and notify it to GitLab/GitHub\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: ksnotify-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: ksnotify-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ksnotify-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hirosassa/tfcmt-gitlab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hirosassa\n    repo_name: tfcmt-gitlab\n    description: tfcmt-gitlab is a CLI command to parse and notify Terraform execution results. This command supports GitLab as a CI and notification platform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: tfcmt-gitlab_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt-gitlab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tfcmt-gitlab_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt-gitlab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hirose31/s3surfer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hirose31\n    repo_name: s3surfer\n    description: s3surfer is CLI tool for browsing S3 bucket and download objects interactively\n    asset: s3surfer_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: s3surfer\n        src: s3surfer_{{.Version}}_{{.OS}}_{{.Arch}}/s3surfer\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hmarr/codeowners/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hmarr\n    repo_name: codeowners\n    description: Command line tool and Go library for CODEOWNERS files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.3.1\"\n        asset: codeowners_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: codeowners_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: codeowners_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hokaccha/spannerdef/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hokaccha\n    repo_name: spannerdef\n    description: Idempotent Google Cloud Spanner schema management by SQL, inspired by sqldef\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: spannerdef-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/homeport/dyff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: homeport\n    repo_name: dyff\n    description: A diff tool for YAML files, and sometimes JSON\n    supported_envs:\n      - darwin\n      - linux\n    asset: dyff_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/homeport/havener/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: homeport\n    repo_name: havener\n    description: \"/ˈheɪvənə/ - Think of it as a swiss army knife for Kubernetes tasks\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0-alpha\")\n        asset: havener-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0-alpha\")\n        asset: havener-kube-1.10-helm-2.10-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: havener-kube-1.10-helm-2.10-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.5.2\")\n        asset: havener-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.2\")\n        asset: havener_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: havener_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hougesen/mdsf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hougesen\n    repo_name: mdsf\n    description: Format markdown code blocks using your favorite tools\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: mdsf-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: mdsf-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.2.3\"\n        asset: mdsf-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mdsf\n            src: \"{{.AssetWithoutExt}}/mdsf\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mdsf-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mdsf\n            src: \"{{.AssetWithoutExt}}/mdsf\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/houseabsolute/omegasort/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: houseabsolute\n    repo_name: omegasort\n    description: The last text sorting tool you'll ever need\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: omegasort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: linux\n            asset: omegasort-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/houseabsolute/ubi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: houseabsolute\n    repo_name: ubi\n    description: The Universal Binary Installer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.10\"\n        asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.19\")\n        asset: ubi-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: darwin\n            asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: ubi-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: darwin\n            asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: ubi-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ubi-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: ubi-{{.OS}}-msvc-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/howardjohn/kubeconfig-proxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: howardjohn\n    repo_name: kubeconfig-proxy\n    description: Tunnel Kubectl requests over `kubectl proxy` to avoid round trips to API server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubeconfig-proxy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubeconfig-proxy_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hrmsk66/terraformify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hrmsk66\n    repo_name: terraformify\n    description: An experimental CLI that generates Terraform files for managing existing Fastly services\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: terraformify_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        files:\n          - name: terraformify\n            src: terraformify_{{.OS}}_{{.Arch}}/terraformify\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/huseyinbabal/taws/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: huseyinbabal\n    repo_name: taws\n    description: \"Terminal UI for AWS (taws) - A terminal-based AWS resource viewer and manager\"\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.6\")\n        asset: taws-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: taws-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/hytromo/mimosa/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: hytromo\n    repo_name: mimosa\n    description: Zero-config docker image promotion\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: mimosa_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: mimosa_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: mimosa_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: mimosa_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iamhsa/pkenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: iamhsa\n    repo_name: pkenv\n    description: Packer version manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: pkenv\n            src: pkenv-{{trimV .Version}}/bin/pkenv\n          - name: packer\n            src: pkenv-{{trimV .Version}}/bin/packer\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ianlewis/todos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ianlewis\n    repo_name: todos\n    description: Parse TODO and FIXME comments from code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: todos-{{.OS}}-{{.Arch}}\n        format: raw\n        complete_windows_ext: false\n        slsa_provenance:\n          type: github_release\n          asset: todos-{{.OS}}-{{.Arch}}.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: todos-{{.OS}}-{{.Arch}}\n        format: raw\n        slsa_provenance:\n          type: github_release\n          asset: todos-{{.OS}}-{{.Arch}}.intoto.jsonl\n        overrides:\n          - goos: windows\n            complete_windows_ext: false\n            asset: todos-{{.OS}}-{{.Arch}}.exe\n            slsa_provenance:\n              type: github_release\n              asset: todos-{{.OS}}-{{.Arch}}.exe.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iann0036/iamlive/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iann0036\n    repo_name: iamlive\n    asset: iamlive-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    description: Generate an IAM policy from AWS calls using client-side monitoring (CSM) or embedded proxy\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iawia002/lux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iawia002\n    repo_name: lux\n    aliases:\n      - name: iawia002/annie\n    description: Fast and simple video download library and CLI tool written in Go\n    asset: lux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: lux_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.17.2\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.14.0\")\n        replacements:\n          amd64: 64-bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\">= 0.12.0\")\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: arm64\n        replacements:\n          amd64: 64-bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 0.11.0\")\n        asset: annie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: annie\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              arm64: arm64\n        replacements:\n          amd64: 64-bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: annie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.6.6\")\n        asset: annie_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: annie\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: annie_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.6.3\")\n        asset: annie_{{.OS}}_{{.Arch}}\n        files:\n          - name: annie\n        format: raw\n        overrides: []\n        replacements: {}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.6.3\")\n        asset: annie_{{.OS}}_{{.Arch}}\n        files:\n          - name: annie\n        format: raw\n        overrides: []\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ibotta/sopstool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ibotta\n    repo_name: sopstool\n    description: SOPS multi-file wrapper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.0\"\n        asset: sopstool_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sopstool_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: sopstool_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: sopstool_{{.OS}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sopstool_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: sopstool_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sopstool_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: sopstool_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sopstool_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/idursun/jjui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: idursun\n    repo_name: jjui\n    description: Jujutsu UI (jjui) is a Text User Interface (TUI) designed for interacting with the Jujutsu version control system\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: jjui-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: jjui\n            src: \"release/{{.AssetWithoutExt}}\"\n      - version_constraint: \"true\"\n        asset: jjui-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: jjui\n            src: \"{{.AssetWithoutExt}}\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iffse/pay-respects/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iffse\n    repo_name: pay-respects\n    description: Command suggestions, command-not-found and thefuck replacement written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.12\")\n        error_message: This version is not supported. Please use a newer version.\n      - version_constraint: Version == \"v0.5.13\"\n        asset: pay-respects-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            asset: pay-respects-{{.Arch}}-{{.OS}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: pay-respects-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.6.12\")\n        asset: pay-respects-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.zst\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: pay-respects-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.zst\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/igor-petruk/scriptisto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: igor-petruk\n    repo_name: scriptisto\n    description: A language-agnostic \"shebang interpreter\" that enables you to write scripts in compiled languages\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: scriptisto.{{.Format}}\n        format: bz2\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.0.0\"\n        asset: scriptisto.{{.Format}}\n        format: bz2\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: scriptisto-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ikanago/omekasy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ikanago\n    repo_name: omekasy\n    description: Command line application that converts alphanumeric characters to various styles defined in Unicode\n    asset: omekasy-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: omekasy\n        src: archive/omekasy\n    version_constraint: semver(\">= 0.2.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.2.0\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ikawaha/kagome/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ikawaha\n    repo_name: kagome\n    description: Self-contained Japanese Morphological Analyzer written in pure Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v2.9.6\", \"v2.9.9\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: kagome_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: kagome\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: kagome\n            src: kagome_{{.OS}}_{{.Arch}}/kagome\n      - version_constraint: semver(\"<= 2.2.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.6.0\")\n        asset: kagome_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kagome_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.6.3\")\n        asset: kagome_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kagome_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.9.2\")\n        asset: kagome_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kagome_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kagome_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kagome_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: kagome_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ilaif/goplicate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ilaif\n    repo_name: goplicate\n    description: A CLI tool that helps define common code or configuration snippets once, and sync it to multiple projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: goplicate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/im2nguyen/rover/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: im2nguyen\n    repo_name: rover\n    asset: rover_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: Interactive Terraform visualization. State and configuration explorer\n    files:\n      - name: rover\n        src: rover_{{.Version}}\n    checksum:\n      type: github_release\n      asset: rover_{{trimV .Version}}_SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/imsnif/bandwhich/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: imsnif\n    repo_name: bandwhich\n    description: Terminal bandwidth utilization tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.22.0\"\n        asset: bandwhich-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: what\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: what-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: what\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: bandwhich-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.22.2\")\n        asset: bandwhich-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bandwhich-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/imuxin/kubectl-watch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: imuxin\n    repo_name: kubectl-watch\n    description: A kubectl plugin to provide a pretty delta change view of being watched kubernetes resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.5\"\n        asset: kubectl-watch_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: kubectl-watch_{{.Version}}_{{.Arch}}-{{.OS}}.zip.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: kubectl-watch-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubectl-watch-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/in-toto/in-toto-golang/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: in-toto\n    repo_name: in-toto-golang\n    description: A Go implementation of in-toto. in-toto is a framework to protect software supply chain integrity\n    files:\n      - name: in-toto\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/in-toto/witness/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: in-toto\n    repo_name: witness\n    description: Witness is a pluggable framework for software supply chain risk management.  It automates, normalizes, and verifies software artifact provenance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.13\"\n        asset: witness_{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n      - version_constraint: semver(\"<= 0.1.11\")\n        asset: witness_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: witness_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: witness_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: witness_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: witness_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: witness_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/in-toto/witness/releases/download/{{.Version}}/witness_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/in-toto/witness/.github/workflows/release.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/in-toto/witness/releases/download/{{.Version}}/witness_{{trimV .Version}}_checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/incu6us/goimports-reviser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: incu6us\n    repo_name: goimports-reviser\n    description: Right imports sorting & code formatting tool (goimports alternative)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.4\"\n        asset: goimports-reviser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.5.1\")\n        asset: goimports-reviser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.9.0\")\n        asset: goimports-reviser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: goimports-reviser_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/influxdata/influx-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: influxdata\n    repo_name: influx-cli\n    description: CLI for managing resources in InfluxDB v2\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    url: https://dl.influxdata.com/influxdb/releases/influxdb2-client-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\">= 2.7.1\")\n    files:\n      - name: influx\n    version_overrides:\n      - version_constraint: semver(\"< 2.7.1\")\n        files:\n          - name: influx\n            src: influxdb2-client-{{trimV .Version}}-{{.OS}}-{{.Arch}}/influx\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/infracost/infracost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: infracost\n    repo_name: infracost\n    description: Cloud cost estimates for Terraform in pull requests. Love your cloud bill\n    asset: infracost-{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: infracost\n        src: infracost-{{.OS}}-{{.Arch}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        goarch: amd64\n        files:\n          - name: infracost\n            src: infracost.exe\n      - goos: windows\n        goarch: arm64\n        files:\n          - name: infracost\n            src: infracost-arm64.exe\n    version_constraint: semver(\">= 0.9.18\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.9.17\")\n        checksum:\n          enabled: false\n      - version_constraint: \"true\"\n        checksum:\n          enabled: false\n        supported_envs:\n          - darwin\n          - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/inlets/inlets-pro/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: inlets\n    repo_name: inlets-pro\n    description: Secure HTTP and TCP tunnels that just work\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: inlets-pro\n    overrides:\n      - goos: darwin\n        goarch: arm64\n        asset: inlets-pro-darwin-arm64\n      - goos: darwin\n        asset: inlets-pro-darwin\n      - goarch: arm64\n        asset: inlets-pro-arm64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/inlets/inletsctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: inlets\n    repo_name: inletsctl\n    description: Create inlets servers on the top cloud platforms\n    asset: inletsctl.tgz\n    overrides:\n      - goos: darwin\n        asset: inletsctl-darwin.tgz\n        files:\n          - name: inletsctl\n            src: inletsctl-darwin\n      - goarch: arm64\n        asset: inletsctl-arm64.tgz\n        files:\n          - name: inletsctl\n            src: inletsctl-arm64\n    checksum:\n      # The checksum in the checksum file is not the checksum of tarball but the checksum of the executable binary in tarball.\n      # aqua doesn't support such a case at the moment.\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/inlets/mixctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: inlets\n    repo_name: mixctl\n    description: A tiny TCP load balancer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.3-rc1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        format: raw\n        asset: mixctl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: mixctl-arm64\n          - goos: darwin\n            goarch: amd64\n            asset: mixctl-darwin\n          - goos: darwin\n            goarch: arm64\n            asset: mixctl-darwin-arm64\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/innobead/huber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: innobead\n    repo_name: huber\n    description: \"Huber: A package installer for GitHub repository releases\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: huber-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: huber-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.11\")\n        asset: huber-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: huber-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/inovex/CalendarSync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: inovex\n    repo_name: CalendarSync\n    description: Stateless CLI tool to sync calendars across different calendaring systems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: CalendarSync_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/instrumenta/kubeval/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: instrumenta\n    repo_name: kubeval\n    description: Validate your Kubernetes configuration files, supports multiple Kubernetes versions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: kubeval-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubeval-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/cronjob-runner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: cronjob-runner\n    description: Run one-shot Kubernetes Job from CronJob template and tail logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cronjob-runner_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/ghcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: ghcp\n    description: Tool to fork a repository, commit files, create a pull request and upload assets using GitHub API\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: ghcp_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.13.0\")\n        asset: ghcp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ghcp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/kauthproxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: kauthproxy\n    description: Local authentication proxy for Kubernetes Dashboard (kubectl auth-proxy)\n    files:\n      - name: kauthproxy\n      - name: kubectl-auth_proxy\n        src: kauthproxy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: kauthproxy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kauthproxy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/kubectl-external-forward/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: kubectl-external-forward\n    asset: kubectl-external_forward_{{.OS}}_{{.Arch}}.zip\n    description: kubectl plugin to connect to external host via Envoy Proxy in Kubernetes cluster\n    files:\n      - name: kubectl-external_forward\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/kubelogin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: kubelogin\n    description: kubectl plugin for Kubernetes OpenID Connect authentication (kubectl oidc-login)\n    files:\n      - name: kubectl-oidc_login\n        src: kubelogin\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: kubelogin_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.8.2\")\n        asset: kubelogin_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubelogin_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.18.0\")\n        asset: kubelogin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.22.1\")\n        asset: kubelogin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.31.1\")\n        asset: kubelogin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubelogin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/int128/yamlpatch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: int128\n    repo_name: yamlpatch\n    description: Apply JSON Patch to YAML Document preserving positions and comments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: yamlpatch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: yamlpatch_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/interlynk-io/sbomqs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: interlynk-io\n    repo_name: sbomqs\n    description: \"sbomqs: The Comprehensive SBOM Quality & Compliance Tool\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: sbomqs-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sbomqs_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: sbomqs-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sbomqs_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.0.2\")\n        asset: sbomqs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: sbomqs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        cosign:\n          opts:\n            - --certificate-identity\n            - https://github.com/interlynk-io/sbomqs/.github/workflows/release.yml@refs/tags/{{.Version}}\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --certificate\n            - https://github.com/interlynk-io/sbomqs/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --signature\n            - https://github.com/interlynk-io/sbomqs/releases/download/{{.Version}}/{{.Asset}}.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iovisor/kubectl-trace/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iovisor\n    repo_name: kubectl-trace\n    description: Schedule bpftrace programs on your kubernetes cluster using the kubectl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1-rc.0\")\n        asset: kubectl-trace_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-trace_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubectl-trace_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-trace_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ip7z/7zip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ip7z\n    repo_name: 7zip\n    description: 7-Zip is a file archiver with a high compression ratio\n    files:\n      - name: 7zzs\n      - name: 7zz\n      - name: 7za\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"21.07\"\n        asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          amd64: x64\n        overrides:\n          - goos: linux\n            files:\n              - name: 7zzs\n          - goos: darwin\n            asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: 7zz\n          - goos: windows\n            format: 7z\n            asset: 7z{{replace \".\" \"\" .Version}}-extra.{{.Format}}\n            files:\n              - name: 7za\n                src: \"{{.Arch}}/7za.exe\"\n      - version_constraint: Version in [\"22.00\", \"22.01\"]\n        asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        overrides:\n          - goos: linux\n            files:\n              - name: 7zzs\n          - goos: windows\n            format: 7z\n            asset: 7z{{replace \".\" \"\" .Version}}-extra.{{.Format}}\n            files:\n              - name: 7za\n                src: \"{{.Arch}}/7za.exe\"\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: Version == \"23.01\"\n        asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          amd64: x64\n        overrides:\n          - goos: linux\n            files:\n              - name: 7zzs\n          - goos: darwin\n            asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: 7zz\n          - goos: windows\n            format: 7z\n            asset: 7z{{replace \".\" \"\" .Version}}-extra.{{.Format}}\n            files:\n              - name: 7za\n                src: \"{{.Arch}}/7za.exe\"\n      - version_constraint: Version in [\"24.05\", \"24.06\"]\n        asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n          amd64: x64\n        overrides:\n          - goos: linux\n            files:\n              - name: 7zzs\n          - goos: darwin\n            asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: 7zz\n          - goos: windows\n            format: 7z\n            asset: 7z{{replace \".\" \"\" .Version}}-extra.{{.Format}}\n            files:\n              - name: 7za\n                src: \"{{.Arch}}/7za.exe\"\n      - version_constraint: \"true\"\n        asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x64\n          darwin: mac\n        overrides:\n          - goos: linux\n            files:\n              - name: 7zzs\n              - name: 7zz\n          - goos: darwin\n            asset: 7z{{replace \".\" \"\" .Version}}-{{.OS}}.{{.Format}}\n            files:\n              - name: 7zz\n          - goos: windows\n            format: 7z\n            asset: 7z{{replace \".\" \"\" .Version}}-extra.{{.Format}}\n            files:\n              - name: 7za\n                src: \"{{.Arch}}/7za.exe\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipfs/kubo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ipfs\n    repo_name: kubo\n    aliases:\n      - name: ipfs/go-ipfs\n    description: IPFS is a global, versioned, peer-to-peer filesystem\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\">= 0.14.0\")\n    asset: kubo_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n    files:\n      - name: ipfs\n        src: kubo/ipfs\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: go-ipfs_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: ipfs\n            src: go-ipfs/ipfs\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha512\"\n      algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/cidr2ip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/cidr2ip\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"cidr2ip-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: cidr2ip_{{trimPrefix \"cidr2ip-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: cidr2ip\n            src: cidr2ip_{{trimPrefix \"cidr2ip-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: cidr2ip\n        src: cidr2ip_{{trimPrefix \"cidr2ip-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/cidr2range/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/cidr2range\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"cidr2range-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: cidr2range_{{trimPrefix \"cidr2range-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: cidr2range\n            src: cidr2range_{{trimPrefix \"cidr2range-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: cidr2range\n        src: cidr2range_{{trimPrefix \"cidr2range-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/grepip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/grepip\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"grepip-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: grepip_{{trimPrefix \"grepip-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: grepip\n            src: grepip_{{trimPrefix \"grepip-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: grepip\n        src: grepip_{{trimPrefix \"grepip-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/prips/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/prips\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"prips-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: prips_{{trimPrefix \"prips-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: prips\n            src: prips_{{trimPrefix \"prips-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: prips\n        src: prips_{{trimPrefix \"prips-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/randip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/randip\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"randip-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: randip_{{trimPrefix \"randip-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: randip\n            src: randip_{{trimPrefix \"randip-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: randip\n        src: randip_{{trimPrefix \"randip-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/range2cidr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/range2cidr\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"range2cidr-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: range2cidr_{{trimPrefix \"range2cidr-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: range2cidr\n            src: range2cidr_{{trimPrefix \"range2cidr-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: range2cidr\n        src: range2cidr_{{trimPrefix \"range2cidr-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/range2ip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/range2ip\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"range2ip-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: range2ip_{{trimPrefix \"range2ip-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: range2ip\n            src: range2ip_{{trimPrefix \"range2ip-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: range2ip\n        src: range2ip_{{trimPrefix \"range2ip-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"ipinfo-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: ipinfo_{{trimPrefix \"ipinfo-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: ipinfo\n            src: ipinfo_{{trimPrefix \"ipinfo-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: ipinfo\n        src: ipinfo_{{trimPrefix \"ipinfo-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipinfo/cli/splitcidr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: ipinfo/cli/splitcidr\n    repo_owner: ipinfo\n    repo_name: cli\n    description: Official Command Line Interface for the IPinfo API (IP geolocation and other types of IP data)\n    version_filter: Version startsWith \"splitcidr-\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: splitcidr_{{trimPrefix \"splitcidr-\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: splitcidr\n            src: splitcidr_{{trimPrefix \"splitcidr-\" .Version}}_{{.OS}}_{{.Arch}}.exe\n    files:\n      - name: splitcidr\n        src: splitcidr_{{trimPrefix \"splitcidr-\" .Version}}_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ipld/go-car/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ipld\n    repo_name: go-car\n    description: A content addressible archive utility\n    asset: go-car_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    files:\n      - name: car\n    overrides:\n      - goos: darwin\n        asset: go-car_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        files:\n          - name: car\n            src: go-car\n      - goos: linux\n        format: tar.gz\n    checksum:\n      type: github_release\n      asset: go-car_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ismaelgv/rnr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ismaelgv\n    repo_name: rnr\n    description: A command-line tool to batch rename files and directories\n    files:\n      - name: rnr\n        src: rnr-{{.Version}}-{{.Arch}}-{{.OS}}/rnr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: rnr-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: rnr\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: rnr-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/istio/istio/istioctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: istio/istio/istioctl\n    type: github_release\n    repo_owner: istio\n    repo_name: istio\n    description: The istioctl tool is a configuration command line utility that allows service operators to debug and diagnose their Istio service mesh deployments\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    replacements:\n      darwin: osx\n      windows: win\n    asset: istioctl-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: istioctl\n    overrides:\n      - goos: darwin\n        goarch: amd64\n        asset: istioctl-{{.Version}}-osx.tar.gz\n      - goos: windows\n        asset: istioctl-{{.Version}}-win.zip\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itamae-kitchen/mitamae/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itamae-kitchen\n    repo_name: mitamae\n    description: mitamae is a fast, simple, and single-binary configuration management tool with a DSL like Chef\n    files:\n      - name: mitamae\n        src: mitamae-{{.Arch}}-{{.OS}}\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.2\"\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: itamae-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: itamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        files:\n          - name: itamae\n            src: itamae-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: itamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        files:\n          - name: itamae\n            src: itamae-{{.Arch}}-{{.OS}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.11.1\")\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.11.7\")\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"< 1.14.4\")\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mitamae-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        github_artifact_attestations:\n          signer_workflow: itamae-kitchen/mitamae/.github/workflows/build.yml\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itaysk/kubectl-neat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itaysk\n    repo_name: kubectl-neat\n    description: Clean up Kubernetes yaml and json output to make it readable\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: kubectl-neat_{{.OS}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: kubectl-neat\n            src: dist/{{.OS}}/kubectl-neat\n      - version_constraint: semver(\"<= 2.0.2\")\n        asset: kubectl-neat_{{.OS}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubectl-neat_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchio/butler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: itchio\n    repo_name: butler\n    description: Command-line itch.io helper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://broth.itch.zone/butler/{{.OS}}-{{.Arch}}/{{trimV .Version}}/archive/default\n        format: zip\n        append_ext: false\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - amd64\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/bed/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: bed\n    asset: bed_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Binary editor written in Go\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: bed\n        src: bed_{{.Version}}_{{.OS}}_{{.Arch}}/bed\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/fillin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: fillin\n    asset: fillin_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: fill-in your command and execute\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: fillin\n        src: fillin_{{.Version}}_{{.OS}}_{{.Arch}}/fillin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/gojo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: gojo\n    asset: gojo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Yet another Go implementation of jo\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: gojo\n        src: gojo_{{.Version}}_{{.OS}}_{{.Arch}}/gojo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/gojq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: gojq\n    asset: gojq_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Pure Go implementation of jq\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: gojq\n        src: gojq_{{.Version}}_{{.OS}}_{{.Arch}}/gojq\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/json2yaml/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: json2yaml\n    asset: json2yaml_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: An efficient JSON to YAML converter written in Go language\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: json2yaml\n        src: json2yaml_{{.Version}}_{{.OS}}_{{.Arch}}/json2yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/maze/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: maze\n    description: A maze command written in Go\n    asset: maze_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: maze\n        src: maze_{{.Version}}_{{.OS}}_{{.Arch}}/maze\n    complete_windows_ext: false\n    version_constraint: semver(\">= 0.0.8\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.0.4\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"< 0.0.4\")\n        asset: maze_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        files:\n          - name: maze\n            src: maze_{{.OS}}_{{.Arch}}/maze\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: maze\n        complete_windows_ext: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/itchyny/mmv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: itchyny\n    repo_name: mmv\n    asset: mmv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: rename multiple files with editor\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: mmv\n        src: mmv_{{.Version}}_{{.OS}}_{{.Arch}}/mmv\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ivaaaan/smug/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ivaaaan\n    repo_name: smug\n    description: Session manager and task runner for tmux. Start your development environment within one command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.5\"\n        asset: smug.{{trimV .Version}}._{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: smug_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: smug_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: smug_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: smug_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ivanilves/lstags/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ivanilves\n    repo_name: lstags\n    description: Explore Docker registries and manipulate Docker images\n    asset: lstags-{{.OS}}-{{.Version}}.tar.gz\n    supported_envs:\n      - windows\n      - darwin\n      - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iximiuz/kexp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iximiuz\n    repo_name: kexp\n    description: \"k'exp - Kubernetes Explorer\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kexp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/iyear/tdl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: iyear\n    repo_name: tdl\n    description: A Telegram toolkit written in Golang\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tdl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tdl_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/j178/prek/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: j178\n    repo_name: prek\n    description: Better `pre-commit`, re-engineered in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: pre-commit-rs-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/pre-commit\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n                src: pre-commit\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.22\")\n        asset: prefligit-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/prefligit\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n                src: prefligit\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.28\")\n        asset: prek-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/prek\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: prek-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/prek\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: prek-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/prek\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n        github_immutable_release: true\n      - version_constraint: \"true\"\n        asset: prek-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: prek\n            src: \"{{.AssetWithoutExt}}/prek\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: prek\n        github_artifact_attestations:\n          signer_workflow: j178/prek/.github/workflows/release.yml\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jacek-kurlit/pik/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jacek-kurlit\n    repo_name: pik\n    description: Process Interactive Kill\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.0\"\n        asset: pik-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: pik\n            src: \"{{.AssetWithoutExt}}/pik\"\n      - version_constraint: Version == \"0.14.0\"\n        asset: pik-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: pik\n            src: \"{{.AssetWithoutExt}}/pik\"\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: pik-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: pik\n            src: \"{{.AssetWithoutExt}}/pik\"\n      - version_constraint: \"true\"\n        asset: pik-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: pik\n            src: \"{{.AssetWithoutExt}}/pik\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jackchuka/confluence-md/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jackchuka\n    repo_name: confluence-md\n    description: From Confluence to clean Markdown, images and all — just one command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: confluence-md_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: confluence-md_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jackchuka/mdschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jackchuka\n    repo_name: mdschema\n    description: A declarative schema-based Markdown validator that helps maintain consistent documentation structure across projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.11.2\")\n        asset: mdschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: mdschema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: mdschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: mdschema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jacobdeichert/mask/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jacobdeichert\n    repo_name: mask\n    description: A CLI task runner defined by a simple markdown file\n    asset: mask-{{.SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: darwin\n        replacements:\n          arm64: aarch64\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    files:\n      - name: mask\n        src: mask-{{.SemVer}}-{{.Arch}}-{{.OS}}/mask\n    supported_envs:\n      - darwin\n      - amd64\n    version_prefix: mask/\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    version_constraint: semver(\">= 0.11.4\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.11.3\")\n        asset: mask-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        version_prefix: \"\"\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.11.2\")\n        asset: mask-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        version_prefix: \"\"\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.11.1\")\n        asset: mask-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n        version_prefix: \"\"\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.11.1\")\n        asset: mask-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n        version_prefix: \"\"\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jamesWoolfenden/pike/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jamesWoolfenden\n    repo_name: pike\n    description: Pike is a tool for determining the permissions or policy required for IAC code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.3\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: pike_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pike_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.35\")\n        asset: pike_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pike_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: pike_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pike_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jamesob/desk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: jamesob\n    repo_name: desk\n    path: desk\n    description: A lightweight workspace manager for the shell\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jamf/Notifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jamf\n    repo_name: Notifier\n    description: Swift project which can post macOS alert or banner notifications on 10.15+ clients\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.3.0\")\n        asset: dataJAR-Notifier-{{.Version}}.{{.Format}}\n        format: pkg\n        files:\n          - name: Notifier\n            src: Payload/Applications/Utilities/Notifier.app/Contents/MacOS/Notifier\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: Notifier-{{.Version}}.{{.Format}}\n        format: pkg\n        files:\n          - name: Notifier\n            src: Payload/Applications/Utilities/Notifier.app/Contents/MacOS/Notifier\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jamietsao/random-winner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jamietsao\n    repo_name: random-winner\n    description: Wrote a silly program to select a random winner from my team\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: random-winner-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jbangdev/jbang/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jbangdev\n    repo_name: jbang\n    description: \"Unleash the power of Java - JBang Lets Students, Educators and Professional Developers create, edit and run self-contained source-only Java programs with unprecedented ease\"\n    link: https://jbang.dev/\n    search_words:\n      - java\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.48.0\")\n        error_message: Use version >= 0.48.0. Older versions are not supported.\n      - version_constraint: \"true\"\n        asset: jbang.zip\n        files:\n          - name: jbang\n            src: jbang/bin/jbang\n        overrides:\n          - goos: windows\n            files:\n              - name: jbang\n                src: jbang/bin/jbang.cmd\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jckuester/terradozer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jckuester\n    repo_name: terradozer\n    description: Terraform destroy without configuration files\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    asset: terradozer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: terradozer\n        src: terradozer_{{trimV .Version}}_{{.OS}}_{{.Arch}}/terradozer\n    checksum:\n      type: github_release\n      asset: terradozer_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jdx/hk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jdx\n    repo_name: hk\n    description: git hook and pre-commit lint manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.9\")\n        asset: hk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: semver(\"< 1.11.0\")\n        asset: hk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: \"true\"\n        asset: hk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jdx/mise/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jdx\n    repo_name: mise\n    aliases:\n      - name: jdxcode/rtx\n      - name: jdx/rtx\n    description: dev tools, env vars, task runner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2023.12.9\")\n        asset: rtx-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rtx\n            src: rtx/bin/rtx\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2024.0.0\")\n        asset: rtx-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rtx\n            src: rtx/bin/rtx\n        overrides:\n          - goos: linux\n            asset: rtx-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 2025.7.13, <= 2025.7.15\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2025.8.21\")\n        asset: mise-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        files:\n          - name: mise\n            src: mise/bin/mise\n        overrides:\n          - goos: darwin\n            asset: mise-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mise-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        files:\n          - name: mise\n            src: mise/bin/mise\n        overrides:\n          - goos: darwin\n            asset: mise-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jdx/pitchfork/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jdx\n    repo_name: pitchfork\n    description: Daemons with DX\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: pitchfork-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: \"true\"\n        asset: pitchfork-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jdx/usage/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jdx\n    repo_name: usage\n    description: A specification for CLIs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.16\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: usage-universal-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            asset: usage-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: usage-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: usage-universal-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.15.1\")\n        asset: usage-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: usage-universal-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n        github_immutable_release: true\n      - version_constraint: \"true\"\n        asset: usage-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            asset: usage-universal-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jedisct1/minisign/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jedisct1\n    repo_name: minisign\n    description: A dead simple tool to sign files and verify digital signatures\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3\")\n        asset: minisign-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"0.4\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.8\")\n        asset: minisign-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"0.9\"\n        asset: minisign-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: osx\n          windows: win64\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version in [\"0.10\", \"0.11\"]\n        asset: minisign-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win64\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: minisign\n                src: minisign-{{.OS}}/{{.Arch}}/minisign\n          - goos: windows\n            files:\n              - name: minisign\n                src: minisign-win64/minisign.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: minisign-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: minisign\n            src: minisign-{{.OS}}/{{.Arch}}/minisign\n        replacements:\n          darwin: macos\n          windows: win64\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            files:\n              - name: minisign\n        supported_envs:\n          - darwin/arm64\n          - windows\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jedisct1/piknik/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jedisct1\n    repo_name: piknik\n    description: Copy/paste anything over the network\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3\")\n        asset: piknik-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n          windows: win64\n        files:\n          - name: piknik\n            src: \"{{.OS}}/piknik\"\n        overrides:\n          - goos: linux\n            asset: piknik-{{.OS}}_{{.Arch}}-{{.Version}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n            files:\n              - name: piknik\n                src: \"{{.OS}}-{{.Arch}}/piknik\"\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: piknik-{{.OS}}_{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n          windows: win64\n        files:\n          - name: piknik\n            src: \"{{.OS}}/piknik\"\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n            files:\n              - name: piknik\n                src: \"{{.OS}}-{{.Arch}}/piknik\"\n          - goos: darwin\n            asset: piknik-{{.OS}}-{{.Version}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: piknik-{{.OS}}-{{.Version}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jenkins-x/jx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jenkins-x\n    repo_name: jx\n    description: Jenkins X provides automated CI+CD for Kubernetes with Preview Environments on Pull Requests using Cloud Native pipelines from Tekton\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v3.2.0\", \"3.2.381\", \"3.2.382\", \"3.2.383\", \"v3.5.19\", \"v3.7.0\", \"v3.10.159\"]\n        no_asset: true\n      - version_constraint: Version == \"v3.2.6\"\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: Version == \"v2.1.156\"\n        asset: jx-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-cli-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.1.155\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.2.5\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.2.261\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.3.4\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 3.4.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.10.182\")\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: jx-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: jx-checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/jenkins-x/jx/.github/workflows/jenkins-x-release.yaml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/jenkins-x/jx/releases/download/{{.Version}}/jx-checksums.txt.sig\n              - --certificate\n              - https://github.com/jenkins-x/jx/releases/download/{{.Version}}/jx-checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jenkins-zh/jenkins-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jenkins-zh\n    repo_name: jenkins-cli\n    description: Jenkins CLI allows you to manage your Jenkins in an easy way\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: jcli-{{.OS}}-{{.Arch}}.{{.Format}}\n    # There is a binary for darwin arm64, but it doesn't work.\n    # > zsh: killed      --help\n    rosetta2: true\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: jcli\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jesseduffield/horcrux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jesseduffield\n    repo_name: horcrux\n    description: Split your file into encrypted fragments so that you don't need to remember a passcode\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: horcrux_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: horcrux_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jesseduffield/lazydocker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jesseduffield\n    repo_name: lazydocker\n    description: The lazier way to manage everything docker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11\"\n        no_asset: true\n      - version_constraint: Version == \"v0.12\"\n        asset: lazydocker_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.7.4\")\n        asset: lazydocker_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: lazydocker_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: lazydocker_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jesseduffield/lazygit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jesseduffield\n    repo_name: lazygit\n    description: simple terminal UI for git commands\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.6\") || Version in [\"v0.1.12\", \"v0.1.77\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.1.7\"\n        asset: lazygit_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.11\")\n        asset: lazygit_{{.OS}}_{{.Arch}}_{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.16\")\n        asset: lazygit_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          arm64: arm\n      - version_constraint: Version == \"v0.1.22\"\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.25\"\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.1.29\")\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.16.2\")\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.17.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.24.2\")\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.34.0\")\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.53.0\")\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: lazygit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jesseduffield/lazynpm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jesseduffield\n    repo_name: lazynpm\n    description: terminal UI for npm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lazynpm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jessfraz/dockfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jessfraz\n    repo_name: dockfmt\n    description: Dockerfile format and parser. Like `gofmt` but for Dockerfiles\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dockfmt-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        overrides:\n          - goos: darwin\n            # Pre built binaries don't work on macOS because they are too old.\n            # https://github.com/aquaproj/aqua-registry/pull/23000#issuecomment-2116536645\n            type: go_install\n            path: github.com/jessfraz/dockfmt\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jetify-com/devbox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jetify-com\n    repo_name: devbox\n    aliases:\n      - name: jetpack-io/devbox\n    description: Instant, easy, and predictable development environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: devbox_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jez/as-tree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jez\n    repo_name: as-tree\n    description: Print a list of paths as a tree of paths\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: as-tree-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jiro4989/ojosama/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jiro4989\n    repo_name: ojosama\n    description: テキストを壱百満天原サロメお嬢様風の口調に変換します\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ojosama_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jiro4989/relma/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jiro4989\n    repo_name: relma\n    description: GitHub Releases Management cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: relma-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jiro4989/textimg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jiro4989\n    repo_name: textimg\n    asset: textimg-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Command to convert from color text (ANSI or 256) to image\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jirutka/tty-copy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jirutka\n    repo_name: tty-copy\n    description: Copy content to system clipboard via TTY and terminal using ANSI OSC52 sequence\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: tty-copy.{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: tty-copy.{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jj-vcs/jj/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jj-vcs\n    repo_name: jj\n    aliases:\n      - name: martinvonz/jj\n    description: A Git-compatible VCS that is both simple and powerful\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.3.1\", \"v0.5.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: jj_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: jj_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: jj-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.17.1\")\n        asset: jj-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.18.0\"\n        asset: jj-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: jj-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          # darwin/amd64 was dropped. https://github.com/martinvonz/jj/pull/3999#issuecomment-2198984242\n          - darwin/arm64\n          - windows\n          - linux\n      - version_constraint: \"true\"\n        asset: jj-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jkfran/killport/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jkfran\n    repo_name: killport\n    description: A command-line tool to easily kill processes running on a specified port\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: killport-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n      - version_constraint: Version == \"v0.5.0\"\n        asset: killport-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.8.0\") || Version == \"v1.0.0\"\n        asset: killport-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: killport-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n          linux: linux-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jmattheis/goverter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: jmattheis\n    repo_name: goverter\n    description: Generate type-safe Go converters by simply defining an interface\n    path: github.com/jmattheis/goverter/cmd/goverter\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jmespath/jp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jmespath\n    repo_name: jp\n    description: Command line interface to JMESPath - http://jmespath.org\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: jp-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.2.0\"\n        asset: jp-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: jp-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/joehillen/sysz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: joehillen\n    repo_name: sysz\n    description: An fzf  terminal UI for systemctl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sysz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/joerdav/xc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: joerdav\n    repo_name: xc\n    description: Markdown defined task runner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.30\"\n        asset: xc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.43\")\n        asset: xc_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: xc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/johanhaleby/kubetail/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: johanhaleby\n    repo_name: kubetail\n    path: kubetail\n    description: Bash script to tail Kubernetes logs from multiple pods at the same time\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/johnkerl/miller/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: johnkerl\n    repo_name: miller\n    description: Miller is like awk, sed, cut, join, and sort for name-indexed data such as CSV, TSV, and tabular JSON\n    asset: miller-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: mlr\n        src: miller-{{trimV .Version}}-{{.OS}}-{{.Arch}}/mlr\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: miller-{{trimV .Version}}-checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 6.9.0\")\n    version_overrides:\n      - version_constraint: Version == \"v5.1.0w\"\n        asset: mlr\n        format: raw\n        overrides: []\n        supported_envs:\n          - windows/amd64\n        checksum:\n          enabled: false\n      - version_constraint: Version == \"v6.0.0-beta\"\n        asset: mlr-{{.OS}}-latest.{{.Format}}\n        format: zip\n        files:\n          - name: mlr\n        overrides: []\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows/amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: Version == \"v6.0.0.rc1\"\n        asset: mlr-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        overrides: []\n        files:\n          - name: mlr\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows/amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 6.1.0\")\n        replacements:\n          darwin: macos\n      - version_constraint: semver(\">= 6.0.0\")\n        asset: miller_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        files:\n          - name: mlr\n        checksum:\n          type: github_release\n          asset: miller_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 5.10.3\")\n        asset: mlr.{{.OS}}_{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.10.1\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.9.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.8.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.7.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.6.2\")\n        asset: mlr.{{.OS}}_{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.6.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.5.0\")\n        asset: mlr.{{.OS}}_{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.4.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: windows\n            asset: mlr\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.3.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.2.2\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.2.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: mlr.mac{{.OS}}\n          - goos: windows\n            asset: mlr\n        replacements:\n          darwin: osx\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 5.1.0\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 2.1.3\")\n        asset: mlr.{{.OS}}.{{.Arch}}\n        format: raw\n        overrides: []\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 2.1.3\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jonaslu/ain/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jonaslu\n    repo_name: ain\n    asset: ain_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: An HTTP API client for the terminal\n    files:\n      - name: ain\n        src: ain_{{trimV .Version}}_{{.OS}}_{{.Arch}}/ain\n    replacements:\n      darwin: mac_os\n      amd64: x86_64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jorgerojas26/lazysql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jorgerojas26\n    repo_name: lazysql\n    description: A cross-platform TUI database management tool written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lazysql_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: lazysql_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/josephburnett/jd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: josephburnett\n    repo_name: jd\n    description: JSON diff and patch\n    asset: jd-{{.Arch}}-{{.OS}}\n    format: raw\n    version_constraint: semver(\">= 1.6.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.5.0\")\n        complete_windows_ext: false\n      - version_constraint: Version == \"v1.4.0\"\n        complete_windows_ext: false\n        rosetta2: true\n        overrides:\n          - goos: linux\n            goarch: arm64\n            type: go_install\n            path: github.com/josephburnett/jd\n          - goos: windows\n            goarch: arm64\n            type: go_install\n            path: github.com/josephburnett/jd\n      - version_constraint: semver(\">= 1.2.0\")\n        asset: jd\n        overrides:\n          - goarch: arm64\n            type: go_install\n            path: github.com/josephburnett/jd\n          - goos: darwin\n            goarch: amd64\n            type: go_install\n            path: github.com/josephburnett/jd\n          - goos: windows\n            goarch: amd64\n            type: go_install\n            path: github.com/josephburnett/jd\n      - version_constraint: semver(\"< 1.2.0\")\n        asset: jd\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/joshdk/retry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: joshdk\n    repo_name: retry\n    description: Rerun a command until it eventually succeeds, or doesn't\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.1\")\n        asset: retry-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: retry-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/joshmedeski/sesh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: joshmedeski\n    repo_name: sesh\n    description: Smart session manager for the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: sesh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sesh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jpbruinsslot/slack-term/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jpbruinsslot\n    repo_name: slack-term\n    aliases:\n      - name: erroneousboat/slack-term\n    description: Slack client for your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: slack-term-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jpillora/chisel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jpillora\n    repo_name: chisel\n    description: A fast TCP/UDP tunnel over HTTP\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: chisel_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}/chisel\"\n        replacements:\n          arm64: arm\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: chisel\n      - version_constraint: semver(\"<= 1.3.1\")\n        asset: chisel_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: arm\n          - goos: windows\n            asset: chisel_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n      - version_constraint: semver(\"<= 1.7.4\")\n        asset: chisel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: chisel_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.7.6\")\n        asset: chisel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: chisel_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.10.1\")\n        asset: chisel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: chisel_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: chisel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        files:\n          - name: chisel\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: chisel_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: chisel\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jqlang/jq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jqlang\n    repo_name: jq\n    aliases:\n      - name: stedolan/jq\n    description: Command-line JSON processor\n    version_constraint: \"false\"\n    version_prefix: jq-\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.4\")\n        asset: jq-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: windows\n            asset: jq-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"jq-1.5rc1\"\n        asset: jq-{{.OS}}-{{.Arch}}-static\n        format: raw\n        replacements:\n          windows: win64\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            asset: jq-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: Version == \"jq-1.5rc2\"\n        asset: jq-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: windows\n            asset: jq-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6\")\n        asset: jq-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          linux: linux64\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: darwin\n            asset: jq-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 1.8.0\")\n        asset: jq-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: jq-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: jqlang/jq/.github/workflows/ci.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jreisinger/checkip/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jreisinger\n    repo_name: checkip\n    aliases:\n      - name: jreisinger/checkip\n      - name: go-monk/checkip\n    description: Get (security) info about IP addresses\n    rosetta2: true\n    asset: checkip_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jreleaser/jreleaser/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: jreleaser/jreleaser\n    type: github_release\n    repo_owner: jreleaser\n    repo_name: jreleaser\n    description: Release projects quickly and easily with JReleaser\n    complete_windows_ext: false\n    asset: jreleaser-{{trimV .Version}}.zip\n    files:\n      - name: jreleaser\n        src: jreleaser-{{trimV .Version}}/bin/jreleaser\n    checksum:\n      type: github_release\n      asset: jreleaser-{{trimV .Version}}.zip.sha256\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jreleaser/jreleaser/standalone/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: jreleaser/jreleaser/standalone\n    type: github_release\n    repo_owner: jreleaser\n    repo_name: jreleaser\n    description: Release projects quickly and easily with JReleaser\n    rosetta2: true\n    replacements:\n      amd64: x86_64\n      darwin: osx\n      linux: linux_musl\n      arm64: aarch64\n    asset: jreleaser-standalone-{{trimV .Version}}-{{.OS}}-{{.Arch}}.zip\n    files:\n      - name: jreleaser\n        src: jreleaser-standalone-{{trimV .Version}}-{{.OS}}-{{.Arch}}/bin/jreleaser\n      - name: java\n        src: jreleaser-standalone-{{trimV .Version}}-{{.OS}}-{{.Arch}}/bin/java\n      - name: keytool\n        src: jreleaser-standalone-{{trimV .Version}}-{{.OS}}-{{.Arch}}/bin/keytool\n      - name: rmiregistry\n        src: jreleaser-standalone-{{trimV .Version}}-{{.OS}}-{{.Arch}}/bin/rmiregistry\n    checksum:\n      type: github_release\n      asset: checksums_sha256.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jscaltreto/eks-auth/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jscaltreto\n    repo_name: eks-auth\n    description: Standalone program to fetch authentication tokens for AWS EKS Clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: eks-auth-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jsonnet-bundler/jsonnet-bundler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jsonnet-bundler\n    repo_name: jsonnet-bundler\n    description: A jsonnet package manager\n    files:\n      - name: jb\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: jb-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.5.1\"\n        asset: jb-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: jb-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: jb-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jstemmer/go-junit-report/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jstemmer\n    repo_name: go-junit-report\n    description: Convert Go test output to JUnit XML\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: go-junit-report-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: go-junit-report-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jtyr/gbt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jtyr\n    repo_name: gbt\n    description: Highly configurable prompt builder for Bash, ZSH and PowerShell written in Go\n    rosetta2: true\n    asset: gbt-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: gbt\n        src: gbt-{{trimV .Version}}/gbt\n    checksum:\n      type: github_release\n      asset: gbt-{{trimV .Version}}-checksums-sha256.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/juan-leon/lowcharts/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: juan-leon\n    repo_name: lowcharts\n    description: Tool to draw low-resolution graphs in terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.5.1\"\n        asset: lowcharts-v0.5.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.6\")\n        asset: lowcharts-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: lowcharts-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/juanfont/headscale/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: juanfont\n    repo_name: headscale\n    description: An open source, self-hosted implementation of the Tailscale control server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: headscale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: headscale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: headscale_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: headscale_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jubako/arx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jubako\n    repo_name: arx\n    description: Store files and directory in an archive. Like tar, but faster and with direct random access\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: arx-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: arx\n            src: arx-{{.Version}}-{{.OS}}/arx\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              type: github_release\n              file_format: regexp\n              asset: \"{{.Asset}}.sha256\"\n              algorithm: sha256\n              pattern:\n                checksum: ^(\\b[A-Fa-f0-9]{64}\\b)\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/juicedata/juicefs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: juicedata\n    repo_name: juicefs\n    description: JuiceFS is a distributed POSIX file system built on top of Redis and S3\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.12.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.0-beta2\")\n        asset: juicefs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: juicefs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/juliosueiras/terraform-lsp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: juliosueiras\n    repo_name: terraform-lsp\n    description: Language Server Protocol for Terraform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: terraform-lsp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: terraform-lsp_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jumppad-labs/jumppad/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jumppad-labs\n    repo_name: jumppad\n    aliases:\n      - name: shipyard-run/shipyard\n    description: Modern cloud native development environments\n    asset: jumppad_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.5.8\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.3.20\")\n        asset: shipyard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        checksum:\n          enabled: false\n        files:\n          - name: shipyard\n      - version_constraint: semver(\">= 0.3.13\")\n        files:\n          - name: shipyard\n        asset: shipyard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\">= 0.3.6\")\n        files:\n          - name: shipyard\n        asset: shipyard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\">= 0.0.3\")\n        files:\n          - name: shipyard\n        asset: shipyard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.2\")\n        asset: shipyard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: shipyard\n        replacements:\n          amd64: x86_64\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/junegunn/fzf/fzf-tmux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: junegunn/fzf/fzf-tmux\n    type: github_content\n    repo_owner: junegunn\n    repo_name: fzf\n    path: bin/fzf-tmux\n    description: starts fzf in a tmux pane\n    files:\n      - name: fzf-tmux\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/junegunn/fzf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: junegunn\n    repo_name: fzf\n    description: \":cherry_blossom: A command-line fuzzy finder\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.25.1\")\n        asset: fzf-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fzf_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.26.0\"\n        asset: fzf-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fzf_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.27.3\")\n        asset: fzf-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fzf_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 0.53.0\")\n        asset: fzf-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: fzf_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.54.1\")\n        asset: fzf-{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: fzf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: \"true\"\n        asset: fzf-{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: fzf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/just-every/code/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: just-every\n    repo_name: code\n    description: Fast, effective, mind-blowing, coding CLI. Browser integration, multi-agents, theming, and reasoning control. Orchestrate agents from OpenAI, Claude, Gemini or any provider\n    version_filter: not (Version startsWith \"preview\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.3\"\n        asset: code-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: coder-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: code-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.1.13\")\n        asset: coder-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.2.34\")\n        asset: code-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: code-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        files:\n          - name: code\n            src: code-{{.Arch}}-{{.OS}}\n        overrides:\n          - goos: windows\n            format: zip\n            asset: code-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n            files:\n              - name: code\n                src: code-{{.Arch}}-{{.OS}}.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/justjanne/powerline-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: justjanne\n    repo_name: powerline-go\n    description: A beautiful and useful low-latency prompt for your shell, written in go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: powerline-go\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.0\")\n        asset: powerline-go-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.16.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.18.0\")\n        asset: powerline-go-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.19.0\"\n        no_asset: true\n      - version_constraint: semver(\"< 1.23\")\n        asset: powerline-go-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: Version == \"v1.23\"\n        asset: powerline-go-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - amd64\n      - version_constraint: \"true\"\n        asset: powerline-go-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/justmiles/go-markdown2confluence/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: justmiles\n    repo_name: go-markdown2confluence\n    description: Push markdown files to Confluence Cloud\n    asset: go-markdown2confluence_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    files:\n      - name: markdown2confluence\n    version_constraint: semver(\">= 3.3.2\")\n    version_overrides:\n      - version_constraint: semver(\">= 3.3.1\")\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 3.3.0\")\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 3.1.1\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 3.0.0\")\n        asset: markdown2confluence_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 2.0.0\")\n        asset: markdown2confluence-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 2.0.0\")\n        asset: markdown2confluence.{{.OS}}-{{.Arch}}\n        format: raw\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/jwilder/dockerize/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: jwilder\n    repo_name: dockerize\n    description: Utility to simplify running applications in docker containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: dockerize-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: dockerize-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: dockerize-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k0sproject/k0s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k0sproject\n    repo_name: k0s\n    description: k0s - The Zero Friction Kubernetes\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: k0s-{{.Version}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.27.16+k0s.0\")\n        asset: k0s-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 1.28.15+k0s.0\")\n        asset: k0s-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: >-\n          (semver(\"<= 1.32.3+k0s.0\") && semver(\">= 1.32.0+k0s.0\")) ||\n          (semver(\"<= 1.31.7+k0s.0\") && semver(\">= 1.31.0+k0s.0\")) ||\n          (semver(\"<= 1.30.11+k0s.0\") && semver(\">= 1.30.0+k0s.0\")) ||\n          semver(\"<= 1.29.15+k0s.0\")\n        asset: k0s-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        cosign:\n          signature:\n            type: github_release\n            asset: \"{{.Asset}}.sig\"\n          key:\n            type: github_release\n            asset: \"cosign.pub\"\n          opts:\n            # `--insecure-ignore-tlog` is required because it is signed with `--tlog-upload=false` option\n            # see also:\n            # https://github.com/k0sproject/k0s/pull/5724\n            # https://github.com/k0sproject/k0s/commit/a01579db2dc7916194e6fd95949b6b4fbbfa2252\n            - --insecure-ignore-tlog\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: \"true\"\n        asset: k0s-{{.Version}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        cosign:\n          signature:\n            type: github_release\n            asset: \"{{.Asset}}.sig\"\n          key:\n            type: github_release\n            asset: \"cosign.pub\"\n        supported_envs:\n          - linux\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k0sproject/k0sctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k0sproject\n    repo_name: k0sctl\n    description: A bootstrapping and management tool for k0s clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: k0sctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: k0sctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.4\")\n        asset: k0sctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.18.1\")\n        asset: k0sctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: k0sctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          windows: win\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/awsdo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: awsdo\n    description: awsdo is a tool to do anything using AWS temporary credentials\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: awsdo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: awsdo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: awsdo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/coglet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: coglet\n    description: coglet is a tool for User pool of Amazon Cognito\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: coglet_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/concrun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: concrun\n    description: Run commands concurrently\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: concrun_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/cuestr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: cuestr\n    description: cuestr is a utility tool for string literals in CUE files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cuestr_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/deck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: deck\n    description: deck is a tool for creating deck using Markdown and Google Slides\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: deck_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/gh-do/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: gh-do\n    description: \":octocat: gh-do is a tool to do anything using GitHub credentials\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: gh-do_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gh-do_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/gh-setup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: gh-setup\n    description: Setup asset of Github releases\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: gh-setup_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gh-setup_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/git-wt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: git-wt\n    description: A Git subcommand that makes `git worktree` simple\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: git-wt_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/gostyle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: gostyle\n    description: gostyle is a set of analyzers for coding styles\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.14.1\", \"v0.20.1\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gostyle_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/hclstr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: hclstr\n    description: hclstr is a utility tool for string literals in HCL files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: hclstr_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/mo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: mo\n    description: mo is a Markdown viewer that opens .md files in a browser\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/ndiag/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: ndiag\n    description: ndiag is a high-level architecture diagramming/documentation tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.14.2\")\n        asset: ndiag_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ndiag_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/octocov/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: octocov\n    description: octocov is a toolkit for collecting code metrics (code coverage, code to test ratio, test execution time and your own custom metrics)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.47.0\"\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.28.2\")\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.40.1\")\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.51.0\")\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.56.1\")\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: octocov_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/oldstable/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: oldstable\n    description: Check if version of go directive in go.mod is oldstable\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: oldstable_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/roots/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: roots\n    description: \"`roots` is a tool for exploring multiple root directories, such as those in a monorepo project\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: roots_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/runn/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: runn\n    description: runn is a package/tool for running operations following a scenario\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.17.0\", \"v0.58.0\", \"v0.112.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.1\"\n        asset: runbk_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: runbk\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.59.4\")\n        asset: runn_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.75.3\")\n        asset: runn_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: runn_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/stubin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: stubin\n    description: This is stub binary\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: stubin_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tailor-log/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tailor-log\n    description: tailor-log is a tool for handling logs from a workspace on the Tailor Platform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tailor-log_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tbls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tbls\n    asset: tbls_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: tbls is a CI-Friendly tool for document a database, written in Go\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"checksums-{{.OS}}.txt\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tbls-ask/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tbls-ask\n    description: tbls-ask is an external subcommand of tbls for asking LLM of the datasource\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\") or Version == \"v0.1.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tbls-ask_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tbls-driver-tailordb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tbls-driver-tailordb\n    description: tbls driver for TailorDB schema definition\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tbls-driver-tailordb_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tcmux/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tcmux\n    description: tcmux is a terminal and coding agent mux viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tcmux_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k1LoW/tmpmod/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k1LoW\n    repo_name: tmpmod\n    description: tmpmod is a tool for temporary use of modified Go modules\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tmpmod_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k3d-io/k3d/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k3d-io\n    repo_name: k3d\n    aliases:\n      - name: rancher/k3d\n    description: Little helper to run CNCF's k3s in Docker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v3.0.0-syntax.0\", \"v3.1.0-dev.0\", \"v3.4.0-test.0\", \"v4.1.0-alpha.2\"]\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 3.0.0-rc.3\")\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 4.2.0\")\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.3.0\")\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.4.9\")\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: k3d-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k3s-io/k3s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k3s-io\n    repo_name: k3s\n    description: Lightweight Kubernetes\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: k3s-{{.Arch}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: k3s\n        checksum:\n          type: github_release\n          asset: sha256sum-{{.Arch}}.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/k8sgpt-ai/k8sgpt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: k8sgpt-ai\n    repo_name: k8sgpt\n    description: Giving Kubernetes Superpowers to everyone\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= v0.3.33, <= v0.3.36\") || semver(\">= v0.3.42, <= v0.3.44\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: k8sgpt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kachick/selfup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kachick\n    repo_name: selfup\n    description: Versions should know how to update themselves\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: selfup_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kahing/goofys/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kahing\n    repo_name: goofys\n    description: a high-performance, POSIX-ish Amazon S3 file system written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: goofys\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kamadorueda/alejandra/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kamadorueda\n    repo_name: alejandra\n    description: The Uncompromising Nix Code Formatter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.0\"\n        asset: alejandra-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: alejandra-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kanisterio/kanister/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kanisterio\n    repo_name: kanister\n    description: An extensible framework for application-level data management on Kubernetes\n    asset: kanister_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: kanctl\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.84.0\")\n    # The darwin support was removed.\n    # https://github.com/aquaproj/aqua-registry/pull/7537#issuecomment-1299550841\n    supported_envs:\n      - linux/amd64\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kashav/fsql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kashav\n    repo_name: fsql\n    description: Search for files using a fun query language\n    version_constraint: semver(\">= 0.5.1\")\n    # asset name was changed\n    asset: fsql-{{trimV .Version}}-fsql-{{.OS}}-{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    # asset structure was changed\n    files:\n      - name: fsql\n        src: fsql-{{.OS}}-{{.Arch}}/fsql\n    version_overrides:\n      - version_constraint: semver(\"= 0.5.0\")\n        # No asset was released\n        type: go_install\n        path: github.com/kashav/fsql/cmd/fsql\n        files:\n          - name: fsql\n      - version_constraint: semver(\"= 0.4.0\")\n        asset: fsql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tar.gz\n        # arm64 wasn't supported\n        rosetta2: true\n        files:\n          - name: fsql\n            src: \"{{.OS}}-{{.Arch}}/fsql\"\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 0.3.0\")\n        # asset name was changed\n        asset: fsql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tar.gz\n        rosetta2: true\n        # asset structure was changed\n        files:\n          - name: fsql\n            src: \"{{.OS}}-{{.Arch}}/fsql\"\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_{{.Arch}}.tar.gz\"\n        rosetta2: true\n        overrides:\n          - goos: windows\n            asset: \"{{.OS}}_{{.Arch}}.zip\"\n        files:\n          - name: fsql\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kastenhq/external-tools/k10multicluster/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kastenhq/external-tools/k10multicluster\n    type: github_release\n    repo_owner: kastenhq\n    repo_name: external-tools\n    description: Used to distribute external tools\n    asset: k10multicluster_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: k10multicluster\n    replacements:\n      darwin: macOS\n    supported_envs:\n      - linux\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 6.0.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 4.5.0\")\n        rosetta2: false\n      - version_constraint: semver(\">= 4.0.3\")\n        asset: k10multicluster_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: false\n      - version_constraint: semver(\"< 4.0.3\")\n        asset: k10multicluster_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kastenhq/external-tools/k10tools/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kastenhq/external-tools/k10tools\n    type: github_release\n    repo_owner: kastenhq\n    repo_name: external-tools\n    description: Used to distribute external tools\n    asset: k10tools_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: k10tools\n    replacements:\n      darwin: macOS\n    supported_envs:\n      - linux\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 6.0.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 4.5.0\")\n        rosetta2: false\n      - version_constraint: semver(\">= 4.0.3\")\n        asset: k10tools_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: false\n      - version_constraint: semver(\">= 3.0.7\")\n        asset: k10tools_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"< 3.0.7\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kastenhq/kubestr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kastenhq\n    repo_name: kubestr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.4.14\", \"v0.4.32\", \"v0.4.42\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.4.23\"\n        asset: kubestr-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.4.29\"\n        asset: kubestr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.18\")\n        asset: kubestr-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.22\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kubestr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/katbyte/terrafmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: katbyte\n    repo_name: terrafmt\n    description: Format terraform blocks embedded in files\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kattouf/ProgressLine/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kattouf\n    repo_name: ProgressLine\n    description: Track commands progress in a compact one-line format\n    files:\n      - name: progressline\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: progressline-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-macosx\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: progressline-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-macosx\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kawaz/authsock-filter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kawaz\n    repo_name: authsock-filter\n    description: SSH agent proxy with filtering and logging\n    asset: authsock-filter-{{.Arch}}-{{.OS}}.tar.gz\n    format: tar.gz\n    files:\n      - name: authsock-filter\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n    supported_envs:\n      - darwin\n      - linux/amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kayac/ecspresso/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kayac\n    repo_name: ecspresso\n    asset: ecspresso_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: ecspresso is a deployment tool for Amazon ECS\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kayac/go-katsubushi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kayac\n    repo_name: go-katsubushi\n    description: ID generator server\n    version_constraint: semver(\">= 2.0.0\")\n    asset: go-katsubushi_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: katsubushi\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      # checksum file not provided & tag style was changed\n      - version_constraint: semver(\">= 1.6.1\")\n        asset: go-katsubushi_v{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n        rosetta2: true\n        files:\n          - name: katsubushi\n            src: go-katsubushi_v{{.Version}}_{{.OS}}_{{.Arch}}/katsubushi\n        supported_envs:\n          - darwin\n          - linux/amd64\n        checksum:\n          enabled: false\n      # asset name was changed\n      - version_constraint: semver(\">= 0.1.0\")\n        asset: katsubushi-{{.Version}}-{{.OS}}-{{.Arch}}.zip\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n        checksum:\n          enabled: false\n      # linux only support\n      - version_constraint: \"true\"\n        asset: katsubushi-{{.Version}}-{{.OS}}-{{.Arch}}.zip\n        files:\n          - name: katsubushi\n            src: katsubushi-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux/amd64\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kaytu-io/kaytu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kaytu-io\n    repo_name: kaytu\n    description: The Kaytu CLI helps you save on cloud costs by finding the perfect server sizes. Kaytu analyzes historical usage and provides tailored recommendations, ensuring you only pay for the resources you need\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kaytu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: raw\n            asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kaytu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kaytu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kaytu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: kaytu\n                src: \"{{.AssetWithoutExt}}/kaytu.exe\"\n            checksum:\n              type: github_release\n              asset: kaytu_{{trimV .Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n              algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kcl-lang/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kcl-lang\n    repo_name: cli\n    description: The KCL Command Line Interface (CLI)\n    asset: kcl-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: cli_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    files:\n      - name: kcl\n    overrides:\n      - goos: windows\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kcl-lang/kcl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kcl-lang\n    repo_name: kcl\n    description: KCL Programming Language (CNCF Sandbox Project). https://kcl-lang.io\n    files:\n      - name: kcl-language-server\n      - name: kclvm_cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kclvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kcl-language-server\n            src: kclvm/bin/kcl-language-server\n          - name: kclvm_cli\n            src: kclvm/bin/kclvm_cli\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kcp-dev/kcp/kubectl-kcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kcp-dev/kcp/kubectl-kcp\n    type: github_release\n    repo_owner: kcp-dev\n    repo_name: kcp\n    description: kubectl plugins for kcp\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.2\")\n        format: tar.gz\n        asset: kubectl-kcp-plugin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kubectl-kcp\n            src: bin/kubectl-kcp\n          - name: kubectl-ws\n            src: bin/kubectl-ws\n          - name: kubectl-workspaces\n            src: bin/kubectl-workspaces\n      - version_constraint: semver(\"<= 0.24.0\")\n        format: tar.gz\n        asset: kubectl-kcp-plugin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kubectl-kcp\n            src: bin/kubectl-kcp\n          - name: kubectl-workspace\n            src: bin/kubectl-workspace\n          - name: kubectl-ws\n            src: bin/kubectl-workspace\n          - name: kubectl-workspaces\n            src: bin/kubectl-workspace\n      - version_constraint: \"true\"\n        format: tar.gz\n        asset: kubectl-kcp-plugin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kubectl-kcp\n            src: bin/kubectl-kcp\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kcp-dev/kcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kcp-dev\n    repo_name: kcp\n    asset: kcp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: kcp\n        src: bin/kcp\n    format: tar.gz\n    description: kcp is a Kubernetes-like control plane for workloads on many clusters\n    supported_envs:\n      - darwin\n      - linux\n    checksum:\n      type: github_release\n      asset: kcp_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kdabir/has/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: kdabir\n    repo_name: has\n    path: has\n    description: checks presence of various command line tools and their versions on the path\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kdash-rs/kdash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kdash-rs\n    repo_name: kdash\n    description: A simple and fast dashboard for Kubernetes\n    asset: kdash-{{.OS}}.{{.Format}}\n    format: tar.gz\n    rosetta2: true\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    checksum:\n      type: github_release\n      asset: kdash-{{.OS}}.sha256\n      algorithm: sha256\n    version_constraint: semver(\">= 0.4.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.3.3\")\n        replacements:\n          darwin: macos\n          linux: linux-musl\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        overrides: &kdash_rs_overrides_1\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: kdash-{{.OS}}.sha256\n              algorithm: sha256\n          - goos: linux\n            goarch: arm64\n            asset: kdash-aarch64-musl.tar.gz\n            checksum:\n              type: github_release\n              asset: kdash-aarch64-musl.sha256\n              algorithm: sha256\n      - version_constraint: semver(\">= 0.0.4\")\n        overrides: *kdash_rs_overrides_1\n        replacements:\n          darwin: macos\n          linux: linux-musl\n      - version_constraint: semver(\"< 0.0.4\")\n        overrides: *kdash_rs_overrides_1\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kdheepak/taskwarrior-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kdheepak\n    repo_name: taskwarrior-tui\n    description: \"`taskwarrior-tui`: A terminal user interface for taskwarrior\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: taskwarrior-tui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.2.0\"\n        asset: taskwarrior-tui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version in [\"v0.13.3\", \"v0.25.2\"]\n        asset: taskwarrior-tui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: taskwarrior-tui-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"v0.26.1\", \"v0.26.2\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: taskwarrior-tui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: taskwarrior-tui-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/keidarcy/e1s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: keidarcy\n    repo_name: e1s\n    description: E1S - Easily Manage AWS ECS Resources in Terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: e1s_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: e1s_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        checksum:\n          type: github_release\n          asset: e1s_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/keilerkonzept/terraform-module-versions/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: keilerkonzept\n    repo_name: terraform-module-versions\n    description: \"CLI tool that checks Terraform code for module updates. Single binary, no dependencies. linux, osx, windows. #golang #cli #terraform\"\n    asset: terraform-module-versions_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: osx\n    supported_envs:\n      - darwin\n    rosetta2: true\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"3.0.29\", \"3.1.14\"]\n        no_asset: true\n      - version_constraint: semver(\"< 3.1.14\")\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/keisku/kubectl-explore/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: keisku\n    repo_name: kubectl-explore\n    description: A better kubectl explain with the fuzzy finder\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: kubectl-explore_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: kubectl-explore_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: kubectl-explore_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: kubectl-explore_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubectl-explore_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubectl-explore_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kellyjonbrazil/jc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kellyjonbrazil\n    repo_name: jc\n    description: CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts\n    asset: jc-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        asset: jc-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        files:\n          - name: jc\n            src: jc-{{trimV .Version}}-windows/jc.exe\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    version_constraint: semver(\">= 1.21.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.19.0\")\n        overrides:\n          - goos: windows\n            format: zip\n            asset: jc-{{trimV .Version}}-{{.OS}}.{{.Format}}\n      - version_constraint: semver(\"< 1.19.0\")\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kentaro-m/md2confl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kentaro-m\n    repo_name: md2confl\n    description: md2confl is a CLI tool to convert the markdown text to confluence wiki format\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: \"{{.OS}}_{{.Arch}}_md2confl\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: md2confl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kesonan/github-compare/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: kesonan\n    repo_name: github-compare\n    aliases:\n      - name: anqiansong/github-compare\n    description: A Command-line statistics tool to compare the GitHub repositories\n    path: github.com/anqiansong/github-compare\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kettle11/devserver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kettle11\n    repo_name: devserver\n    description: A simple HTTPS server for local development. Implemented in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: devserver-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: devserver-{{.Arch}}-{{.OS}}.sha512\n          algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kevincobain2000/gobrew/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kevincobain2000\n    repo_name: gobrew\n    description: Go version manager, written in Go. Super simple tool to install and manage Go versions. Install go without root. Gobrew doesn't require shell rehash\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.9.3\"\n        asset: gobrew-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gobrew_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.10.8\")\n        asset: gobrew-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gobrew_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gobrew-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: gobrew_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kevwan/depu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kevwan\n    repo_name: depu\n    description: A tool to check  available updates of packages in go.mod\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: depu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: depu_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kevwan/tproxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kevwan\n    repo_name: tproxy\n    description: A cli tool to proxy and analyze TCP connections\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tproxy-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kiali/kiali/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kiali\n    repo_name: kiali\n    description: Kiali project, observability for the Istio service mesh\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.14.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kiali-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kjokjo/ipcalc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: kjokjo\n    repo_name: ipcalc\n    path: ipcalc\n    description: ipcalc takes an IP address and netmask and calculates the resulting broadcast, network, Cisco wildcard mask, and host range\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kkdai/youtube/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kkdai\n    repo_name: youtube\n    asset: youtubedr_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Download Youtube Video in Golang\n    files:\n      - name: youtubedr\n    checksum:\n      type: github_release\n      asset: youtubedr_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kkinnear/zprint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kkinnear\n    repo_name: zprint\n    description: Beautifully format Clojure and Clojurescript source code and s-expressions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.7\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.10\")\n        asset: zprint{{.OS}}-{{.Version}}\n        format: raw\n        replacements:\n          linux: l\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.2.7\")\n        asset: zprint{{.OS}}-{{.Version}}\n        format: raw\n        replacements:\n          darwin: m\n          linux: l\n        supported_envs:\n          - darwin/amd64\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: zprint{{.OS}}-{{.Version}}\n        format: raw\n        replacements:\n          darwin: m\n          linux: l\n        supported_envs:\n          - darwin\n          - linux/amd64\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: zprint{{.OS}}a-{{.Version}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kluctl/kluctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kluctl\n    repo_name: kluctl\n    description: The missing glue to put together large Kubernetes deployments, composed of multiple smaller parts (Helm/Kustomize/...)  in a manageable and unified way\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.6.2\")\n        asset: kluctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.7.1\")\n        asset: kluctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.7.8\")\n        asset: kluctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.7.9\"\n        asset: kluctl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kluctl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: kluctl_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knadh/listmonk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knadh\n    repo_name: listmonk\n    description: High performance, self-hosted, newsletter and mailing list manager with a modern dashboard. Single binary app\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.4.0\")\n        asset: listmonk_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: listmonk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: listmonk_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: listmonk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knative/client/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knative\n    repo_name: client\n    format: raw\n    asset: kn-{{.OS}}-{{.Arch}}\n    description: Knative developer experience, docs, reference Knative CLI implementation\n    files:\n      - name: kn\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knative/func/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knative\n    repo_name: func\n    description: Knative Functions client API and CLI\n    format: raw\n    asset: func_{{.OS}}_{{.Arch}}\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semverWithVersion(\">= 1.7.0\", trimPrefix(Version, \"knative-\")) or semver(\">= 0.26.0\")\n    # support linux/arm64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_overrides:\n      - version_constraint: semver(\">= 0.23.1\")\n        # support darwin/arm64\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 0.20.0\")\n        # support checksum\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 0.9.0\")\n        # rename faas to function\n        asset: func_{{.OS}}_{{.Arch}}.gz\n        overrides:\n          - goos: windows\n            asset: func_{{.OS}}_{{.Arch}}.exe.gz\n        format: gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n        files:\n          - name: func\n            src: func_{{.OS}}_{{.Arch}}\n      - version_constraint: \"true\"\n        asset: faas_{{.OS}}_{{.Arch}}.gz\n        overrides:\n          - goos: windows\n            asset: faas_{{.OS}}_{{.Arch}}.exe.gz\n        format: gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n        files:\n          - name: faas\n            src: faas_{{.OS}}_{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knqyf263/cob/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knqyf263\n    repo_name: cob\n    description: Continuous Benchmark for Go Project\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.6\")\n        asset: cob_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: cob_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: cob_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: cob_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knqyf263/go-plugin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knqyf263\n    repo_name: go-plugin\n    description: Go Plugin System over WebAssembly\n    asset: go-plugin_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: protoc-gen-go-plugin\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: go-plugin_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knqyf263/pet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knqyf263\n    repo_name: pet\n    description: Simple command-line snippet manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.4\"\n        asset: pet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: pet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: pet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: pet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knqyf263/sou/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knqyf263\n    repo_name: sou\n    description: A tool for exploring files in container image layers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sou_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/knqyf263/utern/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: knqyf263\n    repo_name: utern\n    description: Multi group and stream log tailing for AWS CloudWatch Logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: utern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: utern_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: utern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: utern_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: utern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: utern_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: utern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: utern_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ko-build/ko/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ko-build\n    repo_name: ko\n    aliases:\n      - name: google/ko\n    asset: ko_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Build and deploy Go applications on Kubernetes\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    slsa_provenance:\n      type: github_release\n      asset: multiple.intoto.jsonl\n    version_constraint: semver(\"> 0.12.0\")\n    version_overrides:\n      - version_constraint: 'semver(\"<=0.12.0\")'\n        slsa_provenance:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ko1nksm/getoptions/gengetoptions/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: ko1nksm/getoptions/gengetoptions\n    repo_owner: ko1nksm\n    repo_name: getoptions\n    type: github_release\n    description: An elegant option/argument parser for shell scripts (full support for bash and all POSIX shells)\n    asset: gengetoptions\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ko1nksm/getoptions/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ko1nksm\n    repo_name: getoptions\n    description: An elegant option/argument parser for shell scripts (full support for bash and all POSIX shells)\n    asset: getoptions\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ko1nksm/shdotenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ko1nksm\n    repo_name: shdotenv\n    description: dotenv for shells with support for POSIX-compliant and multiple .env file syntax\n    asset: shdotenv\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koalaman/shellcheck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koalaman\n    repo_name: shellcheck\n    description: ShellCheck, a static analysis tool for shell scripts\n    version_filter: (not (Version in [\"latest\", \"stable\"])) and semver(\"> 0.4.5\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: shellcheck-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: shellcheck\n            src: shellcheck-{{.Version}}/shellcheck\n        overrides:\n          - goos: windows\n            asset: shellcheck-{{.Version}}.{{.Format}}\n            format: zip\n            files:\n              - name: shellcheck\n                src: shellcheck-{{.Version}}.exe\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: shellcheck-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: shellcheck\n            src: shellcheck-{{.Version}}/shellcheck\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: shellcheck-{{.Version}}.{{.Format}}\n            format: zip\n            files:\n              - name: shellcheck\n      - version_constraint: \"true\"\n        asset: shellcheck-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: shellcheck\n            src: shellcheck-{{.Version}}/shellcheck\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            asset: shellcheck-{{.Version}}.{{.Format}}\n            format: zip\n            files:\n              - name: shellcheck\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koki-develop/clive/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koki-develop\n    repo_name: clive\n    description: Automates terminal operations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: clive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: clive_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koki-develop/gat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koki-develop\n    repo_name: gat\n    description: cat alternative written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.19.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: gat_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.20.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gat_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koki-develop/moview/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koki-develop\n    repo_name: moview\n    description: Play video in terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: moview_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: moview_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koki-develop/sheep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koki-develop\n    repo_name: sheep\n    description: Sleep with Sheep\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sheep_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koluku/s3s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koluku\n    repo_name: s3s\n    description: Easy S3 select like searching in directories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: s3s_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/konradsz/igrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: konradsz\n    repo_name: igrep\n    description: Interactive Grep\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: igrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: ig\n            src: target/{{.Arch}}-{{.OS}}/release/ig\n      - version_constraint: Version == \"v0.3.0\"\n        asset: igrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: ig\n      - version_constraint: \"true\"\n        asset: igrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: ig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kool-dev/kool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kool-dev\n    repo_name: kool\n    description: \"From local development to the cloud: web apps development with containers made easy\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.6\")\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: kool-{{.OS}}-{{.Arch}}.checksum\n          algorithm: sha1\n      - version_constraint: semver(\"<= 1.0.15\")\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: kool-{{.OS}}-{{.Arch}}.checksum\n          algorithm: sha1\n      - version_constraint: Version == \"1.0.16\"\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: kool.exe\n            replacements:\n              amd64: amd64\n            checksum:\n              type: github_release\n              asset: kool.exe.checksum\n              algorithm: sha1\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: kool-{{.OS}}-{{.Arch}}.checksum\n          algorithm: sha1\n      - version_constraint: semver(\"<= 1.10.1\")\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: kool\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.14.0\")\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: kool\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: kool\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kool-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          # https://github.com/kool-dev/kool/pull/491\n          # Drop native windows support\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kopia/kopia/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kopia\n    repo_name: kopia\n    asset: kopia-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Cross-platform backup tool for Windows, macOS & Linux with fast, incremental backups, client-side end-to-end encryption, compression and data deduplication. CLI and GUI included\n    replacements:\n      amd64: x64\n      darwin: macOS\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: kopia\n        src: kopia-{{trimV .Version}}-{{.OS}}-{{.Arch}}/kopia\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koron/iferr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: koron\n    repo_name: iferr\n    description: Generate \"if err != nil {\" block\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kovetskiy/mark/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kovetskiy\n    repo_name: mark\n    description: Sync your markdown files with Confluence pages\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.0\")\n        asset: mark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: mark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 6.7.0\")\n        asset: mark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 9.1.0\")\n        asset: mark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 9.1.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 9.6.2\")\n        asset: mark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mark_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/koyeb/koyeb-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: koyeb\n    repo_name: koyeb-cli\n    description: Koyeb cli\n    files:\n      - name: koyeb\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: koyeb-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.0.0-rc1\"\n        asset: koyeb-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.1\")\n        asset: koyeb-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: koyeb-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kptdev/kpt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kptdev\n    repo_name: kpt\n    aliases:\n      - name: GoogleContainerTools/kpt\n    description: Automate Kubernetes Configuration Editing\n    version_filter: |\n      not (Version startsWith \"porch/\" or Version startsWith \"package-examples/\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.33.0\")\n        asset: kpt_{{.OS}}_{{.Arch}}_{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.37.1\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.38.1\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.39.3\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.0-alpha.5\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.19\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.21\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        # slsa_provenance:\n        #   # FAILED: SLSA verification failed: source used to generate the binary does not match provenance: expected source 'kptdev/kpt', got 'GoogleContainerTools/kpt'\n        #   type: github_release\n        #   asset: attestation.intoto.jsonl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.0.0-beta.22\"\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.35\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        # slsa_provenance:\n        #   # Verifying artifact /tmp/048982138: FAILED: source used to generate the binary does not match provenance: expected source 'kptdev/kpt', got 'GoogleContainerTools/kpt'\n        #   type: github_release\n        #   asset: multiple.intoto.jsonl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.0.0-beta.36\"\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: kpt_darwin_{{.Arch}}\n            format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.49\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.51\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta.55\")\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: kpt_{{.OS}}_{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/krallin/tini/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: krallin\n    repo_name: tini\n    description: A tiny but valid `init` for containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tini-static-{{.Arch}}\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kreuzwerker/awsu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kreuzwerker\n    repo_name: awsu\n    description: Enhanced account switching for AWS, supports Yubikey as MFA source\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.3.10\"\n        asset: awsu_{{trimV .Version}}_{{.OS}}_arm.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.3.2\")\n        asset: awsu-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.3.9\")\n        asset: awsu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: awsu_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kreuzwerker/envplate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kreuzwerker\n    repo_name: envplate\n    description: Docker-friendly trivial templating for configuration files using environment keys\n    files:\n      - name: ep\n        src: envplate\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-RC1\")\n        asset: ep-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: envplate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kreuzwerker/m1-terraform-provider-helper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kreuzwerker\n    repo_name: m1-terraform-provider-helper\n    description: CLI to support with downloading and compiling terraform providers for Mac with M1 chip\n    supported_envs:\n      - darwin\n      - linux\n    asset: m1-terraform-provider-helper_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    replacements:\n      darwin: Darwin\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ktock/buildg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ktock\n    repo_name: buildg\n    description: Interactive debugger for Dockerfile, with support for IDEs (VS Code, Emacs, Neovim, etc.)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: buildg-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: buildg-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: buildg-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: buildg-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: buildg-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ktr0731/evans/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ktr0731\n    repo_name: evans\n    description: \"Evans: more expressive universal gRPC client\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: evans_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.6.9\")\n        asset: evans_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: evans_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n      - version_constraint: semver(\"<= 0.7.3\")\n        asset: evans_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: evans_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: evans_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: evans_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubecfg/kubecfg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubecfg\n    repo_name: kubecfg\n    description: A tool for managing complex enterprise Kubernetes environments as code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.34.3\")\n        asset: kubecfg_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: X64\n          darwin: macOS\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubecfg_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macOS\n          linux: Linux\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: X64\n          - goos: darwin\n            replacements:\n              arm64: ARM64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubecolor/kubecolor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubecolor\n    repo_name: kubecolor\n    description: Colorize your kubectl output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.21\")\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 0.5.1\")\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubecolor_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: kubecolor/kubecolor/.github/workflows/release.yml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubecost/kubectl-cost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubecost\n    repo_name: kubectl-cost\n    description: CLI for determining the cost of Kubernetes workloads\n    supported_envs:\n      - darwin\n      - amd64\n    complete_windows_ext: false\n    asset: kubectl-cost-{{.OS}}-{{.Arch}}.tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubemq-io/kubemqctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubemq-io\n    repo_name: kubemqctl\n    rosetta2: true\n    description: Kubemqctl is a command line interface (CLI) for KubeMQ, Kubernetes Message Broker\n    supported_envs:\n      - darwin\n      - amd64\n    asset: kubemqctl_{{.OS}}_{{.Arch}}\n    overrides:\n      - goos: windows\n        asset: kubemqctl.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubepug/kubepug/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubepug\n    repo_name: kubepug\n    aliases:\n      - name: rikatz/kubepug\n    description: Kubernetes PreUpGrade (Checker)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.1\"\n        no_asset: true\n      - version_constraint: Version == \"v1.2.2\"\n        asset: kubepug_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubepug_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: kubepug_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubepug_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: kubepug_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubepug_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubepug_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: kubepug_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kubepug/kubepug/releases/download/{{.Version}}/kubepug_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/kubepug/kubepug/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kubepug/kubepug/releases/download/{{.Version}}/kubepug_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubermatic/kubeone/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubermatic\n    repo_name: kubeone\n    asset: kubeone_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: Kubermatic KubeOne automate cluster operations on all your cloud, on-prem, edge, and IoT environments\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: kubeone_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.4.2\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/cloud-provider-gcp/gke-gcloud-auth-plugin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/cloud-provider-gcp/gke-gcloud-auth-plugin\n    type: go_build\n    repo_owner: kubernetes\n    repo_name: cloud-provider-gcp\n    description: cloud-provider-gcp contains several projects used to run Kubernetes in Google Cloud\n    files:\n      - name: gke-gcloud-auth-plugin\n        src: ./cmd/gke-gcloud-auth-plugin\n        dir: cloud-provider-gcp-{{trimV .Version}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kompose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes\n    repo_name: kompose\n    description: Go from Docker Compose to Kubernetes\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: raw\n    version_constraint: semver(\">= 1.26.0\")\n    asset: kompose-{{.OS}}-{{.Arch}}\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n    checksum:\n      type: github_release\n      asset: SHA256_SUM\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kops/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes\n    repo_name: kops\n    description: Kubernetes Operations (kops) - Production Grade K8s Installation, Upgrades, and Management\n    complete_windows_ext: false\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: kops-{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/apiextensions-apiserver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/apiextensions-apiserver\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: API server for API extensions like CustomResourceDefinitions\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.13\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/apiextensions-apiserver.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-aggregator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-aggregator\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: \"Aggregator for Kubernetes-style API servers: dynamic registration, discovery summarization, secure proxy\"\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.18.20\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-aggregator.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-apiserver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-apiserver\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The Kubernetes API server validates and configures data for the api objects which include pods, services, replicationcontrollers, and others\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-apiserver.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-controller-manager/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-controller-manager\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The Kubernetes controller manager is a daemon that embeds the core control loops shipped with Kubernetes\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-controller-manager.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-log-runner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-log-runner\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The kube-log-runner is a Go based binary that can run commands and redirect stdout/stderr etc\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.22.17\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.exe.sha256\n              algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-log-runner.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-proxy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-proxy\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The kube-proxy reflects services defined in the Kubernetes API on each node and can perform simple TCP, UDP, or SCTP stream forwarding, or round-robin TCP, UDP, or SCTP forwarding across multiple backends\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.exe.sha256\n              algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-proxy.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kube-scheduler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kube-scheduler\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The Kubernetes scheduler is a control plane process which assigns Pods to Nodes\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler.sha256\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kube-scheduler.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kubeadm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kubeadm\n    aliases:\n      - name: kubernetes/kubeadm\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: Kubeadm is a tool built to provide best-practice \"fast paths\" for creating Kubernetes clusters\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.4.12\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.exe.sha256\n              algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubeadm.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kubectl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kubectl\n    aliases:\n      - name: kubernetes/kubectl\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The kubectl command line tool lets you control Kubernetes clusters\n    link: https://kubernetes.io/docs/reference/kubectl/\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.20.15\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.sha256\n              algorithm: sha256\n      - version_constraint: semver(\"<= 1.22.17\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.sha256\n              algorithm: sha256\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.sha256\n              algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl\n        format: raw\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kubectl-convert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kubectl-convert\n    aliases:\n      - name: kubernetes/kubectl-convert\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: A plugin for Kubernetes command-line tool kubectl, which allows you to convert manifests between different API versions\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.20.15\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.22.17\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.exe.sha256\n              algorithm: sha256\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert\n        format: raw\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.exe.sha256\n              algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert\n        format: raw\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubectl-convert.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/kubernetes/kubelet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes/kubernetes/kubelet\n    type: http\n    repo_owner: kubernetes\n    repo_name: kubernetes\n    description: The kubelet is the primary \"node agent\" that runs on each node\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.7\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.15.3\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 1.25.4\")\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.exe.sha256\n              algorithm: sha256\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: \"true\"\n        url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: http\n          url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.sha256\n          algorithm: sha256\n        cosign:\n          opts:\n            - --signature\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.sig\n            - --certificate\n            - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.cert\n            - --certificate-identity\n            - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n            - --certificate-oidc-issuer\n            - \"https://accounts.google.com\"\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.exe.sha256\n              algorithm: sha256\n            cosign:\n              opts:\n                - --signature\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.exe.sig\n                - --certificate\n                - https://dl.k8s.io/{{.Version}}/bin/{{.OS}}/{{.Arch}}/kubelet.exe.cert\n                - --certificate-identity\n                - \"krel-staging@k8s-releng-prod.iam.gserviceaccount.com\"\n                - --certificate-oidc-issuer\n                - \"https://accounts.google.com\"\n        supported_envs:\n          - linux\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/minikube/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes\n    repo_name: minikube\n    description: Run Kubernetes locally\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.0\"\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - amd64\n      - version_constraint: Version == \"v0.12.1\"\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - amd64\n      - version_constraint: Version == \"v1.17.1\"\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - amd64\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - amd64\n        overrides:\n          - goos: linux\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n          file_format: raw\n        supported_envs:\n          - amd64\n        overrides:\n          - goos: linux\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - amd64\n        overrides:\n          - goos: windows\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 1.9.2\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - amd64\n      - version_constraint: semver(\"<= 1.17.0\")\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: minikube-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes/node-problem-detector/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes\n    repo_name: node-problem-detector\n    description: This is a place for various problem detectors running on the Kubernetes nodes\n    files:\n      - name: node-problem-detector\n        src: bin/{{.FileName}}\n      - name: health-checker\n        src: bin/{{.FileName}}\n      - name: log-counter\n        src: bin/{{.FileName}}\n    version_filter: not (Version matches \"-(alpha|beta|rc)$\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.11\"\n        no_asset: true\n      - version_constraint: Version == \"v0.8.8\"\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n      - version_constraint: Version == \"v0.8.12\"\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        supported_envs:\n          - linux\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n      - version_constraint: Version == \"v0.8.13\"\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n      - version_constraint: semver(\"<= 0.8.7\")\n        asset: node-problem-detector-{{.Version}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.8.10\")\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n      - version_constraint: semver(\"<= 0.8.15\")\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        supported_envs:\n          - linux\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n      - version_constraint: \"true\"\n        asset: node-problem-detector-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - windows\n        overrides:\n          - goos: windows\n            files:\n              - name: node-problem-detector.exe\n                src: bin/{{.FileName}}\n              - name: health-checker.exe\n                src: bin/{{.FileName}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-retired/kubefed/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-retired\n    repo_name: kubefed\n    aliases:\n      - name: kubernetes-sigs/kubefed\n    description: kubefedctl controls a Kubernetes Cluster Federation\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: kubefedctl-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tgz\n    files:\n      - name: kubefedctl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/aws-iam-authenticator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: aws-iam-authenticator\n    description: A tool to use AWS IAM credentials to authenticate to a Kubernetes cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.0\", \"v0.5.4\", \"v0.5.27\", \"v0.6.20\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.3.0\"\n        asset: heptio-authenticator-aws_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: authenticator_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.0-alpha.3\")\n        asset: aws-iam-authenticator_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: authenticator_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.3\")\n        asset: aws-iam-authenticator_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: authenticator_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: aws-iam-authenticator_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: authenticator_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/cloud-provider-kind/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: cloud-provider-kind\n    description: Cloud provider for KIND clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.2\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.1\"\n        asset: cloud-provider-kind-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: \"true\"\n        asset: cloud-provider-kind_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: cloud-provider-kind_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/cluster-api/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: cluster-api\n    description: Home for Cluster API, a subproject of sig-cluster-lifecycle\n    files:\n      - name: clusterctl\n        src: clusterctl-{{.OS}}-{{.Arch}}\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.0-alpha.2\")\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: clusterctl_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.23\")\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.25\")\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: clusterctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/controller-runtime/setup-envtest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes-sigs/controller-runtime/setup-envtest\n    type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: controller-runtime\n    description: Repo for the controller-runtime subproject of kubebuilder (sig-apimachinery)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.18.7\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: setup-envtest-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/controller-tools/controller-gen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    name: kubernetes-sigs/controller-tools/controller-gen\n    search_words:\n      - kubebuilder\n    path: sigs.k8s.io/controller-tools/cmd/controller-gen\n    repo_owner: kubernetes-sigs\n    repo_name: controller-tools\n    description: controller-gen - Generate Kubernetes API extension resources and code\n    version_filter: 'not (Version startsWith \"envtest-\")'\n    files:\n      - name: controller-gen\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/cri-tools/crictl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: kubernetes-sigs/cri-tools/crictl\n    repo_owner: kubernetes-sigs\n    repo_name: cri-tools\n    asset: crictl-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: CLI and validation tools for Kubelet Container Runtime Interface (CRI)\n    files:\n      - name: crictl\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/gwctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: gwctl\n    description: gwctl is a command-line tool for managing and understanding Gateway API resources in your Kubernetes cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gwctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gwctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/ingress2gateway/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: ingress2gateway\n    description: Convert Ingress resources to Gateway API resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ingress2gateway_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/kind/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: kind\n    description: \"Kubernetes IN Docker - local clusters for testing Kubernetes\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.1\"\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.1.0\"\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.5.0\"\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: kind-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: kind-{{.OS}}-{{.Arch}}.sha256sum\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/krew/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: krew\n    asset: krew-{{.OS}}_{{.Arch}}.tar.gz\n    description: Find and install kubectl plugins\n    files:\n      - name: krew\n        src: krew-{{.OS}}_{{.Arch}}\n    version_constraint: semver(\">= 0.4.2\")\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: krew.tar.gz\n        files:\n          - name: krew\n            src: krew-{{.OS}}_{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/kubebuilder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: kubebuilder\n    description: \"Kubebuilder - SDK for building Kubernetes APIs using CRDs\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.9-alpha.30\"\n        no_asset: true\n      - version_constraint: Version == \"release-0.1.6\"\n        asset: kubebuilder_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kubebuilder\n            src: \"{{.AssetWithoutExt}}/bin/kubebuilder\"\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1beta1.2\"\n        asset: kubebuilder-release-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kubebuilder\n            src: \"kubebuilder/bin/kubebuilder\"\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: kubebuilder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kubebuilder\n            src: \"{{.AssetWithoutExt}}/bin/kubebuilder\"\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-beta1.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: kubebuilder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kubebuilder\n            src: \"{{.AssetWithoutExt}}/bin/kubebuilder\"\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.3.2\")\n        asset: kubebuilder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: kubebuilder\n            src: \"{{.AssetWithoutExt}}/bin/kubebuilder\"\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 3.3.0\")\n        asset: kubebuilder_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubebuilder_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/kubectl-validate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: kubectl-validate\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: kubectl-validate_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubectl-validate_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n          - windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/kustomize/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: kustomize\n    description: Customization of kubernetes YAML configurations\n    asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    version_prefix: kustomize/\n    version_constraint: semver(\">= 5.2.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 5.2.0\")\n        asset: kustomize_v5.2.0_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: kustomize\n            src: output/kustomize\n      - version_constraint: semver(\">= 5.1.0\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum: &kustomize_checksum\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\">= 4.5.4\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 4.4.1\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 4.2.0\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - linux\n          - darwin\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 3.8.6\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 3.7.0\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 3.5.5\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 3.3.0\")\n        asset: kustomize_{{.SemVer}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 3.2.1\")\n        asset: kustomize_kustomize.{{.SemVer}}_{{.OS}}_{{.Arch}}\n        format: raw\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 2.1.0\")\n        asset: kustomize_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n        version_prefix: \"\"\n        rosetta2: true\n        checksum: *kustomize_checksum\n      - version_constraint: semver(\">= 1.0.1\")\n        asset: kustomize_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        overrides: []\n        supported_envs:\n          - darwin\n          - amd64\n        version_prefix: \"\"\n        rosetta2: true\n        checksum: *kustomize_checksum\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/kwok/kwokctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubernetes-sigs/kwok/kwokctl\n    type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: kwok\n    description: \"Kubernetes WithOut Kubelet -  Simulates thousands of Nodes and Clusters\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kwok-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubernetes-sigs/zeitgeist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubernetes-sigs\n    repo_name: zeitgeist\n    description: \"Zeitgeist: the language-agnostic dependency checker\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.2\"\n        asset: zeitgeist_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.17\")\n        asset: zeitgeist_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.2\")\n        no_asset: true\n      - version_constraint: Version == \"v0.3.4\"\n        asset: zeitgeist\n        format: raw\n        supported_envs:\n          - windows/amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/kubernetes-sigs/zeitgeist/\\\\.github/workflows/release\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.pem\n      - version_constraint: Version == \"v0.3.5\"\n        asset: zeitgeist_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/kubernetes-sigs/zeitgeist/\\\\.github/workflows/release\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.pem\n      - version_constraint: Version == \"v0.4.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.4.1\"\n        asset: zeitgeist_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/kubernetes-sigs/zeitgeist/\\\\.github/workflows/release\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.pem\n      - version_constraint: \"true\"\n        asset: zeitgeist-{{.Arch}}-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/kubernetes-sigs/zeitgeist/\\\\.github/workflows/release\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/kubernetes-sigs/zeitgeist/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubescape/kubescape/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubescape\n    repo_name: kubescape\n    description: Kubescape is an open-source Kubernetes security platform for your IDE, CI/CD pipelines, and clusters. It includes risk analysis, security, compliance, and misconfiguration scanning, saving Kubernetes users and administrators precious time, effort, and resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.38\")\n        asset: kubescape\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.0.97\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v1.0.98\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.107\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v1.0.108\"\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.0.147\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2.0.168\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        checksum:\n          type: github_release\n          asset: kubescape-{{.OS}}-latest-sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v2.0.169\"\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        checksum:\n          type: github_release\n          asset: kubescape-{{.OS}}-latest-sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.0.183\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}-sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2.1.1\")\n        asset: kubescape-{{.OS}}-latest.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2.2.6\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.0.3\")\n        asset: kubescape-{{.OS}}-latest\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: kubescape-{{.Arch}}-{{.OS}}-latest\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 3.0.46\")\n        asset: kubescape-{{.OS}}-latest.{{.Format}}\n        format: tar.gz\n        complete_windows_ext: false\n        files:\n          - name: kubescape\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        overrides:\n          - goarch: arm64\n            asset: kubescape-{{.Arch}}-{{.OS}}-latest.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: kubescape_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubeshark/kubeshark/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubeshark\n    repo_name: kubeshark\n    aliases:\n      # Repository was transferred at 37.0\n      - name: up9inc/mizu\n    description: The API traffic analyzer for Kubernetes providing real-time K8s protocol-level visibility, capturing and monitoring all traffic and payloads going in, out and across containers, pods, nodes and clusters. Inspired by Wireshark, purposely built for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: mizu_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        files:\n          - name: mizu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.23.0\")\n        asset: mizu_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: mizu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: mizu.exe\n            checksum:\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 36.0\")\n        asset: mizu_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: mizu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: mizu.exe\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 37.0\")\n        asset: kubeshark_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubeshark.exe\n            checksum:\n              enabled: false\n      - version_constraint: semver(\"<= 50.4\")\n        asset: kubeshark_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubeshark_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 52.1.50\")\n        asset: kubeshark_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubeshark_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubeshark_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: kubeshark\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubesphere/kubeeye/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubesphere\n    repo_name: kubeeye\n    asset: kubeeye-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: KubeEye aims to find various problems on Kubernetes, such as application misconfiguration, unhealthy cluster components and node problems\n    supported_envs:\n      - linux\n    files:\n      - name: kubeeye\n        src: ke\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\"< 1.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.0\")\n        error_message: |\n          kubeeye isn't released pre-built binaries anymore.\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubevela/kubevela/kubectl-plugin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubevela/kubevela/kubectl-plugin\n    type: github_release\n    repo_owner: kubevela\n    repo_name: kubevela\n    aliases:\n      - name: oam-dev/kubevela/kubectl-plugin\n    description: The Modern Application Deployment System Based on OAM\n    complete_windows_ext: false\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: kubectl-vela-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: kubectl-vela\n        src: \"{{.OS}}-{{.Arch}}/kubectl-vela\"\n    version_constraint: semver(\">= 1.10.3\")\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n      cosign:\n        opts:\n          - --certificate-identity\n          - https://github.com/kubevela/kubevela/.github/workflows/release.yml@refs/tags/{{.Version}}\n          - --certificate-oidc-issuer\n          - https://token.actions.githubusercontent.com\n          - --signature\n          - https://github.com/kubevela/kubevela/releases/download/{{.Version}}/sha256sums.txt-keyless.sig\n          - --certificate\n          - https://github.com/kubevela/kubevela/releases/download/{{.Version}}/sha256sums.txt-keyless.pem\n    slsa_provenance:\n      type: github_release\n      asset: multiple.intoto.jsonl\n    version_overrides:\n      - version_constraint: semver(\">= 1.10.2\")\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        slsa_provenance:\n          enabled: false\n      - version_constraint: semver(\">= 1.2.0\")\n        checksum:\n          # https://github.com/kubevela/kubevela/issues/4822\n          enabled: false\n        slsa_provenance:\n          enabled: false\n      - version_constraint: \"true\"\n        checksum:\n          # https://github.com/kubevela/kubevela/issues/4822\n          enabled: false\n        slsa_provenance:\n          enabled: false\n        rosetta2: true\n        complete_windows_ext: true\n        asset: kubectl-vela-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubevela/kubevela/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubevela\n    repo_name: kubevela\n    aliases:\n      - name: oam-dev/kubevela\n    description: The Modern Application Platform\n    files:\n      - name: vela\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.7.0\", \"v1.7.1\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.3.4\"\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"v1.3.3\"]\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.0.1.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        # checksum files are broken\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        # checksum files are broken\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n      - version_constraint: semver(\"<= 1.1.13\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        # checksum files are broken\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.7\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        # checksum files are broken\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n      - version_constraint: semver(\"<= 1.10.2\")\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: vela-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vela\n            src: \"{{.OS}}-{{.Arch}}/vela\"\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kubevela/kubevela/releases/download/{{.Version}}/sha256sums.txt-keyless.pem\n              - --certificate-identity\n              - https://github.com/kubevela/kubevela/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kubevela/kubevela/releases/download/{{.Version}}/sha256sums.txt-keyless.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubevious/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubevious\n    repo_name: cli\n    description: \"Kubevious CLI - Prevent Kubernetes disasters at the early stages\"\n    files:\n      - name: kubevious\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubevious-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubevirt/kubevirt/virtctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: kubevirt/kubevirt/virtctl\n    type: github_release\n    repo_owner: kubevirt\n    repo_name: kubevirt\n    description: Kubernetes Virtualization API and runtime in order to define and manage virtual machines\n    asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}} # Workaround of a bug. https://github.com/aquaproj/aqua-registry/pull/18326#issuecomment-1862164476\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1-alpha.6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.3.0-alpha.0\"\n        asset: virtctl-v0.3.0-{{.OS}}-{{.Arch}}.0-179-ge1a1ac09-linux-amd64\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.4\")\n        asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.7.0-alpha.0\"\n        asset: virtctl-v0.6.1-alpha.0-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: virtctl-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubewarden/kwctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubewarden\n    repo_name: kwctl\n    description: Go-to CLI tool for Kubewarden users\n    files:\n      - name: kwctl\n        src: kwctl-{{.OS}}-{{.Arch}}\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.4.1\"\n        asset: kwctl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            asset: kwctl-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n      - version_constraint: Version == \"v1.7.0-rc2\"\n        asset: default.kwctl-{{.OS}}-{{.Arch}}.kwctl-darwin-x86_64.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: default.kwctl-{{.OS}}-{{.Arch}}.kwctl-linux-x86_64.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            asset: default.kwctl-{{.OS}}-{{.Arch}}.kwctl-linux-aarch64.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: default.kwctl-{{.OS}}-{{.Arch}}.kwctl-darwin-aarch64.{{.Format}}\n          - goos: windows\n            asset: default.kwctl-{{.OS}}-{{.Arch}}.kwctl-windows-x86_64.exe.{{.Format}}\n            replacements: {}\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: kwctl.{{.Format}}\n        format: zip\n        files:\n          - name: kwctl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: kwctl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: kwctl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.5-rc2\")\n        asset: kwctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: kwctl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: kwctl-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: kwctl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            asset: kwctl-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kubie-org/kubie/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kubie-org\n    repo_name: kubie\n    aliases:\n      - name: sbstp/kubie\n    description: A more powerful alternative to kubectx and kubens\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.7.2\"\n        no_asset: true\n      - version_constraint: Version == \"v0.12.1\"\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.13.0\"\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.20.0\"\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: kubie-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kudobuilder/kuttl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kudobuilder\n    repo_name: kuttl\n    description: KUbernetes Test TooL (kuttl)\n    supported_envs:\n      - darwin\n      - linux\n    asset: kuttl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: kubectl-kuttl\n    replacements:\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kunobi-ninja/kunobi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: kunobi-ninja\n    repo_name: kunobi\n    aliases:\n      - name: kunobi-ninja/kunobi-releases\n    description: Kubernetes IDE for managing clusters, resources, and workloads\n    link: https://kunobi.ninja\n    version_source: github_tag\n    url: https://r2.kunobi.ninja/v{{.Version}}/Kunobi_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n    files:\n      - name: kunobi\n        src: kunobi/AppRun\n    overrides:\n      - goos: darwin\n        url: https://r2.kunobi.ninja/v{{.Version}}/Kunobi_{{.Version}}_darwin_aarch64.app.tar.gz\n        files:\n          - name: kunobi\n            src: Kunobi.app/Contents/MacOS/kunobi\n    supported_envs:\n      - darwin/arm64\n      - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kurehajime/dajarep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kurehajime\n    repo_name: dajarep\n    description: ダジャレを検索するコマンド\n    version_constraint: semver(\">= 1.9.8\")\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    asset: dajarep_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        asset: dajarep_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: dajarep_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kurehajime/kuzusi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kurehajime\n    repo_name: kuzusi\n    description: breakout for terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kurehajime/pong-command/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kurehajime\n    repo_name: pong-command\n    description: pong is not ping. pong is CLI game\n    files:\n      - name: pong\n    version_constraint: semver(\">= 2.0.8\")\n    asset: pong-command_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    replacements:\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\">= 2.0.5\")\n        supported_envs: []\n      - version_constraint: \"true\"\n        rosetta2: true\n        asset: \"{{.OS}}_{{.Arch}}.zip\"\n        supported_envs:\n          - darwin\n          - amd64\n        replacements:\n          darwin: macos\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kvaps/kubectl-node-shell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: kvaps\n    repo_name: kubectl-node-shell\n    path: kubectl-node_shell\n    description: Exec into node via kubectl\n    files:\n      - name: kubectl-node_shell\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kvz/json2hcl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kvz\n    repo_name: json2hcl\n    asset: json2hcl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Convert JSON to HCL, and vice versa. We don't use json2hcl anymore ourselves, so we can't invest time into it. However, we're still welcoming PRs\n    version_constraint: semver(\">= 0.1.1\")\n    checksum:\n      type: github_release\n      asset: json2hcl_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\"= 0.0.7\")\n        supported_envs: []\n      - version_constraint: semver(\"= 0.0.6\")\n        checksum:\n          enabled: false\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        asset: json2hcl_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n      - version_constraint: \"true\"\n        checksum:\n          enabled: false\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        asset: json2hcl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: json2hcl\n        files:\n          - name: json2hcl\n            src: json2hcl_{{.OS}}_{{.Arch}}/json2hcl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyma-project/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyma-project\n    repo_name: cli\n    description: Simple set of commands to manage a Kyma installation\n    asset: kyma_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: kyma\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.7.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.2.0\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 1.2.0-rc1\")\n        asset: kyma_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\">= 0.2.0\")\n        asset: kyma-{{.OS}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: kyma\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: Version == \"v0.1.0\"\n        asset: kymactl-{{.OS}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: kymactl.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyoh86/richgo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyoh86\n    repo_name: richgo\n    description: Enrich `go test` outputs with text decorations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: richgo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: richgo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.8\")\n        asset: richgo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: richgo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.10\")\n        asset: richgo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: richgo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: richgo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: richgo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyoshidajp/dep-doctor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyoshidajp\n    repo_name: dep-doctor\n    description: Diagnose whether your software dependency libraries are maintained\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dep-doctor_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: dep-doctor_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyoshidajp/ghkw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyoshidajp\n    repo_name: ghkw\n    asset: ghkw_{{.OS}}_{{.Arch}}.tar.gz\n    description: Search how many keywords in GitHub Code tool\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: ghkw_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyverno/chainsaw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyverno\n    repo_name: chainsaw\n    description: Declarative K8s e2e testing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0-alpha.1\"\n        asset: chainsaw_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.sig\n      - version_constraint: Version == \"v0.1.3-alpha.1\"\n        asset: chainsaw_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.sig\n      - version_constraint: semver(\"<= 0.2.13\")\n        asset: chainsaw_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --certificate-identity\n              - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.pem\n              - --signature\n              - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/checksums.txt.sig\n        cosign:\n          opts:\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --certificate-identity\n            - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n            - --certificate\n            - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --signature\n            - https://github.com/kyverno/chainsaw/releases/download/{{.Version}}/{{.Asset}}.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: chainsaw_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        cosign:\n          bundle:\n            type: github_release\n            asset: \"{{.Asset}}.sigstore.json\"\n          opts:\n            - --certificate-identity\n            - \"https://github.com/kyverno/chainsaw/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/kyverno/kyverno/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: kyverno\n    repo_name: kyverno\n    description: Cloud Native Policy Management\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.5.5\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.8\")\n        asset: kyverno-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.10.0\")\n        asset: kyverno-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.10.7\")\n        asset: kyverno-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kyverno/kyverno/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/kyverno/kyverno/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kyverno/kyverno/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kyverno-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/kyverno/kyverno/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/kyverno/kyverno/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/kyverno/kyverno/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/laktak/zfind/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: laktak\n    repo_name: zfind\n    description: search for files (even inside tar/zip/7z/rar) using a SQL-WHERE filter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: zfind-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lasantosr/intelli-shell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lasantosr\n    repo_name: intelli-shell\n    description: Like IntelliSense, but for shells\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: intelli-shell-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: intelli-shell-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lasiar/canonicalheader/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lasiar\n    repo_name: canonicalheader\n    description: Golang linter checking the canonicality of the http header\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: canonicalheader_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: canonicalheader_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lc/gau/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lc\n    repo_name: gau\n    description: Fetch known URLs from AlienVault's Open Threat Exchange, the Wayback Machine, and Common Crawl\n    asset: gau_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: gau_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.2.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.1\")\n        replacements:\n          darwin: macOS\n      - version_constraint: Version == \"v1.0\"\n        asset: gau-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar\n        files:\n          - name: gau\n            src: gau-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            asset: gau-windows-amd64.exe.tar\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ldez/prm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ldez\n    repo_name: prm\n    asset: prm_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Pull Request Manager for Maintainers\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: prm_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/leg100/pug/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: leg100\n    repo_name: pug\n    description: Drive terraform at terminal velocity\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pug_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: pug_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/legal90/awscurl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: legal90\n    repo_name: awscurl\n    description: cURL with AWS request signing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: awscurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.2\"\n        asset: awscurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.1.3\"\n        asset: awscurl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: awscurl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/leoafarias/fvm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: leoafarias\n    repo_name: fvm\n    description: \"Flutter Version Management: A simple CLI to manage Flutter SDK versions\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.13\")\n        asset: fvm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.8\")\n        asset: fvm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: fvm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.8.3\")\n        no_asset: true\n      - version_constraint: Version == \"App-1.0.0-alpha\"\n        asset: fvm-app-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"App-1.0.0-alpha.1\"\n        asset: fvm_{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.2.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.3.4\")\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.bat\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.3.8\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.2.4\")\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.bat\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"2.2.5-dev\"\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"2.2.5-dev.1\"\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.3.1\")\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.bat\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.4.1\")\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.bat\n      - version_constraint: semver(\"<= 3.0.0-alpha.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.bat\n      - version_constraint: \"true\"\n        asset: fvm-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fvm\n            src: fvm/fvm\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fvm\n                src: fvm/fvm.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lewispeckover/consulator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lewispeckover\n    repo_name: consulator\n    description: Import and synchronize your Consul KV data from JSON and YAML\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: consulator_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/comet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: comet\n    description: Command line tool to help you use conventional commit messages (https://www.conventionalcommits.org)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: comet-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: comet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/dismember/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: dismember\n    description: Scan memory for secrets and more. Maybe eventually a full /proc toolkit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dismember-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: dismember_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/extrude/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: extrude\n    description: \":detective: Analyse binaries for missing security features, information disclosure and more\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: extrude-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: extrude_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/gitjacker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: gitjacker\n    description: \":octocat: Leak git repositories from misconfigured websites\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gitjacker-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/memit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: memit\n    description: \":no_entry_sign::floppy_disk: Run binaries straight from memory in Linux\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: memit-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: memit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/pax/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: pax\n    description: \":skull: :unlock: CLI tool for PKCS7 padding oracle attacks\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2\"\n        asset: pax-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: pax-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/scout/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: scout\n    description: \"Lightweight URL fuzzer and spider: Discover a web server's undisclosed files, directories and VHOSTs\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: scout-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liamg/traitor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liamg\n    repo_name: traitor\n    asset: traitor-{{.Arch}}\n    format: raw\n    description: Automatic Linux privesc via exploitation of low-hanging fruit e.g. gtfobins, pwnkit, dirty pipe, +w docker.sock\n    supported_envs:\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/libbpf/bpftool/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: libbpf\n    repo_name: bpftool\n    description: Automated upstream mirror for bpftool stand-alone build\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 7.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: bpftool-{{ .Version}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: bpftool-{{ .Version}}-{{.Arch}}.{{.Format}}.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/librespeed/speedtest-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: librespeed\n    repo_name: speedtest-cli\n    asset: librespeed-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: librespeed-cli\n        src: librespeed-cli\n    description: Command line client for LibreSpeed\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liggitt/audit2rbac/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liggitt\n    repo_name: audit2rbac\n    description: Autogenerate RBAC policies based on Kubernetes audit logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: audit2rbac-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: audit2rbac-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lima-vm/lima/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lima-vm\n    repo_name: lima\n    description: Linux virtual machines, with a focus on running containers\n    files:\n      - name: lima\n        src: bin/lima\n      - name: limactl\n        src: bin/limactl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.1\"\n        error_message: |\n          aqua doesn't support this version.\n          Please update this package.\n          https://github.com/aquaproj/aqua-registry/issues/36874\n          https://github.com/lima-vm/lima/pull/3621\n      - version_constraint: Version == \"v0.7.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.0\"\n        asset: lima-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"< 0.23.0\")\n        asset: lima-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: lima-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: lima-vm/lima/.github/workflows/release.yml\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lima-vm/sshocker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lima-vm\n    repo_name: sshocker\n    description: ssh + reverse sshfs + port forwarder, in Docker-like CLI (predecessor of Lima)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: sshocker-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: sshocker-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lindell/multi-gitter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lindell\n    repo_name: multi-gitter\n    asset: multi-gitter_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: CLI to update multiple repositories in bulk\n    replacements:\n      amd64: x86_64\n      arm64: ARM64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/linebender/resvg/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: linebender\n    repo_name: resvg\n    description: An SVG rendering library\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.15.0\")\n        error_message: This version is not supported. Please use a newer version.\n      - version_constraint: Version == \"0.45.0\"\n        asset: resvg-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.41.0\")\n        asset: resvg-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            asset: resvg-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.44.0\")\n        asset: resvg-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          windows: win64\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: resvg-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: resvg-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: resvg-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: darwin\n            asset: resvg-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/linkerd/linkerd2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: linkerd\n    repo_name: linkerd2\n    description: Ultralight, security-first service mesh for Kubernetes. Main repo for Linkerd 2.x\n    files:\n      - name: linkerd\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"stable-2.9.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.8.1\")\n        version_prefix: stable-\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.10.0\")\n        version_prefix: stable-\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n      - version_constraint: Version startsWith \"stable-\"\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n          - goos: windows\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n      - version_constraint: semver(\"<= 20.7.5\")\n        version_prefix: edge-\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 21.3.2\")\n        version_prefix: edge-\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 25.9.3\")\n        version_prefix: edge-\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n          - goos: windows\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n      - version_constraint: Version startsWith \"edge-\"\n        asset: linkerd2-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n          - goos: windows\n            asset: linkerd2-cli-{{.Version}}-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lintnet/lintnet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lintnet\n    repo_name: lintnet\n    aliases:\n      - name: suzuki-shunsuke/lintnet\n    description: General Linter powered by Jsonnet\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: lintnet_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: lintnet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/lintnet/lintnet/releases/download/{{.Version}}/lintnet_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/lintnet/lintnet/releases/download/{{.Version}}/lintnet_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/linuxkit/linuxkit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: linuxkit\n    repo_name: linuxkit\n    description: A toolkit for building secure, portable and lean operating systems for containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8\"\n        asset: linuxkit-linux-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: linuxkit-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: linuxkit-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liquidmetal-dev/flintlock/flintlock-metrics/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: liquidmetal-dev/flintlock/flintlock-metrics\n    type: github_release\n    repo_owner: liquidmetal-dev\n    repo_name: flintlock\n    description: Lock, Stock, and Two Smoking MicroVMs. Create and manage the lifecycle of MicroVMs backed by containerd\n    version_filter: not (Version matches \"-alpha\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: flintlock-metrics_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liquidmetal-dev/flintlock/flintlockd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: liquidmetal-dev/flintlock/flintlockd\n    type: github_release\n    repo_owner: liquidmetal-dev\n    repo_name: flintlock\n    description: Lock, Stock, and Two Smoking MicroVMs. Create and manage the lifecycle of MicroVMs backed by containerd\n    version_filter: not (Version matches \"-alpha\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: flintlockd_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/livebud/bud/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: livebud\n    repo_name: bud\n    description: The Full-Stack Web Framework for Go\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: bud_{{.Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: bud\n        src: bud_{{.Version}}_{{.OS}}_{{.Arch}}/bud\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/livesense-inc/go-aws-s3get/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: livesense-inc\n    repo_name: go-aws-s3get\n    asset: s3get-{{.OS}}-{{.Arch}}\n    format: raw\n    description: A stupid simple S3 downloader CLI tool with supporting AWS Access Key\n    replacements:\n      amd64: x86_64\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: s3get\n    checksum:\n      type: github_release\n      asset: s3get_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/livesense-inc/go-simple-http-redirector/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: livesense-inc\n    repo_name: go-simple-http-redirector\n    description: Redirect HTTP requests to specific URI\n    files:\n      - name: redirector\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: redirector-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: redirector_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: redirector\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/liweiyi88/gosnakego/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: liweiyi88\n    repo_name: gosnakego\n    description: A snake game written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        asset: gosnakego_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= v0.2.0\")\n        asset: gosnakego_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"<= v0.3.1\")\n        asset: gosnakego_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows/amd64\n        rosetta2: true\n      - version_constraint: Version == \"v0.3.2\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gosnakego_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gosnakego_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/llogick/zigscient/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: llogick\n    repo_name: zigscient\n    description: A Zig Language Server\n    files:\n      - name: zls\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: zigscient-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: zls\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/localstack/localstack-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: localstack\n    repo_name: localstack-cli\n    description: The LocalStack CLI packaged using pyinstaller\n    files:\n      - name: localstack\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.3.2.post0\"\n        asset: localstack-cli-2.3.2-{{.OS}}-{{.Arch}}-onefile.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: localstack\n        checksum:\n          type: github_release\n          asset: localstack-cli-2.3.2-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v3.0.2.post0\"\n        asset: localstack-cli-3.0.2-{{.OS}}-{{.Arch}}-onefile.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: localstack\n        checksum:\n          type: github_release\n          asset: localstack-cli-3.0.2-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: localstack-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}-onefile.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: localstack\n        checksum:\n          type: github_release\n          asset: localstack-cli-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/loeffel-io/ls-lint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: loeffel-io\n    repo_name: ls-lint\n    description: An extremely fast directory and filename linter - Bring some structure to your project filesystem\n    asset: ls-lint-{{.OS}}-{{.Arch}}\n    # error: opening tar archive for reading: wrapping file reader: gzip: invalid header\n    format: raw\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.0.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.10.0-beta.1\")\n        asset: ls-lint-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: ls-lint-{{.OS}}-{{.Arch}}\n          - goos: darwin\n            goarch: arm64\n            asset: ls-lint-{{.OS}}-{{.Arch}}\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.1.0\")\n        asset: ls-lint-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 1.1.0\")\n        asset: ls-lint-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/loft-sh/devpod/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: loft-sh\n    repo_name: devpod\n    description: \"Codespaces but open-source, client-only and unopinionated: Works with any IDE and lets you use any cloud, kubernetes or just localhost docker\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: devpod-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: devpod-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - linux\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/loft-sh/vcluster/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: loft-sh\n    repo_name: vcluster\n    description: \"vCluster - Create fully functional virtual Kubernetes clusters - Each vcluster runs inside a namespace of the underlying k8s cluster. It's cheaper than creating separate full-blown clusters and it offers better multi-tenancy and isolation than regular namespaces\"\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.15.2\")\n        asset: vcluster-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: vcluster-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/loft-sh/vcluster/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/loft-sh/vcluster/.github/workflows/release.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/loft-sh/vcluster/releases/download/{{.Version}}/checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/logdyhq/logdy-core/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: logdyhq\n    repo_name: logdy-core\n    description: Web based real-time log viewer. Stream ANY content to a web UI with autogenerated filters. Parse any format with TypeScript\n    files:\n      - name: logdy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: logdy-core_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: logdy_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/loov/goda/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: loov\n    repo_name: goda\n    description: Go Dependency Analysis toolkit\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lotabout/rargs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lotabout\n    repo_name: rargs\n    description: \"xargs + awk with pattern matching support. `ls *.bak | rargs -p '(.*)\\\\.bak' mv {0} {1}`\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: rargs-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: rargs-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lsd-rs/lsd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lsd-rs\n    repo_name: lsd\n    description: The next gen ls command\n    files:\n      - name: lsd\n        src: lsd-{{.Version}}-{{.Arch}}-{{.OS}}/lsd\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: lsd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.16.0\"\n        asset: lsd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: lsd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.20.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.23.1\")\n        asset: lsd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: lsd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/luau-lang/luau/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: luau-lang\n    repo_name: luau\n    description: A fast, small, safe, gradually typed embeddable scripting language derived from Lua\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.622\")\n        asset: luau-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - darwin\n          - linux\n          - windows/amd64\n        files:\n          - name: luau\n          - name: luau-analyze\n          - name: luau-compile\n      - version_constraint: semver(\"<= 0.644\")\n        asset: luau-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - darwin/arm64\n          - linux\n          - windows\n        files:\n          - name: luau\n          - name: luau-analyze\n          - name: luau-compile\n      - version_constraint: \"true\"\n        asset: luau-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n          linux: ubuntu\n        supported_envs:\n          - darwin/arm64\n          - linux\n          - windows\n        files:\n          - name: luau\n          - name: luau-analyze\n          - name: luau-ast\n          - name: luau-compile\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lusingander/ddv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lusingander\n    repo_name: ddv\n    description: Terminal DynamoDB Viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ddv-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lusingander/serie/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lusingander\n    repo_name: serie\n    description: A rich git commit graph in your terminal, like magic\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: serie-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: serie-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lusingander/stu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lusingander\n    repo_name: stu\n    description: TUI explorer application for Amazon S3 (AWS S3)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: stu-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.6.5\")\n        asset: stu-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: stu-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lxc/incus/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lxc\n    repo_name: incus\n    description: Powerful system container and virtual machine manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: \"{{.OS}}.incus\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bin.{{.OS}}.incus.{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/lycheeverse/lychee/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: lycheeverse\n    repo_name: lychee\n    description: Fast, async, stream-based link checker written in Rust. Finds broken URLs and mail addresses inside Markdown, HTML, reStructuredText, websites and more\n    version_filter: not (Version startsWith \"lychee-lib-\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\") || Version == \"v0.6.0-alpha\"\n        no_asset: true\n      - version_constraint: Version == \"v0.8.0\"\n        asset: lychee-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        overrides:\n          - goos: darwin\n            asset: lychee-{{.Version}}-macos-x86_64.dmg\n            format: dmg\n          - goos: windows\n            format: raw\n            asset: lychee-{{.Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.1-alpha\")\n        asset: lychee-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            asset: lychee-{{.Version}}-macos-x86_64.dmg\n            format: dmg\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: lychee-{{.Version}}-{{.OS}}-{{.Arch}}\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: lychee-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            asset: lychee-{{.Version}}-macos-x86_64.dmg\n            format: dmg\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: lychee-{{.Version}}-{{.OS}}-{{.Arch}}\n      - version_constraint: \"true\"\n        version_prefix: lychee-\n        asset: lychee-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            format: dmg\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: raw\n            asset: lychee-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - linux\n          - windows/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/m7medVision/lazycommit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: m7medVision\n    repo_name: lazycommit\n    description: using AI to generate commit message suggestions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1\"\n        asset: lazycommit_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.3.24\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: lazycommit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/maaslalani/invoice/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: maaslalani\n    repo_name: invoice\n    description: Command line invoice generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: invoice_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: invoice_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/maaslalani/slides/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: maaslalani\n    repo_name: slides\n    description: Terminal based presentation tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: slides_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: slides_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mackee/go-readability/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mackee\n    repo_name: go-readability\n    description: \"Extract readable content from web pages - Mozilla’s and Mizchi Readability ported to Go\"\n    files:\n      - name: readability\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: go-readability_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: readability\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/madelynnblue/sqlfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: madelynnblue\n    repo_name: sqlfmt\n    aliases:\n      - name: mjibson/sqlfmt\n      - name: maddyblue/sqlfmt\n    description: SQL formatter with width-aware output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: sqlfmt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sqlfmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: sqlfmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/magefile/mage/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: magefile\n    repo_name: mage\n    description: a Make/rake-like dev tool using Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.11.0\")\n        asset: mage_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: mage_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.14.0\")\n        asset: mage_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: mage_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: mage_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: mage_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/magodo/hclgrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: magodo\n    repo_name: hclgrep\n    description: Syntax based grep for HCL(v2)\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/magodo/pipeform/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: magodo\n    repo_name: pipeform\n    description: Terraform runtime TUI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version matches \"\\\\b[0-9a-f]{40}\\\\b\"\n        # To keep the compatibility\n        type: go_install\n      - version_constraint: Version == \"v0.1.0\"\n        asset: pipeform_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: pipeform\n            src: pipeform_{{.Version}}\n        checksum:\n          type: github_release\n          asset: pipeform_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: pipeform_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: pipeform_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/magodo/tfadd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: magodo\n    repo_name: tfadd\n    description: Generate valid Terraform configuration from state\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mailru/easyjson/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: mailru\n    repo_name: easyjson\n    description: Fast JSON serializer for golang\n    path: github.com/mailru/easyjson/easyjson\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/majorcontext/moat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: majorcontext\n    repo_name: moat\n    description: Run agents in containers with credential injection and full observability\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: moat_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/makew0rld/didder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: makew0rld\n    repo_name: didder\n    description: An extensive, fast, and accurate command-line image dithering tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: didder_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: didder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: didder_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: 64-bit\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: didder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/making/rsc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: making\n    repo_name: rsc\n    description: RSocket Client CLI (RSC) that aims to be a curl for RSocket\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: rsc-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: rsc-{{.Arch}}-pc-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: darwin\n            asset: rsc-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/makiuchi-d/arelo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: makiuchi-d\n    repo_name: arelo\n    description: a simple auto reload (live reload) utility\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.10.1\")\n        asset: arelo_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: arelo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.12.3\")\n        asset: arelo_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: arelo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: arelo_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: arelo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mame/wsl2-ssh-agent/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mame\n    repo_name: wsl2-ssh-agent\n    description: A bridge from WSL2 ssh client to Windows ssh-agent.exe service\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wsl2-ssh-agent\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: wsl2-ssh-agent-arm64\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/manabusakai/tdtidy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: manabusakai\n    repo_name: tdtidy\n    description: A command line tool for managing ECS task definitions. `tdtidy` can deregister and delete old task definitions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tdtidy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mantil-io/mantil/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mantil-io\n    repo_name: mantil\n    description: Build your AWS Lambda-based Go backends quicker than ever\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: mantil_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: mantil_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: mantil_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.22\")\n        asset: mantil_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.28\")\n        asset: mantil_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: mantil_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/marcosnils/bin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: marcosnils\n    repo_name: bin\n    description: Effortless binary manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.17.1\"\n        asset: bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: bin_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/marp-team/marp-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: marp-team\n    repo_name: marp-cli\n    asset: marp-cli-{{.Version}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A CLI interface for Marp and Marpit based converters\n    files:\n      - name: marp\n    replacements:\n      darwin: mac\n      windows: win\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/marwan-at-work/mod/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: marwan-at-work\n    repo_name: mod\n    description: Automated Semantic Import Versioning Upgrades\n    path: github.com/marwan-at-work/mod/cmd/mod\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mas-cli/mas/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mas-cli\n    repo_name: mas\n    description: Mac App Store command line interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: mas-cli.{{.Format}}\n        format: zip\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.8.6\")\n        asset: mas.{{.Format}}\n        format: pkg\n        files:\n          - name: mas\n            src: mas_components.pkg/Payload/usr/local/bin/mas\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"< 3.0.0\")\n        asset: mas-{{trimV .Version}}.{{.Format}}\n        format: pkg\n        files:\n          - name: mas\n            src: mas_components.pkg/Payload/mas\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 3.1.0\")\n        asset: mas-{{trimV .Version}}-{{.Arch}}.{{.Format}}\n        format: pkg\n        replacements:\n          amd64: x86_64\n        files:\n          - name: mas\n            src: mas_components.pkg/Payload/mas\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 4.1.0\")\n        asset: mas-{{trimV .Version}}-{{.Arch}}.{{.Format}}\n        format: pkg\n        replacements:\n          amd64: x86_64\n        files:\n          - name: mas\n            src: mas_components.pkg/Payload/usr/local/opt/mas/bin/mas\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: mas-{{trimV .Version}}-{{.Arch}}.{{.Format}}\n        format: pkg\n        replacements:\n          amd64: x86_64\n        files:\n          - name: mas\n            src: mas.pkg/Payload/usr/local/opt/mas/bin/mas\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mashiike/acrun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mashiike\n    repo_name: acrun\n    description: acrun is a deployment tool for AWS Bedrock AgentCore Runtime\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: acrun_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mashiike/prepalert/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mashiike\n    repo_name: prepalert\n    description: Toil reduction tool to prepare before responding to Mackerel alerts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: prepalert_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: prepalert_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: prepalert_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: prepalert_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mashiike/redshift-credentials/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mashiike\n    repo_name: redshift-credentials\n    description: a command line tool for Amazon Redshift temporary authorization with AWS IAM\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: redshift-credentials_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: redshift-credentials_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: redshift-credentials_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mashiike/stefunny/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mashiike\n    repo_name: stefunny\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.4\")\n        asset: stefunny_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: stefunny_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: stefunny_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/masutaka/github-nippou/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: masutaka\n    repo_name: github-nippou\n    description: Print today's your GitHub activity for issues and pull requests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.2.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.1.11\")\n        asset: github-nippou_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.2.9\")\n        asset: github-nippou_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: github-nippou_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: github-nippou_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mathew-fleisch/bashbot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mathew-fleisch\n    repo_name: bashbot\n    description: A slack-bot written in golang for infrastructure/devops teams\n    asset: bashbot-{{.OS}}-{{.Arch}}\n    format: raw\n    supported_envs:\n      - linux\n      - darwin\n    version_prefix: bashbot-\n    version_constraint: semver(\">= 2.0.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 2.0.0\")\n        version_prefix: \"\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/matryer/moq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: matryer\n    repo_name: moq\n    description: Interface mocking tool for go generate\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: moq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.1.7\"\n        asset: moq_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: moq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: moq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: moq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.3.3\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: moq_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattermost/mmctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattermost\n    repo_name: mmctl\n    asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n    format: tar\n    description: A remote CLI tool for Mattermost\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.md5.txt\"\n      algorithm: md5\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/algia/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: algia\n    description: A cli application for nostr\n    asset: algia_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: algia\n        src: algia_{{.Version}}_{{.OS}}_{{.Arch}}/algia\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/bsky/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: bsky\n    description: A cli application for bluesky social\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.40\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.63\"\n        asset: bsky-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: darwin\n            asset: bsky-{{.OS}}-.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: bsky-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/cho/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: cho\n    asset: cho_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: cho\n        src: cho_{{.Version}}_{{.OS}}_{{.Arch}}/cho\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/efm-langserver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: efm-langserver\n    asset: efm-langserver_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: General purpose Language Server\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: efm-langserver\n        src: efm-langserver_{{.Version}}_{{.OS}}_{{.Arch}}/efm-langserver\n    version_constraint: semver(\"!= 0.0.45\")\n    version_overrides:\n      - version_constraint: semver(\"= 0.0.45\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/files/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: files\n    description: Fast file find\n    asset: files_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: files\n        src: files_{{.Version}}_{{.OS}}_{{.Arch}}/files\n    version_constraint: semver(\">= 0.3.4\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.3.4\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/gof/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: gof\n    asset: gof_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Go Fuzzy\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: gof\n        src: gof_{{.Version}}_{{.OS}}_{{.Arch}}/gof\n    version_constraint: semver(\">= 0.0.12\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/goreman/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: goreman\n    description: foreman clone written in go language\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: goreman_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: goreman\n        src: goreman_{{.Version}}_{{.OS}}_{{.Arch}}/goreman\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/longcat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: longcat\n    description: Looooooooooooooooooooooooooooooooooooooooooooooong cat\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: longcat_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n        files:\n          - name: longcat\n            src: \"{{.AssetWithoutExt}}/longcat\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/memo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: memo\n    description: Memo Life For You\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: memo_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    files:\n      - name: memo\n        src: memo_{{.Version}}_{{.OS}}_amd64/memo\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/twty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: twty\n    asset: twty_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: command-line twitter client written in golang\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: twty\n        src: twty_{{.Version}}_{{.OS}}_{{.Arch}}/twty\n    version_constraint: semver(\">= 0.0.13\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mattn/zig-update/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mattn\n    repo_name: zig-update\n    description: Zig updator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: zig-update_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: zig-update\n            src: zig-update_{{.Version}}_{{.OS}}_{{.Arch}}/zig-update\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.0.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: zig-update_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: zig-update\n            src: zig-update_{{.Version}}_{{.OS}}_{{.Arch}}/zig-update\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/maxpert/marmot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: maxpert\n    repo_name: marmot\n    description: A distributed SQLite server with MySQL wire compatible interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.1-alpha\"\n        asset: marmot-v0.4.1-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.5\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.8.5-beta.3\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.8.8-alpha.4\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.0.1-beta.2\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 2.0.5\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.1.2\")\n        asset: marmot-{{.Version}}-beta-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: marmot-{{.Version}}-beta-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.4.2\")\n        asset: marmot-{{.Version}}-beta-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            asset: marmot-{{.Version}}-beta-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            asset: marmot-{{.Version}}-{{.OS}}-{{.Arch}}-static.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mazrean/kessoku/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mazrean\n    repo_name: kessoku\n    description: Next-generation google/wire with parallel dependency injection for Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kessoku_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/megaease/easeprobe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: megaease\n    repo_name: easeprobe\n    description: A simple, standalone, and lightWeight tool that can do health/status checking, written in Go\n    asset: easeprobe-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: easeprobe\n        src: bin/easeprobe\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mercari/hcledit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mercari\n    repo_name: hcledit\n    asset: hcledit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Go package to edit HCL configuration\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    files:\n      - name: hcledit\n        src: bin/hcledit\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mercari/tfnotify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mercari\n    repo_name: tfnotify\n    description: A CLI command to parse Terraform execution result and notify it to GitHub\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: tfnotify_{{.OS}}_{{.Arch}}.tar.gz\n    checksum:\n      type: github_release\n      asset: tfnotify_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mergestat/mergestat-lite/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mergestat\n    repo_name: mergestat-lite\n    description: Query git repositories with SQL. Generate reports, perform status checks, analyze codebases\n    rosetta2: true\n    asset: mergestat-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: mergestat\n    supported_envs:\n      - darwin\n      - linux/amd64\n    replacements:\n      darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mesosphere/mindthegap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mesosphere\n    repo_name: mindthegap\n    description: Easily create and use bundles for air-gapped environments\n    asset: mindthegap_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.13.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.7.3\")\n        overrides:\n          - goos: darwin\n            asset: mindthegap_{{.Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\">= 0.6.6\")\n      - version_constraint: semver(\"< 0.6.6\")\n        asset: mindthegap_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides:\n          - goos: darwin\n            asset: mindthegap_{{.Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/metalbear-co/mirrord/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: metalbear-co\n    repo_name: mirrord\n    description: By mirroring traffic to and from your machine, mirrord surrounds your local service with a mirror image of its cloud environment\n    replacements:\n      darwin: mac\n      amd64: x86_64\n      arm64: aarch64\n    version_constraint: semver(\">= 2.2.1\")\n    supported_envs:\n      - linux\n      - darwin\n    rosetta2: true\n    format: zip\n    asset: mirrord_{{.OS}}_{{.Arch}}.{{.Format}}\n    overrides:\n      - goos: darwin\n        replacements:\n          amd64: universal\n    version_overrides:\n      - version_constraint: semver(\"< 2.2.1\")\n        rosetta2: false\n        asset: mirrord_{{.OS}}_{{.Arch}}\n        format: raw\n        overrides: []\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mfontanini/presenterm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mfontanini\n    repo_name: presenterm\n    description: A markdown terminal slideshow tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: presenterm-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: presenterm\n            src: presenterm-{{trimV .Version}}/presenterm\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mfridman/tparse/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mfridman\n    repo_name: tparse\n    description: CLI tool for summarizing go test output. Pipe friendly. CI/CD friendly\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.4\")\n        asset: tparse_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.3\")\n        asset: tparse_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: tparse_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.12.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tparse_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mgdm/htmlq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mgdm\n    repo_name: htmlq\n    description: Like jq, but for HTML\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: htmlq_{{.Arch}}_{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: htmlq-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mgechev/revive/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mgechev\n    repo_name: revive\n    description: ~6x faster, stricter, configurable, extensible, and beautiful drop-in replacement for golint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.2\")\n        asset: revive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: revive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: revive_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mgunyho/tere/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mgunyho\n    repo_name: tere\n    description: Terminal file explorer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: tere-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v1.1.0\"\n        asset: tere-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: tere-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/michidk/vscli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: michidk\n    repo_name: vscli\n    description: A CLI tool to launch vscode projects, which supports devcontainers\n    asset: vscli-{{.Arch}}-{{.OS}}.{{.Format}}\n    files:\n      - name: vscli\n        src: vscli-{{.Arch}}-{{.OS}}/vscli\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    version_constraint: semver(\">= 0.1.7\")\n    version_overrides:\n      - version_constraint: Version == \"v0.1.6\"\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            checksum:\n              enabled: false\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.1.5\"\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.1.5\")\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            checksum:\n              enabled: false\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n        rosetta2: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/micro-editor/micro/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: micro-editor\n    repo_name: micro\n    aliases:\n      - name: zyedidia/micro\n    description: A modern and intuitive terminal-based text editor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.0.8\"\n        asset: micro-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: micro\n            src: micro-{{trimV .Version}}/micro\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: micro-{{trimV .Version}}-{{.OS}}64-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            asset: micro-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0rc1\")\n        asset: micro-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: micro\n            src: micro-{{trimV .Version}}/micro\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: linux\n            asset: micro-{{.Version}}-{{.OS}}64.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: micro-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: micro\n            src: micro-{{trimV .Version}}/micro\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: linux\n            asset: micro-{{trimV .Version}}-{{.OS}}64.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.10\")\n        asset: micro-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: micro\n            src: micro-{{trimV .Version}}/micro\n        replacements:\n          darwin: osx\n          windows: win64\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: micro-{{trimV .Version}}-{{.OS}}64-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            asset: micro-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: micro-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: micro\n            src: micro-{{trimV .Version}}/micro\n        replacements:\n          windows: win64\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: micro-{{trimV .Version}}-{{.OS}}64-static.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            asset: micro-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              darwin: osx\n          - goos: darwin\n            goarch: arm64\n            asset: micro-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              darwin: macos\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/microsoft/component-detection/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: microsoft\n    repo_name: component-detection\n    description: Scans your project to determine what components you use\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: component-detection-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 5.0.0\")\n        asset: component-detection-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: component-detection-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/microsoft/edit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: microsoft\n    repo_name: edit\n    description: We all edit\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.1\"\n        asset: edit-1.2.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.zst\n        overrides:\n          - goos: windows\n            asset: edit-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            format: zip\n            files:\n              - name: edit\n                src: \"{{.AssetWithoutExt}}/edit.exe\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: linux-gnu\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: Version == \"v1.0.0\"\n        asset: edit-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: xz\n        files:\n          - name: edit\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: linux-gnu\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: edit\n                src: \"{{.AssetWithoutExt}}/edit.exe\"\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: \"true\"\n        asset: edit-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.zst\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: edit\n                src: \"{{.AssetWithoutExt}}/edit.exe\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: linux-gnu\n        supported_envs:\n          - linux\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/microsoft/kiota/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: microsoft\n    repo_name: kiota\n    description: OpenAPI based HTTP Client code generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: \"{{.OS}}-{{.Arch}}.{{.Format}}\"\n        files:\n          - name: kiota\n            src: \"{{.OS}}-{{.Arch}}/kiota\"\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}-{{.Arch}}.{{.Format}}\"\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/microsoft/ripgrep-prebuilt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: microsoft\n    repo_name: ripgrep-prebuilt\n    asset: ripgrep-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    description: Builds ripgrep on Azure Pipelines for multiple platforms and makes the binaries available as Github releases\n    format: tar.gz\n    replacements:\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n      linux: unknown-linux-musl\n      arm64: aarch64\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: rg\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/microsoft/vscode/code/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: microsoft/vscode/code\n    type: http\n    repo_owner: microsoft\n    repo_name: vscode\n    description: Visual Studio Code\n    link: https://code.visualstudio.com/\n    search_words:\n      - visual studio code\n    url: https://update.code.visualstudio.com/{{trimV .Version}}/cli-{{.OS}}-{{.Arch}}/stable\n    replacements:\n      windows: win32\n      amd64: x64\n    format: tar.gz\n    append_ext: false\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\">= 1.73.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 1.73.0\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mike-engel/jwt-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mike-engel\n    repo_name: jwt-cli\n    description: A super fast CLI tool to decode and encode JWTs built in Rust\n    files:\n      - name: jwt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        no_asset: true\n      - version_constraint: Version == \"0.3.1\"\n        asset: jwt-cli-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: jwt-cli\n            src: jwt-cli\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: jwt-cli-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: jwt-cli\n            src: jwt-cli\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"0.4.1\"\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: jwt-cli\n            src: jwt-cli\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            asset: jwt-cli-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.2.0\"\n        no_asset: true\n      - version_constraint: semver(\"< 2.2.0\")\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"2.2.0\"\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: linux\n            files:\n              - name: jwt\n                src: target/release/jwt\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"2.2.1\"\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: darwin\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: semver(\"< 3.2.0\")\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"3.2.0\"\n        asset: jwt-cli-{{.Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: linux\n            files:\n              - name: jwt\n                src: target/release/jwt\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 6.1.0\")\n        asset: jwt-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: jwt-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: jwt-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n          linux: linux-musl\n        checksum:\n          type: github_release\n          asset: jwt-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mikefarah/yq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mikefarah\n    repo_name: yq\n    description: yq is a portable command-line YAML processor\n    asset: yq_{{.OS}}_{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    # https://github.com/mikefarah/yq/issues/801#issuecomment-853523411\n    version_constraint: semver(\">= 4.9.6\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/miku/zek/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: miku\n    repo_name: zek\n    description: Generate a Go struct from XML\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.9\"\n        asset: zek-{{trimV .Version}}.{{.OS}}.{{.Arch}}.bin\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"0.1.19\"\n        asset: zek_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: zek_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.12\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.26\")\n        asset: zek_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: zek_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: zek_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: zek_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/hcledit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: hcledit\n    description: A command line editor for HCL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: hcledit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: hcledit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.6\")\n        asset: hcledit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hcledit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: hcledit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hcledit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/myaws/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: myaws\n    description: A human friendly AWS CLI written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: myaws_{{trimV .Version}}_myaws_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: myaws_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: myaws_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: myaws_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: myaws_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: myaws_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: myaws_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/tfedit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: tfedit\n    description: A refactoring tool for Terraform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfedit_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfedit_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/tfmigrate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: tfmigrate\n    description: A Terraform / OpenTofu state migration tool for GitOps\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.12\")\n        asset: tfmigrate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: tfmigrate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: tfmigrate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfmigrate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/tfschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: tfschema\n    description: A schema inspector for Terraform / OpenTofu providers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: tfschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: tfschema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: tfschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfschema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tfschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfschema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minamijoyo/tfupdate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minamijoyo\n    repo_name: tfupdate\n    description: Update version constraints in your Terraform configurations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: tfupdate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfupdate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tfupdate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfupdate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minc-org/minc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minc-org\n    repo_name: minc\n    description: MicroShift in Container\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: minc_{{.OS}}_{{.Arch}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: minc\n      - version_constraint: \"true\"\n        asset: minc_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: minc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minio/mc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: minio\n    repo_name: mc\n    description: Unix like utilities for object store\n    url: https://dl.min.io/client/mc/release/{{.OS}}-{{.Arch}}/archive/mc.{{.Version}}\n    complete_windows_ext: false\n    windows_arm_emulation: true\n    format: raw\n    overrides:\n      - goos: windows\n        files:\n          - name: mc\n            link: mc.exe\n    checksum:\n      type: http\n      algorithm: sha256\n      url: https://dl.min.io/client/mc/release/{{.OS}}-{{.Arch}}/archive/mc.{{.Version}}.sha256sum\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/miniscruff/changie/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: miniscruff\n    repo_name: changie\n    description: Automated changelog tool for preparing releases with lots of customization options\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: changie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: changie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: changie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: changie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/minishift/minishift/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: minishift\n    repo_name: minishift\n    description: Run OpenShift 3.x locally\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: minishift-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tgz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: minishift\n        src: minishift-{{trimV .Version}}-{{.OS}}-{{.Arch}}/minishift\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mintoolkit/mint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mintoolkit\n    repo_name: mint\n    aliases:\n      - name: slimtoolkit/slim\n      - name: docker-slim/docker-slim\n    files:\n      - name: docker-slim\n        src: \"{{.AssetWithoutExt}}/docker-slim\"\n      - name: mint\n        src: \"{{.AssetWithoutExt}}/mint\"\n      - name: mint-sensor\n        src: \"{{.AssetWithoutExt}}/mint-sensor\"\n      - name: slim\n        src: \"{{.AssetWithoutExt}}/slim\"\n    description: \"minT(oolkit): Mint awesome, secure and production ready containers just the way you need them! Don't change anything in your container image and minify it by up to 30x (and for compiled languages even more) making it secure too! (free and open source)\"\n    version_constraint: \"false\"\n    version_overrides:\n      # https://github.com/aquaproj/aqua-registry/issues/37618\n      - version_constraint: semver(\"< 1.40.11\")\n        no_asset: true\n      - version_constraint: Version == \"1.40.11\"\n        repo_owner: slimtoolkit\n        repo_name: slim\n        asset: dist_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: dist_{{.OS}}.{{.Format}}\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: arm\n          - goos: darwin\n            format: zip\n            asset: dist_{{.OS}}.{{.Format}}\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: dist_{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: dist_{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: arm\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mislav/hub/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mislav\n    repo_name: hub\n    aliases:\n      - name: github/hub\n    rosetta2: true\n    asset: hub-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n    description: A command-line tool that makes git easier to use with GitHub\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tgz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: hub\n            src: bin/hub.exe\n    files:\n      - name: hub\n        src: hub-{{.OS}}-{{.Arch}}-{{trimV .Version}}/bin/hub\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mistakenelf/fm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mistakenelf\n    repo_name: fm\n    description: A terminal based file manager\n    aliases:\n      - name: knipferrc/fm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.13.0\"\n        asset: fm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: fm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: fm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: fm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: fm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: fm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: fm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitchellh/golicense/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mitchellh\n    repo_name: golicense\n    description: Scan and analyze OSS dependencies and licenses from compiled Go binaries\n    asset: golicense_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: macos\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitchellh/gon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mitchellh\n    repo_name: gon\n    asset: gon_{{.OS}}.zip\n    description: Sign, notarize, and package macOS CLI tools and applications written in any language. Available as both a CLI and a Go library\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitchellh/gox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: mitchellh\n    repo_name: gox\n    description: A dead simple, no frills Go cross compile tool\n    version_source: github_tag\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitoma/sver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mitoma\n    repo_name: sver\n    description: Version generator based on source code\n    asset: sver_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    replacements:\n      darwin: macos\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: SHASUMS256.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.1.14\")\n    version_overrides:\n      - version_constraint: Version == \"v0.1.13\"\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.1.7\")\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 0.1.2\")\n        replacements: {}\n        checksum:\n          enabled: false\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"< 0.1.2\")\n        asset: sver_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements: {}\n        checksum:\n          enabled: false\n        files:\n          - name: sver\n            src: sver_{{.OS}}_{{.Arch}}/sver\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitsuhiko/insta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mitsuhiko\n    repo_name: insta\n    description: A snapshot testing library for rust\n    files:\n      - name: cargo-insta\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cargo-insta-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-insta\n            src: \"{{.AssetWithoutExt}}/cargo-insta\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-insta\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mitsuhiko/minijinja/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mitsuhiko\n    repo_name: minijinja\n    description: MiniJinja is a powerful but minimal dependency template engine for Rust compatible with Jinja/Jinja2\n    files:\n      - name: minijinja-cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.3.1\")\n        asset: minijinja-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: minijinja-cli\n            src: \"{{.AssetWithoutExt}}/minijinja-cli\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: minijinja-cli\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: minijinja-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: minijinja-cli\n            src: \"{{.AssetWithoutExt}}/minijinja-cli\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: minijinja-cli\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mkchoi212/fac/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mkchoi212\n    repo_name: fac\n    description: Easy-to-use CUI for fixing git conflicts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: fac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: fac_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mkubaczyk/helmsman/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mkubaczyk\n    repo_name: helmsman\n    aliases:\n      - name: Praqma/helmsman\n    description: Helm Charts as Code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.0\"\n        asset: Helmsman_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.3.0\"\n        asset: helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: Helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: Helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: Helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: Helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.0-rc2\")\n        asset: helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.12.0\")\n        asset: Helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: Helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 3.8.1\")\n        asset: helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: helmsman_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: helmsman_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mmalcek/bafi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mmalcek\n    repo_name: bafi\n    asset: bafi_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tgz\n    description: Universal JSON, BSON, YAML, CSV, XML converter with templates\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: bafi_{{.Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n      algorithm: md5\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mmarkdown/mmark/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mmarkdown\n    repo_name: mmark\n    asset: mmark_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tgz\n    description: A powerful markdown processor in Go geared towards the IETF\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/moby/buildkit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: moby\n    repo_name: buildkit\n    description: concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit\n    files:\n      - name: buildctl\n        src: bin/{{.FileName}}\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.3\")\n        asset: buildkit-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            files:\n              - name: buildctl\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-aarch64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-arm\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-i386\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-ppc64le\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-riscv64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-s390x\n                src: bin/{{.FileName}}\n              - name: buildkit-runc\n                src: bin/{{.FileName}}\n              - name: buildkitd\n                src: bin/{{.FileName}}\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: buildctl\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-arm\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-i386\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-ppc64le\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-riscv64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-s390x\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-x86_64\n                src: bin/{{.FileName}}\n              - name: buildkit-runc\n                src: bin/{{.FileName}}\n              - name: buildkitd\n                src: bin/{{.FileName}}\n      - version_constraint: \"true\"\n        asset: buildkit-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            goarch: amd64\n            files:\n              - name: buildctl\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-bridge\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-firewall\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-host-local\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-loopback\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-aarch64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-arm\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-i386\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-ppc64le\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-riscv64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-s390x\n                src: bin/{{.FileName}}\n              - name: buildkit-runc\n                src: bin/{{.FileName}}\n              - name: buildkitd\n                src: bin/{{.FileName}}\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: buildctl\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-bridge\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-firewall\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-host-local\n                src: bin/{{.FileName}}\n              - name: buildkit-cni-loopback\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-arm\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-i386\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-ppc64le\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-riscv64\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-s390x\n                src: bin/{{.FileName}}\n              - name: buildkit-qemu-x86_64\n                src: bin/{{.FileName}}\n              - name: buildkit-runc\n                src: bin/{{.FileName}}\n              - name: buildkitd\n                src: bin/{{.FileName}}\n          - goos: windows\n            files:\n              - name: buildctl\n                src: bin/{{.FileName}}\n              - name: buildkitd\n                src: bin/{{.FileName}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/momaek/authy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: momaek\n    repo_name: authy\n    description: TOTP Alfred Workflow, Authy Aflred Workflow, Authy command line tool\n    asset: authy.tar.gz\n    supported_envs:\n      - darwin\n    files:\n      - name: authy\n        src: authy-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/moncho/dry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: moncho\n    repo_name: dry\n    description: dry - A Docker manager for the terminal @\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.3-beta.2\", \"v0.9-beta.6\"] or semver(\"> 0.3-beta.10, <= 0.4-beta.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9-beta.9\")\n        asset: dry-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10-beta.1\")\n        asset: dry-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: dry-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mongodb/mongodb-atlas-cli/atlascli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: mongodb/mongodb-atlas-cli/atlascli\n    type: github_release\n    repo_owner: mongodb\n    repo_name: mongodb-atlas-cli\n    description: MongoDB Atlas CLI and MongoDB CLI enable you to manage your MongoDB in the Cloud\n    asset: mongodb-atlas-cli_{{trimPrefix \"atlascli/v\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    replacements:\n      darwin: macos\n      amd64: x86_64\n    files:\n      - name: atlas\n        src: bin/atlas\n    overrides:\n      - goos: linux\n        format: tar.gz\n        files:\n          - name: atlas\n            src: mongodb-atlas-cli_{{trimPrefix \"atlascli/v\" .Version}}_{{.OS}}_{{.Arch}}/bin/atlas\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_filter: Version startsWith \"atlascli/\"\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mongodb/mongodb-atlas-cli/mongocli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: mongodb/mongodb-atlas-cli/mongocli\n    type: github_release\n    repo_owner: mongodb\n    repo_name: mongodb-atlas-cli\n    description: MongoDB Atlas CLI and MongoDB CLI enable you to manage your MongoDB in the Cloud\n    aliases:\n      - name: mongodb/mongocli\n    asset: mongocli_{{trimPrefix \"mongocli/v\" .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    replacements:\n      darwin: macos\n      amd64: x86_64\n    files:\n      - name: mongocli\n        src: bin/mongocli\n    overrides:\n      - goos: linux\n        format: tar.gz\n        files:\n          - name: mongocli\n            src: mongocli_{{trimPrefix \"mongocli/v\" .Version}}_{{.OS}}_{{.Arch}}/bin/mongocli\n    supported_envs:\n      - darwin\n      - linux\n    version_filter: Version startsWith \"mongocli/\" or semver(\"< 1.23.0\")\n    version_constraint: semverWithVersion(\">= 1.23.0\", trimPrefix(Version, \"mongocli/\"))\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      # asset style was changed\n      - version_constraint: semver(\">= 1.15.0\")\n        asset: mongocli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - linux\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: mongocli\n                src: mongocli_{{trimV .Version}}_{{.OS}}_{{.Arch}}/bin/mongocli\n      # arm64 wasn't supported\n      - version_constraint: \"true\"\n        asset: mongocli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - amd64\n          - darwin\n        rosetta2: true\n        files:\n          - name: mongocli\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: mongocli\n                src: mongocli_{{trimV .Version}}_{{.OS}}_{{.Arch}}/mongocli\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mono0926/LicensePlist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mono0926\n    repo_name: LicensePlist\n    description: A license list generator of all your dependencies for iOS applications\n    files:\n      - name: license-plist\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.5.3\") or Version in [\"2.15.0\", \"2.11.3\", \"2.5.7\", \"2.5.6\", \"2.3.1\", \"1.7.3\", \"1.7.2\", \"1.7.1\", \"1.6.2\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: portable_licenseplist.{{.Format}}\n        format: zip\n        files:\n          - name: license-plist\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mooltiverse/nyx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mooltiverse\n    repo_name: nyx\n    description: The one stop semantic release tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-alpha.1\")\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.2.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.3.2-hotfix196.1\")\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n      - version_constraint: Version == \"2.3.2\"\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 2.5.0-alpha.2\")\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n      - version_constraint: Version == \"2.5.0-alpha.3\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.5.1-alpha.3\")\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n      - version_constraint: Version == \"2.5.1-alpha.4\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: nyx-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/moonrepo/moon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: moonrepo\n    repo_name: moon\n    description: A build system and monorepo management tool for the web ecosystem, written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"@moonrepo/cli@0.12.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.0\")\n        version_prefix: \"@moonrepo/cli@\"\n        asset: moon-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.1\")\n        version_prefix: \"@moonrepo/cli@\"\n        asset: moon-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.41.8\")\n        asset: moon-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: moon_cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: moon\n            src: \"{{.AssetWithoutExt}}/moon\"\n          - name: moonx\n            src: \"{{.AssetWithoutExt}}/moonx\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n            files:\n              - name: moon\n              - name: moonx\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/moonrepo/proto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: moonrepo\n    repo_name: proto\n    description: A pluggable multi-language version manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: proto_cli-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: proto\n            src: \"{{.AssetWithoutExt}}/proto\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: proto\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: proto_cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: proto\n            src: \"{{.AssetWithoutExt}}/proto\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: proto\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.20.4\")\n        asset: proto_cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: proto\n            src: \"{{.AssetWithoutExt}}/proto\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: proto\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.24.2\")\n        asset: proto_cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: proto\n            src: \"{{.AssetWithoutExt}}/proto\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: proto\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: proto_cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: proto\n            src: \"{{.AssetWithoutExt}}/proto\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: proto\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mozilla/grcov/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mozilla\n    repo_name: grcov\n    description: Rust tool to collect and aggregate code coverage data for multiple source files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v0.7.0\"\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.7.1\"\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.1.28\")\n        asset: grcov-{{.OS}}-standalone-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        overrides:\n          - goos: windows\n            asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.5.15\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: grcov-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.8.6\")\n        asset: grcov-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums-{{.Version}}.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: grcov-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.bz2\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mozilla/sccache/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mozilla\n    repo_name: sccache\n    description: Sccache is a ccache-like tool. It is used as a compiler wrapper and avoids compilation when possible. Sccache has the capability to utilize caching in remote storage environments, including various cloud storage options, or alternatively, in local storage\n    files:\n      - name: sccache\n        src: \"{{.AssetWithoutExt}}/sccache\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.2\"\n        no_asset: true\n      - version_constraint: Version in [\"v0.5.1\", \"v0.6.0\"]\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.13.0\"\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows\n      - version_constraint: semver(\"<= 0.2.13\")\n        error_message: \"This version is too old. Please use newer versions\"\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.0-pre.1\")\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: sccache-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mpalmer/action-validator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mpalmer\n    repo_name: action-validator\n    description: Tool to validate GitHub Action and Workflow YAML files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: action-validator_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: action-validator_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: action-validator_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mpostument/awstaghelper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mpostument\n    repo_name: awstaghelper\n    description: AWS bulk tagging tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.17.1\")\n        asset: awstaghelper_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: awstaghelper_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: awstaghelper_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mr-karan/doggo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mr-karan\n    repo_name: doggo\n    description: \":dog: Command-line DNS Client for Humans. Written in Golang\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: doggo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: doggo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: doggo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: doggo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.7\")\n        asset: doggo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: doggo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: doggo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: doggo\n            src: \"{{.AssetWithoutExt}}/doggo\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: doggo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mrjackwills/oxker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mrjackwills\n    repo_name: oxker\n    description: A simple tui to view & control docker containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.3\")\n        asset: oxker_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: oxker_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: darwin\n            asset: oxker_apple_{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: amd64\n          - goos: windows\n            format: zip\n            replacements: {}\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mrjosh/helm-ls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mrjosh\n    repo_name: helm-ls\n    description: Language server for Helm\n    files:\n      - name: helm_ls\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.3\"\n        asset: helm_ls_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: helm_ls_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: helm_ls_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mrowa44/emojify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: mrowa44\n    repo_name: emojify\n    description: \"Emoji on the command line :scream:\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        path: emojify\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ms-jpq/sad/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ms-jpq\n    repo_name: sad\n    description: CLI search and replace | Space Age seD\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    asset: \"{{.Arch}}-{{.OS}}.zip\"\n    version_constraint: semver(\">= 0.4.17\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n          - amd64\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/msoap/shell2http/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: msoap\n    repo_name: shell2http\n    description: Executing shell commands via HTTP server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1\"\n        asset: shell2http_{{.Version}}.{{.Arch}}.{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"1.2\"\n        asset: shell2http-{{.Version}}.{{.Arch}}.{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"1.7\"\n        asset: shell2http-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: shell2http-{{.Version}}.{{.Arch}}.{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: shell2http-{{.Version}}.{{.Arch}}.{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.13.0\")\n        asset: shell2http-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: shell2http_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mstange/samply/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mstange\n    repo_name: samply\n    description: Command-line sampling profiler for macOS, Linux, and Windows\n    version_prefix: samply-v\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"= 0.12.0\")\n        asset: samply-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: samply\n            src: samply-{{.Arch}}-{{.OS}}/samply\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: samply\n                src: samply.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: samply-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: samply\n            src: samply-{{.Arch}}-{{.OS}}/samply\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            files:\n              - name: samply\n                src: samply.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mszostok/codeowners-validator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mszostok\n    repo_name: codeowners-validator\n    description: The GitHub CODEOWNERS file validator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: codeowners-validator_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: codeowners-validator_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/muesli/duf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: muesli\n    repo_name: duf\n    description: \"Disk Usage/Free Utility - a better 'df' alternative\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0\"\n        asset: duf_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: duf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/muesli/gitty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: muesli\n    repo_name: gitty\n    description: Contextual information about your git projects, right on the command-line\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gitty_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/muesli/markscribe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: muesli\n    repo_name: markscribe\n    description: Your personal markdown scribe with template-engine and Git(Hub) & RSS powers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: markscribe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: markscribe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mumoshu/config-registry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mumoshu\n    repo_name: config-registry\n    description: Switch between kubeconfigs and avoid unintentional operation on your production clusters\n    asset: config-registry_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mumoshu/conflint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mumoshu\n    repo_name: conflint\n    description: Unified lint runners for various configuration files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: conflint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: conflint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mumoshu/variant/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mumoshu\n    repo_name: variant\n    description: Wrap up your bash scripts into a modern CLI today. Graduate to a full-blown golang app tomorrow\n    rosetta2: true\n    asset: variant_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n    checksum:\n      type: github_release\n      asset: variant_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mumoshu/variant2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mumoshu\n    repo_name: variant2\n    description: Turn your bash scripts into a modern, single-executable CLI app today\n    asset: variant_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: variant\n    checksum:\n      type: github_release\n      asset: variant_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/muquit/mailsend-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: muquit\n    repo_name: mailsend-go\n    description: mailsend-go is a multi-platform  command line tool to send mail via SMTP protocol\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.3\")\n        asset: mailsend-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64-bit\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: mailsend-go_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: mailsend-go\n            src: mailsend-go-dir/mailsend-go\n      - version_constraint: semver(\"<= 1.0.10\")\n        asset: mailsend-go_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: mailsend-go_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM\n          - goos: windows\n            format: zip\n        files:\n          - name: mailsend-go\n            src: mailsend-go-dir/mailsend-go\n      - version_constraint: \"true\"\n        asset: mailsend-go-{{.Version}}-{{.OS}}-{{.Arch}}.d.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: mailsend-go-{{.Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: mailsend-go\n            src: \"{{.AssetWithoutExt}}/mailsend-go-{{.Version}}-{{.OS}}-{{.Arch}}\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mutagen-io/mutagen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mutagen-io\n    repo_name: mutagen\n    asset: mutagen_{{.OS}}_{{.Arch}}_{{.Version}}.tar.gz\n    description: Fast file synchronization and network forwarding for remote development\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mutagen-io/mutagen-compose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mutagen-io\n    repo_name: mutagen-compose\n    asset: mutagen-compose_{{.OS}}_{{.Arch}}_{{.Version}}.tar.gz\n    description: Compose with Mutagen integration\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvdan/gofumpt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvdan\n    repo_name: gofumpt\n    description: A stricter gofmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: gofumpt_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: gofumpt_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: gofumpt_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gofumpt_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvdan/sh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvdan\n    repo_name: sh\n    description: A shell parser, formatter, and interpreter with bash support; includes shfmt\n    files:\n      - name: shfmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 3.8.0\")\n        format: raw\n        asset: shfmt_{{.Version}}_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        files:\n          - name: shfmt\n      - version_constraint: semver(\"<= 3.12.0\")\n        format: raw\n        asset: shfmt_{{.Version}}_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        files:\n          - name: shfmt\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        format: raw\n        asset: shfmt_{{.Version}}_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        files:\n          - name: shfmt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvisonneau/approuvez/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvisonneau\n    repo_name: approuvez\n    description: command line helper to obtain live confirmation from relevant people\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"edge\"\n        asset: approuvez_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: approuvez_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: approuvez_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: approuvez_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: approuvez_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: approuvez_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvisonneau/gpcd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvisonneau\n    repo_name: gpcd\n    description: GoPro Cloud Downloader\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gpcd_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gpcd_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvisonneau/s5/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvisonneau\n    repo_name: s5\n    description: Safely Store Super Sensitive Stuff\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.14\"\n        no_asset: true\n      - version_constraint: Version == \"0.1.3\"\n        asset: s5_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: Version == \"0.1.9\"\n        asset: s5_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: s5_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"edge\"\n        asset: s5_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: s5_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.1.10\"\n        asset: s5_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: s5_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: s5_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: s5_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: s5_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: s5_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvisonneau/tfcw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvisonneau\n    repo_name: tfcw\n    description: Terraform Cloud Wrapper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.4\"\n        no_asset: true\n      - version_constraint: Version == \"edge\"\n        asset: tfcw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcw_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.10\"\n        asset: tfcw_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfcw_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.11\"\n        asset: tfcw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfcw_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: tfcw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tfcw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcw_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/mvisonneau/vac/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: mvisonneau\n    repo_name: vac\n    description: AWS credentials management leveraging Vault\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.0.4\"\n        asset: vac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vac_{{.Version}}_SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"edge\"\n        asset: vac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vac_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.5\"\n        asset: vac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vac_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: vac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: vac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vac_{{.Version}}_sha512sums.txt\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nabeken/go-github-apps/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nabeken\n    repo_name: go-github-apps\n    description: A tiny command-line utility to retrieve Github Apps Installation Token\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: go-github-apps_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.2\"\n        asset: go-github-apps_0_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.3\"\n        asset: go-github-apps_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: go-github-apps_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nadoo/glider/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nadoo\n    repo_name: glider\n    description: glider is a forward proxy with multiple protocols support, and also a dns/dhcp server with ipset management features(like dnsmasq)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.3\"\n        no_asset: true\n      - version_constraint: Version == \"v0.7.0\"\n        asset: glider-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: glider-{{.Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: glider-{{.Version}}-{{.OS}}-{{.Arch}}/glider\n      - version_constraint: Version == \"v0.15.0\"\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}/glider\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: glider-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: glider\n      - version_constraint: semver(\"<= 0.6.11\")\n        asset: glider-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macosx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: glider\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: \"{{.AssetWithoutExt}}/glider\"\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: \"{{.AssetWithoutExt}}/glider\"\n      - version_constraint: semver(\"<= 0.15.2\")\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: \"{{.AssetWithoutExt}}/glider\"\n      - version_constraint: semver(\"<= 0.16.3\")\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: \"{{.AssetWithoutExt}}/glider\"\n      - version_constraint: \"true\"\n        asset: glider_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: glider_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: glider\n            src: \"{{.AssetWithoutExt}}/glider\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/naggie/dstask/dstask-import/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: naggie/dstask/dstask-import\n    repo_owner: naggie\n    repo_name: dstask\n    description: Git powered terminal-based todo manager -- markdown note page per task. Single binary\n    rosetta2: true\n    asset: dstask-import-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux/amd64\n    files:\n      - name: dstask-import\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/naggie/dstask/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: naggie\n    repo_name: dstask\n    description: Git powered terminal-based todo manager -- markdown note page per task. Single binary\n    rosetta2: true\n    asset: dstask-{{.OS}}-{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nakabonne/ali/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nakabonne\n    repo_name: ali\n    description: Generate HTTP load and plot the results in real-time\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.7.0\"\n        asset: ali_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: ali_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ali_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/namespacelabs/foundation/nsc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: namespacelabs/foundation/nsc\n    type: github_release\n    repo_owner: namespacelabs\n    repo_name: foundation\n    description: Open-source Kubernetes application platform that powers Namespace's developer-optimized compute platform\n    files:\n      - name: nsc\n      - name: docker-credential-nsc\n      - name: bazel-credential-nsc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.158\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.195\")\n        asset: nsc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: nsc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.391\")\n        asset: nsc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: nsc\n          - name: docker-credential-nsc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: nsc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nametake/golangci-lint-langserver/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nametake\n    repo_name: golangci-lint-langserver\n    description: golangci-lint language server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.6\")\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.7\"\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.8\"\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: golangci-lint-langserver_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: golangci-lint-langserver_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nao1215/gup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nao1215\n    repo_name: gup\n    description: 'gup - Update binaries installed by \"go install\" with goroutines'\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: gup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gup_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nao1215/sqly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nao1215\n    repo_name: sqly\n    description: eaisly execute SQL against CSV/TSV/LTSV/JSON and Microsoft Excel with shell\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.4\"\n        asset: sqly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.8.0\"\n        asset: sqly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: sqly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: sqly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: sqly_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/natecraddock/zf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: natecraddock\n    repo_name: zf\n    description: a commandline fuzzy finder designed for filtering filepaths\n    asset: zf-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.xz\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: macos\n    supported_envs:\n      - linux\n      - darwin\n    files:\n      - name: zf\n        src: \"zf-{{.Version}}-{{.Arch}}-{{.OS}}\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nats-io/natscli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nats-io\n    repo_name: natscli\n    description: The NATS Command Line Interface\n    asset: nats-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    files:\n      - name: nats\n        src: nats-{{trimV .Version}}-{{.OS}}-{{.Arch}}/nats\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 0.0.27\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.0.23\")\n        asset: nats-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.0.22\")\n        asset: nats-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\"< 0.0.22\")\n        asset: nats-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ned1313/terrahash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ned1313\n    repo_name: terrahash\n    description: Create and store a hash of the Terraform modules used by your configuration\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: terrahash_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: terrahash_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/neilotoole/sq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: neilotoole\n    repo_name: sq\n    description: sq data wrangler\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.14.6\")\n        asset: sq-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: sq-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.4\")\n        asset: sq-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: sq-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.11\")\n        asset: sq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.40.0\")\n        asset: sq-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.48.4\")\n        asset: sq-{{trimV .Version}}-{{.Arch}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: darwin\n            asset: sq-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: sq-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/neilpa/yajsv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: neilpa\n    repo_name: yajsv\n    description: Yet Another JSON Schema Validator [CLI]\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: yajsv.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: yajsv.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: yajsv.{{.OS}}.{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nektos/act/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nektos\n    repo_name: act\n    description: Run your GitHub Actions locally\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: act_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: act_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.22\")\n        asset: act_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.24\")\n        asset: act_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: act_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nektro/zigmod/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nektro\n    repo_name: zigmod\n    description: Zig package manager\n    version_prefix: \"r\"\n    asset: zigmod-{{.Arch}}-{{.OS}}\n    format: raw\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/neondatabase/neonctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: neondatabase\n    repo_name: neonctl\n    description: Neon CLI tool. The Neon CLI is a command-line interface that lets you manage Neon Serverless Postgres directly from the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.27.4\")\n        asset: neonctl-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: neonctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/neovim/neovim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: neovim\n    repo_name: neovim\n    description: Vim-fork focused on extensibility and usability\n    files:\n      - name: nvim\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.7\") or Version == \"v0.2.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.2.0\"\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: nvim-osx64/bin/nvim\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: nvim\n                src: Neovim/bin/nvim.exe\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: nvim-osx64/bin/nvim\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: nvim\n                src: Neovim/bin/nvim.exe\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: Version in [\"v0.3.6\", \"v0.4.0\"]\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        overrides:\n          - goos: darwin\n            files:\n              - name: nvim\n                src: nvim-osx64/bin/nvim\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        overrides:\n          - goos: darwin\n            files:\n              - name: nvim\n                src: nvim-osx64/bin/nvim\n          - goos: windows\n            format: zip\n            files:\n              - name: nvim\n                src: Neovim/bin/nvim.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            files:\n              - name: nvim\n                src: nvim-osx64/bin/nvim\n          - goos: windows\n            format: zip\n            files:\n              - name: nvim\n                src: Neovim/bin/nvim.exe\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v0.7.0\"\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            files:\n              - name: nvim\n                src: nvim-osx64/bin/nvim\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.8.3\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.9.5\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.10.3\")\n        asset: nvim-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          linux: linux64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: nvim-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: Version == \"v0.10.4\"\n        asset: nvim-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: nvim-{{.OS}}.{{.Format}}\n            format: zip\n            replacements:\n              amd64: amd64\n      - version_constraint: semver(\"<= 0.11.2\")\n        asset: nvim-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        checksum:\n          type: github_release\n          asset: shasum.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: nvim-{{.OS}}.{{.Format}}\n            format: zip\n      - version_constraint: \"true\"\n        asset: nvim-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          windows: win64\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        overrides:\n          - goos: windows\n            asset: nvim-{{.OS}}.{{.Format}}\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/neovim/neovim-releases/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: neovim\n    repo_name: neovim-releases\n    description: Unsupported Nvim releases\n    files:\n      - name: nvim\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.3\")\n        asset: nvim-linux64.{{.Format}}\n        format: tar.gz\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: nvim-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: nvim\n            src: \"{{.AssetWithoutExt}}/bin/nvim\"\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/newrelic/newrelic-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: newrelic\n    repo_name: newrelic-cli\n    description: The New Relic Command Line Interface\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: newrelic-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: newrelic\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n      386: i386\n      amd64: x86_64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: newrelic-cli_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nextest-rs/nextest/cargo-nextest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: nextest-rs/nextest/cargo-nextest\n    type: github_release\n    repo_owner: nextest-rs\n    repo_name: nextest\n    description: A next-generation test runner for Rust\n    version_prefix: \"cargo-nextest-\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: SemVer in [\"0.9.85-rc.1\", \"0.9.41-a.5\", \"0.9.49-rc.1\", \"0.9.65\", \"0.9.69\", \"0.9.71\"] or semver(\"> 0.9.59, <= 0.9.61-rc.1\") or semver(\"> 0.9.61, <= 0.9.62-a.1\") or semver(\"> 0.9.40, <= 0.9.41-a.3\")\n        no_asset: true\n      - version_constraint: Version in [\"cargo-nextest-0.9.30-rc.1\", \"cargo-nextest-0.9.41\", \"cargo-nextest-0.9.41-a.4\"]\n        asset: \"{{.Version}}-universal-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"cargo-nextest-0.9.30-rc.2\"\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: \"{{.Version}}-universal-{{.OS}}.{{.Format}}\"\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"cargo-nextest-0.9.46\"\n        asset: \"{{.Version}}-i686-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            asset: \"{{.Version}}-universal-{{.OS}}.{{.Format}}\"\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: Version == \"cargo-nextest-0.9.49-rc.2\"\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: Version == \"cargo-nextest-0.9.58-rc.1\"\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/arm64\n      - version_constraint: semver(\"<= 0.9.28\")\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            asset: \"{{.Version}}-universal-{{.OS}}.{{.Format}}\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.84\")\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: darwin\n            asset: \"{{.Version}}-universal-{{.OS}}.{{.Format}}\"\n      - version_constraint: \"true\"\n        asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: universal\n              arm64: universal\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nicarl/somafm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nicarl\n    repo_name: somafm\n    asset: somafm-{{.Version}}-{{.OS}}-{{.Arch}}\n    format: raw\n    description: CLI application to listen to SomaFM stations\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nickel-lang/nickel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nickel-lang\n    repo_name: nickel\n    aliases:\n      - name: tweag/nickel\n    description: Better configuration for less\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.2.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: nickel-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.9.1\")\n        asset: nickel-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: nickel-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nikochiko/autosaved/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nikochiko\n    repo_name: autosaved\n    description: Never worry about losing your code. Written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        asset: asdi_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: asdi\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: autosaved_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nikolaydubina/go-cover-treemap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: nikolaydubina\n    repo_name: go-cover-treemap\n    description: Go code coverage to SVG treemap\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nil0x42/dnsanity/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nil0x42\n    repo_name: dnsanity\n    description: High-performance DNS validator using template-based verification\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dnsanity-{{.OS}}-{{.Arch}}-{{.Version}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ninja-build/ninja/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ninja-build\n    repo_name: ninja\n    description: a small build system with a focus on speed\n    version_filter: not (Version startsWith \"release-\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.11.1\")\n        asset: ninja-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ninja-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: mac\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: ninja-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            goarch: arm64\n            asset: ninja-{{.OS}}{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ninxsoft/mist-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ninxsoft\n    repo_name: mist-cli\n    description: A Mac command-line tool that automatically downloads macOS Firmwares / Installers\n    asset: mist-cli.{{trimV .Version}}.{{.Format}}\n    format: pkg\n    files:\n      - name: mist\n        src: Payload/usr/local/bin/mist\n    supported_envs:\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nishanths/license/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nishanths\n    repo_name: license\n    description: Command line license text generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: license-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nmstate/nmstate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nmstate\n    repo_name: nmstate\n    description: Nmstate is a library with an accompanying command line tool that manages host networking settings in a declarative manner\n    files:\n      - name: nmstatectl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 2.2.0\") || semver(\">= 2.2.28, <= 2.2.31\") || semver(\">= 2.2.41, <= 2.2.47\") || Version == \"v2.2.52\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: nmstatectl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noahgorstein/jqp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: noahgorstein\n    repo_name: jqp\n    description: A TUI playground to experiment with jq\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: jqp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: jqp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noborus/mdviewer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: noborus\n    repo_name: mdviewer\n    description: Rendered display of markdown on terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: mdviewer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: mdviewer_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noborus/ov/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: noborus\n    repo_name: ov\n    description: Feature-rich terminal-based text viewer.  It is a so-called terminal pager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.0-beta.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.1rc1\"\n        asset: ov-{{.OS}}-10.6-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: ov-{{.OS}}-{{.Arch}}\n          - goos: windows\n            asset: ov-{{.OS}}-4.0-{{.Arch}}\n      - version_constraint: Version == \"v0.0.2\"\n        asset: oviewer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: oviewer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: oviewer_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: ov_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: ov_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: ov_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: ov_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ov_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: ov_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noborus/trdsql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: noborus\n    repo_name: trdsql\n    asset: trdsql_{{.Version}}_{{.OS}}_{{.Arch}}.zip\n    description: CLI tool that can execute SQL queries on CSV, LTSV, JSON and TBLN. Can output to various formats\n    files:\n      - name: trdsql\n        src: trdsql_{{.Version}}_{{.OS}}_{{.Arch}}/trdsql\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noborus/xlsxsql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: noborus\n    repo_name: xlsxsql\n    description: Execute SQL on xlsx file\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: xlsxsql_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: xlsxsql_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nodejs/node/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: nodejs\n    repo_name: node\n    description: |\n      Node.js JavaScript runtime\n\n      ## How to set up\n\n      Please see https://aquaproj.github.io/docs/reference/nodejs-support\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 24.10.0\")\n        url: https://nodejs.org/dist/{{.Version}}/node-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        files:\n          - name: corepack\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/corepack\n          - name: node\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/node\n          - name: npm\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/npm\n          - name: npx\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/npx\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: corepack\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/corepack.cmd\n              - name: node\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/node\n              - name: npm\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/npm.cmd\n              - name: npx\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/npx.cmd\n      - version_constraint: \"true\"\n        url: https://nodejs.org/dist/{{.Version}}/node-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          windows: win\n        files:\n          - name: node\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/node\n          - name: npm\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/npm\n          - name: npx\n            src: node-{{.Version}}-{{.OS}}-{{.Arch}}/bin/npx\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: node\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/node\n              - name: npm\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/npm.cmd\n              - name: npx\n                src: node-{{.Version}}-{{.OS}}-{{.Arch}}/npx.cmd\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nojima/httpie-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nojima\n    repo_name: httpie-go\n    description: httpie-like HTTP client written in Go\n    files:\n      - name: ht\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.0\"\n        asset: httpie-go_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        overrides:\n          - goos: windows\n            asset: httpie-go_{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: httpie-go_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: httpie-go_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/noperator/jqfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: noperator\n    repo_name: jqfmt\n    description: like gofmt, but for jq\n    path: github.com/noperator/jqfmt/cmd/jqfmt\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/norwoodj/helm-docs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: norwoodj\n    repo_name: helm-docs\n    description: A tool for automatically generating markdown documentation for helm charts\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.11.2\"\n        asset: helm-docs_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: helm-docs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: helm-docs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: helm-docs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/notaryproject/notation/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: notaryproject\n    repo_name: notation\n    description: A CLI tool to sign and verify artifacts\n    asset: notation_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: notation_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/npryce/adr-tools/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: npryce\n    repo_name: adr-tools\n    description: Command-line tools for working with Architecture Decision Records\n    files:\n      - name: adr\n        src: adr-tools-{{.Version}}/src/adr\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nucleuscloud/neosync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nucleuscloud\n    repo_name: neosync\n    description: Open source data anonymization and synthetic data orchestration for developers. Create high fidelity synthetic data and sync it across your environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.25\")\n        asset: neosync_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: neosync_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: neosync_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nuclio/nuclio/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nuclio\n    repo_name: nuclio\n    description: High-Performance Serverless event and data processing platform\n    asset: nuctl-{{.Version}}-{{.OS}}-{{.Arch}}\n    format: raw\n    complete_windows_ext: false\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/numtide/treefmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: numtide\n    repo_name: treefmt\n    description: one CLI to format your repo\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.6\")\n        asset: treefmt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: treefmt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: treefmt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: treefmt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: treefmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nushell/nushell/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nushell\n    repo_name: nushell\n    asset: nu-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A new type of shell\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n        files:\n          - name: nu\n            src: nu.exe\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.71.0\")\n    files:\n      - name: nu\n        src: nu-{{.Version}}-{{.Arch}}-{{.OS}}/nu\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: nu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/nvarner/typst-lsp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: nvarner\n    repo_name: typst-lsp\n    description: A brand-new language server for Typst, plus a VS Code extension\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\") or Version in [\"v0.5.0\", \"v0.6.0\", \"v0.6.1\", \"v0.8.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: typst-lsp-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: Version == \"v0.8.1\"\n        asset: typst-lsp\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: typst-lsp-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/o2sh/onefetch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: o2sh\n    repo_name: onefetch\n    description: Command-line Git information tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.6.0\", \"v2.10.0\", \"2.15.0\"]\n        no_asset: true\n      - version_constraint: Version in [\"v1.0.0\", \"v2.0.1\"]\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version in [\"v1.0.5\", \"v1.5.4\"]\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            asset: onefetch_{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version in [\"v1.5.5\", \"v1.6.5\"]\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v2.1.0\"\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        overrides:\n          - goos: windows\n            asset: onefetch_{{.OS}}-x86-64.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v2.2.0\"\n        asset: onefetch_{{.OS}}-x86-64.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n          - goos: darwin\n            format: tar.gz\n            asset: onefetch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v2.3.0\"\n        asset: onefetch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.5.3\")\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: onefetch_{{.OS}}_x86-64.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            asset: onefetch_{{.OS}}-{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: onefetch-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oapi-codegen/oapi-codegen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: oapi-codegen\n    repo_name: oapi-codegen\n    aliases:\n      - name: deepmap/oapi-codegen\n    description: Generate Go client and server boilerplate from OpenAPI 3 specifications\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 2.0.0\")\n        path: github.com/deepmap/oapi-codegen/cmd/oapi-codegen\n      - version_constraint: semver(\"<= 2.2.0\")\n        path: github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen\n      - version_constraint: \"true\"\n        path: github.com/oapi-codegen/oapi-codegen/v{{(semver .Version).Major}}/cmd/oapi-codegen\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oberblastmeister/trashy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oberblastmeister\n    repo_name: trashy\n    description: A cli system trash manager, alternative to rm and trash-cli\n    asset: trash-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: trash\n    overrides:\n      - goos: windows\n        format: raw\n        asset: trash-{{.Arch}}-{{.OS}}\n    replacements:\n      amd64: x86_64\n      linux: unknown-linux-gnu\n      windows: pc-windows-msvc\n    supported_envs:\n      - linux/amd64\n      - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/octohelm/cuemod/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: octohelm\n    repo_name: cuemod\n    description: experimental cuelang mod tool\n    supported_envs:\n      - linux\n      - darwin\n    asset: cuem_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: cuem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/odanado/git-pr-release-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: odanado\n    repo_name: git-pr-release-go\n    description: git-pr-release-go streamlines development by automating \"Release Pull Requests\" on GitHub\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: git-pr-release-go_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: git-pr-release-go_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/odigos-io/odigos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: odigos-io\n    repo_name: odigos\n    description: Distributed tracing without code changes.  Instantly monitor any application using OpenTelemetry and eBPF\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.6\"\n        asset: odigos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version in [\"v1.0.1-greatwall\", \"odiglet/v1.0.122\"] or semver(\"<= 0.1.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: odigos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.54\")\n        asset: odigos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.63\")\n        asset: odigos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ogen-go/ogen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: ogen-go\n    repo_name: ogen\n    description: OpenAPI v3 code generator for go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        path: github.com/ogen-go/ogen/cmd/ogen\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ogham/dog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ogham\n    repo_name: dog\n    description: A command-line DNS client\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: dog-{{.Version}}-{{.Arch}}-{{.OS}}.zip\n    replacements:\n      amd64: x86_64\n      windows: pc-windows-msvc\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n    files:\n      - name: dog\n        src: bin/dog\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ogham/exa/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ogham\n    repo_name: exa\n    asset: exa-{{.OS}}-{{.Arch}}-musl-{{.Version}}.{{.Format}}\n    format: zip\n    description: A modern replacement for ‘ls’\n    replacements:\n      amd64: x86_64\n      darwin: macos\n    overrides:\n      - goos: darwin\n        asset: exa-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    files:\n      - name: exa\n        src: bin/exa\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ohkrab/krab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ohkrab\n    repo_name: krab\n    description: Krab is a migration and automation tool for PostgreSQL based on HCL syntax\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.2.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: krab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: krab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: krab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: krab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oknozor/toml-bombadil/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oknozor\n    repo_name: toml-bombadil\n    description: A dotfile manager with templating\n    files:\n      - name: bombadil\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"3.1.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: bombadil-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.0.0\")\n        asset: bombadil-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 4.1.0\")\n        asset: bombadil--{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: bombadil-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: bombadil\n            src: \"{{.Arch}}-{{.OS}}/bombadil\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/okta/okta-aws-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: okta\n    repo_name: okta-aws-cli\n    description: A CLI for having Okta as the IdP for AWS CLI operations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.4\"\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}_signed.{{.Format}}\n            checksum:\n              enabled: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.3.0\"\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.2.2\"\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v2.0.0\"\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: okta-aws-cli\n            src: okta-aws-cli_{{.Version}}\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: okta-aws-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n          - windows/arm64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/okteto/okteto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: okteto\n    repo_name: okteto\n    description: Develop your applications directly in your Kubernetes Cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.6\")\n        asset: cnd-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.7\")\n        asset: okteto-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.4\")\n        asset: okteto-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.10.5\")\n        asset: okteto-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: okteto\n      - version_constraint: \"true\"\n        asset: okteto-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            asset: okteto\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oligot/go-mod-upgrade/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oligot\n    repo_name: go-mod-upgrade\n    description: Update outdated Go dependencies interactively\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.6.0\"\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: go-mod-upgrade_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: go-mod-upgrade_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ollama/ollama/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ollama\n    repo_name: ollama\n    description: Get up and running with Llama 3.1, Mistral, Gemma 2, and other large language models\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.12\")\n        asset: ollama-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.0.21\")\n        asset: ollama-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.29\")\n        asset: ollama-{{.OS}}-{{.Arch}}\n        format: raw\n        overrides:\n          - goos: darwin\n            asset: ollama-{{.OS}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.32\")\n        asset: ollama-{{.OS}}-{{.Arch}}\n        windows_arm_emulation: true\n        format: raw\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ollama-{{.OS}}\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: ollama-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ollama-{{.OS}}\n          - goos: windows\n            asset: ollama-{{.OS}}-{{.Arch}}.{{.Format}}\n            format: zip\n      - version_constraint: semver(\"<= 0.5.7\")\n        asset: ollama-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tgz\n            files:\n              - name: ollama\n                src: bin/ollama\n          - goos: darwin\n            asset: ollama-{{.OS}}\n            format: raw\n      - version_constraint: semver(\"<= 0.13.5\")\n        asset: ollama-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tgz\n            files:\n              - name: ollama\n                src: bin/ollama\n          - goos: darwin\n            asset: ollama-{{.OS}}.{{.Format}}\n            format: tgz\n      - version_constraint: \"true\"\n        asset: ollama-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: ollama-{{.OS}}.{{.Format}}\n            format: tgz\n          - goos: linux\n            format: tar.zst\n            files:\n              - name: ollama\n                src: bin/ollama\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/omegion/ssh-manager/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: omegion\n    repo_name: ssh-manager\n    description: SSH Key Manager for 1Password, Bitwarden and AWS S3\n    asset: ssh-manager-{{.OS}}-{{.Arch}}\n    format: raw\n    complete_windows_ext: false\n    version_constraint: semver(\">= 0.13.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.11.0\")\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"< 0.11.0\")\n        supported_envs:\n          - linux/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/omissis/go-jsonschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: omissis\n    repo_name: go-jsonschema\n    description: A tool to generate Go data types from JSON Schema definitions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.13.1-rc.0\", \"v0.14.0-rc.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: gojsonschema-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: go-jsonschema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: go-jsonschema_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/omrikiei/ktunnel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: omrikiei\n    repo_name: ktunnel\n    asset: ktunnel_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: A cli that exposes your local resources to kubernetes\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    files:\n      - name: kubectl-tunnel\n        src: ktunnel\n      - name: ktunnel\n        src: ktunnel\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/one2nc/cloudlens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: one2nc\n    repo_name: cloudlens\n    description: k9s like CLI for AWS and GCP\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cloudlens_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: cloudlens_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/open-policy-agent/conftest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: open-policy-agent\n    repo_name: conftest\n    description: Write tests against structured configuration data using the Open Policy Agent Rego query language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.44.0\"\n        no_asset: true\n      - version_constraint: Version == \"0.9.1\"\n        asset: conftest_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: conftest_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.27.0\")\n        asset: conftest_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: conftest_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/open-policy-agent/gatekeeper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: open-policy-agent\n    repo_name: gatekeeper\n    description: \"Gatekeeper - Policy Controller for Kubernetes\"\n    files:\n      - name: gator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v3.12.0-rc.0\" || semver(\"<= 3.7.0-beta.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gator-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: gator\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/open-policy-agent/opa/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: open-policy-agent\n    repo_name: opa\n    description: Open Policy Agent (OPA) is an open source, general-purpose policy engine\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.5.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.28.0\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.29.3\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: opa_{{.OS}}_{{.Arch}}_static\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.36.0\"\n        asset: opa_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: opa_{{.OS}}_{{.Arch}}_static\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: Version == \"v0.36.1\"\n        asset: opa_{{.OS}}_{{.Arch}}_static\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: opa_{{.OS}}_{{.Arch}}.exe\n          - goos: darwin\n            goarch: amd64\n            asset: opa_{{.OS}}_{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: opa_{{.OS}}_{{.Arch}}_static\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: opa_{{.OS}}_{{.Arch}}.exe\n          - goos: darwin\n            goarch: amd64\n            asset: opa_{{.OS}}_{{.Arch}}\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/open-policy-agent/regal/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: open-policy-agent\n    repo_name: regal\n    aliases:\n      - name: StyraInc/regal\n      - name: StyraOSS/regal\n    description: Regal is a linter for Rego, with the goal of making your Rego magnificent\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: regal_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openai/codex/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openai\n    repo_name: codex\n    description: Lightweight coding agent that runs in your terminal\n    version_prefix: rust-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: codex-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zst\n        files:\n          - name: codex\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: codex-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zst\n        windows_arm_emulation: true\n        files:\n          - name: codex\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            asset: codex-{{.Arch}}-{{.OS}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openbao/openbao/bao/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: openbao/openbao/bao\n    type: github_release\n    repo_owner: openbao\n    repo_name: openbao\n    description: OpenBao exists to provide a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.0.0-alpha20240329\"\n        asset: openbao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v2.0.0-beta20240618\"\n        asset: bao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.1.1\")\n        asset: bao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.4.4\")\n        asset: bao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/openbao/openbao/releases/download/{{.Version}}/checksums-{{.OS}}.txt.pem\n              - --certificate-identity-regexp\n              - '^https://github\\.com/openbao/openbao/\\.github/workflows/release\\.yml@refs/tags/.*$'\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/openbao/openbao/releases/download/{{.Version}}/checksums-{{.OS}}.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v2.5.0-beta20251125\"\n        asset: bao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: bao_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums-{{.OS}}.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - '^https://github\\.com/openbao/openbao/\\.github/workflows/release\\.yml@refs/tags/.*$'\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n            bundle:\n              type: github_release\n              asset: checksums-{{.OS}}.txt.sigstore.json\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openclarity/kubeclarity/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openclarity\n    repo_name: kubeclarity\n    description: KubeClarity is a tool for detection and management of Software Bill Of Materials (SBOM) and vulnerabilities of container images and filesystems\n    asset: kubeclarity-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: kubeclarity-cli\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 2.1.0\")\n    version_overrides:\n      - version_constraint: semver(\"= 2.0.0\")\n        asset: cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: kubeclarity-cli\n            src: cli\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openclarity/vmclarity/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openclarity\n    repo_name: vmclarity\n    description: VMClarity is an open source tool for agentless detection and management of Virtual Machine Software Bill Of Materials (SBOM) and security threats such as vulnerabilities, exploits, malware, rootkits, misconfigurations and leaked secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: vmclarity-cli-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vmclarity-cli\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: vmclarity-cli-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vmclarity-cli\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/opencontainers/runc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: opencontainers\n    repo_name: runc\n    description: CLI tool for spawning and running containers according to the OCI specification\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: runc.{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n        checksum:\n          type: github_release\n          asset: runc.sha256sum\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openfaas/faas-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openfaas\n    repo_name: faas-cli\n    format: raw\n    description: Official CLI for OpenFaaS\n    asset: faas-cli-{{.Arch}}\n    overrides:\n      - goos: darwin\n        asset: faas-cli-darwin\n      - goarch: amd64\n        asset: faas-cli\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openfga/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openfga\n    repo_name: cli\n    description: A cross-platform CLI to interact with an OpenFGA server\n    files:\n      - name: fga\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0-beta1\"\n        asset: openfga-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/openfga/cli/.github/workflows/main.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.sig\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: fga_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/openfga/cli/.github/workflows/main.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.sig\n      - version_constraint: \"true\"\n        asset: fga_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/openfga/cli/.github/workflows/main.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/openfga/cli/releases/download/{{.Version}}/checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: fga.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/opengrep/opengrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: opengrep\n    repo_name: opengrep\n    description: Static code analysis engine to find security issues in code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: opengrep_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            asset: opengrep_many{{.OS}}_x86\n          - goos: windows\n            asset: opengrep_{{.OS}}_x86\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.1.4\")\n        asset: opengrep_many{{.OS}}_x86\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: opengrep_many{{.OS}}_{{.Arch}}\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: opengrep_{{.OS}}_{{.Arch}}\n          - goos: windows\n            asset: opengrep_{{.OS}}_x86\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: opengrep_{{.OS}}_x86\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: opengrep_many{{.OS}}_x86\n          - goos: linux\n            goarch: arm64\n            asset: opengrep_many{{.OS}}_{{.Arch}}\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            goarch: arm64\n            asset: opengrep_{{.OS}}_{{.Arch}}\n      - version_constraint: \"true\"\n        asset: opengrep_{{.OS}}_x86\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: opengrep_many{{.OS}}_x86\n          - goos: linux\n            goarch: arm64\n            asset: opengrep_many{{.OS}}_{{.Arch}}\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            goarch: arm64\n            asset: opengrep_{{.OS}}_{{.Arch}}\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/opengrep/opengrep/releases/download/{{.Version}}/{{.Asset}}.cert\n            - --signature\n            - https://github.com/opengrep/opengrep/releases/download/{{.Version}}/{{.Asset}}.sig\n            - --certificate-identity-regexp\n            - https://github.com/opengrep/opengrep.+\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openshift/osdctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openshift\n    repo_name: osdctl\n    description: CLI for the OSD utilities\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: osdctl-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: osdctl-{{.OS}}-{{.Version}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.4.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.4\")\n        asset: osdctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: osdctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: osdctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openshift/rosa/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openshift\n    repo_name: rosa\n    version_filter: not (Version matches \"rc[0-9]+$\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.19\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: moactl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: moactl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: '{{trimSuffix \".exe\" .Asset}}.sha256'\n              algorithm: sha256\n      - version_constraint: semver(\"<= 1.2.26\")\n        asset: rosa-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: '{{trimSuffix \".exe\" .Asset}}.sha256'\n              algorithm: sha256\n      - version_constraint: semver(\"<= 1.2.39\")\n        asset: rosa-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: github_release\n              asset: '{{trimSuffix \".exe\" .Asset}}.sha256'\n              algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rosa_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: rosa_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openshift-online/ocm-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openshift-online\n    repo_name: ocm-cli\n    description: CLI for the Red Hat OpenShift Cluster Manager\n    files:\n      - name: ocm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.57\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.30\")\n        asset: ocm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.58\")\n        asset: ocm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.65\")\n        asset: ocm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ocm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/opentofu/opentofu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: opentofu\n    repo_name: opentofu\n    description: OpenTofu lets you declaratively manage your cloud infrastructure\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.0-beta4\")\n        asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: tofu\n        checksum:\n          type: github_release\n          asset: tofu_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.pem\n              - --certificate-identity\n              - https://github.com/opentofu/opentofu/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.sig\n      - version_constraint: semver(\"<= 1.6.0-rc1\")\n        asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: tofu\n        checksum:\n          type: github_release\n          asset: tofu_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/opentofu/opentofu/\\\\.github/workflows/release\\\\.yml@refs/heads/(main|v\\\\d+\\\\..+)$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.sig\n      - version_constraint: semver(\"<= 1.6.2\")\n        asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: tofu\n        checksum:\n          type: github_release\n          asset: tofu_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/opentofu/opentofu/\\\\.github/workflows/release\\\\.yml@refs/heads/(main|v\\\\d+\\\\..+)$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.sig\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --certificate-identity-regexp\n            - \"^https://github\\\\.com/opentofu/opentofu/\\\\.github/workflows/release\\\\.yml@refs/heads/(main|v\\\\d+\\\\..+)$\"\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --signature\n            - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/{{.Asset}}.sig\n      - version_constraint: \"true\"\n        asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: tofu\n        checksum:\n          type: github_release\n          asset: tofu_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/opentofu/opentofu/\\\\.github/workflows/release\\\\.yml@refs/heads/(main|v\\\\d+\\\\..+)$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/tofu_{{trimV .Version}}_SHA256SUMS.sig\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --certificate-identity-regexp\n            - \"^https://github\\\\.com/opentofu/opentofu/\\\\.github/workflows/release\\\\.yml@refs/heads/(main|v\\\\d+\\\\..+)$\"\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --signature\n            - https://github.com/opentofu/opentofu/releases/download/{{.Version}}/{{.Asset}}.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/opentofu/tofu-ls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: opentofu\n    repo_name: tofu-ls\n    description: OpenTofu Language Server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1-alpha1\"\n        asset: tofu-ls_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tofu-ls_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.1-alpha2\"\n        asset: tofu-ls_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tofu-ls_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tofu-ls_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tofu-ls_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openvex/vexctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openvex\n    repo_name: vexctl\n    description: A  tool to create, transform and attest VEX metadata\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.5\")\n        asset: vexctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vex_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/openvex/vexctl/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/openvex/vexctl/releases/download/{{.Version}}/vex_checksums.txt.sig\n              - --certificate\n              - https://github.com/openvex/vexctl/releases/download/{{.Version}}/vex_checksums.txt.pem\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/openvex/vexctl/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/openvex/vexctl/releases/download/{{.Version}}/{{.Asset}}.sig\n            - --certificate\n            - https://github.com/openvex/vexctl/releases/download/{{.Version}}/{{.Asset}}.pem\n      - version_constraint: \"true\"\n        asset: vexctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: vexctl_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/openvex/vexctl/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/openvex/vexctl/releases/download/{{.Version}}/vexctl_checksums.txt.sig\n              - --certificate\n              - https://github.com/openvex/vexctl/releases/download/{{.Version}}/vexctl_checksums.txt.pem\n        cosign:\n          opts:\n            - --certificate-identity-regexp\n            - \"https://github\\\\.com/openvex/vexctl/\\\\.github/workflows/release\\\\.yaml@.*\"\n            - --certificate-oidc-issuer\n            - \"https://token.actions.githubusercontent.com\"\n            - --signature\n            - https://github.com/openvex/vexctl/releases/download/{{.Version}}/{{.Asset}}.sig\n            - --certificate\n            - https://github.com/openvex/vexctl/releases/download/{{.Version}}/{{.Asset}}.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/openziti/zrok/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: openziti\n    repo_name: zrok\n    description: Geo-scale, next-generation peer-to-peer sharing platform built on top of OpenZiti\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.10\")\n        asset: zrok_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: zrok_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: zrok_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha1\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.48\") or (Version startsWith \"v1.0.0-rc\")\n        asset: zrok_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha1\n      # TODO support GitHub Artifact Attestation\n      # https://github.com/openziti/zrok/releases/tag/v0.4.49\n      # > CHANGE: Release binary and text artifacts are now accompanied by provenance attestations\n      # github_artifact_attestations:\n      #   signer_workflow:\n      - version_constraint: \"true\"\n        asset: zrok_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.sha256.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/operator-framework/operator-registry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: operator-framework\n    repo_name: operator-registry\n    description: Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to Operator Lifecycle Manager\n    files:\n      - name: opm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.10.0\", \"v1.16.0\"]\n        no_asset: true\n      - version_constraint: Version in [\"v1.7.0\", \"v1.11.0\", \"v1.12.4\"]\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version in [\"v1.11.1\", \"v1.12.3\", \"v1.15.0\"]\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.14.3\"\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.5.6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.9.0\")\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.12.2\")\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.14.2\")\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.19.5\")\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}-{{.Arch}}-opm\"\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/operator-framework/operator-sdk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: operator-framework\n    repo_name: operator-sdk\n    description: SDK for building Kubernetes applications. Provides high level APIs, useful abstractions, and project scaffolding\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.6\") or Version == \"v1.34.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: operator-sdk-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: operator-sdk-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.18.1\")\n        asset: operator-sdk_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: operator-sdk_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oppiliappan/dijo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oppiliappan\n    repo_name: dijo\n    aliases:\n      - name: nerdypepper/dijo\n    description: scriptable, curses-based, digital habit tracker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: dijo-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.2.1\"\n        asset: dijo-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.2.2-alpha\"\n        asset: dijo-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: dijo-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/optiv/Mangle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: optiv\n    repo_name: Mangle\n    description: Mangle is a tool that manipulates aspects of compiled executables (.exe or DLL) to avoid detection from EDRs\n    files:\n      - name: mangle\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: Mangle_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: Mangle_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orangekame3/stree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orangekame3\n    repo_name: stree\n    description: Directory trees of AWS S3 Bucket\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.12\")\n        asset: stree_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.0.13\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: stree_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orangekame3/viff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orangekame3\n    repo_name: viff\n    description: Visual Diff Viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.8\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: viff_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: viff_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: viff_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oras-project/oras/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oras-project\n    repo_name: oras\n    asset: oras_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: ORAS CLI\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: oras_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orf/gping/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orf\n    repo_name: gping\n    description: Ping, but with a graph\n    version_filter: |\n      not (Version startsWith \"pinger-\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: gping-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.2.1\"\n        asset: gping-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: Linux\n          - goos: linux\n            goarch: arm64\n            asset: gping-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-musl\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.18.0\")\n        version_prefix: gping-\n        asset: gping-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          windows: Windows\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: Linux\n          - goos: linux\n            goarch: arm64\n            asset: gping-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-musl\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        version_prefix: gping-\n        asset: gping-{{.OS}}-gnu-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: darwin\n            asset: gping-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: gping-{{.OS}}-msvc-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orhun/git-cliff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orhun\n    repo_name: git-cliff\n    description: A highly customizable Changelog Generator that follows Conventional Commit specifications\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.0-beta.2\"\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.0-beta.3\"\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n            asset: git-cliff--{{.Arch}}-{{.OS}}.{{.Format}}\n            files:\n              - name: git-cliff\n                src: git-cliff-/git-cliff.exe\n            checksum:\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.0-rc.2\"\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.0-rc.1\")\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.0-rc.5\")\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: git-cliff-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: git-cliff\n            src: git-cliff-{{trimV .Version}}/git-cliff\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha512\"\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orisano/dlayer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orisano\n    repo_name: dlayer\n    description: dlayer is docker layer analyzer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: dlayer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dlayer_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/orlangure/gocovsh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: orlangure\n    repo_name: gocovsh\n    description: \"Go Coverage in your terminal: a tool for exploring Go Coverage reports from the command line\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gocovsh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/orlangure/gocovsh/\\\\.github/workflows/.+\\\\.ya?ml@refs/tags/\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/orlangure/gocovsh/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/orlangure/gocovsh/releases/download/{{.Version}}/checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ory/hydra/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ory\n    repo_name: hydra\n    asset: hydra_{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: OpenID Certified OpenID Connect and OAuth Provider written in Go - cloud native, security-first, open source API security for your infrastructure. SDKs for any language. Works with Hardware Security Modules. Compatible with MITREid\n    replacements:\n      amd64: 64bit\n      darwin: macOS\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ossf/scorecard/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ossf\n    repo_name: scorecard\n    description: OpenSSF Scorecard - Security health metrics for Open Source\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\") || Version == \"v4.9.0\"\n        no_asset: true\n      - version_constraint: Version == \"v1.1.0\"\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: scorecard_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 2.1.2\")\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: scorecard_{{trimV .Version}}_checksums.txt\n          algorithm: sha512\n      - version_constraint: Version == \"v2.1.3\"\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: scorecard_{{trimV .Version}}_checksums.txt\n          algorithm: sha512\n      - version_constraint: semver(\"<= 3.0.1\")\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: scorecard_{{trimV .Version}}_checksums.txt\n          algorithm: sha512\n      - version_constraint: semver(\"<= 4.4.0\")\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: scorecard\n            src: scorecard-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: scorecard_checksums.txt\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            goarch: amd64\n            checksum:\n              enabled: false\n      - version_constraint: Version == \"v4.5.0\"\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: scorecard\n            src: scorecard-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: scorecard_checksums.txt\n          algorithm: sha512\n        supported_envs:\n          - linux/arm64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 4.8.0\")\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: scorecard\n            src: scorecard-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: scorecard_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.0.0\")\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: scorecard\n            src: scorecard-{{.OS}}-{{.Arch}}\n        checksum:\n          type: github_release\n          asset: scorecard_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: scorecard_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: scorecard_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/osteele/gojekyll/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: osteele\n    repo_name: gojekyll\n    description: A fast Go implementation of the Jekyll blogging engine\n    asset: gojekyll_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64v1\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.2.8\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.2.7\")\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\">= 0.2.3\")\n        asset: gojekyll_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides:\n          - goos: linux\n            asset: gojekyll_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n      - version_constraint: semver(\"< 0.2.3\")\n        asset: gojekyll_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides:\n          - goos: darwin\n            asset: gojekyll_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ouch-org/ouch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ouch-org\n    repo_name: ouch\n    description: Painless compression and decompression in the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.4\"\n        asset: ouch\n        format: raw\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: darwin\n            asset: ouch-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"0.1.5\"\n        asset: ouch-{{.OS}}-x86-64-musl\n        format: raw\n        replacements:\n          darwin: macOS\n        overrides:\n          - goos: darwin\n            asset: ouch-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"0.1.6\"\n        asset: ouch-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            asset: ouch-{{.Arch}}-{{.OS}}-musl\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.2.0\"\n        asset: ouch-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            asset: ouch-{{.Arch}}-{{.OS}}-musl\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: ouch-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            asset: ouch-{{.Arch}}-{{.OS}}-musl\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: ouch-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ouch\n            src: \"{{.AssetWithoutExt}}/ouch\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ouch-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: ouch\n            src: \"{{.AssetWithoutExt}}/ouch\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/out-of-cheese-error/the-way/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: out-of-cheese-error\n    repo_name: the-way\n    description: A code snippets manager for your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.1-osx\"\n        asset: the-way-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: the-way-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: the-way-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: the-way-{{.OS}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oven-sh/bun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oven-sh\n    repo_name: bun\n    aliases:\n      - name: Jarred-Sumner/bun\n    description: Incredibly fast JavaScript runtime, bundler, transpiler and package manager – all in one\n    files:\n      - name: bun\n      - name: bunx\n    version_prefix: bun-v\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: bun-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: bun\n            src: \"{{.AssetWithoutExt}}/bun\"\n          - name: bunx\n            src: \"{{.AssetWithoutExt}}/bun\"\n            link: bunx\n      - version_constraint: semver(\"<= 1.0.36\")\n        asset: bun-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x64\n          arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: bun\n            src: \"{{.AssetWithoutExt}}/bun\"\n          - name: bunx\n            src: \"{{.AssetWithoutExt}}/bun\"\n            link: bunx\n      - version_constraint: \"true\"\n        asset: bun-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: bun\n            src: \"{{.AssetWithoutExt}}/bun\"\n          - name: bunx\n            src: \"{{.AssetWithoutExt}}/bun\"\n            link: bunx\n        overrides:\n          - goos: linux\n            asset: bun-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            replacements: {}\n        replacements:\n          amd64: x64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ovh/venom/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ovh\n    repo_name: venom\n    description: \"Manage and run your integration tests with efficiency - Venom run executors (script, HTTP Request, web, imap, etc... ) and assertions\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.0\"\n        asset: venom-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.21.1\"\n        asset: venom.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: venom-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: venom.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: semver(\"<= 1.1.0-beta.2\")\n        asset: venom.{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: venom.{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/owenlamont/ryl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: owenlamont\n    repo_name: ryl\n    description: Personal project to learn Rust and create a yaml linter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: semver(\"< 0.3.2\")\n        asset: ryl-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ryl-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: owenlamont/ryl/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/owenrumney/squealer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: owenrumney\n    repo_name: squealer\n    description: Telling tales on you for leaking secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.20\", \"v1.2.3\", \"v1.2.7\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.19\")\n        asset: squealer.{{.OS}}.{{.Arch}}.{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.22\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.28\")\n        asset: squealer.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: squealer_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: squealer.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: squealer_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: squealer.{{.OS}}.{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: squealer_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/owenthereal/upterm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: owenthereal\n    repo_name: upterm\n    asset: upterm_{{.OS}}_{{.Arch}}.tar.gz\n    description: Secure Terminal Sharing\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oxc-project/oxc/oxlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: oxc-project/oxc/oxlint\n    repo_owner: oxc-project\n    repo_name: oxc\n    description: The linter for oxc\n    version_constraint: \"false\"\n    version_prefix: oxlint_v\n    version_overrides:\n      - version_constraint: semver(\">= 1.17.0\")\n        error_message: |\n          aqua can't support oxlint 1.17.0 or later. \n          > Newer versions of Oxlint require node.js. There isn’t a native executable alternative anymore.\n          https://github.com/oxc-project/oxc/discussions/14452#discussioncomment-14631344\n      - version_constraint: semver(\"<= 0.0.8\")\n        asset: oxlint-{{.OS}}-{{.Arch}}\n        files:\n          - name: oxlint\n            src: oxlint-{{.OS}}-{{.Arch}}\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: Version == \"oxlint_v0.0.9\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.19\")\n        asset: oxlint-{{.OS}}-{{.Arch}}\n        files:\n          - name: oxlint\n            src: oxlint-{{.OS}}-{{.Arch}}\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: Version == \"oxlint_v0.1.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: oxlint-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: oxlint\n            src: oxlint-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: \"true\"\n        asset: oxlint-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: oxlint\n            src: oxlint-{{.OS}}-{{.Arch}}\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: linux\n            asset: oxlint-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n            files:\n              - name: oxlint\n                src: oxlint-{{.OS}}-{{.Arch}}-gnu\n        replacements:\n          amd64: x64\n          windows: win32\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/oxipng/oxipng/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: oxipng\n    repo_name: oxipng\n    aliases:\n      - name: shssoichiro/oxipng\n    description: Multithreaded PNG optimizer written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.11.0\", \"v0.14.0\"]\n        asset: oxipng-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.14.3\"\n        asset: oxipng-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.10.0\") || Version in [\"v0.17.0\", \"v2.2.1\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: oxipng-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.0\")\n        asset: oxipng-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v3.0.1\"\n        asset: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: oxipng\n            src: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}/oxipng\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            asset: oxipng-{{trimV .Version}}-i686-{{.OS}}.{{.Format}}\n            files:\n              - name: oxipng\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 8.0.0\")\n        asset: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: oxipng\n            src: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}/oxipng\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: oxipng\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: oxipng\n            src: oxipng-{{trimV .Version}}-{{.Arch}}-{{.OS}}/oxipng\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ozankasikci/dockerfile-generator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ozankasikci\n    repo_name: dockerfile-generator\n    description: dfg - Generates dockerfiles based on various input channels\n    rosetta2: true\n    format: raw\n    asset: dfg_{{.Version}}_{{.OS}}_{{.Arch}}\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: dfg\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pacedotdev/oto/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pacedotdev\n    repo_name: oto\n    description: Go driven rpc code generation tool for right now\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.1\")\n        asset: oto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.14.2\")\n        asset: oto_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: oto_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pachyderm/pachyderm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pachyderm\n    repo_name: pachyderm\n    asset: pachctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Data-Centric Pipelines and Data Versioning\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: pachctl\n        src: pachctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}/pachctl\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/palantir/conjure-rust/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: palantir\n    repo_name: conjure-rust\n    description: Conjure support for Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: conjure-rust\n            src: conjure-rust-{{.Version}}/bin/conjure-rust\n        url: https://repo.maven.apache.org/maven2/com/palantir/conjure/rust/conjure-rust/{{.Version}}/conjure-rust-{{.Version}}.{{.Format}}\n        format: tgz\n        replacements:\n          arm64: aarch64\n        checksum:\n          type: http\n          url: https://repo.maven.apache.org/maven2/com/palantir/conjure/rust/conjure-rust/{{.Version}}/conjure-rust-{{.Version}}.{{.Format}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/palantir/conjure-typescript/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: palantir\n    repo_name: conjure-typescript\n    description: Conjure generator for TypeScript clients\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: conjure-typescript\n            src: conjure-typescript-{{.Version}}/bin/conjure-typescript\n        url: https://repo.maven.apache.org/maven2/com/palantir/conjure/typescript/conjure-typescript/{{.Version}}/conjure-typescript-{{.Version}}.{{.Format}}\n        format: tgz\n        checksum:\n          type: http\n          url: https://repo.maven.apache.org/maven2/com/palantir/conjure/typescript/conjure-typescript/{{.Version}}/conjure-typescript-{{.Version}}.{{.Format}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pamburus/hl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pamburus\n    repo_name: hl\n    description: A fast and powerful log viewer and processor that translates JSON or logfmt logs into a pretty human-readable format\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.29.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.6.2\"\n        asset: hl-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.7\")\n        asset: hl-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.14\")\n        asset: hl-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.5\")\n        asset: hl-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: hl-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.15.2\")\n        asset: hl-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: hl-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: hl-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hl-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: hl-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: hl-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pan-net-security/kcount/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pan-net-security\n    repo_name: kcount\n    asset: kcount_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Count Kubernetes objects across namespaces and clusters\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/particledecay/kconf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: particledecay\n    repo_name: kconf\n    description: Manage multiple kubeconfigs easily\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: kconf-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.3.4\"\n        asset: kconf-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        # src is program\n        files:\n          - name: kconf\n            src: program\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      # v1.4.0 chore(build): build release binaries with lowercase OS\n      - version_constraint: Version == \"v1.4.0\"\n        asset: kconf-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        # src is program\n        files:\n          - name: kconf\n            src: program\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.9.0\")\n        asset: kconf-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.12.0\")\n        asset: kconf-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kconf-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pavius/impi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pavius\n    repo_name: impi\n    description: Verify proper golang import directives, beyond the capability of gofmt and goimports\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: impi-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pcasteran/terraform-graph-beautifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pcasteran\n    repo_name: terraform-graph-beautifier\n    description: Terraform graph beautifier\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: terraform-graph-beautifier_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: terraform-graph-beautifier_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/peak/s5cmd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: peak\n    repo_name: s5cmd\n    description: Parallel S3 and local filesystem execution tool\n    replacements:\n      darwin: macOS\n      linux: Linux\n      windows: Windows\n      386: 32bit\n      amd64: 64bit\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    asset: s5cmd_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n    checksum:\n      type: github_release\n      asset: s5cmd_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/peco/peco/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: peco\n    repo_name: peco\n    description: Simplistic interactive filtering tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.5\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.9\")\n        asset: peco_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: peco\n            src: peco_{{.OS}}_{{.Arch}}/peco\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: peco\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.5\")\n        asset: peco_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: peco\n            src: peco_{{.OS}}_{{.Arch}}/peco\n        replacements:\n          arm64: arm\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: peco_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: peco\n            src: peco_{{.OS}}_{{.Arch}}/peco\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.8\")\n        asset: peco_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: peco\n            src: peco_{{.OS}}_{{.Arch}}/peco\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.5.11\")\n        asset: peco_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: peco\n            src: peco_{{.OS}}_{{.Arch}}/peco\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: \"true\"\n        asset: peco_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pemistahl/grex/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pemistahl\n    repo_name: grex\n    asset: grex-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A command-line tool and library for generating regular expressions from user-provided test cases\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pen-lang/pen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pen-lang\n    repo_name: pen\n    description: The parallel, concurrent, and functional programming language for scalable software development\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: pen-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: pen\n            src: bin/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.9\")\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: pen\n            src: bin/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.10\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.1.11\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.1.12\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.1.14\")\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.15\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.23\")\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.25\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.6\")\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.6.7\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: Version == \"v0.6.8\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: pen\n            src: target/release/pen\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: pen-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: pen\n            src: target/release/pen\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/peripheryapp/periphery/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: peripheryapp\n    repo_name: periphery\n    description: A tool to identify unused code in Swift projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.13.0\")\n        asset: periphery-v{{.Version}}.zip\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: periphery-{{.Version}}.zip\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/perses/perses/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: perses\n    repo_name: perses\n    description: \"The CNCF sandbox for observability visualisation. Already supports Prometheus, Tempo, Loki and Pyroscope - more data sources to come\"\n    files:\n      - name: perses\n      - name: percli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.2.0\", \"v0.6.0\", \"v0.9.0\", \"v0.21.0\", \"v0.42.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: perses_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: perses_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.29.1\")\n        asset: perses_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: perses_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: perses_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: perses_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pete911/certinfo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pete911\n    repo_name: certinfo\n    description: print x509 certificate info\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.4\")\n        asset: certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.17\")\n        asset: certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.20\")\n        asset: certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: certinfo_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pete911/jwt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pete911\n    repo_name: jwt\n    description: jwt cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: jwt_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/peteretelej/tree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: peteretelej\n    repo_name: tree\n    description: tree is an open-source cross-platform tree cli implemented in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.1\"\n        asset: tree_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: tree_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            asset: tree_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: 64bit\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tree-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            format: zip\n            replacements:\n              amd64: 64bit\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pfnet-research/git-ghost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pfnet-research\n    repo_name: git-ghost\n    description: Synchronize your working directory efficiently to a remote place without committing the changes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: git-ghost-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: git-ghost_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: git-ghost_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pglet/pglet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pglet\n    repo_name: pglet\n    description: \"Pglet - build internal web apps quickly in the language you already know\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.15\")\n        asset: pglet-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pglet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.6\")\n        asset: pglet-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pglet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: pglet-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pglet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pgrok/pgrok/pgrok/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: pgrok/pgrok/pgrok\n    type: github_release\n    repo_owner: pgrok\n    repo_name: pgrok\n    description: (Client) Poor man's ngrok - a multi-tenant HTTP reverse tunnel solution through SSH remote port forwarding\n    asset: pgrok_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: checksums.pgrok.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pgrok/pgrok/pgrokd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: pgrok/pgrok/pgrokd\n    type: github_release\n    repo_owner: pgrok\n    repo_name: pgrok\n    description: (Server) Poor man's ngrok - a multi-tenant HTTP reverse tunnel solution through SSH remote port forwarding\n    asset: pgrokd_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: pgrokd\n    checksum:\n      type: github_release\n      asset: checksums.pgrokd.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/phiresky/ripgrep-all/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: phiresky\n    repo_name: ripgrep-all\n    description: \"rga: ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, etc\"\n    version_filter: not (Version contains \"v1.0.0\")\n    files:\n      - name: rga\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.8\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.5\"\n        asset: ripgrep_all-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rga\n            src: \"{{.AssetWithoutExt}}/rga\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.10.9\"\n        asset: ripgrep_all-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rga\n            src: \"{{.AssetWithoutExt}}/rga\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.6\")\n        asset: ripgrep_all-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: rga\n            src: \"{{.AssetWithoutExt}}/rga\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ripgrep_all-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rga\n            src: \"{{.AssetWithoutExt}}/rga\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pimalaya/himalaya/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pimalaya\n    repo_name: himalaya\n    aliases:\n      - name: soywod/himalaya\n    description: CLI to manage emails\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.7.2\"\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.7.3\"\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.8.2\"\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tgz\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.8.3\"\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.0.0-beta.4\"\n        asset: himalaya.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"< 0.3.2\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          # https://github.com/soywod/himalaya/issues/144\n          - name: himalaya\n            src: himalaya.exe\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.5\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.9\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.0-beta.3\")\n        asset: himalaya-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: himalaya-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: himalaya.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: windows\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pinterest/ktlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pinterest\n    repo_name: ktlint\n    description: An anti-bikeshedding Kotlin linter with built-in formatter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.49.0\")\n        complete_windows_ext: false\n        asset: ktlint\n      - version_constraint: \"true\"\n        asset: \"ktlint-{{.Version}}.{{.Format}}\"\n        format: zip\n        files:\n          - name: ktlint\n            src: \"{{.AssetWithoutExt}}/bin/ktlint\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pipe-cd/pipecd/pipectl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: pipe-cd/pipecd/pipectl\n    type: github_release\n    repo_owner: pipe-cd\n    repo_name: pipecd\n    description: The command line tool for PipeCD\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.33.0\")\n        asset: pipectl_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: pipectl_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pipe-cd/pipecd/piped/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: pipe-cd/pipecd/piped\n    type: github_release\n    repo_owner: pipe-cd\n    repo_name: pipecd\n    description: A component that runs inside target environment to execute deployment and report its state\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.5\")\n        no_asset: true\n      - version_constraint: Version == \"v0.1.6\"\n        asset: piped-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.7.5\")\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.7.6\"\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.9.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.24.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.27.4\")\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.29.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.33.0\")\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: piped_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pivotal-cf/om/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pivotal-cf\n    repo_name: om\n    description: General command line utility for working with VMware Tanzu Operations Manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.33.0\")\n        asset: om-{{.OS}}\n        format: raw\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: om-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 7.7.0\")\n        asset: om-{{.OS}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: om-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pivotal-cf/pivnet-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pivotal-cf\n    repo_name: pivnet-cli\n    description: CLI to interact with Tanzu Network API V2 interface\n    files:\n      - name: pivnet\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0-rc.1\"\n        asset: pivnet-{{.OS}}-{{.Arch}}-1.0.0\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.1\")\n        asset: pivnet-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pivnet-{{.OS}}-{{.Arch}}-{{trimV .Version}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pkgxdev/pkgx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pkgxdev\n    repo_name: pkgx\n    description: “run anything” from the creator of `brew`\n    asset: pkgx-{{trimV .Version}}+{{.OS}}+{{.Arch}}.{{.Format}}\n    format: tar.xz\n    replacements:\n      arm64: aarch64\n      amd64: x86-64\n    supported_envs:\n      - linux\n      - darwin\n    version_constraint: semver(\">= 1.0.0\")\n    version_overrides:\n      - version_constraint: Version == \"v0.14.2\"\n        asset: tea-{{trimV .Version}}+{{.OS}}+{{.Arch}}.{{.Format}}\n        files:\n          - name: tea\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: tea-+{{.OS}}+{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\">= 0.11.14\")\n        asset: tea-{{trimV .Version}}+{{.OS}}+{{.Arch}}.{{.Format}}\n        files:\n          - name: tea\n      - version_constraint: semver(\">= 0.8.8\")\n        asset: tea-{{trimV .Version}}+{{.OS}}+{{.Arch}}.{{.Format}}\n        files:\n          - name: tea\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\">= 0.6.6\")\n        no_asset: true\n      - version_constraint: semver(\"< 0.6.6\")\n        asset: tea-{{trimV .Version}}+{{.OS}}+{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tea\n            src: tea.xyz/{{.Version}}/bin/tea\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pkolaczk/fclones/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pkolaczk\n    repo_name: fclones\n    description: Efficient Duplicate File Finder\n    version_filter: not (Version matches \"^gui\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.12.3\", \"v0.18.1\", \"v0.29.2\", \"v0.31.1\"]\n        no_asset: true\n      - version_constraint: Version == \"0.2.0\"\n        asset: fclones-{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          windows: win\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            asset: fclones-{{.Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux/arm64\n          - windows/amd64\n      - version_constraint: Version in [\"v0.19.0\", \"v0.23.0\"]\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v0.20.0\"\n        asset: fclones-{{trimV .Version}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            files:\n              - name: fclones\n                src: usr/bin/fclones\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.20.1\"\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: win\n        overrides:\n          - goos: linux\n            asset: fclones-{{trimV .Version}}.{{.Format}}\n            format: tgz\n            files:\n              - name: fclones\n                src: usr/bin/fclones\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v0.21.0\"\n        asset: fclones-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: win\n        overrides:\n          - goos: windows\n            asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n          - goos: linux\n            asset: fclones-{{trimV .Version}}.{{.Format}}\n            format: tgz\n            files:\n              - name: fclones\n                src: usr/bin/fclones\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v0.22.0\"\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: win\n        overrides:\n          - goos: darwin\n            format: tar.gz\n          - goos: linux\n            asset: fclones-{{trimV .Version}}.{{.Format}}\n            format: tgz\n            files:\n              - name: fclones\n                src: usr/bin/fclones\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version in [\"v0.24.0\", \"v0.26.0\"]\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n          linux: linux-musl\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"v0.25.0\"\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: linux-musl\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.1.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: fclones-{{.Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          windows: win\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: fclones-{{.Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.12.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.28.0\")\n        asset: fclones-{{trimV .Version}}-{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            asset: fclones-{{trimV .Version}}.{{.Format}}\n            format: tgz\n            files:\n              - name: fclones\n                src: usr/bin/fclones\n        replacements:\n          amd64: x86_64\n          windows: win\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: fclones-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: linux-musl\n        overrides:\n          - goos: linux\n            format: tar.gz\n            files:\n              - name: fclones\n                src: target/{{.Arch}}-unknown-{{.OS}}/release/fclones\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/planetscale/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: planetscale\n    repo_name: cli\n    asset: pscale_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: The CLI for PlanetScale Database\n    replacements:\n      darwin: macOS\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: pscale\n    checksum:\n      type: github_release\n      asset: pscale_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/playwright-community/playwright-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: playwright-community\n    repo_name: playwright-go\n    description: Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API\n    files:\n      - name: playwright\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        path: github.com/playwright-community/playwright-go/cmd/playwright\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/plexsystems/sinker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: plexsystems\n    repo_name: sinker\n    description: A tool to sync images from one container registry to another\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: imagesync-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: imagesync\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: sinker-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/plumber-cd/terraform-backend-git/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: plumber-cd\n    repo_name: terraform-backend-git\n    description: Terraform HTTP Backend implementation that uses Git repository as storage\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: terraform-backend-git-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: terraform-backend-git-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: terraform-backend-git-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pluveto/upgit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pluveto\n    repo_name: upgit\n    description: Another upload hub that supports clipboard. It works well with Typora, Snipaste, VSCode\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: upgit_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          windows: win\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: \"true\"\n        asset: upgit_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n          windows: win\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pnpm/pnpm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pnpm\n    repo_name: pnpm\n    description: Fast, disk space efficient package manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 6.11.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 6.12.1\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 6.16.1\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 6.18.0\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n      - version_constraint: semver(\"<= 6.20.0\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 7.0.0-alpha.0\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n      - version_constraint: Version == \"v7.0.0-alpha.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 10.26.1\")\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: pnpm\n            link: pnpm\n            hard: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n      - version_constraint: \"true\"\n        asset: pnpm-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: pnpm\n            link: pnpm\n            hard: true\n        replacements:\n          amd64: x64\n          darwin: macos\n          windows: win\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/po3rin/github_link_creator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: po3rin\n    repo_name: github_link_creator\n    asset: github_link_creator_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: GitHub Link Card Creator lets you generate GitHub images has links to repositories\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: repoimg\n    checksum:\n      type: github_release\n      asset: github_link_creator_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pomdtr/sunbeam/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pomdtr\n    repo_name: sunbeam\n    description: Command-line launcher\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-rc.47\")\n        asset: sunbeam_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-rc.49\")\n        asset: sunbeam-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-rc.56\")\n        asset: sunbeam-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-rc.73\")\n        asset: sunbeam-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: sunbeam-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ponkio-o/ec2x/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ponkio-o\n    repo_name: ec2x\n    description: A cli tool of connect to ec2 instance with Session Manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.4\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: ec2x_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/porter-dev/porter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: porter-dev\n    repo_name: porter\n    asset: porter_{{.Version}}_{{title .OS}}_x86_64.zip\n    description: Kubernetes powered PaaS that runs in your own cloud\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/postfinance/kubectl-sudo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: postfinance\n    repo_name: kubectl-sudo\n    description: Run kubernetes commands with the security privileges of another user\n    supported_envs:\n      - darwin\n      - linux\n    path: bash/kubectl-sudo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/postfinance/topf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: postfinance\n    repo_name: topf\n    description: Talos orchestrator by PostFinance\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: topf_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: topf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/praetorian-inc/gokart/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: praetorian-inc\n    repo_name: gokart\n    description: A static analysis tool for securing Go code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gokart_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: darwin_macOS\n        checksum:\n          type: github_release\n          asset: gokart_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/praetorian-inc/noseyparker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: praetorian-inc\n    repo_name: noseyparker\n    description: Nosey Parker is a command-line tool that finds secrets and sensitive information in textual data and Git history\n    files:\n      - name: noseyparker\n        src: bin/noseyparker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.12.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: noseyparker-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: noseyparker-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: noseyparker-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macos\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.17.0\"\n        asset: noseyparker-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: noseyparker-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: noseyparker-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pranshuparmar/witr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pranshuparmar\n    repo_name: witr\n    description: Why is this running\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: witr-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: Version == \"v0.1.3\"\n        asset: witr-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.8\")\n        asset: witr-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: witr-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: witr-{{.OS}}-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pre-commit/pre-commit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pre-commit\n    repo_name: pre-commit\n    description: A framework for managing and maintaining multi-language pre-commit hooks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.7.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.4.0\")\n        asset: pre-commit-{{trimV .Version}}.pyz\n        format: raw\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: pre-commit-{{trimV .Version}}.pyz\n        format: raw\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pressly/goose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pressly\n    repo_name: goose\n    description: A database migration tool. Supports SQL migrations and Go functions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v3.13.0\"\n        no_asset: true\n      - version_constraint: Version == \"v1.0\"\n        asset: goose-{{.OS}}64\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.4.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.7.0-rc5\")\n        asset: goose-{{.OS}}64\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: goose_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/princjef/gomarkdoc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: princjef\n    repo_name: gomarkdoc\n    description: Generate markdown documentation for Go (golang) code\n    files:\n      - name: gomarkdoc\n        src: \"{{.AssetWithoutExt}}/gomarkdoc\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: gomarkdoc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gomarkdoc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: gomarkdoc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gomarkdoc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gomarkdoc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gomarkdoc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/printfn/fend/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: printfn\n    repo_name: fend\n    description: Arbitrary-precision unit-aware calculator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.9\")\n        asset: fend-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.26\")\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.28\")\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.29\"\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          arm64: aarch64\n          darwin: macos\n      - version_constraint: semver(\"<= 1.0.3\")\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n          - goos: windows\n            asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}-exe.{{.Format}}\n      - version_constraint: \"true\"\n        asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}-gnu.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: fend-{{trimV .Version}}-{{.OS}}-{{.Arch}}-exe.{{.Format}}\n            replacements:\n              amd64: x64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/project-copacetic/copacetic/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: project-copacetic\n    repo_name: copacetic\n    description: CLI tool for directly patching container images using reports from vulnerability scanners\n    asset: copa_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: copa\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: copacetic_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.3.0\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.2.0\")\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"< 0.2.0\")\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/project-zot/zot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: project-zot\n    repo_name: zot\n    description: \"zot - A scale-out production-ready vendor-neutral OCI-native container image/artifact registry (purely based on OCI Distribution Specification)\"\n    version_filter: Version matches \"^v[0-9]+.[0-9]+.[0-9]+$\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.1\") or Version in [\"1.3.2\", \"1.3.6\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 1.3.5\")\n        asset: zot\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.3.7\")\n        asset: zot-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 2.0.1\")\n        asset: zot-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: zot-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.sha256.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectcalico/calico/calicoctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\n---\npackages:\n  - name: projectcalico/calico/calicoctl\n    type: github_release\n    repo_owner: projectcalico\n    repo_name: calico\n    asset: calicoctl-{{.OS}}-{{.Arch}}\n    format: raw\n    description: CLI tool for Calico cloud native networking and network security\n    link: https://projectcalico.docs.tigera.io/\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: calicoctl\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n    version_constraint: semver(\">= 3.23.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/httpx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: httpx\n    description: httpx is a fast and multi-purpose HTTP toolkit allows to run multiple probers using retryablehttp library, it is designed to maintain the result reliability with increased threads\n    asset: httpx_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    replacements:\n      darwin: macOS\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: httpx_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/katana/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: katana\n    description: A next-generation crawling and spidering framework\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: katana_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: katana_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: katana_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: katana-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              type: github_release\n              asset: katana-mac-checksums.txt\n              algorithm: sha256\n      - version_constraint: \"true\"\n        asset: katana_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: katana-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              type: github_release\n              asset: katana-mac-checksums.txt\n              algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/naabu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: naabu\n    description: A fast port scanner written in go with a focus on reliability and simplicity. Designed to be used in combination with other tools for attack surface discovery in bug bounties and pentests\n    rosetta2: true\n    asset: naabu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    replacements:\n      darwin: macOS\n    version_constraint: semver(\">= 2.0.9\")\n    supported_envs:\n      - darwin\n      - amd64\n    version_overrides:\n      - version_constraint: semver(\"= 2.0.8\")\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: \"true\"\n        supported_envs:\n          - windows\n          - darwin\n          - linux/amd64\n    checksum:\n      type: github_release\n      asset: naabu-{{.OS}}-checksums.txt\n      algorithm: sha256\n      replacements:\n        darwin: mac\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/nuclei/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: nuclei\n    description: Fast and customizable vulnerability scanner based on simple YAML based DSL\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: nuclei_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    replacements:\n      darwin: macOS\n    checksum:\n      type: github_release\n      asset: nuclei_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/pdtm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: pdtm\n    description: ProjectDiscovery's Open Source Tool Manager\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pdtm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: pdtm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/proxify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: proxify\n    description: A versatile and portable proxy for capturing, manipulating, and replaying HTTP/HTTPS traffic on the go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: proxify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: proxify_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.6\")\n        asset: proxify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: proxify_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.7\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: proxify_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: proxify_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/subfinder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: subfinder\n    asset: subfinder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip\n    description: Subfinder is a subdomain discovery tool that discovers valid subdomains for websites. Designed as a passive framework to be useful for bug bounties and safe for penetration testing\n    replacements:\n      darwin: macOS\n    checksum:\n      type: github_release\n      asset: subfinder_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/projectdiscovery/tlsx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: projectdiscovery\n    repo_name: tlsx\n    description: Fast and configurable TLS grabber focused on TLS based data collection\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tlsx_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: tlsx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/prometheus/alertmanager/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: prometheus\n    repo_name: alertmanager\n    asset: alertmanager-{{trimV .Version}}.{{.OS}}-{{.Arch}}.tar.gz\n    description: Prometheus Alertmanager\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n    files:\n      - name: alertmanager\n        src: alertmanager-{{trimV .Version}}.{{.OS}}-{{.Arch}}/alertmanager\n      - name: amtool\n        src: alertmanager-{{trimV .Version}}.{{.OS}}-{{.Arch}}/amtool\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/prometheus/prom2json/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: prometheus\n    repo_name: prom2json\n    asset: prom2json-{{trimV .Version}}.{{.OS}}-{{.Arch}}.tar.gz\n    description: A tool to scrape a Prometheus client and dump the result as JSON\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n    files:\n      - name: prom2json\n        src: prom2json-{{trimV .Version}}.{{.OS}}-{{.Arch}}/prom2json\n    version_constraint: semver(\">= 1.3.1\")\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/prometheus/prometheus/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: prometheus\n    repo_name: prometheus\n    asset: prometheus-{{trimV .Version}}.{{.OS}}-{{.Arch}}.tar.gz\n    description: The Prometheus monitoring system and time series database\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n    files:\n      - name: prometheus\n        src: prometheus-{{trimV .Version}}.{{.OS}}-{{.Arch}}/prometheus\n      - name: promtool\n        src: prometheus-{{trimV .Version}}.{{.OS}}-{{.Arch}}/promtool\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/prometheus/promlens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: prometheus\n    repo_name: promlens\n    asset: promlens-{{trimV .Version}}.{{.OS}}-{{.Arch}}.tar.gz\n    description: PromLens – The query builder, analyzer, and explainer for PromQL\n    checksum:\n      type: github_release\n      asset: sha256sums.txt\n      algorithm: sha256\n    files:\n      - name: promlens\n        src: promlens-{{trimV .Version}}.{{.OS}}-{{.Arch}}/promlens\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/protocolbuffers/protobuf/protoc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: protocolbuffers/protobuf/protoc\n    repo_owner: protocolbuffers\n    repo_name: protobuf\n    asset: protoc-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    files:\n      - name: protoc\n        src: bin/protoc\n    description: Protocol Buffers - Google's data interchange format\n    replacements:\n      arm64: aarch_64\n      amd64: x86_64\n      darwin: osx\n      windows: win64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    overrides:\n      - goos: windows\n        asset: protoc-{{trimV .Version}}-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/protocolbuffers/protobuf-go/protoc-gen-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: protocolbuffers/protobuf-go/protoc-gen-go\n    type: github_release\n    repo_owner: protocolbuffers\n    repo_name: protobuf-go\n    description: Go support for Google's protocol buffers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.24.0\"\n        asset: protoc-gen-go.{{.Version}}-devel.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.26.0\")\n        asset: protoc-gen-go.{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.28.0\")\n        asset: protoc-gen-go.{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: protoc-gen-go.{{.Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/clang-tidy-sarif/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/clang-tidy-sarif\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Convert clang-tidy output into SARIF\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: clang-tidy-sarif-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"clang-tidy-sarif-v0.2.23\"\n        asset: clang-tidy-sarif-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: clang-tidy-sarif\n            src: target/release/{{.FileName}}-{{.Arch}}-{{.OS}}\n      - version_constraint: Version in [\"clang-tidy-sarif-v0.2.24\", \"clang-tidy-sarif-v0.6.2\"]\n        asset: clang-tidy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: clang-tidy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: clang-tidy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/clippy-sarif/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/clippy-sarif\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Convert clippy output into SARIF\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: clippy-sarif-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"clippy-sarif-v0.2.23\"\n        asset: clippy-sarif-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: clippy-sarif\n            src: target/release/{{.FileName}}-{{.Arch}}-{{.OS}}\n      - version_constraint: Version == \"clippy-sarif-v0.6.2\"\n        asset: clippy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: clippy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: clippy-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/hadolint-sarif/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/hadolint-sarif\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Convert hadolint warnings into SARIF\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: hadolint-sarif-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"hadolint-sarif-v0.2.23\"\n        asset: hadolint-sarif-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: hadolint-sarif\n            src: target/release/{{.FileName}}-{{.Arch}}-{{.OS}}\n      - version_constraint: Version in [\"hadolint-sarif-v0.2.24\", \"hadolint-sarif-v0.6.2\"]\n        asset: hadolint-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: hadolint-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: hadolint-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/miri-sarif/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/miri-sarif\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Convert miri output into SARIF\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: miri-sarif-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: miri-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/sarif-fmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/sarif-fmt\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Pretty print SARIF results\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: sarif-fmt-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"sarif-fmt-v0.6.2\"\n        asset: sarif-fmt-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: sarif-fmt-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: sarif-fmt-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psastras/sarif-rs/shellcheck-sarif/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: psastras/sarif-rs/shellcheck-sarif\n    type: github_release\n    repo_owner: psastras\n    repo_name: sarif-rs\n    description: Convert shellcheck warnings into SARIF\n    version_filter: not (Version matches \"-latest$\")\n    version_prefix: shellcheck-sarif-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"shellcheck-sarif-v0.2.23\"\n        asset: shellcheck-sarif-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: shellcheck-sarif\n            src: target/release/{{.FileName}}-{{.Arch}}-{{.OS}}\n      - version_constraint: Version in [\"shellcheck-sarif-v0.2.24\", \"shellcheck-sarif-v0.6.2\"]\n        asset: shellcheck-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: shellcheck-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: shellcheck-sarif-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pseudomuto/protoc-gen-doc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pseudomuto\n    repo_name: protoc-gen-doc\n    asset: protoc-gen-doc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: Documentation generator plugin for Google Protocol Buffers\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/psf/black/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: psf\n    repo_name: black\n    description: The uncompromising Python code formatter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"22.8.0\"\n        asset: black_{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 19.10b0\")\n        asset: black\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 20.8b1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 21.5b1\")\n        asset: black\n        format: raw\n        supported_envs:\n          - windows\n      - version_constraint: semver(\"<= 25.9.0\")\n        asset: black_{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: black_{{.OS}}\n        format: raw\n        replacements:\n          arm64: arm\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: black_{{.OS}}-{{.Arch}}\n          - goos: windows\n            goarch: arm64\n            asset: black_{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pulumi/esc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pulumi\n    repo_name: esc\n    description: Pulumi ESC is a centralized, secure service for environments, secrets, and configuration management, optimized for multi-cloud infrastructures and applications\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: esc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: esc-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: esc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        files:\n          - name: esc\n            src: esc/esc\n        checksum:\n          type: github_release\n          asset: esc-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: esc\n                src: esc/bin/esc.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pulumi/kubespy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pulumi\n    repo_name: kubespy\n    description: Tools for observing Kubernetes resources in real time, powered by Pulumi\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: kubespy-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.6.1\")\n    version_overrides:\n      - version_constraint: \"true\"\n        overrides:\n          - goos: windows\n            asset: kubespy.exe-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pulumi/pulumi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pulumi\n    repo_name: pulumi\n    description: \"Pulumi - Infrastructure as Code in any programming language\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v3.0.0-rc.1\"\n        no_asset: true\n      - version_constraint: Version in [\"v2.11.0\", \"v2.15.1\", \"v2.15.5\", \"v2.16.1\"]\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: pulumi-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v3.39.4\"\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: pulumi\n                src: pulumi/bin/pulumi.exe\n        files:\n          - name: pulumi\n            src: pulumi/pulumi\n      - version_constraint: semver(\"<= 2.20.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.22.0\")\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: pulumi-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: pulumi\n            src: pulumi/pulumi\n      - version_constraint: semver(\"<= 3.2.1\")\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: pulumi-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: pulumi\n            src: pulumi/pulumi\n      - version_constraint: semver(\"<= 3.39.3\")\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: pulumi-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: pulumi\n                src: pulumi/bin/pulumi.exe\n        files:\n          - name: pulumi\n            src: pulumi/pulumi\n      - version_constraint: \"true\"\n        asset: pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n          cosign:\n            bundle:\n              type: github_release\n              asset: SHA512SUMS.sig\n            opts:\n              - --certificate-identity-regexp\n              - '^https://github\\.com/pulumi/pulumi/\\.github/workflows/sign\\.yml@refs/heads/gh-readonly-queue/'\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: pulumi\n                src: pulumi/bin/pulumi.exe\n        files:\n          - name: pulumi\n            src: pulumi/pulumi\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pulumi/tf2pulumi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pulumi\n    repo_name: tf2pulumi\n    asset: tf2pulumi-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: A tool to convert Terraform projects to Pulumi TypeScript programs\n    replacements:\n      amd64: x64\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: tf2pulumi_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/purpleclay/dns53/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: purpleclay\n    repo_name: dns53\n    description: Dynamic DNS within Amazon Route53. Expose your EC2 quickly, easily and privately\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dns53_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/purpleclay/dns53/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/purpleclay/dns53/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/purpleclay/dns53/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/purton-tech/cloak/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: purton-tech\n    repo_name: cloak\n    description: Secrets automation for developers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: cli\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.17.7\")\n        asset: cloak-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.17.11\")\n        asset: cloak-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v1.17.12\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.17.14\")\n        asset: cloak-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: \"true\"\n        asset: cloak-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pvolok/mprocs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pvolok\n    repo_name: mprocs\n    description: Run multiple commands in parallel\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1\")\n        asset: mprocs-{{.OS}}-{{.Arch}}.{{.Format}}\n        files:\n          - name: mprocs\n            src: dist/{{.OS}}-{{.Arch}}/mprocs\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.1.0\"\n        asset: mprocs-{{trimV .Version}}-{{.OS}}64.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n          - goos: windows\n            format: zip\n            asset: mprocs-{{trimV .Version}}-{{.OS}}-upx.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.4\")\n        asset: mprocs-{{trimV .Version}}-{{.OS}}64.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win64\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x64\n          - goos: windows\n            format: zip\n            asset: mprocs-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: mprocs-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            asset: mprocs-{{trimV .Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pyama86/pachanger/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pyama86\n    repo_name: pachanger\n    description: Pachanger - A CLI tool for renaming Go package names safely and efficiently\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pachanger_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pachanger_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/pypa/pipx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: pypa\n    repo_name: pipx\n    description: Install and Run Python Applications in Isolated Environments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\") or Version == \"1.3.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: pipx.pyz\n        format: raw\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/qarmin/czkawka/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: qarmin\n    repo_name: czkawka\n    description: Multi functional app to find duplicates, empty folders, similar images etc\n    version_filter: Version != \"Nightly\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0.1\"\n        asset: \"{{.OS}}_czkawka_cli\"\n        format: raw\n        replacements:\n          darwin: MAC\n          linux: LINUX\n          windows: WINDOWS\n        overrides:\n          - goos: darwin\n            asset: \"{{.OS}}_OS_ACHTUNG_czkawka_cli\"\n          - goos: windows\n            asset: \"{{.OS}}_ACHTUNG_czkawka_cli\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"1.3.0\"\n        asset: \"{{.OS}}_czkawka_cli\"\n        format: raw\n        replacements:\n          darwin: mac\n        overrides:\n          - goos: windows\n            asset: \"{{.OS}}czkawka_cli\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: czkawka_cli\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.3.0\")\n        asset: \"{{.OS}}_czkawka_cli\"\n        format: raw\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.3.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 9.0.0\")\n        asset: \"{{.OS}}_czkawka_cli\"\n        format: raw\n        replacements:\n          darwin: mac\n        overrides:\n          - envs:\n              - darwin/arm64\n              - linux/arm64\n            asset: \"{{.OS}}_czkawka_cli_arm\"\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}_czkawka_cli_{{.Arch}}\"\n        format: raw\n        overrides:\n          - goos: windows\n            asset: \"{{.OS}}_czkawka_cli\"\n        replacements:\n          amd64: x86_64\n          darwin: mac\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/qdrant/qdrant/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: qdrant\n    repo_name: qdrant\n    description: High-performance, massive-scale Vector Database for the next generation of AI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.3\") || Version == \"v1.3.1\"\n        no_asset: true\n      - version_constraint: Version == \"v1.3.0\"\n        asset: qdrant-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"< 1.8.0\")\n        asset: qdrant-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: qdrant-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/qnighy/clippy-reviewdog-filter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: qnighy\n    repo_name: clippy-reviewdog-filter\n    description: A filter for integrating Clippy with Reviewdog\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: clippy-reviewdog-filter-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.4\")\n        asset: clippy-reviewdog-filter-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n      - version_constraint: \"true\"\n        asset: clippy-reviewdog-filter-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/quantumsheep/sshs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: quantumsheep\n    repo_name: sshs\n    description: Terminal user interface for SSH\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.4.0\")\n        asset: sshs-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: sshs-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          file_format: regexp\n          asset: \"{{.Asset}}.sha256\"\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{64}\\b)\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/quarkslab/kdigger/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: quarkslab\n    repo_name: kdigger\n    description: Kubernetes focused container assessment tool for penetration testing\n    supported_envs:\n      - darwin\n      - linux\n    rosetta2: true\n    asset: kdigger-{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/quarto-dev/quarto-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: quarto-dev\n    repo_name: quarto-cli\n    description: Open-source scientific and technical publishing system built on Pandoc\n    files:\n      - name: quarto\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.1.106\", \"v1.3.6\"]\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: Version in [\"v1.2.127\", \"v1.4.49\"]\n        asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: quarto-{{trimV .Version}}/bin/quarto\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.1.29\")\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: quarto-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.1.33\")\n        asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: quarto-{{trimV .Version}}/bin/quarto\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.2.3\")\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: quarto-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.2.7\")\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.3.179\")\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n          windows: win\n        checksum:\n          type: github_release\n          asset: quarto-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: quarto-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: quarto\n            src: bin/quarto\n        replacements:\n          darwin: macos\n          windows: win\n        checksum:\n          type: github_release\n          asset: quarto-{{trimV .Version}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: quarto-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: quarto\n                src: quarto-{{trimV .Version}}/bin/quarto\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/quarylabs/sqruff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: quarylabs\n    repo_name: sqruff\n    description: Fast SQL formatter/linter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.0\"\n        asset: sqruff-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: sqruff-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: sqruff_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256sum\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: sqruff-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            asset: sqruff-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: sqruff-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: sqruff-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 0.25.14\")\n        asset: sqruff-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: sqruff-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: sqruff-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: quarylabs/sqruff/.github/workflows/release.yml\n        overrides:\n          - goos: linux\n            asset: sqruff-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/raaymax/lazytail/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: raaymax\n    repo_name: lazytail\n    description: Log viewer for app development\n    search_words:\n      - log\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: lazytail-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rajatjindal/krew-release-bot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rajatjindal\n    repo_name: krew-release-bot\n    description: bot to bump version of plugin in krew-index on new releases\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.34-2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: krew-release-bot_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: krew-release-bot_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rajatjindal/kubectl-whoami/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rajatjindal\n    repo_name: kubectl-whoami\n    description: This plugin gets the subject name using the effective kubeconfig\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.6\")\n        asset: \"{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\"\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.16\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.18\")\n        asset: kubectl-whoami_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: kubectl-whoami_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.19\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.41\")\n        asset: kubectl-whoami_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: kubectl-whoami_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.42\"\n        asset: kubectl-whoami_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: kubectl-whoami_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.45\")\n        asset: kubectl-whoami_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: kubectl-whoami_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubectl-whoami_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: kubectl-whoami_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rancher/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rancher\n    repo_name: cli\n    description: Rancher CLI\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: rancher-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: rancher\n        src: rancher-{{.Version}}/rancher\n    checksum:\n      type: github_release\n      asset: sha256sum.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rancher/kim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rancher\n    repo_name: kim\n    description: In ur kubernetes, buildin ur imagez\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0-alpha.3\")\n        asset: kim-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.1.0-alpha.6\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: kim-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rancher/rke/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rancher\n    repo_name: rke\n    description: Rancher Kubernetes Engine (RKE), an extremely simple, lightning fast Kubernetes distribution that runs entirely within containers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.10-dev\"\n        asset: rke\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"v0.2.1-rc2\", \"v1.3.5-alpha1\",  \"v1.3.8-rc1\",  \"v1.5.6-rc2\",  \"v1.4.16-rc2\", \"v1.5.0-rc1\"]\n        no_asset: true\n      - version_constraint: Version == \"v1.1.0-rc9\"\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.6.0-rc1\"\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.6.0-rc10\"\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.6-rc3\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.0-rc1\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.0-rc13\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.2.0-rc7\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.20-rc1\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.4.20\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.5.11-rc2\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.11\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.6.0-rc6\")\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rke_{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/raviqqe/muffet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: raviqqe\n    repo_name: muffet\n    description: Fast website link checker in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.1.0\"\n        asset: muffet_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: muffet_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: muffet_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n      - version_constraint: semver(\"<= 2.4.0\")\n        asset: muffet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: muffet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n      - version_constraint: semver(\"<= 2.4.2\")\n        asset: muffet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: ARM64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: muffet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.8.1\")\n        asset: muffet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: ARM64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: muffet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: muffet_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: muffet_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rclone/rclone/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rclone\n    repo_name: rclone\n    asset: rclone-{{.Version}}-{{.OS}}-{{.Arch}}.zip\n    description: '\"rsync for cloud storage\" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Yandex Files'\n    files:\n      - name: rclone\n        src: rclone-{{.Version}}-{{.OS}}-{{.Arch}}/rclone\n    replacements:\n      darwin: osx\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rcoh/angle-grinder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rcoh\n    repo_name: angle-grinder\n    description: Slice and dice logs on the command line\n    files:\n      - name: agrind\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.19.3\"\n        asset: agrind-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.15-alpha1\"\n        asset: agrind-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: angle_grinder-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: ag\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: angle_grinder-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: agrind-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/realm/SwiftLint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: realm\n    repo_name: SwiftLint\n    description: A tool to enforce Swift style and conventions\n    files:\n      - name: swiftlint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.40.0\")\n        asset: portable_swiftlint.{{.Format}}\n        format: zip\n        files:\n          - name: swiftlint\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.59.1\")\n        asset: swiftlint_linux.{{.Format}}\n        format: zip\n        files:\n          - name: swiftlint\n        overrides:\n          - goos: darwin\n            asset: portable_swiftlint.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: swiftlint_linux_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: swiftlint\n        overrides:\n          - goos: darwin\n            asset: portable_swiftlint.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rebuy-de/aws-nuke/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rebuy-de\n    repo_name: aws-nuke\n    description: Nuke a whole AWS account and delete all its resources\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: aws-nuke-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: aws-nuke\n            src: aws-nuke-{{.Version}}-windows-{{.Arch}}.exe\n    files:\n      - name: aws-nuke\n        src: aws-nuke-{{.Version}}-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/redhat-developer/odo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: redhat-developer\n    repo_name: odo\n    description: A fast, and iterative CLI tool for container-based application development\n    url: https://developers.redhat.com/content-gateway/rest/mirror/pub/openshift-v4/clients/odo/{{.Version}}/odo-{{.OS}}-{{.Arch}}\n    format: raw\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    checksum:\n      type: http\n      url: https://developers.redhat.com/content-gateway/rest/mirror/pub/openshift-v4/clients/odo/{{.Version}}/odo-{{.OS}}-{{.Arch}}.sha256\n      algorithm: sha256\n    overrides:\n      - goos: windows\n        checksum:\n          type: http\n          url: https://developers.redhat.com/content-gateway/rest/mirror/pub/openshift-v4/clients/odo/{{.Version}}/odo-{{.OS}}-{{.Arch}}.exe.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/redhat.com/openshift-install/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: redhat.com/openshift-install\n    type: http\n    url: https://mirror.openshift.com/pub/openshift-v4/{{.Arch}}/clients/ocp/{{trimV .Version}}/openshift-install-{{.OS}}.tar.gz\n    description: Install an OpenShift 4.x cluster\n    replacements:\n      darwin: mac\n    supported_envs:\n      - darwin\n      - linux\n    checksum:\n      type: http\n      url: https://mirror.openshift.com/pub/openshift-v4/{{.Arch}}/clients/ocp/{{trimV .Version}}/sha256sum.txt\n      algorithm: sha256\n      file_format: regexp\n      pattern:\n        checksum: ^(\\b[A-Fa-f0-9]{64}\\b)\n        file: \"^\\\\b[A-Fa-f0-9]{64}\\\\b\\\\s+(\\\\S+)$\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/redpanda-data/connect/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: redpanda-data\n    repo_name: connect\n    aliases:\n      - name: Jeffail/benthos\n      - name: benthosdev/benthos\n    description: Fancy stream processing made operationally mundane\n    files:\n      # At v4.28.0, the binary is renamed from benthos to redpanda-connect\n      - name: benthos\n      - name: redpanda-connect\n    version_constraint: \"false\"\n    version_overrides:\n      # v0.10.7 and v0.11.1 doesn't work\n      - version_constraint: semver(\"<= 0.11.1\") or Version == \"v1.7.8\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: benthos_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: benthos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.7.0\")\n        asset: benthos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: benthos\n        checksum:\n          type: github_release\n          asset: benthos_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.43.0-rc1\")\n        asset: benthos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: benthos\n        checksum:\n          type: github_release\n          asset: benthos_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.54.1\")\n        asset: benthos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: benthos\n        checksum:\n          type: github_release\n          asset: benthos_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 4.27.0\")\n        asset: benthos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: benthos\n        checksum:\n          type: github_release\n          asset: benthos_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 4.66.1\")\n        asset: redpanda-connect_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: redpanda-connect\n        checksum:\n          type: github_release\n          asset: redpanda-connect_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v4.67.5\"\n        asset: redpanda-connect_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: redpanda-connect\n        checksum:\n          type: github_release\n          asset: redpanda-connect_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v4.68.0\"\n        asset: redpanda-connect_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: redpanda-connect\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: redpanda-connect_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: redpanda-connect\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/redpanda-data/redpanda/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: redpanda-data\n    repo_name: redpanda\n    description: Redpanda is a streaming data platform for developers. Kafka API compatible. 10x faster. No ZooKeeper. No JVM\n    files:\n      - name: rpk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v21.6.3\"\n        no_asset: true\n      - version_constraint: Version in [\"v21.11.18\", \"v22.1.6\"]\n        asset: rpk-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 21.5.5\")\n        asset: rpk-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 22.3.5\")\n        asset: rpk-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: rpk-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: rpk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/reemus-dev/gitnr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: reemus-dev\n    repo_name: gitnr\n    description: Create `.gitignore` files using one or more templates from TopTal, GitHub or your own collection\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gitnr-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/regclient/regclient/regbot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: regclient/regclient/regbot\n    type: github_release\n    repo_owner: regclient\n    repo_name: regclient\n    asset: regbot-{{.OS}}-{{.Arch}}\n    format: raw\n    files:\n      - name: regbot\n    description: A scripting tool on top of the regclient (Docker and OCI Registry Client) API\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.3.9\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.3.9\")\n        rosetta2: true\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/regclient/regclient/regctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: regclient/regclient/regctl\n    type: github_release\n    repo_owner: regclient\n    repo_name: regclient\n    asset: regctl-{{.OS}}-{{.Arch}}\n    format: raw\n    description: Docker and OCI Registry Client\n    files:\n      - name: regctl\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.3.9\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.3.9\")\n        rosetta2: true\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/regclient/regclient/regsync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: regclient/regclient/regsync\n    type: github_release\n    repo_owner: regclient\n    repo_name: regclient\n    asset: regsync-{{.OS}}-{{.Arch}}\n    format: raw\n    files:\n      - name: regsync\n    description: Docker and OCI image mirroring tool\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_constraint: semver(\">= 0.3.9\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.3.9\")\n        rosetta2: true\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/release-plz/release-plz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: release-plz\n    repo_name: release-plz\n    description: Publish Rust crates from CI with a Release PR\n    version_prefix: release-plz-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"release-plz-v0.3.35\", \"release-plz-v0.3.54\", \"release-plz-v0.3.109\"]\n        no_asset: true\n      - version_constraint: Version in [\"release-plz-v0.3.2\", \"release-plz-v0.3.26\"]\n        asset: release-plz-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.44\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.19\")\n        asset: release-plz-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.3.45\")\n        asset: release-plz-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.3.47\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.147\")\n        asset: release-plz-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: release-plz-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - windows\n          - darwin/arm64\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/relusc/hclconv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: relusc\n    repo_name: hclconv\n    description: Simple tool to convert JSON files to HCL2 files and vice versa\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: hclconv_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: tar.gz\n      - version_constraint: \"true\"\n        asset: hclconv_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: hclconv_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/remko/age-plugin-se/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: remko\n    repo_name: age-plugin-se\n    description: Age plugin for Apple's Secure Enclave\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.2\"\n        asset: age-plugin-se-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.0.3\"\n        asset: age-plugin-se-{{.Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tgz\n            asset: age-plugin-se-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: age-plugin-se-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tgz\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: age-plugin-se-{{.Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: age-plugin-se-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: age-plugin-se-{{.Version}}-{{.OS}}.{{.Format}}\n          - goos: linux\n            format: tgz\n            files:\n              - name: age-plugin-se\n                src: \"{{.AssetWithoutExt}}/usr/bin/age-plugin-se\"\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/replicatedhq/kots/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: replicatedhq\n    repo_name: kots\n    description: KOTS provides the framework, tools and integrations that enable the delivery and management of 3rd-party Kubernetes applications, a.k.a. Kubernetes Off-The-Shelf (KOTS) Software\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: kubectl-kots\n        src: kots\n    asset: kots_{{.OS}}_{{.Arch}}.tar.gz\n    version_constraint: semver(\">= 1.59.2\")\n    overrides:\n      - goos: darwin\n        asset: kots_{{.OS}}_all.tar.gz\n    version_overrides:\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n        overrides: []\n    checksum:\n      type: github_release\n      asset: kots_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/replicatedhq/outdated/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: replicatedhq\n    repo_name: outdated\n    description: Kubectl plugin to find and report outdated images running in a Kubernetes cluster\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: outdated_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: kubectl-outdated\n        src: outdated\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: outdated_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/reproducible-containers/diffoci/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: reproducible-containers\n    repo_name: diffoci\n    description: diff for Docker and OCI container images\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: diffoci-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.1.3\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: diffoci-{{.Version}}.{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/reproio/terraform-j2md/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: reproio\n    repo_name: terraform-j2md\n    description: create readable terraform plan as markdown text from json plan output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: terraform-j2md_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: terraform-j2md_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rest-sh/restish/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rest-sh\n    repo_name: restish\n    aliases:\n      - name: danielgtaylor/restish\n    description: Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: restish-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: restish-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: restish-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.21.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: restish-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/restechnica/semverbot/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: restechnica\n    repo_name: semverbot\n    description: A CLI which automates semver versioning\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: sbot-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: sbot\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: sbot-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: sbot\n      - version_constraint: \"true\"\n        asset: sbot-{{.OS}}-{{.Arch}}\n        format: raw\n        files:\n          - name: sbot\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/restic/restic/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: restic\n    repo_name: restic\n    description: Fast, secure, efficient backup program\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: restic_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: restic\n        src: restic_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n    format: bz2\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: restic\n            src: restic_{{trimV .Version}}_windows_{{.Arch}}.exe\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/reteps/dockerfmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: reteps\n    repo_name: dockerfmt\n    description: Dockerfile format and parser. a modern dockfmt\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dockerfmt-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/reviewdog/reviewdog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: reviewdog\n    repo_name: reviewdog\n    description: Automated code review tool integrated with any code analysis tools regardless of programming language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.11\")\n        asset: reviewdog_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.15\")\n        asset: reviewdog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: reviewdog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: reviewdog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: reviewdog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rfjakob/gocryptfs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rfjakob\n    repo_name: gocryptfs\n    description: Encrypted overlay filesystem written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gocryptfs_{{.Version}}_{{.OS}}-static_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: gocryptfs\n          - name: gocryptfs-xray\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rgreinho/tfe-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rgreinho\n    repo_name: tfe-cli\n    description: CLI client for Terraform enterprise\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfe-cli-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rgwood/systemctl-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rgwood\n    repo_name: systemctl-tui\n    description: A fast, simple TUI for interacting with systemd services and their logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: systemctl-tui-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rhysd/actionlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rhysd\n    repo_name: actionlint\n    description: \":octocat: Static checker for GitHub Actions workflow files\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: actionlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: actionlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: actionlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: actionlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.7.10\")\n        asset: actionlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: actionlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: actionlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: actionlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: rhysd/actionlint/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rhysd/dotfiles/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rhysd\n    repo_name: dotfiles\n    description: dotfiles symbolic links management CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: dotfiles_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: dotfiles_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dotfiles_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: dotfiles_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rhysd/hgrep/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rhysd\n    repo_name: hgrep\n    description: Grep with human-friendly search results\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    asset: hgrep-{{.Version}}-{{.Arch}}-{{.OS}}.zip\n    replacements:\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n      arm64: aarch64\n      amd64: x86_64\n    files:\n      - name: hgrep\n        src: hgrep-{{.Version}}-{{.Arch}}-{{.OS}}/hgrep\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n    version_constraint: semver(\">= 0.2.5\")\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - amd64\n        overrides: []\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rhysd/vim-startuptime/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rhysd\n    repo_name: vim-startuptime\n    asset: vim-startuptime_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: A small Go program for better `vim --startuptime` alternative\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: vim-startuptime_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ribice/glice/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: ribice\n    repo_name: glice\n    description: Go license and dependency checker\n    path: github.com/ribice/glice/v2/cmd/glice\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rlmcpherson/s3gof3r/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rlmcpherson\n    repo_name: s3gof3r\n    description: Fast, concurrent, streaming access to Amazon S3, including gof3r, a CLI\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: gof3r\n        src: gof3r_{{trimV .Version}}_{{.OS}}_{{.Arch}}/gof3r\n    asset: gof3r_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: raw\n        asset: gof3r.exe\n      - goos: darwin\n        format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rmitchellscott/reManager/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rmitchellscott\n    repo_name: reManager\n    description: Linux, MacOS, and Windows desktop app for managing mods on reMarkable tablets\n    asset: reManager-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: zip\n    replacements:\n      darwin: macos\n    overrides:\n      - goos: linux\n        format: tar.gz\n      - goos: darwin\n        asset: reManager-macos-universal.zip\n        files:\n          - name: reManager\n            src: reManager.app/Contents/MacOS/reManager\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rmitchellscott/rm-version-switcher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rmitchellscott\n    repo_name: rm-version-switcher\n    description: A beginner-friendly application for switching between installed reMarkable OS versions with an interactive interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: rm-version-switcher-aarch64.tar.gz\n        files:\n          - name: rm-version-switcher\n            src: rm-version-switcher-aarch64\n        supported_envs:\n          - linux/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/robinovitch61/kl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: robinovitch61\n    repo_name: kl\n    description: An interactive Kubernetes log viewer for your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kl_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: kl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: kl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/robscott/kube-capacity/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: robscott\n    repo_name: kube-capacity\n    asset: kube-capacity_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: A simple CLI that provides an overview of the resource requests, limits, and utilization in a Kubernetes cluster\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: kube-capacity\n        src: kube-capacity\n      - name: kubectl-resource_capacity\n        src: kube-capacity\n    version_constraint: semver(\">= 0.7.4\")\n    version_overrides:\n      - version_constraint: \"true\"\n        overrides: []\n        asset: kube-capacity_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n          amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rogerwelin/cassowary/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rogerwelin\n    repo_name: cassowary\n    description: Modern cross-platform HTTP load-testing tool written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: cassowary_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: cassowary_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: cassowary_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: cassowary_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: cassowary_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rogerwelin/cfnctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rogerwelin\n    repo_name: cfnctl\n    description: \"Cfnctl brings the Terraform cli experience to AWS Cloudformation :cloud:\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: cfnctl_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rootless-containers/rootlesskit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rootless-containers\n    repo_name: rootlesskit\n    description: Linux-native \"fake root\" for implementing rootless containers\n    files:\n      - name: rootlessctl\n      - name: rootlesskit\n      - name: rootlesskit-docker-proxy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\") || Version == \"v2.3.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.0-beta.0\"\n        asset: rootlesskit-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        files:\n          - name: rootlessctl\n          - name: rootlesskit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.9.5\")\n        asset: rootlesskit-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        files:\n          - name: rootlessctl\n          - name: rootlesskit\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: SHA256SUM\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.2.0\")\n        asset: rootlesskit-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: rootlessctl\n          - name: rootlesskit\n          - name: rootlesskit-docker-proxy\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rootlesskit-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: rootlessctl\n          - name: rootlesskit\n          - name: rootlesskit-docker-proxy\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        github_artifact_attestations:\n          signer_workflow: rootless-containers/rootlesskit/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rootless-containers/slirp4netns/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rootless-containers\n    repo_name: slirp4netns\n    description: User-mode networking for unprivileged network namespaces\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.3.2\")\n        asset: slirp4netns-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm: armv7l\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: slirp4netns-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm: armv7l\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n        github_artifact_attestations:\n          signer_workflow: rootless-containers/slirp4netns/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ropnop/kerbrute/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ropnop\n    repo_name: kerbrute\n    description: A tool to perform Kerberos pre-auth bruteforcing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kerbrute_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rossmacarthur/sheldon/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rossmacarthur\n    repo_name: sheldon\n    description: \":bowtie: Fast, configurable, shell plugin manager\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.6\")\n        asset: sheldon-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: sheldon-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.4\")\n        asset: sheldon-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: sheldon-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rs/curlie/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rs\n    repo_name: curlie\n    description: The power of curl, the ease of use of httpie\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: curl-httpie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: http\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: curl-httpie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: curl-httpie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: http\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: curl-httpie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: curlie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: curlie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.7.2\")\n        asset: curlie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: curlie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: curlie_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: curlie_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/rs/curlie/releases/download/{{.Version}}/curlie_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/rs/curlie/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/rs/curlie/releases/download/{{.Version}}/curlie_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rtk-ai/rtk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rtk-ai\n    repo_name: rtk\n    description: CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.4.0\", \"v0.6.0\", \"v0.8.0\", \"v0.13.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.12.0\"\n        asset: rtk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.4\")\n        asset: rtk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.11.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.22.2\")\n        asset: rtk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: rtk-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rubenv/sql-migrate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: rubenv\n    repo_name: sql-migrate\n    description: SQL schema migration tool for Go\n    path: github.com/rubenv/sql-migrate/sql-migrate\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rui314/mold/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rui314\n    repo_name: mold\n    description: \"Mold: A Modern Linker\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.3\") || Version == \"v1.6.0-pre.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.5.1\")\n        asset: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: mold\n            src: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}/bin/mold\n          - name: ld.mold\n            src: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}/bin/mold\n          - name: ld64.mold\n            src: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}/bin/mold\n      - version_constraint: \"true\"\n        asset: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: mold\n            src: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}/bin/mold\n          - name: ld.mold\n            src: mold-{{trimV .Version}}-{{.Arch}}-{{.OS}}/bin/mold\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/runatlantis/atlantis/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: runatlantis\n    repo_name: atlantis\n    description: Terraform Pull Request Automation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.28.2\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.0\"\n        asset: atlantis_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.1\")\n        asset: atlantis_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.17.3\")\n        asset: atlantis_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: atlantis_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/runkids/skillshare/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: runkids\n    repo_name: skillshare\n    description: Sync skills across all AI CLI tools with one command and simplify team sharing. Supporting Claude Code, OpenClaw, OpenCode & more\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: skillshare_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/runmedev/runme/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: runmedev\n    repo_name: runme\n    description: DevOps Notebooks Built with Markdown\n    version_constraint: \"false\"\n    aliases:\n      - name: stateful/rdme\n      - name: stateful/runme\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: rdme_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: rdme\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: runme_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rust-cross/cargo-zigbuild/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rust-cross\n    repo_name: cargo-zigbuild\n    description: Compile Cargo project with zig as linker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: cargo-zigbuild-{{.Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}.{{.Format}}\n            checksum:\n              enabled: false\n          - goos: windows\n            format: zip\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x64\n            checksum:\n              enabled: false\n      - version_constraint: Version == \"v0.10.0\"\n        asset: cargo-zigbuild-{{.Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}.{{.Format}}\n            checksum:\n              enabled: false\n          - goos: windows\n            format: zip\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x64\n            checksum:\n              enabled: false\n        supported_envs:\n          - linux/arm64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.21.4\")\n        asset: cargo-zigbuild-{{.Version}}.{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: cargo-zigbuild-{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x64\n      - version_constraint: \"true\"\n        asset: cargo-zigbuild-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        files:\n          - name: cargo-zigbuild\n            src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-zigbuild\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rust-lang/mdBook/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rust-lang\n    repo_name: mdBook\n    rosetta2: true\n    asset: mdbook-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    supported_envs:\n      - darwin\n      - amd64\n    description: Create book from markdown files. Like Gitbook but implemented in Rust\n    replacements:\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n      amd64: x86_64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: mdbook\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rust-lang/rust-analyzer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rust-lang\n    repo_name: rust-analyzer\n    description: A Rust compiler front-end for IDEs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"2024-09-23\"\n        no_asset: true\n      - version_constraint: semver(\"<= 2020-02-17\")\n        asset: ra_lsp_server-{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2020-07-06\")\n        asset: rust-analyzer-{{.OS}}\n        format: raw\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2020-12-21\")\n        asset: rust-analyzer-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.OS}}\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2021-01-04\")\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"2021-01-11\"\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 2021-02-08\")\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 2024-09-16\")\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: semver(\"<= 2024-10-28\")\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: \"true\"\n        asset: rust-analyzer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: rust-analyzer\n            src: rust-analyzer-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            files:\n              - name: rust-analyzer\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rust-lang/rustup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: rust-lang/rustup\n    aliases:\n      - name: rust-lang/rustup/rustup-init\n    type: http\n    repo_owner: rust-lang\n    repo_name: rustup\n    files:\n      - name: rustup\n        link: rustup\n      - name: rustup-init\n    description: The Rust toolchain installer\n    version_source: github_tag\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://static.rust-lang.org/rustup/archive/{{.Version}}/{{.Arch}}-{{.OS}}/rustup-init\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: http\n          url: https://static.rust-lang.org/rustup/archive/{{.Version}}/{{.Arch}}-{{.OS}}/rustup-init.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            checksum:\n              type: http\n              url: https://static.rust-lang.org/rustup/archive/{{.Version}}/{{.Arch}}-{{.OS}}/rustup-init.exe.sha256\n              algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rustic-rs/rustic/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rustic-rs\n    repo_name: rustic\n    description: rustic - fast, encrypted, and deduplicated backups powered by Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.2\"\n        asset: rustic-{{.Version}}-1-g189b17c-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: rustic-{{.Version}}-1-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: rustic-{{.Version}}-1-{{.Arch}}-{{.OS}}.{{.Format}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.2.0-rc1\")\n        asset: rustic_{{trimV .Version}}_{{.Arch}}_64-{{.OS}}.{{.Format}}\n        format: bz2\n        files:\n          - name: rustic\n            src: rustic_0.2.0-rc1_x64_64-unknown-linux-musl\n        replacements:\n          amd64: x64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: rustic-rs-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rustic\n            src: rustic-rs\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: rustic-rs-{{.Version}}-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: rustic-rs-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: rustic\n            src: rustic-rs\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: rustic-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.5.4\")\n        asset: rustic-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n      - version_constraint: Version == \"v0.6.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: rustic-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rustsec/rustsec/cargo-audit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: rustsec/rustsec/cargo-audit\n    type: github_release\n    repo_owner: rustsec\n    repo_name: rustsec\n    version_prefix: cargo-audit/v\n    description: Audit your dependencies for crates\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.17.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: cargo-audit-{{.Arch}}-{{.OS}}-v{{.SemVer}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-audit\n            src: cargo-audit-{{.Arch}}-{{.OS}}-v{{.SemVer}}/cargo-audit\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/rvben/rumdl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: rvben\n    repo_name: rumdl\n    description: A Markdown Linter written in Rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.45\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.43\")\n        asset: rumdl_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.0.49\")\n        asset: rumdl-{{trimV .Version}}-py3-none-many{{.OS}}_2_17_{{.Arch}}.manylinux2014_x86_64.whl\n        format: zip\n        append_ext: false\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        files:\n          - name: rumdl\n            src: rumdl-{{trimV .Version}}.data/scripts/rumdl\n        replacements:\n          amd64: x86_64\n          darwin: macosx\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: rumdl-{{trimV .Version}}-py3-none-many{{.OS}}_2_17_{{.Arch}}.manylinux2014_aarch64.whl\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            goarch: amd64\n            asset: rumdl-{{trimV .Version}}-py3-none-{{.OS}}_10_12_{{.Arch}}.whl\n          - goos: darwin\n            goarch: arm64\n            asset: rumdl-{{trimV .Version}}-py3-none-{{.OS}}_11_0_{{.Arch}}.whl\n          - goos: windows\n            asset: rumdl-{{trimV .Version}}-py3-none-{{.OS}}_{{.Arch}}.whl\n            replacements:\n              amd64: amd64\n      - version_constraint: semver(\"<= 0.0.97\")\n        asset: rumdl-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.0.109\")\n        asset: rumdl-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            format: tar.gz\n            asset: rumdl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha256\"\n              algorithm: sha256\n      - version_constraint: \"true\"\n        asset: rumdl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ryane/kfilt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ryane\n    repo_name: kfilt\n    description: kfilt can filter Kubernetes resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: kfilt_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kfilt_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: kfilt_{{trimV .Version}}_{{.OS}}_all\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ryodocx/kube-credential-cache/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ryodocx\n    repo_name: kube-credential-cache\n    asset: kube-credential-cache_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Accelerator cache for kubernetes access\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: kcc-cache\n      - name: kcc-injector\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ryoppippi/zigchat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ryoppippi\n    repo_name: zigchat\n    description: Command that sends a prompt to OpenAI and returns a reply\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: zigchat-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/s0md3v/Smap/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: s0md3v\n    repo_name: Smap\n    description: a drop-in replacement for Nmap powered by shodan.io\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: smap_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.xz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: macOS\n    files:\n      - name: smap\n        src: smap_{{.Version}}_{{.OS}}_{{.Arch}}/smap\n    checksum:\n      type: github_release\n      asset: smap_{{.Version}}--sha256_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/go-life/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: go-life\n    description: Terminal based Conway's Game of Life. Implemented in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: go-life_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/note/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: note\n    description: Simple Real-time Markdown previewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: note_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/tcpterm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: tcpterm\n    description: tcpterm is a packet visualizer in TUI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tcpterm_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/todoist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: todoist\n    description: Todoist CLI Client. I  Todoist and CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: todoist_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.20.0\"\n        asset: todoist_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: todoist_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/toggl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: toggl\n    description: Toggl CLI Client\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.0\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: toggl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sachaos/viddy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sachaos\n    repo_name: viddy\n    description: A modern watch command. Time machine and pager etc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: viddy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.6\")\n        asset: viddy_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: viddy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: viddy-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: viddy-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sacloud/usacloud/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sacloud\n    repo_name: usacloud\n    description: \"CLI client for the Sakura Cloud\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.16.0\", \"v0.27.0\", \"v0.30.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 1.0.0-beta.1\")\n        asset: usacloud_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.4\")\n        asset: usacloud_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: usacloud_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: usacloud_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: usacloud_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: usacloud_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: usacloud_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sagiegurari/cargo-make/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sagiegurari\n    repo_name: cargo-make\n    description: Rust task runner and build tool\n    files:\n      - name: cargo-make\n        src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n      - name: makers\n        src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.35.3\"\n        no_asset: true\n      - version_constraint: Version == \"0.16.5\"\n        asset: cargo-make-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n        files:\n          - name: cargo-make\n            src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n        overrides:\n          - goos: windows\n            files:\n              - name: cargo-make\n      - version_constraint: Version == \"0.19.0\"\n        asset: cargo-make-v0.18.0-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: cargo-make\n            src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n        overrides:\n          - goos: windows\n            files:\n              - name: cargo-make\n      - version_constraint: Version == \"0.30.2\"\n        asset: cargo-make-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows/amd64\n        files:\n          - name: cargo-make\n            src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n        overrides:\n          - goos: windows\n            files:\n              - name: cargo-make\n      - version_constraint: Version == \"0.35.14\"\n        asset: cargo-make-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        overrides:\n          - goos: windows\n            files:\n              - name: cargo-make\n              - name: makers\n      - version_constraint: semver(\"<= 0.15.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.36.6\")\n        asset: cargo-make-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        overrides:\n          - goos: windows\n            files:\n              - name: cargo-make\n              - name: makers\n      - version_constraint: \"true\"\n        asset: cargo-make-v{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            files:\n              - name: cargo-make\n              - name: makers\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sahilm/yamldiff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sahilm\n    repo_name: yamldiff\n    description: A CLI tool to diff two YAML files\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    complete_windows_ext: false\n    format: raw\n    asset: yamldiff-v{{.Version}}-{{.OS}}-amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/samuel-lucas6/Kryptor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: samuel-lucas6\n    repo_name: Kryptor\n    description: A simple, modern, and secure encryption and signing tool that aims to be a better version of age and Minisign\n    files:\n      - name: kryptor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.2.2\"\n        asset: KryptorCLI-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.1.1\")\n        asset: kryptor-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kryptor-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/samwho/spacer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: samwho\n    repo_name: spacer\n    description: CLI tool to insert spacers when command output stops\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: spacer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: spacer-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sanathp/statusok/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sanathp\n    repo_name: statusok\n    description: Monitor your Website and APIs from your Computer. Get Notified through Slack, E-mail when your server is down or response time is more than expected\n    rosetta2: true\n    asset: statusok_{{.OS}}.zip\n    supported_envs:\n      - darwin\n      - linux/amd64\n    files:\n      - name: statusok\n        src: statusok_{{.OS}}/statusok\n    replacements:\n      darwin: mac\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sandreas/tone/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sandreas\n    repo_name: tone\n    description: tone is a cross platform audio tagger and metadata editor to dump and modify metadata for a wide variety of formats, including mp3, m4b, flac and more. It has no dependencies and can be downloaded as single binary for Windows, macOS, Linux and other common platforms\n    version_constraint: \"false\"\n    files:\n      - name: tone\n        src: \"{{.AssetWithoutExt}}/tone\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: tone-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: tone\n      - version_constraint: \"true\"\n        asset: tone-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n          windows: win\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: tone-{{trimV .Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            files:\n              - name: tone\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sanposhiho/gomockhandler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: sanposhiho\n    repo_name: gomockhandler\n    description: Mr. gomockhandler is the clever and more agile manager of golang/mock\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/santhosh-tekuri/jsonschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: santhosh-tekuri\n    repo_name: jsonschema\n    description: JSONSchema (draft 2020-12, draft 2019-09, draft-7, draft-6, draft-4) Validation using Go\n    files:\n      - name: jv\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 5.3.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: jv-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: jv\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sarub0b0/kubetui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sarub0b0\n    repo_name: kubetui\n    description: An intuitive Terminal User Interface (TUI) tool for real-time monitoring and exploration of Kubernetes resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.7.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.11.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.3\")\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.5\")\n        no_asset: true\n      - version_constraint: Version == \"v0.11.6\"\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.2\")\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: kubetui-{{.Arch}}-{{.OS}}-openssl\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubetui-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sass/dart-sass/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sass\n    repo_name: dart-sass\n    description: The reference implementation of Sass, written in Dart\n    files:\n      - name: sass\n        src: dart-sass/sass\n    windows_ext: .bat\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.23.5\"\n        no_asset: true\n      - version_constraint: Version in [\"1.20.0\", \"1.49.10\"]\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: Version == \"1.23.6\"\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"1.24.1\"\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"1.56.0\", \"1.63.0\"]\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version in [\"1.59.0\", \"1.69.0\"]\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.25.0\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.26.0-test.3\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.26.3\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.26.6\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.49.9\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.64.2\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.65.1\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.69.5\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.71.0\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: dart-sass-{{.Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.72.0\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"< 1.86.1\")\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: dart-sass-{{.Version}}-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n            github_artifact_attestations:\n              signer_workflow: sass/dart-sass/.github/workflows/build-linux.yml\n          - goos: darwin\n            github_artifact_attestations:\n              signer_workflow: sass/dart-sass/.github/workflows/build-macos.yml\n          - goos: windows\n            format: zip\n            github_artifact_attestations:\n              signer_workflow: sass/dart-sass/.github/workflows/build-windows.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sassman/t-rec-rs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sassman\n    repo_name: t-rec-rs\n    description: Blazingly fast terminal recorder that generates animated gif images for the web written in rust\n    asset: t-rec-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    files:\n      - name: t-rec\n    version_constraint: semver(\">= 0.7.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.7.2\")\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n        rosetta2: false\n      - version_constraint: semver(\">= 0.7.1\")\n      - version_constraint: semver(\">= 0.7.0\")\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"< 0.7.0\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/satococoa/wtp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: satococoa\n    repo_name: wtp\n    description: A powerful Git worktree CLI tool with automated setup, branch tracking, and smart navigation\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wtp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/saucelabs/forwarder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: saucelabs\n    repo_name: forwarder\n    description: Forwarder is a production-ready, fast MITM proxy with PAC support. It's suitable for debugging, intercepting and manipulating HTTP traffic. It's used as a core component of Sauce Labs Sauce Connect Proxy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0-rc0\"\n        asset: forwarder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n      - version_constraint: Version == \"v1.0.0-rc2\"\n        asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: Version == \"v1.0.0\"\n        asset: forwarder-{{trimV .Version}}_{{.OS}}-signed.{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n      - version_constraint: Version == \"v1.2.0\"\n        asset: forwarder-{{trimV .Version}}_{{.OS}}.all.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.1.12\")\n        asset: forwarder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: forwarder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.1.15\")\n        asset: forwarder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: forwarder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: forwarder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: forwarder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: forwarder-{{trimV .Version}}_{{.OS}}-signed.all.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 1.1.0-rc1\")\n        asset: forwarder-{{trimV .Version}}_{{.OS}}.all.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            asset: forwarder-{{trimV .Version}}_{{.OS}}-signed.all.{{.Format}}\n      - version_constraint: \"true\"\n        asset: forwarder-{{trimV .Version}}_{{.OS}}.{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: checksums\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: forwarder-{{trimV .Version}}_{{.OS}}.all.{{.Format}}\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sayanarijit/jf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sayanarijit\n    repo_name: jf\n    description: jf %q \"JSON Formatted\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.1\", \"v0.2.3\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: jf-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sayanarijit/xplr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sayanarijit\n    repo_name: xplr\n    description: A hackable, minimal, fast TUI file explorer\n    asset: xplr-{{.OS}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      darwin: macos\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: xplr-{{.OS}}.sha256\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/scaleway/scaleway-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: scaleway\n    repo_name: scaleway-cli\n    description: Command Line Interface for Scaleway\n    format: raw\n    files:\n      - name: scw\n    version_constraint: semver(\">= 2.5.1\")\n    asset: scaleway-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: scw-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - amd64\n        replacements:\n          amd64: x86_64\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/scenarigo/scenarigo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: scenarigo\n    repo_name: scenarigo\n    aliases:\n      - name: zoncoen/scenarigo\n    description: An end-to-end scenario testing tool for HTTP/gRPC server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.14.0-rc3\", \"v0.15.0-rc1\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: scenarigo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: scenarigo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: scenarigo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: scenarigo_{{.Version}}_go{{.Vars.go_version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        vars:\n          - name: go_version\n            required: true\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/schemalex/schemalex/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: schemalex\n    repo_name: schemalex\n    asset: schemalex_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Generate difference sql of two mysql schema\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: schemadiff\n        src: schemalex_{{.OS}}_{{.Arch}}/schemadiff\n      - name: schemalex\n        src: schemalex_{{.OS}}_{{.Arch}}/schemalex\n      - name: schemalint\n        src: schemalex_{{.OS}}_{{.Arch}}/schemalint\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/schollz/croc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: schollz\n    repo_name: croc\n    description: Easily and securely send things from one computer to another\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.2\")\n        asset: croc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: OSX\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: croc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: OSX\n        checksum:\n          type: github_release\n          asset: croc_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.0.1\")\n        asset: croc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: OSX\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v3.0.2\"\n        no_asset: true\n      - version_constraint: semver(\"<= 3.0.6\")\n        asset: croc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: OSX\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v3.0.7\"\n        no_asset: true\n      - version_constraint: semver(\"<= 4.0.3\")\n        asset: croc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: OSX\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 8.6.7\")\n        asset: croc_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 9.3.0\")\n        asset: croc_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 9.5.6\")\n        asset: croc_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v9.6.0\"\n        asset: croc_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: ARM64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 9.6.6\")\n        asset: croc_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: croc_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: 64bit\n          arm64: ARM64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: croc_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sclevine/yj/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sclevine\n    repo_name: yj\n    description: \"CLI - Convert between YAML, TOML, JSON, and HCL. Preserves map order\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v5.0.0\"\n        asset: yj-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: yj-{{.OS}}-{{.Arch}}\n          - goos: windows\n            asset: yj\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: yj-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: yj\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: yj-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: yj\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sdslabs/gasper/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sdslabs\n    repo_name: gasper\n    asset: gasper_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Your Cloud in a Binary\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    files:\n      - name: gasper\n        src: gasper_{{.Version}}_{{.OS}}_{{.Arch}}/gasper\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: md5\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/secretlint/secretlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: secretlint\n    repo_name: secretlint\n    description: Pluggable linting tool to prevent committing credential\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\") or Version == \"v8.3.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: secretlint_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          linux: Linux\n          windows: Windows_NT\n          darwin: Darwin\n          amd64: x64\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: Version == \"v0.7.3\"\n        asset: secretlint_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          linux: Linux\n          windows: Windows_NT\n          amd64: x64\n        supported_envs:\n          - windows/amd64\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.1.0\")\n        asset: secretlint_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        overrides:\n          - goos: windows\n            asset: secretlint_{{.OS}}_NT_{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 8.1.2\")\n        no_asset: true\n      - version_constraint: Version == \"v8.2.0\"\n        asset: secretlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          amd64: X64\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v8.2.1\"\n        asset: secretlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v8.2.2\"\n        asset: secretlint-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v8.2.4\"\n        asset: secretlint-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: secretlint-{{trimV .Version}}-sha256sum.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: secretlint-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        checksum:\n          type: github_release\n          asset: secretlint-{{trimV .Version}}-sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/securego/gosec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: securego\n    repo_name: gosec\n    description: Go security checker\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.0.0\")\n        asset: gosec_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gosec_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.7.0\")\n        asset: gosec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gosec_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.8.1\")\n        asset: gosec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: gosec_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 2.10.0\")\n        asset: gosec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gosec_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: gosec_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gosec_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://raw.githubusercontent.com/securego/gosec/refs/tags/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/securego/gosec/releases/download/{{.Version}}/gosec_{{trimV .Version}}_checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/segmentio/chamber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: segmentio\n    repo_name: chamber\n    description: CLI for managing secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v2.10.2\", \"v2.10.5\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: chamber-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.3.2\")\n        asset: chamber-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: chamber-{{.Version}}.sha256sums\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.10.7\")\n        asset: chamber-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: chamber-{{.Version}}.sha256sums\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: chamber-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: chamber-{{.Version}}.sha256sums\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/segmentio/golines/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: segmentio\n    repo_name: golines\n    description: A golang formatter that fixes long lines\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.11.0\")\n        type: go_install\n      - version_constraint: \"true\"\n        asset: golines_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: golines\n            src: \"{{.AssetWithoutExt}}/golines\"\n        checksum:\n          type: github_release\n          asset: golines_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: golines_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            type: go_install\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/segmentio/topicctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: segmentio\n    repo_name: topicctl\n    description: Tool for declarative management of Kafka topics\n    path: github.com/segmentio/topicctl/cmd/topicctl\n    search_words:\n      - kafka\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/self-actuated/actuated-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: self-actuated\n    repo_name: actuated-cli\n    description: CLI for actuated\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: actuated-cli\n        format: raw\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: actuated-cli-{{.OS}}\n          - goos: darwin\n            goarch: arm64\n            asset: actuated-cli-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sethvargo/ratchet/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sethvargo\n    repo_name: ratchet\n    description: A tool for securing CI/CD workflows with version pinning\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.10.0\")\n        asset: ratchet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ratchet_{{trimV .Version}}_SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ratchet_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ratchet_{{trimV .Version}}_SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: sethvargo/ratchet/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/bat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: bat\n    description: A cat(1) clone with wings\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: bat\n            src: \"{{.AssetWithoutExt}}/bat\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: bat\n            src: \"{{.AssetWithoutExt}}/bat\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: Version == \"v0.6.1\"\n        asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: bat\n            src: \"{{.AssetWithoutExt}}/bat\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: bat\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: bat\n            src: \"{{.AssetWithoutExt}}/bat\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: bat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: bat\n            src: \"{{.AssetWithoutExt}}/bat\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/diskus/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: diskus\n    asset: diskus-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    description: A minimal, fast alternative to 'du -sh'\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    format: tar.gz\n    replacements:\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n      linux: unknown-linux-musl\n      arm64: aarch64\n      amd64: x86_64\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n    files:\n      - name: diskus\n        src: diskus-{{.Version}}-{{.Arch}}-{{.OS}}/diskus\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/fd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: fd\n    description: A simple, fast and user-friendly alternative to 'find'\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.0\"\n        asset: fd\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - windows\n          - linux/amd64\n      - version_constraint: semver(\"<= 3.1.0\")\n        asset: fd\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v4.0.0\"\n        asset: fd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fd\n            src: \"{{.AssetWithoutExt}}/fd\"\n        replacements:\n          amd64: x86_64\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fd\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 8.2.1\")\n        asset: fd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fd\n            src: \"{{.AssetWithoutExt}}/fd\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: fd\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 9.0.0\")\n        asset: fd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fd\n            src: \"{{.AssetWithoutExt}}/fd\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v10.0.0\"\n        asset: fd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: fd\n            src: \"{{.AssetWithoutExt}}/fd\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: fd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: fd\n            src: \"{{.AssetWithoutExt}}/fd\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/hexyl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: hexyl\n    description: A command-line hex viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: hexyl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: hexyl\n            src: \"{{.AssetWithoutExt}}/hexyl\"\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: hexyl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        files:\n          - name: hexyl\n            src: \"{{.AssetWithoutExt}}/hexyl\"\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hexyl-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        files:\n          - name: hexyl\n            src: \"{{.AssetWithoutExt}}/hexyl\"\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/hyperfine/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: hyperfine\n    description: A command-line benchmarking tool\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: hyperfine-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n    rosetta2: true\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n      386: i686\n    files:\n      - name: hyperfine\n        src: hyperfine-{{.Version}}-{{.Arch}}-{{.OS}}/hyperfine\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/numbat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: numbat\n    description: A statically typed programming language for scientific computations with first class support for physical dimensions and units\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: numbat-{{trimV .Version}}\n        format: tar.gz\n        files:\n          - name: numbat\n            src: numbat/numbat\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v1.9.0\"\n        asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        files:\n          - name: numbat\n            src: \"{{.AssetWithoutExt}}/numbat\"\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}eabihf.{{.Format}}\n            replacements:\n              arm64: arm\n          - goos: windows\n            format: zip\n            asset: numbat-{{.Version}}-i686-{{.OS}}.{{.Format}}\n      - version_constraint: semver(\"<= 1.14.0\")\n        asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        files:\n          - name: numbat\n            src: \"{{.AssetWithoutExt}}/numbat\"\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}eabihf.{{.Format}}\n            replacements:\n              arm64: arm\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: numbat\n            src: \"{{.AssetWithoutExt}}/numbat\"\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: numbat-{{.Version}}-{{.Arch}}-{{.OS}}eabihf.{{.Format}}\n            replacements:\n              arm64: arm\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/pastel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: pastel\n    asset: pastel-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    description: A command-line tool to generate, analyze, convert and manipulate colors\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.gz\n    replacements:\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n      linux: unknown-linux-musl\n      arm64: aarch64\n      amd64: x86_64\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n    files:\n      - name: pastel\n        src: pastel-{{.Version}}-{{.Arch}}-{{.OS}}/pastel\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sharkdp/vivid/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sharkdp\n    repo_name: vivid\n    asset: vivid-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A themeable LS_COLORS generator with a rich filetype datebase\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    overrides:\n      - goos: linux\n        goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    files:\n      - name: vivid\n        src: vivid-{{.Version}}-{{.Arch}}-{{.OS}}/vivid\n    version_constraint: semver(\">= 0.8.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.8.0\")\n        overrides: []\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/fzwiki/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: fzwiki\n    description: A command line tool with fzf-like UI to search Wikipedia articles and open it in your browser quickly\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: fzwiki_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fzwiki_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: fzwiki_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fzwiki_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: fzwiki_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/gofind/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: gofind\n    description: A command line pkg.go.dev searcher and `go get` helper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: gofind_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gofind_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: gofind_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/longgopher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: longgopher\n    description: ʕ◉ϖ◉ʔ loooooooooooooooooooooong gopher\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: longgopher_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/pingu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: pingu\n    description: ping command but with pingu\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: pingu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/qiitaz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: qiitaz\n    description: A command line Qiita searcher & viewer with fuzzyfinder UI\n    asset: qiitaz_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n      386: i386\n      amd64: x86_64\n    overrides:\n      - goos: windows\n        format: zip\n    version_constraint: semver(\"!= 0.0.5\")\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\"= 0.0.5\")\n        # It seems that only v0.0.5 wasn't released with goreleaser.\n        format: tar.gz\n        replacements: {}\n        asset: qiitaz_{{.OS}}_{{.Arch}}.{{.Format}}\n        overrides:\n          - goos: darwin\n            format: zip\n          - goos: windows\n            format: zip\n        files:\n          - name: qiitaz\n            src: qiitaz_{{.OS}}_{{.Arch}}/qiitaz\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sheepla/srss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sheepla\n    repo_name: srss\n    description: A command line RSS/ATOM/JSON feed reader\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: srss_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shellspec/shellspec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: shellspec\n    repo_name: shellspec\n    description: A full-featured BDD unit testing framework for bash, ksh, zsh, dash and all POSIX shells\n    files:\n      - name: shellspec\n        src: shellspec-{{.Version}}/shellspec\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shenwei356/csvtk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shenwei356\n    repo_name: csvtk\n    asset: csvtk_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: A cross-platform, efficient and practical CSV/TSV toolkit in Golang\n    overrides:\n      - goos: windows\n        asset: csvtk_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shenwei356/rush/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shenwei356\n    repo_name: rush\n    description: A cross-platform command-line tool for executing jobs in parallel\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.2\")\n        asset: rush_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: rush_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: rush_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: rush_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shihanng/tfvar/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shihanng\n    repo_name: tfvar\n    description: Terraform's variable definitions template generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: tfvar_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfvar_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.5.0\"\n        asset: tfvar_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfvar_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: tfvar_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: tfvar_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tfvar_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfvar_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shinagawa-web/gomarklint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shinagawa-web\n    repo_name: gomarklint\n    description: A fast and configurable Markdown linter written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gomarklint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: gomarklint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shini4i/argo-compare/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shini4i\n    repo_name: argo-compare\n    description: A comparison tool for displaying the differences between ArgoCD Applications in different Git branches\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: argo-compare_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: argo-compare_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: argo-compare_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: argo-compare_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sho-hata/tparagen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sho-hata\n    repo_name: tparagen\n    description: tparagen inserts `testing.T.Parallel()` in a test function in a specific source file or in an entire directory\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: tparagen_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.1.0\"\n        type: go_install\n        path: github.com/sho-hata/tparagen/cmd/tparagen\n      - version_constraint: Version == \"v1.1.1\"\n        asset: tparagen_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: tparagen_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tparagen_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/showwin/speedtest-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: showwin\n    repo_name: speedtest-go\n    asset: speedtest-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    description: CLI and Go API to Test Internet Speed using speedtest.net\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: speedtest\n        src: speedtest-go\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/shyiko/kubesec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: shyiko\n    repo_name: kubesec\n    description: Secure Secret management for Kubernetes (with gpg, Google Cloud KMS and AWS KMS backends)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubesec-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sibprogrammer/xq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sibprogrammer\n    repo_name: xq\n    description: Command-line XML and HTML beautifier and content extractor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.0\"\n        asset: xq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.4\")\n        asset: xq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: xq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siderolabs/conform/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: siderolabs\n    repo_name: conform\n    aliases:\n      - name: talos-systems/conform\n    description: Policy enforcement for your pipelines\n    supported_envs:\n      - darwin\n      - linux\n    format: raw\n    asset: conform-{{.OS}}-{{.Arch}}\n    checksum:\n      type: github_release\n      asset: sha512sum.txt\n      algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siderolabs/omni/omni/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: siderolabs/omni/omni\n    type: github_release\n    repo_owner: siderolabs\n    repo_name: omni\n    description: SaaS-simple deployment of Kubernetes - on your own hardware\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: omni-{{.OS}}-{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siderolabs/omni/omnictl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: siderolabs/omni/omnictl\n    type: github_release\n    repo_owner: siderolabs\n    repo_name: omni\n    description: SaaS-simple deployment of Kubernetes - on your own hardware\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: omnictl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siderolabs/talos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: siderolabs\n    repo_name: talos\n    aliases:\n      - name: talos-systems/talos\n    description: Talos Linux is a modern Linux distribution built for Kubernetes\n    version_filter: not (Version matches \"-(alpha|beta|rc)\")\n    asset: talosctl-{{.OS}}-{{.Arch}}\n    format: raw\n    files:\n      - name: talosctl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.2.9\"\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha512sum.txt\n          algorithm: sha512\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: osctl-{{.OS}}-{{.Arch}}\n        files:\n          - name: osctl\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin/amd64\n      - version_constraint: semver(\"<= 0.3.3\")\n        asset: osctl-{{.OS}}-{{.Arch}}\n        files:\n          - name: osctl\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha512sum.txt\n          algorithm: sha512\n        supported_envs:\n          - linux/amd64\n          - darwin/amd64\n      - version_constraint: semver(\"<= 0.10.4\")\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin/amd64\n      - version_constraint: semver(\"<= 0.12.3\")\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.8.4\")\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.11.3\")\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/siderolabs/talos/.github/workflows/ci.yaml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n            bundle:\n              type: github_release\n              asset: sha256sum.txt.bundle\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siderolabs/theila/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: siderolabs\n    repo_name: theila\n    description: Theila is the UI for all things Sidero Labs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: theila-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigi-cli/sigi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sigi-cli\n    repo_name: sigi\n    description: Sigi - a tool for organizing\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.6.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.6.3\")\n        asset: sigi_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: sigi_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: sigi_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        checksum:\n          type: github_release\n          asset: sigi_{{.Version}}_{{.Arch}}-{{.OS}}.{{.Format}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigoden/aichat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sigoden\n    repo_name: aichat\n    description: Use GPT-4(V), Gemini, LocalAI, Ollama and other LLMs in the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: aichat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: aichat-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigstore/cosign/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sigstore\n    repo_name: cosign\n    description: Code signing and transparency for containers and binaries\n    version_filter: not (Version matches \"-dev$\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: cosign\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.2.0\"\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: cosign.sha256\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.6.0\"\n        asset: cosign_{{.OS}}_{{.Arch}}_{{trimV .Version}}_linux_amd64\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cosign_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: cosign_{{.OS}}_{{.Arch}}_{{trimV .Version}}_darwin_amd64\n          - goos: darwin\n            goarch: arm64\n            asset: cosign_{{.OS}}_{{.Arch}}_{{trimV .Version}}_darwin_arm64\n          - goos: windows\n            asset: cosign_{{.OS}}_{{.Arch}}_{{trimV .Version}}_windows_amd64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.1\")\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cosign_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cosign_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.6.1\")\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cosign_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/sigstore/cosign/releases/download/{{.Version}}/cosign_checksums.txt-keyless.pem\n              - --certificate-identity\n              - keyless@projectsigstore.iam.gserviceaccount.com\n              - --certificate-oidc-issuer\n              - https://accounts.google.com\n              - --signature\n              - https://github.com/sigstore/cosign/releases/download/{{.Version}}/cosign_checksums.txt-keyless.sig\n      - version_constraint: \"true\"\n        asset: cosign-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cosign_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: cosign_checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - keyless@projectsigstore.iam.gserviceaccount.com\n              - --certificate-oidc-issuer\n              - https://accounts.google.com\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigstore/gitsign/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sigstore\n    repo_name: gitsign\n    description: Keyless Git signing using Sigstore\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1-alpha\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gitsign_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/sigstore/gitsign/releases/download/{{.Version}}/{{.Asset}}.pem\n            - --certificate-identity\n            - https://github.com/sigstore/gitsign/.github/workflows/release.yml@refs/tags/{{.Version}}\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --signature\n            - https://github.com/sigstore/gitsign/releases/download/{{.Version}}/{{.Asset}}.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigstore/rekor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sigstore\n    repo_name: rekor\n    description: Software Supply Chain Transparency Log\n    files:\n      - name: rekor-cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.3.0\")\n        no_asset: true\n      - version_constraint: Version == \"v0.3.0\"\n        asset: rekor-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rekor-cli_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.4.0\"\n        asset: rekor-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rekor_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.4.2\")\n        asset: rekor-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rekor_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/sigstore/rekor/releases/download/{{.Version}}/rekor_checksums.txt-keyless.pem\n              - --certificate-identity\n              - keyless@projectsigstore.iam.gserviceaccount.com\n              - --certificate-oidc-issuer\n              - https://accounts.google.com\n              - --signature\n              - https://github.com/sigstore/rekor/releases/download/{{.Version}}/rekor_checksums.txt-keyless.sig\n      - version_constraint: \"true\"\n        asset: rekor-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: rekor_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: \"rekor_checksums.txt-keyless.sigstore.json\"\n            opts:\n              - --certificate-identity\n              - keyless@projectsigstore.iam.gserviceaccount.com\n              - --certificate-oidc-issuer\n              - https://accounts.google.com\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sigstore/sget/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: sigstore\n    repo_name: sget\n    description: sget is command for safer, automatic verification of signatures and integration with Sigstore's binary transparency log, Rekor\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/siketyan/ghr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: siketyan\n    repo_name: ghr\n    description: Yet another repository management with auto-attaching profiles\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: ghr-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/simeji/jid/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: simeji\n    repo_name: jid\n    asset: jid_{{.OS}}_{{.Arch}}.zip\n    description: json incremental digger\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/simonwhitaker/gibo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: simonwhitaker\n    repo_name: gibo\n    description: Easy access to gitignore boilerplates\n    asset: gibo_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    overrides:\n      - goos: windows\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.windows.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sinclairtarget/git-who/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sinclairtarget\n    repo_name: git-who\n    description: Git blame for file trees\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2\"\n        asset: \"{{.OS}}_{{.Arch}}.{{.Format}}\"\n        format: tar.gz\n        files:\n          - name: git-who\n            src: \"{{.OS}}_{{.Arch}}/git-who\"\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: gitwho_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: git-who\n            src: \"{{.OS}}_{{.Arch}}/git-who\"\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sirrend/terrap-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sirrend\n    repo_name: terrap-cli\n    description: Terrap - a powerful CLI tool that scans your infrastructure and identifies any required changes\n    asset: terrap-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: terrap\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sirwart/ripsecrets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sirwart\n    repo_name: ripsecrets\n    description: A command-line tool to prevent committing secret keys into your source code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.2\"\n        asset: secrets-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: ripsecrets\n            src: secrets-{{trimV .Version}}-{{.Arch}}-{{.OS}}/secrets\n      - version_constraint: \"true\"\n        asset: ripsecrets-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin\n        files:\n          - name: ripsecrets\n            src: ripsecrets-{{trimV .Version}}-{{.Arch}}-{{.OS}}/ripsecrets\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sivchari/ccowl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sivchari\n    repo_name: ccowl\n    description: A cross-platform status bar application that monitors Claude Code usage in real-time\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: ccowl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: ccowl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: ccowl\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n            asset: ccowl-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/six-ddc/plow/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: six-ddc\n    repo_name: plow\n    description: A high-performance HTTP benchmarking tool that includes a real-time web UI and terminal display\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: plow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: plow_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: plow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: plow_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: plow_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: plow_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sj14/kubedump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sj14\n    repo_name: kubedump\n    description: Tool for dumping manifests from your Kubernetes clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: kubedump_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skaji/relocatable-perl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skaji\n    repo_name: relocatable-perl\n    description: self-contained, portable perl binaries\n    files:\n      - name: perl\n        src: \"{{.AssetWithoutExt}}/bin/perl\"\n      - name: cpanm\n        src: \"{{.AssetWithoutExt}}/bin/cpanm\"\n      - name: perldoc\n        src: \"{{.AssetWithoutExt}}/bin/perldoc\"\n      - name: prove\n        src: \"{{.AssetWithoutExt}}/bin/prove\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 5.34.1.0\")\n        asset: perl-{{.OS}}-2level.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            asset: perl-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 5.36.0.0\")\n        asset: perl-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n          - goos: darwin\n            asset: perl-{{.OS}}-2level.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: perl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/ghost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: ghost\n    description: Simple background process manager for Unix systems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: ghost_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: ghost_{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/gjo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: gjo\n    description: Small utility to create JSON objects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0.0\"\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: zip\n        replacements:\n          darwin: MacOS\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: \"{{.OS}}.{{.Format}}\"\n        format: zip\n        replacements:\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/rtty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: rtty\n    description: Terminal on browser via websocket\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: rtty_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: rtty_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: rtty_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: rtty_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/slack-reminder/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: slack-reminder\n    description: Slack remind generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: slack-reminder_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: slack-reminder_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/tson/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: tson\n    description: TUI json editor and viewer written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tson_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skanehira/yd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skanehira\n    repo_name: yd\n    description: YAML Incremental Digger\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yd_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: yd\n            src: \"{{.AssetWithoutExt}}/yd\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skeema/skeema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skeema\n    repo_name: skeema\n    description: Declarative pure-SQL schema management for MySQL and MariaDB (Community Edition)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: skeema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: skeema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.0.1\"\n        asset: skeema_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: Mac\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: skeema_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.3\")\n        asset: skeema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: skeema_checksums_{{trimV .Version}}.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.6.0\"\n        asset: skeema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: skeema_checksums_{{trimV .Version}}.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: skeema_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: mac\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: skeema_checksums_{{trimV .Version}}.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/skim-rs/skim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: skim-rs\n    repo_name: skim\n    description: Fuzzy Finder in rust\n    aliases:\n      - name: lotabout/skim\n    files:\n      - name: sk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1-alpha\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.4\"\n        asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.9\")\n        asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}eabi.{{.Format}}\n            replacements:\n              arm64: arm\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.9.3\")\n        asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            asset: skim-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: arm\n              linux: unknown-linux-gnueabi\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.10.4\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.14.3\")\n        asset: skim-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.15.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.20.5\")\n        asset: skim-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: skim-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: sk\n            src: \"{{.AssetWithoutExt}}/sk\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sl1pm4t/k2tf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sl1pm4t\n    repo_name: k2tf\n    description: Kubernetes YAML to Terraform HCL converter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: k2tf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: k2tf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: k2tf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slack.com/slack-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    name: slack.com/slack-cli\n    description: Slack CLI allows you to interact with your workflow apps via the command line\n    link: https://api.slack.com/automation/cli/commands\n    url: https://downloads.slack-edge.com/slack-cli/slack_cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    rosetta2: true\n    windows_arm_emulation: true\n    files:\n      - name: slack\n        src: bin/slack\n    replacements:\n      amd64: 64-bit\n      darwin: macOS\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - linux/amd64\n      - windows\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slackhq/nebula/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: slackhq\n    repo_name: nebula\n    description: A scalable overlay networking tool with a focus on performance, simplicity and security\n    files:\n      - name: nebula\n      - name: nebula-cert\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: nebula-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v1.4.0\"\n        asset: nebula-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: nebula-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.5.2\")\n        asset: nebula-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            asset: nebula-{{.OS}}.{{.Format}}\n      - version_constraint: \"true\"\n        asset: nebula-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: darwin\n            asset: nebula-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slok/agebox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: slok\n    repo_name: agebox\n    description: Age based repository file encryption gitops tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: agebox-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slok/sloth/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: slok\n    repo_name: sloth\n    description: Easy and simple Prometheus SLO (service level objectives) generator\n    version_filter: not Version startsWith \"sloth-helm-chart-\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sloth-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slsa-framework/slsa-github-generator/slsa-builder-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: slsa-framework/slsa-github-generator/slsa-builder-go\n    repo_owner: slsa-framework\n    repo_name: slsa-github-generator\n    description: builds and generates SLSA3+ provenance for Go projects\n    link: https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/go\n    # Officially only an asset for linux/amd64 is released.\n    # So we support other platforms by `go_install` package.\n    type: go_install\n    path: github.com/slsa-framework/slsa-github-generator/internal/builders/go\n    files:\n      - name: slsa-builder-go\n    overrides:\n      - goos: linux\n        goarch: amd64\n        type: github_release\n        asset: slsa-builder-go-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/slsa-framework/slsa-verifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: slsa-framework\n    repo_name: slsa-verifier\n    description: Verify provenance from SLSA compliant builders\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.4.0\"\n        type: go_install\n        path: github.com/slsa-framework/slsa-verifier/cli/slsa-verifier\n      - version_constraint: semver(\"<= 1.3.2\")\n        type: go_install\n        path: github.com/slsa-framework/slsa-verifier/cli/slsa-verifier\n        overrides:\n          - goos: linux\n            goarch: amd64\n            type: github_release\n            asset: slsa-verifier-{{.OS}}-{{.Arch}}\n            format: raw\n            slsa_provenance:\n              type: github_release\n              asset: slsa-verifier-{{.OS}}-{{.Arch}}.intoto.jsonl\n      - version_constraint: semver(\"<= 2.0.1\")\n        type: go_install\n        path: github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier\n        overrides:\n          - goos: linux\n            goarch: amd64\n            type: github_release\n            asset: slsa-verifier-{{.OS}}-{{.Arch}}\n            format: raw\n            slsa_provenance:\n              type: github_release\n              asset: slsa-verifier-{{.OS}}-{{.Arch}}.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: slsa-verifier-{{.OS}}-{{.Arch}}\n        format: raw\n        slsa_provenance:\n          type: github_release\n          asset: \"{{.Asset}}.intoto.jsonl\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/smallstep/certificates/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: smallstep\n    repo_name: certificates\n    description: A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH\n    version_filter: not (Version matches \"-rc\")\n    files:\n      - name: step-ca\n        src: step-ca_{{.OS}}_{{.Arch}}/step-ca\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.15.1\", \"v0.17.5\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.13.3\")\n        asset: step-certificates_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-certificates_{{trimV .Version}}/bin/step-ca\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: step-certificates_{{.OS}}_{{trimV .Version}}-dev_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-certificates_{{trimV .Version}}-dev/bin/step-ca\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.15.8\")\n        asset: step-certificates_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-certificates_{{trimV .Version}}/bin/step-ca\n        rosetta2: true\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.15.15\")\n        asset: step-ca_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-ca_{{trimV .Version}}/bin/step-ca\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.17.2\")\n        asset: step-ca_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-ca_{{trimV .Version}}/bin/step-ca\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.17.4\")\n        asset: step-ca_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-ca_{{trimV .Version}}/bin/step-ca\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.22.1\")\n        asset: step-ca_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-ca_{{trimV .Version}}/bin/step-ca\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.24.2\")\n        asset: step-ca_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step-ca\n            src: step-ca_{{trimV .Version}}/step-ca\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/smallstep/certificates/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/smallstep/certificates/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/smallstep/certificates/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: step-ca_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/smallstep/certificates/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/smallstep/workflows/.github/workflows/goreleaser.yml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/smallstep/certificates/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/smallstep/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: smallstep\n    repo_name: cli\n    description: A zero trust swiss army knife for working with X509, OAuth, JWT, OATH OTP, etc\n    version_filter: not (Version matches \"-rc[0-9.]+$\")\n    files:\n      - name: step\n        src: step_{{.OS}}_{{.Arch}}/bin/step\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.15.1\", \"v0.27.0\", \"v0.28.1\", \"v0.28.4\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.1\"\n        asset: step_{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.14.0\"\n        asset: step_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v0.14.1\"\n        asset: step_{{.OS}}_{{trimV .Version}}-dev_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}-dev/bin/step\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.13.3\")\n        asset: step_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.15.3\")\n        asset: step_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.17.6\")\n        asset: step_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: step_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.24.4\")\n        asset: step_{{.OS}}_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: step\n            src: step_{{trimV .Version}}/bin/step\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/smallstep/cli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/smallstep/cli/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/smallstep/cli/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: step_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/smallstep/cli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/smallstep/workflows/.github/workflows/goreleaser.yml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/smallstep/cli/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/smartxworks/knest/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: smartxworks\n    repo_name: knest\n    description: Kubernetes-in-Kubernetes Made Simple\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: knest\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: knest-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/smithy-lang/smithy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: smithy-lang\n    repo_name: smithy\n    description: Smithy is a protocol-agnostic interface definition language and set of tools for generating clients, servers, and documentation for any programming language\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.47.0\")\n        asset: smithy-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: smithy\n            src: bin/smithy\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            replacements:\n              amd64: x64\n      - version_constraint: \"true\"\n        asset: smithy-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: smithy\n            src: smithy-cli-{{.OS}}-{{.Arch}}/bin/smithy\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            replacements:\n              amd64: x64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/smtg-ai/claude-squad/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: smtg-ai\n    repo_name: claude-squad\n    description: Manage multiple AI agents like Claude Code, Aider, Codex, and Amp. 10x your productivity\n    files:\n      - name: cs\n      - name: claude-squad\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: claude-squad_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: claude-squad\n          - name: cs\n            src: claude-squad\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/snaplet/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: snaplet/cli\n    type: http\n    description: Seed your PostgreSQL database with production-like data so you can code, debug, and test with ease\n    link: https://www.snaplet.dev/\n    # See https://app.snaplet.dev/get-cli/ for URL structure\n    url: https://snaplet-public.s3-accelerate.amazonaws.com/cli/beta/snaplet-{{.OS}}-{{.Arch}}-{{.Version}}\n    overrides:\n      - goos: darwin\n        goarch: arm64\n        replacements:\n          arm64: x64\n    supported_envs:\n      - linux\n      - darwin\n      - windows/amd64\n    replacements:\n      windows: win\n      darwin: macos\n      amd64: x64\n    files:\n      - name: snaplet\n    format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/snyk/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: snyk\n    repo_name: cli\n    description: Snyk CLI scans and monitors your projects for security vulnerabilities\n    files:\n      - name: snyk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1036.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.850.0\")\n        asset: snyk-{{.OS}}\n        format: raw\n        replacements:\n          windows: win\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1229.0\")\n        asset: snyk-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          windows: win\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: snyk-{{.OS}}-{{.Arch}}\n      - version_constraint: \"true\"\n        asset: snyk-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n          windows: win\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: snyk-{{.OS}}-{{.Arch}}\n          - goos: darwin\n            goarch: arm64\n            asset: snyk-{{.OS}}-{{.Arch}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/snyk/driftctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: snyk\n    repo_name: driftctl\n    description: Detect, track and alert on infrastructure drift\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.0\"\n        asset: driftctl_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: driftctl_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: driftctl_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.18.5\")\n        asset: driftctl_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: driftctl_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: driftctl_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: driftctl_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/snyk/parlay/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: snyk\n    repo_name: parlay\n    description: Enrich SBOMs with data from third party services\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: parlay_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: parlay_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/so-dang-cool/dt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: so-dang-cool\n    repo_name: dt\n    description: \"dt - duct tape for your unix pipes\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: \"{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tgz\n        files:\n          - name: dt\n            src: \"{{.AssetWithoutExt}}/bin/dt\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: linux-gnu\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.2.3\")\n        asset: \"{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n          linux: linux-gnu\n        overrides:\n          - goos: darwin\n            asset: \"{{.Arch}}-{{.OS}}-none.{{.Format}}\"\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.3.0\")\n        asset: dt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n          linux: linux-gnu\n        overrides:\n          - goos: darwin\n            asset: dt-{{.Arch}}-{{.OS}}-none.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: dt-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n          linux: linux-gnu\n        overrides:\n          - goos: darwin\n            asset: dt-{{.Arch}}-{{.OS}}-none.{{.Format}}\n          - goos: windows\n            asset: dt-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n            replacements: {}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/so-dang-cool/fib/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: so-dang-cool\n    repo_name: fib\n    description: A Fibonacci CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1\"\n        asset: fib\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.1.2.3\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: fib-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/so-dang-cool/findup/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: so-dang-cool\n    repo_name: findup\n    description: Find parent directories\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.1\"\n        asset: \"{{.Arch}}-{{.OS}}.{{.Format}}\"\n        format: tgz\n        files:\n          - name: findup\n            src: \"{{.AssetWithoutExt}}/bin/findup\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: linux-gnu\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: findup-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n          linux: linux-gnu\n        overrides:\n          - goos: darwin\n            asset: findup-{{.Arch}}-{{.OS}}-none.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/so-dang-cool/yn/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: so-dang-cool\n    repo_name: yn\n    files:\n      - name: Yn\n      - name: yN\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yn-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tgz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n          linux: linux-gnu\n        overrides:\n          - goos: darwin\n            asset: yn-{{.Arch}}-{{.OS}}-none.{{.Format}}\n            files:\n              - name: Yn\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/soh335/shukujitsu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: soh335\n    repo_name: shukujitsu\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.8\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: shukujitsu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/solidiquis/erdtree/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: solidiquis\n    repo_name: erdtree\n    description: A modern, cross-platform, multi-threaded, and general purpose filesystem and disk-usage utility that is aware of .gitignore and hidden file rules\n    files:\n      - name: erd\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0\"\n        asset: et-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: et\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            asset: et-{{.Arch}}-{{.OS}}\n      - version_constraint: Version == \"v1.6.0\"\n        asset: et-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: et\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: semver(\"<= 1.8.1\")\n        asset: et-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: et\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: raw\n            asset: et-{{.Version}}-{{.Arch}}-{{.OS}}\n      - version_constraint: \"true\"\n        asset: erd-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: raw\n            asset: erd-{{.Version}}-{{.Arch}}-{{.OS}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sonatype-nexus-community/nancy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sonatype-nexus-community\n    repo_name: nancy\n    description: A tool to check for vulnerabilities in your Golang dependencies, powered by Sonatype OSS Index\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.19\"\n        asset: nancy-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nancychecksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.44\")\n        asset: nancy-{{.OS}}.{{.Arch}}-{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: nancy-{{.OS}}.{{.Arch}}-{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nancychecksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: nancy-{{.OS}}.{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nancychecksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.17\")\n        asset: nancy-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nancychecksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: nancy-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: nancychecksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sorah/mairu/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sorah\n    repo_name: mairu\n    description: on-memory AWS credentials agent and executor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mairu-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            goarch: amd64\n            asset: mairu-universal-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sorenisanerd/gotty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sorenisanerd\n    repo_name: gotty\n    description: Share your terminal as a web application\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.1.0\"\n        asset: gotty_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.2.0\"\n        asset: gotty_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: gotty_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sourcegraph/src-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sourcegraph\n    repo_name: src-cli\n    description: Sourcegraph CLI\n    asset: src-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    files:\n      - name: src\n    checksum:\n      type: github_release\n      asset: src-cli_{{.Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 3.31.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 3.30.4\")\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 3.10.9\")\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\"< 3.10.9\")\n        asset: src_{{.OS}}_{{.Arch}}\n        format: raw\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sourcemeta/jsonschema/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sourcemeta\n    repo_name: jsonschema\n    description: The CLI for working with JSON Schema. Covers formatting, linting, testing, bundling, and more for both local development and CI/CD pipelines\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"continuous\"\n        error_message: \"The version 'continuous' is not supported. Please use a specific version.\"\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: jsonschema-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: jsonschema\n            src: \"{{.AssetWithoutExt}}/bin/jsonschema\"\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n          - windows\n      - version_constraint: semver(\"<= 7.2.2\")\n        asset: jsonschema-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: jsonschema\n            src: \"{{.AssetWithoutExt}}/bin/jsonschema\"\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 7.3.0\")\n        asset: jsonschema-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: jsonschema\n            src: \"{{.AssetWithoutExt}}/bin/jsonschema\"\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: jsonschema-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: jsonschema\n            src: \"{{.AssetWithoutExt}}/bin/jsonschema\"\n        replacements:\n          amd64: x86_64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/spacelift-io/spacectl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: spacelift-io\n    repo_name: spacectl\n    description: Spacelift client and CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: spacelift-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n        files:\n          - name: spacelift-cli\n            src: \"{{.AssetWithoutExt}}\"\n      - version_constraint: Version == \"v0.2.0\"\n        asset: spacectl-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: spacectl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: spacectl_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: spacectl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: spacectl_{{trimV .Version}}_SHA256SUMS\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/speakeasy-api/speakeasy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: speakeasy-api\n    repo_name: speakeasy\n    description: Build APIs your users love  with Speakeasy.  Polished and type-safe SDKs.  Terraform providers and Contract Tests for your API. OpenAPI native\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: speakeasy_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/specstoryai/getspecstory/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: specstoryai\n    repo_name: getspecstory\n    description: Install our extensions for GH Copilot, Cursor and Claude Code. Try BearClaude. File issues and requests\n    files:\n      - name: specstory\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: SpecStoryCLI_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: SpecStoryCLI_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/spf13/cobra-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: spf13\n    repo_name: cobra-cli\n    description: Cobra CLI tool to generate applications and commands\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/spinel-coop/rv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: spinel-coop\n    repo_name: rv\n    description: Next-gen very fast Ruby tooling\n    version_constraint: \"false\"\n    files:\n      - name: rv\n        src: rv-{{.Arch}}-{{.OS}}/rv\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: rv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.5.2\")\n        asset: rv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: rv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        github_artifact_attestations:\n          signer_workflow: spinel-coop/rv/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/spinnaker/spin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: spinnaker/spin\n    type: http\n    format: raw\n    repo_owner: spinnaker\n    repo_name: spin\n    rosetta2: true\n    url: https://storage.googleapis.com/spinnaker-artifacts/spin/{{trimV .Version}}/{{.OS}}/{{.Arch}}/spin\n    description: Spinnaker CLI\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: spin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/spotDL/spotify-downloader/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: spotDL\n    repo_name: spotify-downloader\n    description: Download your Spotify playlists and songs along with album art and metadata (from YouTube if a match is found)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v3.2.1\", \"v3.3.2\", \"v3.4.0\", \"v3.4.2\", \"v3.3.3\", \"v3.4.1\", \"v3.5.0\", \"v3.6.1\"]\n        no_asset: true\n      - version_constraint: Version == \"v3.1.0\"\n        asset: spotDL.{{.OS}}\n        format: raw\n        replacements:\n          windows: win64\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v4.0.0rc1\"\n        asset: spotdl-4.0.0-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: spotdl-4.0.0-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v4.0.0\"\n        asset: spotdl-{{trimV .Version}}-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v4.0.3\"\n        asset: spotdl-4.0.2-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: spotdl-4.0.2-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v4.2.3\"\n        asset: spotdl-4.2.2-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 3.9.6\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.0.5\")\n        asset: spotdl-{{trimV .Version}}-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: spotdl-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 4.2.2\")\n        asset: spotdl-{{trimV .Version}}-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 4.2.5\")\n        asset: spotdl-{{trimV .Version}}-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: spotdl-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: spotdl-{{trimV .Version}}-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqlc-dev/sqlc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sqlc-dev\n    repo_name: sqlc\n    aliases:\n      - name: kyleconroy/sqlc\n    description: Generate type-safe code from SQL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: sqlc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: sqlc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: sqlc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.8.0\")\n        asset: sqlc-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.15.0\")\n        asset: sqlc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.17.0\")\n        asset: sqlc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.17.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.24.0\")\n        asset: sqlc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        type: http\n        url: https://downloads.sqlc.dev/sqlc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqldef/sqldef/mssqldef/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: sqldef/sqldef/mssqldef\n    aliases:\n      - name: k0kubun/sqldef/mssqldef\n    type: github_release\n    repo_owner: sqldef\n    repo_name: sqldef\n    description: Idempotent schema management for Microsoft SQL Server\n    asset: mssqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: mssqldef\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqldef/sqldef/mysqldef/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: sqldef/sqldef/mysqldef\n    aliases:\n      - name: k0kubun/sqldef/mysqldef\n    type: github_release\n    repo_owner: sqldef\n    repo_name: sqldef\n    description: Idempotent schema management for MySQL\n    asset: mysqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: mysqldef\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    version_constraint: semver(\">= 0.9.1\")\n    # darwin/arm64 is supported\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    version_overrides:\n      - version_constraint: semver(\">= 0.1.1\")\n        rosetta2: true\n        # windows/amd64 is supported\n        # linux/arm64 is supported\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqldef/sqldef/psqldef/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: sqldef/sqldef/psqldef\n    type: github_release\n    repo_owner: sqldef\n    repo_name: sqldef\n    description: Idempotent schema management for PostgreSQL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: psqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        overrides:\n          - goos: darwin\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: psqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.12.8\")\n        asset: psqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 0.17.19\")\n        asset: psqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: psqldef_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqldef/sqldef/sqlite3def/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: sqldef/sqldef/sqlite3def\n    aliases:\n      - name: k0kubun/sqldef/sqlite3def\n    type: github_release\n    repo_owner: sqldef\n    repo_name: sqldef\n    description: Idempotent schema management for SQLite3\n    asset: sqlite3def_{{.OS}}_{{.Arch}}.{{.Format}}\n    files:\n      - name: sqlite3def\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqls-server/sqls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sqls-server\n    repo_name: sqls\n    description: SQL language server written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: sqls-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        files:\n          - name: sqls\n            src: \"{{.OS}}-{{.Arch}}/sqls\"\n      - version_constraint: semver(\"<= 0.2.20\")\n        asset: sqls_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: sqls-{{.OS}}-{{trimV .Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sqshq/sampler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sqshq\n    repo_name: sampler\n    description: Tool for shell commands execution, visualization and alerting. Configured with a simple YAML file\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.9.0-beta\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.1-beta\"\n        asset: sampler-0.9.1-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v1.0.0\"\n        asset: sampler-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.0.1\"\n        asset: sampler-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: sampler-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/square/certigo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: square\n    repo_name: certigo\n    description: A utility to examine and validate certificates in a variety of formats\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.13.0\"\n        asset: certigo-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.11.0\")\n        asset: certigo-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.12.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: certigo-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/squat/kilo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: squat\n    repo_name: kilo\n    description: Kilo is a multi-cloud network overlay built on WireGuard and designed for Kubernetes (k8s + wg = kg)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"0.2.0\"\n        asset: kgctl-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n      - version_constraint: \"true\"\n        asset: kgctl-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sr.ht/~charles/rq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: sr.ht/~charles/rq\n    type: http\n    description: |\n      rq (Rego Query) is inspired by jq, and aims to offer a similar set of capabilities oriented around running Rego queries\n    link: https://sr.ht/~charles/rq/\n    url: https://git.sr.ht/~charles/rq/refs/download/{{.Version}}/rq-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n    format: gz\n    files:\n      - name: rq\n        src: \"{{.AssetWithoutExt}}\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/srevinsaju/togomak/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: srevinsaju\n    repo_name: togomak\n    description: A declarative pipeline orchestrator with the magic of HCL as a configuration language, inspired from Terraform's architecture\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.1-alpha.5\")\n        asset: togomak_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: togomak_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"0.0.3\"\n        asset: togomak_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: togomak_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: togomak_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: togomak_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/srl-labs/containerlab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: srl-labs\n    repo_name: containerlab\n    description: container-based networking labs\n    version_filter: semver(\">= 0.1.0\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.1\"\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: container-lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: container-lab\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.10.4\")\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 0.20.1\")\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.53.0\")\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: containerlab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sstadick/crabz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sstadick\n    repo_name: crabz\n    description: Like pigz, but rust\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.7.0\", \"v0.7.6\"]\n        asset: crabz-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: crabz-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: crabz-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stacklok/frizbee/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stacklok\n    repo_name: frizbee\n    description: Throw a tag at it and it comes back with a checksum\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: frizbee_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: frizbee_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.1.5\"\n        asset: frizbee_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: frizbee_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.1.6\"\n        asset: frizbee_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: frizbee_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/stacklok/frizbee/releases/download/{{.Version}}/{{.AssetWithoutExt}}.pem\n            - --certificate-identity\n            - https://github.com/stacklok/frizbee/.github/workflows/releaser.yml@refs/tags/{{.Version}}\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n            - --signature\n            - https://github.com/stacklok/frizbee/releases/download/{{.Version}}/{{.Asset}}.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: frizbee_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: frizbee_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stackrox/kube-linter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stackrox\n    repo_name: kube-linter\n    description: KubeLinter is a static analysis tool that checks Kubernetes YAML files and Helm charts to ensure the applications represented in them adhere to best practices\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.0.1\", \"v0.8.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.6.8\"\n        asset: kube-linter-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: darwin\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: windows\n            goarch: amd64\n            asset: kube-linter\n          - goos: windows\n            goarch: arm64\n            asset: kube-linter_{{.Arch}}\n        cosign:\n          opts:\n            - --key\n            - https://raw.githubusercontent.com/stackrox/kube-linter/refs/tags/{{.Version}}/kubelinter-cosign.pub\n            - --signature\n            - https://github.com/stackrox/kube-linter/releases/download/{{.Version}}/{{.Asset}}.sig\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: kube-linter-{{.OS}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.7\")\n        asset: kube-linter-{{.OS}}\n        format: raw\n        overrides:\n          - goos: windows\n            asset: kube-linter\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        cosign:\n          opts:\n            - --key\n            - https://raw.githubusercontent.com/stackrox/kube-linter/refs/tags/{{.Version}}/kubelinter-cosign.pub\n            - --signature\n            - https://github.com/stackrox/kube-linter/releases/download/{{.Version}}/{{.Asset}}.sig\n      - version_constraint: semver(\"<= 0.7.6\")\n        asset: kube-linter-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: darwin\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: windows\n            goarch: amd64\n            asset: kube-linter\n          - goos: windows\n            goarch: arm64\n            asset: kube-linter_{{.Arch}}\n        cosign:\n          opts:\n            - --key\n            - https://raw.githubusercontent.com/stackrox/kube-linter/refs/tags/{{.Version}}/kubelinter-cosign.pub\n            - --signature\n            - https://github.com/stackrox/kube-linter/releases/download/{{.Version}}/{{.Asset}}.sig\n      - version_constraint: \"true\"\n        asset: kube-linter-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: darwin\n            goarch: arm64\n            asset: kube-linter-{{.OS}}_{{.Arch}}\n          - goos: windows\n            goarch: amd64\n            asset: kube-linter\n          - goos: windows\n            goarch: arm64\n            asset: kube-linter_{{.Arch}}\n        cosign:\n          bundle:\n            type: github_release\n            asset: \"{{.Asset}}.sigstore.json\"\n          opts:\n            - --key\n            - https://raw.githubusercontent.com/stackrox/kube-linter/refs/tags/{{.Version}}/kubelinter-cosign.pub\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stackrox/stackrox/roxctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: stackrox\n    repo_name: stackrox\n    name: stackrox/stackrox/roxctl\n    description: CLI for StackRox Kubernetes Security Platform\n    link: https://www.stackrox.io/\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.4.8\")\n        url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/{{.OS}}/roxctl\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n        checksum:\n          type: http\n          url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/{{.OS}}/sha256sum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/{{.OS}}/roxctl\n        format: raw\n        overrides:\n          - goos: windows\n            url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/windows/roxctl.exe\n          - goarch: arm64\n            url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/{{.OS}}/roxctl-arm64\n        checksum:\n          type: http\n          url: https://mirror.openshift.com/pub/rhacs/assets/{{.Version}}/bin/{{.OS}}/sha256sum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/starship/starship/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: starship\n    repo_name: starship\n    description: The minimal, blazing-fast, and infinitely customizable prompt for any shell\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.14.0\", \"v0.32.0\", \"v0.35.0\", \"v0.37.1\", \"v0.41.2\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.31.0\"\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.39.0\"\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.20.0\"\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux\n          - windows\n      - version_constraint: Version == \"v1.22.0\"\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: starship-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: starship\n            src: \"{{.Arch}}-{{.OS}}/starship\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.8.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: starship-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: starship\n            src: \"{{.Arch}}-{{.OS}}/starship\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: starship-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: starship\n            src: \"{{.Arch}}-{{.OS}}/starship\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.26.2\")\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: starship\n            src: target/{{.Arch}}-{{.OS}}/release/starship\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.26.4\")\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.48.0\")\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.50.0\")\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: starship-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/static-web-server/static-web-server/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: static-web-server\n    repo_name: static-web-server\n    description: A cross-platform, high-performance and asynchronous web server for static files-serving\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"1.0.0-beta.4\"\n        no_asset: true\n      - version_constraint: Version == \"1.0.0-beta.2\"\n        asset: static-web-server-v{{.Version}}-{{.Arch}}-x86_64-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: static-web-server-v{{.Version}}-{{.Arch}}-x86_64-{{.OS}}-sha1sum.txt\n          algorithm: sha1\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"1.0.0-beta.3\"\n        asset: static-web-server-v{{.Version}}-{{.Arch}}-x86_64-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: md5sum.txt\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v2.0.0-beta.5\"\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: static-web-server\n            src: \"{{.AssetWithoutExt}}/static-web-server\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-x86_64-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: md5sum.txt\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}-SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.13.0\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.16.0\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.19.4\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: static-web-server\n            src: \"{{.AssetWithoutExt}}/static-web-server\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.0-beta.4\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.23.0\")\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: static-web-server\n            src: \"{{.AssetWithoutExt}}/static-web-server\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: static-web-server-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: static-web-server\n            src: \"{{.AssetWithoutExt}}/static-web-server\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: static-web-server-{{.Version}}-SHA256SUM\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stefanprodan/timoni/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stefanprodan\n    repo_name: timoni\n    description: Timoni is a package manager for Kubernetes, powered by CUE and inspired by Helm\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.7.1\")\n        asset: timoni_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: timoni_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 0.10.0\")\n        asset: timoni_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: timoni_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: timoni_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          type: github_release\n          asset: timoni_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: timoni_{{trimV .Version}}_provenance.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/steipete/gogcli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: steipete\n    repo_name: gogcli\n    description: \"Google Suite CLI: Gmail, GCal, GDrive, GContacts\"\n    files:\n      - name: gog\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: gogcli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: gog\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gogcli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: gog\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stepchowfun/docuum/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stepchowfun\n    repo_name: docuum\n    description: Docuum performs least recently used (LRU) eviction of Docker images\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.22.1\"\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.22.2\"\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n      - version_constraint: Version == \"v0.22.3\"\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.22.0\")\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: docuum-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stern/stern/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stern\n    repo_name: stern\n    description: \"⎈ Multi pod and container log tailing for Kubernetes -- Friendly fork of https://github.com/wercker/stern\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.20.1\"\n        asset: stern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: stern\n            src: \"{{.AssetWithoutExt}}/stern\"\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.14.0\")\n        asset: stern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: stern\n            src: \"{{.AssetWithoutExt}}/stern\"\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.20.0\")\n        asset: stern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: stern\n            src: \"{{.AssetWithoutExt}}/stern\"\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: stern_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/steveyegge/beads/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: steveyegge\n    repo_name: beads\n    description: \"Beads - A memory upgrade for your coding agent\"\n    files:\n      - name: bd\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.11\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.21.9\")\n        asset: beads_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.24.3\")\n        asset: beads_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: beads_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stoplightio/spectral/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stoplightio\n    repo_name: spectral\n    description: A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI (v3.1, v3.0, and v2.0), Arazzo v1.0, as well as AsyncAPI v2.x\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v4.0.0-beta.7\"\n        asset: spectral-cli\n        format: raw\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v4.2.0-beta5\"\n        asset: spectral-cli\n        format: raw\n        supported_envs:\n          - windows/amd64\n      - version_constraint: Version == \"v4.2.0\"\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral-cli\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v5.4.0-beta1\"\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v6.7.0\"\n        asset: spectral-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.1.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 4.0.0-beta.6\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 4.1.0-beta2\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral-cli\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 4.1.0\")\n        asset: spectral-cli\n        format: raw\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 4.2.0-beta4\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral-cli\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 5.0.0-beta3\")\n        asset: spectral-cli\n        format: raw\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 5.5.0-beta3\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral-cli\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 5.5.0-beta5\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 6.2.1\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral-cli\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 6.6.0\")\n        asset: spectral-{{.OS}}\n        format: raw\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: spectral-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: spectral\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/str4d/age-plugin-yubikey/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: str4d\n    repo_name: age-plugin-yubikey\n    description: YubiKey plugin for age\n    version_constraint: \"false\"\n    files:\n      - name: age-plugin-yubikey\n        src: age-plugin-yubikey/age-plugin-yubikey\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: age-plugin-yubikey-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: age-plugin-yubikey-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: \"true\"\n        asset: age-plugin-yubikey-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin/arm64\n          - linux/amd64\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/str4d/rage/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: str4d\n    repo_name: rage\n    description: A simple, secure and modern file encryption tool (and Rust library) with small explicit keys, no config options, and UNIX-style composability\n    files:\n      - name: rage\n        src: rage/{{.FileName}}\n      - name: rage-keygen\n        src: rage/{{.FileName}}\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.1\"\n        asset: rage-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: linux\n            goarch: amd64\n            files:\n              - name: rage\n                src: rage/{{.FileName}}\n              - name: rage-keygen\n                src: rage/{{.FileName}}\n              - name: rage-mount\n                src: rage/{{.FileName}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: rage-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: linux\n            goarch: amd64\n            files:\n              - name: rage\n                src: rage/{{.FileName}}\n              - name: rage-keygen\n                src: rage/{{.FileName}}\n              - name: rage-mount\n                src: rage/{{.FileName}}\n      - version_constraint: \"true\"\n        asset: rage-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n          - goos: linux\n            goarch: amd64\n            files:\n              - name: rage\n                src: rage/{{.FileName}}\n              - name: rage-keygen\n                src: rage/{{.FileName}}\n              - name: rage-mount\n                src: rage/{{.FileName}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/streamdal/plumber/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: streamdal\n    repo_name: plumber\n    aliases:\n      - name: batchcorp/plumber\n    description: A swiss army knife CLI tool for interacting with Kafka, RabbitMQ and other messaging systems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        asset: plumber-{{.OS}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: plumber-{{.OS}}\n        format: raw\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: plumber-{{.OS}}\n        format: raw\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: plumber-{{.OS}}-{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stripe/stripe-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stripe\n    repo_name: stripe-cli\n    description: A command-line tool for Stripe\n    files:\n      - name: stripe\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.5.10\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac-os\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            checksum:\n              type: github_release\n              asset: stripe-checksums.txt\n              algorithm: sha256\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.7.2\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: stripe_{{trimV .Version}}_{{.OS}}-os_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.7.5\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: Version == \"v1.7.6\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: stripe_{{trimV .Version}}_{{.OS}}-os_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v1.7.7\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - windows\n      - version_constraint: Version == \"v1.13.2\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: tar.gz\n            asset: stripe_{{trimV .Version}}_{{.OS}}-os_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 0.8.2\")\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac-os\n        checksum:\n          type: github_release\n          asset: stripe-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.5.9\")\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac-os\n        checksum:\n          type: github_release\n          asset: stripe-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.12.3\")\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: stripe_{{trimV .Version}}_{{.OS}}-os_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: stripe_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: stripe-{{.OS}}-checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: stripe_{{trimV .Version}}_{{.OS}}-os_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/stunnel/static-curl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: stunnel\n    repo_name: static-curl\n    description: static builds cURL with HTTP3\n    files:\n      - name: curl\n      - name: curl-config\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"8.6.0-1\"\n        asset: curl-{{.OS}}-{{.Arch}}-8.6.0.{{.Format}}\n        format: tar.xz\n        files:\n          - name: curl\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm64\n      - version_constraint: Version == \"8.6.0\"\n        asset: curl-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: curl\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 8.2.0\")\n        asset: curl-static-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: curl\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 8.5.0\")\n        asset: curl-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: curl\n        replacements:\n          linux: static\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: curl-{{.OS}}-{{.Arch}}-dev-{{.Version}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: curl\n            src: curl-{{.Arch}}/bin/curl\n          - name: curl-config\n            src: curl-{{.Arch}}/bin/curl-config\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/subtrace/subtrace/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: subtrace\n    repo_name: subtrace\n    description: Wireshark for Docker containers\n    version_prefix: \"b\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 154.0.0\")\n        asset: subtrace-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: subtrace-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sudorandom/fauxrpc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sudorandom\n    repo_name: fauxrpc\n    description: Easily start a fake gRPC/gRPC-Web/Connect/REST server from protobufs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.17-4\"\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.0.17\"\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fauxrpc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.16\")\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: fauxrpc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.16.1\")\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.19.4\")\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n        asset: fauxrpc_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sudorandom/protoc-gen-connect-openapi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sudorandom\n    repo_name: protoc-gen-connect-openapi\n    description: Plugin for generating OpenAPIv3 from protobufs matching the Connect RPC interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.3\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.13.0\")\n        asset: protoc-gen-connect-openapi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: protoc-gen-connect-openapi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: protoc-gen-connect-openapi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: protoc-gen-connect-openapi_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sue445/plant_erd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sue445\n    repo_name: plant_erd\n    description: ERD exporter with PlantUML and mermaid format\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.1.rc1\"\n        no_asset: true\n      - version_constraint: Version in [\"v0.0.1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\", \"v0.2.0.rc1\"]\n        asset: plant_erd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: plant_erd\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            asset: plant_erd_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: plant_erd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: plant_erd\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            asset: plant_erd_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sunny0826/kubecm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sunny0826\n    repo_name: kubecm\n    description: Manage your kubeconfig more easily\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: kubecm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.13.1\")\n        asset: kubecm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.2\")\n        asset: kubecm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.19.2\")\n        asset: kubecm_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kubecm_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sunny0826/kubectl-pod-lens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sunny0826\n    repo_name: kubectl-pod-lens\n    description: kubectl plugin for show pod-related resources\n    files:\n      - name: kubectl-pod_lens\n        src: pod-lens\n      - name: pod-lens\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.1\"\n        asset: pod-lens_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pod-lens_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.2\"\n        asset: pod-lens_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pod-lens_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: pod-lens_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: pod-lens_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: pod-lens_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pod-lens_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/supabase/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: supabase\n    repo_name: cli\n    description: Supabase CLI. Manage postgres migrations, run Supabase locally, deploy edge functions. Postgres backups. Generating types from your database schema\n    files:\n      - name: supabase\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.7.8\", \"v1.10.0\", \"v1.22.2\", \"v1.40.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 1.27.10\")\n        asset: supabase_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: supabase_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.126.0\")\n        asset: supabase_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: supabase_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: supabase_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: supabase_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/superbrothers/ksort/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: superbrothers\n    repo_name: ksort\n    description: Sort manfest files in a proper order by Kind\n    files:\n      - name: ksort\n      - name: kubectl-sort_manifests\n        src: ksort\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.4.1\"\n        asset: ksort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.4.2\"\n        asset: ksort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: ksort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: ksort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ksort-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/superfly/flyctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: superfly\n    repo_name: flyctl\n    description: Command line tools for fly.io services\n    files:\n      - name: flyctl\n      - name: fly\n        src: flyctl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.144\", \"v0.2.73\", \"v0.3.0\", \"v0.3.11\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.517\"\n        asset: flyctl_{{trimV .Version}}_{{.OS}}{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: flyctl_{{trimV .Version}}_mac{{.OS}}86_64.{{.Format}}\n            replacements:\n              darwin: OSx\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              darwin: macOS\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.158\")\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.175\")\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.201\")\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.0.243\")\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.2.72\")\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.80\"\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.84\"\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: flyctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: flyctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: flyctl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/akoi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: akoi\n    description: \"Deprecated: Please use aqua\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.3.0\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: akoi_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: akoi_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: akoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: akoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/asciinema-trim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: asciinema-trim\n    description: Trim and change the playback speed of asciinema's session\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: asciinema-trim_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: asciinema-trim_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: asciinema-trim_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: asciinema-trim_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/checkout-merged-branch-with-ci-info/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: suzuki-shunsuke\n    repo_name: checkout-merged-branch-with-ci-info\n    path: checkout-merged-branch\n    description: checkout a merged branch\n    files:\n      - name: checkout-merged-branch\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ci-info/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ci-info\n    description: CLI tool to get CI related information\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v2.1.1\"\n        asset: ci-info_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ci-info_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.1.0\")\n        asset: ci-info_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: ci-info_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.4.0\")\n        asset: ci-info_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: ci-info_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ci-info/releases/download/{{.Version}}/ci-info_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ci-info/releases/download/{{.Version}}/ci-info_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: \"true\"\n        asset: ci-info_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: ci-info_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: ci-info_{{trimV .Version}}_checksums.txt.bundle\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ci-renovate-config-validator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: suzuki-shunsuke\n    repo_name: ci-renovate-config-validator\n    path: ci-renovate-config-validator\n    description: script to validate Renovate configuration file with renovate-config-validator\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/circleci-config-merge/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: circleci-config-merge\n    description: Generate .circleci/config.yml by merging multiple files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: semver(\"<= 1.1.4-4\")\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            slsa_provenance:\n              enabled: false\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: semver(\"<= 1.1.4-10\")\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: semver(\"<= 1.1.4-12\")\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n            slsa_provenance:\n              enabled: false\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: Version == \"v1.1.4\"\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n      - version_constraint: \"true\"\n        asset: circleci-config-merge_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: circleci-config-merge_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/circleci-config-merge/releases/download/{{.Version}}/circleci-config-merge_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/cmdx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: cmdx\n    description: Task runner. It provides useful help messages and supports interactive prompts and validation of arguments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.7.0-2\"\n        asset: cmdx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.0\")\n        asset: cmdx_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: cmdx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.0.0-0\")\n        asset: cmdx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: semver(\"<= 2.0.1\")\n        asset: cmdx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: cmdx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: cmdx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/cmdx/releases/download/{{.Version}}/cmdx_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_immutable_release: true\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/dd-time/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: dd-time\n    description: CLI tool to post the command execution time as time-series data to DataDog\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: dd-time_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: dd-time_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/deny-self-approve/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: deny-self-approve\n    description: CLI to deny self-approved GitHub Pull Requests\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: deny-self-approve_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: deny-self-approve_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/deny-self-approve/releases/download/{{.Version}}/deny-self-approve_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/deny-self-approve/releases/download/{{.Version}}/deny-self-approve_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/disable-checkout-persist-credentials/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: disable-checkout-persist-credentials\n    description: CLI to disable actions/checkout's persist-credentials\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: disable-checkout-persist-credentials_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: disable-checkout-persist-credentials_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/disable-checkout-persist-credentials/releases/download/{{.Version}}/disable-checkout-persist-credentials_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/disable-checkout-persist-credentials/releases/download/{{.Version}}/disable-checkout-persist-credentials_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/discussion-slack-notifier/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: discussion-slack-notifier\n    asset: discussion-slack-notifier_{{.OS}}_{{.Arch}}.tar.gz\n    description: Notify GitHub Discussions events to Slack with GitHub Actions\n    supported_envs:\n      - darwin\n      - linux\n    checksum:\n      type: github_release\n      asset: discussion-slack-notifier_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/docfresh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: docfresh\n    description: Make document maintainable, reusable, and testable\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: docfresh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: docfresh_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: docfresh_checksums.txt.bundle\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/durl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: durl\n    description: \"[DEPRECATED] Use https://github.com/lycheeverse/lychee\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: durl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: durl_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghalint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghalint\n    description: GitHub Actions linter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0-1\"\n        asset: ghalint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghalint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: semver(\"<= 0.2.12\")\n        asset: ghalint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghalint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: ghalint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghalint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghalint/releases/download/{{.Version}}/ghalint_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghaperf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghaperf\n    description: ghaperf is a CLI to analyze the performance of GitHub Actions using GitHub API and raw job logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghaperf_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghaperf_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n            bundle:\n              type: github_release\n              asset: ghaperf_checksums.txt.bundle\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghatm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghatm\n    description: Set timeout-minutes to all GitHub Actions jobs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: gha-set-timeout-minutes_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: gha-set-timeout-minutes\n        checksum:\n          type: github_release\n          asset: gha-set-timeout-minutes_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ghatm_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: ghatm_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghatm/releases/download/{{.Version}}/ghatm_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghatm/releases/download/{{.Version}}/ghatm_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghcp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghcp\n    description: Tool to fork a repository, commit files, create a pull request and upload assets using GitHub API\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghcp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: ghcp_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghcp/releases/download/{{.Version}}/ghcp_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghcp/releases/download/{{.Version}}/ghcp_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghd2i/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghd2i\n    description: CLI to create GitHub Issues from GitHub Discussions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghd2i_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghd2i_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghd2i/releases/download/{{.Version}}/ghd2i_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghd2i/releases/download/{{.Version}}/ghd2i_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghir/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghir\n    description: ghir is a CLI making past GitHub Releases immutable\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghir_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghir_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghir/releases/download/{{.Version}}/ghir_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghir/releases/download/{{.Version}}/ghir_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n        github_immutable_release: true\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghomfc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghomfc\n    description: GitHub Organization Members' Followers Counter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghomfc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghomfc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghomfc/releases/download/{{.Version}}/ghomfc_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghomfc/releases/download/{{.Version}}/ghomfc_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghproj/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghproj\n    description: Add GitHub Issues and Pull Requests to GitHub Projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghproj_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghproj_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghproj/releases/download/{{.Version}}/ghproj_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghproj/releases/download/{{.Version}}/ghproj_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/ghtkn/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: ghtkn\n    description: A CLI to create GitHub App User Access Token for secure local development\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ghtkn_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: ghtkn_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/ghtkn/releases/download/{{.Version}}/ghtkn_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/ghtkn/releases/download/{{.Version}}/ghtkn_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/git-rm-branch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: git-rm-branch\n    description: cli tool to remove merged branches\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: git-rm-branch_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: git-rm-branch_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/github-comment/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: github-comment\n    description: CLI to create and hide GitHub comments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.3.0-0\")\n        asset: github-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: github-comment_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 5.0.0\")\n        asset: github-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: github-comment_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 5.0.1\")\n        asset: github-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: github-comment_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: github-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: github-comment_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/github-comment/releases/download/{{.Version}}/github-comment_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/github-comment/releases/download/{{.Version}}/github-comment_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/matchfile/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: matchfile\n    description: CLI tool to check file paths are matched to the condition\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: matchfile_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: matchfile_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/migrate-urfave-cli-v3/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: migrate-urfave-cli-v3\n    description: Migrate github.com/urfave/cli/v2 to v3. This tool doesn't aim to the complete migration. Probably you need to fix code manually after running this tool, but this tool makes the migration easy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: migrate-urfave-cli-v3_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: migrate-urfave-cli-v3_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/migrate-urfave-cli-v3/releases/download/{{.Version}}/migrate-urfave-cli-v3_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/migrate-urfave-cli-v3/releases/download/{{.Version}}/migrate-urfave-cli-v3_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/mkghtag/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: mkghtag\n    description: CLI to create GitHub Tags via API\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: mkghtag_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: mkghtag_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/mkghtag/releases/download/{{.Version}}/mkghtag_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/mkghtag/releases/download/{{.Version}}/mkghtag_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n            slsa_provenance:\n              enabled: false\n      - version_constraint: \"true\"\n        asset: mkghtag_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: mkghtag_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/mkghtag/releases/download/{{.Version}}/mkghtag_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/mkghtag/releases/download/{{.Version}}/mkghtag_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/nllint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: nllint\n    description: Linter to check newlines at the end of files\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: nllint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: nllint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/nllint/releases/download/{{.Version}}/nllint_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/nllint/releases/download/{{.Version}}/nllint_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/pinact/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: pinact\n    description: pinact is a CLI to edit GitHub Workflow and Composite action files and pin versions of Actions and Reusable Workflows. pinact can also update their versions and verify version annotations\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.0-1\")\n        asset: pinact_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pinact_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/pinact/releases/download/{{.Version}}/pinact_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/pinact/releases/download/{{.Version}}/pinact_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: pinact_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: pinact_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/pinact/releases/download/{{.Version}}/pinact_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/pinact/releases/download/{{.Version}}/pinact_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/renovate-issue-action/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: renovate-issue-action\n    description: Create, update, and close GitHub Issues with GitHub Actions according to Renovate Pull Requests\n    supported_envs:\n      - darwin\n      - linux\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: renovate-issue-action_{{.OS}}_{{.Arch}}.tar.gz\n        checksum:\n          type: github_release\n          asset: renovate-issue-action_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: renovate-issue-action_{{.OS}}_{{.Arch}}.tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: renovate-issue-action_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/renovate-issue-action/releases/download/{{.Version}}/renovate-issue-action_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/renovate-issue-action/releases/download/{{.Version}}/renovate-issue-action_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/rgo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: rgo\n    description: rgo is a CLI to release a Homebrew-tap recipe, Scoop App Manifest, and a winget manifest built with GoReleaser\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.3\")\n        type: github_content\n        path: rgo\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: \"true\"\n        asset: rgo_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: rgo_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n            bundle:\n              type: github_release\n              asset: rgo_{{trimV .Version}}_checksums.txt.bundle\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/rjsa/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: suzuki-shunsuke\n    repo_name: rjsa\n    description: A command to release JavaScript action\n    path: rjsa\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/sort-issue-template/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: sort-issue-template\n    description: CLI to sort GitHub Issue Templates using a text editor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: sort-issue-template_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: sort-issue-template_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/sort-issue-template/releases/download/{{.Version}}/sort-issue-template_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/sort-issue-template/releases/download/{{.Version}}/sort-issue-template_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/tfaction-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: tfaction-go\n    description: CLI for tfaction\n    files:\n      - name: tfaction\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.4\"\n        asset: tfaction_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfaction_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfaction-go/releases/download/{{.Version}}/tfaction_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfaction-go/releases/download/{{.Version}}/tfaction_{{trimV .Version}}_checksums.txt.sig\n      - version_constraint: \"true\"\n        asset: tfaction_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfaction_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfaction-go/releases/download/{{.Version}}/tfaction_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.+$\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfaction-go/releases/download/{{.Version}}/tfaction_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/tfcmt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: tfcmt\n    description: tfcmt enhances mercari/tfnotify in many ways, including Terraform >= v0.15 support and advanced formatting options\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0-0\")\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 3.2.4\")\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 4.0.0\")\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"< 4.14.0\")\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfcmt/releases/download/{{.Version}}/tfcmt_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfcmt/releases/download/{{.Version}}/tfcmt_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n      - version_constraint: \"true\"\n        asset: tfcmt_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfcmt_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfcmt/releases/download/{{.Version}}/tfcmt_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfcmt/releases/download/{{.Version}}/tfcmt_{{trimV .Version}}_checksums.txt.sig\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        github_artifact_attestations:\n          signer_workflow: suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/tfmv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: tfmv\n    description: CLI to rename Terraform resources and modules and generate moved blocks\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfmv_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: tfmv_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfmv/releases/download/{{.Version}}/tfmv_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfmv/releases/download/{{.Version}}/tfmv_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/tfprovidercheck/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: tfprovidercheck\n    description: Censor Terraform Providers\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfprovidercheck_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        checksum:\n          type: github_release\n          asset: tfprovidercheck_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfprovidercheck/releases/download/{{.Version}}/tfprovidercheck_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfprovidercheck/releases/download/{{.Version}}/tfprovidercheck_{{trimV .Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/tfrstate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: tfrstate\n    description: Find directories where changed terraform_remote_state data source is used\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfrstate_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tfrstate_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/tfrstate/releases/download/{{.Version}}/tfrstate_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/tfrstate/releases/download/{{.Version}}/tfrstate_{{trimV .Version}}_checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/yaml2json/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: yaml2json\n    description: Convert YAML to JSON\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: yaml2json_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: yaml2json_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: yaml2json_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: yaml2json_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/suzuki-shunsuke/yodoc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: suzuki-shunsuke\n    repo_name: yodoc\n    description: Test command results and embed them into document\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yodoc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: yodoc_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/suzuki-shunsuke/yodoc/releases/download/{{.Version}}/yodoc_{{trimV .Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/suzuki-shunsuke/yodoc/releases/download/{{.Version}}/yodoc_{{trimV .Version}}_checksums.txt.pem\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/svenstaro/genact/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: svenstaro\n    repo_name: genact\n    description: A nonsense activity generator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: genact-{{.OS}}\n        format: raw\n        replacements:\n          windows: win\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: genact-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: genact-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: genact-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/svenstaro/miniserve/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: svenstaro\n    repo_name: miniserve\n    description: For when you really just want to serve some files over HTTP right now\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.10.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: miniserve-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: miniserve-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: miniserve-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: osx\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.4\")\n        asset: miniserve-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.20.0\")\n        asset: miniserve-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: semver(\"<= 0.23.1\")\n        asset: miniserve-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: miniserve-{{trimV .Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/swaggo/swag/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: swaggo\n    repo_name: swag\n    description: Automatically generate RESTful API documentation with Swagger 2.0 for Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.4.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.6.9\")\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.7.0\"\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.7.1\"\n        asset: swag_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: swag\n            src: swag_{{.OS}}_{{.Arch}}/swag\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.8.1\")\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.8.2\"\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: swag_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.8.9\")\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.8.10\"\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.16.2\")\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v1.16.3\"\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: swag_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/swanysimon/mdlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: swanysimon\n    repo_name: mdlint\n    aliases:\n      - name: swanysimon/markdownlint-rs\n    description: Attempting to port markdownlint (and the markdownlint-cli2 interface) to Rust using mostly vibes\n    files:\n      - name: mdlint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: mdlint-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: mdlint\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: mdlint-{{.OS}}-{{.Arch}}-musl.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: mdlint-{{.OS}}-{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sxyazi/yazi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sxyazi\n    repo_name: yazi\n    description: Blazing fast terminal file manager written in Rust, based on async I/O\n    files:\n      - name: yazi\n      - name: ya\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: yazi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: yazi\n            src: yazi-{{.Arch}}-{{.OS}}\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.1.4\"\n        asset: yazi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: yazi\n            src: yazi-{{.Arch}}-{{.OS}}\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: yazi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: yazi\n            src: yazi-{{.Arch}}-{{.OS}}/yazi\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n      - version_constraint: Version == \"v0.2.4\"\n        asset: yazi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: yazi\n            src: yazi-{{.Arch}}-{{.OS}}/yazi\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n      - version_constraint: \"true\"\n        asset: yazi-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: yazi\n            src: yazi-{{.Arch}}-{{.OS}}/yazi\n          - name: ya\n            src: yazi-{{.Arch}}-{{.OS}}/ya\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sylwit/terraform-cleaner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sylwit\n    repo_name: terraform-cleaner\n    description: Tiny utility which detects unused variables in your terraform modules\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: terraform-cleaner_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/syncthing/syncthing/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: syncthing\n    repo_name: syncthing\n    description: Open Source Continuous File Synchronization\n    files:\n      - name: syncthing\n        src: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}/syncthing\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.12.25\"\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macosx\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.13.3\")\n        no_asset: true\n      - version_constraint: Version in [\"v0.14.22\", \"v1.6.0\", \"v1.20.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.14.48\")\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macosx\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.5.0\")\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.12.1\")\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 1.18.2\")\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 2.0.13\")\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: \"true\"\n        asset: syncthing-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            format: tar.gz\n        github_artifact_attestations:\n          signer_workflow: syncthing/syncthing/.github/workflows/build-syncthing.yaml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/synfinatic/aws-sso-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: synfinatic\n    repo_name: aws-sso-cli\n    description: A powerful tool for using AWS Identity Center for the CLI and web console\n    files:\n      - name: aws-sso\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.9.5\"\n        asset: aws-sso-1.9.4-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 1.0.0\") or Version == \"v1.9.3\"\n        asset: aws-sso-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        asset: aws-sso-{{trimV .Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/sysdiglabs/kube-psp-advisor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: sysdiglabs\n    repo_name: kube-psp-advisor\n    description: Help building an adaptive and fine-grained pod security policy\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: kube-psp-advisor_{{.Version}}_{{.OS}}_amd64.tar.gz\n    files:\n      - name: kubectl-advise_psp\n        src: kubectl-advise-psp\n      - name: kube-psp-advisor\n        src: kubectl-advise-psp\n    checksum:\n      type: github_release\n      asset: kube-psp-advisor_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/syumai/sbx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: syumai\n    repo_name: sbx\n    description: an easy-to-use command-line tool for running commands with macOS sandbox-exec policies using flag-based interface\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.2\"\n        asset: sbx_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: sbx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: sbx-{{.Arch}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sbx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: sbx-{{.Arch}}-{{.OS}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: sbx_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/t-kikuc/ecstop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: t-kikuc\n    repo_name: ecstop\n    description: Stop your running resources of Amazon ECS easily\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ecstop_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ecstop_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/taiki-e/cargo-llvm-cov/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: taiki-e\n    repo_name: cargo-llvm-cov\n    description: Cargo subcommand to easily use LLVM source-based code coverage (-C instrument-coverage)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0-alpha.4\")\n        asset: cargo-llvm-cov-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.15\")\n        asset: cargo-llvm-cov-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: cargo-llvm-cov-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n      - version_constraint: \"true\"\n        asset: cargo-llvm-cov-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tailor-platform/patterner/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tailor-platform\n    repo_name: patterner\n    description: patterner is a tool to analyze and present best practices (patterns) for Tailor Platform applications\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: patterner_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tailor-platform/tailorctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tailor-platform\n    repo_name: tailorctl\n    description: Command line tool for Tailor Platform\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.9.4\", \"v0.12.1\", \"v1.19.0\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.8\")\n        asset: tailorctl_{{.OS}}_{{.Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tailorctl_{{.OS}}_{{.Version}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tailscale/tailscale/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: tailscale\n    repo_name: tailscale\n    description: The easiest, most secure way to use WireGuard and 2FA\n    url: https://pkgs.tailscale.com/stable/tailscale_{{trimV .Version}}_{{.Arch}}.{{.Format}}\n    format: tgz\n    files:\n      - name: tailscale\n        src: \"{{.AssetWithoutExt}}/tailscale\"\n      - name: tailscaled\n        src: \"{{.AssetWithoutExt}}/tailscaled\"\n    overrides:\n      - goos: darwin\n        url: https://pkgs.tailscale.com/stable/Tailscale-{{trimV .Version}}-macos.{{.Format}}\n        format: pkg\n        files:\n          - name: tailscale\n            src: Distribution.pkg/Payload/Contents/MacOS/Tailscale\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tailwindlabs/tailwindcss/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tailwindlabs\n    repo_name: tailwindcss\n    description: A utility-first CSS framework for rapid UI development\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 3.0.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 3.0.7\")\n        asset: tailwindcss-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.2.4\")\n        asset: tailwindcss-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: semver(\"<= 3.2.7\")\n        asset: tailwindcss-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: semver(\"<= 3.4.17\")\n        asset: tailwindcss-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: tailwindcss-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: tailwindcss-{{.OS}}-{{.Arch}}-musl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takaishi/awscost/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takaishi\n    repo_name: awscost\n    description: Print AWS costs to text or graph image\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: awscost_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takaishi/tfclean/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takaishi\n    repo_name: tfclean\n    description: tfclean is tool to remove applied moved block, import block, etc\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfclean_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takaishi/tfdiff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takaishi\n    repo_name: tfdiff\n    description: A CLI that shows attribute-level diffs between Terraform modules with clean, diff-like output\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tfdiff_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takaishi/tftargets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takaishi\n    repo_name: tftargets\n    description: A tool that analyzes Terraform configurations and identifies directories that need to be executed based on Git changes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tftargets_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takumin/gjson/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takumin\n    repo_name: gjson\n    description: Golang JSON Tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.1\"\n        asset: gjson_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gjson_sha256sums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: gjson_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: gjson_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gjson_sha256sums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takumin/gyaml/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takumin\n    repo_name: gyaml\n    description: Golang YAML Tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gyaml_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: gyaml_sha256sums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/takumin/zizmor-bin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: takumin\n    repo_name: zizmor-bin\n    description: Static build of `zizmor`\n    files:\n      - name: zizmor\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: zizmor-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnullvm\n        cosign:\n          opts:\n            - --certificate\n            - https://github.com/takumin/zizmor-bin/releases/download/{{.Version}}/{{.Asset}}.cert\n            - --signature\n            - https://github.com/takumin/zizmor-bin/releases/download/{{.Version}}/{{.Asset}}.sig\n            - --certificate-identity\n            - https://github.com/takumin/zizmor-bin/.github/workflows/wc-sign.yml@refs/heads/main\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/takumin/zizmor-bin/releases/download/{{.Version}}/SHA256SUMS.cert\n              - --signature\n              - https://github.com/takumin/zizmor-bin/releases/download/{{.Version}}/SHA256SUMS.sig\n              - --certificate-identity\n              - https://github.com/takumin/zizmor-bin/.github/workflows/wc-sign.yml@refs/heads/main\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        github_artifact_attestations:\n          signer_workflow: takumin/zizmor-bin/.github/workflows/wc-sign.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tamasfe/taplo/full/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tamasfe\n    repo_name: taplo\n    name: tamasfe/taplo/full\n    description: A TOML toolkit written in Rust\n    version_constraint: not (Version startsWith \"release-taplo-cli-\") and not (Version startsWith \"release-cli-\") and semver(\">= 0.8.0\")\n    asset: taplo-full-{{.OS}}-{{.Arch}}.{{.Format}}\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    format: gz\n    files:\n      - name: taplo\n        src: taplo-full-{{.OS}}-{{.Arch}}\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: taplo\n            src: taplo.exe\n    version_overrides:\n      - version_constraint: Version startsWith \"release-taplo-cli-\"\n        asset: taplo-full-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n        rosetta2: true\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n        overrides: []\n        files:\n          - name: taplo\n      - version_constraint: Version startsWith \"release-cli-\" and semverWithVersion(\">= 0.6.0\", trimPrefix(Version, \"release-cli-\"))\n        asset: taplo-full-{{trimPrefix \"release-cli-\" .Version}}-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n        rosetta2: true\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n        overrides: []\n        files:\n          - name: taplo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tamasfe/taplo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tamasfe\n    repo_name: taplo\n    description: A TOML toolkit written in Rust\n    version_constraint: not (Version startsWith \"release-taplo-cli-\") and not (Version startsWith \"release-cli-\") and semver(\">= 0.8.0\")\n    asset: taplo-{{.OS}}-{{.Arch}}.{{.Format}}\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - darwin\n      - linux\n      - windows/amd64\n    format: gz\n    files:\n      - name: taplo\n        src: taplo-{{.OS}}-{{.Arch}}\n    overrides:\n      - goos: windows\n        format: zip\n        files:\n          - name: taplo\n            src: taplo.exe\n    version_overrides:\n      - version_constraint: Version startsWith \"release-taplo-cli-\"\n        asset: taplo-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n        rosetta2: true\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n        overrides: []\n        files:\n          - name: taplo\n      - version_constraint: Version startsWith \"release-cli-\" and semverWithVersion(\">= 0.6.0\", trimPrefix(Version, \"release-cli-\"))\n        asset: taplo-{{trimPrefix \"release-cli-\" .Version}}-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n        rosetta2: true\n        format: tar.gz\n        supported_envs:\n          - darwin\n          - linux/amd64\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n        overrides: []\n        files:\n          - name: taplo\n      - version_constraint: Version startsWith \"release-cli-\" and semverWithVersion(\"<= 0.5.0\", trimPrefix(Version, \"release-cli-\"))\n        asset: taplo-{{.Arch}}-{{.OS}}-gnu.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux\n          windows: pc-windows\n        files:\n          - name: taplo\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/taskctl/taskctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: taskctl\n    repo_name: taskctl\n    asset: taskctl_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Concurrent task runner, developer's routine tasks automation toolkit. Simple modern alternative to GNU Make\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tassiovirginio/try-rs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tassiovirginio\n    repo_name: try-rs\n    description: A blazing fast, Rust-based workspace manager for your temporary experiments\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.1.0\", \"v0.1.15\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.1.22\"\n        asset: try-rs-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.1.6\")\n        asset: try-rs-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.21\")\n        asset: try-rs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.1.27\")\n        asset: try-rs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: raw\n            asset: try-rs-{{.OS}}-{{.Arch}}\n          - goos: linux\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha256\"\n              algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.1.29\")\n        asset: try-rs-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: try-rs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: windows\n            format: raw\n            asset: try-rs-{{.OS}}-{{.Arch}}\n          - goos: linux\n            checksum:\n              type: github_release\n              asset: \"{{.Asset}}.sha256\"\n              algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tattoy-org/tattoy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tattoy-org\n    repo_name: tattoy\n    description: A text-based compositor for modern terminals\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tattoy-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: tattoy-{{.Arch}}-{{.OS}}.sha256\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tauri-apps/tauri/cargo-tauri/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: tauri-apps/tauri/cargo-tauri\n    type: github_release\n    repo_owner: tauri-apps\n    repo_name: tauri\n    description: Build smaller, faster, and more secure desktop and mobile applications with a web frontend\n    version_prefix: tauri-cli-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"tauri-cli-v2.0.0-rc.10\", \"tauri-cli-v1.6.4\", \"tauri-cli-v2.0.0-beta.5\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: cargo-tauri-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            format: tgz\n            replacements:\n              arm64: arm64\n        supported_envs:\n          - linux/amd64\n          - darwin\n          - windows\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tcnksm/ghr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tcnksm\n    repo_name: ghr\n    description: Upload multiple artifacts to GitHub Release in parallel\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - amd64\n    asset: ghr_{{.Version}}_{{.OS}}_amd64.{{.Format}}\n    files:\n      - name: ghr\n        src: ghr_{{.Version}}_{{.OS}}_amd64/ghr\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tdewolff/minify/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tdewolff\n    repo_name: minify\n    asset: minify_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Go minifiers for web formats\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tealdeer-rs/tealdeer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tealdeer-rs\n    repo_name: tealdeer\n    aliases:\n      - name: dbrgn/tealdeer\n    description: A very fast implementation of tldr in Rust\n    files:\n      - name: tldr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        asset: tldr-{{.Arch}}-musl\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.4.1\")\n        asset: tldr-{{.OS}}-{{.Arch}}-musl\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.6.1\")\n        asset: tealdeer-{{.OS}}-{{.Arch}}-musl\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tealdeer-{{.OS}}-{{.Arch}}\n          - goos: windows\n            asset: tealdeer-{{.OS}}-{{.Arch}}-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tealdeer-{{.OS}}-{{.Arch}}-musl\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tealdeer-{{.OS}}-{{.Arch}}\n          - goos: windows\n            asset: tealdeer-{{.OS}}-{{.Arch}}-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/technicalpickles/envsense/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: technicalpickles\n    repo_name: envsense\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.0\"\n        asset: envsense-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: envsense-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.2.1\"\n        asset: envsense-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: envsense-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: envsense-v0.1.0-universal-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: envsense-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: envsense-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.4\")\n        asset: envsense-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        cosign:\n          bundle:\n            type: github_release\n            asset: \"{{.Asset}}.bundle\"\n          opts:\n            - --certificate-identity-regexp\n            - '^https://github\\.com/technicalpickles/envsense/'\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: darwin\n            asset: envsense-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: envsense-{{.Version}}-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        cosign:\n          bundle:\n            type: github_release\n            asset: \"{{.Asset}}.bundle\"\n          opts:\n            - --certificate-identity-regexp\n            - '^https://github\\.com/technicalpickles/envsense/'\n            - --certificate-oidc-issuer\n            - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: darwin\n            asset: envsense-{{.Version}}-universal-{{.OS}}\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tektoncd/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tektoncd\n    repo_name: cli\n    description: A CLI for interacting with Tekton\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tkn\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tkn\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.4.0\"\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tkn\n        overrides:\n          - goos: windows\n            format: zip\n            checksum:\n              enabled: false\n            files:\n              - name: tkn\n                src: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}/tkn.exe\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.21.0\")\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tkn\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.23.1\")\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tkn\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.27.0\")\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tkn\n        overrides:\n          - goos: darwin\n            asset: tkn_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.34.0\"\n        # https://github.com/tektoncd/cli/issues/2211\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tkn\n        overrides:\n          - goos: darwin\n            asset: tkn_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n      - version_constraint: \"true\"\n        asset: tkn_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tkn\n        overrides:\n          - goos: darwin\n            asset: tkn_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tektoncd/pipelines-as-code/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tektoncd\n    repo_name: pipelines-as-code\n    aliases:\n      - name: openshift-pipelines/pipelines-as-code\n    description: Pipelines-as-Code for Tekton\n    files:\n      - name: tkn-pac\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.4.3\"\n        asset: tkn-pac_{{.Version}}_{{.OS}}_all.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: Version == \"v0.17.4\"\n        asset: tkn-pac_.{{trimV .Version}}_.{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        # Checksum file is broken\n        replacements:\n          amd64: x86_64\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_.{{trimV .Version}}_.{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.33.0\"\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            # Checksums are missing for Windows\n            checksum:\n              enabled: false\n      - version_constraint: Version == \"v0.35.3\"\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n      - version_constraint: Version == \"v0.36.0\"\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.5\")\n        asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{.Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: tkn-pac_{{.Version}}_{{.OS}}_all.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: tkn-pac_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 0.17.3\")\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.17.7\")\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.19.2\")\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: MacOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.32.0\")\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.35.2\")\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tkn-pac_{{trimV .Version}}_{{.OS}}_all.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: tkn-pac_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/telepresenceio/telepresence/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: telepresenceio\n    repo_name: telepresence\n    description: Local development against a remote Kubernetes or OpenShift cluster\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.14.4\")\n        asset: telepresence-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: telepresence-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n            asset: telepresence-{{.OS}}-{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/teler-sh/teler/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: teler-sh\n    repo_name: teler\n    aliases:\n      - name: kitabisa/teler\n    description: Real-time HTTP Intrusion Detection\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 2.0.0-beta\")\n        asset: teler_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: teler_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.0-rc.4\")\n        asset: teler_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: teler_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: teler_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: teler_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tellerops/teller/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tellerops\n    repo_name: teller\n    aliases:\n      - name: SpectralOps/teller\n    description: Cloud native secrets management for developers - never leave your command line for secrets\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.4.0\")\n        asset: teller_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.5.6\")\n        asset: teller_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: teller-{{.Arch}}-{{.OS}}.{{.Format}}\n        files:\n          - name: teller\n            src: \"{{.AssetWithoutExt}}/teller\"\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/temporalio/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: temporalio/cli\n    type: github_release\n    repo_owner: temporalio\n    repo_name: cli\n    description: Command-line interface for running Temporal Server and interacting with Workflows, Activities, Namespaces, and other parts of Temporal\n    files:\n      - name: temporal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.13.0-rc.1\"\n        no_asset: true\n      - version_constraint: Version == \"v0.1.0\"\n        asset: temporal-cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.2.0\"\n        asset: cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"0.5.0\"\n        asset: temporal_cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: temporal_cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: temporal_cli_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/temporalio/tctl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: temporalio\n    repo_name: tctl\n    description: Temporal CLI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.16.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: tctl_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/temporalio/temporal/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: temporalio\n    repo_name: temporal\n    description: Temporal service and CLI\n    asset: temporal_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    files:\n      - name: tctl\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tenable/terrascan/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tenable\n    repo_name: terrascan\n    aliases:\n      - name: accurics/terrascan\n    asset: terrascan_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    description: Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/termkit/gama/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: termkit\n    repo_name: gama\n    description: Manage your GitHub Actions from Terminal with great UI\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.7\")\n        asset: gama-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.2\")\n        asset: gama-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n      - version_constraint: \"true\"\n        asset: gama-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terraform-docs/terraform-docs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terraform-docs\n    repo_name: terraform-docs\n    description: Generate documentation from Terraform modules in various output formats\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: terraform-docs_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.3.0\"\n        asset: terraform-docs_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n      - version_constraint: Version == \"v0.4.0\"\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.1\")\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: terraform-docs-{{.Version}}.sha256sum\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.11.2\")\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: terraform-docs-{{.Version}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.16.0\")\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: terraform-docs-{{.Version}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: terraform-docs-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: terraform-docs-{{.Version}}.sha256sum\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terraform-linters/tflint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terraform-linters\n    repo_name: tflint\n    description: A Pluggable Terraform Linter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.32.0\"\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.32.1\"\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.7.6\")\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.29.0\")\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.51.0\")\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - \"https://github.com/terraform-linters/tflint/.github/workflows/release.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/terraform-linters/tflint/releases/download/{{.Version}}/checksums.txt.keyless.sig\n              - --certificate\n              - https://github.com/terraform-linters/tflint/releases/download/{{.Version}}/checksums.txt.pem\n      - version_constraint: \"true\"\n        asset: tflint_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - \"https://github.com/terraform-linters/tflint/.github/workflows/release.yml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/terraform-linters/tflint/releases/download/{{.Version}}/checksums.txt.keyless.sig\n              - --certificate\n              - https://github.com/terraform-linters/tflint/releases/download/{{.Version}}/checksums.txt.pem\n          github_artifact_attestations:\n            signer_workflow: terraform-linters/tflint/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terramate-io/terramate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terramate-io\n    repo_name: terramate\n    description: \"Open-source Infrastructure as Code (IaC) orchestration platform: GitOps workflows, orchestration, code generation, observability, drift detection, asset management, policies, Slack notifications, and more. Integrates with Terraform, OpenTofu, Terragrunt, Kubernetes, GitHub Actions, GitLab CI/CD, BitBucket Pipelines, and any other CI/CD platform\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.10\"\n        no_asset: true\n      - version_constraint: Version == \"v0.0.1\"\n        asset: terrastack-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.0.2\"\n        asset: terrastack-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.0.3\"\n        asset: terramate-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.11\"\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.7\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.9\")\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.33\")\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.2.7\")\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          windows: win\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: terramate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/terramate-io/terramate/releases/download/{{.Version}}/cosign.pub\n              - --signature\n              - https://github.com/terramate-io/terramate/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terrastruct/d2/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terrastruct\n    repo_name: d2\n    asset: d2-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: D2 is a modern diagram scripting language that turns text to diagrams\n    replacements:\n      darwin: macos\n    files:\n      - name: d2\n        src: d2-{{.Version}}/bin/d2\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terrastruct/tala/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terrastruct\n    repo_name: tala\n    asset: tala-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    description: A diagram layout engine designed specifically for software architecture diagrams\n    replacements:\n      darwin: macos\n    files:\n      - name: d2plugin-tala\n        src: tala-{{.Version}}/bin/d2plugin-tala\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/terratags/terratags/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: terratags\n    repo_name: terratags\n    description: Required tags validation on terraform resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: terratags_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tfmigrator/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tfmigrator\n    repo_name: cli\n    description: CLI to migrate Terraform Configuration and State\n    asset: tfmigrator_{{.OS}}_amd64.tar.gz\n    files:\n      - name: tfmigrator\n    version_constraint: semver(\">= 0.2.2\")\n    slsa_provenance:\n      type: github_release\n      asset: multiple.intoto.jsonl\n    checksum:\n      type: github_release\n      asset: tfmigrator_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n      cosign:\n        opts:\n          - --certificate-identity-regexp\n          - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n          - --certificate-oidc-issuer\n          - \"https://token.actions.githubusercontent.com\"\n          - --signature\n          - https://github.com/tfmigrator/cli/releases/download/{{.Version}}/tfmigrator_{{trimV .Version}}_checksums.txt.sig\n          - --certificate\n          - https://github.com/tfmigrator/cli/releases/download/{{.Version}}/tfmigrator_{{trimV .Version}}_checksums.txt.pem\n    version_overrides:\n      - version_constraint: \"true\"\n        slsa_provenance:\n          enabled: false\n        checksum:\n          type: github_release\n          asset: tfmigrator_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tfutils/tfenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: tfutils\n    repo_name: tfenv\n    description: Terraform version manager\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: tfenv\n        src: tfenv-{{trimV .Version}}/bin/tfenv\n      - name: terraform\n        src: tfenv-{{trimV .Version}}/bin/terraform\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tgenv/tgenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: tgenv\n    repo_name: tgenv\n    description: A tool to manage multiples Terragrunt versions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        files:\n          - name: tgenv\n            src: tgenv-{{trimV .Version}}/bin/tgenv\n          - name: terragrunt\n            src: tgenv-{{trimV .Version}}/bin/terragrunt\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/thanos-io/thanos/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: thanos-io\n    repo_name: thanos\n    description: Highly available Prometheus setup with long term storage capabilities. A CNCF Incubating project\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0-rc.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: thanos-{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: thanos\n            src: \"{{.AssetWithoutExt}}/thanos\"\n        checksum:\n          type: github_release\n          asset: sha256sums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/thazelart/terraform-validator/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: thazelart\n    repo_name: terraform-validator\n    description: A norms and conventions validator for Terraform\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    asset: terraform-validator_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: Darwin\n      linux: Linux\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: terraform-validator_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/theryangeary/choose/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: theryangeary\n    repo_name: choose\n    description: A human-friendly and fast alternative to cut (and sometimes awk)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.3.0\"\n        no_asset: true\n      - version_constraint: Version == \"v1.3.6\"\n        asset: choose-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: Version == \"v1.3.5\"\n        asset: choose-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-window-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n      - version_constraint: semver(\"<= 1.3.4\")\n        asset: choose-{{.Arch}}-{{.OS}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: choose-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-gnu\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: darwin\n            replacements:\n              amd64: amd64\n        supported_envs:\n          - linux\n          - darwin/arm64\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/theseus-rs/postgresql-binaries/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: theseus-rs\n    repo_name: postgresql-binaries\n    description: PostgreSQL binaries for Linux, MacOS and Windows\n    files:\n      - name: psql\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: postgresql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: psql\n            src: postgresql-{{.Version}}-{{.Arch}}-{{.OS}}/bin/psql\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu # https://github.com/aquaproj/aqua-registry/issues/34136\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            files:\n              - name: psql\n                src: postgresql-{{.Version}}-{{.Arch}}-{{.OS}}/bin/psql.exe\n            checksum:\n              # Skip because the contents of the provided file cannot be handled\n              enabled: false\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/thestormforge/optimize-controller/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: thestormforge\n    repo_name: optimize-controller\n    asset: stormforge-{{.OS}}-{{.Arch}}.tar.gz\n    description: Release with Confidence\n    supported_envs:\n      - linux/amd64\n      - darwin\n    files:\n      - name: stormforge\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/theupdateframework/go-tuf/tuf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: theupdateframework/go-tuf/tuf\n    type: github_release\n    repo_owner: theupdateframework\n    repo_name: go-tuf\n    description: Go implementation of The Update Framework (TUF)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 2.0.0\")\n        error_message: |\n          They decided to leave go-tuf as a library only.\n          https://github.com/theupdateframework/go-tuf/releases/tag/v2.0.0\n      - version_constraint: \"true\"\n        asset: tuf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: tuf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/theupdateframework/go-tuf/tuf-client/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: theupdateframework/go-tuf/tuf-client\n    type: github_release\n    repo_owner: theupdateframework\n    repo_name: go-tuf\n    description: Go implementation of The Update Framework (TUF)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\">= 2.0.0\")\n        error_message: |\n          They decided to leave go-tuf as a library only.\n          https://github.com/theupdateframework/go-tuf/releases/tag/v2.0.0\n      - version_constraint: \"true\"\n        asset: tuf-client_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n        checksum:\n          type: github_release\n          asset: tuf-client_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/theurichde/go-aws-sso/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: theurichde\n    repo_name: go-aws-sso\n    description: Makes dealing with AWS SSO Logins an ease\n    asset: go-aws-sso_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: go-aws-sso_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.2.0-dev.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.6.1\")\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 0.3.0\")\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n      - version_constraint: semver(\">= 0.1.0\")\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"< 0.1.0\")\n        asset: go-aws-sso-util_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: go-aws-sso-util\n        checksum:\n          type: github_release\n          asset: go-aws-sso-util_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/thomasschafer/scooter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: thomasschafer\n    repo_name: scooter\n    description: Interactive find and replace in the terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: scooter-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: scooter\n            src: scooter-{{.Arch}}-{{.OS}}\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: scooter-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/thought-machine/please/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: thought-machine\n    repo_name: please\n    description: High-performance extensible build system for reproducible multi-language builds\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: please_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    files:\n      - name: please\n        src: please/please\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tilt-dev/ctlptl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tilt-dev\n    repo_name: ctlptl\n    description: Making local Kubernetes clusters fun and easy to set up\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: ctlptl.{{trimV .Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: ctlptl.{{trimV .Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: mac\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tilt-dev/tilt/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tilt-dev\n    repo_name: tilt\n    description: Define your dev environment as code. For microservice apps on Kubernetes\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    asset: tilt.{{trimV .Version}}.{{.OS}}.{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      darwin: mac\n      386: i386\n      amd64: x86_64\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/timdp/lwc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: timdp\n    repo_name: lwc\n    description: A live-updating version of the UNIX wc command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: lwc-golang_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lwc-golang_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.4\")\n        asset: lwc-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lwc-checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: lwc-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lwc-checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/timvisee/ffsend/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: timvisee\n    repo_name: ffsend\n    description: Easily and securely share files from the command line. A fully featured Firefox Send client\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.2.13\", \"v0.2.75\"]\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"v0.2.60\", \"v0.2.69\"]\n        asset: ffsend-{{.Version}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: windows\n            asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        supported_envs:\n          - darwin\n          - windows/amd64\n      - version_constraint: Version == \"v0.2.47\"\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: ffsend-{{.Version}}-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.9\"\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.0.2\")\n        asset: ffsend-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.0.3\"\n        asset: ffsend-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: Version == \"v0.0.4\"\n        asset: ffsend-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.2.9\")\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.17\")\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: semver(\"<= 0.2.22\")\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: ffsend-{{.Version}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.24\")\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: ffsend-{{.Version}}-{{.OS}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ffsend-{{.Version}}-{{.OS}}-{{.Arch}}-static\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: ffsend-{{.Version}}-{{.OS}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tinygo-org/tinygo/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tinygo-org\n    repo_name: tinygo\n    description: Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1\"\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.7.1\"\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.8.0\"\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"v0.13.0\", \"v0.22.0\", \"v0.25.0-beta1\"]\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.7.0\")\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.30.0\")\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: tinygo{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: tinygo\n            src: tinygo/bin/tinygo\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tkuchiki/alp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tkuchiki\n    repo_name: alp\n    description: Access Log Profiler\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.8\")\n        asset: alp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: alp_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: alp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: alp_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tkuchiki/slp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tkuchiki\n    repo_name: slp\n    description: SlowLog Profiler for MySQL and PostgreSQL\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: slp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: slp_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: slp_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: slp_{{.Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tldr-pages/tlrc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tldr-pages\n    repo_name: tlrc\n    description: A tldr client written in Rust\n    files:\n      - name: tldr\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 1.9.3\")\n        asset: tlrc-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: tlrc-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        github_artifact_attestations:\n          signer_workflow: tldr-pages/tlrc/.github/workflows/build-release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tmc/json-to-struct/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: tmc\n    repo_name: json-to-struct\n    description: A simple command-line tool for generating to struct definitions from JSON\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tmccombs/hcl2json/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tmccombs\n    repo_name: hcl2json\n    description: Convert hcl2 to json\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.2\"\n        asset: hcl2json_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.3.3\"\n        asset: hcl2json_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.0.2\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: hcl2json_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.3.5\")\n        asset: hcl2json_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.3\")\n        asset: hcl2json_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: semver(\"<= 0.6.5\")\n        asset: hcl2json_{{.OS}}_{{.Arch}}\n        format: raw\n      - version_constraint: Version == \"v0.6.6\"\n        asset: hcl2json_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: hcl2json_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: hcl2json_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        checksum:\n          type: github_release\n          asset: hcl2json_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tmknom/actdocs/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tmknom\n    repo_name: actdocs\n    description: Generate documentation from Actions and Reusable Workflows\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: actdocs_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: actdocs_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: actdocs_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        github_artifact_attestations:\n          signer_workflow: tmknom/release-workflows/.github/workflows/go.yml\n        checksum:\n          type: github_release\n          asset: actdocs_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/tmknom/actdocs/releases/download/{{.Version}}/actdocs_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity-regexp\n              - \"^https://github\\\\.com/tmknom/release-workflows/\\\\.github/workflows/go\\\\.yml@\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/tmknom/actdocs/releases/download/{{.Version}}/actdocs_{{trimV .Version}}_checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tmux/tmux-builds/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tmux\n    repo_name: tmux-builds\n    description: tmux builds\n    files:\n      - name: tmux\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"preview\"\n        error_message: The preview version isn't supported.\n      - version_constraint: \"true\"\n        asset: tmux-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tofuutils/tenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tofuutils\n    repo_name: tenv\n    description: OpenTofu / Terraform version manager\n    files:\n      - name: tenv\n      - name: terraform\n      - name: tofu\n      - name: terragrunt\n      - name: tf\n      - name: atmos\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: tenv_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n        checksum:\n          type: github_release\n          asset: tenv_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.0.6\"\n        asset: tenv_.{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          enabled: false\n      - version_constraint: Version == \"v1.0.7\"\n        asset: tenv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tenv_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.1.1\")\n        # 1.0.8 terragrunt\n        asset: tenv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n          - name: terragrunt\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tenv_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.10.2\")\n        # 1.2.0 tf\n        asset: tenv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n          - name: terragrunt\n          - name: tf\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tenv_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.11.19\")\n        # 1.11.0 atmos\n        asset: tenv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n          - name: terragrunt\n          - name: tf\n          - name: atmos\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tenv_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: tenv_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: tenv\n          - name: terraform\n          - name: tofu\n          - name: terragrunt\n          - name: tf\n          - name: atmos\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: tenv_{{.Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity\n              - https://github.com/tofuutils/tenv/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/tofuutils/tenv/releases/download/{{.Version}}/tenv_{{.Version}}_checksums.txt.sig\n              - --certificate\n              - https://github.com/tofuutils/tenv/releases/download/{{.Version}}/tenv_{{.Version}}_checksums.txt.pem\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tofuutils/tofuenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_archive\n    repo_owner: tofuutils\n    repo_name: tofuenv\n    description: OpenTofu version manager\n    supported_envs:\n      - darwin\n      - linux\n    files:\n      - name: tofuenv\n        src: tofuenv-{{trimV .Version}}/bin/tofuenv\n      - name: tofu\n        src: tofuenv-{{trimV .Version}}/bin/tofu\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tohjustin/kube-lineage/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tohjustin\n    repo_name: kube-lineage\n    description: A CLI tool to display all dependencies or dependents of an object in a Kubernetes cluster\n    asset: kube-lineage_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: kubectl-lineage\n        src: kube-lineage\n      - name: kube-lineage\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.2.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.2.0\")\n        files:\n          - name: kubectl-lineage\n        asset: kubectl-lineage_{{.OS}}_{{.Arch}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tombi-toml/tombi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tombi-toml\n    repo_name: tombi\n    description: TOML Formatter / Linter / Language Server\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.3.27\" || semver(\"<= 0.2.23\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.3.37\")\n        asset: tombi-cli-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: tombi\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.3.38\")\n        asset: tombi-cli-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: tombi\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: tombi\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n      - version_constraint: semver(\"<= 0.3.39\")\n        asset: tombi-cli-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: tombi\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: tombi\n      - version_constraint: \"true\"\n        asset: tombi-cli-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: gz\n        files:\n          - name: tombi\n            src: \"{{.AssetWithoutExt}}\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: tombi\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tomnomnom/gron/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tomnomnom\n    repo_name: gron\n    description: Make JSON greppable\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.1\"\n        asset: gron-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.1.2\")\n        asset: gron-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: gron-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.2\")\n        asset: gron-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: gron-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tgz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gron-{{.OS}}-{{.Arch}}-{{trimV .Version}}.{{.Format}}\n        format: tgz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tomohiro/gyazo-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tomohiro\n    repo_name: gyazo-cli\n    description: Gyazo command-line uploader\n    asset: gyazo-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    files:\n      - name: gyazo-cli\n        src: gyazo-cli_{{.Version}}_{{.OS}}_{{.Arch}}/gyazo-cli\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: \"{{.Version}}_SHA256SUMS\"\n      algorithm: sha256\n    version_constraint: semver(\">= 1.0.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 1.0.0\")\n        asset: gyazo_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: gyazo\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/topgrade-rs/topgrade/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: topgrade-rs\n    repo_name: topgrade\n    description: Upgrade all the things\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v9.1.0\", \"v10.2.5\"]\n        no_asset: true\n      - version_constraint: Version == \"v10.0.0\"\n        asset: topgrade-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: linux-gnu\n        overrides:\n          - goos: linux\n            format: tar.gz\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - windows/amd64\n      - version_constraint: Version == \"v10.0.1\"\n        asset: topgrade-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n      - version_constraint: Version == \"v11.0.0\"\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 10.1.0-cd1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 10.1.0-cd5\")\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 10.1.0-rc1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 10.2.2\")\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 10.2.4\")\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 14.0.1\")\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 16.1.0\")\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v16.2.0\"\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        github_artifact_attestations:\n          signer_workflow: topgrade-rs/topgrade/.github/workflows/create_release_assets.yml\n      - version_constraint: \"true\"\n        asset: topgrade-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: topgrade-rs/topgrade/.github/workflows/create_release_assets.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/toshimaru/nyan/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: toshimaru\n    repo_name: nyan\n    description: Colored `cat` command\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.0.0\"\n        asset: nyan_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.9.2\")\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.9.6\")\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: nyan_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: nyan_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/traefik/yaegi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: traefik\n    repo_name: yaegi\n    description: Yaegi is Another Elegant Go Interpreter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.14\"\n        no_asset: true\n      - version_constraint: Version == \"v0.9.23\"\n        asset: yaegi_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: yaegi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.9.13\")\n        asset: yaegi_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: yaegi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: yaegi_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: yaegi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/transcend-io/terragrunt-atlantis-config/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: transcend-io\n    repo_name: terragrunt-atlantis-config\n    description: Generate Atlantis config for Terragrunt projects\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.10.1\") || Version in [\"v0.12.0\", \"v1.0.0\", \"v1.4.0\", \"v1.7.1\", \"v1.17.1\", \"v1.17.2\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 1.7.0\")\n        asset: terragrunt-atlantis-config_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: terragrunt-atlantis-config\n            src: \"{{.AssetWithoutExt}}/{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: terragrunt-atlantis-config\n                src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.17.4\")\n        asset: terragrunt-atlantis-config_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: terragrunt-atlantis-config\n            src: \"{{.AssetWithoutExt}}/{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: SHA256SUMS\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n          - goos: windows\n            files:\n              - name: terragrunt-atlantis-config\n                src: \"{{.AssetWithoutExt}}\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: terragrunt-atlantis-config_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/travis-ci/gimme/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: travis-ci\n    repo_name: gimme\n    path: gimme\n    description: Install go, yay\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/traviswt/gke-auth-plugin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: traviswt\n    repo_name: gke-auth-plugin\n    description: A GKE standalone auth plugin, with no dependencies on gcloud cli and python\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gke-auth-plugin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tree-sitter/tree-sitter/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tree-sitter\n    repo_name: tree-sitter\n    description: An incremental parsing system for programming tools\n    files:\n      - name: tree-sitter\n        src: tree-sitter-{{.OS}}-{{.Arch}}\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.20.8\"\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: semver(\"<= 0.18.0\")\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.20.7\")\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: macos\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.24.4\")\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: semver(\"<= 0.24.7\")\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: semver(\"<= 0.25.10\")\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x64\n          darwin: macos\n      - version_constraint: \"true\"\n        asset: tree-sitter-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: gz\n        replacements:\n          amd64: x64\n          darwin: macos\n        github_artifact_attestations:\n          signer_workflow: tree-sitter/tree-sitter/.github/workflows/release.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/truffleruby/truffleruby/community-native/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: truffleruby/truffleruby/community-native\n    aliases:\n      - name: oracle/truffleruby/community-native\n    type: github_release\n    repo_owner: truffleruby\n    repo_name: truffleruby\n    description: |\n      A high performance implementation of the Ruby programming language, built on GraalVM\n\n      *GraalVM Community Edition Native Standalone Version*\n\n      ## Setup\n\n      If you are using RubyGems or similar, please follow the steps below.\n\n      1. Install truffleruby with aqua\n      2. Install dependent libraries (make, gcc, g++, libssl-dev, libyaml-dev, libz-dev)\n      3. Run the shell script to enable dependent libraries ($EXTRACTED_DIRECTORY/lib/truffle/post_install_hook.sh)\n\n      For more information, see the following document:\n\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-llvm.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libssl.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libyaml.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-zlib.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-truffleruby.md#after-downloading\n    files:\n      - name: bundle\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: bundler\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: erb\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: gem\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: irb\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: racc\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rake\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rbs\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rdbg\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rdoc\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: ri\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: ruby\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: syntax_suggest\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: truffleruby\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: truffleruby-polyglot-get\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n    version_filter: not (Version matches \"-(dev|rc|preview)\")\n    version_prefix: graal-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 23.0.1\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: truffleruby-community-{{.SemVer}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/truffleruby/truffleruby/oracle-native/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: truffleruby/truffleruby/oracle-native\n    aliases:\n      - name: oracle/truffleruby/oracle-native\n    type: github_release\n    repo_owner: truffleruby\n    repo_name: truffleruby\n    description: |\n      A high performance implementation of the Ruby programming language, built on GraalVM\n\n      *Oracle GraalVM Native Standalone Version*\n\n      ## Setup\n\n      If you are using RubyGems or similar, please follow the steps below.\n\n      1. Install truffleruby with aqua\n      2. Install dependent libraries (make, gcc, g++, libssl-dev, libyaml-dev, libz-dev)\n      3. Run the shell script to enable dependent libraries ($EXTRACTED_DIRECTORY/lib/truffle/post_install_hook.sh)\n\n      For more information, see the following document:\n\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-llvm.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libssl.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-libyaml.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-zlib.md\n      - https://github.com/oracle/truffleruby/blob/master/doc/user/installing-truffleruby.md#after-downloading\n    files:\n      - name: bundle\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: bundler\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: erb\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: gem\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: irb\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: racc\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rake\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rbs\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rdbg\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: rdoc\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: ri\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: ruby\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: syntax_suggest\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: truffleruby\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n      - name: truffleruby-polyglot-get\n        src: \"{{.AssetWithoutExt}}/bin/{{.FileName}}\"\n    version_filter: not (Version matches \"-(dev|rc|preview)\")\n    version_prefix: graal-\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: truffleruby-{{.SemVer}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/trufflesecurity/driftwood/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: trufflesecurity\n    repo_name: driftwood\n    description: Private key usage verification\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: driftwood_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: driftwood_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: driftwood_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: driftwood_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/trufflesecurity/trufflehog/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: trufflesecurity\n    repo_name: trufflehog\n    description: Find, verify, and analyze leaked credentials\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"2.0.97\", \"v3.6.5\", \"v3.7.1\", \"v3.41.0\", \"v3.80.0\", \"3.80.4\", \"v3.82.10\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 3.63.1\")\n        asset: trufflehog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: trufflehog_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: trufflehog_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: trufflehog_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/trufflesecurity/trufflehog/releases/download/{{.Version}}/trufflehog_{{trimV .Version}}_checksums.txt.pem\n              - --certificate-identity\n              - https://github.com/trufflesecurity/trufflehog/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/trufflesecurity/trufflehog/releases/download/{{.Version}}/trufflehog_{{trimV .Version}}_checksums.txt.sig\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/trunk-io/launcher/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: trunk-io/launcher\n    type: http\n    # https://github.com/aquaproj/aqua-registry/issues/13989#issuecomment-1802981855\n    link: https://docs.trunk.io/reference/components#trunk-launcher\n    description: trunk launcher is a bash script that enables users to easily switch between multiple versions of trunk\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        type: http\n        url: https://trunk.io/releases/launcher/{{.Version}}/trunk\n        format: raw\n        complete_windows_ext: false\n        files:\n          - name: trunk\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/trzsz/trzsz-ssh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: trzsz\n    repo_name: trzsz-ssh\n    description: trzsz-ssh ( tssh ) is an ssh client designed as a drop-in replacement for the openssh client. It aims to provide complete compatibility with openssh, mirroring all its features, while also offering additional useful features. Such as login prompt, batch login, remember password, automated interaction, trzsz, zmodem(rz/sz), udp mode like mosh, etc\n    files:\n      - name: tssh\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tssh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        files:\n          - name: tssh\n            src: \"{{.AssetWithoutExt}}/tssh\"\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: tssh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tsenart/vegeta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tsenart\n    repo_name: vegeta\n    description: HTTP load testing tool and library. It's over 9000\n    rosetta2: true\n    supported_envs:\n      - darwin\n      - linux/amd64\n    asset: vegeta_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    checksum:\n      type: github_release\n      asset: vegeta_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tsl0922/ttyd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tsl0922\n    repo_name: ttyd\n    description: Share your terminal over the web\n    asset: ttyd.{{.Arch}}\n    format: raw\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      windows: win32\n    overrides:\n      - goos: windows\n        goarch: amd64\n        asset: ttyd.{{.OS}}.exe\n    supported_envs:\n      - linux\n      - windows/amd64\n    version_constraint: semver(\">= 1.7.3\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.7.0\")\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          windows: win10\n        overrides:\n          - goos: windows\n            goarch: amd64\n            asset: ttyd.{{.OS}}.exe\n      - version_constraint: semver(\"< 1.7.0\")\n        supported_envs:\n          - linux\n      - version_constraint: \"true\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tstack/lnav/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tstack\n    repo_name: lnav\n    description: Log file navigator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: lnav-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.8.2-alpha\"\n        asset: lnav-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.8.2\"\n        asset: lnav-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.8.3b\")\n        asset: lnav-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.8.5\")\n        asset: lnav-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"v0.9.0\"\n        asset: lnav-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: 64bit\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.11.0\")\n        asset: lnav-{{trimV .Version}}-musl-64bit.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        overrides:\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-os-x.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.11.1-test1\")\n        asset: lnav-0.11.1-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: lnav-0.11.1-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.11.2\")\n        asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}-musl.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.12.0\")\n        asset: lnav-{{trimV .Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.12.3\")\n        asset: lnav-{{trimV .Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v0.12.4\"\n        asset: lnav-{{trimV .Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: lnav-{{trimV .Version}}-{{.OS}}-musl-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: lnav\n            src: lnav-{{trimV .Version}}/lnav\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: lnav-{{trimV .Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            asset: lnav-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            files:\n              - name: lnav\n                src: lnav-{{trimV .Version}}/bin/lnav.exe\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tuist/tuist/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tuist\n    repo_name: tuist\n    description: A toolchain to generate Xcode projects from Swift packages\n    version_filter: Version matches \"^[0-9]\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 4.139.1\")\n        asset: tuist.zip\n        format: zip\n        supported_envs:\n          - darwin\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: tuist.zip\n        format: zip\n        checksum:\n          type: github_release\n          asset: SHASUMS256.txt\n          algorithm: sha256\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        overrides:\n          - goos: linux\n            asset: tuist-linux-{{.Arch}}.tar.gz\n            format: tar.gz\n        supported_envs:\n          - darwin\n          - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/tummychow/git-absorb/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: tummychow\n    repo_name: git-absorb\n    description: git commit --fixup, but automatic\n    files:\n      - name: git-absorb\n        src: git-absorb-{{.Version}}-{{.Arch}}-{{.OS}}/git-absorb\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.6\")\n        asset: git-absorb-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version == \"0.6.7\"\n        asset: git-absorb-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.10\")\n        asset: git-absorb-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: git-absorb-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/turbot/flowpipe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: turbot\n    repo_name: flowpipe\n    description: Flowpipe is a cloud scripting engine. Automation and workflow to connect your clouds to the people, systems and data that matters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: flowpipe.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/turbot/powerpipe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: turbot\n    repo_name: powerpipe\n    description: \"Powerpipe: Dashboards for DevOps. Visualize cloud configurations. Assess security posture against a massive library of benchmarks. Build custom dashboards with code\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: powerpipe.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/turbot/steampipe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: turbot\n    repo_name: steampipe\n    asset: steampipe_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: Use SQL to instantly query your cloud services (AWS, Azure, GCP and more). Open source CLI. No DB required\n    overrides:\n      - goos: darwin\n        format: zip\n    supported_envs:\n      - linux\n      - darwin\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/turbot/tailpipe/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: turbot\n    repo_name: tailpipe\n    description: select * from logs! Tailpipe is an open source SIEM for instant log insights, powered by DuckDB. Analyze millions of events in seconds, right from your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tailpipe.{{.OS}}.{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/twistedpair/google-cloud-sdk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: twistedpair\n    repo_name: google-cloud-sdk\n    description: CLI for interacting with Google Cloud products and services\n    version_source: github_tag\n    url: https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz\n    files:\n      - name: gcloud\n        src: google-cloud-sdk/bin/gcloud\n      - name: gsutil\n        src: google-cloud-sdk/bin/gsutil\n      - name: docker-credential-gcloud\n        src: google-cloud-sdk/bin/docker-credential-gcloud\n      - name: bq\n        src: google-cloud-sdk/bin/bq\n    replacements:\n      amd64: x86_64\n      arm64: arm\n    supported_envs:\n      - darwin\n      - linux\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/twpayne/chezmoi/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: twpayne\n    repo_name: chezmoi\n    description: Manage your dotfiles across multiple diverse machines, securely\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.5\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.5.10\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.7.5\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.7.10\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.8.11\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.3\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.0.6\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.1.5\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.13.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.21.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.27.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 2.29.4\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: tar.zst\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.pkg.{{.Format}}\n            files:\n              - name: chezmoi\n                src: usr/bin/chezmoi\n          - goos: darwin\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 2.66.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --signature\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_{{trimV .Version}}_checksums.txt.sig\n              - --key\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_cosign.pub\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: tar.zst\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.pkg.{{.Format}}\n            files:\n              - name: chezmoi\n                src: usr/bin/chezmoi\n          - goos: darwin\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n      - version_constraint: semver(\"<= 2.67.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --signature\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_{{trimV .Version}}_checksums.txt.sig\n              - --key\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_cosign.pub\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: tar.zst\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.pkg.{{.Format}}\n            files:\n              - name: chezmoi\n                src: usr/bin/chezmoi\n          - goos: darwin\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        github_immutable_release: true\n      - version_constraint: semver(\"<= 2.68.1\")\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}-glibc_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: \"chezmoi_{{trimV .Version}}_checksums.txt.sigstore.json\"\n            opts:\n              - --key\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_cosign.pub\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: tar.zst\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.pkg.{{.Format}}\n            files:\n              - name: chezmoi\n                src: usr/bin/chezmoi\n          - goos: darwin\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        github_immutable_release: true\n      - version_constraint: \"true\"\n        asset: chezmoi_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: chezmoi_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --key\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_cosign.pub\n              - --signature\n              - https://github.com/twpayne/chezmoi/releases/download/{{.Version}}/chezmoi_{{trimV .Version}}_checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n        github_immutable_release: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/txn2/kubefwd/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: txn2\n    repo_name: kubefwd\n    description: Bulk port forwarding Kubernetes services for local development\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.13.1\"\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: kubefwd_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"< 1.4.10\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.2\")\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: kubefwd_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.9.4\")\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: kubefwd_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.14.2\")\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: Darwin\n        checksum:\n          type: github_release\n          asset: kubefwd_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.14.7\")\n        asset: kubefwd_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: kubefwd\n            src: \"{{.AssetWithoutExt}}/kubefwd\"\n        replacements:\n          amd64: x86_64\n          darwin: macOS\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubefwd_{{.Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.18.1\")\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubefwd_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"< 1.24.1\")\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubefwd_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: kubefwd_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: kubefwd_checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: kubefwd_checksums.txt.sigstore.json\n            opts:\n              - --certificate-identity\n              - https://github.com/txn2/kubefwd/.github/workflows/release.yml@refs/tags/{{.Version}}\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/typst/typst/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: typst\n    repo_name: typst\n    description: A new markup-based typesetting system that is powerful and easy to learn\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: typst-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: typst\n            src: \"{{.AssetWithoutExt}}/typst\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: typst-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: typst\n            src: \"{{.AssetWithoutExt}}/typst\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: typst-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: typst\n            src: \"{{.AssetWithoutExt}}/typst\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: typst-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: typst\n            src: \"{{.AssetWithoutExt}}/typst\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/typstyle-rs/typstyle/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: typstyle-rs\n    repo_name: typstyle\n    aliases:\n      - name: Enter-tainer/typstyle\n    description: Beautiful and reliable typst code formatter\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.6\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.11.28\")\n        asset: typstyle-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x64\n          windows: win32\n      - version_constraint: \"true\"\n        asset: typstyle-{{.Arch}}-{{.OS}}\n        format: raw\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uber-go/mock/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: uber-go\n    repo_name: mock\n    description: GoMock is a mocking framework for the Go programming language\n    path: go.uber.org/mock/mockgen\n    files:\n      - name: mockgen\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ubicloud/cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: ubicloud/cli\n    type: github_release\n    repo_owner: ubicloud\n    repo_name: cli\n    description: Command line program for interacting with Ubicloud\n    files:\n      - name: ubi\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: ubi-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/umlx5h/gtrash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: umlx5h\n    repo_name: gtrash\n    description: \"A Featureful Trash CLI manager: alternative to rm and trash-cli\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gtrash_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: gtrash_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/undistro/marvin/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: undistro\n    repo_name: marvin\n    description: Marvin is a CLI tool that scans a k8s cluster by performing CEL expressions to report potential issues, misconfigurations and vulnerabilities\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: marvin_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/unfrl/dug/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: unfrl\n    repo_name: dug\n    description: A global DNS propagation checker that gives pretty output. Written in dotnet core\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.74\")\n        asset: dug-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: amd64\n            format: tar.gz\n            asset: dug.{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: dug\n      - version_constraint: Version == \"0.0.75\"\n        asset: dug.{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: raw\n            asset: dug-{{.OS}}-{{.Arch}}\n          - goos: darwin\n            asset: dug.0.0.1.{{.OS}}-{{.Arch}}.{{.Format}}\n          - goos: windows\n            format: raw\n            asset: dug\n      - version_constraint: \"true\"\n        asset: dug.{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x64\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: arm64\n            format: raw\n            asset: dug-{{.OS}}-{{.Arch}}\n          - goos: windows\n            format: raw\n            asset: dug\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/updatecli/updatecli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: updatecli\n    repo_name: updatecli\n    description: A Declarative Dependency Management tool\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.0.18\", \"v0.0.32\"]\n        no_asset: true\n      - version_constraint: Version == \"v0.0.23\"\n        asset: updatecli.amd64.exe\n        format: raw\n        supported_envs:\n          - windows\n      - version_constraint: semver(\"<= 0.0.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.0.10\")\n        asset: updatecli\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: updatecli.{{.OS}}.{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            asset: updatecli.{{.Arch}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: updatecli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: updatecli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.40.1\")\n        asset: updatecli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: updatecli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.110.3\")\n        asset: updatecli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate\n              - https://github.com/updatecli/updatecli/releases/download/{{.Version}}/checksums.txt.pem\n              - --certificate-identity\n              - \"https://github.com/updatecli/updatecli/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n              - --signature\n              - https://github.com/updatecli/updatecli/releases/download/{{.Version}}/checksums.txt.sig\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: updatecli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            bundle:\n              type: github_release\n              asset: checksums.txt.sig\n            opts:\n              - --certificate-identity\n              - \"https://github.com/updatecli/updatecli/.github/workflows/release.yaml@refs/tags/{{.Version}}\"\n              - --certificate-oidc-issuer\n              - https://token.actions.githubusercontent.com\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uptrace/uptrace/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: uptrace\n    repo_name: uptrace\n    description: \"Open source APM: OpenTelemetry traces, metrics, and logs\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.8\")\n        asset: uptrace_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: uptrace_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/upx/upx/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: upx\n    repo_name: upx\n    description: \"UPX - the Ultimate Packer for eXecutables\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v3.00\", \"v3.99\"]\n        no_asset: true\n      - version_constraint: Version == \"v3.91\"\n        asset: upx-{{trimV .Version}}-{{.Arch}}_{{.OS}}.{{.Format}}\n        format: tar.bz2\n        files:\n          - name: upx\n            src: \"{{.AssetWithoutExt}}/upx\"\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 3.94.0\")\n        asset: upx-{{trimV .Version}}-{{.Arch}}_{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: upx\n            src: \"{{.AssetWithoutExt}}/upx\"\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: upx-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: zip\n        files:\n          - name: upx\n            src: \"{{.AssetWithoutExt}}/upx\"\n        replacements:\n          windows: win64\n        overrides:\n          - goos: linux\n            format: tar.xz\n            asset: upx-{{trimV .Version}}-{{.Arch}}_{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux\n          - windows/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/urfave/gfmrun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: urfave\n    repo_name: gfmrun\n    description: GitHub-Flavored Markdown Runner\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.2.0\")\n        no_asset: true\n      - version_constraint: Version == \"v1.2.12-beta\"\n        asset: gfmrun-{{.OS}}-{{.Arch}}-{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          windows: win\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: gfmrun-{{.OS}}-{{.Arch}}-{{.Version}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/utkuozdemir/pv-migrate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: utkuozdemir\n    repo_name: pv-migrate\n    description: CLI tool to easily migrate Kubernetes persistent volumes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: pv-migrate-{{.OS}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: pv-migrate\n            src: bin/{{.OS}}/pv-migrate\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.5.4\"\n        asset: pv-migrate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        # disable checksum because asset names in the checksum file are different from actual asset names.\n        # https://github.com/aquaproj/aqua-registry/pull/12352#issuecomment-1558413383\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.3\")\n        asset: pv-migrate_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.6.2\")\n        asset: pv-migrate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: pv-migrate_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: pv-migrate_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uutils/coreutils/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: uutils\n    repo_name: coreutils\n    description: Cross-platform Rust rewrite of the GNU coreutils\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"0.0.9\", \"0.0.24\", \"0.0.25\", \"0.0.29\"]\n        no_asset: true\n      - version_constraint: Version == \"0.0.1\"\n        asset: uutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        files:\n          - name: uutils\n            src: uutils-{{.Version}}-{{.Arch}}-{{.OS}}/uutils\n      - version_constraint: Version == \"0.0.1.1\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.2\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.7\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - darwin\n          - linux/amd64\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.14\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - linux/amd64\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: semver(\"<= 0.0.22\")\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.23\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - linux/amd64\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.26\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin/arm64\n          - linux\n          - windows\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.0.27\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: Version == \"0.6.0\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: coreutils\n            src: coreutils-{{.Arch}}-{{.OS}}/coreutils\n      - version_constraint: \"true\"\n        asset: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        files:\n          - name: coreutils\n            src: coreutils-{{.Version}}-{{.Arch}}-{{.OS}}/coreutils\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uw-labs/strongbox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: uw-labs\n    repo_name: strongbox\n    description: Encryption for Git users\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0-rc2\")\n        asset: strongbox_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: strongbox_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"0.1.0-rc3\"\n        asset: strongbox_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: strongbox_{{.Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.1.0\"\n        asset: strongbox_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: strongbox_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.0-rc1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: strongbox_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: strongbox_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v0.2.1\"\n        asset: strongbox_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: strongbox_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.0.0-RC3\")\n        asset: strongbox_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: strongbox_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: strongbox_{{trimV .Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        checksum:\n          type: github_release\n          asset: strongbox_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uzimaru0000/oglens/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: uzimaru0000\n    repo_name: oglens\n    asset: og-{{.Arch}}-{{.OS}}.zip\n    description: Tools for viewing OGP\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n      windows: pc-windows-gnu\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: og\n        src: og-{{.Arch}}-{{.OS}}/og\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/uzimaru0000/tv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: uzimaru0000\n    repo_name: tv\n    description: Format json into table view\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: tv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: tv\n            src: \"{{.AssetWithoutExt}}/tv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-gnu\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/variadico/noti/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: variadico\n    repo_name: noti\n    description: Monitor a process and trigger a notification\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.3.0\"\n        asset: noti1.3.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"v2.0.0\", \"v2.6.0\"]\n        asset: noti{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v2.1.0\"\n        asset: noti{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v2.7.0\"\n        asset: noti{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.2.0\")\n        asset: noti\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: semver(\"<= 2.2.1\")\n        asset: noti{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 2.5.0\")\n        asset: noti{{trimV .Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.2.0\")\n        asset: noti{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 3.4.0\")\n        asset: noti{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        supported_envs:\n          - linux/amd64\n          - windows/amd64\n      - version_constraint: \"true\"\n        asset: noti{{.Version}}.{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vburenin/ifacemaker/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: go_install\n    repo_owner: vburenin\n    repo_name: ifacemaker\n    description: Generate interfaces from structure methods\n    version_constraint: semver(\">= 1.2.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        type: github_release\n        rosetta2: true\n        asset: ifacemaker_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: arm64\n            type: go_install\n            asset: \"\"\n            replacements: {}\n            checksum:\n              enabled: false\n          - goos: windows\n            goarch: arm64\n            type: go_install\n            asset: \"\"\n            replacements: {}\n            checksum:\n              enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/veeso/termscp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: veeso\n    repo_name: termscp\n    asset: termscp-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    description: A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      linux: unknown-linux-gnu\n      windows: pc-windows-msvc\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - amd64\n    version_constraint: semver(\">= 0.8.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 0.6.1\")\n        rosetta2: true\n      - version_constraint: \"true\"\n        asset: termscp-{{.OS}}.{{.Format}}\n        rosetta2: true\n        replacements:\n          darwin: mac\n          windows: msvc\n        overrides:\n          - goos: linux\n            format: txz\n            asset: termscp-{{trimV .Version}}.{{.Format}}\n            files:\n              - name: termscp\n                src: usr/local/bin/termscp\n          - goos: windows\n            format: zip\n            asset: termscp-{{trimV .Version}}-{{.OS}}.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vektra/mockery/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vektra\n    repo_name: mockery\n    description: A mock code autogenerator for Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v1.0.0\", \"v2.9.0\"]\n        no_asset: true\n      - version_constraint: Version == \"v2.9.6\"\n        asset: mockery_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.7.4\")\n        asset: mockery_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.10.1\")\n        asset: mockery_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: mockery_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksum.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/version-fox/vfox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: version-fox\n    repo_name: vfox\n    description: A cross-platform and extendable version manager with support for Java, Node.js, Flutter, .Net & more\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.2.5\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: vfox_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: vfox\n            src: \"{{.AssetWithoutExt}}/vfox\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n          cosign:\n            opts:\n              - --certificate-identity-regexp\n              - \"https://github\\\\.com/version-fox/vfox/\\\\.github/workflows/go-releaser\\\\.yml@.*\"\n              - --certificate-oidc-issuer\n              - \"https://token.actions.githubusercontent.com\"\n              - --signature\n              - https://github.com/version-fox/vfox/releases/download/{{.Version}}/checksums.txt.sig\n              - --certificate\n              - https://github.com/version-fox/vfox/releases/download/{{.Version}}/checksums.txt.pem\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vi/websocat/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vi\n    repo_name: websocat\n    description: \"Command-line client for WebSockets, like netcat (or curl) for ws:// with advanced socat-like functions\"\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: raw\n    rosetta2: true\n    version_constraint: semver(\">= 1.10.0\")\n    asset: websocat.{{.Arch}}-{{.OS}}\n    replacements:\n      darwin: apple-darwin\n      amd64: x86_64\n      windows: pc-windows-gnu\n      linux: unknown-linux-musl\n      arm64: aarch64\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - darwin\n          - amd64\n        asset: websocat_{{.OS}}\n        replacements:\n          darwin: mac\n          linux: linux64\n          windows: win64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/viaduct-ai/kustomize-sops/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: viaduct-ai\n    repo_name: kustomize-sops\n    description: KSOPS - A Flexible Kustomize Plugin for SOPS Encrypted Resources\n    version_constraint: \"false\"\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    files:\n      - name: ksops\n    version_overrides:\n      - version_constraint: semver(\"<= 2.1.5\")\n        no_asset: true\n      - version_constraint: semver(\"<= 2.3.2\")\n        asset: ksops_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 2.5.6\")\n        asset: ksops_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 3.0.1\")\n        asset: ksops_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: ksops_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vishaltelangre/ff/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vishaltelangre\n    repo_name: ff\n    description: Find files (ff) by name, fast\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.1\"\n        asset: ff-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: find-files-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vishnubob/wait-for-it/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_content\n    repo_owner: vishnubob\n    repo_name: wait-for-it\n    description: Pure bash script to test and wait on the availability of a TCP host and port\n    path: wait-for-it.sh\n    format: raw\n    supported_envs:\n      - linux\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/visma-prodsec/confused/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: visma-prodsec\n    repo_name: confused\n    description: Tool to check for dependency confusion vulnerabilities in multiple package management systems\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: confused_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macOS\n        checksum:\n          type: github_release\n          asset: confused_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vladimirvivien/ktop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vladimirvivien\n    repo_name: ktop\n    description: A top-like tool for your Kubernetes clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: ktop_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: ktop_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vmware/govmomi/govc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: vmware/govmomi/govc\n    type: github_release\n    repo_owner: vmware\n    repo_name: govmomi\n    description: a vSphere CLI built on top of govmomi\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: govc\n            src: govc_{{.OS}}_{{.Arch}}\n        overrides:\n          - goos: windows\n            asset: govc_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.18.0\"\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: govc\n            src: govc_{{.OS}}_{{.Arch}}\n        checksum:\n          type: github_release\n          asset: govc_{{trimV .Version}}_checksums.txt\n          algorithm: sha1\n        overrides:\n          - goos: windows\n            format: zip\n            asset: govc_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n            files:\n              - name: govc\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: govc\n            src: govc_{{.OS}}_{{.Arch}}\n        overrides:\n          - goos: windows\n            format: zip\n            asset: govc_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"v0.25.0\"\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.27.4\")\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: govc_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vmware/govmomi/vcsim/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: vmware/govmomi/vcsim\n    type: github_release\n    repo_owner: vmware\n    repo_name: govmomi\n    description: A vCenter and ESXi API based simulator\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.24.0\")\n        no_asset: true\n      - version_constraint: Version == \"v0.25.0\"\n        asset: vcsim_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.27.4\")\n        asset: vcsim_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: vcsim_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vmware-archive/octant/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vmware-archive\n    repo_name: octant\n    aliases:\n      - name: vmware-tanzu/octant\n    description: Highly extensible platform for developers to better understand the complexity of Kubernetes clusters\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.0\")\n        asset: octant_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: octant\n            src: \"{{.AssetWithoutExt}}/octant\"\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.17.0\")\n        asset: octant_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: octant\n            src: \"{{.AssetWithoutExt}}/octant\"\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.24.0\")\n        asset: octant_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: octant\n            src: \"{{.AssetWithoutExt}}/octant\"\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: octant_{{trimV .Version}}_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: octant\n            src: \"{{.AssetWithoutExt}}/octant\"\n        replacements:\n          amd64: 64bit\n          darwin: macOS\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/vmware-tanzu/velero/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: vmware-tanzu\n    repo_name: velero\n    description: Backup and migrate Kubernetes applications and their persistent volumes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.8.0-rc.1\"\n        asset: ark-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ark\n      - version_constraint: Version == \"v0.10.0-beta.1\"\n        asset: ark-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ark\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n      - version_constraint: Version == \"v1.10.0-rc.2\"\n        asset: velero-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: velero\n            src: \"{{.AssetWithoutExt}}/velero\"\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: ark-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ark\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.10.2\")\n        asset: ark-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: ark\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n      - version_constraint: semver(\"<= 1.10.3\")\n        asset: velero-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: velero\n            src: \"{{.AssetWithoutExt}}/velero\"\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: velero-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: velero\n            src: \"{{.AssetWithoutExt}}/velero\"\n        checksum:\n          type: github_release\n          asset: CHECKSUM\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/volta-cli/volta/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: volta-cli\n    repo_name: volta\n    description: \"Volta: JS Toolchains as Code\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.5\")\n        asset: notion-{{trimV .Version}}-{{.OS}}.sh\n        format: raw\n        rosetta2: true\n        files:\n          - name: notion\n        replacements:\n          darwin: macos\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: notion-{{trimV .Version}}-{{.OS}}-openssl-1.0.sh\n        format: raw\n        rosetta2: true\n        files:\n          - name: notion\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: notion-{{trimV .Version}}-{{.OS}}.sh\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.4.1\")\n        asset: notion-{{trimV .Version}}-{{.OS}}-openssl-1.0.1.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: macos\n        files:\n          - name: notion\n        overrides:\n          - goos: darwin\n            asset: notion-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: volta-{{trimV .Version}}-{{.OS}}-openssl-1.0.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.0.0\")\n        asset: volta-{{trimV .Version}}-{{.OS}}-openssl-1.0.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n          - goos: windows\n            format: zip\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.6\")\n        asset: volta-{{trimV .Version}}-{{.OS}}-openssl-1.0.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            asset: volta-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.0.8\")\n        asset: volta-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            asset: volta-{{trimV .Version}}-{{.OS}}-openssl-1.0.{{.Format}}\n          - goos: darwin\n            goarch: amd64\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n          - goos: darwin\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            goarch: arm64\n            asset: volta-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: volta-{{trimV .Version}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: volta-{{trimV .Version}}-{{.OS}}-arm.{{.Format}}\n          - goos: windows\n            format: zip\n          - goos: windows\n            goarch: arm64\n            asset: volta-{{trimV .Version}}-{{.OS}}-arm64.{{.Format}}\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wader/fq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wader\n    repo_name: fq\n    description: \"jq for binary formats - tool, language and decoders for working with binary and text formats\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.4\")\n        asset: fq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: fq_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wagoodman/dive/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wagoodman\n    repo_name: dive\n    description: A tool for exploring each layer in a docker image\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.3.0\")\n        asset: dive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: dive_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: dive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: dive_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: dive_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: dive_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wakatara/harsh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wakatara\n    repo_name: harsh\n    description: Habit tracking for geeks. A minimalist, command line tool for tracking and understanding your habits\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.8.7\")\n        asset: harsh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.8.10\")\n        asset: harsh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: harsh_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wakatime/wakatime-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wakatime\n    repo_name: wakatime-cli\n    description: Command line interface used by all WakaTime text editor plugins\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.6.0-alpha.5\"\n        no_asset: true\n      - version_constraint: semver(\"<= 0.4.0-alpha.1\")\n        asset: wakatime-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: wakatime-cli\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: checksums_sha256.txt\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            format: tar.gz\n      - version_constraint: semver(\"<= 1.28.1-alpha.3\")\n        asset: wakatime-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: wakatime-cli\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: checksums_sha256.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: wakatime-cli-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        files:\n          - name: wakatime-cli\n            src: \"{{.AssetWithoutExt}}\"\n        checksum:\n          type: github_release\n          asset: checksums_sha256.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/walles/moor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: walles\n    repo_name: moor\n    description: Moor is a pager. It's designed to just do the right thing without any configuration\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.23.3\"\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: moar\n        supported_envs:\n          - windows\n      - version_constraint: semver(\"<= 0.9.7\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.1\")\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        files:\n          - name: moar\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 1.11.4\")\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: moar\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 1.23.7\")\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: moar\n            link: moar\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: semver(\"<= 1.31.4\")\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: moar\n            link: moar\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: semver(\"<= 1.33.0\")\n        asset: moar-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: moar\n            link: moar\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: moor-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        files:\n          - name: moor\n            link: moor\n        supported_envs:\n          - darwin\n          - windows\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wallix/awless/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wallix\n    repo_name: awless\n    description: A Mighty CLI for AWS\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.0.25\")\n        asset: awless-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: awless-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wasmCloud/wasmCloud/wash/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: wasmCloud/wasmCloud/wash\n    type: github_release\n    repo_owner: wasmCloud\n    repo_name: wasmCloud\n    description: wasmCloud is an open source Cloud Native Computing Foundation (CNCF) project that enables teams to build, manage, and scale polyglot apps across any cloud, K8s, or edge\n    version_prefix: wash-v\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: wash-{{.Arch}}-{{.OS}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wasmerio/wapm-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wasmerio\n    repo_name: wapm-cli\n    asset: wapm-cli-{{.OS}}-{{.Arch}}.tar.gz\n    description: WebAssembly Package Manager (CLI)\n    replacements:\n      arm64: aarch64\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: wapm\n        src: bin/wapm\n      - name: wax\n        src: bin/wax\n    overrides:\n      - goos: windows\n        files:\n          - name: wapm\n            src: bin/wapm.exe\n          - name: wax\n            src: bin/wax.cmd\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wasmerio/wasmer/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wasmerio\n    repo_name: wasmer\n    description: The leading WebAssembly Runtime supporting WASI and Emscripten\n    asset: wasmer-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    replacements:\n      arm64: aarch64\n    overrides:\n      - goos: darwin\n        replacements:\n          arm64: arm64\n      - goos: linux\n        goarch: arm64\n        files:\n          - name: wasmer\n            src: bin/wasmer\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    files:\n      - name: wasmer\n        src: bin/wasmer\n      - name: wasmer-headless\n        src: bin/wasmer-headless\n    version_constraint: semver(\">= 3.0.0-beta\")\n    version_overrides:\n      - version_constraint: semver(\">= 3.0.0-alpha\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n        replacements: {}\n      - version_constraint: semver(\">= 2.2.1\")\n        files:\n          - name: wapm\n            src: bin/wapm\n          - name: wasmer-headless\n            src: bin/wasmer-headless\n          - name: wax\n            src: bin/wax\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: arm64\n          - goos: linux\n            goarch: arm64\n            files:\n              - name: wasmer\n                src: bin/wasmer\n          - goos: windows\n            files:\n              - name: wapm\n                src: bin/wapm.exe\n              - name: wasmer-headless\n                src: bin/wasmer-headless.exe\n              - name: wasmer\n                src: bin/wasmer.exe\n      - version_constraint: semver(\">= 2.0.0-rc1\")\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n      - version_constraint: semver(\">= 1.0.0-beta1\")\n        files:\n          - name: wasmer\n            src: bin/wasmer\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: raw\n            asset: wasmer-{{.OS}}\n        replacements: {}\n      - version_constraint: semver(\">= 1.0.0-alpha3\")\n        overrides:\n          - goos: linux\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: raw\n            asset: wasmer-{{.OS}}\n        replacements: {}\n        rosetta2: true\n      - version_constraint: semver(\">= 0.16.0\")\n        files: &wasmerio_wasmer_files_1\n          - name: wapm\n            src: bin/wapm\n          - name: wasmer\n            src: bin/wasmer\n        replacements: {}\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux/amd64\n      - version_constraint: semver(\">= 0.14.0\")\n        files: *wasmerio_wasmer_files_1\n        overrides:\n          - goos: windows\n            asset: wasmer-c-api-{{.OS}}.{{.Format}}\n        replacements: {}\n        supported_envs:\n          - darwin\n          - linux/amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.10.2\")\n        files: *wasmerio_wasmer_files_1\n        overrides:\n          - goos: windows\n            format: raw\n            asset: wasmer-{{.OS}}\n        replacements: {}\n        rosetta2: true\n      - version_constraint: semver(\">= 0.10.0\")\n        files: *wasmerio_wasmer_files_1\n        overrides:\n          - goos: windows\n            format: raw\n            asset: wasmer-{{.OS}}\n        replacements: {}\n        supported_envs:\n          - darwin\n          - amd64\n        rosetta2: true\n      - version_constraint: semver(\">= 0.3.0\")\n        files:\n          - name: wasmer\n            src: bin/wasmer\n        replacements: {}\n        supported_envs:\n          - linux/amd64\n          - darwin\n        rosetta2: true\n      - version_constraint: semver(\"< 0.3.0\")\n        asset: wasmer-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements: {}\n        supported_envs:\n          - darwin\n          - linux/amd64\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/watchexec/cargo-watch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: watchexec\n    repo_name: cargo-watch\n    description: Watches over your Cargo project's source\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 7.0.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 7.0.5\")\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-gnu\n        overrides:\n          - goos: windows\n            format: zip\n            files:\n              - name: cargo-watch\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 7.5.1\")\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 7.7.2\")\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              arm64: aarch64\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 8.0.0\")\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 8.1.1\")\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v8.1.2\"\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: cargo-watch-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        files:\n          - name: cargo-watch\n            src: \"{{.AssetWithoutExt}}/cargo-watch\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: SHA512SUMS\n          algorithm: sha512\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/watchexec/watchexec/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: watchexec\n    repo_name: watchexec\n    description: Executes commands in response to file modifications\n    asset: watchexec-{{trimV .SemVer}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    format: tar.xz\n    replacements:\n      windows: pc-windows-msvc\n      darwin: apple-darwin\n      amd64: x86_64\n      arm64: aarch64\n      linux: unknown-linux-musl\n    overrides:\n      - goos: windows\n        format: zip\n      - goarch: arm64\n        replacements:\n          linux: unknown-linux-gnu\n    files:\n      - name: watchexec\n        src: watchexec-{{trimV .SemVer}}-{{.Arch}}-{{.OS}}/watchexec\n    checksum:\n      type: github_release\n      asset: SHA512SUMS\n      algorithm: sha512\n    version_constraint: semver(\">= 1.21.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.21.0\")\n        checksum:\n          enabled: false\n      - version_constraint: semver(\">= 1.20.6\")\n        rosetta2: true\n      - version_constraint: semver(\">= 1.18.0\")\n        version_prefix: cli-\n      - version_constraint: semver(\"< 1.18.0\")\n        version_prefix: cli-\n        rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/weaviate/weaviate/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: weaviate\n    repo_name: weaviate\n    description: Weaviate is an open-source vector database that stores both objects and vectors, allowing for the combination of vector search with structured filtering with the fault tolerance and scalability of a cloud-native database\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.18.0-rc.0\") || Version == \"v1.18.6\"\n        no_asset: true\n      - version_constraint: Version == \"v1.22.1\"\n        asset: weaviate-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: darwin\n            asset: weaviate-v1.21.1-{{.OS}}-all.{{.Format}}\n            format: zip\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.19.5\") || Version == \"v1.19.13\"\n        asset: weaviate-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n      - version_constraint: semver(\"<= 1.20.6\")\n        asset: weaviate-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: darwin\n            asset: weaviate-{{.Version}}-{{.OS}}-all.{{.Format}}\n            format: zip\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 1.30.3\")\n        asset: weaviate-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: darwin\n            asset: weaviate-{{.Version}}-{{.OS}}-all.{{.Format}}\n            format: zip\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: weaviate-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        overrides:\n          - goos: darwin\n            asset: weaviate-{{.Version}}-{{.OS}}-all.{{.Format}}\n            format: zip\n        supported_envs:\n          # https://github.com/weaviate/weaviate/pull/8123\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/webdevops/go-crond/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: webdevops\n    repo_name: go-crond\n    description: \":alarm_clock: Cron daemon written in golang (for eg. usage in docker images)\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: go-crond-64-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.1\")\n        asset: go-crond-64-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: go-crond-{{.Arch}}-{{.OS}}\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 21.5.0\")\n        asset: go-crond-64-{{.OS}}\n        format: raw\n        replacements:\n          darwin: osx\n        overrides:\n          - goos: linux\n            goarch: arm64\n            asset: go-crond-arm64-linux\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: go-crond.{{.OS}}.{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/weedonandscott/trolley/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: weedonandscott\n    repo_name: trolley\n    description: Run terminal apps anywhere\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: trolley-cli-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: macos\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/werf/nelm/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: werf\n    repo_name: nelm\n    description: Nelm is a Helm 3 alternative. It is a Kubernetes deployment tool that manages Helm Charts and deploys them to Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.1\")\n        url: https://storage.googleapis.com/nelm-tuf/targets/releases/{{trimV .Version}}/{{.OS}}-{{.Arch}}/bin/nelm\n        format: raw\n        windows_arm_emulation: true\n      - version_constraint: \"true\"\n        url: https://tuf.nelm.sh/targets/releases/{{trimV .Version}}/{{.OS}}-{{.Arch}}/bin/nelm\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/werf/werf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: werf\n    repo_name: werf\n    description: A solution for implementing efficient and consistent software delivery to Kubernetes facilitating best practices.\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://tuf.werf.io/targets/releases/{{trimV .Version}}/{{.OS}}-{{.Arch}}/bin/werf\n        format: raw\n        windows_arm_emulation: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wfxr/csview/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wfxr\n    repo_name: csview\n    description: Pretty and fast csv viewer for cli with cjk/emoji support\n    asset: csview-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: linux\n        goarch: amd64\n        replacements:\n          linux: unknown-linux-musl\n      - goos: linux\n        goarch: arm64\n        replacements:\n          arm64: aarch64\n          linux: unknown-linux-gnu\n      - goos: windows\n        format: zip\n    files:\n      - name: csview\n        src: csview-{{.Version}}-{{.Arch}}-{{.OS}}/csview\n    replacements:\n      amd64: x86_64\n      darwin: apple-darwin\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    rosetta2: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/whalebrew/whalebrew/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: whalebrew\n    repo_name: whalebrew\n    description: Homebrew, but with Docker images\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.2.5\"\n        asset: whalebrew-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.1.0\")\n        asset: whalebrew-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.2.4\")\n        asset: whalebrew-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.3.1\")\n        asset: whalebrew-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: whalebrew-{{.OS}}-{{.Arch}}\n        format: raw\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/windvalley/gossh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: windvalley\n    repo_name: gossh\n    description: A high-performance and high-concurrency ssh tool written in Go. It is 10 times faster than Ansible. If you need much more performance and better ease of use, you will love it\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.6.1\"\n        no_asset: true\n      - version_constraint: semver(\"<= 1.12.0\")\n        asset: gossh-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: gossh-{{.Version}}-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/winebarrel/cronplan/cronmatch/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: winebarrel/cronplan/cronmatch\n    type: github_release\n    repo_owner: winebarrel\n    repo_name: cronplan\n    description: Cron expression parser for Amazon EventBridge\n    asset: cronmatch_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    version_constraint: semver(\">= 1.8.1\")\n    files:\n      - name: cronmatch\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\">= 1.2.0\")\n        checksum:\n          type: github_release\n          asset: cronmatch-checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/winebarrel/cronplan/cronplan/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    name: winebarrel/cronplan/cronplan\n    repo_owner: winebarrel\n    repo_name: cronplan\n    description: Cron expression parser for Amazon EventBridge\n    asset: cronplan_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    version_constraint: semver(\">= 1.8.1\")\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    version_overrides:\n      - version_constraint: semver(\">= 1.2.0\")\n        checksum:\n          type: github_release\n          asset: cronplan-checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/winebarrel/cronplan/cronviz/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: winebarrel/cronplan/cronviz\n    type: github_release\n    repo_owner: winebarrel\n    repo_name: cronplan\n    description: Cron expression parser for Amazon EventBridge\n    asset: cronviz_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    version_constraint: semver(\">= 1.8.1\")\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    files:\n      - name: cronviz\n    version_overrides:\n      - version_constraint: semver(\">= 1.5.0\")\n        checksum:\n          type: github_release\n          asset: cronviz-checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/woodpecker-ci/woodpecker/woodpecker-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: woodpecker-ci/woodpecker/woodpecker-cli\n    type: github_release\n    repo_owner: woodpecker-ci\n    repo_name: woodpecker\n    description: Woodpecker is a simple yet powerful CI/CD engine with great extensibility\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.11.0\")\n        no_asset: true\n      - version_constraint: Version in [\"v0.14.0-rc.2\", \"v0.15.0-rc1\", \"v2.2.0\", \"v2.2.1\"]\n        no_asset: true\n      - version_constraint: semver(\"<= 0.14.4\")\n        asset: woodpecker_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: woodpecker\n        checksum:\n          type: github_release\n          asset: woodpecker_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 2.6.1\")\n        asset: woodpecker-cli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: woodpecker-cli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wren-lang/wren-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wren-lang\n    repo_name: wren-cli\n    description: A command line tool for the Wren programming language\n    files:\n      - name: wren_cli\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.3.0\"\n        asset: wren_cli-{{.OS}}-{{.Version}}.{{.Format}}\n        format: zip\n        files:\n          - name: wren_cli\n            src: \"{{.AssetWithoutExt}}/wren_cli\"\n        overrides:\n          - goos: darwin\n            files:\n              - name: wren_cli\n            replacements:\n              darwin: mac\n          - goos: windows\n            files:\n              - name: wren_cli\n                src: wren_cli-{{.Version}}.exe\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: wren-cli-{{.OS}}-{{.Version}}.{{.Format}}\n        format: zip\n        files:\n          - name: wren_cli\n            src: \"{{.AssetWithoutExt}}/wren_cli\"\n        replacements:\n          darwin: mac\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wtetsu/gaze/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wtetsu\n    repo_name: gaze\n    asset: gaze_{{.OS}}_{{.Version}}.{{.Format}}\n    format: zip\n    description: Executes commands for you\n    replacements:\n      darwin: macos\n      arm64: arm\n      amd64: amd\n    overrides:\n      - goos: darwin\n        asset: gaze_{{.OS}}_{{.Arch}}_{{.Version}}.{{.Format}}\n        files:\n          - name: gaze\n            src: gaze_{{.OS}}_{{.Arch}}_{{.Version}}/gaze\n    supported_envs:\n      - darwin\n      - amd64\n    files:\n      - name: gaze\n        src: gaze_{{.OS}}_{{.Version}}/gaze\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/wtfutil/wtf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: wtfutil\n    repo_name: wtf\n    description: The personal information dashboard for your terminal\n    files:\n      - name: wtfutil\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.39.2\"\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtfutil\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.0.7\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: wtf\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.0.10\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtf\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: wtf_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtf\"\n        checksum:\n          type: github_release\n          asset: wtf_{{.Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.14.0\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtf\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.19.0\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtfutil\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.35.0\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtfutil\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.46.1\")\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: wtfutil\n            src: \"{{.AssetWithoutExt}}/wtfutil\"\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: wtf_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: wtfutil\n        checksum:\n          type: github_release\n          asset: wtf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/x-motemen/blogsync/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: x-motemen\n    repo_name: blogsync\n    asset: blogsync_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Push and pull blog entries from/to local filesystem\n    overrides:\n      - goos: linux\n        format: tar.gz\n    files:\n      - name: blogsync\n        src: blogsync_{{.Version}}_{{.OS}}_{{.Arch}}/blogsync\n    version_constraint: semver(\">= 0.12.3\")\n    version_overrides:\n      - version_constraint: semver(\"= 0.12.2\")\n        supported_envs:\n          - darwin\n          - linux\n      - version_constraint: \"true\"\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/x-motemen/ghq/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: x-motemen\n    repo_name: ghq\n    asset: ghq_{{.OS}}_{{.Arch}}.zip\n    description: Remote repository management made easy\n    files:\n      - name: ghq\n        src: ghq_{{.OS}}_{{.Arch}}/ghq\n    version_constraint: semver(\">= 1.3.0\")\n    version_overrides:\n      - version_constraint: \"true\"\n        supported_envs:\n          - amd64\n          - darwin\n        rosetta2: true\n    checksum:\n      type: github_release\n      asset: SHASUMS\n      file_format: regexp\n      algorithm: sha1\n      pattern:\n        checksum: ^(\\b[A-Fa-f0-9]{40}\\b)\n        file: \"^\\\\b[A-Fa-f0-9]{40}\\\\b\\\\s+(\\\\S+)$\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/x-motemen/gobump/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: x-motemen\n    repo_name: gobump\n    asset: gobump_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: zip\n    description: Bumps up Go program version\n    overrides:\n      - goos: linux\n        format: tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n    rosetta2: true\n    files:\n      - name: gobump\n        src: gobump_{{.Version}}_{{.OS}}_{{.Arch}}/gobump\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xataio/pgroll/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xataio\n    repo_name: pgroll\n    description: PostgreSQL zero-downtime migrations made easy\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: pgroll.{{.OS}}.{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        complete_windows_ext: false\n        replacements:\n          darwin: macos\n          windows: win\n      - version_constraint: \"true\"\n        asset: pgroll.{{.OS}}.{{.Arch}}\n        format: raw\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n          windows: win\n        checksum:\n          type: github_release\n          asset: pgroll_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xeol-io/xeol/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xeol-io\n    repo_name: xeol\n    description: A scanner for end-of-life (EOL) software and dependencies in container images, filesystems, and SBOMs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.4\")\n        asset: xeol_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: xeol_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.9.13\")\n        asset: xeol_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: xeol_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: xeol_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: xeol_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: xeol_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: xeol_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        slsa_provenance:\n          type: github_release\n          asset: multiple.intoto.jsonl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xiecat/fofax/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xiecat\n    repo_name: fofax\n    description: FOFAX是一个基于fofa.info的API命令行查询工具\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.34\")\n        asset: fofax_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: fofax_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xitonix/trubka/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xitonix\n    repo_name: trubka\n    description: A CLI tool for Kafka\n    rosetta2: true\n    asset: trubka_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz\n    supported_envs:\n      - darwin\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xo/dbtpl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xo\n    repo_name: dbtpl\n    aliases:\n      - name: xo/xo\n    description: Command line tool to generate idiomatic Go code for SQL databases supporting PostgreSQL, MySQL, SQLite, Oracle, and Microsoft SQL Server\n    files:\n      - name: xo\n      - name: dbtpl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.2\")\n        asset: xo-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        files:\n          - name: xo\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: xo-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        files:\n          - name: dbtpl\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xo/usql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xo\n    repo_name: usql\n    description: Universal command-line interface for SQL databases\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        asset: usql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.10.0\")\n        asset: usql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.15.2\")\n        asset: usql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: usql-{{trimV .Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.bz2\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xremap/xremap/gnome/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: xremap/xremap/gnome\n    aliases:\n      - name: k0kubun/xremap/gnome\n    type: github_release\n    repo_owner: xremap\n    repo_name: xremap\n    description: Key remapper for X11 and Wayland (for GNOME Wayland)\n    asset: xremap-{{.OS}}-{{.Arch}}-gnome.{{.Format}}\n    format: zip\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - linux\n    files:\n      - name: xremap\n    version_constraint: semver(\">= 0.5.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.5.0\")\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xremap/xremap/hypr/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: xremap/xremap/hypr\n    aliases:\n      - name: k0kubun/xremap/hypr\n    type: github_release\n    repo_owner: xremap\n    repo_name: xremap\n    description: Key remapper for X11 and Wayland (for Hyprland)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.7.12\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: xremap-{{.OS}}-{{.Arch}}-hypr.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: xremap\n      - version_constraint: \"true\"\n        error_message: |\n          The client for hypr was dropped.\n          https://github.com/xremap/xremap/pull/479\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xremap/xremap/kde/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: xremap/xremap/kde\n    aliases:\n      - name: k0kubun/xremap/kde\n    type: github_release\n    repo_owner: xremap\n    repo_name: xremap\n    description: Key remapper for X11 and Wayland (for KDE-Plasma Wayland)\n    asset: xremap-{{.OS}}-{{.Arch}}-kde.{{.Format}}\n    format: zip\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - linux\n    files:\n      - name: xremap\n    version_constraint: semver(\">= 0.8.3\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.8.3\")\n        no_asset: true\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xremap/xremap/sway/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: xremap/xremap/sway\n    aliases:\n      - name: k0kubun/xremap/sway\n    type: github_release\n    repo_owner: xremap\n    repo_name: xremap\n    description: Key remapper for X11 and Wayland (for Sway)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.4.6\")\n        asset: xremap-{{.OS}}-{{.Arch}}-sway.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux/amd64\n        files:\n          - name: xremap\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: xremap-{{.OS}}-{{.Arch}}-sway.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n        supported_envs:\n          - linux\n        files:\n          - name: xremap\n      - version_constraint: \"true\"\n        error_message: |\n          The client for sway was dropped.\n          https://github.com/xremap/xremap/pull/479\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xremap/xremap/x11/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - name: xremap/xremap/x11\n    aliases:\n      - name: k0kubun/xremap/x11\n    type: github_release\n    repo_owner: xremap\n    repo_name: xremap\n    description: Key remapper for X11 and Wayland (for X11)\n    asset: xremap-{{.OS}}-{{.Arch}}-x11.{{.Format}}\n    format: zip\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n    supported_envs:\n      - linux\n    files:\n      - name: xremap\n    version_constraint: semver(\">= 0.5.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.5.0\")\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xtaci/kcptun/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xtaci\n    repo_name: kcptun\n    asset: kcptun-{{.OS}}-{{.Arch}}-{{trimV .Version}}.tar.gz\n    description: A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC. Available for ARM, MIPS, 386 and AMD64\n    files:\n      - name: kcptun-client\n        src: client_{{.OS}}_{{.Arch}}\n      - name: kcptun-server\n        src: server_{{.OS}}_{{.Arch}}\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xwjdsh/manssh/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xwjdsh\n    repo_name: manssh\n    description: Manage your ssh alias configs easily\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.1\")\n        asset: manssh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: manssh_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: manssh_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/xxxserxxx/gotop/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: xxxserxxx\n    repo_name: gotop\n    description: A terminal based graphical activity monitor inspired by gtop and vtop\n    asset: gotop_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tgz\n    overrides:\n      - goos: windows\n        format: zip\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yamafaktory/jql/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yamafaktory\n    repo_name: jql\n    description: A JSON Query Language CLI tool\n    asset: \"{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\"\n    format: zip\n    overrides:\n      - goos: linux\n        format: tar.gz\n      - goos: windows\n        replacements:\n          arm64: arm64\n    replacements:\n      amd64: x86_64\n      arm64: aarch64\n      darwin: apple-darwin\n      linux: unknown-linux-musl\n      windows: pc-windows-msvc\n    supported_envs:\n      - darwin\n      - linux\n      - amd64\n    version_prefix: jql-\n    checksum:\n      type: github_release\n      asset: \"{{.Asset}}.sha256\"\n      algorithm: sha256\n    version_constraint: semver(\">= 6.0.7\")\n    version_overrides:\n      - version_constraint: semver(\">= 6.0.5\")\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 6.0.4\")\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 6.0.3\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\">= 5.1.3\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        version_prefix: \"\"\n      - version_constraint: semver(\">= 5.1.2\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        version_prefix: \"\"\n      - version_constraint: semver(\">= 5.1.1\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        version_prefix: \"\"\n      - version_constraint: semver(\">= 5.1.0\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        version_prefix: \"\"\n      - version_constraint: semver(\">= 3.2.4\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        overrides:\n          - goos: linux\n            format: tar.gz\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        version_prefix: \"\"\n      - version_constraint: semver(\"< 3.2.4\")\n        asset: jql-{{.Version}}-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: darwin\n            format: zip\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux\n          - darwin\n        version_prefix: \"\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yaml/yamlscript/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yaml\n    repo_name: yamlscript\n    description: Programming in YAML\n    version_constraint: \"false\"\n    asset: ys-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.xz\n    files:\n      - name: ys\n        src: \"{{.AssetWithoutExt}}/ys\"\n    replacements:\n      amd64: x64\n      arm64: aarch64\n      darwin: macos\n    version_overrides:\n      - version_constraint: Version in [\"0.1.29\", \"0.1.44\", \"0.1.50\"]\n        supported_envs:\n          - linux/amd64\n      - version_constraint: Version in [\"0.1.36\", \"0.1.63\", \"0.1.64\", \"0.1.66\"] or semver(\">= 0.1.69, <= 0.1.71\")\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version in [\"0.1.40\", \"0.1.60\", \"0.1.61\"]\n        supported_envs:\n          - linux\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.1.33\") or semver(\">= 0.1.36, <=0.1.39\") or Version == \"0.1.45\"\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.2.8\")\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yannh/kubeconform/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yannh\n    repo_name: kubeconform\n    description: A FAST Kubernetes manifests validator, with support for Custom Resources\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"0.1.0\"\n        asset: kubeconform-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.4.8\")\n        asset: kubeconform-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: CHECKSUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: kubeconform-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: CHECKSUMS\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yarnpkg/berry/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: yarnpkg\n    repo_name: berry\n    description: Active development trunk for Yarn\n    files:\n      - name: yarn\n    version_constraint: \"false\"\n    version_prefix: \"@yarnpkg/cli/\"\n    version_overrides:\n      - version_constraint: \"true\"\n        url: https://repo.yarnpkg.com/{{.SemVer}}/packages/yarnpkg-cli/bin/yarn.js\n        format: raw\n        complete_windows_ext: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yarnpkg/yarn/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yarnpkg\n    repo_name: yarn\n    search_words:\n      - v1 only\n    description: \"The 1.x line is frozen - features and bugfixes now happen on https://github.com/yarnpkg/berry\"\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yarn-{{.Version}}.tar.gz\n        files:\n          - name: yarn\n            src: \"{{.AssetWithoutExt}}/bin/yarn\"\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yashikota/exiftool-go/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yashikota\n    repo_name: exiftool-go\n    description: Pure Go ExifTool wrapper powered by WebAssembly\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: exiftool-go_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: exiftool-go_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yashikota/genenv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yashikota\n    repo_name: genenv\n    description: A simple CLI tool to generate .env files from template files, automatically filling in placeholders with cryptographically secure random values\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: genenv-{{.OS}}-{{.Arch}}\n        format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yassinebenaid/bunster/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yassinebenaid\n    repo_name: bunster\n    description: Compile shell scripts to static binaries\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.6.0\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.7.1\")\n        asset: bunster_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: bunster\n            src: bunster_{{.OS}}-{{.Arch}}\n      - version_constraint: \"true\"\n        asset: bunster_{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yassinebridi/serpl/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yassinebridi\n    repo_name: serpl\n    description: A simple terminal UI for search and replace, ala VS Code\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: serpl-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: serpl-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ycd/dstp/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ycd\n    repo_name: dstp\n    description: Run common networking tests against any site\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.1.3\")\n        asset: dstp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: dstp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: Version == \"v0.4.20\"\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: dstp_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yinheli/sshw/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yinheli\n    repo_name: sshw\n    asset: sshw_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    description: ssh client wrapper for automatic login\n    overrides:\n      - goos: windows\n        format: zip\n    checksum:\n      type: github_release\n      asset: sshw_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 1.1.1\")\n    version_overrides:\n      - version_constraint: semver(\">= 1.0.8\")\n        # asset name was changed\n        asset: sshw-{{.OS}}-{{.Arch}}-{{.Version}}.tar.gz\n        files:\n          - name: sshw\n            src: sshw-{{.OS}}-{{.Arch}}-{{.Version}}/sshw\n        overrides: []\n        # arm64 wasn't supported\n        rosetta2: true\n        supported_envs:\n          - darwin\n          - linux\n          - amd64\n        checksum:\n          # SHA1 is used for algorithm of checksum\n          type: github_release\n          asset: checksum.txt\n          file_format: regexp\n          algorithm: sha1\n          pattern:\n            checksum: ^(\\b[A-Fa-f0-9]{40}\\b)\n            file: \"^\\\\b[A-Fa-f0-9]{40}\\\\b\\\\s+(\\\\S+)$\"\n      - version_constraint: \"true\"\n        # asset name was changed\n        asset: sshw-{{.OS}}-{{.Arch}}.tar.gz\n        overrides: []\n        rosetta2: true\n        # windows wasn't supported\n        supported_envs:\n          - darwin\n          - linux/amd64\n        checksum:\n          # checksum file not provided\n          enabled: false\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yitsushi/totp-cli/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yitsushi\n    repo_name: totp-cli\n    description: Authy/Google Authenticator like TOTP CLI tool written in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.0.5\")\n        asset: totp-cli-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.1.3\")\n        asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n          algorithm: md5\n      - version_constraint: Version == \"v1.1.4\"\n        asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n          algorithm: md5\n      - version_constraint: semver(\"<= 1.1.9\")\n        asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n        checksum:\n          type: github_release\n          asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n          algorithm: md5\n      - version_constraint: Version == \"v1.1.10\"\n        asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n        checksum:\n          type: github_release\n          asset: totp-cli_{{.Version}}_{{.OS}}_{{.Arch}}_checksum.txt\n          algorithm: md5\n      - version_constraint: semver(\"<= 1.1.17\")\n        asset: totp-cli-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n      - version_constraint: semver(\"<= 1.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 1.8.5\")\n        asset: totp-cli-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.md5\"\n          algorithm: md5\n      - version_constraint: Version == \"v1.8.6\"\n        asset: totp-cli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: totp-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: totp-cli_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        overrides:\n          - goos: windows\n            format: zip\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: totp-cli_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ymtdzzz/otel-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ymtdzzz\n    repo_name: otel-tui\n    description: A terminal OpenTelemetry viewer inspired by otel-desktop-viewer\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: otel-tui_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: otel-tui_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ynqa/jnv/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ynqa\n    repo_name: jnv\n    description: Interactive JSON filter using jq\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: jnv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: jnv\n            src: \"{{.AssetWithoutExt}}/jnv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - darwin\n      - version_constraint: Version == \"v0.3.0\"\n        asset: jnv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: jnv\n            src: \"{{.AssetWithoutExt}}/jnv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: jnv\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.3\")\n        asset: jnv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        rosetta2: true\n        files:\n          - name: jnv\n            src: \"{{.AssetWithoutExt}}/jnv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: jnv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: jnv\n            src: \"{{.AssetWithoutExt}}/jnv\"\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-musl\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n          - goos: windows\n            format: zip\n            files:\n              - name: jnv\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: jnv-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.xz\n        windows_arm_emulation: true\n        files:\n          - name: jnv\n            src: \"{{.AssetWithoutExt}}/jnv\"\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          windows: pc-windows-msvc\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            goarch: amd64\n            replacements:\n              linux: unknown-linux-musl\n          - goos: linux\n            goarch: arm64\n            replacements:\n              linux: unknown-linux-gnu\n          - goos: windows\n            format: zip\n            files:\n              - name: jnv\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yoheimuta/protolint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yoheimuta\n    repo_name: protolint\n    description: A pluggable linter and fixer to enforce Protocol Buffer style and conventions\n    files:\n      - name: protolint\n      - name: protoc-gen-protolint\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.3\")\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        files:\n          - name: protolint\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.27.0\")\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.31.0\")\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.35.1\")\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.45.0\")\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: protolint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yokecd/yoke/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yokecd\n    repo_name: yoke\n    description: yoke is a Helm-inspired infrastructure-as-code (IaC) package deployer\n    version_filter: not (Version matches \"installer\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: yoke_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: gz\n        windows_arm_emulation: true\n        files:\n          - name: yoke\n            src: \"{{.AssetWithoutExt}}\"\n        overrides:\n          - goos: windows\n            asset: yoke_{{.Version}}_{{.OS}}_{{.Arch}}.exe.{{.Format}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yonahd/kor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yonahd\n    repo_name: kor\n    description: A Golang Tool to discover unused Kubernetes Resources\n    asset: kor_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    overrides:\n      - goos: windows\n        format: zip\n    replacements:\n      amd64: x86_64\n      darwin: Darwin\n      linux: Linux\n      windows: Windows\n    supported_envs:\n      - darwin\n      - amd64\n    checksum:\n      type: github_release\n      asset: kor_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n    version_constraint: semver(\">= 0.2.0\")\n    version_overrides:\n      - version_constraint: semver(\"< 0.2.0\")\n        rosetta2: true\n        files:\n          - name: kor\n            src: kor-{{.GOOS}}-{{if eq .GOOS \"darwin\"}}amd64{{else}}{{.GOARCH}}{{end}}\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yonaskolb/XcodeGen/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yonaskolb\n    repo_name: XcodeGen\n    description: A Swift command line tool for generating your Xcode project\n    asset: xcodegen.zip\n    files:\n      - name: xcodegen\n        src: xcodegen/bin/xcodegen\n    supported_envs:\n      - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yorukot/superfile/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yorukot\n    repo_name: superfile\n    aliases:\n      - name: MHNightCat/superfile\n    description: Pretty fancy and modern terminal file manager\n    files:\n      - name: spf\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.0.0\"\n        asset: spf\n        format: raw\n        supported_envs:\n          - linux/amd64\n      - version_constraint: \"true\"\n        asset: superfile-{{.OS}}-{{.Version}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: spf\n            src: dist/{{.AssetWithoutExt}}/spf\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ysugimoto/falco/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ysugimoto\n    repo_name: falco\n    description: falco is a VCL developer tool dedicated to Fastly\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.1\")\n        asset: falco-{{.OS}}-{{.Arch}}\n        format: raw\n        rosetta2: true\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.20.1\")\n        asset: falco-{{.OS}}-{{.Arch}}\n        format: raw\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 1.1.1\")\n        asset: falco-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: falco-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ysugimoto/gcsdeploy/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ysugimoto\n    repo_name: gcsdeploy\n    description: Deploy files to GCS like rsync\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: gcsdeploy-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ysugimoto/vintage/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ysugimoto\n    repo_name: vintage\n    description: VCL Transpiler for Edge Runtime\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: vintage-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        supported_envs:\n          - linux/amd64\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ytdl-org/ytdl-nightly/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: ytdl-org\n    repo_name: ytdl-nightly\n    description: Nightly builds for youtube-dl\n    files:\n      - name: youtube-dl\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"2024.03.28\"\n        asset: youtube-dl-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: youtube-dl\n            src: youtube-dl/youtube-dl\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: youtube-dl-{{.Version}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: youtube-dl\n            src: youtube-dl/youtube-dl\n        overrides:\n          - goos: windows\n            asset: youtube-dl\n            format: raw\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yudai/gotty/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yudai\n    repo_name: gotty\n    asset: gotty_{{.OS}}_{{.Arch}}.tar.gz\n    description: Share your terminal as a web application\n    supported_envs:\n      - linux/amd64\n      - darwin\n    rosetta2: true\n    checksum:\n      type: github_release\n      asset: SHA256SUMS\n      algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yujqiao/catproc/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yujqiao\n    repo_name: catproc\n    aliases:\n      - name: rapiz1/catp\n      - name: yujqiao/catp\n    description: Print the output of a running process\n    files:\n      - name: catp\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: catp-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          linux: unknown-linux-musl\n        supported_envs:\n          - linux/amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yukiarrr/ecsk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yukiarrr\n    repo_name: ecsk\n    description: CLI tool that you can interactively call Amazon ECS APIs (run-task, execute-command, stop-task), copy files between ECS and local, and view logs\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.6\")\n        asset: ecsk_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: ecsk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.9.0\")\n        asset: ecsk_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ecsk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: ecsk_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: ecsk_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yumafuu/s1m/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yumafuu\n    repo_name: s1m\n    description: TUI Application for AWS Systems Manager Parameter Store (ssm)\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version in [\"v0.2.2\", \"v0.2.3\"]\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: s1m_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: s1m_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yuuki/tcpulse/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yuuki\n    repo_name: tcpulse\n    description: A TCP/UDP load generator that provides fine-grained, flow-level control in Go\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: connperf_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: connperf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: connperf\n      - version_constraint: semver(\"<= 0.7.2\")\n        asset: connperf_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: connperf_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n        files:\n          - name: connperf\n      - version_constraint: semver(\"<= 0.8.1\")\n        asset: tcpulse_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n        checksum:\n          type: github_release\n          asset: tcpulse_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: \"true\"\n        asset: tcpulse_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: tcpulse_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/yuyaban/gitlab-comment/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: yuyaban\n    repo_name: gitlab-comment\n    description: About gitlab-comment is a CLI command to post Merge Request Note\n    asset: gitlab-comment_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: gitlab-comment_{{trimV .Version}}_checksums.txt\n      algorithm: sha256\n      cosign:\n        opts:\n          - --certificate-identity-regexp\n          - \"https://github\\\\.com/suzuki-shunsuke/go-release-workflow/\\\\.github/workflows/release\\\\.yaml@.*\"\n          - --certificate-oidc-issuer\n          - \"https://token.actions.githubusercontent.com\"\n          - --signature\n          - https://github.com/yuyaban/gitlab-comment/releases/download/{{.Version}}/gitlab-comment_{{trimV .Version}}_checksums.txt.sig\n          - --certificate\n          - https://github.com/yuyaban/gitlab-comment/releases/download/{{.Version}}/gitlab-comment_{{trimV .Version}}_checksums.txt.pem\n    slsa_provenance:\n      type: github_release\n      asset: multiple.intoto.jsonl\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zaghaghi/openapi-tui/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zaghaghi\n    repo_name: openapi-tui\n    description: Terminal UI to list, browse and run APIs defined with openapi spec\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.5.0\")\n        asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n      - version_constraint: Version == \"0.6.0\"\n        asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n      - version_constraint: \"true\"\n        asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        checksum:\n          type: github_release\n          asset: openapi-tui-{{.Version}}-{{.OS}}-{{.Arch}}.sha256\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zaquestion/lab/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zaquestion\n    repo_name: lab\n    description: Lab wraps Git or Hub, making it simple to clone, fork, and interact with repositories on GitLab\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.5.0\"\n        no_asset: true\n      - version_constraint: Version == \"v0.24.0\"\n        asset: lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: lab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.11.1\")\n        asset: lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: lab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.17.2\")\n        asset: lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.23.0\")\n        asset: lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: lab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: lab_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: lab_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zarf-dev/zarf/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zarf-dev\n    repo_name: zarf\n    description: The Airgap Native Packager Manager for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"< 0.51.0\")\n        error_message: Please use v0.51.0 or later\n      - version_constraint: \"true\"\n        asset: zarf_{{.Version}}_{{.OS}}_{{.Arch}}\n        format: raw\n        replacements:\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zegl/kube-score/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zegl\n    repo_name: kube-score\n    description: Kubernetes object analysis with recommendations for improved reliability and security. kube-score actively prevents downtime and bugs in your Kubernetes YAML and Charts. Static code analysis for Kubernetes\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v1.7.1\"\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: kube-score_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: Version == \"v1.11.0\"\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: Version == \"v1.12.0\"\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: semver(\"<= 0.4.0\")\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: semver(\"<= 0.6.0\")\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.7.3\")\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 1.10.1\")\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n      - version_constraint: \"true\"\n        asset: kube-score_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zellij-org/zellij/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zellij-org\n    repo_name: zellij\n    description: A terminal workspace with batteries included\n    supported_envs:\n      - darwin\n      - linux\n    asset: zellij-{{.Arch}}-{{.OS}}.tar.gz\n    replacements:\n      linux: unknown-linux-musl\n      darwin: apple-darwin\n      amd64: x86_64\n      arm64: aarch64\n    checksum:\n      enabled: false # https://github.com/aquaproj/aqua-registry/issues/6780#issuecomment-1267714776\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zerocore-ai/microsandbox/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zerocore-ai\n    repo_name: microsandbox\n    aliases:\n      - name: microsandbox/microsandbox\n    description: Self-Hosted Plaform for Secure Execution of Untrusted User/AI Code\n    files:\n      - name: msb\n    version_prefix: microsandbox-v\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: \"true\"\n        asset: microsandbox-{{.SemVer}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        files:\n          - name: msb\n            src: \"{{.AssetWithoutExt}}/msb\"\n          - name: msbrun\n            src: \"{{.AssetWithoutExt}}/msbrun\"\n          - name: msbserver\n            src: \"{{.AssetWithoutExt}}/msbserver\"\n          - name: msi\n            src: \"{{.AssetWithoutExt}}/msi\"\n          - name: msr\n            src: \"{{.AssetWithoutExt}}/msr\"\n          - name: msx\n            src: \"{{.AssetWithoutExt}}/msx\"\n        checksum:\n          type: github_release\n          asset: \"{{.Asset}}.sha256\"\n          algorithm: sha256\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n              arm64: aarch64\n        supported_envs:\n          - linux\n          - darwin/arm64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/ziglang/zig/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: ziglang\n    repo_name: zig\n    description: General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software\n    link: https://ziglang.org/\n    version_source: github_tag\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version contains \"-dev\"\n        url: https://ziglang.org/builds/zig-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        minisign:\n          type: http\n          url: https://ziglang.org/builds/zig-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        files:\n          - name: zig\n            src: zig-{{.OS}}-{{.Arch}}-{{.Version}}/zig\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 0.14.0\")\n        url: https://ziglang.org/download/{{.Version}}/zig-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        minisign:\n          type: http\n          url: https://ziglang.org/download/{{.Version}}/zig-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        files:\n          - name: zig\n            src: zig-{{.OS}}-{{.Arch}}-{{.Version}}/zig\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        url: https://ziglang.org/download/{{.Version}}/zig-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        minisign:\n          type: http\n          url: https://ziglang.org/download/{{.Version}}/zig-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        files:\n          - name: zig\n            src: zig-{{.Arch}}-{{.OS}}-{{.Version}}/zig\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zigtools/zls/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: http\n    repo_owner: zigtools\n    repo_name: zls\n    description: A Zig language server supporting Zig developers with features like autocomplete and goto definition\n    link: https://zigtools.org/\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.9.0\")\n        url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        rosetta2: true\n        windows_arm_emulation: true\n        minisign:\n          type: http\n          url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWR+9B91GBZ0zOjh6Lr17+zKf5BoSuFvrx2xSeDE57uIYvnKBGmMjOex\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: Version == \"0.10.0\"\n        url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        windows_arm_emulation: true\n        minisign:\n          type: http\n          url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWR+9B91GBZ0zOjh6Lr17+zKf5BoSuFvrx2xSeDE57uIYvnKBGmMjOex\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.14.0\")\n        url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}\n        windows_arm_emulation: true\n        minisign:\n          type: http\n          url: https://builds.zigtools.org/zls-{{.OS}}-{{.Arch}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWR+9B91GBZ0zOjh6Lr17+zKf5BoSuFvrx2xSeDE57uIYvnKBGmMjOex\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        url: https://builds.zigtools.org/zls-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}\n        windows_arm_emulation: true\n        minisign:\n          type: http\n          url: https://builds.zigtools.org/zls-{{.Arch}}-{{.OS}}-{{.Version}}.{{.Format}}.minisig\n          public_key: \"RWR+9B91GBZ0zOjh6Lr17+zKf5BoSuFvrx2xSeDE57uIYvnKBGmMjOex\"\n        replacements:\n          darwin: macos\n          arm64: aarch64\n          amd64: x86_64\n        format: tar.xz\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zitadel/zitadel/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zitadel\n    repo_name: zitadel\n    description: ZITADEL - The best of Auth0 and Keycloak combined. Built for the serverless era\n    asset: zitadel-{{.OS}}-{{.Arch}}.{{.Format}}\n    format: tar.gz\n    checksum:\n      type: github_release\n      asset: checksums.txt\n      algorithm: sha256\n    files:\n      - name: zitadel\n        src: zitadel-{{.OS}}-{{.Arch}}/zitadel\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zix99/rare/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zix99\n    repo_name: rare\n    description: Create console histograms, bar graphs, tables, heatmaps and more in realtime using regex and expressions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1.20\")\n        asset: rare_{{.OS}}_{{.Arch}}\n        format: raw\n        rosetta2: true\n        windows_arm_emulation: true\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.1.31\")\n        asset: rare_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.2.0\")\n        asset: rare_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: rare_{{.Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: checksums.txt\n          algorithm: sha256\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zizmorcore/zizmor/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zizmorcore\n    repo_name: zizmor\n    description: Static analysis for GitHub Actions\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.8.0-rc2\") || Version in [\"v1.12.0\", \"v1.13.0\"]\n        type: cargo\n        crate: zizmor\n      - version_constraint: \"true\"\n        asset: zizmor-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          arm64: aarch64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: windows\n            format: zip\n        github_artifact_attestations:\n          signer_workflow: zizmorcore/zizmor/.github/workflows/release-binaries.yml\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zk-org/zk/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zk-org\n    repo_name: zk\n    description: A plain text note-taking assistant\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.11.0\"\n        asset: zk-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: zip\n        replacements:\n          amd64: x86_64\n          darwin: macos\n        supported_envs:\n          - darwin\n      - version_constraint: semver(\"<= 0.2.1\")\n        asset: zk-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            format: zip\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.14.1\")\n        asset: zk-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            format: zip\n            replacements:\n              amd64: x86_64\n        supported_envs:\n          - linux\n          - darwin\n      - version_constraint: semver(\"<= 0.15.0\")\n        asset: zk-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            goarch: amd64\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            goarch: arm64\n            asset: zk-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n          - goos: windows\n            asset: zk-{{.Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n            replacements:\n              amd64: x64_86\n      - version_constraint: \"true\"\n        asset: zk-{{.Version}}-{{.OS}}-{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          darwin: macos\n        overrides:\n          - goos: darwin\n            replacements:\n              amd64: x86_64\n          - goos: windows\n            replacements:\n              amd64: x86_64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zmap/zlint/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zmap\n    repo_name: zlint\n    description: X.509 Certificate Linter focused on Web PKI standards and requirements\n    version_filter: not (Version matches \"-rc\")\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 1.1.0\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: zlint_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: zlint\n            src: \"{{.AssetWithoutExt}}/{{.FileName}}\"\n        replacements:\n          amd64: x86_64\n          darwin: Darwin\n          linux: Linux\n          windows: Windows\n        checksum:\n          type: github_release\n          asset: zlint_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zmwangx/ets/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zmwangx\n    repo_name: ets\n    description: Command output timestamper\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.1\")\n        asset: ets_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: ets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux/amd64\n          - darwin\n      - version_constraint: \"true\"\n        asset: ets_{{trimV .Version}}_{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        checksum:\n          type: github_release\n          asset: ets_{{trimV .Version}}_checksums.txt\n          algorithm: sha256\n        supported_envs:\n          - linux\n          - darwin\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zquestz/s/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zquestz\n    repo_name: s\n    description: Open a web search in your terminal\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: semver(\"<= 0.2.1\")\n        no_asset: true\n      - version_constraint: semver(\"<= 0.5.14\")\n        asset: s-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: s\n            src: \"{{.AssetWithoutExt}}/s\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: \"true\"\n        asset: s-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: zip\n        windows_arm_emulation: true\n        files:\n          - name: s\n            src: \"{{.AssetWithoutExt}}/s\"\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zurawiki/gptcommit/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zurawiki\n    repo_name: gptcommit\n    description: A git prepare-commit-msg hook for authoring commit messages with GPT-3\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.7\"\n        asset: gptcommit-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        replacements:\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n        overrides:\n          - goos: linux\n            replacements:\n              amd64: x86_64\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - linux/amd64\n          - darwin/arm64\n      - version_constraint: semver(\"<= 0.5.3\")\n        asset: gptcommit-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n      - version_constraint: semver(\"<= 0.5.5\")\n        no_asset: true\n      - version_constraint: \"true\"\n        asset: gptcommit-{{.Arch}}-{{.OS}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        replacements:\n          amd64: x86_64\n          darwin: apple-darwin\n          linux: unknown-linux-gnu\n          windows: pc-windows-msvc\n        overrides:\n          - goos: darwin\n            replacements:\n              arm64: aarch64\n        supported_envs:\n          - darwin\n          - windows\n          - amd64\n"
  },
  {
    "path": "crates/aqua-registry/aqua-registry/pkgs/zyedidia/eget/registry.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/registry.json\npackages:\n  - type: github_release\n    repo_owner: zyedidia\n    repo_name: eget\n    description: Easily install prebuilt binaries from GitHub\n    version_constraint: \"false\"\n    version_overrides:\n      - version_constraint: Version == \"v0.1.0\"\n        asset: eget-{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: eget\n            src: \"{{.AssetWithoutExt}}/eget\"\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: semver(\"<= 1.0.1\")\n        asset: eget-{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        rosetta2: true\n        windows_arm_emulation: true\n        files:\n          - name: eget\n            src: \"{{.AssetWithoutExt}}/eget\"\n        overrides:\n          - goos: windows\n            format: zip\n      - version_constraint: \"true\"\n        asset: eget-{{trimV .Version}}-{{.OS}}_{{.Arch}}.{{.Format}}\n        format: tar.gz\n        windows_arm_emulation: true\n        files:\n          - name: eget\n            src: \"{{.AssetWithoutExt}}/eget\"\n        overrides:\n          - goos: windows\n            format: zip\n"
  },
  {
    "path": "crates/aqua-registry/build.rs",
    "content": "use std::env;\nuse std::fs;\nuse std::path::Path;\n\nfn main() {\n    let out_dir = env::var(\"OUT_DIR\").expect(\"OUT_DIR environment variable must be set\");\n    generate_baked_registry(&out_dir);\n}\nfn generate_baked_registry(out_dir: &str) {\n    let dest_path = Path::new(out_dir).join(\"aqua_standard_registry.rs\");\n\n    let registry_dir = find_registry_dir();\n\n    let registries =\n        collect_aqua_registries(&registry_dir).expect(\"Failed to collect aqua registry files\");\n\n    if registries.is_empty() {\n        panic!(\n            \"No aqua registry files found in {}/pkgs/\",\n            registry_dir.display()\n        );\n    }\n\n    let mut code = String::from(\"HashMap::from([\\n\");\n    for (id, content) in registries {\n        code.push_str(&format!(\"    ({:?}, {:?}),\\n\", id, content));\n    }\n    code.push_str(\"])\");\n\n    fs::write(dest_path, code).expect(\"Failed to write baked registry file\");\n}\n\nfn find_registry_dir() -> std::path::PathBuf {\n    // Registry location is constant: crates/aqua-registry/aqua-registry\n    let manifest_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"CARGO_MANIFEST_DIR environment variable must be set\");\n    let embedded = std::path::Path::new(&manifest_dir).join(\"aqua-registry\");\n    if embedded.exists() {\n        return embedded;\n    }\n    panic!(\"Registry directory not found\");\n}\n\nfn collect_aqua_registries(\n    dir: &Path,\n) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {\n    let mut registries = Vec::new();\n\n    if !dir.exists() {\n        return Ok(registries);\n    }\n\n    let pkgs_dir = dir.join(\"pkgs\");\n    if !pkgs_dir.exists() {\n        return Ok(registries);\n    }\n\n    collect_registries_recursive(&pkgs_dir, &mut registries, String::new())?;\n    Ok(registries)\n}\n\nfn collect_registries_recursive(\n    dir: &Path,\n    registries: &mut Vec<(String, String)>,\n    prefix: String,\n) -> Result<(), Box<dyn std::error::Error>> {\n    for entry in fs::read_dir(dir)? {\n        let entry = entry?;\n        let path = entry.path();\n\n        if path.is_dir() {\n            let dir_name = path.file_name().unwrap().to_string_lossy();\n            let new_prefix = if prefix.is_empty() {\n                dir_name.to_string()\n            } else {\n                format!(\"{}/{}\", prefix, dir_name)\n            };\n            collect_registries_recursive(&path, registries, new_prefix)?;\n        } else if path.file_name() == Some(std::ffi::OsStr::new(\"registry.yaml\")) {\n            let content = fs::read_to_string(&path)?;\n            registries.push((prefix.clone(), content.clone()));\n\n            // Process aliases if they exist\n            #[allow(clippy::collapsible_if)]\n            if content.contains(\"aliases\") {\n                if let Ok(registry) = serde_yaml::from_str::<serde_yaml::Value>(&content) {\n                    if let Some(packages) = registry.get(\"packages\").and_then(|p| p.as_sequence()) {\n                        for package in packages {\n                            if let Some(aliases) =\n                                package.get(\"aliases\").and_then(|a| a.as_sequence())\n                            {\n                                for alias in aliases {\n                                    if let Some(name) = alias.get(\"name\").and_then(|n| n.as_str()) {\n                                        registries.push((name.to_string(), content.clone()));\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "crates/aqua-registry/src/lib.rs",
    "content": "//! Aqua Registry\n//!\n//! This crate provides functionality for working with Aqua package registry files.\n//! It can load registry data from baked-in files, local repositories, or remote HTTP sources.\n\nmod registry;\nmod template;\nmod types;\n\n// Re-export only what's needed by the main mise crate\npub use registry::{\n    AQUA_STANDARD_REGISTRY_FILES, AquaRegistry, DefaultRegistryFetcher, FileCacheStore,\n    NoOpCacheStore, package_ids,\n};\npub use types::{\n    AquaChecksum, AquaChecksumType, AquaMinisignType, AquaPackage, AquaPackageType, RegistryYaml,\n};\n\nuse thiserror::Error;\n\n/// Errors that can occur when working with the Aqua registry\n#[derive(Error, Debug)]\npub enum AquaRegistryError {\n    #[error(\"package not found: {0}\")]\n    PackageNotFound(String),\n    #[error(\"registry not available: {0}\")]\n    RegistryNotAvailable(String),\n    #[error(\"template error: {0}\")]\n    TemplateError(#[from] eyre::Error),\n    #[error(\"yaml parse error: {0}\")]\n    YamlError(#[from] serde_yaml::Error),\n    #[error(\"io error: {0}\")]\n    IoError(#[from] std::io::Error),\n    #[error(\"expression error: {0}\")]\n    ExpressionError(String),\n}\n\npub type Result<T> = std::result::Result<T, AquaRegistryError>;\n\n/// Configuration for the Aqua registry\n#[derive(Debug, Clone)]\npub struct AquaRegistryConfig {\n    /// Path to cache directory for cloned repositories\n    pub cache_dir: std::path::PathBuf,\n    /// URL of the registry repository (if None, only baked registry will be used)\n    pub registry_url: Option<String>,\n    /// Whether to use the baked-in registry\n    pub use_baked_registry: bool,\n    /// Whether to skip network operations (prefer offline mode)\n    pub prefer_offline: bool,\n}\n\nimpl Default for AquaRegistryConfig {\n    fn default() -> Self {\n        Self {\n            cache_dir: std::env::temp_dir().join(\"aqua-registry\"),\n            registry_url: Some(\"https://github.com/aquaproj/aqua-registry\".to_string()),\n            use_baked_registry: true,\n            prefer_offline: false,\n        }\n    }\n}\n\n/// Trait for fetching registry files from various sources\n#[allow(async_fn_in_trait)]\npub trait RegistryFetcher {\n    /// Fetch and parse a registry YAML file for the given package ID\n    async fn fetch_registry(&self, package_id: &str) -> Result<crate::types::RegistryYaml>;\n}\n\n/// Trait for caching registry data\npub trait CacheStore {\n    /// Check if cached data exists and is fresh\n    fn is_fresh(&self, key: &str) -> bool;\n    /// Store data in cache\n    fn store(&self, key: &str, data: &[u8]) -> std::io::Result<()>;\n    /// Retrieve data from cache\n    fn retrieve(&self, key: &str) -> std::io::Result<Option<Vec<u8>>>;\n}\n"
  },
  {
    "path": "crates/aqua-registry/src/registry.rs",
    "content": "use crate::types::{AquaPackage, RegistryYaml};\nuse crate::{AquaRegistryConfig, AquaRegistryError, CacheStore, RegistryFetcher, Result};\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::sync::LazyLock;\nuse tokio::sync::Mutex;\n\n/// The main Aqua registry implementation\n#[derive(Debug)]\npub struct AquaRegistry<F = DefaultRegistryFetcher, C = NoOpCacheStore>\nwhere\n    F: RegistryFetcher,\n    C: CacheStore,\n{\n    #[allow(dead_code)]\n    config: AquaRegistryConfig,\n    fetcher: F,\n    #[allow(dead_code)]\n    cache_store: C,\n    #[allow(dead_code)]\n    repo_exists: bool,\n}\n\n/// Default implementation of RegistryFetcher\n#[derive(Debug, Clone)]\npub struct DefaultRegistryFetcher {\n    config: AquaRegistryConfig,\n}\n\n/// No-op implementation of CacheStore\n#[derive(Debug, Clone, Default)]\npub struct NoOpCacheStore;\n\n/// File-based cache store implementation\n#[derive(Debug, Clone)]\npub struct FileCacheStore {\n    cache_dir: PathBuf,\n}\n\n/// Baked registry files (compiled into binary)\npub static AQUA_STANDARD_REGISTRY_FILES: LazyLock<HashMap<&'static str, &'static str>> =\n    LazyLock::new(|| include!(concat!(env!(\"OUT_DIR\"), \"/aqua_standard_registry.rs\")));\n\n/// Returns all package IDs from the baked-in aqua registry.\npub fn package_ids() -> Vec<&'static str> {\n    AQUA_STANDARD_REGISTRY_FILES.keys().copied().collect()\n}\n\nimpl AquaRegistry {\n    /// Create a new AquaRegistry with the given configuration\n    pub fn new(config: AquaRegistryConfig) -> Self {\n        let repo_exists = Self::check_repo_exists(&config.cache_dir);\n        let fetcher = DefaultRegistryFetcher {\n            config: config.clone(),\n        };\n        Self {\n            config,\n            fetcher,\n            cache_store: NoOpCacheStore,\n            repo_exists,\n        }\n    }\n\n    /// Create a new AquaRegistry with custom fetcher and cache store\n    pub fn with_fetcher_and_cache<F, C>(\n        config: AquaRegistryConfig,\n        fetcher: F,\n        cache_store: C,\n    ) -> AquaRegistry<F, C>\n    where\n        F: RegistryFetcher,\n        C: CacheStore,\n    {\n        let repo_exists = Self::check_repo_exists(&config.cache_dir);\n        AquaRegistry {\n            config,\n            fetcher,\n            cache_store,\n            repo_exists,\n        }\n    }\n\n    fn check_repo_exists(cache_dir: &std::path::Path) -> bool {\n        cache_dir.join(\".git\").exists()\n    }\n}\n\nimpl<F, C> AquaRegistry<F, C>\nwhere\n    F: RegistryFetcher,\n    C: CacheStore,\n{\n    /// Get a package definition by ID\n    pub async fn package(&self, id: &str) -> Result<AquaPackage> {\n        static CACHE: LazyLock<Mutex<HashMap<String, AquaPackage>>> =\n            LazyLock::new(|| Mutex::new(HashMap::new()));\n\n        if let Some(pkg) = CACHE.lock().await.get(id) {\n            return Ok(pkg.clone());\n        }\n\n        let registry = self.fetcher.fetch_registry(id).await?;\n        let mut pkg = registry\n            .packages\n            .into_iter()\n            .next()\n            .ok_or_else(|| AquaRegistryError::PackageNotFound(id.to_string()))?;\n\n        pkg.setup_version_filter()?;\n        CACHE.lock().await.insert(id.to_string(), pkg.clone());\n        Ok(pkg)\n    }\n\n    /// Get a package definition configured for specific versions\n    pub async fn package_with_version(\n        &self,\n        id: &str,\n        versions: &[&str],\n        os: &str,\n        arch: &str,\n    ) -> Result<AquaPackage> {\n        Ok(self.package(id).await?.with_version(versions, os, arch))\n    }\n}\n\nimpl RegistryFetcher for DefaultRegistryFetcher {\n    async fn fetch_registry(&self, package_id: &str) -> Result<RegistryYaml> {\n        let path_id = package_id\n            .split('/')\n            .collect::<Vec<_>>()\n            .join(std::path::MAIN_SEPARATOR_STR);\n        let path = self\n            .config\n            .cache_dir\n            .join(\"pkgs\")\n            .join(&path_id)\n            .join(\"registry.yaml\");\n\n        // Try to read from local repository first\n        if self.config.cache_dir.join(\".git\").exists() && path.exists() {\n            log::trace!(\"reading aqua-registry for {package_id} from repo at {path:?}\");\n            let contents = std::fs::read_to_string(&path)?;\n            return Ok(serde_yaml::from_str(&contents)?);\n        }\n\n        // Fall back to baked registry if enabled\n        #[allow(clippy::collapsible_if)]\n        if self.config.use_baked_registry && AQUA_STANDARD_REGISTRY_FILES.contains_key(package_id) {\n            if let Some(content) = AQUA_STANDARD_REGISTRY_FILES.get(package_id) {\n                log::trace!(\"reading baked-in aqua-registry for {package_id}\");\n                return Ok(serde_yaml::from_str(content)?);\n            }\n        }\n\n        Err(AquaRegistryError::RegistryNotAvailable(format!(\n            \"no aqua-registry found for {package_id}\"\n        )))\n    }\n}\n\nimpl CacheStore for NoOpCacheStore {\n    fn is_fresh(&self, _key: &str) -> bool {\n        false\n    }\n\n    fn store(&self, _key: &str, _data: &[u8]) -> std::io::Result<()> {\n        Ok(())\n    }\n\n    fn retrieve(&self, _key: &str) -> std::io::Result<Option<Vec<u8>>> {\n        Ok(None)\n    }\n}\n\nimpl FileCacheStore {\n    pub fn new(cache_dir: PathBuf) -> Self {\n        Self { cache_dir }\n    }\n}\n\nimpl CacheStore for FileCacheStore {\n    fn is_fresh(&self, key: &str) -> bool {\n        // Check if cache entry exists and is less than a week old\n        #[allow(clippy::collapsible_if)]\n        if let Ok(metadata) = std::fs::metadata(self.cache_dir.join(key)) {\n            if let Ok(modified) = metadata.modified() {\n                let age = std::time::SystemTime::now()\n                    .duration_since(modified)\n                    .unwrap_or_default();\n                return age < std::time::Duration::from_secs(7 * 24 * 60 * 60); // 1 week\n            }\n        }\n        false\n    }\n\n    fn store(&self, key: &str, data: &[u8]) -> std::io::Result<()> {\n        let path = self.cache_dir.join(key);\n        if let Some(parent) = path.parent() {\n            std::fs::create_dir_all(parent)?;\n        }\n        std::fs::write(path, data)\n    }\n\n    fn retrieve(&self, key: &str) -> std::io::Result<Option<Vec<u8>>> {\n        let path = self.cache_dir.join(key);\n        match std::fs::read(path) {\n            Ok(data) => Ok(Some(data)),\n            Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),\n            Err(e) => Err(e),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[tokio::test]\n    async fn test_registry_creation() {\n        let config = AquaRegistryConfig::default();\n        let registry = AquaRegistry::new(config);\n\n        // This should not panic - registry should be created successfully\n        drop(registry);\n    }\n\n    #[test]\n    fn test_cache_store() {\n        let cache = NoOpCacheStore;\n        assert!(!cache.is_fresh(\"test\"));\n        assert!(cache.store(\"test\", b\"data\").is_ok());\n        assert!(cache.retrieve(\"test\").unwrap().is_none());\n    }\n}\n"
  },
  {
    "path": "crates/aqua-registry/src/template.rs",
    "content": "use eyre::{ContextCompat, Result, bail};\nuse heck::ToTitleCase;\nuse itertools::Itertools;\nuse std::collections::HashMap;\nuse std::fmt::Debug;\nuse std::sync::LazyLock;\nuse versions::Versioning;\n\ntype Context = HashMap<String, String>;\n\n/// AST node representing an expression in the template\n#[derive(Debug, Clone, PartialEq)]\nenum Expr {\n    /// Variable reference: .Version\n    Var(String),\n    /// String literal: \"foo\"\n    Literal(String),\n    /// Function call: func arg1 arg2\n    FuncCall(String, Vec<Expr>),\n    /// Property access: expr.Property\n    PropertyAccess(Box<Expr>, String),\n    /// Pipe: expr | func\n    Pipe(Box<Expr>, Box<Expr>),\n}\n\n/// Runtime value trait - implemented by different value types\ntrait Value: Debug {\n    fn as_string(&self) -> String;\n    fn get_property(&self, prop: &str) -> Result<String>;\n}\n\n/// String value type\n#[derive(Debug, Clone)]\nstruct StringValue(String);\n\nimpl Value for StringValue {\n    fn as_string(&self) -> String {\n        self.0.clone()\n    }\n\n    fn get_property(&self, _prop: &str) -> Result<String> {\n        bail!(\"cannot access property on string\")\n    }\n}\n\n/// Semantic version value type\n#[derive(Debug, Clone)]\nstruct SemVerValue {\n    major: u32,\n    minor: u32,\n    patch: u32,\n    original: String,\n}\n\nimpl Value for SemVerValue {\n    fn as_string(&self) -> String {\n        self.original.clone()\n    }\n\n    fn get_property(&self, prop: &str) -> Result<String> {\n        Ok(match prop {\n            \"Major\" => self.major.to_string(),\n            \"Minor\" => self.minor.to_string(),\n            \"Patch\" => self.patch.to_string(),\n            _ => bail!(\"unknown semver property: {prop}\"),\n        })\n    }\n}\n\npub fn render(tmpl: &str, ctx: &Context) -> Result<String> {\n    let mut result = String::new();\n    let mut in_tag = false;\n    let mut tag = String::new();\n    let chars = tmpl.chars().collect_vec();\n    let mut i = 0;\n    let evaluator = Evaluator::new(ctx);\n    while i < chars.len() {\n        let c = chars[i];\n        let next = chars.get(i + 1).cloned().unwrap_or(' ');\n        if !in_tag && c == '{' && next == '{' {\n            in_tag = true;\n            i += 1;\n        } else if in_tag && c == '}' && next == '}' {\n            in_tag = false;\n            let tokens = lex(&tag)?;\n            let ast = parse_tokens(&tokens)?;\n            result += &evaluator.eval(&ast)?;\n            tag.clear();\n            i += 1;\n        } else if in_tag {\n            tag.push(c);\n        } else {\n            result.push(c);\n        }\n        i += 1;\n    }\n    Ok(result)\n}\n\n#[derive(Debug, Clone, PartialEq, strum::EnumIs)]\nenum Token<'a> {\n    Key(&'a str),\n    String(&'a str),\n    Func(&'a str),\n    Whitespace(&'a str),\n    Pipe,\n    LParen,\n    RParen,\n    Dot,\n    Ident(&'a str),\n}\n\nfn lex(code: &str) -> Result<Vec<Token<'_>>> {\n    let mut tokens = vec![];\n    let mut code = code.trim();\n    while !code.is_empty() {\n        if code.starts_with(\" \") {\n            let end = code\n                .chars()\n                .enumerate()\n                .find(|(_, c)| !c.is_whitespace())\n                .map(|(i, _)| i);\n            if let Some(end) = end {\n                tokens.push(Token::Whitespace(&code[..end]));\n                code = &code[end..];\n            } else {\n                break;\n            }\n        } else if code.starts_with(\"(\") {\n            tokens.push(Token::LParen);\n            code = &code[1..];\n        } else if code.starts_with(\")\") {\n            tokens.push(Token::RParen);\n            code = &code[1..];\n        } else if code.starts_with(\"|\") {\n            tokens.push(Token::Pipe);\n            code = &code[1..];\n        } else if code.starts_with('\"') {\n            for (end, _) in code[1..].match_indices('\"') {\n                if code.chars().nth(end) != Some('\\\\') {\n                    tokens.push(Token::String(&code[1..end + 1]));\n                    code = &code[end + 2..];\n                    break;\n                }\n            }\n        } else if code.starts_with(\".\") {\n            // Check if this is a property access (after ) or identifier)\n            let next_char = code.chars().nth(1);\n            if next_char.is_some_and(|c| c.is_alphabetic()) {\n                // This could be .Key or .Property\n                let end = code[1..]\n                    .chars()\n                    .enumerate()\n                    .find(|(_, c)| !c.is_alphanumeric() && *c != '_')\n                    .map(|(i, _)| i + 1)\n                    .unwrap_or(code.len());\n\n                // If preceded by RParen, it's a property access\n                if tokens.last().is_some_and(|t| t.is_r_paren()) {\n                    tokens.push(Token::Dot);\n                    tokens.push(Token::Ident(&code[1..end]));\n                } else {\n                    // Otherwise it's a key reference\n                    tokens.push(Token::Key(&code[1..end]));\n                }\n                code = &code[end..];\n            } else {\n                tokens.push(Token::Dot);\n                code = &code[1..];\n            }\n        } else {\n            // Check if it's an identifier (alphanumeric starting with letter)\n            let end = code\n                .chars()\n                .enumerate()\n                .find(|(_, c)| !c.is_alphanumeric() && *c != '_' && *c != '-')\n                .map(|(i, _)| i)\n                .unwrap_or(code.len());\n\n            if end > 0 {\n                let token_str = &code[..end];\n                // Determine if this is a function or identifier based on context\n                tokens.push(Token::Func(token_str));\n                code = &code[end..];\n            } else {\n                bail!(\"unexpected character: {}\", code.chars().next().unwrap());\n            }\n        }\n    }\n    Ok(tokens)\n}\n\n/// Parse tokens into an AST\nfn parse_tokens(tokens: &[Token]) -> Result<Expr> {\n    let mut tokens = tokens.iter().peekable();\n    parse_pipe(&mut tokens)\n}\n\n/// Parse pipe expressions (lowest precedence)\nfn parse_pipe(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) -> Result<Expr> {\n    let mut left = parse_primary(tokens)?;\n\n    // Skip whitespace before checking for pipe\n    skip_whitespace(tokens);\n    while matches!(tokens.peek(), Some(Token::Pipe)) {\n        tokens.next(); // consume pipe\n        skip_whitespace(tokens);\n        let right = parse_primary(tokens)?;\n        left = Expr::Pipe(Box::new(left), Box::new(right));\n        // Skip whitespace before checking for next pipe\n        skip_whitespace(tokens);\n    }\n\n    Ok(left)\n}\n\n/// Parse primary expressions\nfn parse_primary(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) -> Result<Expr> {\n    skip_whitespace(tokens);\n\n    let token = tokens.next().wrap_err(\"unexpected end of expression\")?;\n\n    let mut expr = match token {\n        Token::Key(k) => Expr::Var(k.to_string()),\n        Token::String(s) => Expr::Literal(s.to_string()),\n        Token::LParen => {\n            // Parenthesized expression: (func arg)\n            skip_whitespace(tokens);\n            let inner = parse_pipe(tokens)?;\n            skip_whitespace(tokens);\n            if !matches!(tokens.next(), Some(Token::RParen)) {\n                bail!(\"expected closing parenthesis\");\n            }\n            inner\n        }\n        Token::Func(f) => {\n            // Function call: func arg1 arg2\n            let func_name = f.to_string();\n            let mut args = Vec::new();\n\n            // Collect arguments until we hit pipe, rparen, or end\n            loop {\n                skip_whitespace(tokens);\n\n                match tokens.peek() {\n                    None | Some(Token::Pipe) | Some(Token::RParen) => break,\n                    Some(Token::Dot) | Some(Token::Ident(_)) => break, // Stop before property access\n                    _ => {\n                        args.push(parse_arg(tokens)?);\n                    }\n                }\n            }\n\n            Expr::FuncCall(func_name, args)\n        }\n        _ => bail!(\"unexpected token: {token:?}\"),\n    };\n\n    // Handle property access: expr.Property\n    while matches!(tokens.peek(), Some(Token::Dot)) {\n        tokens.next(); // consume dot\n        skip_whitespace(tokens);\n\n        if let Some(Token::Ident(prop)) = tokens.next() {\n            expr = Expr::PropertyAccess(Box::new(expr), prop.to_string());\n        } else {\n            bail!(\"expected identifier after dot\");\n        }\n    }\n\n    Ok(expr)\n}\n\n/// Parse a function argument\nfn parse_arg(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) -> Result<Expr> {\n    skip_whitespace(tokens);\n\n    match tokens.peek() {\n        Some(Token::LParen) => {\n            tokens.next(); // consume lparen\n            skip_whitespace(tokens);\n            let expr = parse_pipe(tokens)?;\n            skip_whitespace(tokens);\n            if !matches!(tokens.next(), Some(Token::RParen)) {\n                bail!(\"expected closing parenthesis\");\n            }\n\n            // Check for property access after paren\n            let mut result = expr;\n            while matches!(tokens.peek(), Some(Token::Dot)) {\n                tokens.next(); // consume dot\n                skip_whitespace(tokens);\n                if let Some(Token::Ident(prop)) = tokens.next() {\n                    result = Expr::PropertyAccess(Box::new(result), prop.to_string());\n                } else {\n                    bail!(\"expected identifier after dot\");\n                }\n            }\n            Ok(result)\n        }\n        Some(Token::Key(k)) => {\n            tokens.next();\n            Ok(Expr::Var(k.to_string()))\n        }\n        Some(Token::String(s)) => {\n            tokens.next();\n            Ok(Expr::Literal(s.to_string()))\n        }\n        _ => bail!(\"expected argument\"),\n    }\n}\n\nfn skip_whitespace(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) {\n    while matches!(tokens.peek(), Some(Token::Whitespace(_))) {\n        tokens.next();\n    }\n}\n\n/// Function signature for template functions that return Value trait objects\ntype TemplateFn = fn(&[Box<dyn Value>]) -> Result<Box<dyn Value>>;\n\n/// Static registry of available template functions\nstatic FUNCTION_REGISTRY: LazyLock<HashMap<&'static str, TemplateFn>> = LazyLock::new(|| {\n    let mut registry: HashMap<&'static str, TemplateFn> = HashMap::new();\n\n    registry.insert(\"semver\", |args| {\n        if args.len() != 1 {\n            bail!(\"semver requires exactly 1 argument\");\n        }\n        let input = args[0].as_string();\n        let clean_version = input.strip_prefix('v').unwrap_or(&input);\n        let version = Versioning::new(clean_version)\n            .wrap_err_with(|| format!(\"invalid semver version: {input}\"))?;\n\n        Ok(Box::new(SemVerValue {\n            major: version.nth(0).unwrap_or(0),\n            minor: version.nth(1).unwrap_or(0),\n            patch: version.nth(2).unwrap_or(0),\n            original: clean_version.to_string(),\n        }) as Box<dyn Value>)\n    });\n\n    registry.insert(\"title\", |args| {\n        if args.len() != 1 {\n            bail!(\"title requires exactly 1 argument\");\n        }\n        Ok(Box::new(StringValue(args[0].as_string().to_title_case())) as Box<dyn Value>)\n    });\n\n    registry.insert(\"trimV\", |args| {\n        if args.len() != 1 {\n            bail!(\"trimV requires exactly 1 argument\");\n        }\n        Ok(Box::new(StringValue(\n            args[0].as_string().trim_start_matches('v').to_string(),\n        )) as Box<dyn Value>)\n    });\n\n    registry.insert(\"trimPrefix\", |args| {\n        if args.len() != 2 {\n            bail!(\"trimPrefix requires exactly 2 arguments\");\n        }\n        let prefix = args[0].as_string();\n        let text = args[1].as_string();\n        Ok(Box::new(StringValue(\n            text.strip_prefix(&prefix).unwrap_or(&text).to_string(),\n        )) as Box<dyn Value>)\n    });\n\n    registry.insert(\"trimSuffix\", |args| {\n        if args.len() != 2 {\n            bail!(\"trimSuffix requires exactly 2 arguments\");\n        }\n        let suffix = args[0].as_string();\n        let text = args[1].as_string();\n        Ok(Box::new(StringValue(\n            text.strip_suffix(&suffix).unwrap_or(&text).to_string(),\n        )) as Box<dyn Value>)\n    });\n\n    registry.insert(\"replace\", |args| {\n        if args.len() != 3 {\n            bail!(\"replace requires exactly 3 arguments\");\n        }\n        let from = args[0].as_string();\n        let to = args[1].as_string();\n        let text = args[2].as_string();\n        Ok(Box::new(StringValue(text.replace(&from, &to))) as Box<dyn Value>)\n    });\n\n    registry\n});\n\n/// Evaluator walks the AST and produces results\nstruct Evaluator<'a> {\n    ctx: &'a Context,\n}\n\nimpl<'a> Evaluator<'a> {\n    fn new(ctx: &'a Context) -> Self {\n        Self { ctx }\n    }\n\n    /// Evaluate an AST node and return a string (public interface)\n    fn eval(&self, expr: &Expr) -> Result<String> {\n        let value = self.eval_value(expr)?;\n        Ok(value.as_string())\n    }\n\n    /// Evaluate an AST node and return a Value trait object (internal)\n    fn eval_value(&self, expr: &Expr) -> Result<Box<dyn Value>> {\n        match expr {\n            Expr::Var(name) => {\n                let s = self\n                    .ctx\n                    .get(name)\n                    .wrap_err_with(|| format!(\"variable not found: {name}\"))?;\n                Ok(Box::new(StringValue(s.clone())) as Box<dyn Value>)\n            }\n            Expr::Literal(s) => Ok(Box::new(StringValue(s.clone())) as Box<dyn Value>),\n            Expr::FuncCall(func, args) => self.eval_func(func, args),\n            Expr::PropertyAccess(expr, prop) => self.eval_property(expr, prop),\n            Expr::Pipe(left, right) => {\n                let left_val = self.eval_value(left)?;\n                self.eval_with_input(right, left_val)\n            }\n        }\n    }\n\n    /// Evaluate an expression with a piped input value\n    fn eval_with_input(&self, expr: &Expr, input: Box<dyn Value>) -> Result<Box<dyn Value>> {\n        match expr {\n            Expr::FuncCall(func, args) => {\n                // For piped functions, append the input as last argument\n                let mut full_args = args.clone();\n                full_args.push(Expr::Literal(input.as_string()));\n                self.eval_func(func, &full_args)\n            }\n            _ => bail!(\"can only pipe to function calls\"),\n        }\n    }\n\n    /// Evaluate property access\n    fn eval_property(&self, expr: &Expr, prop: &str) -> Result<Box<dyn Value>> {\n        let value = self.eval_value(expr)?;\n        let prop_value = value.get_property(prop)?;\n        Ok(Box::new(StringValue(prop_value)) as Box<dyn Value>)\n    }\n\n    /// Evaluate a function call\n    fn eval_func(&self, func: &str, args: &[Expr]) -> Result<Box<dyn Value>> {\n        // Evaluate all arguments first\n        let evaluated_args: Result<Vec<Box<dyn Value>>> =\n            args.iter().map(|arg| self.eval_value(arg)).collect();\n        let evaluated_args = evaluated_args?;\n\n        // Look up function in registry\n        if let Some(func_impl) = FUNCTION_REGISTRY.get(func) {\n            func_impl(&evaluated_args)\n        } else {\n            bail!(\"unknown function: {func}\")\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn hashmap(data: Vec<(&str, &str)>) -> HashMap<String, String> {\n        data.iter()\n            .map(|(k, v)| (k.to_string(), v.to_string()))\n            .collect()\n    }\n\n    #[test]\n    fn test_render() {\n        let tmpl = \"Hello, {{.OS}}!\";\n        let ctx = hashmap(vec![(\"OS\", \"world\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"Hello, world!\");\n    }\n\n    #[test]\n    fn test_render_semver_maven() {\n        let tmpl = \"https://archive.apache.org/dist/maven/maven-{{(semver .SemVer).Major}}/{{.SemVer}}/binaries/apache-maven-{{.SemVer}}-bin.tar.gz\";\n        let ctx = hashmap(vec![(\"SemVer\", \"3.9.11\")]);\n        assert_eq!(\n            render(tmpl, &ctx).unwrap(),\n            \"https://archive.apache.org/dist/maven/maven-3/3.9.11/binaries/apache-maven-3.9.11-bin.tar.gz\"\n        );\n    }\n\n    #[test]\n    fn test_render_nested_semver_in_function() {\n        // The semver function handles 'v' prefix internally, so (semver .Version).Major\n        // correctly extracts \"3\" from \"v3.9.11\". Then trimV is called on \"3\" (no-op).\n        let tmpl = \"{{trimV (semver .Version).Major}}\";\n        let ctx = hashmap(vec![(\"Version\", \"v3.9.11\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"3\");\n    }\n\n    #[test]\n    fn test_render_semver_handles_v_prefix() {\n        // semver function automatically strips 'v' prefix - no need for trimV\n        let tmpl = \"{{semver .Version}}\";\n        let ctx = hashmap(vec![(\"Version\", \"v3.9.11\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"3.9.11\");\n    }\n\n    #[test]\n    fn test_versioning_nth() {\n        // Test the versions crate directly\n        let v = Versioning::new(\"3.6.0\").unwrap();\n        assert_eq!(v.nth(0).unwrap_or(0), 3);\n        assert_eq!(v.nth(1).unwrap_or(0), 6);\n        assert_eq!(v.nth(2).unwrap_or(0), 0);\n    }\n\n    #[test]\n    fn test_two_semver_calls() {\n        // Test calling semver twice in same template\n        let tmpl = \"{{(semver .Version).Major}}.{{(semver .Version).Minor}}\";\n        let ctx = hashmap(vec![(\"Version\", \"4.6.0\")]);\n        let result = render(tmpl, &ctx).unwrap();\n        assert_eq!(result, \"4.6\", \"Expected '4.6' but got '{}'\", result);\n    }\n\n    #[test]\n    fn test_parse_second_semver() {\n        // Debug: parse just the second semver call\n        let tokens = lex(\"(semver .Version).Minor\").unwrap();\n        let ast = parse_tokens(&tokens).unwrap();\n\n        // Should be: PropertyAccess(FuncCall(\"semver\", [Var(\"Version\")]), \"Minor\")\n        if let Expr::PropertyAccess(inner, prop) = ast {\n            assert_eq!(prop, \"Minor\");\n            if let Expr::FuncCall(func, args) = *inner {\n                assert_eq!(func, \"semver\");\n                assert_eq!(args.len(), 1);\n            } else {\n                panic!(\"Inner should be FuncCall, got: {:?}\", inner);\n            }\n        } else {\n            panic!(\"Should be PropertyAccess, got: {:?}\", ast);\n        }\n    }\n\n    #[test]\n    fn test_semver_property_major() {\n        let tmpl = \"{{(semver .Version).Major}}\";\n        let ctx = hashmap(vec![(\"Version\", \"3.6.0\")]);\n        let result = render(tmpl, &ctx).unwrap();\n        assert_eq!(result, \"3\");\n    }\n\n    #[test]\n    fn test_semver_property_minor() {\n        let tmpl = \"{{(semver .Version).Minor}}\";\n        let ctx = hashmap(vec![(\"Version\", \"3.6.0\")]);\n        let result = render(tmpl, &ctx).unwrap();\n        assert_eq!(result, \"6\");\n    }\n\n    #[test]\n    fn test_render_blender_url() {\n        // Exact pattern from blender registry with version 3.6.0 (failing case)\n        let tmpl = \"https://download.blender.org/release/Blender{{(semver .Version).Major}}.{{(semver .Version).Minor}}/blender-{{trimV .Version}}-linux-x64.tar.xz\";\n        let ctx = hashmap(vec![(\"Version\", \"3.6.0\")]);\n        let result = render(tmpl, &ctx).unwrap();\n        assert_eq!(\n            result,\n            \"https://download.blender.org/release/Blender3.6/blender-3.6.0-linux-x64.tar.xz\"\n        );\n    }\n\n    #[test]\n    fn test_render_blender_url_4_3() {\n        // Test with 4.3.2\n        let tmpl = \"https://download.blender.org/release/Blender{{(semver .Version).Major}}.{{(semver .Version).Minor}}/blender-{{trimV .Version}}-linux-x64.tar.xz\";\n        let ctx = hashmap(vec![(\"Version\", \"4.3.2\")]);\n        let result = render(tmpl, &ctx).unwrap();\n        assert_eq!(\n            result,\n            \"https://download.blender.org/release/Blender4.3/blender-4.3.2-linux-x64.tar.xz\"\n        );\n    }\n\n    #[test]\n    fn test_render_semver_as_function_arg() {\n        let tmpl = \"{{title (semver .Version).Major}}\";\n        let ctx = hashmap(vec![(\"Version\", \"3.9.11\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"3\");\n    }\n\n    #[test]\n    fn test_lex_semver_with_property() {\n        let tokens = lex(\"(semver .Version).Major\").unwrap();\n        // Should be: LParen, Func(semver), Whitespace, Key(Version), RParen, Dot, Ident(Major)\n        assert!(\n            tokens.len() >= 6,\n            \"Expected at least 6 tokens, got {}: {:?}\",\n            tokens.len(),\n            tokens\n        );\n    }\n\n    #[test]\n    fn test_render_just_semver_paren() {\n        let tmpl = \"{{(semver .Version)}}\";\n        let ctx = hashmap(vec![(\"Version\", \"1.2.3\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"1.2.3\");\n    }\n\n    macro_rules! parse_tests {\n    ($($name:ident: $value:expr,)*) => {\n        $(\n            #[test]\n            fn $name() {\n                let (input, expected, ctx_data): (&str, &str, Vec<(&str, &str)>) = $value;\n                let ctx = hashmap(ctx_data);\n                let tmpl = format!(\"{{{{{}}}}}\", input);\n                assert_eq!(expected, render(&tmpl, &ctx).unwrap());\n            }\n        )*\n    }}\n\n    parse_tests!(\n        test_parse_key: (\".OS\", \"world\", vec![(\"OS\", \"world\")]),\n        test_parse_string: (\"\\\"world\\\"\", \"world\", vec![]),\n        test_parse_title: (r#\"title \"world\"\"#, \"World\", vec![]),\n        test_parse_trimv: (r#\"trimV \"v1.0.0\"\"#, \"1.0.0\", vec![]),\n        test_parse_trim_prefix: (r#\"trimPrefix \"v\" \"v1.0.0\"\"#, \"1.0.0\", vec![]),\n        test_parse_trim_prefix2: (r#\"trimPrefix \"v\" \"1.0.0\"\"#, \"1.0.0\", vec![]),\n        test_parse_trim_suffix: (r#\"trimSuffix \"-v1.0.0\" \"foo-v1.0.0\"\"#, \"foo\", vec![]),\n        test_parse_pipe: (r#\"trimPrefix \"foo-\" \"foo-v1.0.0\" | trimV\"#, \"1.0.0\", vec![]),\n        test_parse_multiple_pipes: (\n            r#\"trimPrefix \"foo-\" \"foo-v1.0.0-beta\" | trimSuffix \"-beta\" | trimV\"#,\n            \"1.0.0\",\n            vec![],\n        ),\n        test_parse_replace: (r#\"replace \"foo\" \"bar\" \"foo-bar\"\"#, \"bar-bar\", vec![]),\n        test_parse_semver_major: (r#\"(semver .Version).Major\"#, \"3\", vec![(\"Version\", \"3.9.11\")]),\n        test_parse_semver_minor: (r#\"(semver .Version).Minor\"#, \"9\", vec![(\"Version\", \"3.9.11\")]),\n        test_parse_semver_patch: (r#\"(semver .Version).Patch\"#, \"11\", vec![(\"Version\", \"3.9.11\")]),\n        test_parse_semver_major_v_prefix: (r#\"(semver .Version).Major\"#, \"1\", vec![(\"Version\", \"v1.2.3\")]),\n        test_parse_semver_no_property: (r#\"(semver .Version)\"#, \"1.2.3\", vec![(\"Version\", \"1.2.3\")]),\n        test_parse_nested_semver_in_trimv: (r#\"trimV (semver .Version).Major\"#, \"3\", vec![(\"Version\", \"v3.9.11\")]),\n        test_parse_nested_semver_in_title: (r#\"title (semver .Version).Minor\"#, \"9\", vec![(\"Version\", \"3.9.11\")]),\n        test_parse_semver_standalone: (r#\"semver .Version\"#, \"1.2.3\", vec![(\"Version\", \"v1.2.3\")]),\n        test_parse_semver_standalone_no_v: (r#\"semver .Version\"#, \"1.2.3\", vec![(\"Version\", \"1.2.3\")]),\n    );\n\n    #[test]\n    fn test_parse_err() {\n        let ctx = HashMap::new();\n        let result = render(\"{{foo}}\", &ctx);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_lex() {\n        assert_eq!(\n            lex(r#\"trimPrefix \"foo-\" \"foo-v1.0.0\" | trimV\"#).unwrap(),\n            vec![\n                Token::Func(\"trimPrefix\"),\n                Token::Whitespace(\" \"),\n                Token::String(\"foo-\"),\n                Token::Whitespace(\" \"),\n                Token::String(\"foo-v1.0.0\"),\n                Token::Whitespace(\" \"),\n                Token::Pipe,\n                Token::Whitespace(\" \"),\n                Token::Func(\"trimV\"),\n            ]\n        );\n    }\n\n    #[test]\n    fn test_gradle_src_template() {\n        // Test the gradle src template pattern: {{.AssetWithoutExt | trimSuffix \"-bin\"}}/bin/gradle\n        // This tests that pipe expressions work correctly when preceded by whitespace\n        let tmpl = r#\"{{.AssetWithoutExt | trimSuffix \"-bin\"}}/bin/gradle\"#;\n        let ctx = hashmap(vec![(\"AssetWithoutExt\", \"gradle-8.14.3-bin\")]);\n        assert_eq!(render(tmpl, &ctx).unwrap(), \"gradle-8.14.3/bin/gradle\");\n    }\n}\n"
  },
  {
    "path": "crates/aqua-registry/src/types.rs",
    "content": "use expr::{Context, Environment, Program, Value};\nuse eyre::{Result, eyre};\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse serde_derive::Deserialize;\nuse std::cmp::PartialEq;\nuse std::collections::HashMap;\nuse versions::Versioning;\n\n/// Type of Aqua package\n#[derive(Debug, Deserialize, Default, Clone, PartialEq, strum::Display)]\n#[strum(serialize_all = \"snake_case\")]\n#[serde(rename_all = \"snake_case\")]\npub enum AquaPackageType {\n    GithubArchive,\n    GithubContent,\n    #[default]\n    GithubRelease,\n    Http,\n    GoInstall,\n    Cargo,\n}\n\n/// Main Aqua package definition\n#[derive(Debug, Deserialize, Clone)]\n#[serde(default)]\npub struct AquaPackage {\n    pub r#type: AquaPackageType,\n    pub repo_owner: String,\n    pub repo_name: String,\n    pub name: Option<String>,\n    pub asset: String,\n    pub url: String,\n    pub description: Option<String>,\n    pub format: String,\n    pub rosetta2: bool,\n    pub windows_arm_emulation: bool,\n    pub complete_windows_ext: bool,\n    pub supported_envs: Vec<String>,\n    pub files: Vec<AquaFile>,\n    pub replacements: HashMap<String, String>,\n    pub version_prefix: Option<String>,\n    version_filter: Option<String>,\n    #[serde(skip)]\n    version_filter_expr: Option<Program>,\n    pub version_source: Option<String>,\n    pub checksum: Option<AquaChecksum>,\n    pub slsa_provenance: Option<AquaSlsaProvenance>,\n    pub minisign: Option<AquaMinisign>,\n    pub github_artifact_attestations: Option<AquaGithubArtifactAttestations>,\n    overrides: Vec<AquaOverride>,\n    version_constraint: String,\n    pub version_overrides: Vec<AquaPackage>,\n    pub no_asset: bool,\n    pub error_message: Option<String>,\n    pub path: Option<String>,\n}\n\n/// Override configuration for specific OS/architecture combinations\n#[derive(Debug, Deserialize, Clone)]\nstruct AquaOverride {\n    #[serde(flatten)]\n    pkg: AquaPackage,\n    goos: Option<String>,\n    goarch: Option<String>,\n}\n\n/// File definition within a package\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaFile {\n    pub name: String,\n    pub src: Option<String>,\n}\n\n/// Checksum algorithm options\n#[derive(Debug, Deserialize, Clone, strum::AsRefStr, strum::Display)]\n#[serde(rename_all = \"lowercase\")]\n#[strum(serialize_all = \"lowercase\")]\npub enum AquaChecksumAlgorithm {\n    Sha1,\n    Sha256,\n    Sha512,\n    Md5,\n}\n\n/// Type of checksum source\n#[derive(Debug, Deserialize, Clone)]\n#[serde(rename_all = \"snake_case\")]\npub enum AquaChecksumType {\n    GithubRelease,\n    Http,\n}\n\n/// Type of minisign source\n#[derive(Debug, Deserialize, Clone)]\n#[serde(rename_all = \"snake_case\")]\npub enum AquaMinisignType {\n    GithubRelease,\n    Http,\n}\n\n/// Cosign signature configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaCosignSignature {\n    pub r#type: Option<String>,\n    pub repo_owner: Option<String>,\n    pub repo_name: Option<String>,\n    pub url: Option<String>,\n    pub asset: Option<String>,\n}\n\n/// Cosign verification configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaCosign {\n    pub enabled: Option<bool>,\n    pub signature: Option<AquaCosignSignature>,\n    pub key: Option<AquaCosignSignature>,\n    pub certificate: Option<AquaCosignSignature>,\n    pub bundle: Option<AquaCosignSignature>,\n    #[serde(skip_serializing_if = \"Vec::is_empty\", default)]\n    opts: Vec<String>,\n}\n\n/// SLSA provenance configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaSlsaProvenance {\n    pub enabled: Option<bool>,\n    pub r#type: Option<String>,\n    pub repo_owner: Option<String>,\n    pub repo_name: Option<String>,\n    pub url: Option<String>,\n    pub asset: Option<String>,\n    pub source_uri: Option<String>,\n    pub source_tag: Option<String>,\n}\n\n/// Minisign verification configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaMinisign {\n    pub enabled: Option<bool>,\n    pub r#type: Option<AquaMinisignType>,\n    pub repo_owner: Option<String>,\n    pub repo_name: Option<String>,\n    pub url: Option<String>,\n    pub asset: Option<String>,\n    pub public_key: Option<String>,\n}\n\n/// GitHub artifact attestations configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaGithubArtifactAttestations {\n    pub enabled: Option<bool>,\n    pub signer_workflow: Option<String>,\n}\n\n/// Checksum verification configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaChecksum {\n    pub r#type: Option<AquaChecksumType>,\n    pub algorithm: Option<AquaChecksumAlgorithm>,\n    pub pattern: Option<AquaChecksumPattern>,\n    pub cosign: Option<AquaCosign>,\n    file_format: Option<String>,\n    enabled: Option<bool>,\n    asset: Option<String>,\n    url: Option<String>,\n}\n\n/// Checksum pattern configuration\n#[derive(Debug, Deserialize, Clone)]\npub struct AquaChecksumPattern {\n    pub checksum: String,\n    pub file: Option<String>,\n}\n\n/// Registry YAML file structure\n#[derive(Debug, Deserialize)]\npub struct RegistryYaml {\n    pub packages: Vec<AquaPackage>,\n}\n\nimpl Default for AquaPackage {\n    fn default() -> Self {\n        Self {\n            r#type: AquaPackageType::GithubRelease,\n            repo_owner: String::new(),\n            repo_name: String::new(),\n            name: None,\n            asset: String::new(),\n            url: String::new(),\n            description: None,\n            format: String::new(),\n            rosetta2: false,\n            windows_arm_emulation: false,\n            complete_windows_ext: true,\n            supported_envs: Vec::new(),\n            files: Vec::new(),\n            replacements: HashMap::new(),\n            version_prefix: None,\n            version_filter: None,\n            version_filter_expr: None,\n            version_source: None,\n            checksum: None,\n            slsa_provenance: None,\n            minisign: None,\n            github_artifact_attestations: None,\n            overrides: Vec::new(),\n            version_constraint: String::new(),\n            version_overrides: Vec::new(),\n            no_asset: false,\n            error_message: None,\n            path: None,\n        }\n    }\n}\n\nimpl AquaPackage {\n    /// Apply version-specific configurations and overrides\n    pub fn with_version(mut self, versions: &[&str], os: &str, arch: &str) -> AquaPackage {\n        self = apply_override(self.clone(), self.version_override(versions));\n        if let Some(avo) = self.overrides.clone().into_iter().find(|o| {\n            if let (Some(goos), Some(goarch)) = (&o.goos, &o.goarch) {\n                goos == os && goarch == arch\n            } else if let Some(goos) = &o.goos {\n                goos == os\n            } else if let Some(goarch) = &o.goarch {\n                goarch == arch\n            } else {\n                false\n            }\n        }) {\n            self = apply_override(self, &avo.pkg)\n        }\n        self\n    }\n\n    fn version_override(&self, versions: &[&str]) -> &AquaPackage {\n        let expressions = versions\n            .iter()\n            .map(|v| (self.expr_parser(v), self.expr_ctx(v)))\n            .collect_vec();\n        vec![self]\n            .into_iter()\n            .chain(self.version_overrides.iter())\n            .find(|vo| {\n                if vo.version_constraint.is_empty() {\n                    true\n                } else {\n                    expressions.iter().any(|(expr, ctx)| {\n                        expr.eval(&vo.version_constraint, ctx)\n                            .map_err(|e| {\n                                log::debug!(\"error parsing {}: {e}\", vo.version_constraint)\n                            })\n                            .unwrap_or(false.into())\n                            .as_bool()\n                            .unwrap()\n                    })\n                }\n            })\n            .unwrap_or(self)\n    }\n\n    /// Detect the format of an archive based on its filename\n    fn detect_format(&self, asset_name: &str) -> &'static str {\n        let formats = [\n            \"tar.br\", \"tar.bz2\", \"tar.gz\", \"tar.lz4\", \"tar.sz\", \"tar.xz\", \"tbr\", \"tbz\", \"tbz2\",\n            \"tgz\", \"tlz4\", \"tsz\", \"txz\", \"tar.zst\", \"zip\", \"gz\", \"bz2\", \"lz4\", \"sz\", \"xz\", \"zst\",\n            \"dmg\", \"pkg\", \"rar\", \"tar\",\n        ];\n\n        for format in formats {\n            if asset_name.ends_with(&format!(\".{format}\")) {\n                return match format {\n                    \"tgz\" => \"tar.gz\",\n                    \"txz\" => \"tar.xz\",\n                    \"tbz2\" | \"tbz\" => \"tar.bz2\",\n                    _ => format,\n                };\n            }\n        }\n        \"raw\"\n    }\n\n    /// Get the format for this package and version\n    pub fn format(&self, v: &str, os: &str, arch: &str) -> Result<&str> {\n        if self.r#type == AquaPackageType::GithubArchive {\n            return Ok(\"tar.gz\");\n        }\n        let format = if self.format.is_empty() {\n            let asset = if !self.asset.is_empty() {\n                self.asset(v, os, arch)?\n            } else if !self.url.is_empty() {\n                self.url.to_string()\n            } else {\n                log::debug!(\"no asset or url for {}/{}\", self.repo_owner, self.repo_name);\n                String::new()\n            };\n            self.detect_format(&asset)\n        } else {\n            match self.format.as_str() {\n                \"tgz\" => \"tar.gz\",\n                \"txz\" => \"tar.xz\",\n                \"tbz2\" | \"tbz\" => \"tar.bz2\",\n                format => format,\n            }\n        };\n        Ok(format)\n    }\n\n    /// Get the asset name for this package and version\n    pub fn asset(&self, v: &str, os: &str, arch: &str) -> Result<String> {\n        if self.asset.is_empty() && self.url.split(\"/\").count() > \"//\".len() {\n            let asset = self.url.rsplit(\"/\").next().unwrap_or(\"\");\n            self.parse_aqua_str(asset, v, &Default::default(), os, arch)\n        } else {\n            self.parse_aqua_str(&self.asset, v, &Default::default(), os, arch)\n        }\n    }\n\n    /// Get all possible asset strings for this package, version and platform\n    pub fn asset_strs(&self, v: &str, os: &str, arch: &str) -> Result<IndexSet<String>> {\n        let mut strs =\n            IndexSet::from([self.parse_aqua_str(&self.asset, v, &Default::default(), os, arch)?]);\n        if os == \"darwin\" {\n            let mut ctx = HashMap::default();\n            ctx.insert(\"Arch\".to_string(), \"universal\".to_string());\n            strs.insert(self.parse_aqua_str(&self.asset, v, &ctx, os, arch)?);\n        } else if os == \"windows\" {\n            let mut ctx = HashMap::default();\n            let asset = self.parse_aqua_str(&self.asset, v, &ctx, os, arch)?;\n            if self.complete_windows_ext && self.format(v, os, arch)? == \"raw\" {\n                strs.insert(format!(\"{asset}.exe\"));\n            } else {\n                strs.insert(asset);\n            }\n            if arch == \"arm64\" {\n                ctx.insert(\"Arch\".to_string(), \"amd64\".to_string());\n                strs.insert(self.parse_aqua_str(&self.asset, v, &ctx, os, arch)?);\n                let asset = self.parse_aqua_str(&self.asset, v, &ctx, os, arch)?;\n                if self.complete_windows_ext && self.format(v, os, arch)? == \"raw\" {\n                    strs.insert(format!(\"{asset}.exe\"));\n                } else {\n                    strs.insert(asset);\n                }\n            }\n        }\n        Ok(strs)\n    }\n\n    /// Get the URL for this package and version\n    pub fn url(&self, v: &str, os: &str, arch: &str) -> Result<String> {\n        let mut url = self.url.clone();\n        if os == \"windows\" && self.complete_windows_ext && self.format(v, os, arch)? == \"raw\" {\n            url.push_str(\".exe\");\n        }\n        self.parse_aqua_str(&url, v, &Default::default(), os, arch)\n    }\n\n    /// Parse an Aqua template string with variable substitution and platform info\n    pub fn parse_aqua_str(\n        &self,\n        s: &str,\n        v: &str,\n        overrides: &HashMap<String, String>,\n        os: &str,\n        arch: &str,\n    ) -> Result<String> {\n        let mut actual_arch = arch;\n        if os == \"darwin\" && arch == \"arm64\" && self.rosetta2 {\n            actual_arch = \"amd64\";\n        }\n        if os == \"windows\" && arch == \"arm64\" && self.windows_arm_emulation {\n            actual_arch = \"amd64\";\n        }\n\n        let replace = |s: &str| {\n            self.replacements\n                .get(s)\n                .map(|s| s.to_string())\n                .unwrap_or_else(|| s.to_string())\n        };\n\n        let semver = if let Some(prefix) = &self.version_prefix {\n            v.strip_prefix(prefix).unwrap_or(v)\n        } else {\n            v\n        };\n\n        let mut ctx = HashMap::new();\n        ctx.insert(\"Version\".to_string(), replace(v));\n        ctx.insert(\"SemVer\".to_string(), replace(semver));\n        ctx.insert(\"OS\".to_string(), replace(os));\n        ctx.insert(\"GOOS\".to_string(), replace(os));\n        ctx.insert(\"GOARCH\".to_string(), replace(actual_arch));\n        ctx.insert(\"Arch\".to_string(), replace(actual_arch));\n        ctx.insert(\"Format\".to_string(), replace(&self.format));\n        ctx.extend(overrides.clone());\n\n        crate::template::render(s, &ctx)\n    }\n\n    /// Set up version filter expression if configured\n    pub fn setup_version_filter(&mut self) -> Result<()> {\n        if let Some(version_filter) = &self.version_filter {\n            self.version_filter_expr = Some(expr::compile(version_filter)?);\n        }\n        Ok(())\n    }\n\n    /// Check if a version passes the version filter\n    pub fn version_filter_ok(&self, v: &str) -> Result<bool> {\n        if let Some(filter) = self.version_filter_expr.clone() {\n            if let Value::Bool(expr) = self.expr(v, filter)? {\n                Ok(expr)\n            } else {\n                log::warn!(\n                    \"invalid response from version filter: {}\",\n                    self.version_filter.as_ref().unwrap()\n                );\n                Ok(true)\n            }\n        } else {\n            Ok(true)\n        }\n    }\n\n    fn expr(&self, v: &str, program: Program) -> Result<Value> {\n        let expr = self.expr_parser(v);\n        expr.run(program, &self.expr_ctx(v)).map_err(|e| eyre!(e))\n    }\n\n    fn expr_parser(&self, v: &str) -> Environment<'_> {\n        let (_, v) = split_version_prefix(v);\n        let ver = Versioning::new(v);\n        let mut env = Environment::new();\n        env.add_function(\"semver\", move |c| {\n            if c.args.len() != 1 {\n                return Err(\"semver() takes exactly one argument\".to_string().into());\n            }\n            let requirements = c.args[0]\n                .as_string()\n                .unwrap()\n                .replace(' ', \"\")\n                .split(',')\n                .map(versions::Requirement::new)\n                .collect::<Vec<_>>();\n            if requirements.iter().any(|r| r.is_none()) {\n                return Err(\"invalid semver requirement\".to_string().into());\n            }\n            if let Some(ver) = &ver {\n                Ok(requirements\n                    .iter()\n                    .all(|r| r.clone().is_some_and(|r| r.matches(ver)))\n                    .into())\n            } else {\n                Err(\"invalid version\".to_string().into())\n            }\n        });\n        env\n    }\n\n    fn expr_ctx(&self, v: &str) -> Context {\n        let mut ctx = Context::default();\n        ctx.insert(\"Version\", v);\n        ctx\n    }\n}\n\n/// splits a version number into an optional prefix and the remaining version string\nfn split_version_prefix(version: &str) -> (String, String) {\n    version\n        .char_indices()\n        .find_map(|(i, c)| {\n            if c.is_ascii_digit() {\n                if i == 0 {\n                    return Some(i);\n                }\n                // If the previous char is a delimiter or 'v', we found a split point.\n                let prev_char = version.chars().nth(i - 1).unwrap();\n                if ['-', '_', '/', '.', 'v', 'V'].contains(&prev_char) {\n                    return Some(i);\n                }\n            }\n            None\n        })\n        .map_or_else(\n            || (\"\".into(), version.into()),\n            |i| {\n                let (prefix, version) = version.split_at(i);\n                (prefix.into(), version.into())\n            },\n        )\n}\n\nimpl AquaFile {\n    /// Get the source path for this file within the package\n    pub fn src(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<Option<String>> {\n        let asset = pkg.asset(v, os, arch)?;\n        let asset = asset.strip_suffix(\".tar.gz\").unwrap_or(&asset);\n        let asset = asset.strip_suffix(\".tar.xz\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".tar.bz2\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".gz\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".xz\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".bz2\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".zip\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".tar\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".tgz\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".txz\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".tbz2\").unwrap_or(asset);\n        let asset = asset.strip_suffix(\".tbz\").unwrap_or(asset);\n\n        let mut ctx = HashMap::new();\n        ctx.insert(\"AssetWithoutExt\".to_string(), asset.to_string());\n        ctx.insert(\"FileName\".to_string(), self.name.to_string());\n\n        self.src\n            .as_ref()\n            .map(|src| pkg.parse_aqua_str(src, v, &ctx, os, arch))\n            .transpose()\n    }\n}\n\nfn apply_override(mut orig: AquaPackage, avo: &AquaPackage) -> AquaPackage {\n    if avo.r#type != AquaPackageType::GithubRelease {\n        orig.r#type = avo.r#type.clone();\n    }\n    if !avo.repo_owner.is_empty() {\n        orig.repo_owner = avo.repo_owner.clone();\n    }\n    if !avo.repo_name.is_empty() {\n        orig.repo_name = avo.repo_name.clone();\n    }\n    if !avo.asset.is_empty() {\n        orig.asset = avo.asset.clone();\n    }\n    if !avo.url.is_empty() {\n        orig.url = avo.url.clone();\n    }\n    if !avo.format.is_empty() {\n        orig.format = avo.format.clone();\n    }\n    if avo.rosetta2 {\n        orig.rosetta2 = true;\n    }\n    if avo.windows_arm_emulation {\n        orig.windows_arm_emulation = true;\n    }\n    if !avo.complete_windows_ext {\n        orig.complete_windows_ext = false;\n    }\n    if !avo.supported_envs.is_empty() {\n        orig.supported_envs = avo.supported_envs.clone();\n    }\n    if !avo.files.is_empty() {\n        orig.files = avo.files.clone();\n    }\n    orig.replacements.extend(avo.replacements.clone());\n    if let Some(avo_version_prefix) = avo.version_prefix.clone() {\n        orig.version_prefix = Some(avo_version_prefix);\n    }\n    if !avo.overrides.is_empty() {\n        orig.overrides = avo.overrides.clone();\n    }\n\n    if let Some(avo_checksum) = avo.checksum.clone() {\n        match &mut orig.checksum {\n            Some(checksum) => {\n                checksum.merge(avo_checksum.clone());\n            }\n            None => {\n                orig.checksum = Some(avo_checksum.clone());\n            }\n        }\n    }\n\n    if let Some(avo_slsa_provenance) = avo.slsa_provenance.clone() {\n        match &mut orig.slsa_provenance {\n            Some(slsa_provenance) => {\n                slsa_provenance.merge(avo_slsa_provenance.clone());\n            }\n            None => {\n                orig.slsa_provenance = Some(avo_slsa_provenance.clone());\n            }\n        }\n    }\n\n    if let Some(avo_minisign) = avo.minisign.clone() {\n        match &mut orig.minisign {\n            Some(minisign) => {\n                minisign.merge(avo_minisign.clone());\n            }\n            None => {\n                orig.minisign = Some(avo_minisign.clone());\n            }\n        }\n    }\n\n    if let Some(avo_attestations) = avo.github_artifact_attestations.clone() {\n        match &mut orig.github_artifact_attestations {\n            Some(orig_attestations) => {\n                orig_attestations.merge(avo_attestations.clone());\n            }\n            None => {\n                orig.github_artifact_attestations = Some(avo_attestations.clone());\n            }\n        }\n    }\n\n    if avo.no_asset {\n        orig.no_asset = true;\n    }\n    if let Some(error_message) = avo.error_message.clone() {\n        orig.error_message = Some(error_message);\n    }\n    if let Some(path) = avo.path.clone() {\n        orig.path = Some(path);\n    }\n    orig\n}\n\n// Implementation of merge methods for various types\nimpl AquaChecksum {\n    pub fn _type(&self) -> &AquaChecksumType {\n        self.r#type.as_ref().unwrap()\n    }\n\n    pub fn algorithm(&self) -> &AquaChecksumAlgorithm {\n        self.algorithm.as_ref().unwrap()\n    }\n\n    pub fn asset_strs(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<IndexSet<String>> {\n        let mut asset_strs = IndexSet::new();\n        for asset in pkg.asset_strs(v, os, arch)? {\n            let checksum_asset = self.asset.as_ref().unwrap();\n            let mut ctx = HashMap::new();\n            ctx.insert(\"Asset\".to_string(), asset.to_string());\n            asset_strs.insert(pkg.parse_aqua_str(checksum_asset, v, &ctx, os, arch)?);\n        }\n        Ok(asset_strs)\n    }\n\n    pub fn pattern(&self) -> &AquaChecksumPattern {\n        self.pattern.as_ref().unwrap()\n    }\n\n    pub fn enabled(&self) -> bool {\n        self.enabled.unwrap_or(true)\n    }\n\n    pub fn file_format(&self) -> &str {\n        self.file_format.as_deref().unwrap_or(\"raw\")\n    }\n\n    pub fn url(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(self.url.as_ref().unwrap(), v, &Default::default(), os, arch)\n    }\n\n    fn merge(&mut self, other: Self) {\n        if let Some(r#type) = other.r#type {\n            self.r#type = Some(r#type);\n        }\n        if let Some(algorithm) = other.algorithm {\n            self.algorithm = Some(algorithm);\n        }\n        if let Some(pattern) = other.pattern {\n            self.pattern = Some(pattern);\n        }\n        if let Some(enabled) = other.enabled {\n            self.enabled = Some(enabled);\n        }\n        if let Some(asset) = other.asset {\n            self.asset = Some(asset);\n        }\n        if let Some(url) = other.url {\n            self.url = Some(url);\n        }\n        if let Some(file_format) = other.file_format {\n            self.file_format = Some(file_format);\n        }\n        if let Some(cosign) = other.cosign {\n            if self.cosign.is_none() {\n                self.cosign = Some(cosign.clone());\n            }\n            self.cosign.as_mut().unwrap().merge(cosign);\n        }\n    }\n}\n\nimpl AquaCosign {\n    // TODO: This does not support `{{.Asset}}`.\n    pub fn opts(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<Vec<String>> {\n        self.opts\n            .iter()\n            .map(|opt| pkg.parse_aqua_str(opt, v, &Default::default(), os, arch))\n            .collect()\n    }\n\n    fn merge(&mut self, other: Self) {\n        if let Some(enabled) = other.enabled {\n            self.enabled = Some(enabled);\n        }\n        if let Some(signature) = other.signature.clone() {\n            if self.signature.is_none() {\n                self.signature = Some(signature.clone());\n            }\n            self.signature.as_mut().unwrap().merge(signature);\n        }\n        if let Some(key) = other.key.clone() {\n            if self.key.is_none() {\n                self.key = Some(key.clone());\n            }\n            self.key.as_mut().unwrap().merge(key);\n        }\n        if let Some(certificate) = other.certificate.clone() {\n            if self.certificate.is_none() {\n                self.certificate = Some(certificate.clone());\n            }\n            self.certificate.as_mut().unwrap().merge(certificate);\n        }\n        if let Some(bundle) = other.bundle.clone() {\n            if self.bundle.is_none() {\n                self.bundle = Some(bundle.clone());\n            }\n            self.bundle.as_mut().unwrap().merge(bundle);\n        }\n        if !other.opts.is_empty() {\n            self.opts = other.opts.clone();\n        }\n    }\n}\n\nimpl AquaCosignSignature {\n    pub fn url(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(self.url.as_ref().unwrap(), v, &Default::default(), os, arch)\n    }\n\n    pub fn asset_strs(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<IndexSet<String>> {\n        let mut asset_strs = IndexSet::new();\n        if let Some(cosign_asset_template) = &self.asset {\n            for asset in pkg.asset_strs(v, os, arch)? {\n                let mut ctx = HashMap::new();\n                ctx.insert(\"Asset\".to_string(), asset.to_string());\n                asset_strs.insert(pkg.parse_aqua_str(cosign_asset_template, v, &ctx, os, arch)?);\n            }\n        }\n        Ok(asset_strs)\n    }\n\n    fn merge(&mut self, other: Self) {\n        if let Some(r#type) = other.r#type {\n            self.r#type = Some(r#type);\n        }\n        if let Some(repo_owner) = other.repo_owner {\n            self.repo_owner = Some(repo_owner);\n        }\n        if let Some(repo_name) = other.repo_name {\n            self.repo_name = Some(repo_name);\n        }\n        if let Some(url) = other.url {\n            self.url = Some(url);\n        }\n        if let Some(asset) = other.asset {\n            self.asset = Some(asset);\n        }\n    }\n}\n\nimpl AquaSlsaProvenance {\n    pub fn asset_strs(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<IndexSet<String>> {\n        let mut asset_strs = IndexSet::new();\n        if let Some(slsa_asset_template) = &self.asset {\n            for asset in pkg.asset_strs(v, os, arch)? {\n                let mut ctx = HashMap::new();\n                ctx.insert(\"Asset\".to_string(), asset.to_string());\n                asset_strs.insert(pkg.parse_aqua_str(slsa_asset_template, v, &ctx, os, arch)?);\n            }\n        }\n        Ok(asset_strs)\n    }\n\n    pub fn url(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(self.url.as_ref().unwrap(), v, &Default::default(), os, arch)\n    }\n\n    fn merge(&mut self, other: Self) {\n        if let Some(enabled) = other.enabled {\n            self.enabled = Some(enabled);\n        }\n        if let Some(r#type) = other.r#type {\n            self.r#type = Some(r#type);\n        }\n        if let Some(repo_owner) = other.repo_owner {\n            self.repo_owner = Some(repo_owner);\n        }\n        if let Some(repo_name) = other.repo_name {\n            self.repo_name = Some(repo_name);\n        }\n        if let Some(url) = other.url {\n            self.url = Some(url);\n        }\n        if let Some(asset) = other.asset {\n            self.asset = Some(asset);\n        }\n        if let Some(source_uri) = other.source_uri {\n            self.source_uri = Some(source_uri);\n        }\n        if let Some(source_tag) = other.source_tag {\n            self.source_tag = Some(source_tag);\n        }\n    }\n}\n\nimpl AquaMinisign {\n    pub fn _type(&self) -> &AquaMinisignType {\n        self.r#type.as_ref().unwrap()\n    }\n\n    pub fn url(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(self.url.as_ref().unwrap(), v, &Default::default(), os, arch)\n    }\n\n    pub fn asset(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(\n            self.asset.as_ref().unwrap(),\n            v,\n            &Default::default(),\n            os,\n            arch,\n        )\n    }\n\n    pub fn public_key(&self, pkg: &AquaPackage, v: &str, os: &str, arch: &str) -> Result<String> {\n        pkg.parse_aqua_str(\n            self.public_key.as_ref().unwrap(),\n            v,\n            &Default::default(),\n            os,\n            arch,\n        )\n    }\n\n    fn merge(&mut self, other: Self) {\n        if let Some(enabled) = other.enabled {\n            self.enabled = Some(enabled);\n        }\n        if let Some(r#type) = other.r#type {\n            self.r#type = Some(r#type);\n        }\n        if let Some(repo_owner) = other.repo_owner {\n            self.repo_owner = Some(repo_owner);\n        }\n        if let Some(repo_name) = other.repo_name {\n            self.repo_name = Some(repo_name);\n        }\n        if let Some(url) = other.url {\n            self.url = Some(url);\n        }\n        if let Some(asset) = other.asset {\n            self.asset = Some(asset);\n        }\n        if let Some(public_key) = other.public_key {\n            self.public_key = Some(public_key);\n        }\n    }\n}\n\nimpl AquaGithubArtifactAttestations {\n    fn merge(&mut self, other: Self) {\n        if let Some(enabled) = other.enabled {\n            self.enabled = Some(enabled);\n        }\n        if let Some(signer_workflow) = other.signer_workflow {\n            self.signer_workflow = Some(signer_workflow);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_aqua_file_src_gradle() {\n        // Test the gradle package src template: {{.AssetWithoutExt | trimSuffix \"-bin\"}}/bin/gradle\n        let pkg = AquaPackage {\n            repo_owner: \"gradle\".to_string(),\n            repo_name: \"gradle-distributions\".to_string(),\n            asset: \"gradle-{{trimV .Version}}-bin.zip\".to_string(),\n            ..Default::default()\n        };\n        let file = AquaFile {\n            name: \"gradle\".to_string(),\n            src: Some(\"{{.AssetWithoutExt | trimSuffix \\\"-bin\\\"}}/bin/gradle\".to_string()),\n        };\n\n        let result = file.src(&pkg, \"8.14.3\", \"darwin\", \"arm64\").unwrap();\n        assert_eq!(result, Some(\"gradle-8.14.3/bin/gradle\".to_string()));\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/.gitignore",
    "content": "mise.json\n"
  },
  {
    "path": "crates/mise-interactive-config/Cargo.toml",
    "content": "[package]\nname = \"mise-interactive-config\"\nversion = \"2026.1.12\"\nedition = \"2024\"\nlicense = \"MIT\"\ndescription = \"Interactive TOML config editor for mise\"\ndocumentation = \"https://docs.rs/mise-interactive-config\"\nhomepage = \"https://github.com/jdx/mise\"\nrepository = \"https://github.com/jdx/mise\"\ninclude = [\"src/**/*\", \"build.rs\", \"mise.json\"]\n\n[lib]\nname = \"mise_interactive_config\"\npath = \"src/lib.rs\"\n\n[dependencies]\nasync-trait = \"0.1\" # Async trait support\nconsole = \"0.16\" # Terminal control, key reading\nfuzzy-matcher = \"0.3\" # Fuzzy matching for tool/setting pickers\ntokio = { version = \"1\", features = [\n  \"rt\",\n  \"sync\",\n] } # Async runtime for spawn_blocking\ntoml_edit = { version = \"0.24\", features = [\"parse\"] }\nunicode-width = \"0.2\" # Text width calculation for cursor positioning\nxx = { version = \"2.5\", default-features = false } # For display_path\n\n[build-dependencies]\nserde_json = \"1\"\n\n[package.metadata.cargo-machete]\nignored = [\"serde_json\"]\n"
  },
  {
    "path": "crates/mise-interactive-config/build.rs",
    "content": "//! Build script to generate schema data from mise.json\n\nuse serde_json::Value;\nuse std::env;\nuse std::fs;\nuse std::path::Path;\n\n/// Schema type information for a property\n#[derive(Debug, Clone, PartialEq)]\nenum SchemaType {\n    String,\n    Boolean,\n    Integer,\n    Number,\n    Array,\n    Object,\n    Unknown,\n}\n\nimpl SchemaType {\n    fn as_str(&self) -> &'static str {\n        match self {\n            SchemaType::String => \"string\",\n            SchemaType::Boolean => \"boolean\",\n            SchemaType::Integer => \"integer\",\n            SchemaType::Number => \"number\",\n            SchemaType::Array => \"array\",\n            SchemaType::Object => \"object\",\n            SchemaType::Unknown => \"unknown\",\n        }\n    }\n}\n\nfn main() {\n    let out_dir = env::var(\"OUT_DIR\").unwrap();\n    let dest_path = Path::new(&out_dir).join(\"schema_sections.rs\");\n\n    // Read the schema file - check local copy first (used by cargo publish),\n    // then fall back to repo-root location (used during normal development)\n    let manifest_dir = Path::new(env!(\"CARGO_MANIFEST_DIR\"));\n    let local_schema = manifest_dir.join(\"mise.json\");\n    let repo_schema = manifest_dir\n        .parent()\n        .unwrap()\n        .parent()\n        .unwrap()\n        .join(\"schema/mise.json\");\n    let schema_path = if local_schema.exists() {\n        local_schema\n    } else {\n        repo_schema\n    };\n\n    println!(\"cargo:rerun-if-changed={}\", schema_path.display());\n\n    let schema_content = fs::read_to_string(&schema_path)\n        .unwrap_or_else(|e| panic!(\"Failed to read schema at {}: {}\", schema_path.display(), e));\n\n    let schema: Value = serde_json::from_str(&schema_content)\n        .unwrap_or_else(|e| panic!(\"Failed to parse schema JSON: {}\", e));\n\n    let defs = schema.get(\"$defs\");\n\n    // Extract top-level properties and classify them\n    let mut sections = Vec::new();\n    let mut entries = Vec::new(); // (name, description, type)\n\n    if let Some(properties) = schema.get(\"properties\").and_then(|p| p.as_object()) {\n        for (name, prop) in properties {\n            // Skip deprecated and internal properties\n            if prop\n                .get(\"deprecated\")\n                .and_then(|d| d.as_bool())\n                .unwrap_or(false)\n            {\n                continue;\n            }\n            if name == \"_\" {\n                continue;\n            }\n\n            let description = prop\n                .get(\"description\")\n                .and_then(|d| d.as_str())\n                .unwrap_or(\"\");\n\n            let is_section = is_section_property(prop, defs);\n\n            if is_section {\n                sections.push((name.clone(), description.to_string()));\n            } else {\n                let schema_type = get_schema_type(prop, defs);\n                entries.push((name.clone(), description.to_string(), schema_type));\n            }\n        }\n    }\n\n    // Extract settings keys from $defs/settings (with type info)\n    let mut settings_keys = Vec::new(); // (name, description, type)\n    if let Some(settings_def) = defs.and_then(|d| d.get(\"settings\")) {\n        extract_settings_keys(settings_def, defs, \"\", &mut settings_keys);\n    }\n\n    // Extract task_config keys from $defs/task_config\n    let mut task_config_keys = Vec::new();\n    if let Some(task_config_def) = defs.and_then(|d| d.get(\"task_config\")) {\n        extract_simple_properties(task_config_def, defs, &mut task_config_keys);\n    }\n\n    // Extract monorepo keys from $defs/monorepo\n    let mut monorepo_keys = Vec::new();\n    if let Some(monorepo_def) = defs.and_then(|d| d.get(\"monorepo\")) {\n        extract_simple_properties(monorepo_def, defs, &mut monorepo_keys);\n    }\n\n    // Sort by name for consistent output\n    sections.sort_by(|a, b| a.0.cmp(&b.0));\n    entries.sort_by(|a, b| a.0.cmp(&b.0));\n    settings_keys.sort_by(|a, b| a.0.cmp(&b.0));\n    task_config_keys.sort_by(|a, b| a.0.cmp(&b.0));\n    monorepo_keys.sort_by(|a, b| a.0.cmp(&b.0));\n\n    // Generate the Rust code\n    let mut code = String::new();\n\n    // Generate SchemaType enum\n    code.push_str(\"/// Type of a schema property\\n\");\n    code.push_str(\"#[derive(Debug, Clone, Copy, PartialEq, Eq)]\\n\");\n    code.push_str(\"pub enum SchemaType {\\n\");\n    code.push_str(\"    String,\\n\");\n    code.push_str(\"    Boolean,\\n\");\n    code.push_str(\"    Integer,\\n\");\n    code.push_str(\"    Number,\\n\");\n    code.push_str(\"    Array,\\n\");\n    code.push_str(\"    Object,\\n\");\n    code.push_str(\"    Unknown,\\n\");\n    code.push_str(\"}\\n\\n\");\n\n    // Generate sections constant\n    code.push_str(\"/// Valid top-level sections in mise.toml (tables with user-defined keys)\\n\");\n    code.push_str(\"pub const SCHEMA_SECTIONS: &[(&str, &str)] = &[\\n\");\n    for (name, description) in &sections {\n        let escaped_desc = escape_string(description);\n        code.push_str(&format!(\"    (\\\"{}\\\", \\\"{}\\\"),\\n\", name, escaped_desc));\n    }\n    code.push_str(\"];\\n\\n\");\n\n    // Generate entries constant with type info\n    code.push_str(\n        \"/// Valid top-level entries in mise.toml (scalar values, not sections) with type info\\n\",\n    );\n    code.push_str(\"pub const SCHEMA_ENTRIES: &[(&str, &str, SchemaType)] = &[\\n\");\n    for (name, description, schema_type) in &entries {\n        let escaped_desc = escape_string(description);\n        code.push_str(&format!(\n            \"    (\\\"{}\\\", \\\"{}\\\", SchemaType::{}),\\n\",\n            name,\n            escaped_desc,\n            capitalize_first(schema_type.as_str())\n        ));\n    }\n    code.push_str(\"];\\n\\n\");\n\n    // Generate settings keys constant with type info\n    code.push_str(\"/// Valid settings keys in mise.toml [settings] section with type info\\n\");\n    code.push_str(\"pub const SCHEMA_SETTINGS: &[(&str, &str, SchemaType)] = &[\\n\");\n    for (name, description, schema_type) in &settings_keys {\n        let escaped_desc = escape_string(description);\n        code.push_str(&format!(\n            \"    (\\\"{}\\\", \\\"{}\\\", SchemaType::{}),\\n\",\n            name,\n            escaped_desc,\n            capitalize_first(schema_type.as_str())\n        ));\n    }\n    code.push_str(\"];\\n\\n\");\n\n    // Generate common hooks constant\n    code.push_str(\"/// Common hook names in mise.toml [hooks] section\\n\");\n    code.push_str(\"pub const SCHEMA_HOOKS: &[(&str, &str)] = &[\\n\");\n    code.push_str(\"    (\\\"enter\\\", \\\"Run when entering a directory with this mise.toml\\\"),\\n\");\n    code.push_str(\"    (\\\"leave\\\", \\\"Run when leaving a directory with this mise.toml\\\"),\\n\");\n    code.push_str(\"    (\\\"cd\\\", \\\"Run on any directory change\\\"),\\n\");\n    code.push_str(\"    (\\\"preinstall\\\", \\\"Run before installing a tool\\\"),\\n\");\n    code.push_str(\"    (\\\"postinstall\\\", \\\"Run after installing a tool\\\"),\\n\");\n    code.push_str(\"];\\n\\n\");\n\n    // Generate task_config keys constant with type info\n    code.push_str(\"/// Valid keys in mise.toml [task_config] section with type info\\n\");\n    code.push_str(\"pub const SCHEMA_TASK_CONFIG: &[(&str, &str, SchemaType)] = &[\\n\");\n    for (name, description, schema_type) in &task_config_keys {\n        let escaped_desc = escape_string(description);\n        code.push_str(&format!(\n            \"    (\\\"{}\\\", \\\"{}\\\", SchemaType::{}),\\n\",\n            name,\n            escaped_desc,\n            capitalize_first(schema_type.as_str())\n        ));\n    }\n    code.push_str(\"];\\n\\n\");\n\n    // Generate monorepo keys constant with type info\n    code.push_str(\"/// Valid keys in mise.toml [monorepo] section with type info\\n\");\n    code.push_str(\"pub const SCHEMA_MONOREPO: &[(&str, &str, SchemaType)] = &[\\n\");\n    for (name, description, schema_type) in &monorepo_keys {\n        let escaped_desc = escape_string(description);\n        code.push_str(&format!(\n            \"    (\\\"{}\\\", \\\"{}\\\", SchemaType::{}),\\n\",\n            name,\n            escaped_desc,\n            capitalize_first(schema_type.as_str())\n        ));\n    }\n    code.push_str(\"];\\n\");\n\n    fs::write(&dest_path, code).unwrap();\n}\n\n/// Capitalize first letter\nfn capitalize_first(s: &str) -> String {\n    let mut chars = s.chars();\n    match chars.next() {\n        None => String::new(),\n        Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),\n    }\n}\n\n/// Get the schema type for a property\nfn get_schema_type(prop: &Value, defs: Option<&Value>) -> SchemaType {\n    // Check direct type first\n    if let Some(type_val) = prop.get(\"type\").and_then(|t| t.as_str()) {\n        return match type_val {\n            \"string\" => SchemaType::String,\n            \"boolean\" => SchemaType::Boolean,\n            \"integer\" => SchemaType::Integer,\n            \"number\" => SchemaType::Number,\n            \"array\" => SchemaType::Array,\n            \"object\" => SchemaType::Object,\n            _ => SchemaType::Unknown,\n        };\n    }\n\n    // Handle $ref\n    if let Some(ref_val) = prop.get(\"$ref\").and_then(|r| r.as_str())\n        && let Some(def_name) = ref_val.strip_prefix(\"#/$defs/\")\n        && let Some(def) = defs.and_then(|d| d.get(def_name))\n    {\n        return get_schema_type(def, defs);\n    }\n\n    // Handle oneOf - return the first simple type found\n    if let Some(one_of) = prop.get(\"oneOf\").and_then(|o| o.as_array()) {\n        for option in one_of {\n            let t = get_schema_type(option, defs);\n            if t != SchemaType::Unknown && t != SchemaType::Object {\n                return t;\n            }\n        }\n    }\n\n    SchemaType::Unknown\n}\n\n/// Extract simple properties from a schema object (non-recursive) with type info\nfn extract_simple_properties(\n    prop: &Value,\n    defs: Option<&Value>,\n    keys: &mut Vec<(String, String, SchemaType)>,\n) {\n    if let Some(properties) = prop.get(\"properties\").and_then(|p| p.as_object()) {\n        for (name, prop_value) in properties {\n            // Skip deprecated properties\n            if prop_value\n                .get(\"deprecated\")\n                .and_then(|d| d.as_bool())\n                .unwrap_or(false)\n            {\n                continue;\n            }\n\n            let description = prop_value\n                .get(\"description\")\n                .and_then(|d| d.as_str())\n                .unwrap_or(\"\");\n\n            let schema_type = get_schema_type(prop_value, defs);\n            keys.push((name.clone(), description.to_string(), schema_type));\n        }\n    }\n}\n\n/// Extract settings keys recursively, with dot notation for nested settings and type info\nfn extract_settings_keys(\n    prop: &Value,\n    defs: Option<&Value>,\n    prefix: &str,\n    keys: &mut Vec<(String, String, SchemaType)>,\n) {\n    if let Some(properties) = prop.get(\"properties\").and_then(|p| p.as_object()) {\n        for (name, prop_value) in properties {\n            // Skip deprecated properties\n            if prop_value\n                .get(\"deprecated\")\n                .and_then(|d| d.as_bool())\n                .unwrap_or(false)\n            {\n                continue;\n            }\n\n            let full_name = if prefix.is_empty() {\n                name.clone()\n            } else {\n                format!(\"{}.{}\", prefix, name)\n            };\n\n            let description = prop_value\n                .get(\"description\")\n                .and_then(|d| d.as_str())\n                .unwrap_or(\"\");\n\n            // Check if this is a nested object with properties (like aqua, cargo, etc.)\n            let is_nested_object = prop_value.get(\"type\").and_then(|t| t.as_str())\n                == Some(\"object\")\n                && prop_value.get(\"properties\").is_some()\n                && prop_value\n                    .get(\"additionalProperties\")\n                    .and_then(|a| a.as_bool())\n                    == Some(false);\n\n            if is_nested_object {\n                // Recurse into nested settings\n                extract_settings_keys(prop_value, defs, &full_name, keys);\n            } else {\n                // Add this as a leaf setting with type\n                let schema_type = get_schema_type(prop_value, defs);\n                keys.push((full_name, description.to_string(), schema_type));\n            }\n        }\n    }\n}\n\n/// Escape special characters in strings for Rust string literals\nfn escape_string(s: &str) -> String {\n    s.replace('\\\\', \"\\\\\\\\\")\n        .replace('\"', \"\\\\\\\"\")\n        .replace('\\n', \"\\\\n\")\n}\n\n/// Determine if a property represents a TOML section (table with user-defined keys)\n/// vs a simple entry (scalar, array, or fixed-structure object)\nfn is_section_property(prop: &Value, defs: Option<&Value>) -> bool {\n    // Check if it directly has additionalProperties (user-defined keys)\n    if prop.get(\"additionalProperties\").is_some() {\n        return true;\n    }\n\n    // Check the type\n    if let Some(type_val) = prop.get(\"type\").and_then(|t| t.as_str()) {\n        match type_val {\n            \"array\" => return false, // Arrays are entries, not sections\n            \"string\" | \"number\" | \"boolean\" | \"integer\" => return false, // Scalars\n            \"object\" => {\n                // Object type - check if it has additionalProperties or is just fixed properties\n                if prop.get(\"additionalProperties\").is_some() {\n                    return true;\n                }\n                // Check if this is a fixed-structure object (like min_version with hard/soft)\n                // If it only has \"properties\" without additionalProperties, treat as entry\n                if prop.get(\"properties\").is_some() && prop.get(\"additionalProperties\").is_none() {\n                    return false;\n                }\n                // Default to section for plain objects\n                return true;\n            }\n            _ => {}\n        }\n    }\n\n    // Handle $ref - look up the definition\n    if let Some(ref_val) = prop.get(\"$ref\").and_then(|r| r.as_str())\n        && let Some(def_name) = ref_val.strip_prefix(\"#/$defs/\")\n        && let Some(def) = defs.and_then(|d| d.get(def_name))\n    {\n        return is_section_property(def, defs);\n    }\n\n    // Handle oneOf - if any option is a simple type, treat as entry\n    if let Some(one_of) = prop.get(\"oneOf\").and_then(|o| o.as_array()) {\n        // If oneOf includes a simple type (string, number), it's an entry\n        for option in one_of {\n            if let Some(type_val) = option.get(\"type\").and_then(|t| t.as_str())\n                && matches!(type_val, \"string\" | \"number\" | \"boolean\" | \"integer\")\n            {\n                return false;\n            }\n        }\n        // If all options are objects/refs, check if any has additionalProperties\n        for option in one_of {\n            if is_section_property(option, defs) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    // Default to section (most mise.toml properties are sections)\n    true\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/cursor.rs",
    "content": "//! Cursor: Navigation state and position tracking\n\nuse crate::document::{EntryValue, TomlDocument};\n\n/// Cursor position in the document\n#[derive(Debug, Clone)]\npub struct Cursor {\n    /// Flat index into visible items\n    index: usize,\n}\n\n/// What the cursor is currently pointing at\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum CursorTarget {\n    /// Section header (section index)\n    SectionHeader(usize),\n    /// Entry within a section (section index, entry index)\n    Entry(usize, usize),\n    /// Array item within an entry (section index, entry index, array index)\n    ArrayItem(usize, usize, usize),\n    /// Inline table field (section index, entry index, field index)\n    InlineTableField(usize, usize, usize),\n    /// Add button\n    AddButton(AddButtonKind),\n    /// Comment line (not navigable, just for rendering)\n    Comment(String),\n}\n\n/// Types of add buttons\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum AddButtonKind {\n    /// Add a new section\n    Section,\n    /// Add an entry to a section (section index) - generic\n    Entry(usize),\n    /// Add a tool from registry via picker (section index) - for [tools] section\n    ToolRegistry(usize),\n    /// Add a tool from a backend (section index) - for [tools] section\n    ToolBackend(usize),\n    /// Add PATH entry (section index) - for [env] section\n    EnvPath(usize),\n    /// Load .env file (section index) - for [env] section\n    EnvDotenv(usize),\n    /// Source a shell script (section index) - for [env] section\n    EnvSource(usize),\n    /// Add environment variable (section index) - for [env] section\n    EnvVariable(usize),\n    /// Add a task (section index) - for [tasks] section\n    Task(usize),\n    /// Add a prepare provider (section index) - for [prepare] section\n    Prepare(usize),\n    /// Add a setting via picker (section index) - for [settings] section\n    Setting(usize),\n    /// Add a hook via picker (section index) - for [hooks] section\n    Hook(usize),\n    /// Add a task_config key via picker (section index) - for [task_config] section\n    TaskConfig(usize),\n    /// Add a monorepo key via picker (section index) - for [monorepo] section\n    Monorepo(usize),\n    /// Add an item to an array (section index, entry index)\n    ArrayItem(usize, usize),\n    /// Add a field to an inline table (section index, entry index)\n    InlineTableField(usize, usize),\n}\n\nimpl Cursor {\n    /// Create a new cursor at the beginning\n    pub fn new() -> Self {\n        Self { index: 0 }\n    }\n\n    /// Get the current index\n    pub fn index(&self) -> usize {\n        self.index\n    }\n\n    /// Set the index directly\n    #[allow(dead_code)]\n    pub fn set_index(&mut self, index: usize) {\n        self.index = index;\n    }\n\n    /// Move cursor up, skipping comments\n    pub fn up(&mut self, doc: &TomlDocument) {\n        let items = Self::build_visible_items(doc);\n        let max = items.len();\n        if max == 0 {\n            return;\n        }\n\n        // Move up, skipping comments\n        let mut new_idx = if self.index > 0 {\n            self.index - 1\n        } else {\n            max - 1 // Wrap to end\n        };\n\n        // Skip any comments\n        let mut attempts = 0;\n        while matches!(items.get(new_idx), Some(CursorTarget::Comment(_))) && attempts < max {\n            if new_idx > 0 {\n                new_idx -= 1;\n            } else {\n                new_idx = max - 1;\n            }\n            attempts += 1;\n        }\n        self.index = new_idx;\n    }\n\n    /// Move cursor down, skipping comments\n    pub fn down(&mut self, doc: &TomlDocument) {\n        let items = Self::build_visible_items(doc);\n        let max = items.len();\n        if max == 0 {\n            return;\n        }\n\n        // Move down, skipping comments\n        let mut new_idx = if self.index < max - 1 {\n            self.index + 1\n        } else {\n            0 // Wrap to beginning\n        };\n\n        // Skip any comments\n        let mut attempts = 0;\n        while matches!(items.get(new_idx), Some(CursorTarget::Comment(_))) && attempts < max {\n            if new_idx < max - 1 {\n                new_idx += 1;\n            } else {\n                new_idx = 0;\n            }\n            attempts += 1;\n        }\n        self.index = new_idx;\n    }\n\n    /// Jump to next section header\n    pub fn next_section(&mut self, doc: &TomlDocument) {\n        let items = Self::build_visible_items(doc);\n        let current = self.index;\n\n        // Find next section header after current position\n        for (i, item) in items.iter().enumerate().skip(current + 1) {\n            if matches!(item, CursorTarget::SectionHeader(_)) {\n                self.index = i;\n                return;\n            }\n        }\n\n        // Wrap to first section header\n        for (i, item) in items.iter().enumerate() {\n            if matches!(item, CursorTarget::SectionHeader(_)) {\n                self.index = i;\n                return;\n            }\n        }\n    }\n\n    /// Jump to previous section header\n    pub fn prev_section(&mut self, doc: &TomlDocument) {\n        let items = Self::build_visible_items(doc);\n        let current = self.index;\n\n        // Find previous section header before current position\n        for i in (0..current).rev() {\n            if matches!(items[i], CursorTarget::SectionHeader(_)) {\n                self.index = i;\n                return;\n            }\n        }\n\n        // Wrap to last section header\n        for i in (0..items.len()).rev() {\n            if matches!(items[i], CursorTarget::SectionHeader(_)) {\n                self.index = i;\n                return;\n            }\n        }\n    }\n\n    /// Get what the cursor is currently pointing at\n    pub fn target(&self, doc: &TomlDocument) -> Option<CursorTarget> {\n        let items = Self::build_visible_items(doc);\n        items.get(self.index).cloned()\n    }\n\n    /// Ensure cursor is within valid bounds and not on a comment\n    pub fn clamp(&mut self, doc: &TomlDocument) {\n        let items = Self::build_visible_items(doc);\n        let max = items.len();\n        if max == 0 {\n            self.index = 0;\n            return;\n        }\n        if self.index >= max {\n            self.index = max - 1;\n        }\n\n        // If on a comment, move to the next non-comment item\n        let mut attempts = 0;\n        while matches!(items.get(self.index), Some(CursorTarget::Comment(_))) && attempts < max {\n            if self.index < max - 1 {\n                self.index += 1;\n            } else {\n                self.index = 0;\n            }\n            attempts += 1;\n        }\n    }\n\n    /// Build list of all visible items (for navigation)\n    pub fn build_visible_items(doc: &TomlDocument) -> Vec<CursorTarget> {\n        let mut items = Vec::new();\n\n        for (section_idx, section) in doc.sections.iter().enumerate() {\n            // Add section comments (non-navigable)\n            for comment in &section.comments {\n                items.push(CursorTarget::Comment(comment.clone()));\n            }\n\n            // Section header is always visible\n            items.push(CursorTarget::SectionHeader(section_idx));\n\n            // If expanded, show entries and add button\n            if section.expanded {\n                for (entry_idx, entry) in section.entries.iter().enumerate() {\n                    // Add entry comments (non-navigable)\n                    for comment in &entry.comments {\n                        items.push(CursorTarget::Comment(format!(\"    {}\", comment)));\n                    }\n                    items.push(CursorTarget::Entry(section_idx, entry_idx));\n\n                    // If entry is expanded and complex, show sub-items\n                    if entry.expanded {\n                        match &entry.value {\n                            EntryValue::Array(arr) => {\n                                for array_idx in 0..arr.len() {\n                                    items.push(CursorTarget::ArrayItem(\n                                        section_idx,\n                                        entry_idx,\n                                        array_idx,\n                                    ));\n                                }\n                                items.push(CursorTarget::AddButton(AddButtonKind::ArrayItem(\n                                    section_idx,\n                                    entry_idx,\n                                )));\n                            }\n                            EntryValue::InlineTable(pairs) => {\n                                for field_idx in 0..pairs.len() {\n                                    items.push(CursorTarget::InlineTableField(\n                                        section_idx,\n                                        entry_idx,\n                                        field_idx,\n                                    ));\n                                }\n                                items.push(CursorTarget::AddButton(\n                                    AddButtonKind::InlineTableField(section_idx, entry_idx),\n                                ));\n                            }\n                            EntryValue::Simple(_) => {}\n                        }\n                    }\n                }\n\n                // Add section-specific buttons\n                Self::add_section_buttons(&mut items, section_idx, &section.name);\n            }\n        }\n\n        // Add section button\n        items.push(CursorTarget::AddButton(AddButtonKind::Section));\n\n        items\n    }\n\n    /// Add the appropriate add button(s) for a section based on its name\n    fn add_section_buttons(items: &mut Vec<CursorTarget>, section_idx: usize, section_name: &str) {\n        match section_name {\n            // Root section (empty name) doesn't have add buttons\n            // Users add top-level entries via the section picker\n            \"\" => {}\n            \"tools\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::ToolRegistry(\n                    section_idx,\n                )));\n                items.push(CursorTarget::AddButton(AddButtonKind::ToolBackend(\n                    section_idx,\n                )));\n            }\n            \"env\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::EnvPath(section_idx)));\n                items.push(CursorTarget::AddButton(AddButtonKind::EnvDotenv(\n                    section_idx,\n                )));\n                items.push(CursorTarget::AddButton(AddButtonKind::EnvSource(\n                    section_idx,\n                )));\n                items.push(CursorTarget::AddButton(AddButtonKind::EnvVariable(\n                    section_idx,\n                )));\n            }\n            \"tasks\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::Task(section_idx)));\n            }\n            \"prepare\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::Prepare(section_idx)));\n            }\n            \"settings\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::Setting(section_idx)));\n            }\n            \"hooks\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::Hook(section_idx)));\n            }\n            \"task_config\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::TaskConfig(\n                    section_idx,\n                )));\n            }\n            \"monorepo\" => {\n                items.push(CursorTarget::AddButton(AddButtonKind::Monorepo(\n                    section_idx,\n                )));\n            }\n            _ => {\n                // Generic entry button for unknown sections\n                items.push(CursorTarget::AddButton(AddButtonKind::Entry(section_idx)));\n            }\n        }\n    }\n\n    /// Find index for a specific target\n    pub fn find_index(doc: &TomlDocument, target: &CursorTarget) -> Option<usize> {\n        let items = Self::build_visible_items(doc);\n        items.iter().position(|t| t == target)\n    }\n\n    /// Move cursor to a specific target if it exists\n    pub fn goto(&mut self, doc: &TomlDocument, target: &CursorTarget) {\n        if let Some(idx) = Self::find_index(doc, target) {\n            self.index = idx;\n        }\n    }\n}\n\nimpl Default for Cursor {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::document::TomlDocument;\n\n    #[test]\n    fn test_cursor_navigation() {\n        let doc = TomlDocument::new();\n        let mut cursor = Cursor::new();\n\n        // First item should be section header\n        assert!(matches!(\n            cursor.target(&doc),\n            Some(CursorTarget::SectionHeader(0))\n        ));\n\n        // Move down\n        cursor.down(&doc);\n        // Should be add tool from registry button for tools section (expanded)\n        assert!(matches!(\n            cursor.target(&doc),\n            Some(CursorTarget::AddButton(AddButtonKind::ToolRegistry(0)))\n        ));\n    }\n\n    #[test]\n    fn test_cursor_wrap() {\n        let doc = TomlDocument::new();\n        let mut cursor = Cursor::new();\n\n        // Move up from start should wrap to end\n        cursor.up(&doc);\n        let max = Cursor::build_visible_items(&doc).len();\n        assert_eq!(cursor.index(), max - 1);\n    }\n\n    #[test]\n    fn test_section_navigation() {\n        let doc = TomlDocument::new();\n        let mut cursor = Cursor::new();\n\n        // Jump to next section\n        cursor.next_section(&doc);\n        assert!(matches!(\n            cursor.target(&doc),\n            Some(CursorTarget::SectionHeader(1))\n        ));\n\n        // Jump back\n        cursor.prev_section(&doc);\n        assert!(matches!(\n            cursor.target(&doc),\n            Some(CursorTarget::SectionHeader(0))\n        ));\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/document.rs",
    "content": "//! TomlDocument: In-memory TOML representation with sections and entries\n\nuse std::path::Path;\nuse toml_edit::{DocumentMut, Formatted, Item, Table, Value};\n\n/// Represents a TOML document with navigable sections\n#[derive(Debug)]\npub struct TomlDocument {\n    pub sections: Vec<Section>,\n    pub modified: bool,\n}\n\n/// A section in the TOML document (e.g., [tools], [env])\n#[derive(Debug, Clone)]\npub struct Section {\n    pub name: String,\n    pub entries: Vec<Entry>,\n    pub expanded: bool,\n    /// Comments appearing before this section header\n    pub comments: Vec<String>,\n}\n\n/// An entry within a section (key = value)\n#[derive(Debug, Clone)]\npub struct Entry {\n    pub key: String,\n    pub value: EntryValue,\n    pub expanded: bool,\n    /// Comments appearing before this entry\n    pub comments: Vec<String>,\n}\n\n/// The value of an entry\n#[derive(Debug, Clone)]\npub enum EntryValue {\n    /// Simple string, number, or boolean value\n    Simple(String),\n    /// Array of values\n    Array(Vec<String>),\n    /// Inline table of key-value pairs\n    InlineTable(Vec<(String, String)>),\n}\n\nimpl TomlDocument {\n    /// Create a new document with default sections\n    pub fn new() -> Self {\n        Self::new_with_prepare(false)\n    }\n\n    /// Create a new document with default sections, optionally including prepare\n    pub fn new_with_prepare(include_prepare: bool) -> Self {\n        let mut sections = vec![\n            Section {\n                name: \"tools\".to_string(),\n                entries: Vec::new(),\n                expanded: true,\n                comments: Vec::new(),\n            },\n            Section {\n                name: \"env\".to_string(),\n                entries: Vec::new(),\n                expanded: false,\n                comments: Vec::new(),\n            },\n            Section {\n                name: \"tasks\".to_string(),\n                entries: Vec::new(),\n                expanded: false,\n                comments: Vec::new(),\n            },\n        ];\n\n        if include_prepare {\n            sections.push(Section {\n                name: \"prepare\".to_string(),\n                entries: Vec::new(),\n                expanded: false,\n                comments: Vec::new(),\n            });\n        }\n\n        sections.push(Section {\n            name: \"settings\".to_string(),\n            entries: Vec::new(),\n            expanded: false,\n            comments: Vec::new(),\n        });\n\n        Self {\n            sections,\n            modified: false,\n        }\n    }\n\n    /// Parse a TOML document from a string\n    pub fn parse(content: &str) -> Result<Self, toml_edit::TomlError> {\n        let doc: DocumentMut = content.parse()?;\n        let mut sections = Vec::new();\n\n        // Known sections in preferred order\n        let known_sections = [\"tools\", \"env\", \"tasks\", \"prepare\", \"settings\"];\n\n        // Collect top-level entries (non-table items like min_version)\n        let mut root_entries = Vec::new();\n        for (key, item) in doc.iter() {\n            if !item.is_table()\n                && !item.is_array_of_tables()\n                && let Some(entry) = Self::parse_entry(key, item)\n            {\n                root_entries.push(entry);\n            }\n        }\n\n        // Add root section (empty name) if we have top-level entries\n        if !root_entries.is_empty() {\n            sections.push(Section {\n                name: String::new(),\n                entries: root_entries,\n                expanded: true,\n                comments: Vec::new(),\n            });\n        }\n\n        // Add known sections first (in order)\n        for name in &known_sections {\n            if let Some(item) = doc.get(name)\n                && let Some(table) = item.as_table()\n            {\n                sections.push(Self::parse_section(name, table));\n            }\n        }\n\n        // Add any other sections\n        for (key, item) in doc.iter() {\n            if !known_sections.contains(&key)\n                && let Some(table) = item.as_table()\n            {\n                sections.push(Self::parse_section(key, table));\n            }\n        }\n\n        // Add missing default sections\n        for name in &known_sections {\n            if !sections.iter().any(|s| s.name == *name) {\n                sections.push(Section {\n                    name: name.to_string(),\n                    entries: Vec::new(),\n                    expanded: false,\n                    comments: Vec::new(),\n                });\n            }\n        }\n\n        // Sort to maintain preferred order (empty name for root entries comes first)\n        sections.sort_by(|a, b| {\n            let order = |n: &str| {\n                if n.is_empty() {\n                    return 0; // Root entries come first\n                }\n                known_sections\n                    .iter()\n                    .position(|&s| s == n)\n                    .map(|p| p + 1)\n                    .unwrap_or(known_sections.len() + 1)\n            };\n            order(&a.name).cmp(&order(&b.name))\n        });\n\n        // Expand first non-empty section, or tools if all empty\n        let first_non_empty = sections.iter_mut().find(|s| !s.entries.is_empty());\n        if let Some(section) = first_non_empty {\n            section.expanded = true;\n        } else if let Some(tools) = sections.iter_mut().find(|s| s.name == \"tools\") {\n            tools.expanded = true;\n        }\n\n        Ok(Self {\n            sections,\n            modified: false,\n        })\n    }\n\n    /// Load a TOML document from a file\n    pub fn load(path: &Path) -> std::io::Result<Self> {\n        let content = std::fs::read_to_string(path)?;\n        Self::parse(&content).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))\n    }\n\n    fn parse_section(name: &str, table: &Table) -> Section {\n        let mut entries = Vec::new();\n\n        for (key, item) in table.iter() {\n            if let Some(entry) = Self::parse_entry(key, item) {\n                entries.push(entry);\n            }\n        }\n\n        // Extract comments from the table's decor\n        let comments = Self::extract_comments_from_decor(table.decor().prefix());\n\n        Section {\n            name: name.to_string(),\n            entries,\n            expanded: false,\n            comments,\n        }\n    }\n\n    fn parse_entry(key: &str, item: &Item) -> Option<Entry> {\n        // Extract comments from the item's decor (handle both Values and Tables)\n        let comments = match item {\n            Item::Value(v) => Self::extract_comments_from_decor(v.decor().prefix()),\n            Item::Table(t) => Self::extract_comments_from_decor(t.decor().prefix()),\n            _ => Vec::new(),\n        };\n\n        let value = match item {\n            Item::Value(v) => Self::parse_value(v),\n            Item::Table(t) => {\n                // Nested table - convert to inline table representation\n                let pairs: Vec<(String, String)> = t\n                    .iter()\n                    .filter_map(|(k, v)| {\n                        if let Item::Value(val) = v {\n                            Some((k.to_string(), Self::value_to_string(val)))\n                        } else {\n                            None\n                        }\n                    })\n                    .collect();\n                EntryValue::InlineTable(pairs)\n            }\n            _ => return None,\n        };\n\n        Some(Entry {\n            key: key.to_string(),\n            value,\n            expanded: false,\n            comments,\n        })\n    }\n\n    /// Extract comment lines from a decor prefix\n    fn extract_comments_from_decor(prefix: Option<&toml_edit::RawString>) -> Vec<String> {\n        let Some(prefix) = prefix else {\n            return Vec::new();\n        };\n        let prefix_str = prefix.as_str().unwrap_or(\"\");\n        prefix_str\n            .lines()\n            .filter_map(|line| {\n                let trimmed = line.trim();\n                if trimmed.starts_with('#') {\n                    Some(trimmed.to_string())\n                } else {\n                    None\n                }\n            })\n            .collect()\n    }\n\n    fn parse_value(value: &Value) -> EntryValue {\n        match value {\n            Value::Array(arr) => {\n                let items: Vec<String> = arr.iter().map(Self::value_to_string).collect();\n                EntryValue::Array(items)\n            }\n            Value::InlineTable(t) => {\n                let pairs: Vec<(String, String)> = t\n                    .iter()\n                    .map(|(k, v)| (k.to_string(), Self::value_to_string(v)))\n                    .collect();\n                EntryValue::InlineTable(pairs)\n            }\n            _ => EntryValue::Simple(Self::value_to_string(value)),\n        }\n    }\n\n    fn value_to_string(value: &Value) -> String {\n        match value {\n            Value::String(s) => s.value().to_string(),\n            Value::Integer(i) => i.value().to_string(),\n            Value::Float(f) => f.value().to_string(),\n            Value::Boolean(b) => b.value().to_string(),\n            Value::Array(arr) => {\n                let items: Vec<String> = arr.iter().map(Self::value_to_string).collect();\n                format!(\"[{}]\", items.join(\", \"))\n            }\n            Value::InlineTable(t) => {\n                let pairs: Vec<String> = t\n                    .iter()\n                    .map(|(k, v)| format!(\"{} = {}\", k, Self::value_to_string(v)))\n                    .collect();\n                format!(\"{{ {} }}\", pairs.join(\", \"))\n            }\n            Value::Datetime(dt) => dt.value().to_string(),\n        }\n    }\n\n    /// Serialize the document to a TOML string\n    pub fn to_toml(&self) -> String {\n        let mut doc = DocumentMut::new();\n\n        for section in &self.sections {\n            if section.entries.is_empty() {\n                continue;\n            }\n\n            // Handle root-level entries (section with empty name)\n            if section.name.is_empty() {\n                for entry in &section.entries {\n                    let item = Self::entry_value_to_item(&entry.value);\n                    doc.insert(&entry.key, item);\n                }\n                continue;\n            }\n\n            let mut table = Table::new();\n\n            for entry in &section.entries {\n                let item = Self::entry_value_to_item(&entry.value);\n\n                // Handle dotted keys (like _.path in env section) by creating nested tables\n                if entry.key.contains('.') && section.name == \"env\" {\n                    Self::insert_dotted_key(&mut table, &entry.key, item);\n                } else {\n                    table.insert(&entry.key, item);\n                }\n            }\n\n            doc.insert(&section.name, Item::Table(table));\n        }\n\n        doc.to_string()\n    }\n\n    /// Insert a dotted key into a table by creating nested structure\n    /// e.g., \"_.path\" becomes _: { path: value }\n    fn insert_dotted_key(table: &mut Table, key: &str, item: Item) {\n        let parts: Vec<&str> = key.splitn(2, '.').collect();\n        if parts.len() == 2 {\n            let parent_key = parts[0];\n            let child_key = parts[1];\n\n            // Get or create the parent subtable\n            if !table.contains_key(parent_key) {\n                let mut subtable = Table::new();\n                subtable.set_implicit(true);\n                table.insert(parent_key, Item::Table(subtable));\n            }\n\n            if let Some(Item::Table(subtable)) = table.get_mut(parent_key) {\n                // Recursively handle if child_key also contains a dot\n                if child_key.contains('.') {\n                    Self::insert_dotted_key(subtable, child_key, item);\n                } else {\n                    subtable.insert(child_key, item);\n                }\n            }\n        } else {\n            // No dot, insert directly\n            table.insert(key, item);\n        }\n    }\n\n    fn entry_value_to_item(value: &EntryValue) -> Item {\n        match value {\n            EntryValue::Simple(s) => {\n                // Only special-case booleans, keep everything else as strings\n                // This is appropriate for mise configs where versions like \"22\" should stay quoted\n                if s == \"true\" {\n                    Item::Value(Value::Boolean(Formatted::new(true)))\n                } else if s == \"false\" {\n                    Item::Value(Value::Boolean(Formatted::new(false)))\n                } else {\n                    Item::Value(Value::String(Formatted::new(s.clone())))\n                }\n            }\n            EntryValue::Array(items) => {\n                let mut arr = toml_edit::Array::new();\n                for item in items {\n                    // Keep array items as strings unless explicitly boolean\n                    let val = if item == \"true\" {\n                        Value::Boolean(Formatted::new(true))\n                    } else if item == \"false\" {\n                        Value::Boolean(Formatted::new(false))\n                    } else {\n                        Value::String(Formatted::new(item.clone()))\n                    };\n                    arr.push(val);\n                }\n                Item::Value(Value::Array(arr))\n            }\n            EntryValue::InlineTable(pairs) => {\n                let mut table = toml_edit::InlineTable::new();\n                for (k, v) in pairs {\n                    let val = if v == \"true\" {\n                        Value::Boolean(Formatted::new(true))\n                    } else if v == \"false\" {\n                        Value::Boolean(Formatted::new(false))\n                    } else {\n                        Value::String(Formatted::new(v.clone()))\n                    };\n                    table.insert(k, val);\n                }\n                Item::Value(Value::InlineTable(table))\n            }\n        }\n    }\n\n    /// Save the document to a file\n    pub fn save(&self, path: &Path) -> std::io::Result<()> {\n        std::fs::write(path, self.to_toml())\n    }\n\n    /// Add a new section\n    pub fn add_section(&mut self, name: String) {\n        if !self.sections.iter().any(|s| s.name == name) {\n            self.sections.push(Section {\n                name,\n                entries: Vec::new(),\n                expanded: true,\n                comments: Vec::new(),\n            });\n            self.modified = true;\n        }\n    }\n\n    /// Add an entry to a section with a simple string value\n    pub fn add_entry(&mut self, section_idx: usize, key: String, value: String) {\n        self.add_entry_with_value(section_idx, key, EntryValue::Simple(value));\n    }\n\n    /// Add an entry to a section with a specific value type\n    pub fn add_entry_with_value(&mut self, section_idx: usize, key: String, value: EntryValue) {\n        if let Some(section) = self.sections.get_mut(section_idx) {\n            section.entries.push(Entry {\n                key,\n                value,\n                expanded: false,\n                comments: Vec::new(),\n            });\n            self.modified = true;\n        }\n    }\n\n    /// Delete an entry from a section\n    pub fn delete_entry(&mut self, section_idx: usize, entry_idx: usize) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && entry_idx < section.entries.len()\n        {\n            section.entries.remove(entry_idx);\n            self.modified = true;\n        }\n    }\n\n    /// Update an entry's value\n    pub fn update_entry(&mut self, section_idx: usize, entry_idx: usize, value: String) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n        {\n            entry.value = EntryValue::Simple(value);\n            self.modified = true;\n        }\n    }\n\n    /// Add an item to an array entry\n    pub fn add_array_item(&mut self, section_idx: usize, entry_idx: usize, value: String) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n            && let EntryValue::Array(ref mut items) = entry.value\n        {\n            items.push(value);\n            self.modified = true;\n        }\n    }\n\n    /// Update an array item\n    pub fn update_array_item(\n        &mut self,\n        section_idx: usize,\n        entry_idx: usize,\n        array_idx: usize,\n        value: String,\n    ) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n            && let EntryValue::Array(ref mut items) = entry.value\n            && let Some(item) = items.get_mut(array_idx)\n        {\n            *item = value;\n            self.modified = true;\n        }\n    }\n\n    /// Delete an array item\n    pub fn delete_array_item(&mut self, section_idx: usize, entry_idx: usize, array_idx: usize) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n            && let EntryValue::Array(ref mut items) = entry.value\n            && array_idx < items.len()\n        {\n            items.remove(array_idx);\n            self.modified = true;\n        }\n    }\n\n    /// Toggle section expanded state\n    pub fn toggle_section(&mut self, section_idx: usize) {\n        if let Some(section) = self.sections.get_mut(section_idx) {\n            section.expanded = !section.expanded;\n        }\n    }\n\n    /// Toggle entry expanded state (for arrays/inline tables)\n    pub fn toggle_entry(&mut self, section_idx: usize, entry_idx: usize) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n        {\n            entry.expanded = !entry.expanded;\n        }\n    }\n\n    /// Delete a section\n    pub fn delete_section(&mut self, section_idx: usize) {\n        if section_idx < self.sections.len() {\n            self.sections.remove(section_idx);\n            self.modified = true;\n        }\n    }\n\n    /// Convert a simple entry value to an inline table with version key\n    /// Returns true if conversion was successful\n    pub fn convert_to_inline_table(&mut self, section_idx: usize, entry_idx: usize) -> bool {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n            && let EntryValue::Simple(value) = &entry.value\n        {\n            // Convert \"value\" to { version = \"value\" }\n            entry.value = EntryValue::InlineTable(vec![(\"version\".to_string(), value.clone())]);\n            entry.expanded = true;\n            self.modified = true;\n            return true;\n        }\n        false\n    }\n\n    /// Add a field to an inline table entry\n    #[allow(dead_code)]\n    pub fn add_inline_table_field(\n        &mut self,\n        section_idx: usize,\n        entry_idx: usize,\n        key: String,\n        value: String,\n    ) {\n        if let Some(section) = self.sections.get_mut(section_idx)\n            && let Some(entry) = section.entries.get_mut(entry_idx)\n            && let EntryValue::InlineTable(ref mut pairs) = entry.value\n        {\n            pairs.push((key, value));\n            self.modified = true;\n        }\n    }\n}\n\nimpl Default for TomlDocument {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[allow(dead_code)]\nimpl EntryValue {\n    /// Check if this is a complex value (array or inline table)\n    pub fn is_complex(&self) -> bool {\n        !matches!(self, EntryValue::Simple(_))\n    }\n\n    /// Get the display string for this value\n    pub fn display(&self) -> String {\n        match self {\n            EntryValue::Simple(s) => s.clone(),\n            EntryValue::Array(items) => format!(\"[{}]\", items.join(\", \")),\n            EntryValue::InlineTable(pairs) => {\n                let parts: Vec<String> = pairs\n                    .iter()\n                    .map(|(k, v)| format!(\"{} = {}\", k, v))\n                    .collect();\n                format!(\"{{ {} }}\", parts.join(\", \"))\n            }\n        }\n    }\n\n    /// Get item count for complex values\n    pub fn item_count(&self) -> Option<usize> {\n        match self {\n            EntryValue::Simple(_) => None,\n            EntryValue::Array(items) => Some(items.len()),\n            EntryValue::InlineTable(pairs) => Some(pairs.len()),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_new_document() {\n        let doc = TomlDocument::new();\n        assert_eq!(doc.sections.len(), 4);\n        assert_eq!(doc.sections[0].name, \"tools\");\n        assert!(doc.sections[0].expanded);\n    }\n\n    #[test]\n    fn test_parse_simple() {\n        let content = r#\"\n[tools]\nnode = \"22\"\npython = \"3.12\"\n\n[env]\nNODE_ENV = \"development\"\n\"#;\n        let doc = TomlDocument::parse(content).unwrap();\n        assert_eq!(doc.sections[0].name, \"tools\");\n        assert_eq!(doc.sections[0].entries.len(), 2);\n        assert_eq!(doc.sections[0].entries[0].key, \"node\");\n    }\n\n    #[test]\n    fn test_parse_array() {\n        let content = r#\"\n[env]\npaths = [\"./bin\", \"./node_modules/.bin\"]\n\"#;\n        let doc = TomlDocument::parse(content).unwrap();\n        let env_section = doc.sections.iter().find(|s| s.name == \"env\").unwrap();\n        let entry = &env_section.entries[0];\n        assert_eq!(entry.key, \"paths\");\n        assert!(matches!(entry.value, EntryValue::Array(_)));\n        if let EntryValue::Array(items) = &entry.value {\n            assert_eq!(items.len(), 2);\n            assert_eq!(items[0], \"./bin\");\n        }\n    }\n\n    #[test]\n    fn test_to_toml() {\n        let mut doc = TomlDocument::new();\n        doc.add_entry(0, \"node\".to_string(), \"22\".to_string());\n        let toml = doc.to_toml();\n        assert!(toml.contains(\"[tools]\"));\n        assert!(toml.contains(\"node = \\\"22\\\"\"));\n    }\n\n    #[test]\n    fn test_roundtrip() {\n        let content = r#\"[tools]\nnode = \"22\"\npython = \"3.12\"\n\n[env]\nNODE_ENV = \"development\"\n\"#;\n        let doc = TomlDocument::parse(content).unwrap();\n        let output = doc.to_toml();\n        assert!(output.contains(\"node = \\\"22\\\"\"));\n        assert!(output.contains(\"python = \\\"3.12\\\"\"));\n        assert!(output.contains(\"NODE_ENV = \\\"development\\\"\"));\n    }\n\n    #[test]\n    fn test_parse_top_level_entries() {\n        let content = r#\"min_version = \"2024.1.0\"\n\n[tools]\nnode = \"22\"\n\"#;\n        let doc = TomlDocument::parse(content).unwrap();\n        // Root section (empty name) should be first\n        let root_section = doc.sections.iter().find(|s| s.name.is_empty()).unwrap();\n        assert_eq!(root_section.entries.len(), 1);\n        assert_eq!(root_section.entries[0].key, \"min_version\");\n    }\n\n    #[test]\n    fn test_top_level_entries_roundtrip() {\n        let content = r#\"min_version = \"2024.1.0\"\n\n[tools]\nnode = \"22\"\n\"#;\n        let doc = TomlDocument::parse(content).unwrap();\n        let output = doc.to_toml();\n        assert!(output.contains(\"min_version = \\\"2024.1.0\\\"\"));\n        assert!(output.contains(\"[tools]\"));\n        assert!(output.contains(\"node = \\\"22\\\"\"));\n    }\n\n    #[test]\n    fn test_env_dotted_key_serialization() {\n        // Create a document with _.path in the env section\n        let mut doc = TomlDocument::new();\n        let env_idx = doc.sections.iter().position(|s| s.name == \"env\").unwrap();\n\n        // Add _.path as an array\n        doc.sections[env_idx].entries.push(Entry {\n            key: \"_.path\".to_string(),\n            value: EntryValue::Array(vec![\"./bin\".to_string(), \"./node_modules/.bin\".to_string()]),\n            expanded: false,\n            comments: Vec::new(),\n        });\n\n        let output = doc.to_toml();\n        // Should output as dotted key, not quoted key\n        // _.path = [...] means _: { path: [...] }\n        assert!(\n            output.contains(\"_.path\") || output.contains(\"[env._]\"),\n            \"Output should contain dotted key notation: {}\",\n            output\n        );\n        // Should NOT contain quoted key\n        assert!(\n            !output.contains(\"\\\"_.path\\\"\"),\n            \"Output should not contain quoted key: {}\",\n            output\n        );\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/editor/actions.rs",
    "content": "//! Action handlers for the interactive editor\n\nuse std::io;\n\nuse super::InteractiveConfig;\nuse super::undo::UndoAction;\nuse crate::cursor::{AddButtonKind, CursorTarget};\nuse crate::document::EntryValue;\nuse crate::inline_edit::InlineEdit;\nuse crate::picker::{PickerItem, PickerState};\nuse crate::providers::version_variants;\nuse crate::render::{BooleanSelectState, Mode, PickerKind, VersionSelectState};\n\nimpl InteractiveConfig {\n    pub(super) async fn handle_enter(&mut self) -> io::Result<()> {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::SectionHeader(section_idx)) => {\n                self.doc.toggle_section(section_idx);\n                // If we just expanded, move cursor to first entry or add button\n                if self.doc.sections[section_idx].expanded {\n                    self.cursor.down(&self.doc);\n                }\n            }\n\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                let section_name = self.doc.sections[section_idx].name.clone();\n                let entry = &self.doc.sections[section_idx].entries[entry_idx];\n                let tool_name = entry.key.clone();\n                let current_value_opt = match &entry.value {\n                    EntryValue::Simple(v) => Some(v.clone()),\n                    _ => None,\n                };\n                let is_complex = matches!(\n                    entry.value,\n                    EntryValue::Array(_) | EntryValue::InlineTable(_)\n                );\n\n                if let Some(current_value) = current_value_opt {\n                    // For tools section, try to use version selector\n                    if section_name == \"tools\" {\n                        // Show loading indicator while fetching version info\n                        self.mode =\n                            Mode::Loading(format!(\"Fetching versions for {}...\", tool_name));\n                        let _ = self.render_current_mode();\n                        if let Some(latest) = self.version_provider.latest_version(&tool_name).await\n                        {\n                            let variants = version_variants(&latest);\n                            // Find which variant matches the current value, if any\n                            let mut vs = VersionSelectState::new(\n                                tool_name,\n                                variants.clone(),\n                                section_idx,\n                                entry_idx,\n                            );\n                            // Try to match current value to a variant, or select \"other...\"\n                            if let Some(pos) = variants.iter().position(|v| v == &current_value) {\n                                vs.selected = pos;\n                            } else {\n                                // Current value is custom, select \"other...\"\n                                vs.selected = variants.len().saturating_sub(1);\n                            }\n                            self.mode = Mode::VersionSelect(vs);\n                        } else {\n                            // Fall back to inline edit if no version info available\n                            self.mode = Mode::Edit(InlineEdit::new(&current_value));\n                        }\n                    } else {\n                        // Non-tools section: check if it's a boolean setting\n                        let schema_type = match section_name.as_str() {\n                            \"settings\" => crate::schema::setting_type(&tool_name),\n                            \"task_config\" => crate::schema::task_config_type(&tool_name),\n                            \"monorepo\" => crate::schema::monorepo_type(&tool_name),\n                            \"\" => crate::schema::entry_type(&tool_name),\n                            _ => None,\n                        };\n\n                        if schema_type == Some(crate::schema::SchemaType::Boolean) {\n                            // Use boolean selector for boolean settings\n                            let current_bool = current_value == \"true\";\n                            self.mode = Mode::BooleanSelect(BooleanSelectState::edit_entry(\n                                tool_name,\n                                current_bool,\n                                section_idx,\n                                entry_idx,\n                            ));\n                        } else {\n                            // Use regular inline edit\n                            self.mode = Mode::Edit(InlineEdit::new(&current_value));\n                        }\n                    }\n                } else if is_complex {\n                    // Toggle expansion for arrays/inline tables\n                    self.doc.toggle_entry(section_idx, entry_idx);\n                }\n            }\n\n            Some(CursorTarget::ArrayItem(section_idx, entry_idx, array_idx)) => {\n                if let EntryValue::Array(items) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let value = items[array_idx].clone();\n                    self.mode = Mode::Edit(InlineEdit::new(&value));\n                }\n            }\n\n            Some(CursorTarget::InlineTableField(section_idx, entry_idx, field_idx)) => {\n                if let EntryValue::InlineTable(pairs) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let (key, value) = &pairs[field_idx];\n                    // Check if it's a boolean value\n                    if value == \"true\" || value == \"false\" {\n                        let current_bool = value == \"true\";\n                        self.mode =\n                            Mode::BooleanSelect(BooleanSelectState::edit_inline_table_field(\n                                key.clone(),\n                                current_bool,\n                                section_idx,\n                                entry_idx,\n                                field_idx,\n                            ));\n                    } else {\n                        self.mode = Mode::Edit(InlineEdit::new(value));\n                    }\n                }\n            }\n\n            Some(CursorTarget::AddButton(kind)) => match kind {\n                AddButtonKind::Section => {\n                    // Open section picker with valid sections AND top-level entries from schema\n                    // We include both so users can add things like min_version at the top level\n                    let mut items: Vec<PickerItem> = crate::schema::SCHEMA_SECTIONS\n                        .iter()\n                        .filter(|(name, _)| {\n                            // Filter out sections that already exist\n                            !self.doc.sections.iter().any(|s| s.name == *name)\n                        })\n                        .map(|(name, desc)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    // Also add top-level entries (like min_version, redactions)\n                    // These get added at the file level, not as sections\n                    let entry_items: Vec<PickerItem> = crate::schema::SCHEMA_ENTRIES\n                        .iter()\n                        .filter(|(name, _, _)| {\n                            // Filter out entries that already exist in any section at root level\n                            // (top-level entries are stored in a virtual \"\" section or handled specially)\n                            !self.doc.sections.iter().any(|s| {\n                                s.name.is_empty() && s.entries.iter().any(|e| e.key == *name)\n                            })\n                        })\n                        .map(|(name, desc, _)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    items.extend(entry_items);\n                    items.sort_by(|a, b| a.name.cmp(&b.name));\n                    if items.is_empty() {\n                        // All sections already exist, fall back to manual entry\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode = Mode::Picker(PickerKind::Section, Box::new(picker));\n                    }\n                }\n                AddButtonKind::Entry(_) => {\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::ToolRegistry(section_idx) => {\n                    // Open tool picker\n                    let tools = self.tool_provider.list_tools();\n                    if tools.is_empty() {\n                        // Fall back to manual entry if no tools available\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let items: Vec<PickerItem> = tools\n                            .into_iter()\n                            .map(|t| {\n                                let mut item = PickerItem::new(&t.name);\n                                if let Some(desc) = t.description {\n                                    item = item.with_description(desc);\n                                }\n                                item\n                            })\n                            .collect();\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode = Mode::Picker(PickerKind::Tool(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::ToolBackend(section_idx) => {\n                    // Open backend picker\n                    let backends = self.backend_provider.list_backends();\n                    if backends.is_empty() {\n                        // Fall back to manual entry if no backends available\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let items: Vec<PickerItem> = backends\n                            .into_iter()\n                            .map(|b| {\n                                let mut item = PickerItem::new(&b.name);\n                                if let Some(desc) = b.description {\n                                    item = item.with_description(desc);\n                                }\n                                item\n                            })\n                            .collect();\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode =\n                            Mode::Picker(PickerKind::Backend(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::EnvPath(section_idx) => {\n                    // Add _.path array entry\n                    self.doc\n                        .add_entry(section_idx, \"_.path\".to_string(), String::new());\n                    // Convert to array and start editing\n                    let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    // Track undo for added entry\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, entry_idx));\n                    self.doc.sections[section_idx].entries[entry_idx].value =\n                        EntryValue::Array(vec![\"./bin\".to_string()]);\n                    self.doc.sections[section_idx].entries[entry_idx].expanded = true;\n                    self.doc.modified = true;\n                    // Move cursor to the new entry\n                    let target = CursorTarget::Entry(section_idx, entry_idx);\n                    self.cursor.goto(&self.doc, &target);\n                }\n                AddButtonKind::EnvDotenv(_) => {\n                    // Prompt for filename with \".env\" as default\n                    self.mode = Mode::NewKey(InlineEdit::new(\".env\"));\n                }\n                AddButtonKind::EnvSource(_) => {\n                    // Prompt for script path\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::EnvVariable(_) => {\n                    // Standard key=value flow\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::Task(_) => {\n                    // Standard key=value flow for now\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::Prepare(_) => {\n                    // Standard key=value flow for prepare providers\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::Setting(section_idx) => {\n                    // Open setting picker with valid settings from schema\n                    let existing_keys: std::collections::HashSet<_> = self.doc.sections\n                        [section_idx]\n                        .entries\n                        .iter()\n                        .map(|e| e.key.as_str())\n                        .collect();\n                    let items: Vec<PickerItem> = crate::schema::SCHEMA_SETTINGS\n                        .iter()\n                        .filter(|(name, _, _)| !existing_keys.contains(*name))\n                        .map(|(name, desc, _)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    if items.is_empty() {\n                        // All settings already exist, fall back to manual entry\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode =\n                            Mode::Picker(PickerKind::Setting(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::Hook(section_idx) => {\n                    // Open hook picker with common hooks from schema\n                    let existing_keys: std::collections::HashSet<_> = self.doc.sections\n                        [section_idx]\n                        .entries\n                        .iter()\n                        .map(|e| e.key.as_str())\n                        .collect();\n                    let items: Vec<PickerItem> = crate::schema::SCHEMA_HOOKS\n                        .iter()\n                        .filter(|(name, _)| !existing_keys.contains(*name))\n                        .map(|(name, desc)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    if items.is_empty() {\n                        // All common hooks already exist, fall back to manual entry\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode = Mode::Picker(PickerKind::Hook(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::TaskConfig(section_idx) => {\n                    // Open task_config picker with valid keys from schema\n                    let existing_keys: std::collections::HashSet<_> = self.doc.sections\n                        [section_idx]\n                        .entries\n                        .iter()\n                        .map(|e| e.key.as_str())\n                        .collect();\n                    let items: Vec<PickerItem> = crate::schema::SCHEMA_TASK_CONFIG\n                        .iter()\n                        .filter(|(name, _, _)| !existing_keys.contains(*name))\n                        .map(|(name, desc, _)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    if items.is_empty() {\n                        // All task_config keys already exist, fall back to manual entry\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode =\n                            Mode::Picker(PickerKind::TaskConfig(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::Monorepo(section_idx) => {\n                    // Open monorepo picker with valid keys from schema\n                    let existing_keys: std::collections::HashSet<_> = self.doc.sections\n                        [section_idx]\n                        .entries\n                        .iter()\n                        .map(|e| e.key.as_str())\n                        .collect();\n                    let items: Vec<PickerItem> = crate::schema::SCHEMA_MONOREPO\n                        .iter()\n                        .filter(|(name, _, _)| !existing_keys.contains(*name))\n                        .map(|(name, desc, _)| PickerItem::new(*name).with_description(*desc))\n                        .collect();\n                    if items.is_empty() {\n                        // All monorepo keys already exist, fall back to manual entry\n                        self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                    } else {\n                        let picker = PickerState::new(items).with_visible_height(10);\n                        self.mode =\n                            Mode::Picker(PickerKind::Monorepo(section_idx), Box::new(picker));\n                    }\n                }\n                AddButtonKind::ArrayItem(_, _) => {\n                    // For arrays, go straight to value entry\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n                AddButtonKind::InlineTableField(_, _) => {\n                    self.mode = Mode::NewKey(InlineEdit::new(\"\"));\n                }\n            },\n\n            // Comments are not interactive\n            Some(CursorTarget::Comment(_)) => {}\n\n            None => {}\n        }\n\n        Ok(())\n    }\n\n    pub(super) fn handle_remove(&mut self) -> io::Result<()> {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                // Save to undo stack before deleting\n                let entry = self.doc.sections[section_idx].entries[entry_idx].clone();\n                self.undo_stack\n                    .push(UndoAction::DeleteEntry(section_idx, entry_idx, entry));\n                self.doc.delete_entry(section_idx, entry_idx);\n                self.cursor.clamp(&self.doc);\n            }\n            Some(CursorTarget::ArrayItem(section_idx, entry_idx, array_idx)) => {\n                if let EntryValue::Array(items) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let value = items[array_idx].clone();\n                    self.undo_stack.push(UndoAction::DeleteArrayItem(\n                        section_idx,\n                        entry_idx,\n                        array_idx,\n                        value,\n                    ));\n                }\n                self.doc\n                    .delete_array_item(section_idx, entry_idx, array_idx);\n                self.cursor.clamp(&self.doc);\n            }\n            Some(CursorTarget::InlineTableField(section_idx, entry_idx, field_idx)) => {\n                if let Some(section) = self.doc.sections.get_mut(section_idx)\n                    && let Some(entry) = section.entries.get_mut(entry_idx)\n                    && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                    && field_idx < pairs.len()\n                {\n                    let (key, value) = pairs.remove(field_idx);\n                    self.undo_stack.push(UndoAction::DeleteInlineTableField(\n                        section_idx,\n                        entry_idx,\n                        field_idx,\n                        key,\n                        value,\n                    ));\n                    self.doc.modified = true;\n                }\n                self.cursor.clamp(&self.doc);\n            }\n            Some(CursorTarget::SectionHeader(section_idx)) => {\n                // Save to undo stack before deleting\n                let section = self.doc.sections[section_idx].clone();\n                self.undo_stack\n                    .push(UndoAction::DeleteSection(section_idx, section));\n                self.doc.delete_section(section_idx);\n                self.cursor.clamp(&self.doc);\n            }\n            _ => {}\n        }\n\n        Ok(())\n    }\n\n    pub(super) fn undo(&mut self) {\n        if let Some(action) = self.undo_stack.pop() {\n            match action {\n                UndoAction::DeleteEntry(section_idx, entry_idx, entry) => {\n                    // Re-insert the entry at its original position\n                    if section_idx < self.doc.sections.len() {\n                        let entries = &mut self.doc.sections[section_idx].entries;\n                        let insert_idx = entry_idx.min(entries.len());\n                        entries.insert(insert_idx, entry);\n                        self.doc.modified = true;\n                        let target = CursorTarget::Entry(section_idx, insert_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::DeleteArrayItem(section_idx, entry_idx, array_idx, value) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::Array(ref mut items) = entry.value\n                    {\n                        let insert_idx = array_idx.min(items.len());\n                        items.insert(insert_idx, value);\n                        self.doc.modified = true;\n                        let target = CursorTarget::ArrayItem(section_idx, entry_idx, insert_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::DeleteInlineTableField(\n                    section_idx,\n                    entry_idx,\n                    field_idx,\n                    key,\n                    value,\n                ) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                    {\n                        let insert_idx = field_idx.min(pairs.len());\n                        pairs.insert(insert_idx, (key, value));\n                        self.doc.modified = true;\n                        let target =\n                            CursorTarget::InlineTableField(section_idx, entry_idx, insert_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::DeleteSection(section_idx, section) => {\n                    let insert_idx = section_idx.min(self.doc.sections.len());\n                    self.doc.sections.insert(insert_idx, section);\n                    self.doc.modified = true;\n                    let target = CursorTarget::SectionHeader(insert_idx);\n                    self.cursor.goto(&self.doc, &target);\n                }\n                UndoAction::AddEntry(section_idx, entry_idx) => {\n                    // Remove the added entry\n                    if section_idx < self.doc.sections.len() {\n                        let entries = &mut self.doc.sections[section_idx].entries;\n                        if entry_idx < entries.len() {\n                            entries.remove(entry_idx);\n                            self.doc.modified = true;\n                            self.cursor.clamp(&self.doc);\n                        }\n                    }\n                }\n                UndoAction::AddArrayItem(section_idx, entry_idx, array_idx) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::Array(ref mut items) = entry.value\n                        && array_idx < items.len()\n                    {\n                        items.remove(array_idx);\n                        self.doc.modified = true;\n                        self.cursor.clamp(&self.doc);\n                    }\n                }\n                UndoAction::AddInlineTableField(section_idx, entry_idx, field_idx) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                        && field_idx < pairs.len()\n                    {\n                        pairs.remove(field_idx);\n                        self.doc.modified = true;\n                        self.cursor.clamp(&self.doc);\n                    }\n                }\n                UndoAction::AddSection(section_idx) => {\n                    if section_idx < self.doc.sections.len() {\n                        self.doc.sections.remove(section_idx);\n                        self.doc.modified = true;\n                        self.cursor.clamp(&self.doc);\n                    }\n                }\n                UndoAction::EditEntry(section_idx, entry_idx, old_value) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                    {\n                        entry.value = old_value;\n                        self.doc.modified = true;\n                        let target = CursorTarget::Entry(section_idx, entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::EditArrayItem(section_idx, entry_idx, array_idx, old_value) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::Array(ref mut items) = entry.value\n                        && array_idx < items.len()\n                    {\n                        items[array_idx] = old_value;\n                        self.doc.modified = true;\n                        let target = CursorTarget::ArrayItem(section_idx, entry_idx, array_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::EditInlineTableField(section_idx, entry_idx, field_idx, old_value) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                        && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                        && field_idx < pairs.len()\n                    {\n                        pairs[field_idx].1 = old_value;\n                        self.doc.modified = true;\n                        let target =\n                            CursorTarget::InlineTableField(section_idx, entry_idx, field_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::RenameEntry(section_idx, entry_idx, old_key) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                    {\n                        entry.key = old_key;\n                        self.doc.modified = true;\n                        let target = CursorTarget::Entry(section_idx, entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n                UndoAction::ConvertToInlineTable(section_idx, entry_idx, old_value) => {\n                    if let Some(section) = self.doc.sections.get_mut(section_idx)\n                        && let Some(entry) = section.entries.get_mut(entry_idx)\n                    {\n                        entry.value = EntryValue::Simple(old_value);\n                        entry.expanded = false;\n                        self.doc.modified = true;\n                        let target = CursorTarget::Entry(section_idx, entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                }\n            }\n        }\n    }\n\n    pub(super) fn handle_add_options(&mut self) -> io::Result<()> {\n        let target = self.cursor.target(&self.doc);\n\n        // Only works on simple entries (not already inline tables or arrays)\n        if let Some(CursorTarget::Entry(section_idx, entry_idx)) = target {\n            let entry = &self.doc.sections[section_idx].entries[entry_idx];\n            if let EntryValue::Simple(old_value) = &entry.value {\n                // Save old value for undo\n                self.undo_stack.push(UndoAction::ConvertToInlineTable(\n                    section_idx,\n                    entry_idx,\n                    old_value.clone(),\n                ));\n                // Convert to inline table with version key\n                self.doc.convert_to_inline_table(section_idx, entry_idx);\n                // The entry is now expanded, cursor stays on it\n            }\n        }\n\n        Ok(())\n    }\n\n    pub(super) fn handle_rename(&mut self) -> io::Result<()> {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                let key = self.doc.sections[section_idx].entries[entry_idx]\n                    .key\n                    .clone();\n                self.mode = Mode::RenameKey(section_idx, entry_idx, InlineEdit::new(&key));\n            }\n            Some(CursorTarget::InlineTableField(section_idx, entry_idx, field_idx)) => {\n                if let EntryValue::InlineTable(pairs) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let key = pairs[field_idx].0.clone();\n                    // For inline table fields, we use a different approach\n                    // Store field info in a way we can use it\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, InlineEdit::new(&key));\n                    // Note: We'll need to track the field_idx somehow\n                    // For now, we only support entry rename\n                }\n            }\n            _ => {}\n        }\n\n        Ok(())\n    }\n\n    pub(super) fn handle_expand(&mut self) {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::SectionHeader(section_idx)) => {\n                if !self.doc.sections[section_idx].expanded {\n                    self.doc.sections[section_idx].expanded = true;\n                }\n            }\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                let entry = &self.doc.sections[section_idx].entries[entry_idx];\n                // Only expand if it's a complex type (array or inline table)\n                if !entry.expanded\n                    && matches!(\n                        entry.value,\n                        EntryValue::Array(_) | EntryValue::InlineTable(_)\n                    )\n                {\n                    self.doc.sections[section_idx].entries[entry_idx].expanded = true;\n                }\n            }\n            _ => {}\n        }\n    }\n\n    pub(super) fn handle_collapse(&mut self) {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::SectionHeader(section_idx)) => {\n                if self.doc.sections[section_idx].expanded {\n                    self.doc.sections[section_idx].expanded = false;\n                }\n            }\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                if self.doc.sections[section_idx].entries[entry_idx].expanded {\n                    self.doc.sections[section_idx].entries[entry_idx].expanded = false;\n                }\n            }\n            // If on a child item (array item or inline table field), collapse the parent entry\n            Some(CursorTarget::ArrayItem(section_idx, entry_idx, _))\n            | Some(CursorTarget::InlineTableField(section_idx, entry_idx, _)) => {\n                self.doc.sections[section_idx].entries[entry_idx].expanded = false;\n                // Move cursor to the parent entry\n                let target = CursorTarget::Entry(section_idx, entry_idx);\n                self.cursor.goto(&self.doc, &target);\n            }\n            _ => {}\n        }\n    }\n\n    pub(super) fn apply_edit(&mut self, value: String) {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                // Save old value for undo\n                let old_value = self.doc.sections[section_idx].entries[entry_idx]\n                    .value\n                    .clone();\n                self.undo_stack\n                    .push(UndoAction::EditEntry(section_idx, entry_idx, old_value));\n                self.doc.update_entry(section_idx, entry_idx, value);\n            }\n            Some(CursorTarget::ArrayItem(section_idx, entry_idx, array_idx)) => {\n                // Save old value for undo\n                if let EntryValue::Array(items) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let old_value = items[array_idx].clone();\n                    self.undo_stack.push(UndoAction::EditArrayItem(\n                        section_idx,\n                        entry_idx,\n                        array_idx,\n                        old_value,\n                    ));\n                }\n                self.doc\n                    .update_array_item(section_idx, entry_idx, array_idx, value);\n            }\n            Some(CursorTarget::InlineTableField(section_idx, entry_idx, field_idx)) => {\n                if let Some(section) = self.doc.sections.get_mut(section_idx)\n                    && let Some(entry) = section.entries.get_mut(entry_idx)\n                    && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                    && let Some((_, v)) = pairs.get_mut(field_idx)\n                {\n                    // Save old value for undo\n                    let old_value = v.clone();\n                    self.undo_stack.push(UndoAction::EditInlineTableField(\n                        section_idx,\n                        entry_idx,\n                        field_idx,\n                        old_value,\n                    ));\n                    *v = value;\n                    self.doc.modified = true;\n                }\n            }\n            _ => {}\n        }\n    }\n\n    pub(super) fn apply_new_key(&mut self, key_name: String) {\n        let target = self.cursor.target(&self.doc);\n\n        match target {\n            Some(CursorTarget::AddButton(AddButtonKind::Section)) => {\n                let count_before = self.doc.sections.len();\n                self.doc.add_section(key_name);\n                // Only track undo if a section was actually added\n                if self.doc.sections.len() > count_before {\n                    let section_idx = self.doc.sections.len() - 1;\n                    self.undo_stack.push(UndoAction::AddSection(section_idx));\n                }\n                // Move cursor to the new section\n                self.cursor.clamp(&self.doc);\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::Entry(section_idx)))\n            | Some(CursorTarget::AddButton(AddButtonKind::Setting(section_idx))) => {\n                self.doc.add_entry(section_idx, key_name, String::new());\n                // Track undo for added entry\n                let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                self.undo_stack\n                    .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                // Move cursor to the new entry to edit its value\n                let target = CursorTarget::Entry(section_idx, new_entry_idx);\n                self.cursor.goto(&self.doc, &target);\n                // Start editing the value\n                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::Task(section_idx))) => {\n                // Create task as inline table with run field\n                self.doc.sections[section_idx]\n                    .entries\n                    .push(crate::document::Entry {\n                        key: key_name,\n                        value: EntryValue::InlineTable(vec![(\"run\".to_string(), String::new())]),\n                        expanded: true,\n                        comments: Vec::new(),\n                    });\n                self.doc.modified = true;\n                // Track undo for added entry\n                let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                self.undo_stack\n                    .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                // Move cursor to the run field and start editing\n                let target = CursorTarget::InlineTableField(section_idx, new_entry_idx, 0);\n                self.cursor.goto(&self.doc, &target);\n                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::Prepare(section_idx))) => {\n                // Create prepare provider as inline table (e.g., npm = { disable = true })\n                self.doc.sections[section_idx]\n                    .entries\n                    .push(crate::document::Entry {\n                        key: key_name,\n                        value: EntryValue::InlineTable(Vec::new()),\n                        expanded: true,\n                        comments: Vec::new(),\n                    });\n                self.doc.modified = true;\n                // Track undo for added entry\n                let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                self.undo_stack\n                    .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                // Move cursor to the new entry\n                let target = CursorTarget::Entry(section_idx, new_entry_idx);\n                self.cursor.goto(&self.doc, &target);\n                self.mode = Mode::Navigate;\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::EnvVariable(section_idx))) => {\n                // Parse KEY=value format\n                if let Some((key, value)) = key_name.split_once('=') {\n                    let key = key.trim().to_string();\n                    let value = value.trim();\n                    // Strip surrounding quotes (single or double) - must be at least 2 chars\n                    let value = if value.len() >= 2\n                        && ((value.starts_with('\"') && value.ends_with('\"'))\n                            || (value.starts_with('\\'') && value.ends_with('\\'')))\n                    {\n                        value[1..value.len() - 1].to_string()\n                    } else {\n                        value.to_string()\n                    };\n                    if !key.is_empty() {\n                        self.doc.add_entry(section_idx, key, value);\n                        // Track undo for added entry\n                        let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                        self.undo_stack\n                            .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                    }\n                }\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::ArrayItem(section_idx, entry_idx))) => {\n                // key_name is actually the value for arrays\n                self.doc.add_array_item(section_idx, entry_idx, key_name);\n                // Track undo for added array item\n                if let EntryValue::Array(items) =\n                    &self.doc.sections[section_idx].entries[entry_idx].value\n                {\n                    let array_idx = items.len() - 1;\n                    self.undo_stack.push(UndoAction::AddArrayItem(\n                        section_idx,\n                        entry_idx,\n                        array_idx,\n                    ));\n                }\n                self.cursor.clamp(&self.doc);\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::InlineTableField(\n                section_idx,\n                entry_idx,\n            ))) => {\n                if let Some(section) = self.doc.sections.get_mut(section_idx)\n                    && let Some(entry) = section.entries.get_mut(entry_idx)\n                    && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                {\n                    pairs.push((key_name, String::new()));\n                    self.doc.modified = true;\n                    // Track undo for added inline table field\n                    let field_idx = pairs.len() - 1;\n                    self.undo_stack.push(UndoAction::AddInlineTableField(\n                        section_idx,\n                        entry_idx,\n                        field_idx,\n                    ));\n                }\n                self.cursor.clamp(&self.doc);\n                // Move to the new field and edit its value\n                // TODO: implement moving to and editing the new field\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::EnvDotenv(section_idx))) => {\n                // key_name is the filename, add as mise.file = \"<filename>\"\n                if !key_name.is_empty() {\n                    self.doc\n                        .add_entry(section_idx, \"mise.file\".to_string(), key_name);\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                }\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::EnvSource(section_idx))) => {\n                // key_name is the script path, add as _.source = \"<script>\"\n                if !key_name.is_empty() {\n                    self.doc\n                        .add_entry(section_idx, \"_.source\".to_string(), key_name);\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                }\n            }\n            // ToolRegistry and EnvPath are handled in handle_enter directly\n            Some(CursorTarget::AddButton(AddButtonKind::ToolRegistry(_)))\n            | Some(CursorTarget::AddButton(AddButtonKind::EnvPath(_))) => {}\n            Some(CursorTarget::AddButton(AddButtonKind::ToolBackend(section_idx))) => {\n                // Add backend tool (e.g., cargo:ripgrep) with \"latest\" as default\n                if !key_name.is_empty() {\n                    self.doc\n                        .add_entry(section_idx, key_name, \"latest\".to_string());\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                }\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::Hook(section_idx))) => {\n                // Add custom hook entry (e.g., custom_hook = \"echo hello\")\n                if !key_name.is_empty() {\n                    self.doc.add_entry(section_idx, key_name, String::new());\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                    // Move cursor to the new entry to edit its value\n                    let target = CursorTarget::Entry(section_idx, new_entry_idx);\n                    self.cursor.goto(&self.doc, &target);\n                    self.mode = Mode::Edit(InlineEdit::new(\"\"));\n                }\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::TaskConfig(section_idx))) => {\n                // Add custom task_config entry\n                if !key_name.is_empty() {\n                    self.doc.add_entry(section_idx, key_name, String::new());\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                    // Move cursor to the new entry to edit its value\n                    let target = CursorTarget::Entry(section_idx, new_entry_idx);\n                    self.cursor.goto(&self.doc, &target);\n                    self.mode = Mode::Edit(InlineEdit::new(\"\"));\n                }\n            }\n            Some(CursorTarget::AddButton(AddButtonKind::Monorepo(section_idx))) => {\n                // Add custom monorepo entry\n                if !key_name.is_empty() {\n                    self.doc.add_entry(section_idx, key_name, String::new());\n                    // Track undo for added entry\n                    let new_entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                    self.undo_stack\n                        .push(UndoAction::AddEntry(section_idx, new_entry_idx));\n                    // Move cursor to the new entry to edit its value\n                    let target = CursorTarget::Entry(section_idx, new_entry_idx);\n                    self.cursor.goto(&self.doc, &target);\n                    self.mode = Mode::Edit(InlineEdit::new(\"\"));\n                }\n            }\n            _ => {}\n        }\n    }\n\n    pub(super) fn save(&mut self) -> io::Result<()> {\n        if self.dry_run {\n            self.renderer.flash_message(\"Dry-run mode: not saving\")?;\n        } else {\n            self.doc.save(&self.path)?;\n            self.doc.modified = false;\n            self.renderer.flash_message(\"Saved\")?;\n        }\n        Ok(())\n    }\n\n    /// Get a type-appropriate default value for a schema type.\n    /// Returns (value, needs_edit) where needs_edit indicates if the user should be prompted.\n    pub(super) fn type_appropriate_default(\n        schema_type: Option<crate::schema::SchemaType>,\n    ) -> (EntryValue, bool) {\n        use crate::schema::SchemaType;\n        match schema_type {\n            Some(SchemaType::Boolean) => {\n                // Booleans default to true, no edit needed\n                (EntryValue::Simple(\"true\".to_string()), false)\n            }\n            Some(SchemaType::Array) => {\n                // Arrays start empty\n                (EntryValue::Array(Vec::new()), false)\n            }\n            Some(SchemaType::Object) => {\n                // Objects start as empty inline tables\n                (EntryValue::InlineTable(Vec::new()), false)\n            }\n            Some(SchemaType::Integer) | Some(SchemaType::Number) => {\n                // Numbers need user input, start with \"0\"\n                (EntryValue::Simple(\"0\".to_string()), true)\n            }\n            Some(SchemaType::String) | Some(SchemaType::Unknown) | None => {\n                // Strings need user input\n                (EntryValue::Simple(String::new()), true)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/editor/handlers.rs",
    "content": "//! Key handlers for different editor modes\n\nuse console::Key;\nuse std::io;\n\nuse super::undo::UndoAction;\nuse super::{ConfigResult, InteractiveConfig};\nuse crate::cursor::{AddButtonKind, CursorTarget};\nuse crate::document::EntryValue;\nuse crate::inline_edit::InlineEdit;\nuse crate::providers::version_variants;\nuse crate::render::{BooleanSelectState, Mode, PickerKind, VersionSelectState};\n\nimpl InteractiveConfig {\n    /// Handle a key press. Returns Some(result) if the editor should exit.\n    pub(super) async fn handle_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        match &mut self.mode {\n            Mode::Navigate => self.handle_navigate_key(key).await,\n            Mode::Edit(_) => self.handle_edit_key(key),\n            Mode::NewKey(_) => self.handle_new_key_key(key),\n            Mode::ConfirmQuit => self.handle_confirm_quit_key(key),\n            Mode::RenameKey(_, _, _) => self.handle_rename_key(key),\n            Mode::Picker(_, _) => self.handle_picker_key(key).await,\n            Mode::VersionSelect(_) => self.handle_version_select_key(key),\n            Mode::BackendToolName(_, _, _) => self.handle_backend_tool_name_key(key),\n            Mode::BooleanSelect(_) => self.handle_boolean_select_key(key),\n            Mode::Loading(_) => {\n                // Loading mode doesn't handle key presses - it's a transient state\n                Ok(None)\n            }\n        }\n    }\n\n    pub(super) async fn handle_navigate_key(\n        &mut self,\n        key: Key,\n    ) -> io::Result<Option<ConfigResult>> {\n        match key {\n            // Navigation\n            Key::ArrowUp | Key::Char('k') => {\n                self.cursor.up(&self.doc);\n            }\n            Key::ArrowDown | Key::Char('j') => {\n                self.cursor.down(&self.doc);\n            }\n            Key::ArrowLeft | Key::Char('h') => {\n                self.handle_collapse();\n            }\n            Key::ArrowRight | Key::Char('l') => {\n                self.handle_expand();\n            }\n            Key::Tab => {\n                self.cursor.next_section(&self.doc);\n            }\n            Key::BackTab => {\n                self.cursor.prev_section(&self.doc);\n            }\n\n            // Actions\n            Key::Enter => {\n                self.handle_enter().await?;\n            }\n            Key::Backspace => {\n                self.handle_remove()?;\n            }\n            Key::Char('o') => {\n                self.handle_add_options()?;\n            }\n            Key::Char('u') => {\n                self.undo();\n            }\n            Key::Char('r') => {\n                self.handle_rename()?;\n            }\n            Key::Char('s') if !self.dry_run => {\n                self.save()?;\n                let content = self.doc.to_toml();\n                return Ok(Some(ConfigResult::Saved(content)));\n            }\n            Key::Char('q') | Key::Escape => {\n                if self.dry_run {\n                    // In dry-run mode, just exit immediately\n                    let content = self.doc.to_toml();\n                    return Ok(Some(ConfigResult::Saved(content)));\n                } else if self.doc.modified {\n                    self.mode = Mode::ConfirmQuit;\n                } else {\n                    return Ok(Some(ConfigResult::Cancelled));\n                }\n            }\n\n            _ => {}\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_edit_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        if let Mode::Edit(ref mut edit) = self.mode {\n            match key {\n                Key::Enter => {\n                    let value = std::mem::replace(edit, InlineEdit::new(\"\")).confirm();\n                    self.apply_edit(value);\n                    self.mode = Mode::Navigate;\n                }\n                Key::Escape => {\n                    self.mode = Mode::Navigate;\n                }\n                Key::ArrowLeft => {\n                    edit.left();\n                }\n                Key::ArrowRight => {\n                    edit.right();\n                }\n                Key::Home => {\n                    edit.home();\n                }\n                Key::End => {\n                    edit.end();\n                }\n                Key::Backspace => {\n                    edit.backspace();\n                }\n                Key::Del => {\n                    edit.delete();\n                }\n                Key::Char(c) => {\n                    edit.insert(c);\n                }\n                _ => {}\n            }\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_new_key_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        if let Mode::NewKey(ref mut edit) = self.mode {\n            match key {\n                Key::Enter => {\n                    // Check if we need KEY=value validation (for env variables)\n                    let needs_key_value = matches!(\n                        self.cursor.target(&self.doc),\n                        Some(CursorTarget::AddButton(AddButtonKind::EnvVariable(_)))\n                    );\n\n                    let input = edit.buffer().to_string();\n\n                    // Validate KEY=value format if needed\n                    if needs_key_value && !input.contains('=') {\n                        // Don't accept - needs KEY=value format\n                        return Ok(None);\n                    }\n\n                    let key_name = std::mem::replace(edit, InlineEdit::new(\"\")).confirm();\n                    if !key_name.is_empty() {\n                        self.apply_new_key(key_name);\n                    }\n                    self.mode = Mode::Navigate;\n                }\n                Key::Escape => {\n                    self.mode = Mode::Navigate;\n                }\n                Key::ArrowLeft => {\n                    edit.left();\n                }\n                Key::ArrowRight => {\n                    edit.right();\n                }\n                Key::Home => {\n                    edit.home();\n                }\n                Key::End => {\n                    edit.end();\n                }\n                Key::Backspace => {\n                    edit.backspace();\n                }\n                Key::Del => {\n                    edit.delete();\n                }\n                Key::Char(c) => {\n                    edit.insert(c);\n                }\n                _ => {}\n            }\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_confirm_quit_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        match key {\n            Key::Char('y') | Key::Char('Y') => {\n                self.save()?;\n                let content = self.doc.to_toml();\n                return Ok(Some(ConfigResult::Saved(content)));\n            }\n            Key::Char('n') | Key::Char('N') => {\n                return Ok(Some(ConfigResult::Cancelled));\n            }\n            Key::Escape => {\n                self.mode = Mode::Navigate;\n            }\n            _ => {}\n        }\n        Ok(None)\n    }\n\n    pub(super) async fn handle_picker_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        // We need to take ownership of the mode to modify the picker\n        let mode = std::mem::replace(&mut self.mode, Mode::Navigate);\n\n        if let Mode::Picker(kind, picker) = mode {\n            let mut picker = *picker;\n            match key {\n                Key::Escape => {\n                    // Cancel and return to navigate mode\n                    self.mode = Mode::Navigate;\n                }\n                Key::Enter => {\n                    // Select the current item\n                    if let Some(selected) = picker.selected() {\n                        let tool_name = selected.name.clone();\n                        match &kind {\n                            PickerKind::Tool(section_idx) => {\n                                self.handle_picker_tool_select(&tool_name, *section_idx)\n                                    .await;\n                            }\n                            PickerKind::Backend(section_idx) => {\n                                // Transition to entering the tool name with the selected backend\n                                let backend_name = tool_name;\n                                self.mode = Mode::BackendToolName(\n                                    backend_name,\n                                    *section_idx,\n                                    InlineEdit::new(\"\"),\n                                );\n                            }\n                            PickerKind::Setting(section_idx) => {\n                                self.handle_picker_setting_select(&tool_name, *section_idx);\n                            }\n                            PickerKind::Hook(section_idx) => {\n                                // Add the selected hook with empty value\n                                self.doc.add_entry(*section_idx, tool_name, String::new());\n                                let entry_idx = self.doc.sections[*section_idx].entries.len() - 1;\n                                // Track undo for added entry\n                                self.undo_stack\n                                    .push(UndoAction::AddEntry(*section_idx, entry_idx));\n                                let target = CursorTarget::Entry(*section_idx, entry_idx);\n                                self.cursor.goto(&self.doc, &target);\n                                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n                            }\n                            PickerKind::TaskConfig(section_idx) => {\n                                self.handle_picker_task_config_select(&tool_name, *section_idx);\n                            }\n                            PickerKind::Monorepo(section_idx) => {\n                                self.handle_picker_monorepo_select(&tool_name, *section_idx);\n                            }\n                            PickerKind::Section => {\n                                self.handle_picker_section_select(&tool_name);\n                            }\n                        }\n                    } else {\n                        // No selection, return to navigate\n                        self.mode = Mode::Navigate;\n                    }\n                }\n                Key::ArrowUp | Key::Char('k') => {\n                    picker.move_up();\n                    self.mode = Mode::Picker(kind, Box::new(picker));\n                }\n                Key::ArrowDown | Key::Char('j') => {\n                    picker.move_down();\n                    self.mode = Mode::Picker(kind, Box::new(picker));\n                }\n                Key::Backspace => {\n                    picker.backspace();\n                    self.mode = Mode::Picker(kind, Box::new(picker));\n                }\n                Key::Char(c) => {\n                    picker.type_char(c);\n                    self.mode = Mode::Picker(kind, Box::new(picker));\n                }\n                _ => {\n                    // Keep current state for unhandled keys\n                    self.mode = Mode::Picker(kind, Box::new(picker));\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    async fn handle_picker_tool_select(&mut self, tool_name: &str, section_idx: usize) {\n        // Add the selected tool with default version\n        self.doc\n            .add_entry(section_idx, tool_name.to_string(), \"latest\".to_string());\n        // Move cursor to the new entry\n        let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n        // Track undo for added entry\n        self.undo_stack\n            .push(UndoAction::AddEntry(section_idx, entry_idx));\n        let target = CursorTarget::Entry(section_idx, entry_idx);\n        self.cursor.goto(&self.doc, &target);\n\n        // Show loading indicator while fetching version info\n        self.mode = Mode::Loading(format!(\"Fetching versions for {}...\", tool_name));\n        let _ = self.render_current_mode();\n\n        // Try to use version selector if we have version info\n        if let Some(latest) = self.version_provider.latest_version(tool_name).await {\n            let variants = version_variants(&latest);\n            let mut vs = VersionSelectState::new(\n                tool_name.to_string(),\n                variants.clone(),\n                section_idx,\n                entry_idx,\n            );\n            // Use preferred specificity, clamped to valid range\n            vs.selected = self\n                .preferred_specificity\n                .min(variants.len().saturating_sub(2));\n            self.mode = Mode::VersionSelect(vs);\n        } else {\n            // Fall back to inline edit\n            self.mode = Mode::Edit(InlineEdit::new(\"latest\"));\n        }\n    }\n\n    fn handle_picker_setting_select(&mut self, tool_name: &str, section_idx: usize) {\n        // Check if this is a boolean setting\n        let schema_type = crate::schema::setting_type(tool_name);\n        if schema_type == Some(crate::schema::SchemaType::Boolean) {\n            // Show boolean picker\n            self.mode = Mode::BooleanSelect(BooleanSelectState::new_entry(\n                tool_name.to_string(),\n                section_idx,\n            ));\n        } else {\n            // Add with type-appropriate value\n            let (value, needs_edit) = Self::type_appropriate_default(schema_type);\n            self.doc\n                .add_entry_with_value(section_idx, tool_name.to_string(), value);\n            let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n            // Track undo for added entry\n            self.undo_stack\n                .push(UndoAction::AddEntry(section_idx, entry_idx));\n            let target = CursorTarget::Entry(section_idx, entry_idx);\n            self.cursor.goto(&self.doc, &target);\n            if needs_edit {\n                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n            } else {\n                self.mode = Mode::Navigate;\n            }\n        }\n    }\n\n    fn handle_picker_task_config_select(&mut self, tool_name: &str, section_idx: usize) {\n        // Check if this is a boolean\n        let schema_type = crate::schema::task_config_type(tool_name);\n        if schema_type == Some(crate::schema::SchemaType::Boolean) {\n            // Show boolean picker\n            self.mode = Mode::BooleanSelect(BooleanSelectState::new_entry(\n                tool_name.to_string(),\n                section_idx,\n            ));\n        } else {\n            // Add with type-appropriate value\n            let (value, needs_edit) = Self::type_appropriate_default(schema_type);\n            self.doc\n                .add_entry_with_value(section_idx, tool_name.to_string(), value);\n            let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n            // Track undo for added entry\n            self.undo_stack\n                .push(UndoAction::AddEntry(section_idx, entry_idx));\n            let target = CursorTarget::Entry(section_idx, entry_idx);\n            self.cursor.goto(&self.doc, &target);\n            if needs_edit {\n                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n            } else {\n                self.mode = Mode::Navigate;\n            }\n        }\n    }\n\n    fn handle_picker_monorepo_select(&mut self, tool_name: &str, section_idx: usize) {\n        // Check if this is a boolean\n        let schema_type = crate::schema::monorepo_type(tool_name);\n        if schema_type == Some(crate::schema::SchemaType::Boolean) {\n            // Show boolean picker\n            self.mode = Mode::BooleanSelect(BooleanSelectState::new_entry(\n                tool_name.to_string(),\n                section_idx,\n            ));\n        } else {\n            // Add with type-appropriate value\n            let (value, needs_edit) = Self::type_appropriate_default(schema_type);\n            self.doc\n                .add_entry_with_value(section_idx, tool_name.to_string(), value);\n            let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n            // Track undo for added entry\n            self.undo_stack\n                .push(UndoAction::AddEntry(section_idx, entry_idx));\n            let target = CursorTarget::Entry(section_idx, entry_idx);\n            self.cursor.goto(&self.doc, &target);\n            if needs_edit {\n                self.mode = Mode::Edit(InlineEdit::new(\"\"));\n            } else {\n                self.mode = Mode::Navigate;\n            }\n        }\n    }\n\n    fn handle_picker_section_select(&mut self, tool_name: &str) {\n        // Check if the selected item is a section or a top-level entry\n        let is_section = crate::schema::is_valid_section(tool_name);\n\n        if is_section {\n            // Add as a new section\n            let count_before = self.doc.sections.len();\n            self.doc.add_section(tool_name.to_string());\n            // Find and move cursor to the new section\n            if let Some(idx) = self.doc.sections.iter().position(|s| s.name == tool_name) {\n                // Only track undo if a section was actually added\n                if self.doc.sections.len() > count_before {\n                    self.undo_stack.push(UndoAction::AddSection(idx));\n                }\n                let target = CursorTarget::SectionHeader(idx);\n                self.cursor.goto(&self.doc, &target);\n            }\n            self.mode = Mode::Navigate;\n        } else {\n            // Add as a top-level entry (in root section with empty name)\n            // Find or create the root section\n            let root_idx =\n                if let Some(idx) = self.doc.sections.iter().position(|s| s.name.is_empty()) {\n                    idx\n                } else {\n                    // Create root section at the beginning\n                    // This shifts all section indices, so clear undo stack to avoid corruption\n                    self.undo_stack.clear();\n                    self.doc.sections.insert(\n                        0,\n                        crate::document::Section {\n                            name: String::new(),\n                            entries: Vec::new(),\n                            expanded: true,\n                            comments: Vec::new(),\n                        },\n                    );\n                    self.doc.modified = true;\n                    0\n                };\n\n            // Check if this is a boolean entry\n            let schema_type = crate::schema::entry_type(tool_name);\n            if schema_type == Some(crate::schema::SchemaType::Boolean) {\n                // Show boolean picker\n                self.mode = Mode::BooleanSelect(BooleanSelectState::new_entry(\n                    tool_name.to_string(),\n                    root_idx,\n                ));\n            } else {\n                // Add the entry with type-appropriate value\n                let (value, needs_edit) = Self::type_appropriate_default(schema_type);\n                self.doc\n                    .add_entry_with_value(root_idx, tool_name.to_string(), value);\n                let entry_idx = self.doc.sections[root_idx].entries.len() - 1;\n                // Track undo for added entry\n                self.undo_stack\n                    .push(UndoAction::AddEntry(root_idx, entry_idx));\n                let target = CursorTarget::Entry(root_idx, entry_idx);\n                self.cursor.goto(&self.doc, &target);\n                if needs_edit {\n                    self.mode = Mode::Edit(InlineEdit::new(\"\"));\n                } else {\n                    self.mode = Mode::Navigate;\n                }\n            }\n        }\n    }\n\n    pub(super) fn handle_backend_tool_name_key(\n        &mut self,\n        key: Key,\n    ) -> io::Result<Option<ConfigResult>> {\n        // Take ownership of the mode\n        let mode = std::mem::replace(&mut self.mode, Mode::Navigate);\n\n        if let Mode::BackendToolName(backend_name, section_idx, mut edit) = mode {\n            match key {\n                Key::Escape => {\n                    // Cancel and return to navigate mode\n                    self.mode = Mode::Navigate;\n                }\n                Key::Enter => {\n                    let tool_name = edit.confirm();\n                    if !tool_name.is_empty() {\n                        // Combine backend and tool name (e.g., \"cargo:ripgrep\")\n                        let full_name = format!(\"{}:{}\", backend_name, tool_name);\n                        self.doc\n                            .add_entry(section_idx, full_name, \"latest\".to_string());\n                        // Move cursor to the new entry\n                        let entry_idx = self.doc.sections[section_idx].entries.len() - 1;\n                        // Track undo for added entry\n                        self.undo_stack\n                            .push(UndoAction::AddEntry(section_idx, entry_idx));\n                        let target = CursorTarget::Entry(section_idx, entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                    self.mode = Mode::Navigate;\n                }\n                Key::ArrowLeft => {\n                    edit.left();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::ArrowRight => {\n                    edit.right();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::Home => {\n                    edit.home();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::End => {\n                    edit.end();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::Backspace => {\n                    edit.backspace();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::Del => {\n                    edit.delete();\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                Key::Char(c) => {\n                    edit.insert(c);\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n                _ => {\n                    self.mode = Mode::BackendToolName(backend_name, section_idx, edit);\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_version_select_key(\n        &mut self,\n        key: Key,\n    ) -> io::Result<Option<ConfigResult>> {\n        use crate::providers::VERSION_CUSTOM_MARKER;\n\n        // Take ownership of the mode\n        let mode = std::mem::replace(&mut self.mode, Mode::Navigate);\n\n        if let Mode::VersionSelect(mut vs) = mode {\n            match key {\n                Key::Escape => {\n                    // Cancel and return to navigate mode\n                    self.mode = Mode::Navigate;\n                }\n                Key::Enter => {\n                    let version = vs.current().to_string();\n                    if version == VERSION_CUSTOM_MARKER {\n                        // Switch to inline edit for custom version entry\n                        // Move cursor to the entry we're editing\n                        let target = CursorTarget::Entry(vs.section_idx, vs.entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                        // Get current value to pre-fill the edit\n                        let current = if let Some(entry) = self\n                            .doc\n                            .sections\n                            .get(vs.section_idx)\n                            .and_then(|s| s.entries.get(vs.entry_idx))\n                        {\n                            match &entry.value {\n                                EntryValue::Simple(v) => v.clone(),\n                                _ => String::new(),\n                            }\n                        } else {\n                            String::new()\n                        };\n                        self.mode = Mode::Edit(InlineEdit::new(&current));\n                    } else {\n                        // Confirm selection and update the entry\n                        // Save old value for undo\n                        let old_value = self.doc.sections[vs.section_idx].entries[vs.entry_idx]\n                            .value\n                            .clone();\n                        self.undo_stack.push(UndoAction::EditEntry(\n                            vs.section_idx,\n                            vs.entry_idx,\n                            old_value,\n                        ));\n                        self.doc\n                            .update_entry(vs.section_idx, vs.entry_idx, version.clone());\n                        // Remember this specificity for future tools\n                        self.preferred_specificity = vs.selected;\n                        self.mode = Mode::Navigate;\n                    }\n                }\n                Key::ArrowLeft | Key::Char('h') => {\n                    vs.prev();\n                    self.mode = Mode::VersionSelect(vs);\n                }\n                Key::ArrowRight | Key::Char('l') => {\n                    vs.next();\n                    self.mode = Mode::VersionSelect(vs);\n                }\n                _ => {\n                    // Keep current state\n                    self.mode = Mode::VersionSelect(vs);\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_boolean_select_key(\n        &mut self,\n        key: Key,\n    ) -> io::Result<Option<ConfigResult>> {\n        // Take ownership of the mode\n        let mode = std::mem::replace(&mut self.mode, Mode::Navigate);\n\n        if let Mode::BooleanSelect(mut bs) = mode {\n            match key {\n                Key::Escape => {\n                    // Cancel and return to navigate mode\n                    self.mode = Mode::Navigate;\n                }\n                Key::Enter => {\n                    // Confirm selection\n                    let value = bs.value_str().to_string();\n                    if let (Some(entry_idx), Some(field_idx)) = (bs.entry_idx, bs.field_idx) {\n                        // Editing inline table field\n                        if let Some(section) = self.doc.sections.get_mut(bs.section_idx)\n                            && let Some(entry) = section.entries.get_mut(entry_idx)\n                            && let EntryValue::InlineTable(ref mut pairs) = entry.value\n                            && let Some((_, v)) = pairs.get_mut(field_idx)\n                        {\n                            *v = value;\n                            self.doc.modified = true;\n                        }\n                    } else if let Some(entry_idx) = bs.entry_idx {\n                        // Editing existing entry\n                        self.doc.update_entry(bs.section_idx, entry_idx, value);\n                    } else {\n                        // Adding new entry\n                        self.doc.add_entry(bs.section_idx, bs.key.clone(), value);\n                        let entry_idx = self.doc.sections[bs.section_idx].entries.len() - 1;\n                        // Track undo for added entry\n                        self.undo_stack\n                            .push(UndoAction::AddEntry(bs.section_idx, entry_idx));\n                        let target = CursorTarget::Entry(bs.section_idx, entry_idx);\n                        self.cursor.goto(&self.doc, &target);\n                    }\n                    self.mode = Mode::Navigate;\n                }\n                Key::ArrowLeft | Key::ArrowRight | Key::Char('h') | Key::Char('l') | Key::Tab => {\n                    // Toggle between true and false\n                    bs.toggle();\n                    self.mode = Mode::BooleanSelect(bs);\n                }\n                Key::Char('t') => {\n                    // Quick select true\n                    bs.selected = true;\n                    self.mode = Mode::BooleanSelect(bs);\n                }\n                Key::Char('f') => {\n                    // Quick select false\n                    bs.selected = false;\n                    self.mode = Mode::BooleanSelect(bs);\n                }\n                _ => {\n                    // Keep current state\n                    self.mode = Mode::BooleanSelect(bs);\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    pub(super) fn handle_rename_key(&mut self, key: Key) -> io::Result<Option<ConfigResult>> {\n        // Take ownership of the mode\n        let mode = std::mem::replace(&mut self.mode, Mode::Navigate);\n\n        if let Mode::RenameKey(section_idx, entry_idx, mut edit) = mode {\n            match key {\n                Key::Escape => {\n                    self.mode = Mode::Navigate;\n                }\n                Key::Enter => {\n                    let new_key = edit.confirm();\n                    if !new_key.is_empty() {\n                        // Apply the rename\n                        if let Some(section) = self.doc.sections.get_mut(section_idx)\n                            && let Some(entry) = section.entries.get_mut(entry_idx)\n                            && entry.key != new_key\n                        {\n                            // Save old key for undo\n                            let old_key = entry.key.clone();\n                            self.undo_stack.push(UndoAction::RenameEntry(\n                                section_idx,\n                                entry_idx,\n                                old_key,\n                            ));\n                            entry.key = new_key;\n                            self.doc.modified = true;\n                        }\n                    }\n                    self.mode = Mode::Navigate;\n                }\n                Key::ArrowLeft => {\n                    edit.left();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::ArrowRight => {\n                    edit.right();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::Home => {\n                    edit.home();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::End => {\n                    edit.end();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::Backspace => {\n                    edit.backspace();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::Del => {\n                    edit.delete();\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                Key::Char(c) => {\n                    edit.insert(c);\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n                _ => {\n                    self.mode = Mode::RenameKey(section_idx, entry_idx, edit);\n                }\n            }\n        }\n        Ok(None)\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/editor/mod.rs",
    "content": "//! Interactive TOML config editor\n//!\n//! This module provides the main editor interface for interactively editing\n//! mise configuration files.\n\nmod actions;\nmod handlers;\nmod undo;\n\nuse std::io;\nuse std::path::PathBuf;\n\nuse crate::cursor::Cursor;\nuse crate::document::{EntryValue, TomlDocument};\nuse crate::providers::{\n    BackendProvider, EmptyBackendProvider, EmptyToolProvider, EmptyVersionProvider, ToolProvider,\n    VersionProvider,\n};\nuse crate::render::{Mode, Renderer};\n\nuse undo::UndoAction;\n\n/// Result of running the interactive config editor\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum ConfigResult {\n    /// User saved changes (includes document content as TOML string)\n    Saved(String),\n    /// User quit without saving\n    Cancelled,\n}\n\n/// Interactive TOML config editor\npub struct InteractiveConfig {\n    path: PathBuf,\n    pub(crate) doc: TomlDocument,\n    pub(crate) cursor: Cursor,\n    pub(crate) mode: Mode,\n    dry_run: bool,\n    title: String,\n    pub(crate) renderer: Renderer,\n    pub(crate) tool_provider: Box<dyn ToolProvider>,\n    pub(crate) version_provider: Box<dyn VersionProvider>,\n    pub(crate) backend_provider: Box<dyn BackendProvider>,\n    /// Preferred version specificity index (0=latest, 1=major, 2=major.minor, 3=full, etc.)\n    pub(crate) preferred_specificity: usize,\n    /// Undo stack for deleted items\n    pub(crate) undo_stack: Vec<UndoAction>,\n    /// Cached display path for rendering\n    pub(crate) path_display: String,\n}\n\nimpl InteractiveConfig {\n    /// Create a new config editor for a new file with default sections\n    pub fn new(path: PathBuf) -> Self {\n        let path_display = Self::compute_path_display(&path);\n        Self {\n            path,\n            doc: TomlDocument::new(),\n            cursor: Cursor::new(),\n            mode: Mode::Navigate,\n            dry_run: false,\n            title: \"mise config editor\".to_string(),\n            renderer: Renderer::new(),\n            tool_provider: Box::new(EmptyToolProvider),\n            version_provider: Box::new(EmptyVersionProvider),\n            backend_provider: Box::new(EmptyBackendProvider),\n            preferred_specificity: 0, // Default to \"latest\"\n            undo_stack: Vec::new(),\n            path_display,\n        }\n    }\n\n    /// Open an existing config file for editing\n    pub fn open(path: PathBuf) -> io::Result<Self> {\n        let doc = if path.exists() {\n            TomlDocument::load(&path)?\n        } else {\n            TomlDocument::new()\n        };\n\n        // Infer preferred specificity from last tool in the file\n        let preferred_specificity = Self::infer_specificity_from_doc(&doc);\n        let path_display = Self::compute_path_display(&path);\n\n        Ok(Self {\n            path,\n            doc,\n            cursor: Cursor::new(),\n            mode: Mode::Navigate,\n            dry_run: false,\n            title: \"mise config editor\".to_string(),\n            renderer: Renderer::new(),\n            tool_provider: Box::new(EmptyToolProvider),\n            version_provider: Box::new(EmptyVersionProvider),\n            backend_provider: Box::new(EmptyBackendProvider),\n            preferred_specificity,\n            undo_stack: Vec::new(),\n            path_display,\n        })\n    }\n\n    /// Infer version specificity from the last tool in the document\n    fn infer_specificity_from_doc(doc: &TomlDocument) -> usize {\n        // Find the tools section\n        let tools_section = doc.sections.iter().find(|s| s.name == \"tools\");\n        if let Some(section) = tools_section {\n            // Get the last entry's version\n            if let Some(entry) = section.entries.last()\n                && let EntryValue::Simple(version) = &entry.value\n            {\n                return Self::version_to_specificity(version);\n            }\n        }\n        0 // Default to \"latest\"\n    }\n\n    /// Convert a version string to a specificity index\n    fn version_to_specificity(version: &str) -> usize {\n        if version == \"latest\" {\n            0\n        } else {\n            // Count dots to determine specificity\n            // \"22\" -> 1 (major)\n            // \"22.13\" -> 2 (major.minor)\n            // \"22.13.1\" -> 3 (full)\n            let dots = version.chars().filter(|c| *c == '.').count();\n            dots + 1\n        }\n    }\n\n    /// Compute the display path for rendering\n    fn compute_path_display(path: &std::path::Path) -> String {\n        let abs_path = if path.is_relative() {\n            std::env::current_dir()\n                .map(|cwd| cwd.join(path))\n                .unwrap_or_else(|_| path.to_path_buf())\n        } else {\n            path.to_path_buf()\n        };\n        xx::file::display_path(&abs_path)\n    }\n\n    /// Set dry-run mode (no file writes)\n    pub fn dry_run(mut self, dry_run: bool) -> Self {\n        self.dry_run = dry_run;\n        self\n    }\n\n    /// Set the title displayed in the header\n    pub fn title(mut self, title: &str) -> Self {\n        self.title = title.to_string();\n        self\n    }\n\n    /// Set the tool provider for the tool picker\n    pub fn with_tool_provider(mut self, provider: Box<dyn ToolProvider>) -> Self {\n        self.tool_provider = provider;\n        self\n    }\n\n    /// Set the version provider for version cycling\n    pub fn with_version_provider(mut self, provider: Box<dyn VersionProvider>) -> Self {\n        self.version_provider = provider;\n        self\n    }\n\n    /// Set the backend provider for the backend picker\n    pub fn with_backend_provider(mut self, provider: Box<dyn BackendProvider>) -> Self {\n        self.backend_provider = provider;\n        self\n    }\n\n    /// Add a tool to the tools section\n    pub fn add_tool(&mut self, name: &str, version: &str) {\n        if let Some(tools_idx) = self.doc.sections.iter().position(|s| s.name == \"tools\") {\n            // Check if tool already exists\n            if !self.doc.sections[tools_idx]\n                .entries\n                .iter()\n                .any(|e| e.key == name)\n            {\n                self.doc\n                    .add_entry(tools_idx, name.to_string(), version.to_string());\n            }\n        }\n    }\n\n    /// Add a prepare provider with auto = true\n    pub fn add_prepare(&mut self, provider: &str) {\n        // Find or create prepare section\n        let prepare_idx =\n            if let Some(idx) = self.doc.sections.iter().position(|s| s.name == \"prepare\") {\n                idx\n            } else {\n                // Insert prepare section before settings\n                let settings_idx = self.doc.sections.iter().position(|s| s.name == \"settings\");\n                let insert_idx = settings_idx.unwrap_or(self.doc.sections.len());\n                self.doc.sections.insert(\n                    insert_idx,\n                    crate::document::Section {\n                        name: \"prepare\".to_string(),\n                        entries: Vec::new(),\n                        expanded: false,\n                        comments: Vec::new(),\n                    },\n                );\n                insert_idx\n            };\n\n        // Check if provider already exists\n        if !self.doc.sections[prepare_idx]\n            .entries\n            .iter()\n            .any(|e| e.key == provider)\n        {\n            // Add as inline table with auto = true\n            self.doc.sections[prepare_idx]\n                .entries\n                .push(crate::document::Entry {\n                    key: provider.to_string(),\n                    value: EntryValue::InlineTable(vec![(\"auto\".to_string(), \"true\".to_string())]),\n                    expanded: false,\n                    comments: Vec::new(),\n                });\n            self.doc.modified = true;\n        }\n    }\n\n    /// Run the interactive editor\n    pub async fn run(mut self) -> io::Result<ConfigResult> {\n        // Initial render\n        self.render_current_mode()?;\n\n        loop {\n            // Read key in blocking task to not block the async runtime\n            let term = self.renderer.term().clone();\n            let key = tokio::task::spawn_blocking(move || term.read_key())\n                .await\n                .map_err(io::Error::other)??;\n\n            let should_exit = self.handle_key(key).await?;\n            if let Some(result) = should_exit {\n                // Clear the display before returning\n                self.renderer.clear()?;\n                return Ok(result);\n            }\n\n            // Re-render\n            self.render_current_mode()?;\n        }\n    }\n\n    /// Render based on current mode\n    pub(crate) fn render_current_mode(&mut self) -> io::Result<()> {\n        match &self.mode {\n            Mode::Picker(kind, picker) => {\n                self.renderer\n                    .render_picker(picker, kind, &self.path_display)?;\n            }\n            Mode::Loading(message) => {\n                self.renderer\n                    .render_loading(message, &self.title, &self.path_display)?;\n            }\n            _ => {\n                self.renderer.render(\n                    &self.doc,\n                    &self.cursor,\n                    &self.mode,\n                    &self.title,\n                    &self.path_display,\n                    self.dry_run,\n                    !self.undo_stack.is_empty(),\n                )?;\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/editor/undo.rs",
    "content": "//! Undo system for the interactive editor\n\nuse crate::document::{Entry, EntryValue, Section};\n\n/// An action that can be undone\n#[derive(Debug, Clone)]\npub enum UndoAction {\n    /// Deleted an entry (section_idx, entry_idx, entry)\n    DeleteEntry(usize, usize, Entry),\n    /// Deleted an array item (section_idx, entry_idx, array_idx, value)\n    DeleteArrayItem(usize, usize, usize, String),\n    /// Deleted an inline table field (section_idx, entry_idx, field_idx, key, value)\n    DeleteInlineTableField(usize, usize, usize, String, String),\n    /// Deleted a section (section_idx, section)\n    DeleteSection(usize, Section),\n    /// Added an entry (section_idx, entry_idx)\n    AddEntry(usize, usize),\n    /// Added an array item (section_idx, entry_idx, array_idx)\n    AddArrayItem(usize, usize, usize),\n    /// Added an inline table field (section_idx, entry_idx, field_idx)\n    AddInlineTableField(usize, usize, usize),\n    /// Added a section (section_idx)\n    AddSection(usize),\n    /// Edited an entry value (section_idx, entry_idx, old_value)\n    EditEntry(usize, usize, EntryValue),\n    /// Edited an array item (section_idx, entry_idx, array_idx, old_value)\n    EditArrayItem(usize, usize, usize, String),\n    /// Edited an inline table field value (section_idx, entry_idx, field_idx, old_value)\n    EditInlineTableField(usize, usize, usize, String),\n    /// Renamed an entry key (section_idx, entry_idx, old_key)\n    RenameEntry(usize, usize, String),\n    /// Converted entry to inline table (section_idx, entry_idx, old_simple_value)\n    ConvertToInlineTable(usize, usize, String),\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/inline_edit.rs",
    "content": "//! InlineEdit: Text editing with cursor position\n\nuse unicode_width::UnicodeWidthStr;\n\n/// Inline text editor state\n#[derive(Debug, Clone)]\npub struct InlineEdit {\n    /// The text being edited\n    buffer: String,\n    /// Cursor position (character index, not byte)\n    cursor: usize,\n    /// Original value (for cancel/restore)\n    #[allow(dead_code)]\n    original: String,\n}\n\nimpl InlineEdit {\n    /// Create a new inline editor with initial value\n    pub fn new(initial: &str) -> Self {\n        let len = initial.chars().count();\n        Self {\n            buffer: initial.to_string(),\n            cursor: len,\n            original: initial.to_string(),\n        }\n    }\n\n    /// Get the current buffer contents\n    pub fn buffer(&self) -> &str {\n        &self.buffer\n    }\n\n    /// Get the cursor position (character index)\n    pub fn cursor(&self) -> usize {\n        self.cursor\n    }\n\n    /// Get display width up to cursor position\n    #[allow(dead_code)]\n    pub fn cursor_display_width(&self) -> usize {\n        let text_before_cursor: String = self.buffer.chars().take(self.cursor).collect();\n        text_before_cursor.width()\n    }\n\n    /// Get the original value\n    #[allow(dead_code)]\n    pub fn original(&self) -> &str {\n        &self.original\n    }\n\n    /// Move cursor left\n    pub fn left(&mut self) {\n        if self.cursor > 0 {\n            self.cursor -= 1;\n        }\n    }\n\n    /// Move cursor right\n    pub fn right(&mut self) {\n        let len = self.buffer.chars().count();\n        if self.cursor < len {\n            self.cursor += 1;\n        }\n    }\n\n    /// Move cursor to start\n    pub fn home(&mut self) {\n        self.cursor = 0;\n    }\n\n    /// Move cursor to end\n    pub fn end(&mut self) {\n        self.cursor = self.buffer.chars().count();\n    }\n\n    /// Insert a character at cursor position\n    pub fn insert(&mut self, c: char) {\n        let byte_pos = self.cursor_byte_position();\n        self.buffer.insert(byte_pos, c);\n        self.cursor += 1;\n    }\n\n    /// Insert a string at cursor position\n    #[allow(dead_code)]\n    pub fn insert_str(&mut self, s: &str) {\n        let byte_pos = self.cursor_byte_position();\n        self.buffer.insert_str(byte_pos, s);\n        self.cursor += s.chars().count();\n    }\n\n    /// Delete character before cursor (backspace)\n    pub fn backspace(&mut self) {\n        if self.cursor > 0 {\n            self.cursor -= 1;\n            let byte_pos = self.cursor_byte_position();\n            let char_len = self.buffer[byte_pos..]\n                .chars()\n                .next()\n                .map_or(0, |c| c.len_utf8());\n            self.buffer.drain(byte_pos..byte_pos + char_len);\n        }\n    }\n\n    /// Delete character at cursor (delete key)\n    pub fn delete(&mut self) {\n        let len = self.buffer.chars().count();\n        if self.cursor < len {\n            let byte_pos = self.cursor_byte_position();\n            let char_len = self.buffer[byte_pos..]\n                .chars()\n                .next()\n                .map_or(0, |c| c.len_utf8());\n            self.buffer.drain(byte_pos..byte_pos + char_len);\n        }\n    }\n\n    /// Delete word before cursor (ctrl+backspace)\n    #[allow(dead_code)]\n    pub fn delete_word(&mut self) {\n        if self.cursor == 0 {\n            return;\n        }\n\n        let chars: Vec<char> = self.buffer.chars().collect();\n        let mut new_cursor = self.cursor;\n\n        // Skip any trailing spaces\n        while new_cursor > 0 && chars[new_cursor - 1].is_whitespace() {\n            new_cursor -= 1;\n        }\n\n        // Delete until start of word\n        while new_cursor > 0 && !chars[new_cursor - 1].is_whitespace() {\n            new_cursor -= 1;\n        }\n\n        // Remove the characters\n        let start_byte = self.char_to_byte_position(new_cursor);\n        let end_byte = self.cursor_byte_position();\n        self.buffer.drain(start_byte..end_byte);\n        self.cursor = new_cursor;\n    }\n\n    /// Clear the entire buffer\n    #[allow(dead_code)]\n    pub fn clear(&mut self) {\n        self.buffer.clear();\n        self.cursor = 0;\n    }\n\n    /// Confirm edit and return the final value\n    pub fn confirm(self) -> String {\n        self.buffer\n    }\n\n    /// Cancel edit and return the original value\n    #[allow(dead_code)]\n    pub fn cancel(self) -> String {\n        self.original\n    }\n\n    /// Check if buffer has been modified\n    #[allow(dead_code)]\n    pub fn is_modified(&self) -> bool {\n        self.buffer != self.original\n    }\n\n    /// Get byte position for current cursor\n    fn cursor_byte_position(&self) -> usize {\n        self.char_to_byte_position(self.cursor)\n    }\n\n    /// Convert character position to byte position\n    fn char_to_byte_position(&self, char_pos: usize) -> usize {\n        self.buffer\n            .char_indices()\n            .nth(char_pos)\n            .map(|(i, _)| i)\n            .unwrap_or(self.buffer.len())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_new_editor() {\n        let edit = InlineEdit::new(\"hello\");\n        assert_eq!(edit.buffer(), \"hello\");\n        assert_eq!(edit.cursor(), 5); // Cursor at end\n    }\n\n    #[test]\n    fn test_insert() {\n        let mut edit = InlineEdit::new(\"hllo\");\n        edit.cursor = 1;\n        edit.insert('e');\n        assert_eq!(edit.buffer(), \"hello\");\n        assert_eq!(edit.cursor(), 2);\n    }\n\n    #[test]\n    fn test_backspace() {\n        let mut edit = InlineEdit::new(\"hello\");\n        edit.backspace();\n        assert_eq!(edit.buffer(), \"hell\");\n        assert_eq!(edit.cursor(), 4);\n    }\n\n    #[test]\n    fn test_delete() {\n        let mut edit = InlineEdit::new(\"hello\");\n        edit.cursor = 0;\n        edit.delete();\n        assert_eq!(edit.buffer(), \"ello\");\n        assert_eq!(edit.cursor(), 0);\n    }\n\n    #[test]\n    fn test_cursor_movement() {\n        let mut edit = InlineEdit::new(\"hello\");\n        assert_eq!(edit.cursor(), 5);\n\n        edit.left();\n        assert_eq!(edit.cursor(), 4);\n\n        edit.home();\n        assert_eq!(edit.cursor(), 0);\n\n        edit.right();\n        assert_eq!(edit.cursor(), 1);\n\n        edit.end();\n        assert_eq!(edit.cursor(), 5);\n    }\n\n    #[test]\n    fn test_unicode() {\n        let mut edit = InlineEdit::new(\"héllo\");\n        assert_eq!(edit.cursor(), 5);\n\n        edit.backspace();\n        assert_eq!(edit.buffer(), \"héll\");\n\n        edit.cursor = 1;\n        edit.delete();\n        assert_eq!(edit.buffer(), \"hll\");\n    }\n\n    #[test]\n    fn test_confirm_cancel() {\n        let edit = InlineEdit::new(\"original\");\n        assert!(!edit.is_modified());\n\n        let mut edit = InlineEdit::new(\"original\");\n        edit.clear();\n        edit.insert_str(\"modified\");\n        assert!(edit.is_modified());\n        assert_eq!(edit.confirm(), \"modified\");\n\n        let mut edit = InlineEdit::new(\"original\");\n        edit.insert_str(\"_modified\");\n        assert_eq!(edit.cancel(), \"original\");\n    }\n\n    #[test]\n    fn test_delete_word() {\n        let mut edit = InlineEdit::new(\"hello world\");\n        edit.delete_word();\n        assert_eq!(edit.buffer(), \"hello \");\n\n        edit.delete_word();\n        assert_eq!(edit.buffer(), \"\");\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/lib.rs",
    "content": "//! Interactive TOML config editor for mise\n//!\n//! This crate provides an interactive editor where the TOML config file itself IS the menu.\n//! Users navigate and edit the actual TOML structure directly.\n\nmod cursor;\nmod document;\nmod editor;\nmod inline_edit;\nmod picker;\nmod providers;\nmod render;\npub mod schema;\n\npub use editor::{ConfigResult, InteractiveConfig};\npub use picker::{PickerItem, PickerState};\npub use providers::{\n    BackendInfo, BackendProvider, EmptyBackendProvider, EmptySettingProvider, EmptyToolProvider,\n    EmptyVersionProvider, SettingInfo, SettingProvider, SettingType, ToolInfo, ToolProvider,\n    VERSION_CUSTOM_MARKER, VersionProvider, version_variants,\n};\n"
  },
  {
    "path": "crates/mise-interactive-config/src/picker.rs",
    "content": "//! Picker: Fuzzy-searchable list picker UI component\n\nuse fuzzy_matcher::FuzzyMatcher;\nuse fuzzy_matcher::skim::SkimMatcherV2;\n\n/// An item that can be displayed in the picker\n#[derive(Debug, Clone)]\npub struct PickerItem {\n    /// Display name (used for matching and display)\n    pub name: String,\n    /// Optional description shown next to the name\n    pub description: Option<String>,\n    /// Optional data payload (e.g., tool backend info)\n    pub data: Option<String>,\n}\n\nimpl PickerItem {\n    /// Create a new picker item\n    pub fn new(name: impl Into<String>) -> Self {\n        Self {\n            name: name.into(),\n            description: None,\n            data: None,\n        }\n    }\n\n    /// Add a description\n    pub fn with_description(mut self, description: impl Into<String>) -> Self {\n        self.description = Some(description.into());\n        self\n    }\n\n    /// Add data payload\n    #[allow(dead_code)]\n    pub fn with_data(mut self, data: impl Into<String>) -> Self {\n        self.data = Some(data.into());\n        self\n    }\n}\n\n/// Filtered item with match score for sorting\n#[derive(Debug, Clone)]\npub struct FilteredItem {\n    /// Index into the original items list\n    pub index: usize,\n    /// Match score (higher is better)\n    pub score: i64,\n    /// Matched positions in the name (for highlighting)\n    pub positions: Vec<usize>,\n}\n\n/// State for the fuzzy picker\npub struct PickerState {\n    /// All available items\n    items: Vec<PickerItem>,\n    /// Filtered items after applying search filter\n    filtered: Vec<FilteredItem>,\n    /// Current filter text\n    filter: String,\n    /// Selected index in the filtered list\n    cursor: usize,\n    /// Scroll offset for the visible window\n    scroll_offset: usize,\n    /// Height of visible area (number of items)\n    visible_height: usize,\n    /// Fuzzy matcher instance (created fresh, not stored for Clone/Debug)\n    matcher: SkimMatcherV2,\n}\n\nimpl std::fmt::Debug for PickerState {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"PickerState\")\n            .field(\"items\", &self.items)\n            .field(\"filtered\", &self.filtered)\n            .field(\"filter\", &self.filter)\n            .field(\"cursor\", &self.cursor)\n            .field(\"scroll_offset\", &self.scroll_offset)\n            .field(\"visible_height\", &self.visible_height)\n            .finish_non_exhaustive()\n    }\n}\n\nimpl Clone for PickerState {\n    fn clone(&self) -> Self {\n        Self {\n            items: self.items.clone(),\n            filtered: self.filtered.clone(),\n            filter: self.filter.clone(),\n            cursor: self.cursor,\n            scroll_offset: self.scroll_offset,\n            visible_height: self.visible_height,\n            matcher: SkimMatcherV2::default(),\n        }\n    }\n}\n\nimpl PickerState {\n    /// Create a new picker with the given items\n    pub fn new(items: Vec<PickerItem>) -> Self {\n        let filtered: Vec<FilteredItem> = items\n            .iter()\n            .enumerate()\n            .map(|(i, _)| FilteredItem {\n                index: i,\n                score: 0,\n                positions: Vec::new(),\n            })\n            .collect();\n\n        Self {\n            items,\n            filtered,\n            filter: String::new(),\n            cursor: 0,\n            scroll_offset: 0,\n            visible_height: 10,\n            matcher: SkimMatcherV2::default(),\n        }\n    }\n\n    /// Set the visible height\n    pub fn with_visible_height(mut self, height: usize) -> Self {\n        self.visible_height = height;\n        self\n    }\n\n    /// Get the current filter text\n    pub fn filter(&self) -> &str {\n        &self.filter\n    }\n\n    /// Get the currently selected item, if any\n    pub fn selected(&self) -> Option<&PickerItem> {\n        self.filtered.get(self.cursor).map(|f| &self.items[f.index])\n    }\n\n    /// Get visible items with their display info\n    pub fn visible_items(&self) -> impl Iterator<Item = VisibleItem<'_>> {\n        let start = self.scroll_offset;\n        let end = (self.scroll_offset + self.visible_height).min(self.filtered.len());\n\n        self.filtered[start..end]\n            .iter()\n            .enumerate()\n            .map(move |(i, filtered)| VisibleItem {\n                item: &self.items[filtered.index],\n                is_selected: start + i == self.cursor,\n                positions: &filtered.positions,\n            })\n    }\n\n    /// Check if there are more items above the visible area\n    pub fn has_more_above(&self) -> bool {\n        self.scroll_offset > 0\n    }\n\n    /// Check if there are more items below the visible area\n    pub fn has_more_below(&self) -> bool {\n        self.scroll_offset + self.visible_height < self.filtered.len()\n    }\n\n    /// Get the total number of filtered items\n    pub fn filtered_count(&self) -> usize {\n        self.filtered.len()\n    }\n\n    /// Get the total number of items\n    #[allow(dead_code)]\n    pub fn total_count(&self) -> usize {\n        self.items.len()\n    }\n\n    /// Add a character to the filter\n    pub fn type_char(&mut self, c: char) {\n        self.filter.push(c);\n        self.apply_filter();\n    }\n\n    /// Remove the last character from the filter\n    pub fn backspace(&mut self) {\n        self.filter.pop();\n        self.apply_filter();\n    }\n\n    /// Clear the filter\n    #[allow(dead_code)]\n    pub fn clear_filter(&mut self) {\n        self.filter.clear();\n        self.apply_filter();\n    }\n\n    /// Move cursor up\n    pub fn move_up(&mut self) {\n        if self.cursor > 0 {\n            self.cursor -= 1;\n            self.ensure_cursor_visible();\n        }\n    }\n\n    /// Move cursor down\n    pub fn move_down(&mut self) {\n        if self.cursor + 1 < self.filtered.len() {\n            self.cursor += 1;\n            self.ensure_cursor_visible();\n        }\n    }\n\n    /// Apply the current filter to the items\n    fn apply_filter(&mut self) {\n        if self.filter.is_empty() {\n            // No filter - show all items in original order\n            self.filtered = self\n                .items\n                .iter()\n                .enumerate()\n                .map(|(i, _)| FilteredItem {\n                    index: i,\n                    score: 0,\n                    positions: Vec::new(),\n                })\n                .collect();\n        } else {\n            // Apply fuzzy matching\n            self.filtered = self\n                .items\n                .iter()\n                .enumerate()\n                .filter_map(|(i, item)| {\n                    // Match against name and description\n                    let name_match = self.matcher.fuzzy_indices(&item.name, &self.filter);\n                    let desc_match = item\n                        .description\n                        .as_ref()\n                        .and_then(|d| self.matcher.fuzzy_match(d, &self.filter));\n\n                    // Take the best score\n                    match (name_match, desc_match) {\n                        (Some((name_score, positions)), Some(desc_score)) => Some(FilteredItem {\n                            index: i,\n                            score: name_score.max(desc_score),\n                            positions,\n                        }),\n                        (Some((score, positions)), None) => Some(FilteredItem {\n                            index: i,\n                            score,\n                            positions,\n                        }),\n                        (None, Some(score)) => Some(FilteredItem {\n                            index: i,\n                            score,\n                            positions: Vec::new(),\n                        }),\n                        (None, None) => None,\n                    }\n                })\n                .collect();\n\n            // Sort by score (highest first)\n            self.filtered.sort_by(|a, b| b.score.cmp(&a.score));\n        }\n\n        // Reset cursor to start\n        self.cursor = 0;\n        self.scroll_offset = 0;\n    }\n\n    /// Ensure the cursor is visible in the viewport\n    fn ensure_cursor_visible(&mut self) {\n        if self.cursor < self.scroll_offset {\n            self.scroll_offset = self.cursor;\n        } else if self.cursor >= self.scroll_offset + self.visible_height {\n            self.scroll_offset = self.cursor.saturating_sub(self.visible_height - 1);\n        }\n    }\n}\n\n/// A visible item in the picker with display metadata\n#[derive(Debug)]\npub struct VisibleItem<'a> {\n    /// The item to display\n    pub item: &'a PickerItem,\n    /// Whether this item is currently selected\n    pub is_selected: bool,\n    /// Character positions to highlight (from fuzzy match)\n    pub positions: &'a [usize],\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_picker_basic() {\n        let items = vec![\n            PickerItem::new(\"node\").with_description(\"Node.js runtime\"),\n            PickerItem::new(\"python\").with_description(\"Python interpreter\"),\n            PickerItem::new(\"ruby\").with_description(\"Ruby interpreter\"),\n        ];\n\n        let picker = PickerState::new(items);\n        assert_eq!(picker.filtered_count(), 3);\n        assert_eq!(picker.selected().unwrap().name, \"node\");\n    }\n\n    #[test]\n    fn test_picker_filter() {\n        let items = vec![\n            PickerItem::new(\"node\"),\n            PickerItem::new(\"python\"),\n            PickerItem::new(\"ruby\"),\n            PickerItem::new(\"nodenv\"),\n        ];\n\n        let mut picker = PickerState::new(items);\n        picker.type_char('n');\n        picker.type_char('o');\n        picker.type_char('d');\n\n        // Should match \"node\" and \"nodenv\"\n        assert_eq!(picker.filtered_count(), 2);\n\n        // \"node\" should rank higher (exact prefix match)\n        let selected = picker.selected().unwrap();\n        assert!(selected.name == \"node\" || selected.name == \"nodenv\");\n    }\n\n    #[test]\n    fn test_picker_navigation() {\n        let items = vec![\n            PickerItem::new(\"a\"),\n            PickerItem::new(\"b\"),\n            PickerItem::new(\"c\"),\n        ];\n\n        let mut picker = PickerState::new(items);\n        assert_eq!(picker.selected().unwrap().name, \"a\");\n\n        picker.move_down();\n        assert_eq!(picker.selected().unwrap().name, \"b\");\n\n        picker.move_down();\n        assert_eq!(picker.selected().unwrap().name, \"c\");\n\n        picker.move_down(); // Should stay at end\n        assert_eq!(picker.selected().unwrap().name, \"c\");\n\n        picker.move_up();\n        assert_eq!(picker.selected().unwrap().name, \"b\");\n    }\n\n    #[test]\n    fn test_picker_backspace() {\n        let items = vec![PickerItem::new(\"node\"), PickerItem::new(\"python\")];\n\n        let mut picker = PickerState::new(items);\n        picker.type_char('p');\n        picker.type_char('y');\n        assert_eq!(picker.filtered_count(), 1);\n\n        picker.backspace();\n        picker.backspace();\n        assert_eq!(picker.filtered_count(), 2);\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/providers.rs",
    "content": "//! Provider traits for injecting external data into the editor\n//!\n//! These traits allow the main mise crate to inject data (like the tool registry)\n//! without creating circular dependencies.\n\nuse async_trait::async_trait;\n\n/// Information about a tool from the registry\n#[derive(Debug, Clone)]\npub struct ToolInfo {\n    /// Tool name (e.g., \"node\", \"python\")\n    pub name: String,\n    /// Short description of the tool\n    pub description: Option<String>,\n    /// Aliases for this tool\n    pub aliases: Vec<String>,\n}\n\n/// Information about a setting\n#[derive(Debug, Clone)]\npub struct SettingInfo {\n    /// Setting name (e.g., \"experimental\", \"jobs\")\n    pub name: String,\n    /// Description of what this setting does\n    pub description: Option<String>,\n    /// Type of the setting (for display and validation)\n    pub setting_type: SettingType,\n    /// Default value as string\n    pub default: Option<String>,\n}\n\n/// Type of a setting value\n#[derive(Debug, Clone, PartialEq)]\npub enum SettingType {\n    /// Boolean (true/false)\n    Bool,\n    /// Integer number\n    Integer,\n    /// String value\n    String,\n    /// Array of strings\n    StringArray,\n    /// Duration (e.g., \"1h\", \"30m\")\n    Duration,\n    /// Path on filesystem\n    Path,\n    /// Enum with specific allowed values\n    Enum(Vec<String>),\n}\n\n/// Information about a backend\n#[derive(Debug, Clone)]\npub struct BackendInfo {\n    /// Backend name (e.g., \"cargo\", \"npm\")\n    pub name: String,\n    /// Description of the backend\n    pub description: Option<String>,\n}\n\n/// Provider for tool information from the registry\npub trait ToolProvider: Send + Sync {\n    /// List all available tools\n    fn list_tools(&self) -> Vec<ToolInfo>;\n}\n\n/// Provider for backend information\npub trait BackendProvider: Send + Sync {\n    /// List all available backends\n    fn list_backends(&self) -> Vec<BackendInfo>;\n}\n\n/// Default empty backend provider\npub struct EmptyBackendProvider;\n\nimpl BackendProvider for EmptyBackendProvider {\n    fn list_backends(&self) -> Vec<BackendInfo> {\n        Vec::new()\n    }\n}\n\n/// Provider for setting information\npub trait SettingProvider: Send + Sync {\n    /// List all available settings\n    fn list_settings(&self) -> Vec<SettingInfo>;\n}\n\n/// Default empty tool provider (no tools available)\npub struct EmptyToolProvider;\n\nimpl ToolProvider for EmptyToolProvider {\n    fn list_tools(&self) -> Vec<ToolInfo> {\n        Vec::new()\n    }\n}\n\n/// Default empty setting provider (no settings available)\npub struct EmptySettingProvider;\n\nimpl SettingProvider for EmptySettingProvider {\n    fn list_settings(&self) -> Vec<SettingInfo> {\n        Vec::new()\n    }\n}\n\n/// Provider for tool version information\n#[async_trait]\npub trait VersionProvider: Send + Sync {\n    /// Get the latest version of a tool\n    ///\n    /// Returns the full version string (e.g., \"3.12.4\" for python)\n    async fn latest_version(&self, tool: &str) -> Option<String>;\n}\n\n/// Default empty version provider\npub struct EmptyVersionProvider;\n\n#[async_trait]\nimpl VersionProvider for EmptyVersionProvider {\n    async fn latest_version(&self, _tool: &str) -> Option<String> {\n        None\n    }\n}\n\n/// Marker for the custom version entry option\npub const VERSION_CUSTOM_MARKER: &str = \"other...\";\n\n/// Generate version variants from a full version string\n///\n/// Given \"3.12.4\", returns [\"latest\", \"3\", \"3.12\", \"3.12.4\", \"other...\"]\npub fn version_variants(full_version: &str) -> Vec<String> {\n    let mut variants = vec![\"latest\".to_string()];\n\n    // Parse version segments\n    let parts: Vec<&str> = full_version.split('.').collect();\n\n    // Build progressive versions\n    let mut current = String::new();\n    for (i, part) in parts.iter().enumerate() {\n        if i > 0 {\n            current.push('.');\n        }\n        current.push_str(part);\n        variants.push(current.clone());\n    }\n\n    // Add custom entry option at the end\n    variants.push(VERSION_CUSTOM_MARKER.to_string());\n\n    variants\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/render.rs",
    "content": "//! Render: Terminal output with colors and scrolling\n\nuse console::{Style, Term};\nuse std::io::{self, Write};\n\nuse crate::cursor::{AddButtonKind, Cursor, CursorTarget};\nuse crate::document::{EntryValue, TomlDocument};\nuse crate::inline_edit::InlineEdit;\nuse crate::picker::PickerState;\n\n/// What kind of picker is currently active\n#[derive(Debug, Clone)]\npub enum PickerKind {\n    /// Picking a tool from registry to add\n    Tool(usize), // section_idx\n    /// Picking a backend type for a tool\n    Backend(usize), // section_idx\n    /// Picking a setting to add\n    Setting(usize), // section_idx\n    /// Picking a hook to add\n    Hook(usize), // section_idx\n    /// Picking a task_config key to add\n    TaskConfig(usize), // section_idx\n    /// Picking a monorepo key to add\n    Monorepo(usize), // section_idx\n    /// Picking a section to add\n    Section,\n}\n\n/// State for version selection mode\n#[derive(Debug, Clone)]\npub struct VersionSelectState {\n    /// Tool name being edited\n    #[allow(dead_code)]\n    pub tool: String,\n    /// Available version variants (e.g., [\"latest\", \"3\", \"3.12\", \"3.12.4\"])\n    pub variants: Vec<String>,\n    /// Currently selected variant index\n    pub selected: usize,\n    /// Section and entry indices\n    pub section_idx: usize,\n    pub entry_idx: usize,\n}\n\nimpl VersionSelectState {\n    /// Create a new version select state\n    pub fn new(tool: String, variants: Vec<String>, section_idx: usize, entry_idx: usize) -> Self {\n        Self {\n            tool,\n            variants,\n            selected: 0,\n            section_idx,\n            entry_idx,\n        }\n    }\n\n    /// Get the currently selected version\n    pub fn current(&self) -> &str {\n        &self.variants[self.selected]\n    }\n\n    /// Move to previous variant (more general)\n    pub fn prev(&mut self) {\n        if self.selected > 0 {\n            self.selected -= 1;\n        }\n    }\n\n    /// Move to next variant (more specific)\n    pub fn next(&mut self) {\n        if self.selected + 1 < self.variants.len() {\n            self.selected += 1;\n        }\n    }\n}\n\n/// State for boolean selection mode\n#[derive(Debug, Clone)]\npub struct BooleanSelectState {\n    /// Key being set\n    pub key: String,\n    /// Currently selected value (true or false)\n    pub selected: bool,\n    /// Section index\n    pub section_idx: usize,\n    /// Entry index (if editing existing) or None (if adding new)\n    pub entry_idx: Option<usize>,\n    /// Field index for inline table fields (if editing a field within an entry)\n    pub field_idx: Option<usize>,\n}\n\nimpl BooleanSelectState {\n    /// Create a new boolean select state for a new entry\n    pub fn new_entry(key: String, section_idx: usize) -> Self {\n        Self {\n            key,\n            selected: true, // Default to true\n            section_idx,\n            entry_idx: None,\n            field_idx: None,\n        }\n    }\n\n    /// Create a new boolean select state for editing existing entry\n    pub fn edit_entry(key: String, current: bool, section_idx: usize, entry_idx: usize) -> Self {\n        Self {\n            key,\n            selected: current,\n            section_idx,\n            entry_idx: Some(entry_idx),\n            field_idx: None,\n        }\n    }\n\n    /// Create a new boolean select state for editing an inline table field\n    pub fn edit_inline_table_field(\n        key: String,\n        current: bool,\n        section_idx: usize,\n        entry_idx: usize,\n        field_idx: usize,\n    ) -> Self {\n        Self {\n            key,\n            selected: current,\n            section_idx,\n            entry_idx: Some(entry_idx),\n            field_idx: Some(field_idx),\n        }\n    }\n\n    /// Toggle the selection\n    pub fn toggle(&mut self) {\n        self.selected = !self.selected;\n    }\n\n    /// Get the current selection as a string\n    pub fn value_str(&self) -> &'static str {\n        if self.selected { \"true\" } else { \"false\" }\n    }\n}\n\n/// Editor mode\n#[derive(Debug, Clone)]\npub enum Mode {\n    /// Navigating the document\n    Navigate,\n    /// Editing a value inline\n    Edit(InlineEdit),\n    /// Entering a new key name\n    NewKey(InlineEdit),\n    /// Renaming a key (section_idx, entry_idx, edit)\n    RenameKey(usize, usize, InlineEdit),\n    /// Confirming quit with unsaved changes\n    ConfirmQuit,\n    /// Picking from a list (tool picker, setting picker)\n    Picker(PickerKind, Box<PickerState>),\n    /// Selecting a version for a tool (arrow left/right to cycle)\n    VersionSelect(VersionSelectState),\n    /// Entering a tool name after selecting a backend (backend_name, section_idx, edit)\n    BackendToolName(String, usize, InlineEdit),\n    /// Selecting a boolean value (true/false)\n    BooleanSelect(BooleanSelectState),\n    /// Loading indicator during async operations\n    Loading(String),\n}\n\n/// Renderer for the interactive config editor\npub struct Renderer {\n    term: Term,\n    /// Number of lines rendered in the last frame\n    last_rendered_lines: usize,\n    /// Viewport scroll offset\n    scroll_offset: usize,\n    /// Visible height (terminal height minus header/footer)\n    visible_height: usize,\n}\n\nimpl Renderer {\n    /// Create a new renderer\n    pub fn new() -> Self {\n        let term = Term::stderr();\n        let (height, _) = term.size();\n        Self {\n            term,\n            last_rendered_lines: 0,\n            scroll_offset: 0,\n            visible_height: height.saturating_sub(6) as usize, // Reserve for header/footer\n        }\n    }\n\n    /// Get terminal reference\n    pub fn term(&self) -> &Term {\n        &self.term\n    }\n\n    /// Clear previously rendered lines\n    pub fn clear(&mut self) -> io::Result<()> {\n        if self.last_rendered_lines > 0 {\n            self.term.clear_last_lines(self.last_rendered_lines)?;\n        }\n        self.last_rendered_lines = 0;\n        Ok(())\n    }\n\n    /// Update viewport height\n    pub fn update_size(&mut self) {\n        let (height, _) = self.term.size();\n        self.visible_height = height.saturating_sub(6) as usize;\n    }\n\n    /// Render the document\n    #[allow(clippy::too_many_arguments)]\n    pub fn render(\n        &mut self,\n        doc: &TomlDocument,\n        cursor: &Cursor,\n        mode: &Mode,\n        title: &str,\n        path: &str,\n        dry_run: bool,\n        can_undo: bool,\n    ) -> io::Result<()> {\n        self.clear()?;\n        self.update_size();\n\n        let mut output = Vec::new();\n\n        // Styles\n        let header_style = Style::new().cyan().bold();\n        let section_style = Style::new().yellow().bold();\n        let key_style = Style::new().green();\n        let value_style = Style::new().white();\n        let cursor_style = Style::new().reverse();\n        let dim_style = Style::new().dim();\n        let add_style = Style::new().blue();\n\n        // Header\n        let dry_run_str = if dry_run { \" [dry-run]\" } else { \"\" };\n        output.push(format!(\"{}\", header_style.apply_to(title)));\n        output.push(format!(\n            \"{}{}\",\n            dim_style.apply_to(path),\n            dim_style.apply_to(dry_run_str)\n        ));\n        output.push(String::new());\n\n        // Build visible items\n        let items = Cursor::build_visible_items(doc);\n        let cursor_idx = cursor.index();\n\n        // Adjust scroll offset to keep cursor visible\n        if cursor_idx < self.scroll_offset {\n            self.scroll_offset = cursor_idx;\n        } else if cursor_idx >= self.scroll_offset + self.visible_height {\n            self.scroll_offset = cursor_idx.saturating_sub(self.visible_height - 1);\n        }\n\n        // Render items\n        let visible_start = self.scroll_offset;\n        let visible_end = (self.scroll_offset + self.visible_height).min(items.len());\n\n        for (idx, target) in items\n            .iter()\n            .enumerate()\n            .skip(visible_start)\n            .take(visible_end - visible_start)\n        {\n            let is_cursor = idx == cursor_idx;\n            let line = self.render_item(\n                doc,\n                target,\n                is_cursor,\n                mode,\n                &section_style,\n                &key_style,\n                &value_style,\n                &cursor_style,\n                &dim_style,\n                &add_style,\n            );\n            output.push(line);\n        }\n\n        // Scroll indicators\n        if self.scroll_offset > 0 {\n            output.insert(3, format!(\"{}\", dim_style.apply_to(\"  ↑ more above\")));\n        }\n        if visible_end < items.len() {\n            output.push(format!(\"{}\", dim_style.apply_to(\"  ↓ more below\")));\n        }\n\n        // Footer\n        output.push(String::new());\n        let footer: String = match mode {\n            Mode::Navigate => {\n                // Build context-sensitive footer based on cursor position\n                let target = cursor.target(doc);\n\n                // Determine Enter action based on target\n                let enter_action = match &target {\n                    Some(CursorTarget::SectionHeader(idx)) => {\n                        if doc.sections[*idx].expanded {\n                            \"Enter collapse\"\n                        } else {\n                            \"Enter expand\"\n                        }\n                    }\n                    Some(CursorTarget::Entry(section_idx, entry_idx)) => {\n                        let entry = &doc.sections[*section_idx].entries[*entry_idx];\n                        match &entry.value {\n                            EntryValue::Simple(_) => \"Enter edit\",\n                            _ if entry.expanded => \"Enter collapse\",\n                            _ => \"Enter expand\",\n                        }\n                    }\n                    Some(CursorTarget::ArrayItem(_, _, _))\n                    | Some(CursorTarget::InlineTableField(_, _, _)) => \"Enter edit\",\n                    Some(CursorTarget::AddButton(_)) => \"Enter add\",\n                    _ => \"Enter\",\n                };\n\n                // Check if \"o options\" is available (Entry with Simple value)\n                let can_add_options = matches!(&target, Some(CursorTarget::Entry(section_idx, entry_idx))\n                    if matches!(doc.sections[*section_idx].entries[*entry_idx].value, EntryValue::Simple(_)));\n\n                // Check if \"backspace remove\" is available\n                let can_remove = matches!(\n                    &target,\n                    Some(CursorTarget::Entry(_, _))\n                        | Some(CursorTarget::ArrayItem(_, _, _))\n                        | Some(CursorTarget::InlineTableField(_, _, _))\n                        | Some(CursorTarget::SectionHeader(_))\n                );\n\n                // Check if \"r rename\" is available (Entry or InlineTableField)\n                let can_rename = matches!(\n                    &target,\n                    Some(CursorTarget::Entry(_, _)) | Some(CursorTarget::InlineTableField(_, _, _))\n                );\n\n                let mut parts = vec![\"↑/↓/←/→ navigate\", enter_action];\n                if can_add_options {\n                    parts.push(\"o options\");\n                }\n                if can_rename {\n                    parts.push(\"r rename\");\n                }\n                if can_remove {\n                    parts.push(\"backspace remove\");\n                }\n                if can_undo {\n                    parts.push(\"u undo\");\n                }\n                if !dry_run {\n                    parts.push(\"s save\");\n                }\n                parts.push(if dry_run { \"q done\" } else { \"q quit\" });\n                parts.join(\" • \")\n            }\n            Mode::Edit(_)\n            | Mode::NewKey(_)\n            | Mode::BackendToolName(_, _, _)\n            | Mode::RenameKey(_, _, _) => \"Enter confirm • Esc cancel • ←/→ cursor\".to_string(),\n            Mode::ConfirmQuit => \"Unsaved changes. Save? y/n/Esc\".to_string(),\n            Mode::Picker(_, _) => {\n                \"Type to filter • ↑/↓ select • Enter add • Esc cancel\".to_string()\n            }\n            Mode::VersionSelect(_) => \"←/→ select version • Enter confirm • Esc cancel\".to_string(),\n            Mode::BooleanSelect(_) => \"←/→ or t/f toggle • Enter confirm • Esc cancel\".to_string(),\n            Mode::Loading(_) => \"Please wait...\".to_string(),\n        };\n        output.push(format!(\"{}\", dim_style.apply_to(&footer)));\n\n        // Write output\n        for line in &output {\n            writeln!(self.term, \"{}\", line)?;\n        }\n        self.last_rendered_lines = output.len();\n\n        self.term.flush()?;\n        Ok(())\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    fn render_item(\n        &self,\n        doc: &TomlDocument,\n        target: &CursorTarget,\n        is_cursor: bool,\n        mode: &Mode,\n        section_style: &Style,\n        key_style: &Style,\n        value_style: &Style,\n        cursor_style: &Style,\n        dim_style: &Style,\n        add_style: &Style,\n    ) -> String {\n        match target {\n            CursorTarget::Comment(text) => {\n                // Comments are rendered in dim green style (not selectable)\n                let comment_style = Style::new().dim().green();\n                format!(\"{}\", comment_style.apply_to(text))\n            }\n\n            CursorTarget::SectionHeader(section_idx) => {\n                let section = &doc.sections[*section_idx];\n                let arrow = if section.expanded { \"▼\" } else { \"▶\" };\n                let count = if section.entries.is_empty() {\n                    String::new()\n                } else {\n                    format!(\" ({})\", section.entries.len())\n                };\n                // Display \"(root)\" for the root section (empty name)\n                let section_label = if section.name.is_empty() {\n                    \"(root)\".to_string()\n                } else {\n                    format!(\"[{}]\", section.name)\n                };\n                let text = format!(\"{} {}{}\", arrow, section_label, count);\n                if is_cursor {\n                    format!(\"{}\", cursor_style.apply_to(&text))\n                } else {\n                    format!(\"{}\", section_style.apply_to(&text))\n                }\n            }\n\n            CursorTarget::Entry(section_idx, entry_idx) => {\n                let entry = &doc.sections[*section_idx].entries[*entry_idx];\n\n                // Check if we're editing this entry\n                if is_cursor {\n                    if let Mode::Edit(edit) = mode {\n                        // Render with inline edit cursor\n                        let key_part = format!(\"    {} = \", key_style.apply_to(&entry.key));\n                        let cursor_pos = edit.cursor();\n                        let buffer = edit.buffer();\n\n                        // Split buffer at cursor position\n                        let chars: Vec<char> = buffer.chars().collect();\n                        let before: String = chars[..cursor_pos].iter().collect();\n                        let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                        let after: String = chars\n                            .get(cursor_pos + 1..)\n                            .map(|c| c.iter().collect())\n                            .unwrap_or_default();\n\n                        return format!(\n                            \"{}\\\"{}{}{}\\\"\",\n                            key_part,\n                            value_style.apply_to(&before),\n                            cursor_style.apply_to(at_cursor),\n                            value_style.apply_to(&after)\n                        );\n                    }\n\n                    // Check if we're renaming the key\n                    if let Mode::RenameKey(s_idx, e_idx, edit) = mode\n                        && *s_idx == *section_idx\n                        && *e_idx == *entry_idx\n                    {\n                        let cursor_pos = edit.cursor();\n                        let buffer = edit.buffer();\n                        let chars: Vec<char> = buffer.chars().collect();\n                        let before: String = chars[..cursor_pos].iter().collect();\n                        let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                        let after: String = chars\n                            .get(cursor_pos + 1..)\n                            .map(|c| c.iter().collect())\n                            .unwrap_or_default();\n\n                        let value_display = match &entry.value {\n                            EntryValue::Simple(s) => format!(\"\\\"{}\\\"\", s),\n                            EntryValue::Array(_) => \"[...]\".to_string(),\n                            EntryValue::InlineTable(_) => \"{...}\".to_string(),\n                        };\n\n                        return format!(\n                            \"    {}{}{} = {}\",\n                            key_style.apply_to(&before),\n                            cursor_style.apply_to(at_cursor),\n                            key_style.apply_to(&after),\n                            value_style.apply_to(&value_display)\n                        );\n                    }\n\n                    // Check if we're selecting a version\n                    if let Mode::VersionSelect(vs) = mode\n                        && vs.section_idx == *section_idx\n                        && vs.entry_idx == *entry_idx\n                    {\n                        let key_part = format!(\"    {} = \", key_style.apply_to(&entry.key));\n                        // Show all variants with current one highlighted\n                        let variants_display: Vec<String> = vs\n                            .variants\n                            .iter()\n                            .enumerate()\n                            .map(|(i, v)| {\n                                if i == vs.selected {\n                                    format!(\"{}\", cursor_style.apply_to(format!(\"[{}]\", v)))\n                                } else {\n                                    format!(\"{}\", dim_style.apply_to(v))\n                                }\n                            })\n                            .collect();\n                        return format!(\"{}{}\", key_part, variants_display.join(\"  \"));\n                    }\n\n                    // Check if we're selecting a boolean (for existing entries being edited)\n                    if let Mode::BooleanSelect(bs) = mode\n                        && let Some(editing_entry_idx) = bs.entry_idx\n                        && bs.section_idx == *section_idx\n                        && editing_entry_idx == *entry_idx\n                    {\n                        let key_part = format!(\"    {} = \", key_style.apply_to(&entry.key));\n                        let true_display = if bs.selected {\n                            format!(\"{}\", cursor_style.apply_to(\"[true]\"))\n                        } else {\n                            format!(\"{}\", dim_style.apply_to(\"true\"))\n                        };\n                        let false_display = if !bs.selected {\n                            format!(\"{}\", cursor_style.apply_to(\"[false]\"))\n                        } else {\n                            format!(\"{}\", dim_style.apply_to(\"false\"))\n                        };\n                        return format!(\"{}{}  {}\", key_part, true_display, false_display);\n                    }\n                }\n\n                let value_display = match &entry.value {\n                    EntryValue::Simple(s) => {\n                        // Don't quote booleans\n                        if s == \"true\" || s == \"false\" {\n                            s.clone()\n                        } else {\n                            format!(\"\\\"{}\\\"\", s)\n                        }\n                    }\n                    EntryValue::Array(_) if entry.expanded => \"▼\".to_string(),\n                    EntryValue::Array(items) => {\n                        let preview: Vec<_> =\n                            items.iter().take(3).map(|s| format!(\"\\\"{}\\\"\", s)).collect();\n                        let suffix = if items.len() > 3 { \", ...\" } else { \"\" };\n                        format!(\"▶ [{}{}]\", preview.join(\", \"), suffix)\n                    }\n                    EntryValue::InlineTable(_) if entry.expanded => \"▼\".to_string(),\n                    EntryValue::InlineTable(pairs) => {\n                        let preview: Vec<_> = pairs\n                            .iter()\n                            .take(2)\n                            .map(|(k, v)| {\n                                // Don't quote booleans in inline table preview\n                                if v == \"true\" || v == \"false\" {\n                                    format!(\"{} = {}\", k, v)\n                                } else {\n                                    format!(\"{} = \\\"{}\\\"\", k, v)\n                                }\n                            })\n                            .collect();\n                        let suffix = if pairs.len() > 2 { \", ...\" } else { \"\" };\n                        format!(\"▶ {{ {}{} }}\", preview.join(\", \"), suffix)\n                    }\n                };\n\n                if is_cursor {\n                    format!(\n                        \"  {} {} = {}\",\n                        cursor_style.apply_to(\">\"),\n                        key_style.apply_to(&entry.key),\n                        value_style.apply_to(&value_display)\n                    )\n                } else {\n                    format!(\n                        \"    {} = {}\",\n                        key_style.apply_to(&entry.key),\n                        value_style.apply_to(&value_display)\n                    )\n                }\n            }\n\n            CursorTarget::ArrayItem(section_idx, entry_idx, array_idx) => {\n                let entry = &doc.sections[*section_idx].entries[*entry_idx];\n                if let EntryValue::Array(items) = &entry.value {\n                    let value = &items[*array_idx];\n\n                    // Check if we're editing this item\n                    if is_cursor && let Mode::Edit(edit) = mode {\n                        let cursor_pos = edit.cursor();\n                        let buffer = edit.buffer();\n                        let chars: Vec<char> = buffer.chars().collect();\n                        let before: String = chars[..cursor_pos].iter().collect();\n                        let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                        let after: String = chars\n                            .get(cursor_pos + 1..)\n                            .map(|c| c.iter().collect())\n                            .unwrap_or_default();\n\n                        return format!(\n                            \"        \\\"{}{}{}\\\"\",\n                            value_style.apply_to(&before),\n                            cursor_style.apply_to(at_cursor),\n                            value_style.apply_to(&after)\n                        );\n                    }\n\n                    let text = format!(\"\\\"{}\\\"\", value);\n                    if is_cursor {\n                        format!(\n                            \"      {} {}\",\n                            cursor_style.apply_to(\">\"),\n                            value_style.apply_to(&text)\n                        )\n                    } else {\n                        format!(\"        {}\", dim_style.apply_to(&text))\n                    }\n                } else {\n                    String::new()\n                }\n            }\n\n            CursorTarget::InlineTableField(section_idx, entry_idx, field_idx) => {\n                let entry = &doc.sections[*section_idx].entries[*entry_idx];\n                if let EntryValue::InlineTable(pairs) = &entry.value {\n                    let (key, value) = &pairs[*field_idx];\n                    let is_boolean = value == \"true\" || value == \"false\";\n\n                    // Check if we're editing this field with boolean selector\n                    if is_cursor\n                        && let Mode::BooleanSelect(bs) = mode\n                        && let Some(f_idx) = bs.field_idx\n                        && bs.section_idx == *section_idx\n                        && bs.entry_idx == Some(*entry_idx)\n                        && f_idx == *field_idx\n                    {\n                        let key_part = format!(\"        {} = \", key_style.apply_to(key));\n                        let true_display = if bs.selected {\n                            format!(\"{}\", cursor_style.apply_to(\"[true]\"))\n                        } else {\n                            format!(\"{}\", dim_style.apply_to(\"true\"))\n                        };\n                        let false_display = if !bs.selected {\n                            format!(\"{}\", cursor_style.apply_to(\"[false]\"))\n                        } else {\n                            format!(\"{}\", dim_style.apply_to(\"false\"))\n                        };\n                        return format!(\"{}{}  {}\", key_part, true_display, false_display);\n                    }\n\n                    // Check if we're editing this field with text editor\n                    if is_cursor && let Mode::Edit(edit) = mode {\n                        let prefix = format!(\"        {} = \", key_style.apply_to(key));\n                        let cursor_pos = edit.cursor();\n                        let buffer = edit.buffer();\n                        let chars: Vec<char> = buffer.chars().collect();\n                        let before: String = chars[..cursor_pos].iter().collect();\n                        let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                        let after: String = chars\n                            .get(cursor_pos + 1..)\n                            .map(|c| c.iter().collect())\n                            .unwrap_or_default();\n\n                        return format!(\n                            \"{}\\\"{}{}{}\\\"\",\n                            prefix,\n                            value_style.apply_to(&before),\n                            cursor_style.apply_to(at_cursor),\n                            value_style.apply_to(&after)\n                        );\n                    }\n\n                    // Display value - don't quote booleans\n                    let value_display = if is_boolean {\n                        value.clone()\n                    } else {\n                        format!(\"\\\"{}\\\"\", value)\n                    };\n                    let text = format!(\"{} = {}\", key, value_display);\n                    if is_cursor {\n                        format!(\n                            \"      {} {}\",\n                            cursor_style.apply_to(\">\"),\n                            value_style.apply_to(&text)\n                        )\n                    } else {\n                        format!(\n                            \"        {} = {}\",\n                            key_style.apply_to(key),\n                            value_style.apply_to(&value_display)\n                        )\n                    }\n                } else {\n                    String::new()\n                }\n            }\n\n            CursorTarget::AddButton(kind) => {\n                let label = match kind {\n                    AddButtonKind::Section => \"[+ Add section]\",\n                    AddButtonKind::Entry(_) => \"    [+ Add entry]\",\n                    AddButtonKind::ToolRegistry(_) => \"    [+ Add tool from registry]\",\n                    AddButtonKind::ToolBackend(_) => \"    [+ Add tool from backend]\",\n                    AddButtonKind::EnvPath(_) => \"    [+ Add PATH]\",\n                    AddButtonKind::EnvDotenv(_) => \"    [+ Load .env]\",\n                    AddButtonKind::EnvSource(_) => \"    [+ Source script]\",\n                    AddButtonKind::EnvVariable(_) => \"    [+ Add variable]\",\n                    AddButtonKind::Task(_) => \"    [+ Add task]\",\n                    AddButtonKind::Prepare(_) => \"    [+ Add prepare provider]\",\n                    AddButtonKind::Setting(_) => \"    [+ Add setting]\",\n                    AddButtonKind::Hook(_) => \"    [+ Add hook]\",\n                    AddButtonKind::TaskConfig(_) => \"    [+ Add task config]\",\n                    AddButtonKind::Monorepo(_) => \"    [+ Add monorepo config]\",\n                    AddButtonKind::ArrayItem(_, _) => \"        [+ Add item]\",\n                    AddButtonKind::InlineTableField(_, _) => \"        [+ Add field]\",\n                };\n\n                // Check if we're entering a backend tool name (shows as \"backend:_\")\n                if is_cursor && let Mode::BackendToolName(backend_name, _, edit) = mode {\n                    let cursor_pos = edit.cursor();\n                    let buffer = edit.buffer();\n                    let chars: Vec<char> = buffer.chars().collect();\n                    let before: String = chars[..cursor_pos].iter().collect();\n                    let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                    let after: String = chars\n                        .get(cursor_pos + 1..)\n                        .map(|c| c.iter().collect())\n                        .unwrap_or_default();\n\n                    return format!(\n                        \"    {}:{}{}{}\",\n                        key_style.apply_to(backend_name),\n                        value_style.apply_to(&before),\n                        cursor_style.apply_to(at_cursor),\n                        value_style.apply_to(&after)\n                    );\n                }\n\n                // Check if we're entering a new key\n                if is_cursor && let Mode::NewKey(edit) = mode {\n                    let prefix = match kind {\n                        AddButtonKind::Entry(_)\n                        | AddButtonKind::ToolRegistry(_)\n                        | AddButtonKind::ToolBackend(_)\n                        | AddButtonKind::EnvPath(_)\n                        | AddButtonKind::EnvDotenv(_)\n                        | AddButtonKind::EnvSource(_)\n                        | AddButtonKind::EnvVariable(_)\n                        | AddButtonKind::Task(_)\n                        | AddButtonKind::Prepare(_)\n                        | AddButtonKind::Setting(_)\n                        | AddButtonKind::Hook(_)\n                        | AddButtonKind::TaskConfig(_)\n                        | AddButtonKind::Monorepo(_) => \"    \",\n                        AddButtonKind::ArrayItem(_, _) | AddButtonKind::InlineTableField(_, _) => {\n                            \"        \"\n                        }\n                        AddButtonKind::Section => \"\",\n                    };\n                    let prompt = match kind {\n                        AddButtonKind::Section => \"Section name: \",\n                        AddButtonKind::Entry(_) => \"Key: \",\n                        AddButtonKind::ToolRegistry(_) => \"Tool: \",\n                        AddButtonKind::ToolBackend(_) => \"Tool (e.g. cargo:ripgrep): \",\n                        AddButtonKind::EnvPath(_) => \"Path: \",\n                        AddButtonKind::EnvDotenv(_) => \"File: \",\n                        AddButtonKind::EnvSource(_) => \"Script: \",\n                        AddButtonKind::EnvVariable(_) => \"KEY=value: \",\n                        AddButtonKind::Task(_) => \"Task name: \",\n                        AddButtonKind::Prepare(_) => \"Provider name: \",\n                        AddButtonKind::Setting(_) => \"Setting: \",\n                        AddButtonKind::Hook(_) => \"Hook name: \",\n                        AddButtonKind::TaskConfig(_) => \"Config key: \",\n                        AddButtonKind::Monorepo(_) => \"Config key: \",\n                        AddButtonKind::ArrayItem(_, _) => \"Value: \",\n                        AddButtonKind::InlineTableField(_, _) => \"Field name: \",\n                    };\n                    let cursor_pos = edit.cursor();\n                    let buffer = edit.buffer();\n                    let chars: Vec<char> = buffer.chars().collect();\n                    let before: String = chars[..cursor_pos].iter().collect();\n                    let at_cursor = chars.get(cursor_pos).copied().unwrap_or(' ');\n                    let after: String = chars\n                        .get(cursor_pos + 1..)\n                        .map(|c| c.iter().collect())\n                        .unwrap_or_default();\n\n                    return format!(\n                        \"{}{}{}{}{}\",\n                        prefix,\n                        dim_style.apply_to(prompt),\n                        value_style.apply_to(&before),\n                        cursor_style.apply_to(at_cursor),\n                        value_style.apply_to(&after)\n                    );\n                }\n\n                // Check if we're showing a boolean picker for a new entry\n                if is_cursor\n                    && let Mode::BooleanSelect(bs) = mode\n                    && bs.entry_idx.is_none()\n                {\n                    // New entry - show key = [true] false or key = true [false]\n                    let (true_display, false_display) = if bs.selected {\n                        (\n                            cursor_style.apply_to(\"[true]\").to_string(),\n                            dim_style.apply_to(\"false\").to_string(),\n                        )\n                    } else {\n                        (\n                            dim_style.apply_to(\"true\").to_string(),\n                            cursor_style.apply_to(\"[false]\").to_string(),\n                        )\n                    };\n                    return format!(\n                        \"    {} = {}  {}\",\n                        key_style.apply_to(&bs.key),\n                        true_display,\n                        false_display\n                    );\n                }\n\n                if is_cursor {\n                    format!(\"{}\", cursor_style.apply_to(label))\n                } else {\n                    format!(\"{}\", add_style.apply_to(label))\n                }\n            }\n        }\n    }\n\n    /// Show a message briefly\n    pub fn flash_message(&mut self, message: &str) -> io::Result<()> {\n        let style = Style::new().yellow().bold();\n        writeln!(self.term, \"{}\", style.apply_to(message))?;\n        self.term.flush()?;\n        std::thread::sleep(std::time::Duration::from_millis(500));\n        self.term.clear_last_lines(1)?;\n        Ok(())\n    }\n\n    /// Render a loading indicator\n    pub fn render_loading(&mut self, message: &str, title: &str, path: &str) -> io::Result<()> {\n        self.clear()?;\n\n        let mut output = Vec::new();\n\n        // Styles\n        let header_style = Style::new().cyan().bold();\n        let dim_style = Style::new().dim();\n        let loading_style = Style::new().yellow();\n\n        // Header\n        output.push(format!(\"{}\", header_style.apply_to(title)));\n        output.push(format!(\"{}\", dim_style.apply_to(path)));\n        output.push(String::new());\n\n        // Loading message with spinner character\n        output.push(format!(\"{} {}\", loading_style.apply_to(\"⠋\"), message));\n        output.push(String::new());\n\n        // Footer hint\n        output.push(format!(\n            \"{}\",\n            dim_style.apply_to(\"Fetching version information...\")\n        ));\n\n        // Write output\n        for line in &output {\n            writeln!(self.term, \"{}\", line)?;\n        }\n        self.last_rendered_lines = output.len();\n\n        self.term.flush()?;\n        Ok(())\n    }\n\n    /// Render the picker overlay\n    pub fn render_picker(\n        &mut self,\n        picker: &PickerState,\n        kind: &PickerKind,\n        title: &str,\n    ) -> io::Result<()> {\n        self.clear()?;\n        self.update_size();\n\n        let mut output = Vec::new();\n\n        // Styles\n        let header_style = Style::new().cyan().bold();\n        let cursor_style = Style::new().reverse();\n        let dim_style = Style::new().dim();\n        let name_style = Style::new().green();\n        let desc_style = Style::new().white().dim();\n\n        // Header with picker type\n        let picker_title = match kind {\n            PickerKind::Tool(_) => \"Add Tool from Registry\",\n            PickerKind::Backend(_) => \"Select Backend\",\n            PickerKind::Setting(_) => \"Add Setting\",\n            PickerKind::Hook(_) => \"Add Hook\",\n            PickerKind::TaskConfig(_) => \"Add Task Config\",\n            PickerKind::Monorepo(_) => \"Add Monorepo Config\",\n            PickerKind::Section => \"Add Section\",\n        };\n        output.push(format!(\"{}\", header_style.apply_to(picker_title)));\n        output.push(format!(\"{}\", dim_style.apply_to(title)));\n        output.push(String::new());\n\n        // Filter input line\n        let filter = picker.filter();\n        let filter_display = if filter.is_empty() {\n            format!(\n                \"{}{}\",\n                dim_style.apply_to(\"Filter: \"),\n                cursor_style.apply_to(\" \")\n            )\n        } else {\n            format!(\n                \"{}{}{}\",\n                dim_style.apply_to(\"Filter: \"),\n                filter,\n                cursor_style.apply_to(\" \")\n            )\n        };\n        output.push(filter_display);\n        output.push(String::new());\n\n        // Scroll indicator above\n        if picker.has_more_above() {\n            output.push(format!(\"{}\", dim_style.apply_to(\"  ↑ more above\")));\n        }\n\n        // Render visible items\n        for visible in picker.visible_items() {\n            let name = &visible.item.name;\n            let desc = visible.item.description.as_deref().unwrap_or(\"\");\n\n            // Truncate description if too long\n            let (_, width) = self.term.size();\n            let max_desc_len = width.saturating_sub(name.len() as u16 + 10) as usize;\n            let truncated_desc = if desc.len() > max_desc_len && max_desc_len > 3 {\n                format!(\"{}...\", &desc[..max_desc_len.saturating_sub(3)])\n            } else {\n                desc.to_string()\n            };\n\n            let line = if visible.is_selected {\n                format!(\n                    \"{} {} {}\",\n                    cursor_style.apply_to(\">\"),\n                    name_style.apply_to(name),\n                    desc_style.apply_to(&truncated_desc)\n                )\n            } else {\n                format!(\n                    \"  {} {}\",\n                    name_style.apply_to(name),\n                    desc_style.apply_to(&truncated_desc)\n                )\n            };\n            output.push(line);\n        }\n\n        // Scroll indicator below\n        if picker.has_more_below() {\n            output.push(format!(\"{}\", dim_style.apply_to(\"  ↓ more below\")));\n        }\n\n        // Footer\n        output.push(String::new());\n        let footer = \"Type to filter • ↑/↓ select • Enter add • Esc cancel\";\n        output.push(format!(\"{}\", dim_style.apply_to(footer)));\n\n        // Write output\n        for line in &output {\n            writeln!(self.term, \"{}\", line)?;\n        }\n        self.last_rendered_lines = output.len();\n\n        self.term.flush()?;\n        Ok(())\n    }\n}\n\nimpl Default for Renderer {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n"
  },
  {
    "path": "crates/mise-interactive-config/src/schema.rs",
    "content": "//! Schema information generated from mise.json at build time\n\n// Include the generated schema sections, entries, settings, and hooks\ninclude!(concat!(env!(\"OUT_DIR\"), \"/schema_sections.rs\"));\n\n/// Check if a section name is valid according to the schema\npub fn is_valid_section(name: &str) -> bool {\n    SCHEMA_SECTIONS.iter().any(|(n, _)| *n == name)\n}\n\n/// Get the description for a section, if it exists\npub fn section_description(name: &str) -> Option<&'static str> {\n    SCHEMA_SECTIONS\n        .iter()\n        .find(|(n, _)| *n == name)\n        .map(|(_, desc)| *desc)\n}\n\n/// Check if a top-level entry name is valid according to the schema\npub fn is_valid_entry(name: &str) -> bool {\n    SCHEMA_ENTRIES.iter().any(|(n, _, _)| *n == name)\n}\n\n/// Get the description for a top-level entry, if it exists\npub fn entry_description(name: &str) -> Option<&'static str> {\n    SCHEMA_ENTRIES\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, desc, _)| *desc)\n}\n\n/// Get the type for a top-level entry, if it exists\npub fn entry_type(name: &str) -> Option<SchemaType> {\n    SCHEMA_ENTRIES\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, _, t)| *t)\n}\n\n/// Check if a setting key is valid according to the schema\npub fn is_valid_setting(name: &str) -> bool {\n    SCHEMA_SETTINGS.iter().any(|(n, _, _)| *n == name)\n}\n\n/// Get the description for a setting key, if it exists\npub fn setting_description(name: &str) -> Option<&'static str> {\n    SCHEMA_SETTINGS\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, desc, _)| *desc)\n}\n\n/// Get the type for a setting key, if it exists\npub fn setting_type(name: &str) -> Option<SchemaType> {\n    SCHEMA_SETTINGS\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, _, t)| *t)\n}\n\n/// Check if a hook name is a common/known hook\npub fn is_common_hook(name: &str) -> bool {\n    SCHEMA_HOOKS.iter().any(|(n, _)| *n == name)\n}\n\n/// Get the description for a hook, if it exists\npub fn hook_description(name: &str) -> Option<&'static str> {\n    SCHEMA_HOOKS\n        .iter()\n        .find(|(n, _)| *n == name)\n        .map(|(_, desc)| *desc)\n}\n\n/// Check if a task_config key is valid according to the schema\npub fn is_valid_task_config(name: &str) -> bool {\n    SCHEMA_TASK_CONFIG.iter().any(|(n, _, _)| *n == name)\n}\n\n/// Get the description for a task_config key, if it exists\npub fn task_config_description(name: &str) -> Option<&'static str> {\n    SCHEMA_TASK_CONFIG\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, desc, _)| *desc)\n}\n\n/// Get the type for a task_config key, if it exists\npub fn task_config_type(name: &str) -> Option<SchemaType> {\n    SCHEMA_TASK_CONFIG\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, _, t)| *t)\n}\n\n/// Check if a monorepo key is valid according to the schema\npub fn is_valid_monorepo(name: &str) -> bool {\n    SCHEMA_MONOREPO.iter().any(|(n, _, _)| *n == name)\n}\n\n/// Get the description for a monorepo key, if it exists\npub fn monorepo_description(name: &str) -> Option<&'static str> {\n    SCHEMA_MONOREPO\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, desc, _)| *desc)\n}\n\n/// Get the type for a monorepo key, if it exists\npub fn monorepo_type(name: &str) -> Option<SchemaType> {\n    SCHEMA_MONOREPO\n        .iter()\n        .find(|(n, _, _)| *n == name)\n        .map(|(_, _, t)| *t)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_valid_sections() {\n        assert!(is_valid_section(\"tools\"));\n        assert!(is_valid_section(\"env\"));\n        assert!(is_valid_section(\"tasks\"));\n        assert!(is_valid_section(\"settings\"));\n        assert!(!is_valid_section(\"invalid_section\"));\n        // min_version should NOT be a section\n        assert!(!is_valid_section(\"min_version\"));\n    }\n\n    #[test]\n    fn test_section_descriptions() {\n        assert!(section_description(\"tools\").is_some());\n        assert!(section_description(\"invalid\").is_none());\n    }\n\n    #[test]\n    fn test_valid_entries() {\n        // min_version should be an entry, not a section\n        assert!(is_valid_entry(\"min_version\"));\n        // tools should NOT be an entry\n        assert!(!is_valid_entry(\"tools\"));\n    }\n\n    #[test]\n    fn test_entry_descriptions() {\n        assert!(entry_description(\"min_version\").is_some());\n        assert!(entry_description(\"invalid\").is_none());\n    }\n\n    #[test]\n    fn test_entry_types() {\n        // redactions is an array\n        assert_eq!(entry_type(\"redactions\"), Some(SchemaType::Array));\n        // experimental_monorepo_root is a boolean\n        assert_eq!(\n            entry_type(\"experimental_monorepo_root\"),\n            Some(SchemaType::Boolean)\n        );\n    }\n\n    #[test]\n    fn test_valid_settings() {\n        // Common settings should be valid\n        assert!(is_valid_setting(\"experimental\"));\n        assert!(is_valid_setting(\"color\"));\n        // Nested settings should use dot notation\n        assert!(is_valid_setting(\"aqua.baked_registry\"));\n        // Invalid settings\n        assert!(!is_valid_setting(\"invalid_setting\"));\n    }\n\n    #[test]\n    fn test_setting_descriptions() {\n        assert!(setting_description(\"experimental\").is_some());\n        assert!(setting_description(\"invalid\").is_none());\n    }\n\n    #[test]\n    fn test_setting_types() {\n        // quiet is a boolean\n        assert_eq!(setting_type(\"quiet\"), Some(SchemaType::Boolean));\n        // jobs is a number\n        assert_eq!(setting_type(\"jobs\"), Some(SchemaType::Number));\n    }\n\n    #[test]\n    fn test_common_hooks() {\n        assert!(is_common_hook(\"enter\"));\n        assert!(is_common_hook(\"leave\"));\n        assert!(is_common_hook(\"cd\"));\n        // Custom hooks are allowed but not \"common\"\n        assert!(!is_common_hook(\"my_custom_hook\"));\n    }\n\n    #[test]\n    fn test_hook_descriptions() {\n        assert!(hook_description(\"enter\").is_some());\n        assert!(hook_description(\"invalid\").is_none());\n    }\n\n    #[test]\n    fn test_valid_task_config() {\n        assert!(is_valid_task_config(\"dir\"));\n        assert!(is_valid_task_config(\"includes\"));\n        assert!(!is_valid_task_config(\"invalid\"));\n    }\n\n    #[test]\n    fn test_task_config_descriptions() {\n        assert!(task_config_description(\"dir\").is_some());\n        assert!(task_config_description(\"invalid\").is_none());\n    }\n\n    #[test]\n    fn test_valid_monorepo() {\n        assert!(is_valid_monorepo(\"config_roots\"));\n        assert!(!is_valid_monorepo(\"invalid\"));\n    }\n\n    #[test]\n    fn test_monorepo_descriptions() {\n        assert!(monorepo_description(\"config_roots\").is_some());\n        assert!(monorepo_description(\"invalid\").is_none());\n    }\n}\n"
  },
  {
    "path": "crates/mise-shim/Cargo.toml",
    "content": "[package]\nname = \"mise-shim\"\nversion = \"2026.2.5\"\nedition = \"2024\"\nlicense = \"MIT\"\ndescription = \"Native executable shim for mise\"\nhomepage = \"https://github.com/jdx/mise\"\nrepository = \"https://github.com/jdx/mise\"\n\n[[bin]]\nname = \"mise-shim\"\npath = \"src/main.rs\"\n\n[dependencies]\n# zero external dependencies — only std\n"
  },
  {
    "path": "crates/mise-shim/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2026 Jeff Dickey\nCopyright (c) 2026 Jan Killian\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "crates/mise-shim/src/main.rs",
    "content": "// Based on https://github.com/iki/mise-shim by Jan Killian (MIT License)\n\nuse std::env;\nuse std::process::{Command, exit};\n\nfn main() {\n    let exe = env::current_exe().unwrap_or_else(|e| {\n        eprintln!(\"mise-shim: failed to determine executable path: {e}\");\n        exit(1);\n    });\n    let tool = exe\n        .file_stem()\n        .unwrap_or_else(|| {\n            eprintln!(\"mise-shim: failed to determine tool name from executable path\");\n            exit(1);\n        })\n        .to_os_string();\n\n    let args = env::args_os().skip(1);\n\n    let status = Command::new(\"mise\")\n        .arg(\"x\")\n        .arg(\"--\")\n        .arg(&tool)\n        .args(args)\n        .status();\n\n    match status {\n        Ok(s) => exit(s.code().unwrap_or(1)),\n        Err(e) => {\n            eprintln!(\"mise-shim: failed to execute mise: {e}\");\n            eprintln!(\"Ensure `mise` is installed and available on your PATH.\");\n            eprintln!(\"See https://mise.jdx.dev for installation instructions.\");\n            exit(1);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/.cargo/config.toml",
    "content": "[env]\nRUST_TEST_THREADS = '1'\n"
  },
  {
    "path": "crates/vfox/.gitignore",
    "content": "test/downloads\n"
  },
  {
    "path": "crates/vfox/.prettierignore",
    "content": "plugins/nodejs\nembedded-plugins\n"
  },
  {
    "path": "crates/vfox/Cargo.toml",
    "content": "[package]\nname = \"vfox\"\nversion = \"2026.3.0\"\nedition = \"2024\"\nlicense = \"MIT\"\ndescription = \"Interface to vfox plugins\"\ndocumentation = \"https://docs.rs/vfox\"\nhomepage = \"https://github.com/jdx/mise\"\nrepository = \"https://github.com/jdx/mise\"\ninclude = [\n  \"src\",\n  \"lua\",\n  \"embedded-plugins\",\n  \"build.rs\",\n  \"Cargo.toml\",\n  \"Cargo.lock\",\n  \"README.md\",\n  \"LICENSE\",\n]\nbuild = \"build.rs\"\n\n[lib]\nname = \"vfox\"\npath = \"src/lib.rs\"\n\n[[bin]]\nname = \"vfox-cli\"\npath = \"src/bin.rs\"\n\n[dependencies]\nhomedir = \"0.3\"\nindexmap = { version = \"2\", features = [\"serde\"] }\nitertools = \"0.14\"\nlog = \"0.4\"\nmlua = { version = \"0.11\", features = [\n  \"async\",\n  \"lua51\",\n  \"macros\",\n  \"serialize\",\n  \"send\",\n] }\nonce_cell = \"1\"\nreqwest = { version = \"0.12\", default-features = false, features = [\n  \"json\",\n] } # TODO: replace with xx\nserde = \"1\"\nserde_json = \"1\"\nthiserror = \"2\"\ntokio = { version = \"1\", features = [\"macros\", \"fs\", \"io-util\"] }\nurl = \"2\"\nxx = { version = \"2\", default-features = false, features = [\"archive\", \"hash\"] }\n\n# cli dependencies\nenv_logger = { version = \"0.11\", optional = true }\nclap = { version = \"4\", features = [\"derive\"], optional = true }\ntempfile = \"3\"\nsigstore-verification = \"0.2\"\n\n[dev-dependencies]\ninsta = \"1\"\nwiremock = \"0.6\"\n#pretty_assertions = \"1.4.0\"\n\n[features]\ndefault = [\"vendored-lua\", \"native-tls\"]\ncli = [\"clap\", \"tokio/full\", \"env_logger\"]\nnative-tls = [\"xx/native-tls\", \"xx/http\", \"reqwest/native-tls\"]\nrustls = [\"xx/rustls\", \"xx/http\", \"reqwest/rustls-tls\"]\nrustls-native-roots = [\n  \"reqwest/rustls-tls-native-roots\",\n  \"xx/http\",\n  \"xx/rustls-native-roots\",\n]\nvendored-lua = [\"mlua/vendored\"]\n\n# [workspace.metadata.release] - removed since this is now part of mise workspace\n# pre-release-hook = [\"git\", \"cliff\", \"-o\", \"CHANGELOG.md\", \"--tag\", \"{{version}}\"]\n"
  },
  {
    "path": "crates/vfox/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2025 Jeff Dickey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "crates/vfox/README.md",
    "content": "A rust interface to [vfox](https://github.com/version-fox/vfox).\n"
  },
  {
    "path": "crates/vfox/build.rs",
    "content": "use std::collections::BTreeMap;\nuse std::env;\nuse std::fs;\nuse std::path::Path;\n\nfn main() {\n    codegen_embedded_plugins();\n}\n\n/// Convert a path to a string with forward slashes (required for include_str! on Windows)\nfn path_to_forward_slashes(path: &Path) -> String {\n    path.to_string_lossy().replace('\\\\', \"/\")\n}\n\nfn codegen_embedded_plugins() {\n    let out_dir = env::var_os(\"OUT_DIR\").unwrap();\n    let dest_path = Path::new(&out_dir).join(\"embedded_plugins.rs\");\n\n    let manifest_dir = env::var(\"CARGO_MANIFEST_DIR\").unwrap();\n    let embedded_dir = Path::new(&manifest_dir).join(\"embedded-plugins\");\n\n    // Tell Cargo to re-run if any embedded plugin files change\n    println!(\"cargo:rerun-if-changed=embedded-plugins\");\n\n    if !embedded_dir.exists() {\n        // Generate empty implementation if no embedded plugins\n        let code = r#\"\n#[derive(Debug)]\npub struct EmbeddedPlugin {\n    pub metadata: &'static str,\n    pub hooks: &'static [(&'static str, &'static str)],\n    pub lib: &'static [(&'static str, &'static str)],\n}\n\npub fn get_embedded_plugin(_name: &str) -> Option<&'static EmbeddedPlugin> {\n    None\n}\n\npub fn list_embedded_plugins() -> &'static [&'static str] {\n    &[]\n}\n\"#;\n        fs::write(&dest_path, code).unwrap();\n        return;\n    }\n\n    let mut plugins: BTreeMap<String, PluginFiles> = BTreeMap::new();\n\n    // Scan for plugin directories\n    for entry in fs::read_dir(&embedded_dir).unwrap() {\n        let entry = entry.unwrap();\n        let path = entry.path();\n        if !path.is_dir() {\n            continue;\n        }\n\n        let dir_name = path.file_name().unwrap().to_string_lossy().to_string();\n        if !dir_name.starts_with(\"vfox-\") {\n            continue;\n        }\n\n        // Tell Cargo to re-run if this plugin directory or any Lua files change\n        println!(\"cargo:rerun-if-changed={}\", path.display());\n\n        // Also track subdirectories and individual Lua files\n        let hooks_dir = path.join(\"hooks\");\n        if hooks_dir.exists() {\n            println!(\"cargo:rerun-if-changed={}\", hooks_dir.display());\n            for entry in fs::read_dir(&hooks_dir).unwrap().flatten() {\n                if entry.path().extension().is_some_and(|ext| ext == \"lua\") {\n                    println!(\"cargo:rerun-if-changed={}\", entry.path().display());\n                }\n            }\n        }\n        let lib_dir = path.join(\"lib\");\n        if lib_dir.exists() {\n            println!(\"cargo:rerun-if-changed={}\", lib_dir.display());\n            for entry in fs::read_dir(&lib_dir).unwrap().flatten() {\n                if entry.path().extension().is_some_and(|ext| ext == \"lua\") {\n                    println!(\"cargo:rerun-if-changed={}\", entry.path().display());\n                }\n            }\n        }\n        let metadata_file = path.join(\"metadata.lua\");\n        if metadata_file.exists() {\n            println!(\"cargo:rerun-if-changed={}\", metadata_file.display());\n        }\n\n        let plugin = collect_plugin_files(&path);\n        plugins.insert(dir_name, plugin);\n    }\n\n    // Generate Rust code\n    let mut code = String::new();\n\n    // Struct definition\n    code.push_str(\n        r#\"\n#[derive(Debug)]\npub struct EmbeddedPlugin {\n    pub metadata: &'static str,\n    pub hooks: &'static [(&'static str, &'static str)],\n    pub lib: &'static [(&'static str, &'static str)],\n}\n\n\"#,\n    );\n\n    // Generate static instances for each plugin\n    for (name, files) in &plugins {\n        let var_name = name.replace('-', \"_\").to_uppercase();\n        code.push_str(&format!(\n            \"static {var_name}: EmbeddedPlugin = EmbeddedPlugin {{\\n\"\n        ));\n\n        // Metadata - use absolute path with forward slashes for cross-platform include_str!\n        let metadata_path = embedded_dir.join(name).join(\"metadata.lua\");\n        code.push_str(&format!(\n            \"    metadata: include_str!(\\\"{}\\\"),\\n\",\n            path_to_forward_slashes(&metadata_path)\n        ));\n\n        // Hooks\n        code.push_str(\"    hooks: &[\\n\");\n        for hook in &files.hooks {\n            let hook_path = embedded_dir\n                .join(name)\n                .join(\"hooks\")\n                .join(format!(\"{}.lua\", hook));\n            code.push_str(&format!(\n                \"        (\\\"{}\\\", include_str!(\\\"{}\\\")),\\n\",\n                hook,\n                path_to_forward_slashes(&hook_path)\n            ));\n        }\n        code.push_str(\"    ],\\n\");\n\n        // Lib files\n        code.push_str(\"    lib: &[\\n\");\n        for lib in &files.lib {\n            let lib_path = embedded_dir\n                .join(name)\n                .join(\"lib\")\n                .join(format!(\"{}.lua\", lib));\n            code.push_str(&format!(\n                \"        (\\\"{}\\\", include_str!(\\\"{}\\\")),\\n\",\n                lib,\n                path_to_forward_slashes(&lib_path)\n            ));\n        }\n        code.push_str(\"    ],\\n\");\n\n        code.push_str(\"};\\n\\n\");\n    }\n\n    // Generate lookup function\n    code.push_str(\"pub fn get_embedded_plugin(name: &str) -> Option<&'static EmbeddedPlugin> {\\n\");\n    code.push_str(\"    match name {\\n\");\n    for name in plugins.keys() {\n        let var_name = name.replace('-', \"_\").to_uppercase();\n        let short_name = name.strip_prefix(\"vfox-\").unwrap_or(name);\n        code.push_str(&format!(\n            \"        \\\"{}\\\" | \\\"{}\\\" => Some(&{}),\\n\",\n            name, short_name, var_name\n        ));\n    }\n    code.push_str(\"        _ => None,\\n\");\n    code.push_str(\"    }\\n\");\n    code.push_str(\"}\\n\\n\");\n\n    // Generate list function\n    code.push_str(\"pub fn list_embedded_plugins() -> &'static [&'static str] {\\n\");\n    code.push_str(\"    &[\\n\");\n    for name in plugins.keys() {\n        code.push_str(&format!(\"        \\\"{}\\\",\\n\", name));\n    }\n    code.push_str(\"    ]\\n\");\n    code.push_str(\"}\\n\");\n\n    fs::write(&dest_path, code).unwrap();\n}\n\nstruct PluginFiles {\n    hooks: Vec<String>,\n    lib: Vec<String>,\n}\n\nfn collect_plugin_files(plugin_dir: &Path) -> PluginFiles {\n    let mut hooks = Vec::new();\n    let mut lib = Vec::new();\n\n    // Collect hooks\n    let hooks_dir = plugin_dir.join(\"hooks\");\n    if hooks_dir.exists() {\n        for entry in fs::read_dir(&hooks_dir).unwrap() {\n            let entry = entry.unwrap();\n            let path = entry.path();\n            if path.extension().is_some_and(|ext| ext == \"lua\") {\n                let name = path.file_stem().unwrap().to_string_lossy().to_string();\n                hooks.push(name);\n            }\n        }\n    }\n    hooks.sort();\n\n    // Collect lib files\n    let lib_dir = plugin_dir.join(\"lib\");\n    if lib_dir.exists() {\n        for entry in fs::read_dir(&lib_dir).unwrap() {\n            let entry = entry.unwrap();\n            let path = entry.path();\n            if path.extension().is_some_and(|ext| ext == \"lua\") {\n                let name = path.file_stem().unwrap().to_string_lossy().to_string();\n                lib.push(name);\n            }\n        }\n    }\n    lib.sort();\n\n    PluginFiles { hooks, lib }\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-1password/hooks/available.lua",
    "content": "local http = require(\"http\")\n\n--- Get the available version list.\n--- @param ctx table Empty table, no data provided. Always {}.\n--- @return table Version list\nfunction PLUGIN:Available(ctx)\n\tlocal result = {}\n\n\t-- Fetch CLI v2 versions (current)\n\tlocal resp2 = http.get({\n\t\turl = \"https://app-updates.agilebits.com/product_history/CLI2\",\n\t})\n\tif resp2.status_code == 200 then\n\t\t-- Versions appear on lines after <h3> tags\n\t\t-- Pattern: <h3>\\n\\t\\t\\t\\tVERSION\n\t\tfor version in resp2.body:gmatch(\"<h3>[^<]*</h3>%s*([%d%.%-beta]+)\") do\n\t\t\tlocal clean_version = version:match(\"^%s*(.-)%s*$\")\n\t\t\tif clean_version and clean_version ~= \"\" then\n\t\t\t\ttable.insert(result, {\n\t\t\t\t\tversion = clean_version,\n\t\t\t\t\tnote = \"CLI v2\",\n\t\t\t\t})\n\t\t\tend\n\t\tend\n\t\t-- Alternative pattern if the above doesn't work\n\t\tif #result == 0 then\n\t\t\tfor version in resp2.body:gmatch(\"<h3>%s*</h3>%s*([%d%.%-beta]+)\") do\n\t\t\t\tlocal clean_version = version:match(\"^%s*(.-)%s*$\")\n\t\t\t\tif clean_version and clean_version ~= \"\" then\n\t\t\t\t\ttable.insert(result, {\n\t\t\t\t\t\tversion = clean_version,\n\t\t\t\t\t\tnote = \"CLI v2\",\n\t\t\t\t\t})\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\t\t-- Try line-by-line parsing\n\t\tif #result == 0 then\n\t\t\tlocal in_h3 = false\n\t\t\tfor line in resp2.body:gmatch(\"[^\\r\\n]+\") do\n\t\t\t\tif line:match(\"<h3>\") then\n\t\t\t\t\tin_h3 = true\n\t\t\t\telseif in_h3 then\n\t\t\t\t\tlocal version = line:match(\"^%s*([%d%.%-beta]+)%s*$\")\n\t\t\t\t\tif version then\n\t\t\t\t\t\ttable.insert(result, {\n\t\t\t\t\t\t\tversion = version,\n\t\t\t\t\t\t\tnote = \"CLI v2\",\n\t\t\t\t\t\t})\n\t\t\t\t\tend\n\t\t\t\t\tin_h3 = false\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\tend\n\n\t-- Fetch CLI v1 versions (legacy)\n\tlocal resp1 = http.get({\n\t\turl = \"https://app-updates.agilebits.com/product_history/CLI\",\n\t})\n\tif resp1.status_code == 200 then\n\t\tlocal in_h3 = false\n\t\tfor line in resp1.body:gmatch(\"[^\\r\\n]+\") do\n\t\t\tif line:match(\"<h3>\") then\n\t\t\t\tin_h3 = true\n\t\t\telseif in_h3 then\n\t\t\t\tlocal version = line:match(\"^%s*([%d%.%-beta]+)%s*$\")\n\t\t\t\tif version then\n\t\t\t\t\ttable.insert(result, {\n\t\t\t\t\t\tversion = version,\n\t\t\t\t\t\tnote = \"CLI v1\",\n\t\t\t\t\t})\n\t\t\t\tend\n\t\t\t\tin_h3 = false\n\t\t\tend\n\t\tend\n\tend\n\n\t-- Sort versions (newest first)\n\ttable.sort(result, function(a, b)\n\t\treturn compare_versions(a.version, b.version)\n\tend)\n\n\treturn result\nend\n\n--- Compare two version strings\n--- @param v1 string\n--- @param v2 string\n--- @return boolean true if v1 > v2\nfunction compare_versions(v1, v2)\n\tlocal function parse(v)\n\t\tlocal parts = {}\n\t\t-- Handle beta versions: 2.31.0-beta.01 -> {2, 31, 0, -1, 1}\n\t\tlocal main, beta = v:match(\"^([%d%.]+)%-beta%.?(%d*)$\")\n\t\tif main then\n\t\t\tfor num in main:gmatch(\"(%d+)\") do\n\t\t\t\ttable.insert(parts, tonumber(num))\n\t\t\tend\n\t\t\ttable.insert(parts, -1) -- beta marker\n\t\t\tif beta and beta ~= \"\" then\n\t\t\t\ttable.insert(parts, tonumber(beta))\n\t\t\telse\n\t\t\t\ttable.insert(parts, 0)\n\t\t\tend\n\t\telse\n\t\t\tfor num in v:gmatch(\"(%d+)\") do\n\t\t\t\ttable.insert(parts, tonumber(num))\n\t\t\tend\n\t\tend\n\t\treturn parts\n\tend\n\n\tlocal p1, p2 = parse(v1), parse(v2)\n\tfor i = 1, math.max(#p1, #p2) do\n\t\tlocal n1, n2 = p1[i] or 0, p2[i] or 0\n\t\tif n1 ~= n2 then\n\t\t\treturn n1 > n2\n\t\tend\n\tend\n\treturn false\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-1password/hooks/env_keys.lua",
    "content": "--- Returns the environment variables that need to be set.\n--- @param ctx {path: string}  (Installation directory)\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n\treturn {\n\t\t{\n\t\t\tkey = \"PATH\",\n\t\t\tvalue = ctx.path,\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-1password/hooks/pre_install.lua",
    "content": "local http = require(\"http\")\n\n--- Returns pre-installed information, such as version number, download address, etc.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n\tlocal version = ctx.version\n\tlocal os_type = RUNTIME.osType\n\tlocal arch_type = RUNTIME.archType\n\n\t-- Determine CLI version (v1 or v2) and base path\n\tlocal cli_path\n\tif version:match(\"^1%.\") then\n\t\tcli_path = \"op\"\n\telse\n\t\tcli_path = \"op2\"\n\tend\n\n\t-- Map OS type\n\tlocal os_name = os_type\n\tif os_type == \"darwin\" then\n\t\tos_name = \"darwin\"\n\telseif os_type == \"windows\" then\n\t\tos_name = \"windows\"\n\tend\n\n\t-- Map architecture\n\tlocal arch = arch_type\n\tif arch_type == \"x86_64\" then\n\t\tarch = \"amd64\"\n\telseif arch_type == \"i386\" or arch_type == \"i686\" then\n\t\tarch = \"386\"\n\telseif arch_type == \"aarch64\" then\n\t\tarch = \"arm64\"\n\tend\n\n\tlocal base_url = \"https://cache.agilebits.com/dist/1P/\" .. cli_path .. \"/pkg/v\" .. version .. \"/\"\n\tlocal filename = \"op_\" .. os_name .. \"_\" .. arch .. \"_v\" .. version .. \".zip\"\n\tlocal download_url = base_url .. filename\n\n\t-- Verify URL exists\n\tlocal resp = http.head({ url = download_url })\n\tif resp.status_code ~= 200 then\n\t\terror(\"Download URL not found: \" .. download_url .. \" (status: \" .. resp.status_code .. \")\")\n\tend\n\n\treturn {\n\t\tversion = version,\n\t\turl = download_url,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-1password/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"1password\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-1password\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"1Password CLI (op) - Password manager developed by AgileBits Inc\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n\t\"Provides the 1Password CLI tool (op command)\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/hooks/available.lua",
    "content": "local util = require(\"util\")\n\n--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n\tlocal versions = util.parseVersions()\n\n\ttable.sort(versions, function(a, b)\n\t\treturn util.compareVersions(a.version, b.version)\n\tend)\n\n\treturn versions\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n\tlocal mainPath = ctx.path\n\treturn {\n\t\t{\n\t\t\tkey = \"PATH\",\n\t\t\tvalue = mainPath,\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/hooks/post_install.lua",
    "content": "local util = require(\"util\")\n\n--- Extension point, called after PreInstall, can perform additional operations,\n--- such as file operations for the SDK installation directory\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation directory\nfunction PLUGIN:PostInstall(ctx)\n\tlocal rootPath = ctx.rootPath\n\tlocal os_name = util.getOsName()\n\n\t-- Find the JAR file in the install directory\n\tlocal find_cmd\n\tlocal jar_path\n\tif RUNTIME.osType == \"windows\" then\n\t\tfind_cmd = string.format('dir /b \"%s\\\\aapt2-*.jar\" 2>nul', rootPath)\n\telse\n\t\tfind_cmd = string.format('ls \"%s\"/aapt2-*.jar 2>/dev/null | head -1', rootPath)\n\tend\n\n\tlocal handle = io.popen(find_cmd)\n\tif handle then\n\t\tjar_path = handle:read(\"*l\")\n\t\thandle:close()\n\tend\n\n\tif not jar_path or jar_path == \"\" then\n\t\t-- JAR not found, maybe already extracted\n\t\treturn\n\tend\n\n\t-- On Windows, need to prepend the rootPath\n\tif RUNTIME.osType == \"windows\" and not string.match(jar_path, \"^[A-Za-z]:\") then\n\t\tjar_path = rootPath .. \"\\\\\" .. jar_path\n\tend\n\n\t-- Extract the JAR file (it's a ZIP)\n\tlocal extract_cmd\n\tif RUNTIME.osType == \"windows\" then\n\t\textract_cmd = string.format(\n\t\t\t\"powershell -Command \\\"Expand-Archive -Path '%s' -DestinationPath '%s' -Force\\\"\",\n\t\t\tjar_path,\n\t\t\trootPath\n\t\t)\n\telse\n\t\textract_cmd = string.format('unzip -o \"%s\" -d \"%s\"', jar_path, rootPath)\n\tend\n\n\tlocal result = os.execute(extract_cmd)\n\tif not result then\n\t\terror(\"Failed to extract JAR file: \" .. jar_path)\n\tend\n\n\t-- Remove the JAR file after extraction\n\tos.remove(jar_path)\n\n\t-- Make the binary executable on Unix systems\n\tif RUNTIME.osType ~= \"windows\" then\n\t\tlocal aapt2_path = rootPath .. \"/aapt2\"\n\t\tos.execute(string.format('chmod +x \"%s\"', aapt2_path))\n\tend\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/hooks/pre_install.lua",
    "content": "local util = require(\"util\")\n\n--- Returns pre-installed information, such as version number, download address, etc.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n\tlocal version = ctx.version\n\n\treturn {\n\t\tversion = version,\n\t\turl = util.getDownloadUrl(version),\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/lib/util.lua",
    "content": "local http = require(\"http\")\n\nlocal util = {}\n\nutil.MAVEN_REPO = \"https://dl.google.com/android/maven2/com/android/tools/build\"\nutil.GROUP_INDEX_URL = util.MAVEN_REPO .. \"/group-index.xml\"\n\nfunction util.getOsName()\n    local os_type = RUNTIME.osType\n    if os_type == \"darwin\" then\n        return \"osx\"\n    elseif os_type == \"linux\" then\n        return \"linux\"\n    elseif os_type == \"windows\" then\n        return \"windows\"\n    else\n        error(\"Unsupported OS: \" .. os_type)\n    end\nend\n\nfunction util.getDownloadUrl(version)\n    local os_name = util.getOsName()\n    return string.format(\"%s/aapt2/%s/aapt2-%s-%s.jar\", util.MAVEN_REPO, version, version, os_name)\nend\n\nfunction util.parseVersions()\n    local resp, err = http.get({\n        url = util.GROUP_INDEX_URL\n    })\n    if err ~= nil or resp.status_code ~= 200 then\n        error(\"Failed to fetch version list: \" .. (err or \"HTTP \" .. resp.status_code))\n    end\n\n    local result = {}\n    -- Parse versions from XML: <aapt2 versions=\"8.9.0-alpha04,8.9.0-alpha03,...\"/>\n    local versions_str = string.match(resp.body, '<aapt2 versions=\"([^\"]*)\"')\n    if versions_str then\n        for version in string.gmatch(versions_str, \"([^,]+)\") do\n            table.insert(result, {\n                version = version,\n                note = \"\",\n            })\n        end\n    end\n\n    return result\nend\n\nfunction util.compareVersions(a, b)\n    -- Extract major.minor.patch and optional suffix\n    local function parseVersion(v)\n        local major, minor, patch, suffix = string.match(v, \"^(%d+)%.(%d+)%.(%d+)%-?(.*)$\")\n        if not major then\n            major, minor, patch = string.match(v, \"^(%d+)%.(%d+)%.(%d+)$\")\n            suffix = \"\"\n        end\n        return tonumber(major) or 0, tonumber(minor) or 0, tonumber(patch) or 0, suffix or \"\"\n    end\n\n    local a1, a2, a3, a4 = parseVersion(a)\n    local b1, b2, b3, b4 = parseVersion(b)\n\n    if a1 ~= b1 then return a1 > b1 end\n    if a2 ~= b2 then return a2 > b2 end\n    if a3 ~= b3 then return a3 > b3 end\n    -- For suffix: stable (empty) > rc > beta > alpha\n    if a4 == \"\" and b4 ~= \"\" then return true end\n    if a4 ~= \"\" and b4 == \"\" then return false end\n    return a4 > b4\nend\n\nreturn util\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-aapt2/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"aapt2\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-aapt2\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Android Asset Packaging Tool 2 (aapt2)\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n\t\"aapt2 is used to compile and package Android app resources.\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ag/hooks/available.lua",
    "content": "--- Returns all available versions of ag from GitHub tags\n--- @param ctx table Context provided by vfox\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local result = {}\n    local page = 1\n\n    -- Get GitHub token from environment for rate limiting\n    local github_token = os.getenv(\"GITHUB_TOKEN\") or os.getenv(\"GH_TOKEN\")\n    local headers = {\n        [\"Accept\"] = \"application/vnd.github.v3+json\",\n    }\n    if github_token and github_token ~= \"\" then\n        headers[\"Authorization\"] = \"token \" .. github_token\n    end\n\n    while true do\n        local resp, err = http.get({\n            url = \"https://api.github.com/repos/ggreer/the_silver_searcher/tags?per_page=100&page=\" .. page,\n            headers = headers,\n        })\n\n        if err ~= nil then\n            error(\"Failed to fetch tags: \" .. err)\n        end\n\n        if resp.status_code ~= 200 then\n            error(\"Failed to fetch tags, status: \" .. resp.status_code)\n        end\n\n        local tags = json.decode(resp.body)\n        if tags == nil or #tags == 0 then\n            break\n        end\n\n        for _, tag in ipairs(tags) do\n            local version = tag.name\n            table.insert(result, {\n                version = version,\n            })\n        end\n\n        -- If we got less than 100 results, we've reached the end\n        if #tags < 100 then\n            break\n        end\n\n        page = page + 1\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ag/hooks/env_keys.lua",
    "content": "--- Returns environment keys and paths for the installed tool\n--- @param ctx table Context provided by vfox\n--- @return table Environment keys\nfunction PLUGIN:EnvKeys(ctx)\n    local mainSdk = ctx.sdkInfo[\"ag\"]\n    local path = mainSdk.path\n\n    return {\n        {\n            key = \"PATH\",\n            value = path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ag/hooks/post_install.lua",
    "content": "--- Compiles ag from source after download\n--- @param ctx table Context provided by vfox\nfunction PLUGIN:PostInstall(ctx)\n    local cmd = require(\"cmd\")\n\n    local sdkInfo = ctx.sdkInfo[\"ag\"]\n    local path = sdkInfo.path\n\n    -- Source files are extracted directly to the install path\n    local srcDir = path\n\n    --- Run autogen.sh to generate configure script\n    cmd.exec(\"cd '\" .. srcDir .. \"' && ./autogen.sh\")\n\n    --- Run configure with prefix set to installation path\n    --- Add -fcommon to CFLAGS for GCC 10+ compatibility (fixes multiple definition errors)\n    local configureArgs = os.getenv(\"AG_CONFIGURE_ARGS\") or \"\"\n    local cflags = os.getenv(\"CFLAGS\") or \"\"\n    if cflags == \"\" then\n        cflags = \"-fcommon\"\n    else\n        cflags = cflags .. \" -fcommon\"\n    end\n    cmd.exec(\"cd '\" .. srcDir .. \"' && CFLAGS='\" .. cflags .. \"' ./configure --prefix='\" .. path .. \"' \" .. configureArgs)\n\n    --- Run make\n    cmd.exec(\"cd '\" .. srcDir .. \"' && make\")\n\n    --- Run make install\n    cmd.exec(\"cd '\" .. srcDir .. \"' && make install\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ag/hooks/pre_install.lua",
    "content": "--- Returns download information for a specific version\n--- @param ctx table Context provided by vfox (contains version)\n--- @return table Version info with download URL\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    if version == nil or version == \"\" then\n        error(\"You must provide a version number, eg: vfox install ag@2.2.0\")\n    end\n\n    -- Download source tarball from GitHub\n    local url = \"https://github.com/ggreer/the_silver_searcher/archive/refs/tags/\" .. version .. \".tar.gz\"\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ag/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"ag\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-ag\"\n--- Plugin license, please choose a correct license according to your needs.\nPLUGIN.license = \"Apache-2.0\"\n--- Plugin description\nPLUGIN.description = \"The Silver Searcher - A code searching tool similar to ack, with a focus on speed\"\n\n--- !!! OPTIONAL !!!\n--- Minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n--- Manifest URL, if set, it will be used to check for updates\n-- PLUGIN.manifestUrl = \"https://github.com/mise-plugins/vfox-ag/releases/download/manifest/manifest.json\"\n--- User attention\nPLUGIN.notes = {\n    \"ag requires build dependencies: automake, pkg-config, pcre, xz, and a C compiler\",\n    \"On macOS: brew install automake pkg-config pcre xz\",\n    \"On Debian/Ubuntu: apt-get install automake pkg-config libpcre3-dev zlib1g-dev liblzma-dev\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-android-sdk/hooks/available.lua",
    "content": "--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local env = require(\"env\")\n\n    local base_url = env.ANDROID_SDK_MIRROR_URL or \"https://dl.google.com/android/repository\"\n    local metadata_url = base_url .. \"/repository2-3.xml\"\n\n    local resp = http.get({ url = metadata_url })\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch Android SDK metadata: HTTP \" .. resp.status_code)\n    end\n\n    local versions = {}\n    local seen = {}\n\n    -- Parse XML to find cmdline-tools packages\n    -- Look for remotePackage elements with path=\"cmdline-tools;VERSION\"\n    for path_attr in resp.body:gmatch('remotePackage%s+path=\"([^\"]+)\"') do\n        -- Match cmdline-tools;VERSION pattern, excluding \"latest\"\n        local version = path_attr:match(\"^cmdline%-tools;(.+)$\")\n        if version and version ~= \"latest\" and not seen[version] then\n            seen[version] = true\n            table.insert(versions, {\n                version = version,\n                note = \"\",\n            })\n        end\n    end\n\n    -- Sort versions (simple string sort, works for numeric versions)\n    table.sort(versions, function(a, b)\n        return a.version < b.version\n    end)\n\n    return versions\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-android-sdk/hooks/env_keys.lua",
    "content": "--- Return environment variables for the tool\n--- @param ctx {path: string}  (The installation path of the tool version)\n--- @field ctx.version string The version\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n    local file = require(\"file\")\n\n    local install_path = ctx.path\n    local version = ctx.version\n\n    -- Structure is: install_path/cmdline-tools/VERSION/bin\n    local bin_path = file.join_path(install_path, \"cmdline-tools\", version, \"bin\")\n\n    return {\n        {\n            key = \"PATH\",\n            value = bin_path,\n        },\n        {\n            key = \"ANDROID_HOME\",\n            value = install_path,\n        },\n        {\n            key = \"ANDROID_SDK_ROOT\",\n            value = install_path,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-android-sdk/hooks/post_install.lua",
    "content": "--- Called after the tool is installed.\n--- Used to set up the correct directory structure for Android SDK.\n--- @param ctx table\n--- @field ctx.rootPath string The installation root path\n--- @field ctx.sdkInfo table SDK information including version\nfunction PLUGIN:PostInstall(ctx)\n    local file = require(\"file\")\n\n    local root_path = ctx.rootPath\n\n    -- Get the version from sdkInfo\n    local version = nil\n    for _, info in pairs(ctx.sdkInfo) do\n        version = info.version\n        break\n    end\n\n    if not version then\n        error(\"Could not determine version from sdkInfo\")\n    end\n\n    -- vfox extracts cmdline-tools contents directly to rootPath\n    -- But Android SDK expects: ANDROID_HOME/cmdline-tools/VERSION/bin/sdkmanager\n    -- So we need to reorganize: move rootPath/* to rootPath/cmdline-tools/VERSION/\n\n    local temp_path = root_path .. \"-temp\"\n    local target_path = file.join_path(root_path, \"cmdline-tools\", version)\n\n    -- Move current rootPath to temp location\n    os.execute(\"mv \" .. root_path .. \" \" .. temp_path)\n\n    -- Recreate rootPath with proper structure\n    os.execute(\"mkdir -p \" .. target_path)\n\n    -- Move contents from temp to target\n    os.execute(\"mv \" .. temp_path .. \"/* \" .. target_path .. \"/\")\n\n    -- Clean up temp\n    os.execute(\"rm -rf \" .. temp_path)\n\n    -- Verify installation\n    local sdkmanager_path = file.join_path(target_path, \"bin\", \"sdkmanager\")\n    if not file.exists(sdkmanager_path) then\n        error(\"Installation verification failed: sdkmanager not found at \" .. sdkmanager_path)\n    end\n\n    -- Make sure binaries are executable (for Unix systems)\n    os.execute(\"chmod +x \" .. file.join_path(target_path, \"bin\", \"*\") .. \" 2>/dev/null || true\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-android-sdk/hooks/pre_install.lua",
    "content": "--- Returns some pre-installed information, such as version number, download address, etc.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    local http = require(\"http\")\n    local env = require(\"env\")\n\n    local version = ctx.version\n\n    -- Determine OS (from global RUNTIME object)\n    local os_type = RUNTIME.osType\n    local android_sdk_os\n    if os_type == \"darwin\" then\n        android_sdk_os = \"macosx\"\n    elseif os_type == \"linux\" then\n        android_sdk_os = \"linux\"\n    elseif os_type == \"windows\" then\n        android_sdk_os = \"windows\"\n    else\n        error(\"Unsupported OS type: \" .. os_type)\n    end\n\n    -- Determine architecture (from global RUNTIME object)\n    local arch_type = RUNTIME.archType\n    local android_sdk_arch\n    if arch_type == \"amd64\" or arch_type == \"x86_64\" then\n        android_sdk_arch = \"x64\"\n    elseif arch_type == \"arm64\" or arch_type == \"aarch64\" then\n        android_sdk_arch = \"aarch64\"\n    else\n        error(\"Unsupported architecture: \" .. arch_type)\n    end\n\n    local base_url = env.ANDROID_SDK_MIRROR_URL or \"https://dl.google.com/android/repository\"\n    local metadata_url = base_url .. \"/repository2-3.xml\"\n\n    local resp = http.get({ url = metadata_url })\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch Android SDK metadata: HTTP \" .. resp.status_code)\n    end\n\n    -- Parse the XML to find the matching package\n    local package_pattern = 'remotePackage%s+path=\"cmdline%-tools;'\n        .. version:gsub(\"%-\", \"%%-\")\n        .. '\".-</remotePackage>'\n    local package_block = resp.body:match(package_pattern)\n\n    if not package_block then\n        error(\"Version \" .. version .. \" not found in Android SDK repository\")\n    end\n\n    -- Find archives block\n    local archives_block = package_block:match(\"<archives>(.-)</archives>\")\n    if not archives_block then\n        error(\"No archives found for version \" .. version)\n    end\n\n    -- Find matching archive for our OS/arch\n    local best_archive = nil\n\n    for archive in archives_block:gmatch(\"<archive>(.-)</archive>\") do\n        local host_os = archive:match(\"<host%-os>([^<]+)</host%-os>\")\n        local host_arch = archive:match(\"<host%-arch>([^<]+)</host%-arch>\")\n\n        -- Match if OS matches and either no arch specified or arch matches\n        if host_os == android_sdk_os then\n            if host_arch == nil or host_arch == android_sdk_arch then\n                best_archive = archive\n                -- Prefer exact arch match\n                if host_arch == android_sdk_arch then\n                    break\n                end\n            end\n        end\n    end\n\n    if not best_archive then\n        error(\"No archive found for \" .. android_sdk_os .. \":\" .. android_sdk_arch)\n    end\n\n    -- Extract complete block (contains url, size, checksum)\n    local complete_block = best_archive:match(\"<complete>(.-)</complete>\")\n    if not complete_block then\n        error(\"No complete block found in archive\")\n    end\n\n    -- Extract URL\n    local url = complete_block:match(\"<url>([^<]+)</url>\")\n    if not url then\n        error(\"No URL found in archive\")\n    end\n\n    -- Make URL absolute if it's relative\n    if not url:match(\"^https?://\") then\n        url = base_url .. \"/\" .. url\n    end\n\n    local result = {\n        version = version,\n        url = url,\n    }\n\n    -- Note: Android SDK only provides sha1 checksums, which vfox doesn't support yet\n    -- Checksum verification is skipped for now\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-android-sdk/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"android-sdk\"\n--- Plugin version\nPLUGIN.version = \"1.0.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://developer.android.com/studio/command-line\"\n--- Plugin license\nPLUGIN.license = \"Apache 2.0\"\n--- Plugin description\nPLUGIN.description = \"Android SDK Command-line Tools\"\n\n--- !!! OPTIONAL !!!\n--- minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n--- Some things that need user to be attention!\nPLUGIN.notes = {\n    \"Requires Java 11+ to be installed\",\n    \"Set ANDROID_SDK_MIRROR_URL to use a mirror\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/hooks/available.lua",
    "content": "local util = require(\"util\")\n\n--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n    local versions = util.parseVersions()\n\n    table.sort(versions, function(a, b)\n        return util.compareVersions(a.version, b.version)\n    end)\n\n    return versions\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n    return {\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\",\n        },\n        {\n            key = \"ANT_HOME\",\n            value = mainPath,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/hooks/post_install.lua",
    "content": "--- Extension point, called after PreInstall, can perform additional operations,\n--- such as file operations for the SDK installation directory\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation directory\nfunction PLUGIN:PostInstall(ctx)\n    -- The tarball extracts to apache-ant-{version}/ directory\n    -- mise should handle this automatically\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/hooks/pre_install.lua",
    "content": "local http = require(\"http\")\nlocal util = require(\"util\")\n\n--- Returns pre-installed information, such as version number, download address, etc.\n--- If checksum is provided, vfox will automatically check it for you.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Try to get checksum (sha512 first, then sha1)\n    local checksums = {\n        { type = \"sha512\", url = util.CHECKSUM_URL:format(version, \"sha512\") },\n        { type = \"sha1\", url = util.CHECKSUM_URL:format(version, \"sha1\") },\n    }\n\n    for _, checksum in ipairs(checksums) do\n        local resp, err = http.get({\n            url = checksum.url,\n        })\n        if err == nil and resp.status_code == 200 then\n            local hash = string.match(resp.body, \"^(%S+)\")\n            if hash then\n                local result = {\n                    version = version,\n                    url = util.FILE_URL:format(version),\n                }\n                result[checksum.type] = hash\n                return result\n            end\n        end\n    end\n\n    -- No checksum found, return without checksum\n    return {\n        version = version,\n        url = util.FILE_URL:format(version),\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/lib/util.lua",
    "content": "local http = require(\"http\")\nlocal html = require(\"html\")\n\nlocal util = {}\n\nutil.ARCHIVE_URL = \"https://archive.apache.org/dist/ant/binaries/\"\nutil.FILE_URL = \"https://archive.apache.org/dist/ant/binaries/apache-ant-%s-bin.tar.gz\"\nutil.CHECKSUM_URL = \"https://archive.apache.org/dist/ant/binaries/apache-ant-%s-bin.tar.gz.%s\"\n\nfunction util.parseVersions()\n    local resp, err = http.get({\n        url = util.ARCHIVE_URL,\n    })\n    if err ~= nil or resp.status_code ~= 200 then\n        error(\"Failed to fetch version list: \" .. (err or \"HTTP \" .. resp.status_code))\n    end\n\n    local result = {}\n    html.parse(resp.body):find(\"a\"):each(function(i, selection)\n        local href = selection:attr(\"href\")\n        -- Match apache-ant-X.Y.Z-bin.tar.gz\n        local version = string.match(href, \"^apache%-ant%-([%d%.]+)%-bin%.tar%.gz$\")\n        if version then\n            table.insert(result, {\n                version = version,\n                note = \"\",\n            })\n        end\n    end)\n\n    return result\nend\n\nfunction util.compareVersions(a, b)\n    local function parseVersion(v)\n        local parts = {}\n        for part in string.gmatch(v, \"([^.]+)\") do\n            table.insert(parts, tonumber(part) or 0)\n        end\n        return parts\n    end\n\n    local pa = parseVersion(a)\n    local pb = parseVersion(b)\n\n    for i = 1, math.max(#pa, #pb) do\n        local va = pa[i] or 0\n        local vb = pb[i] or 0\n        if va ~= vb then\n            return va > vb\n        end\n    end\n    return false\nend\n\nreturn util\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-ant/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"ant\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-ant\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Apache Ant build tool\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Apache Ant is a Java library and command-line tool for building Java applications.\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-asciidoctorj/hooks/available.lua",
    "content": "local http = require(\"http\")\n\n--- Get the available version list from Maven Central.\n--- @param ctx table Empty table, no data provided. Always {}.\n--- @return table Version list\nfunction PLUGIN:Available(ctx)\n    local result = {}\n\n    local resp = http.get({\n        url = \"https://repo1.maven.org/maven2/org/asciidoctor/asciidoctorj/\",\n    })\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch versions from Maven Central: \" .. resp.status_code)\n    end\n\n    -- Parse version directories from Maven Central HTML\n    -- Pattern matches: <a href=\"2.5.13/\" title=\"2.5.13/\">\n    for version in resp.body:gmatch('<a href=\"([%d%.]+)/\"') do\n        -- Skip versions without bin distribution (older than 1.5.0)\n        local major = tonumber(version:match(\"^(%d+)\"))\n        local minor = tonumber(version:match(\"^%d+%.(%d+)\"))\n        if major and minor then\n            if major > 1 or (major == 1 and minor >= 5) then\n                table.insert(result, {\n                    version = version,\n                })\n            end\n        end\n    end\n\n    -- Sort versions (newest first)\n    table.sort(result, function(a, b)\n        return compare_versions(a.version, b.version)\n    end)\n\n    return result\nend\n\n--- Compare two version strings\n--- @param v1 string\n--- @param v2 string\n--- @return boolean true if v1 > v2\nfunction compare_versions(v1, v2)\n    local function parse(v)\n        local parts = {}\n        for num in v:gmatch(\"(%d+)\") do\n            table.insert(parts, tonumber(num))\n        end\n        return parts\n    end\n\n    local p1, p2 = parse(v1), parse(v2)\n    for i = 1, math.max(#p1, #p2) do\n        local n1, n2 = p1[i] or 0, p2[i] or 0\n        if n1 ~= n2 then\n            return n1 > n2\n        end\n    end\n    return false\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-asciidoctorj/hooks/env_keys.lua",
    "content": "--- Sets environment variables for the installed version.\n--- @param ctx {path: string}  (Installation path)\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n    -- mise flattens the zip structure, so bin is directly in ctx.path\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-asciidoctorj/hooks/pre_install.lua",
    "content": "local http = require(\"http\")\n\n--- Returns pre-installed information, such as version number, download address, etc.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    local base_url = \"https://repo1.maven.org/maven2/org/asciidoctor/asciidoctorj/\"\n    local download_url = base_url .. version .. \"/asciidoctorj-\" .. version .. \"-bin.zip\"\n\n    -- Verify URL exists\n    local resp = http.head({ url = download_url })\n    if resp.status_code ~= 200 then\n        error(\"Download URL not found: \" .. download_url .. \" (status: \" .. resp.status_code .. \")\")\n    end\n\n    return {\n        version = version,\n        url = download_url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-asciidoctorj/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"asciidoctorj\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-asciidoctorj\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"AsciidoctorJ - the official library for running Asciidoctor on the JVM\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Provides the asciidoctorj command for converting AsciiDoc documents\",\n    \"Requires Java to be installed\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-azure-functions-core-tools/hooks/available.lua",
    "content": "local http = require(\"http\")\nlocal json = require(\"json\")\n\n--- Get the available version list from GitHub releases.\n--- @param ctx table Empty table, no data provided. Always {}.\n--- @return table Version list\nfunction PLUGIN:Available(ctx)\n    local result = {}\n    local page = 1\n    local per_page = 100\n\n    while true do\n        local url = \"https://api.github.com/repos/Azure/azure-functions-core-tools/releases?per_page=\"\n            .. per_page\n            .. \"&page=\"\n            .. page\n        local resp = http.get({\n            url = url,\n            headers = {\n                [\"Accept\"] = \"application/vnd.github.v3+json\",\n            },\n        })\n\n        if resp.status_code ~= 200 then\n            if page == 1 then\n                error(\"Failed to fetch releases from GitHub: \" .. resp.status_code)\n            end\n            break\n        end\n\n        local releases = json.decode(resp.body)\n        if #releases == 0 then\n            break\n        end\n\n        for _, release in ipairs(releases) do\n            if not release.prerelease and not release.draft then\n                local version = release.tag_name\n                table.insert(result, {\n                    version = version,\n                    note = release.name or \"\",\n                })\n            end\n        end\n\n        page = page + 1\n        -- Limit to avoid too many API calls\n        if page > 5 then\n            break\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-azure-functions-core-tools/hooks/env_keys.lua",
    "content": "--- Sets environment variables for the installed version.\n--- @param ctx {path: string}  (Installation path)\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n    -- The func binary is at the root of the extracted zip\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-azure-functions-core-tools/hooks/post_install.lua",
    "content": "--- Called after installation is complete to fix binary permissions.\n--- @param ctx table\n--- @field ctx.rootPath string Installation root path\nfunction PLUGIN:PostInstall(ctx)\n    local os_type = RUNTIME.osType\n\n    -- On Unix systems, we need to make the binary executable\n    if os_type ~= \"windows\" then\n        local func_path = ctx.rootPath .. \"/func\"\n        -- Use os.execute to chmod +x the binary\n        local result = os.execute(\"chmod +x \" .. func_path)\n        if result ~= 0 and result ~= true then\n            -- Some Lua versions return true on success, others return 0\n            print(\"Warning: could not chmod +x \" .. func_path)\n        end\n\n        -- Also chmod other potential executables\n        local gozip_path = ctx.rootPath .. \"/gozip\"\n        os.execute(\"chmod +x \" .. gozip_path .. \" 2>/dev/null\")\n\n        local createdump_path = ctx.rootPath .. \"/createdump\"\n        os.execute(\"chmod +x \" .. createdump_path .. \" 2>/dev/null\")\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-azure-functions-core-tools/hooks/pre_install.lua",
    "content": "local http = require(\"http\")\n\n--- Returns pre-installed information, such as version number, download address, etc.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n    local os_type = RUNTIME.osType\n    local arch_type = RUNTIME.archType\n\n    -- Map OS type to Azure naming convention\n    local os_name\n    if os_type == \"darwin\" then\n        os_name = \"osx\"\n    elseif os_type == \"windows\" then\n        os_name = \"win\"\n    else\n        os_name = \"linux\"\n    end\n\n    -- Map architecture\n    local arch\n    if arch_type == \"amd64\" or arch_type == \"x86_64\" then\n        arch = \"x64\"\n    elseif arch_type == \"arm64\" or arch_type == \"aarch64\" then\n        arch = \"arm64\"\n    elseif arch_type == \"386\" or arch_type == \"i386\" or arch_type == \"i686\" then\n        arch = \"x86\"\n    else\n        arch = arch_type\n    end\n\n    local base_url = \"https://github.com/Azure/azure-functions-core-tools/releases/download/\"\n    local filename = \"Azure.Functions.Cli.\" .. os_name .. \"-\" .. arch .. \".\" .. version .. \".zip\"\n    local download_url = base_url .. version .. \"/\" .. filename\n\n    -- Verify URL exists\n    local resp = http.head({ url = download_url })\n    if resp.status_code ~= 200 and resp.status_code ~= 302 then\n        error(\"Download URL not found: \" .. download_url .. \" (status: \" .. resp.status_code .. \")\")\n    end\n\n    return {\n        version = version,\n        url = download_url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-azure-functions-core-tools/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"azure-functions-core-tools\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-azure-functions-core-tools\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Azure Functions Core Tools - Command line tools for Azure Functions\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Provides the 'func' command for local Azure Functions development\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/hooks/available.lua",
    "content": "--- Returns all available versions of bfs from GitHub tags\n--- @param ctx table Context object (unused for this plugin)\n--- @return table Array of version objects with 'version' field\nfunction PLUGIN:Available(ctx)\n    local util = require(\"util\")\n    local versions = util.get_versions()\n\n    -- Sort versions (newest first)\n    table.sort(versions, util.version_compare)\n\n    -- Convert to vfox format\n    local result = {}\n    for _, v in ipairs(versions) do\n        table.insert(result, { version = v })\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/hooks/post_install.lua",
    "content": "--- Extension point, called after PreInstall, compiles bfs from source\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation directory\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n\n    -- mise extracts the tarball and moves content directly to rootPath\n    -- So rootPath IS the source directory\n\n    -- Check if configure script exists (to verify we're in the right place)\n    local check_cmd = string.format('test -f \"%s/configure\"', rootPath)\n    local exists = os.execute(check_cmd)\n    if not exists then\n        error(\n            \"Could not find configure script in \" .. rootPath .. \". The source may not have been extracted correctly.\"\n        )\n    end\n\n    -- Build bfs using configure && make\n    -- RELEASE=y enables optimizations\n    local build_cmd = string.format(\n        'cd \"%s\" && ./configure RELEASE=y && make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)',\n        rootPath\n    )\n\n    print(\"Compiling bfs from source...\")\n    local result = os.execute(build_cmd)\n    if not result then\n        error(\"Failed to compile bfs. Make sure you have a C compiler (gcc/clang) and make installed.\")\n    end\n\n    -- bfs binary is built in bin/ subdirectory\n    -- Make sure it's executable\n    local binPath = rootPath .. \"/bin\"\n    os.execute(string.format('chmod +x \"%s/bfs\"', binPath))\n\n    print(\"bfs compiled successfully!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/hooks/pre_install.lua",
    "content": "--- Returns information about where to download the bfs source tarball\n--- @param ctx {version: string}  Context containing version info (The version to install)\n--- @return table Installation info including download URL\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- bfs releases source tarballs on GitHub\n    -- URL format: https://github.com/tavianator/bfs/archive/refs/tags/{version}.tar.gz\n    local url = string.format(\"https://github.com/tavianator/bfs/archive/refs/tags/%s.tar.gz\", version)\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/lib/util.lua",
    "content": "--- Utility functions for the bfs vfox plugin\n\nlocal util = {}\n\n--- Fetch content from a URL using curl\n--- @param url string The URL to fetch\n--- @return string|nil content The response body or nil on error\nfunction util.fetch(url)\n    local handle = io.popen(string.format('curl -sfL \"%s\"', url))\n    if not handle then\n        return nil\n    end\n    local content = handle:read(\"*a\")\n    handle:close()\n    if content == \"\" then\n        return nil\n    end\n    return content\nend\n\n--- Get all version tags from GitHub releases\n--- @return table versions List of version strings\nfunction util.get_versions()\n    local versions = {}\n    local url = \"https://api.github.com/repos/tavianator/bfs/tags?per_page=100\"\n    local content = util.fetch(url)\n    if not content then\n        return versions\n    end\n\n    -- Parse JSON to extract tag names (versions)\n    for tag in content:gmatch('\"name\"%s*:%s*\"([^\"]+)\"') do\n        -- bfs uses tags like \"4.0.4\", \"4.1\", etc. (no 'v' prefix)\n        if tag:match(\"^%d+%.%d+\") then\n            table.insert(versions, tag)\n        end\n    end\n\n    return versions\nend\n\n--- Compare version strings for sorting (descending - newest first)\n--- @param a string First version\n--- @param b string Second version\n--- @return boolean true if a > b\nfunction util.version_compare(a, b)\n    local function parse_version(v)\n        local parts = {}\n        for num in v:gmatch(\"(%d+)\") do\n            table.insert(parts, tonumber(num))\n        end\n        return parts\n    end\n\n    local pa = parse_version(a)\n    local pb = parse_version(b)\n\n    for i = 1, math.max(#pa, #pb) do\n        local na = pa[i] or 0\n        local nb = pb[i] or 0\n        if na ~= nb then\n            return na > nb\n        end\n    end\n    return false\nend\n\nreturn util\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bfs/metadata.lua",
    "content": "--- Plugin metadata for mise/vfox integration\nPLUGIN = {}\n\n--- Plugin name\nPLUGIN.name = \"bfs\"\n\n--- Plugin version (SemVer)\nPLUGIN.version = \"0.1.0\"\n\n--- Plugin description\nPLUGIN.description = \"A breadth-first version of the UNIX find command\"\n\n--- Minimum vfox version required\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n\n--- Repository URL\nPLUGIN.repository = \"https://github.com/mise-plugins/vfox-bfs\"\n\n--- Tool homepage\nPLUGIN.homepage = \"https://tavianator.com/projects/bfs.html\"\n\n--- License\nPLUGIN.license = \"0BSD\"\n\n--- Notes about this plugin\nPLUGIN.notes = \"Compiles from source. Requires a C compiler (gcc/clang) and make.\"\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bpkg/hooks/available.lua",
    "content": "--- Returns all available versions of bpkg from GitHub releases\n--- @param ctx table Context provided by vfox\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local result = {}\n\n    -- Get GitHub token from environment if available\n    local github_token = os.getenv(\"GITHUB_TOKEN\") or os.getenv(\"GH_TOKEN\")\n    local headers = {\n        [\"Accept\"] = \"application/vnd.github.v3+json\",\n    }\n    if github_token and github_token ~= \"\" then\n        headers[\"Authorization\"] = \"token \" .. github_token\n    end\n\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/bpkg/bpkg/tags\",\n        headers = headers,\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch versions, status: \" .. resp.status_code)\n    end\n\n    local tags = json.decode(resp.body)\n    if tags == nil then\n        return result\n    end\n\n    for _, tag in ipairs(tags) do\n        local version = tag.name\n        -- Remove 'v' prefix if present\n        if version:sub(1, 1) == \"v\" then\n            version = version:sub(2)\n        end\n        table.insert(result, {\n            version = version,\n        })\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bpkg/hooks/env_keys.lua",
    "content": "--- Returns environment keys and paths for the installed tool\n--- @param ctx table Context provided by vfox\n--- @return table Environment keys\nfunction PLUGIN:EnvKeys(ctx)\n    local mainSdk = ctx.sdkInfo[\"bpkg\"]\n    local path = mainSdk.path\n\n    return {\n        {\n            key = \"PATH\",\n            value = path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bpkg/hooks/post_install.lua",
    "content": "--- Installs bpkg by copying bash scripts to bin directory\n--- @param ctx table Context provided by vfox\nfunction PLUGIN:PostInstall(ctx)\n    local cmd = require(\"cmd\")\n\n    local sdkInfo = ctx.sdkInfo[\"bpkg\"]\n    local path = sdkInfo.path\n    local version = sdkInfo.version\n\n    -- The tarball may extract to bpkg-{version}/ or directly to path\n    -- Check which case we have\n    local srcDir = path .. \"/bpkg-\" .. version\n    local file = io.open(srcDir .. \"/bpkg.sh\", \"r\")\n    if file then\n        file:close()\n    else\n        -- Files are directly in path\n        srcDir = path\n    end\n\n    -- Create bin directory\n    cmd.exec(\"mkdir -p '\" .. path .. \"/bin'\")\n\n    -- bpkg uses symlinks to lib/ directory, so we need to:\n    -- 1. Copy the lib directory\n    -- 2. Copy the main bpkg.sh script\n    -- 3. Copy the symlinks (they point to lib/)\n\n    -- Copy lib directory\n    cmd.exec(\"cp -r '\" .. srcDir .. \"/lib' '\" .. path .. \"/bin/'\")\n\n    -- Copy main script\n    cmd.exec(\"cp -f '\" .. srcDir .. \"/bpkg.sh' '\" .. path .. \"/bin/'\")\n\n    -- Copy all symlinks (they'll still point to lib/ which we copied)\n    local scripts = {\n        \"bpkg\",\n        \"bpkg-env\",\n        \"bpkg-getdeps\",\n        \"bpkg-init\",\n        \"bpkg-install\",\n        \"bpkg-json\",\n        \"bpkg-list\",\n        \"bpkg-package\",\n        \"bpkg-run\",\n        \"bpkg-show\",\n        \"bpkg-source\",\n        \"bpkg-suggest\",\n        \"bpkg-term\",\n        \"bpkg-update\",\n        \"bpkg-utils\",\n        \"bpkg-realpath\",\n    }\n\n    for _, script in ipairs(scripts) do\n        local src = srcDir .. \"/\" .. script\n        local dst = path .. \"/bin/\" .. script\n        -- Copy symlink as symlink (-P preserves symlinks)\n        cmd.exec(\"cp -P '\" .. src .. \"' '\" .. dst .. \"' 2>/dev/null || true\")\n    end\n\n    -- Make all scripts executable\n    cmd.exec(\"chmod +x '\" .. path .. \"/bin/bpkg.sh'\")\n    cmd.exec(\"find '\" .. path .. \"/bin/lib' -name '*.sh' -exec chmod +x {} \\\\;\")\n\n    -- Verify main bpkg script was installed\n    local file = io.open(path .. \"/bin/bpkg.sh\", \"r\")\n    if file then\n        file:close()\n    else\n        error(\"Failed to install bpkg - main script not found at \" .. path .. \"/bin/bpkg.sh\")\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bpkg/hooks/pre_install.lua",
    "content": "--- Returns version information for installation\n--- @param ctx table Context provided by vfox (contains version)\n--- @return table Version info with download URL\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    if version == nil or version == \"\" then\n        error(\"You must provide a version number, eg: vfox install bpkg@1.1.3\")\n    end\n\n    -- bpkg releases don't have a 'v' prefix in the tarball URL\n    local url = \"https://github.com/bpkg/bpkg/archive/refs/tags/\" .. version .. \".tar.gz\"\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-bpkg/metadata.lua",
    "content": "--- Plugin metadata\nPLUGIN = {}\n\nPLUGIN.name = \"bpkg\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-bpkg\"\nPLUGIN.license = \"Apache-2.0\"\nPLUGIN.description = \"Lightweight bash package manager\"\nPLUGIN.notes = \"Requires bash\"\n\n--- Minimum vfox version required\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/hooks/available.lua",
    "content": "--- Returns all available versions of carthage from GitHub releases\n--- @param ctx table Context object (unused for this plugin)\n--- @return table Array of version objects with 'version' field\nfunction PLUGIN:Available(ctx)\n    local util = require(\"util\")\n    local versions = util.get_versions()\n\n    -- Sort versions (newest first)\n    table.sort(versions, util.version_compare)\n\n    -- Convert to vfox format\n    local result = {}\n    for _, v in ipairs(versions) do\n        table.insert(result, { version = v })\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/hooks/post_install.lua",
    "content": "--- Extension point, called after PreInstall, extracts carthage from .pkg\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation directory\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n\n    -- Check if we're on macOS (carthage is macOS only)\n    if RUNTIME.osType ~= \"darwin\" then\n        error(\"Carthage is only available for macOS\")\n    end\n\n    -- Find the downloaded .pkg file\n    local find_cmd = string.format('ls \"%s\"/*.pkg 2>/dev/null | head -1', rootPath)\n    local handle = io.popen(find_cmd)\n    if not handle then\n        error(\"Failed to find .pkg file\")\n    end\n    local pkg_path = handle:read(\"*l\")\n    handle:close()\n\n    if not pkg_path or pkg_path == \"\" then\n        error(\"Could not find Carthage.pkg in \" .. rootPath)\n    end\n\n    -- Create extraction directory\n    local expand_dir = rootPath .. \"/expanded\"\n    os.execute(string.format('mkdir -p \"%s\"', expand_dir))\n\n    -- Expand the .pkg file using pkgutil\n    local expand_cmd = string.format('pkgutil --expand \"%s\" \"%s\"', pkg_path, expand_dir)\n    local result = os.execute(expand_cmd)\n    if not result then\n        error(\"Failed to expand .pkg file\")\n    end\n\n    -- Find the payload and extract it\n    -- The payload is typically in CarthageApp.pkg/Payload\n    local payload_dir = expand_dir .. \"/CarthageApp.pkg\"\n    local extract_cmd = string.format('cd \"%s\" && cat Payload | gunzip | cpio -id 2>/dev/null', payload_dir)\n    result = os.execute(extract_cmd)\n    if not result then\n        error(\"Failed to extract payload from .pkg\")\n    end\n\n    -- Create bin directory and move carthage binary\n    local binDir = rootPath .. \"/bin\"\n    os.execute(string.format('mkdir -p \"%s\"', binDir))\n\n    local move_cmd = string.format('mv \"%s/usr/local/bin/carthage\" \"%s/carthage\"', payload_dir, binDir)\n    result = os.execute(move_cmd)\n    if not result then\n        error(\"Failed to move carthage binary to bin directory\")\n    end\n\n    -- Make executable and remove quarantine\n    os.execute(string.format('chmod +x \"%s/carthage\"', binDir))\n    os.execute(string.format('xattr -d com.apple.quarantine \"%s/carthage\" 2>/dev/null || true', binDir))\n\n    -- Clean up\n    os.execute(string.format('rm -rf \"%s\"', expand_dir))\n    os.execute(string.format('rm -f \"%s\"', pkg_path))\n\n    print(\"Carthage installed successfully!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/hooks/pre_install.lua",
    "content": "--- Returns information about where to download the carthage .pkg\n--- @param ctx {version: string}  Context containing version info (The version to install)\n--- @return table Installation info including download URL\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Carthage releases .pkg files on GitHub\n    local url = string.format(\"https://github.com/Carthage/Carthage/releases/download/%s/Carthage.pkg\", version)\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/lib/util.lua",
    "content": "--- Utility functions for the carthage vfox plugin\n\nlocal util = {}\n\n--- Fetch content from a URL using curl\n--- @param url string The URL to fetch\n--- @return string|nil content The response body or nil on error\nfunction util.fetch(url)\n    local handle = io.popen(string.format('curl -sfL \"%s\"', url))\n    if not handle then\n        return nil\n    end\n    local content = handle:read(\"*a\")\n    handle:close()\n    if content == \"\" then\n        return nil\n    end\n    return content\nend\n\n--- Get all version tags from GitHub releases\n--- @return table versions List of version strings\nfunction util.get_versions()\n    local versions = {}\n    local url = \"https://api.github.com/repos/Carthage/Carthage/releases?per_page=100\"\n    local content = util.fetch(url)\n    if not content then\n        return versions\n    end\n\n    -- Parse JSON to extract tag names (versions)\n    for tag in content:gmatch('\"tag_name\"%s*:%s*\"([^\"]+)\"') do\n        -- Carthage uses tags like \"0.40.0\", \"0.39.1\", etc.\n        if tag:match(\"^%d+%.%d+\") then\n            table.insert(versions, tag)\n        end\n    end\n\n    return versions\nend\n\n--- Compare version strings for sorting (descending - newest first)\n--- @param a string First version\n--- @param b string Second version\n--- @return boolean true if a > b\nfunction util.version_compare(a, b)\n    local function parse_version(v)\n        local parts = {}\n        for num in v:gmatch(\"(%d+)\") do\n            table.insert(parts, tonumber(num))\n        end\n        return parts\n    end\n\n    local pa = parse_version(a)\n    local pb = parse_version(b)\n\n    for i = 1, math.max(#pa, #pb) do\n        local na = pa[i] or 0\n        local nb = pb[i] or 0\n        if na ~= nb then\n            return na > nb\n        end\n    end\n    return false\nend\n\nreturn util\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-carthage/metadata.lua",
    "content": "--- Plugin metadata for mise/vfox integration\nPLUGIN = {}\n\n--- Plugin name\nPLUGIN.name = \"carthage\"\n\n--- Plugin version (SemVer)\nPLUGIN.version = \"0.1.0\"\n\n--- Plugin description\nPLUGIN.description = \"A simple, decentralized dependency manager for Cocoa\"\n\n--- Minimum vfox version required\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n\n--- Repository URL\nPLUGIN.repository = \"https://github.com/mise-plugins/vfox-carthage\"\n\n--- Tool homepage\nPLUGIN.homepage = \"https://github.com/Carthage/Carthage\"\n\n--- License\nPLUGIN.license = \"MIT\"\n\n--- Notes about this plugin\nPLUGIN.notes = \"macOS only. Extracts binary from .pkg installer.\"\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chezscheme/hooks/available.lua",
    "content": "local http = require(\"http\")\nlocal json = require(\"json\")\n\n--- Returns all available versions of Chez Scheme from GitHub tags.\n--- @param ctx table Context\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local results = {}\n\n    -- Fetch releases from GitHub API (tags show up as releases)\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/cisco/ChezScheme/tags?per_page=100\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch versions: HTTP \" .. resp.status_code)\n    end\n\n    local tags = json.decode(resp.body)\n\n    for _, tag in ipairs(tags) do\n        local version = tag.name\n        -- Remove 'v' prefix if present\n        if version:sub(1, 1) == \"v\" then\n            version = version:sub(2)\n        end\n        -- Only include version-like tags (e.g., 10.3.0, 9.5.8)\n        if version:match(\"^%d+%.%d+\") then\n            table.insert(results, {\n                version = version,\n                note = \"\",\n            })\n        end\n    end\n\n    return results\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chezscheme/hooks/env_keys.lua",
    "content": "--- Returns environment variables to set for this tool.\n--- @param ctx {path: string}  (Installation path)\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chezscheme/hooks/post_install.lua",
    "content": "--- Called after extraction to compile Chez Scheme from source.\n--- @param ctx table\n--- @field ctx.rootPath string Installation root path\nfunction PLUGIN:PostInstall(ctx)\n    local os_type = RUNTIME.osType\n\n    -- Windows uses the .exe installer, not source compilation\n    if os_type == \"windows\" then\n        print(\"Windows installation requires the ChezScheme.exe installer from GitHub releases\")\n        print(\"Please download and run it manually from:\")\n        print(\"https://github.com/cisco/ChezScheme/releases\")\n        return\n    end\n\n    local root_path = ctx.rootPath\n\n    -- The tarball extracts with contents at root level (no top-level directory to strip)\n    -- We need to run configure and make install\n    print(\"Compiling Chez Scheme from source...\")\n\n    -- Configure with install prefix\n    local configure_cmd = \"cd \" .. root_path .. \" && ./configure --installprefix=\" .. root_path\n    print(\"Running: \" .. configure_cmd)\n    local result = os.execute(configure_cmd)\n    if result ~= 0 and result ~= true then\n        error(\"Configure failed\")\n    end\n\n    -- Build\n    local make_cmd = \"cd \" .. root_path .. \" && make\"\n    print(\"Running: make\")\n    result = os.execute(make_cmd)\n    if result ~= 0 and result ~= true then\n        error(\"Make failed\")\n    end\n\n    -- Install to the prefix directory\n    local install_cmd = \"cd \" .. root_path .. \" && make install\"\n    print(\"Running: make install\")\n    result = os.execute(install_cmd)\n    if result ~= 0 and result ~= true then\n        error(\"Make install failed\")\n    end\n\n    -- Clean up build artifacts to save space (optional)\n    os.execute(\n        \"cd \"\n            .. root_path\n            .. \" && rm -rf boot c examples mats s unicode workarea Makefile configure LOG NOTICE 2>/dev/null\"\n    )\n\n    print(\"Chez Scheme compilation complete!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chezscheme/hooks/pre_install.lua",
    "content": "--- Called before installation to return the download URL.\n--- Chez Scheme only provides source tarballs, which need to be compiled.\n--- @param ctx {version: string}  (Version to install)\n--- @return table File info with URL\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Source tarball URL pattern: csv{version}.tar.gz\n    local url = \"https://github.com/cisco/ChezScheme/releases/download/v\" .. version .. \"/csv\" .. version .. \".tar.gz\"\n\n    return {\n        url = url,\n        version = version,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chezscheme/metadata.lua",
    "content": "PLUGIN = {}\n\nPLUGIN.name = \"chezscheme\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-chezscheme\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Chez Scheme - a programming language and implementation\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = { \"Compiles from source - requires C compiler (gcc/clang) and make\" }\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chicken/hooks/available.lua",
    "content": "--- Returns a list of available versions of CHICKEN\n--- Fetches from foldling.org/dust/ and parses the tarball filenames\n\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local resp, err = http.get({\n        url = \"https://foldling.org/dust/\",\n    })\n    if err ~= nil then\n        error(\"Failed to fetch version list: \" .. err)\n    end\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch version list: HTTP \" .. resp.status_code)\n    end\n\n    local versions = {}\n    local seen = {}\n\n    -- Parse HTML for chicken tarballs: chicken-VERSION-ARCH-OS-VARIANT.tar.gz\n    -- Only match versioned releases, not \"master\"\n    for version in resp.body:gmatch(\"chicken%-([0-9]+%.[0-9]+%.[0-9]+)%-\") do\n        if not seen[version] then\n            seen[version] = true\n            table.insert(versions, {\n                version = version,\n            })\n        end\n    end\n\n    -- Sort versions in descending order (newest first)\n    table.sort(versions, function(a, b)\n        local function parse_version(v)\n            local parts = {}\n            for num in v:gmatch(\"(%d+)\") do\n                table.insert(parts, tonumber(num))\n            end\n            return parts\n        end\n        local va = parse_version(a.version)\n        local vb = parse_version(b.version)\n        for i = 1, math.max(#va, #vb) do\n            local na = va[i] or 0\n            local nb = vb[i] or 0\n            if na ~= nb then\n                return na > nb\n            end\n        end\n        return false\n    end)\n\n    return versions\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chicken/hooks/env_keys.lua",
    "content": "--- Returns environment variables to set for CHICKEN\n--- Sets PATH to include the bin directory and library paths\n\nfunction PLUGIN:EnvKeys(ctx)\n    local file = require(\"file\")\n    local main_path = ctx.path\n    local lib_path = file.join_path(main_path, \"lib\")\n\n    return {\n        {\n            key = \"PATH\",\n            value = file.join_path(main_path, \"bin\"),\n        },\n        {\n            key = \"CHICKEN_HOME\",\n            value = main_path,\n        },\n        {\n            key = \"LD_LIBRARY_PATH\",\n            value = lib_path,\n        },\n        {\n            key = \"DYLD_LIBRARY_PATH\",\n            value = lib_path,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chicken/hooks/post_install.lua",
    "content": "--- Post-installation hook for CHICKEN\n--- Fixes library paths for macOS binaries\n\nfunction PLUGIN:PostInstall(ctx)\n    local file = require(\"file\")\n    local root_path = ctx.rootPath\n    local os_type = RUNTIME.osType\n\n    -- On macOS, we need to fix up library paths using install_name_tool\n    if os_type == \"darwin\" then\n        local lib_path = file.join_path(root_path, \"lib\")\n        local bin_path = file.join_path(root_path, \"bin\")\n        local libchicken = file.join_path(lib_path, \"libchicken.dylib\")\n\n        -- Create a shell script to fix library paths\n        local script = string.format(\n            [[\n#!/bin/bash\nset -e\nLIB=\"%s\"\nBIN=\"%s\"\n\n# Fix the library's own id\ninstall_name_tool -id \"$LIB/libchicken.dylib\" \"$LIB/libchicken.dylib\" 2>/dev/null || true\n\n# Fix all binaries\nfor bin in chicken csc csi chicken-install chicken-uninstall chicken-status chicken-profile chicken-do feathers; do\n    if [ -f \"$BIN/$bin\" ]; then\n        # Get the old library path (the xxx placeholder)\n        OLD_PATH=$(otool -L \"$BIN/$bin\" 2>/dev/null | grep libchicken | head -1 | awk '{print $1}')\n        if [ -n \"$OLD_PATH\" ]; then\n            install_name_tool -change \"$OLD_PATH\" \"$LIB/libchicken.dylib\" \"$BIN/$bin\" 2>/dev/null || true\n        fi\n    fi\ndone\n]],\n            lib_path,\n            bin_path\n        )\n\n        -- Write and execute the script\n        local script_path = root_path .. \"/fix_libs.sh\"\n        local f = io.open(script_path, \"w\")\n        if f then\n            f:write(script)\n            f:close()\n            os.execute(\"chmod +x \" .. script_path .. \" && \" .. script_path)\n            os.execute(\"rm -f \" .. script_path)\n        end\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chicken/hooks/pre_install.lua",
    "content": "--- Returns information about the version to install\n--- Constructs the download URL based on OS and architecture\n\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    local os_type = RUNTIME.osType\n    local arch_type = RUNTIME.archType\n\n    -- Map OS and arch to the filename components\n    -- Pattern: chicken-VERSION-ARCH-OS-VARIANT.tar.gz\n    local arch, os_name, variant\n\n    if os_type == \"darwin\" then\n        if arch_type ~= \"amd64\" then\n            error(\"CHICKEN only has x86_64 binaries for macOS. ARM64 is not supported.\")\n        end\n        arch = \"x86_64\"\n        os_name = \"macosx\"\n        variant = \"macosx\"\n    elseif os_type == \"linux\" then\n        if arch_type ~= \"amd64\" then\n            error(\"CHICKEN only has x86_64 binaries for Linux. ARM64 is not supported.\")\n        end\n        arch = \"x86_64\"\n        os_name = \"linux\"\n        variant = \"gnu\" -- Use GNU libc version by default\n    elseif os_type == \"freebsd\" then\n        if arch_type ~= \"amd64\" then\n            error(\"CHICKEN only has amd64 binaries for FreeBSD.\")\n        end\n        arch = \"amd64\"\n        os_name = \"bsd\"\n        variant = \"freebsd\"\n    elseif os_type == \"openbsd\" then\n        if arch_type ~= \"amd64\" then\n            error(\"CHICKEN only has amd64 binaries for OpenBSD.\")\n        end\n        arch = \"amd64\"\n        os_name = \"bsd\"\n        variant = \"openbsd\"\n    else\n        error(\"Unsupported operating system: \" .. os_type)\n    end\n\n    local filename = string.format(\"chicken-%s-%s-%s-%s.tar.gz\", version, arch, os_name, variant)\n    local url = \"https://foldling.org/dust/\" .. filename\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chicken/metadata.lua",
    "content": "--- Metadata for the CHICKEN Scheme plugin\n--- CHICKEN is a compiler for the Scheme programming language\n--- https://call-cc.org/\n\nPLUGIN = {\n    name = \"chicken\",\n    version = \"0.1.0\",\n    description = \"CHICKEN Scheme compiler\",\n    homepage = \"https://call-cc.org/\",\n    license = \"BSD\",\n    minRuntimeVersion = \"0.3.0\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chromedriver/hooks/available.lua",
    "content": "--- Returns all available versions of chromedriver from Google's API\n--- @param ctx table Context provided by vfox\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local result = {}\n\n    local resp, err = http.get({\n        url = \"https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json\",\n        headers = {\n            [\"Accept\"] = \"application/json\",\n        },\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch versions, status: \" .. resp.status_code)\n    end\n\n    local data = json.decode(resp.body)\n    if data == nil or data.versions == nil then\n        return result\n    end\n\n    -- Collect versions that have chromedriver downloads\n    for _, v in ipairs(data.versions) do\n        if v.downloads and v.downloads.chromedriver then\n            table.insert(result, {\n                version = v.version,\n            })\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chromedriver/hooks/env_keys.lua",
    "content": "--- Returns environment keys and paths for the installed tool\n--- @param ctx table Context provided by vfox\n--- @return table Environment keys\nfunction PLUGIN:EnvKeys(ctx)\n    local mainSdk = ctx.sdkInfo[\"chromedriver\"]\n    local path = mainSdk.path\n\n    return {\n        {\n            key = \"PATH\",\n            value = path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chromedriver/hooks/post_install.lua",
    "content": "--- Installs chromedriver by moving binary to bin directory\n--- @param ctx table Context provided by vfox\nfunction PLUGIN:PostInstall(ctx)\n    local cmd = require(\"cmd\")\n\n    local sdkInfo = ctx.sdkInfo[\"chromedriver\"]\n    local path = sdkInfo.path\n    local version = sdkInfo.version\n\n    -- Create bin directory\n    cmd.exec(\"mkdir -p '\" .. path .. \"/bin'\")\n\n    -- Determine platform suffix for the extracted directory using RUNTIME global\n    local osType = RUNTIME.osType\n    local archType = RUNTIME.archType\n    local platform = \"\"\n\n    if osType == \"darwin\" then\n        if archType == \"arm64\" then\n            platform = \"mac-arm64\"\n        else\n            platform = \"mac-x64\"\n        end\n    elseif osType == \"linux\" then\n        platform = \"linux64\"\n    elseif osType == \"windows\" then\n        if archType == \"amd64\" or archType == \"x86_64\" then\n            platform = \"win64\"\n        else\n            platform = \"win32\"\n        end\n    end\n\n    -- The zip extracts to chromedriver-{platform}/\n    local srcDir = path .. \"/chromedriver-\" .. platform\n\n    -- Check if srcDir exists, if not try without subdirectory\n    local file = io.open(srcDir .. \"/chromedriver\", \"r\")\n    if file then\n        file:close()\n    else\n        -- Try direct path (files extracted directly)\n        srcDir = path\n    end\n\n    -- Copy chromedriver binary\n    if osType == \"windows\" then\n        cmd.exec(\"cp -f '\" .. srcDir .. \"/chromedriver.exe' '\" .. path .. \"/bin/'\")\n    else\n        cmd.exec(\"cp -f '\" .. srcDir .. \"/chromedriver' '\" .. path .. \"/bin/'\")\n        cmd.exec(\"chmod +x '\" .. path .. \"/bin/chromedriver'\")\n    end\n\n    -- Verify installation\n    local binaryName = osType == \"windows\" and \"chromedriver.exe\" or \"chromedriver\"\n    local verifyFile = io.open(path .. \"/bin/\" .. binaryName, \"r\")\n    if verifyFile then\n        verifyFile:close()\n    else\n        error(\"Failed to install chromedriver - binary not found at \" .. path .. \"/bin/\" .. binaryName)\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chromedriver/hooks/pre_install.lua",
    "content": "--- Returns version information for installation\n--- @param ctx table Context provided by vfox (contains version)\n--- @return table Version info with download URL\nfunction PLUGIN:PreInstall(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local version = ctx.version\n\n    if version == nil or version == \"\" then\n        error(\"You must provide a version number, eg: vfox install chromedriver@131.0.6778.0\")\n    end\n\n    -- Determine platform using RUNTIME global\n    local osType = RUNTIME.osType\n    local archType = RUNTIME.archType\n    local platform = \"\"\n\n    if osType == \"darwin\" then\n        if archType == \"arm64\" then\n            platform = \"mac-arm64\"\n        else\n            platform = \"mac-x64\"\n        end\n    elseif osType == \"linux\" then\n        platform = \"linux64\"\n    elseif osType == \"windows\" then\n        if archType == \"amd64\" or archType == \"x86_64\" then\n            platform = \"win64\"\n        else\n            platform = \"win32\"\n        end\n    else\n        error(\"Unsupported OS: \" .. osType)\n    end\n\n    -- Fetch the versions JSON to get the download URL\n    local resp, err = http.get({\n        url = \"https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json\",\n        headers = {\n            [\"Accept\"] = \"application/json\",\n        },\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch versions, status: \" .. resp.status_code)\n    end\n\n    local data = json.decode(resp.body)\n    if data == nil or data.versions == nil then\n        error(\"Failed to parse versions JSON\")\n    end\n\n    -- Find the version and platform URL\n    local downloadUrl = nil\n    for _, v in ipairs(data.versions) do\n        if v.version == version and v.downloads and v.downloads.chromedriver then\n            for _, d in ipairs(v.downloads.chromedriver) do\n                if d.platform == platform then\n                    downloadUrl = d.url\n                    break\n                end\n            end\n            break\n        end\n    end\n\n    if downloadUrl == nil then\n        error(\"Could not find chromedriver \" .. version .. \" for platform \" .. platform)\n    end\n\n    return {\n        version = version,\n        url = downloadUrl,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-chromedriver/metadata.lua",
    "content": "--- Plugin metadata\nPLUGIN = {}\n\nPLUGIN.name = \"chromedriver\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-chromedriver\"\nPLUGIN.license = \"Apache-2.0\"\nPLUGIN.description = \"ChromeDriver - WebDriver for Chrome\"\n\n--- Minimum vfox version required\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/hooks/available.lua",
    "content": "--- Returns all available versions of clickhouse from GitHub releases\n--- @param ctx table Context object (unused for this plugin)\n--- @return table Array of version objects with 'version' field\nfunction PLUGIN:Available(ctx)\n    local util = require(\"util\")\n    local versions = util.get_versions()\n\n    -- Sort versions (newest first)\n    table.sort(versions, util.version_compare)\n\n    -- Convert to vfox format\n    local result = {}\n    for _, v in ipairs(versions) do\n        table.insert(result, { version = v })\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    return {\n        {\n            key = \"PATH\",\n            value = ctx.path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/hooks/post_install.lua",
    "content": "--- Extension point, called after PreInstall, sets up clickhouse binary\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation directory\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n    local binDir = rootPath .. \"/bin\"\n\n    -- Create bin directory\n    os.execute(string.format('mkdir -p \"%s\"', binDir))\n\n    if RUNTIME.osType == \"darwin\" then\n        -- macOS: single binary file was downloaded\n        -- Find the downloaded binary (clickhouse-macos or clickhouse-macos-aarch64)\n        local find_cmd = string.format('ls \"%s\"/clickhouse-macos* 2>/dev/null | head -1', rootPath)\n        local handle = io.popen(find_cmd)\n        if not handle then\n            error(\"Failed to find clickhouse binary\")\n        end\n        local binary_path = handle:read(\"*l\")\n        handle:close()\n\n        if not binary_path or binary_path == \"\" then\n            error(\"Could not find clickhouse-macos binary in \" .. rootPath)\n        end\n\n        -- Move and rename to bin/clickhouse\n        local move_cmd = string.format('mv \"%s\" \"%s/clickhouse\"', binary_path, binDir)\n        local result = os.execute(move_cmd)\n        if not result then\n            error(\"Failed to move clickhouse binary\")\n        end\n\n        -- Make executable and remove quarantine\n        os.execute(string.format('chmod +x \"%s/clickhouse\"', binDir))\n        os.execute(string.format('xattr -d com.apple.quarantine \"%s/clickhouse\" 2>/dev/null || true', binDir))\n    else\n        -- Linux: tarball was extracted\n        -- The tarball extracts to usr/bin/clickhouse\n        local src_binary = rootPath .. \"/usr/bin/clickhouse\"\n\n        -- Check if binary exists at expected location\n        local check_cmd = string.format('test -f \"%s\"', src_binary)\n        if not os.execute(check_cmd) then\n            -- Try alternate location\n            src_binary = rootPath .. \"/clickhouse\"\n            check_cmd = string.format('test -f \"%s\"', src_binary)\n            if not os.execute(check_cmd) then\n                error(\"Could not find clickhouse binary after extraction\")\n            end\n        end\n\n        -- Move binary to bin/\n        local move_cmd = string.format('mv \"%s\" \"%s/clickhouse\"', src_binary, binDir)\n        local result = os.execute(move_cmd)\n        if not result then\n            -- Try copying instead\n            move_cmd = string.format('cp \"%s\" \"%s/clickhouse\"', src_binary, binDir)\n            result = os.execute(move_cmd)\n            if not result then\n                error(\"Failed to copy clickhouse binary to bin/\")\n            end\n        end\n\n        -- Make executable\n        os.execute(string.format('chmod +x \"%s/clickhouse\"', binDir))\n\n        -- Clean up extracted directories\n        os.execute(\n            string.format('rm -rf \"%s/usr\" \"%s/install\" \"%s/etc\" 2>/dev/null || true', rootPath, rootPath, rootPath)\n        )\n    end\n\n    -- Create symlinks for clickhouse subcommands\n    local symlinks = {\n        \"clickhouse-client\",\n        \"clickhouse-server\",\n        \"clickhouse-local\",\n        \"clickhouse-benchmark\",\n        \"clickhouse-compressor\",\n        \"clickhouse-format\",\n        \"clickhouse-obfuscator\",\n    }\n\n    for _, link in ipairs(symlinks) do\n        os.execute(string.format('ln -sf clickhouse \"%s/%s\" 2>/dev/null || true', binDir, link))\n    end\n\n    print(\"ClickHouse installed successfully!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/hooks/pre_install.lua",
    "content": "--- Returns information about where to download clickhouse\n--- @param ctx {version: string}  Context containing version info (The version to install)\n--- @return table Installation info including download URL\nfunction PLUGIN:PreInstall(ctx)\n    local util = require(\"util\")\n    local version = ctx.version\n    local arch = util.get_arch()\n    local trimmed_version = util.trim_version_suffix(version)\n    local url\n\n    if RUNTIME.osType == \"darwin\" then\n        -- macOS: single binary file\n        -- clickhouse-macos (x86_64) or clickhouse-macos-aarch64 (arm64)\n        if arch == \"arm64\" then\n            url = string.format(\n                \"https://github.com/ClickHouse/ClickHouse/releases/download/v%s/clickhouse-macos-aarch64\",\n                version\n            )\n        else\n            url = string.format(\n                \"https://github.com/ClickHouse/ClickHouse/releases/download/v%s/clickhouse-macos\",\n                version\n            )\n        end\n    else\n        -- Linux: tarball\n        -- clickhouse-common-static-{trimmed_version}-{arch}.tgz\n        url = string.format(\n            \"https://github.com/ClickHouse/ClickHouse/releases/download/v%s/clickhouse-common-static-%s-%s.tgz\",\n            version,\n            trimmed_version,\n            arch\n        )\n    end\n\n    return {\n        version = version,\n        url = url,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/lib/util.lua",
    "content": "--- Utility functions for the clickhouse vfox plugin\n\nlocal util = {}\n\n--- Fetch content from a URL using curl\n--- @param url string The URL to fetch\n--- @return string|nil content The response body or nil on error\nfunction util.fetch(url)\n    local handle = io.popen(string.format('curl -sfL \"%s\"', url))\n    if not handle then\n        return nil\n    end\n    local content = handle:read(\"*a\")\n    handle:close()\n    if content == \"\" then\n        return nil\n    end\n    return content\nend\n\n--- Get all version tags from GitHub releases (only lts and stable)\n--- @return table versions List of version strings\nfunction util.get_versions()\n    local versions = {}\n    local url = \"https://api.github.com/repos/ClickHouse/ClickHouse/releases?per_page=100\"\n    local content = util.fetch(url)\n    if not content then\n        return versions\n    end\n\n    -- Parse JSON to extract tag names (versions)\n    for tag in content:gmatch('\"tag_name\"%s*:%s*\"v([^\"]+)\"') do\n        -- Only include lts and stable releases\n        if tag:match(\"%-lts$\") or tag:match(\"%-stable$\") then\n            table.insert(versions, tag)\n        end\n    end\n\n    return versions\nend\n\n--- Compare version strings for sorting (descending - newest first)\n--- @param a string First version\n--- @param b string Second version\n--- @return boolean true if a > b\nfunction util.version_compare(a, b)\n    local function parse_version(v)\n        local parts = {}\n        for num in v:gmatch(\"(%d+)\") do\n            table.insert(parts, tonumber(num))\n        end\n        return parts\n    end\n\n    local pa = parse_version(a)\n    local pb = parse_version(b)\n\n    for i = 1, math.max(#pa, #pb) do\n        local na = pa[i] or 0\n        local nb = pb[i] or 0\n        if na ~= nb then\n            return na > nb\n        end\n    end\n    return false\nend\n\n--- Get architecture string\n--- @return string arch Architecture (amd64 or arm64)\nfunction util.get_arch()\n    local handle = io.popen(\"uname -m\")\n    if not handle then\n        return \"amd64\"\n    end\n    local arch = handle:read(\"*l\")\n    handle:close()\n\n    if arch == \"x86_64\" or arch == \"amd64\" then\n        return \"amd64\"\n    elseif arch == \"aarch64\" or arch == \"arm64\" then\n        return \"arm64\"\n    end\n    return \"amd64\"\nend\n\n--- Trim version suffix (remove -lts, -stable, -prestable)\n--- @param version string The version string\n--- @return string trimmed The trimmed version\nfunction util.trim_version_suffix(version)\n    local trimmed = version:gsub(\"%-lts$\", \"\")\n    trimmed = trimmed:gsub(\"%-stable$\", \"\")\n    trimmed = trimmed:gsub(\"%-prestable$\", \"\")\n    return trimmed\nend\n\nreturn util\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-clickhouse/metadata.lua",
    "content": "--- Plugin metadata for mise/vfox integration\nPLUGIN = {}\n\n--- Plugin name\nPLUGIN.name = \"clickhouse\"\n\n--- Plugin version (SemVer)\nPLUGIN.version = \"0.1.0\"\n\n--- Plugin description\nPLUGIN.description = \"ClickHouse - fast open-source column-oriented database management system\"\n\n--- Minimum vfox version required\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n\n--- Repository URL\nPLUGIN.repository = \"https://github.com/mise-plugins/vfox-clickhouse\"\n\n--- Tool homepage\nPLUGIN.homepage = \"https://clickhouse.com\"\n\n--- License\nPLUGIN.license = \"Apache-2.0\"\n\n--- Notes about this plugin\nPLUGIN.notes = \"Installs the ClickHouse server and client binaries.\"\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-gcloud/hooks/available.lua",
    "content": "--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\n\nlocal http = require(\"http\")\nlocal json = require(\"json\")\n\n-- GCS bucket configuration\nlocal GCS_BUCKET = \"cloud-sdk-release\"\nlocal GCS_PREFIX = \"google-cloud-sdk\"\nlocal GCS_API_URL = \"https://storage.googleapis.com/storage/v1/b/\" .. GCS_BUCKET .. \"/o\"\n\n-- Cache for versions\nlocal available_versions = nil\n\n--- Fetch versions from GCS with pagination\nlocal function fetch_versions()\n    local versions = {}\n    local seen = {}\n    local page_token = nil\n\n    repeat\n        -- Build URL with query parameters\n        local url = GCS_API_URL .. \"?prefix=\" .. GCS_PREFIX .. \"&fields=kind,nextPageToken,items(name)\"\n        if page_token then\n            url = url .. \"&pageToken=\" .. page_token\n        end\n\n        -- Fetch page\n        local resp, err = http.get({\n            url = url,\n        })\n\n        if err ~= nil or resp.status_code ~= 200 then\n            error(\"Failed to fetch versions from GCS: \" .. (err or \"status \" .. resp.status_code))\n        end\n\n        local data = json.decode(resp.body)\n\n        -- Extract versions from object names\n        -- Pattern: google-cloud-sdk-{version}-linux-x86_64.tar.gz\n        for _, item in ipairs(data.items or {}) do\n            local name = item.name\n            local version = string.match(name, \"^google%-cloud%-sdk%-([%d%.]+)%-linux%-x86_64%.tar%.gz$\")\n            if version and not seen[version] then\n                seen[version] = true\n                table.insert(versions, version)\n            end\n        end\n\n        page_token = data.nextPageToken\n    until page_token == nil\n\n    return versions\nend\n\n--- Compare version strings for sorting\nlocal function compare_versions(a, b)\n    local function parse_version(v)\n        local parts = {}\n        for part in string.gmatch(v, \"([^%.]+)\") do\n            table.insert(parts, tonumber(part) or 0)\n        end\n        return parts\n    end\n\n    local va = parse_version(a)\n    local vb = parse_version(b)\n\n    for i = 1, math.max(#va, #vb) do\n        local na = va[i] or 0\n        local nb = vb[i] or 0\n        if na ~= nb then\n            return na > nb\n        end\n    end\n    return false\nend\n\nfunction PLUGIN:Available(ctx)\n    -- Use cached versions if available\n    if available_versions ~= nil then\n        return available_versions\n    end\n\n    local versions = fetch_versions()\n\n    -- Sort versions in descending order (newest first) to match vfox conventions\n    table.sort(versions, compare_versions)\n\n    -- Build result table\n    local result = {}\n    for _, version in ipairs(versions) do\n        table.insert(result, {\n            version = version,\n            note = \"\",\n        })\n    end\n\n    available_versions = result\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-gcloud/hooks/env_keys.lua",
    "content": "--- Return environment variables for the tool\n--- @param ctx {path: string}  Context information (SDK installation directory)\n--- @return table Environment variables\n\nlocal file = require(\"file\")\n\nfunction PLUGIN:EnvKeys(ctx)\n    local version_path = ctx.path\n\n    -- The SDK extracts directly to the version path\n    local bin_path = file.join_path(version_path, \"bin\")\n\n    return {\n        {\n            key = \"PATH\",\n            value = bin_path,\n        },\n        {\n            key = \"CLOUDSDK_ROOT_DIR\",\n            value = version_path,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-gcloud/hooks/post_install.lua",
    "content": "--- Called after the tool is installed\n--- @param ctx table Context information\n--- @field ctx.rootPath string The installation directory\n\nlocal file = require(\"file\")\n\n--- Compare version strings\n--- Returns true if v1 >= v2\nlocal function version_gte(v1, v2)\n    local function parse_version(v)\n        local parts = {}\n        for part in string.gmatch(v, \"([^%.]+)\") do\n            table.insert(parts, tonumber(part) or 0)\n        end\n        return parts\n    end\n\n    local va = parse_version(v1)\n    local vb = parse_version(v2)\n\n    for i = 1, math.max(#va, #vb) do\n        local na = va[i] or 0\n        local nb = vb[i] or 0\n        if na > nb then\n            return true\n        elseif na < nb then\n            return false\n        end\n    end\n    return true\nend\n\nfunction PLUGIN:PostInstall(ctx)\n    local sdkInfo = ctx.sdkInfo[PLUGIN.name]\n    local root_path = sdkInfo.path\n    local version = sdkInfo.version or \"\"\n\n    -- The SDK extracts directly to the root path\n    local sdk_path = root_path\n    local install_script = file.join_path(sdk_path, \"install.sh\")\n\n    -- Check if install script exists\n    if not file.exists(install_script) then\n        -- On Windows, use install.bat\n        if RUNTIME.osType == \"windows\" or RUNTIME.osType == \"Windows\" then\n            install_script = file.join_path(sdk_path, \"install.bat\")\n        end\n    end\n\n    if not file.exists(install_script) then\n        -- Some versions might not have an install script, skip silently\n        return\n    end\n\n    -- Build install command arguments\n    local args = {\n        \"--usage-reporting\",\n        \"false\",\n        \"--path-update\",\n        \"false\",\n        \"--quiet\",\n    }\n\n    -- For versions >= 352.0.0, disable Python installation\n    -- (gcloud bundles its own Python in newer versions)\n    if version ~= \"\" and version_gte(version, \"352.0.0\") then\n        table.insert(args, \"--install-python\")\n        table.insert(args, \"false\")\n    end\n\n    -- Run the install script\n    local cmd_str\n    if RUNTIME.osType == \"windows\" or RUNTIME.osType == \"Windows\" then\n        cmd_str = '\"' .. install_script .. '\" ' .. table.concat(args, \" \")\n    else\n        cmd_str = 'sh \"' .. install_script .. '\" ' .. table.concat(args, \" \")\n    end\n\n    local status = os.execute(cmd_str)\n    if status ~= 0 and status ~= true then\n        error(\"Failed to run gcloud install script\")\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-gcloud/hooks/pre_install.lua",
    "content": "--- Return the pre-installation information including download URL\n--- @param ctx {version: string}  Context information (Version to install)\n--- @return table Version information with download URL\n\nlocal http = require(\"http\")\n\n-- GCS bucket configuration\nlocal GCS_BUCKET = \"cloud-sdk-release\"\nlocal BASE_URL = \"https://storage.googleapis.com/\" .. GCS_BUCKET\n\n--- Get OS name for download URL\nlocal function get_os_name()\n    local os_type = RUNTIME.osType\n    if os_type == \"darwin\" or os_type == \"Darwin\" then\n        return \"darwin\"\n    elseif os_type == \"linux\" or os_type == \"Linux\" then\n        return \"linux\"\n    elseif os_type == \"windows\" or os_type == \"Windows\" then\n        return \"windows\"\n    else\n        error(\"Unsupported operating system: \" .. os_type)\n    end\nend\n\n--- Get architecture name for download URL\nlocal function get_arch_name()\n    local arch_type = RUNTIME.archType\n    local os_name = get_os_name()\n\n    if arch_type == \"amd64\" or arch_type == \"x86_64\" then\n        return \"x86_64\"\n    elseif arch_type == \"arm64\" or arch_type == \"aarch64\" then\n        -- macOS uses arm64, Linux uses aarch64\n        if os_name == \"darwin\" then\n            return \"arm\"\n        else\n            return \"arm\"\n        end\n    elseif arch_type == \"386\" or arch_type == \"x86\" then\n        return \"x86\"\n    else\n        error(\"Unsupported architecture: \" .. arch_type)\n    end\nend\n\n--- Get file extension based on OS\nlocal function get_extension()\n    local os_name = get_os_name()\n    if os_name == \"windows\" then\n        return \".zip\"\n    else\n        return \".tar.gz\"\n    end\nend\n\n--- Build the download filename\nlocal function build_filename(version)\n    local os_name = get_os_name()\n    local arch_name = get_arch_name()\n    local ext = get_extension()\n\n    -- Format: google-cloud-sdk-{version}-{os}-{arch}.tar.gz\n    -- For bundled Python (recommended): google-cloud-sdk-{version}-{os}-{arch}-bundled-python.tar.gz\n    return \"google-cloud-sdk-\" .. version .. \"-\" .. os_name .. \"-\" .. arch_name .. ext\nend\n\n--- Fetch SHA256 checksum for the file\nlocal function fetch_checksum(filename)\n    -- Google provides checksums at a .sha256 file\n    local checksum_url = BASE_URL .. \"/\" .. filename .. \".sha256\"\n\n    local resp, err = http.get({\n        url = checksum_url,\n    })\n\n    if err ~= nil or resp.status_code ~= 200 then\n        -- Checksum file might not exist for all versions\n        return nil\n    end\n\n    -- The file contains just the hash\n    local hash = string.match(resp.body, \"^(%x+)\")\n    return hash\nend\n\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    local filename = build_filename(version)\n    local url = BASE_URL .. \"/\" .. filename\n\n    -- Verify the file exists\n    local resp, err = http.head({\n        url = url,\n    })\n\n    if err ~= nil or resp.status_code == 404 then\n        error(\"Version \" .. version .. \" not found for this platform. URL: \" .. url)\n    end\n\n    -- Try to fetch checksum\n    local checksum = fetch_checksum(filename)\n\n    local result = {\n        version = version,\n        url = url,\n    }\n\n    if checksum then\n        result.sha256 = checksum\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-gcloud/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"gcloud\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-gcloud\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Google Cloud SDK (gcloud CLI)\"\n\n--- !!! OPTIONAL !!!\n--- Minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n--- Some things that need user attention\nPLUGIN.notes = {\n    \"After installation, you may need to run 'gcloud init' to configure your account.\",\n    \"Additional components can be installed with 'gcloud components install <component>'.\",\n}\n\n--- Legacy configuration filenames for determining tool version\nPLUGIN.legacyFilenames = {}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-leiningen/hooks/available.lua",
    "content": "--- Returns all available versions of Leiningen\n--- @param ctx table Context object\n--- @return table Array of version objects with version and optional note fields\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/technomancy/leiningen/releases\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch Leiningen releases: \" .. err)\n    end\n\n    local releases, err = json.decode(resp.body)\n    if err ~= nil then\n        error(\"Failed to parse releases JSON: \" .. err)\n    end\n\n    local results = {}\n\n    for _, release in ipairs(releases) do\n        local version = release.tag_name\n        if version then\n            table.insert(results, {\n                version = version,\n                note = release.prerelease and \"prerelease\" or \"\",\n            })\n        end\n    end\n\n    return results\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-leiningen/hooks/env_keys.lua",
    "content": "--- Returns environment variables to set\n--- @param ctx table Context object with path field (install directory)\n--- @return table Array of environment variable definitions\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n\n    return {\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\",\n        },\n        {\n            key = \"LEIN_HOME\",\n            value = mainPath,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-leiningen/hooks/post_install.lua",
    "content": "--- Post-install hook to set up Leiningen\n--- Downloads the lein script and organizes files properly\n--- @param ctx table Context object with rootPath field\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n    local http = require(\"http\")\n\n    -- Extract version from rootPath (e.g., /path/to/installs/leiningen/2.12.0)\n    local version = rootPath:match(\"([^/\\\\]+)$\")\n    if not version then\n        error(\"Could not extract version from rootPath: \" .. rootPath)\n    end\n\n    -- Create directory structure\n    local binDir = rootPath .. \"/bin\"\n    local selfInstallDir = rootPath .. \"/self-installs\"\n\n    os.execute('mkdir -p \"' .. binDir .. '\"')\n    os.execute('mkdir -p \"' .. selfInstallDir .. '\"')\n\n    -- Move the downloaded JAR to self-installs directory\n    local jarName = \"leiningen-\" .. version .. \"-standalone.jar\"\n    local sourceJar = rootPath .. \"/\" .. jarName\n    local destJar = selfInstallDir .. \"/\" .. jarName\n\n    -- The JAR might be at rootPath directly or we need to find it\n    local moveCmd = string.format(\n        'mv \"%s\" \"%s\" 2>/dev/null || find \"%s\" -name \"*.jar\" -exec mv {} \"%s\" \\\\;',\n        sourceJar,\n        destJar,\n        rootPath,\n        destJar\n    )\n    os.execute(moveCmd)\n\n    -- Download the lein script\n    print(\"Downloading lein script...\")\n    local resp, err = http.get({\n        url = \"https://raw.githubusercontent.com/technomancy/leiningen/\" .. version .. \"/bin/lein\",\n    })\n\n    if err ~= nil then\n        -- Try stable branch as fallback\n        resp, err = http.get({\n            url = \"https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein\",\n        })\n        if err ~= nil then\n            error(\"Failed to download lein script: \" .. err)\n        end\n    end\n\n    -- Write the lein script\n    local leinPath = binDir .. \"/lein\"\n    local f = io.open(leinPath, \"w\")\n    if f then\n        f:write(resp.body)\n        f:close()\n    else\n        error(\"Failed to write lein script\")\n    end\n\n    -- Make it executable\n    os.execute('chmod +x \"' .. leinPath .. '\"')\n\n    -- Clean up any remaining files in root that aren't needed\n    os.execute('rm -f \"' .. rootPath .. '\"/*.jar 2>/dev/null')\n\n    print(\"Leiningen \" .. version .. \" installed successfully!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-leiningen/hooks/pre_install.lua",
    "content": "--- Returns download information for a specific version\n--- @param ctx table Context object with version field\n--- @return table Download info with version and url fields\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    return {\n        version = version,\n        url = \"https://github.com/technomancy/leiningen/releases/download/\"\n            .. version\n            .. \"/leiningen-\"\n            .. version\n            .. \"-standalone.jar\",\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-leiningen/metadata.lua",
    "content": "PLUGIN = {}\n\nPLUGIN.name = \"leiningen\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-leiningen\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Leiningen - automating Clojure projects without setting your hair on fire\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Requires Java to be installed\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-lua/hooks/available.lua",
    "content": "--- Returns all available Lua versions from lua.org\n--- @param ctx table Context provided by vfox\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n\n    local result = {}\n    local seen = {}\n\n    -- Fetch the Lua FTP page\n    local resp, err = http.get({\n        url = \"https://www.lua.org/ftp/\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch Lua versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch Lua versions, status: \" .. resp.status_code)\n    end\n\n    -- Parse HTML to extract lua-X.Y.Z.tar.gz filenames\n    -- Pattern matches: lua-5.4.8.tar.gz, lua-5.1.tar.gz, etc.\n    for version in string.gmatch(resp.body, \"lua%-(%d+%.%d+[%.%d]*).tar.gz\") do\n        if not seen[version] then\n            seen[version] = true\n            table.insert(result, {\n                version = version,\n            })\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-lua/hooks/env_keys.lua",
    "content": "--- Returns environment variables for Lua\n--- @param ctx table Context provided by vfox\n--- @return table Environment configuration\nfunction PLUGIN:EnvKeys(ctx)\n    local sdkInfo = ctx.sdkInfo[\"lua\"]\n    local version = sdkInfo.version\n    local installDir = sdkInfo.path\n\n    -- Extract major.minor version for Lua paths\n    local shortVersion = string.match(version, \"^(%d+%.%d+)\")\n\n    local envs = {\n        {\n            key = \"PATH\",\n            value = installDir .. \"/bin\",\n        },\n    }\n\n    -- Add LuaRocks bin to PATH if it exists\n    local luarocksBin = installDir .. \"/luarocks/bin\"\n    local f = io.open(luarocksBin, \"r\")\n    if f ~= nil then\n        f:close()\n        table.insert(envs, {\n            key = \"PATH\",\n            value = luarocksBin,\n        })\n    end\n\n    -- Set LUA_INIT for package paths (similar to asdf-lua)\n    if shortVersion then\n        local packagePath = string.format(\n            \"package.path = package.path .. ';%s/share/lua/%s/?.lua;%s/share/lua/%s/?/init.lua;%s/luarocks/share/lua/%s/?.lua;%s/luarocks/share/lua/%s/?/init.lua'\",\n            installDir,\n            shortVersion,\n            installDir,\n            shortVersion,\n            installDir,\n            shortVersion,\n            installDir,\n            shortVersion\n        )\n        local packageCpath = string.format(\n            \"package.cpath = package.cpath .. ';%s/lib/lua/%s/?.so;%s/luarocks/lib/lua/%s/?.so'\",\n            installDir,\n            shortVersion,\n            installDir,\n            shortVersion\n        )\n\n        table.insert(envs, {\n            key = \"LUA_INIT\",\n            value = packagePath .. \"\\n\" .. packageCpath,\n        })\n    end\n\n    return envs\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-lua/hooks/post_install.lua",
    "content": "--- Compiles and installs Lua from source\n--- @param ctx table Context provided by vfox\n--- @field ctx.sdkInfo table SDK information with version and path\nfunction PLUGIN:PostInstall(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local sdkInfo = ctx.sdkInfo[\"lua\"]\n    local version = sdkInfo.version\n    local sdkPath = sdkInfo.path\n\n    -- mise extracts tarball and strips top-level directory, so sdkPath IS the source directory\n\n    -- Determine OS-specific make target\n    local os_type = RUNTIME.osType\n    local make_target = \"guess\"\n\n    if os_type == \"darwin\" then\n        make_target = \"macosx\"\n    elseif os_type == \"linux\" then\n        -- For Lua < 5.4, use \"linux\", otherwise \"guess\"\n        local major, minor = string.match(version, \"^(%d+)%.(%d+)\")\n        if major and minor then\n            local ver_num = tonumber(major) * 100 + tonumber(minor)\n            if ver_num < 504 then\n                make_target = \"linux\"\n            end\n        end\n    end\n\n    -- Build Lua\n    local major = tonumber(string.match(version, \"^(%d+)\"))\n    local buildCmd\n\n    if major and major >= 5 then\n        -- Lua 5.x: use make local target which creates install/ subdirectory\n        buildCmd = string.format(\"cd '%s' && make %s && make local\", sdkPath, make_target)\n    else\n        -- Older versions\n        buildCmd = string.format(\"cd '%s' && make && make install INSTALL_ROOT=install\", sdkPath)\n    end\n\n    local status = os.execute(buildCmd)\n    if status ~= 0 and status ~= true then\n        error(\"Failed to build Lua: make failed\")\n    end\n\n    -- After make local, files are in install/ subdirectory\n    -- Move them to the root of sdkPath (overwriting source files is fine)\n    local moveCmd = string.format(\"cd '%s' && mv install/* . 2>/dev/null || cp -r install/* . 2>/dev/null\", sdkPath)\n    os.execute(moveCmd)\n\n    -- Install LuaRocks for Lua 5.x\n    if major and major >= 5 then\n        -- Get latest LuaRocks version from GitHub releases\n        local luarocksVersion = \"3.11.1\" -- Default fallback\n\n        local resp, err = http.get({\n            url = \"https://api.github.com/repos/luarocks/luarocks/releases/latest\",\n        })\n\n        if err == nil and resp.status_code == 200 then\n            local data = json.decode(resp.body)\n            if data ~= nil and type(data) == \"table\" then\n                local tag = data[\"tag_name\"]\n                if tag then\n                    -- Remove 'v' prefix if present\n                    luarocksVersion = string.gsub(tag, \"^v\", \"\")\n                end\n            end\n        end\n\n        -- Download and install LuaRocks\n        local luarocksUrl = \"https://github.com/luarocks/luarocks/archive/refs/tags/v\" .. luarocksVersion .. \".tar.gz\"\n        local luarocksArchive = sdkPath .. \"/luarocks.tar.gz\"\n\n        local downloadCmd = string.format(\"curl -sL '%s' -o '%s'\", luarocksUrl, luarocksArchive)\n        status = os.execute(downloadCmd)\n        if status ~= 0 and status ~= true then\n            -- LuaRocks installation is optional, don't fail\n            return\n        end\n\n        local extractCmd = string.format(\"cd '%s' && tar xzf luarocks.tar.gz\", sdkPath)\n        status = os.execute(extractCmd)\n        if status ~= 0 and status ~= true then\n            return\n        end\n\n        local luarocksDir = sdkPath .. \"/luarocks-\" .. luarocksVersion\n        local configureCmd = string.format(\n            \"cd '%s' && ./configure --with-lua='%s' --with-lua-include='%s/include' --with-lua-lib='%s/lib' --prefix='%s/luarocks' 2>/dev/null\",\n            luarocksDir,\n            sdkPath,\n            sdkPath,\n            sdkPath,\n            sdkPath\n        )\n        status = os.execute(configureCmd)\n        if status ~= 0 and status ~= true then\n            -- Clean up and return without luarocks\n            os.execute(string.format(\"rm -rf '%s/luarocks.tar.gz' '%s/luarocks-'*\", sdkPath, sdkPath))\n            return\n        end\n\n        local bootstrapCmd = string.format(\"cd '%s' && make bootstrap 2>&1\", luarocksDir)\n        os.execute(bootstrapCmd)\n\n        -- Clean up LuaRocks source\n        os.execute(string.format(\"rm -rf '%s/luarocks.tar.gz' '%s/luarocks-'*\", sdkPath, sdkPath))\n    end\n\n    -- Clean up Lua source files (keep only bin, lib, include, man, share, luarocks)\n    local cleanCmd = string.format(\"cd '%s' && rm -rf src doc Makefile README install 2>/dev/null\", sdkPath)\n    os.execute(cleanCmd)\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-lua/hooks/pre_install.lua",
    "content": "--- Returns pre-install information for Lua\n--- @param ctx table Context provided by vfox\n--- @return table Pre-install info\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    return {\n        version = version,\n        url = \"https://www.lua.org/ftp/lua-\" .. version .. \".tar.gz\",\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-lua/metadata.lua",
    "content": "PLUGIN = {}\nPLUGIN.name = \"lua\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-lua\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Lua version manager - compiles from source\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Compiles Lua from source. Requires a C compiler (gcc/clang).\",\n    \"Automatically installs LuaRocks for Lua 5.x versions.\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-neovim/hooks/available.lua",
    "content": "--- Returns a list of available Neovim versions\n--- Fetches from GitHub releases API\n\n-- Helper function to get checksum for a release\nlocal function get_release_checksum(release, http)\n    -- Determine platform-specific asset name\n    local os_type = RUNTIME.osType\n    local arch_type = RUNTIME.archType\n    local platform, ext\n\n    if os_type == \"darwin\" then\n        ext = \".tar.gz\"\n        if arch_type == \"arm64\" then\n            platform = \"macos-arm64\"\n        else\n            platform = \"macos-x86_64\"\n        end\n    elseif os_type == \"linux\" then\n        ext = \".tar.gz\"\n        if arch_type == \"arm64\" then\n            platform = \"linux-arm64\"\n        else\n            platform = \"linux-x86_64\"\n        end\n    elseif os_type == \"windows\" then\n        ext = \".zip\"\n        if arch_type == \"arm64\" then\n            platform = \"win-arm64\"\n        else\n            platform = \"win64\"\n        end\n    else\n        return nil\n    end\n\n    local checksum_name = \"nvim-\" .. platform .. ext .. \".sha256sum\"\n    local checksum_url = nil\n\n    for _, asset in ipairs(release.assets or {}) do\n        if asset.name == checksum_name then\n            checksum_url = asset.browser_download_url\n            break\n        end\n    end\n\n    if checksum_url == nil then\n        return nil\n    end\n\n    local checksum_resp, checksum_err = http.get({ url = checksum_url })\n    if checksum_err ~= nil or checksum_resp.status_code ~= 200 then\n        return nil\n    end\n\n    -- Format is: \"checksum  filename\\n\"\n    return checksum_resp.body:match(\"^(%x+)\")\nend\n\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/neovim/neovim/releases\",\n        headers = {\n            [\"Accept\"] = \"application/vnd.github.v3+json\",\n        },\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch releases: \" .. err)\n    end\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch releases: HTTP \" .. resp.status_code)\n    end\n\n    local releases = json.decode(resp.body)\n    local result = {}\n\n    for _, release in ipairs(releases) do\n        if not release.draft then\n            local tag = release.tag_name\n            local version = tag\n            local rolling = false\n            local checksum = nil\n\n            -- Handle special release tags\n            if tag == \"nightly\" or tag == \"stable\" then\n                -- Both nightly and stable are rolling releases (they point to moving targets)\n                rolling = true\n                -- Fetch checksum for rolling releases to detect updates\n                checksum = get_release_checksum(release, http)\n            else\n                -- Strip 'v' prefix for versioned releases\n                version = tag:gsub(\"^v\", \"\")\n            end\n\n            table.insert(result, {\n                version = version,\n                note = release.name or \"\",\n                rolling = rolling,\n                checksum = checksum,\n            })\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-neovim/hooks/env_keys.lua",
    "content": "--- Sets environment variables for the installed Neovim version\n\nfunction PLUGIN:EnvKeys(ctx)\n    local main_path = ctx.path\n    return {\n        {\n            key = \"PATH\",\n            value = main_path .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-neovim/hooks/pre_install.lua",
    "content": "--- Returns information about the version to install\n--- Constructs the download URL based on OS and architecture\n\nfunction PLUGIN:PreInstall(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    local version = ctx.version\n    local os_type = RUNTIME.osType\n    local arch_type = RUNTIME.archType\n\n    -- Map OS/arch to Neovim asset naming\n    local platform, ext\n\n    if os_type == \"darwin\" then\n        ext = \".tar.gz\"\n        if arch_type == \"arm64\" then\n            platform = \"macos-arm64\"\n        else\n            platform = \"macos-x86_64\"\n        end\n    elseif os_type == \"linux\" then\n        ext = \".tar.gz\"\n        if arch_type == \"arm64\" then\n            platform = \"linux-arm64\"\n        else\n            platform = \"linux-x86_64\"\n        end\n    elseif os_type == \"windows\" then\n        ext = \".zip\"\n        if arch_type == \"arm64\" then\n            platform = \"win-arm64\"\n        else\n            platform = \"win64\"\n        end\n    else\n        error(\"Unsupported OS: \" .. os_type)\n    end\n\n    -- Determine the tag to fetch\n    local tag = version\n    if version ~= \"nightly\" and version ~= \"stable\" then\n        tag = \"v\" .. version\n    end\n\n    -- Fetch the specific release\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/neovim/neovim/releases/tags/\" .. tag,\n        headers = {\n            [\"Accept\"] = \"application/vnd.github.v3+json\",\n        },\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch release: \" .. err)\n    end\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch release \" .. tag .. \": HTTP \" .. resp.status_code)\n    end\n\n    local release = json.decode(resp.body)\n\n    -- Find the right asset and its checksum file\n    local asset_name = \"nvim-\" .. platform .. ext\n    local checksum_name = asset_name .. \".sha256sum\"\n    local download_url = nil\n    local checksum_url = nil\n\n    for _, asset in ipairs(release.assets) do\n        if asset.name == asset_name then\n            download_url = asset.browser_download_url\n        elseif asset.name == checksum_name then\n            checksum_url = asset.browser_download_url\n        end\n    end\n\n    if download_url == nil then\n        error(\"Could not find asset \" .. asset_name .. \" for release \" .. tag)\n    end\n\n    -- Fetch the sha256 checksum if available\n    local sha256 = nil\n    if checksum_url ~= nil then\n        local checksum_resp, checksum_err = http.get({\n            url = checksum_url,\n        })\n        if checksum_err == nil and checksum_resp.status_code == 200 then\n            -- Format is: \"checksum  filename\\n\"\n            -- Extract just the checksum (first field)\n            sha256 = checksum_resp.body:match(\"^(%x+)\")\n        end\n    end\n\n    return {\n        version = version,\n        url = download_url,\n        sha256 = sha256,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-neovim/metadata.lua",
    "content": "PLUGIN = {\n    name = \"neovim\",\n    version = \"0.1.0\",\n    description = \"Neovim - hyperextensible Vim-based text editor\",\n    homepage = \"https://neovim.io/\",\n    license = \"Apache 2.0\",\n    minRuntimeVersion = \"0.3.0\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-pipenv/hooks/available.lua",
    "content": "local http = require(\"http\")\nlocal json = require(\"json\")\n\n--- Compare two semantic version strings\n--- @param v1 string\n--- @param v2 string\n--- @return boolean true if v1 > v2\nlocal function compare_versions(v1, v2)\n    local function parse(v)\n        local parts = {}\n        -- Handle pre-release versions like 2020.4.1b2, 2020.4.1.dev1\n        local main = v:match(\"^([%d%.]+)\")\n        if main then\n            for num in main:gmatch(\"(%d+)\") do\n                table.insert(parts, tonumber(num))\n            end\n        end\n        -- Pre-release versions should sort before release versions\n        if v:match(\"[abrc]%d*$\") or v:match(\"%.dev%d*$\") then\n            table.insert(parts, -1)\n        else\n            table.insert(parts, 0)\n        end\n        return parts\n    end\n\n    local p1, p2 = parse(v1), parse(v2)\n    for i = 1, math.max(#p1, #p2) do\n        local n1, n2 = p1[i] or 0, p2[i] or 0\n        if n1 ~= n2 then\n            return n1 > n2\n        end\n    end\n    return false\nend\n\n--- Get the available version list from PyPI.\n--- @param ctx table Empty table, no data provided. Always {}.\n--- @return table Version list\nfunction PLUGIN:Available(ctx)\n    local resp, err = http.get({\n        url = \"https://pypi.org/pypi/pipenv/json\",\n    })\n\n    if err ~= nil or resp.status_code ~= 200 then\n        error(\"Failed to fetch pipenv versions from PyPI: \" .. (err or (\"HTTP \" .. resp.status_code)))\n    end\n\n    local data = json.decode(resp.body)\n    if not data or not data.releases then\n        error(\"Invalid response from PyPI\")\n    end\n\n    local result = {}\n    for version, release_info in pairs(data.releases) do\n        -- Skip versions with no files (yanked or broken releases)\n        if release_info and #release_info > 0 then\n            local note = \"\"\n            -- Mark pre-release versions\n            if version:match(\"[abrc]%d*$\") or version:match(\"%.dev%d*$\") then\n                note = \"pre-release\"\n            end\n            table.insert(result, {\n                version = version,\n                note = note,\n            })\n        end\n    end\n\n    -- Sort versions (newest first)\n    table.sort(result, function(a, b)\n        return compare_versions(a.version, b.version)\n    end)\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-pipenv/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    local version_path = ctx.path\n    local result = {}\n\n    -- Add wrapper_bin to PATH for pipenv command\n    if RUNTIME.osType == \"windows\" then\n        table.insert(result, {\n            key = \"PATH\",\n            value = version_path .. \"\\\\wrapper_bin\",\n        })\n    else\n        table.insert(result, {\n            key = \"PATH\",\n            value = version_path .. \"/wrapper_bin\",\n        })\n    end\n\n    -- Check for Pipfile in current directory to auto-activate virtualenv\n    local cwd = os.getenv(\"PWD\")\n    if not cwd then\n        -- Fallback: try to get cwd via shell command\n        local handle = io.popen(\"pwd 2>/dev/null\")\n        if handle then\n            cwd = handle:read(\"*a\"):gsub(\"%s+$\", \"\")\n            handle:close()\n        end\n    end\n\n    if cwd and cwd ~= \"\" then\n        local pipfile_path = cwd .. \"/Pipfile\"\n        local f = io.open(pipfile_path, \"r\")\n        if f then\n            f:close()\n\n            -- Pipfile exists, try to get the virtualenv path\n            local pipenv_cmd = version_path\n            if RUNTIME.osType == \"windows\" then\n                pipenv_cmd = pipenv_cmd .. \"\\\\wrapper_bin\\\\pipenv\"\n            else\n                pipenv_cmd = pipenv_cmd .. \"/wrapper_bin/pipenv\"\n            end\n\n            local venv_handle =\n                io.popen('PIPENV_PIPFILE=\"' .. pipfile_path .. '\" \"' .. pipenv_cmd .. '\" --venv 2>/dev/null')\n            if venv_handle then\n                local venv_path = venv_handle:read(\"*a\"):gsub(\"%s+$\", \"\")\n                venv_handle:close()\n\n                if venv_path and venv_path ~= \"\" then\n                    -- Verify the venv exists\n                    local venv_bin = venv_path .. \"/bin\"\n                    local test_file = io.open(venv_bin .. \"/python\", \"r\")\n                    if test_file then\n                        test_file:close()\n\n                        -- Add virtualenv activation\n                        table.insert(result, {\n                            key = \"VIRTUAL_ENV\",\n                            value = venv_path,\n                        })\n                        table.insert(result, {\n                            key = \"PIPENV_ACTIVE\",\n                            value = \"1\",\n                        })\n                        table.insert(result, {\n                            key = \"PATH\",\n                            value = venv_bin,\n                        })\n                    end\n                end\n            end\n        end\n    end\n\n    return result\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-pipenv/hooks/post_install.lua",
    "content": "--- Post-installation hook that creates a venv and installs pipenv.\n--- @param ctx table\n--- @field ctx.rootPath string SDK installation root path\n--- @field ctx.sdkInfo table SDK info containing version\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n\n    -- Extract version from rootPath (e.g., /path/to/installs/pipenv/2024.0.1)\n    -- The version is the last component of the path\n    local version = rootPath:match(\"([^/\\\\]+)$\")\n    if not version then\n        error(\"Could not extract version from rootPath: \" .. rootPath)\n    end\n\n    -- Find Python interpreter\n    local python_cmd = nil\n    local python_candidates = { \"python3\", \"python\" }\n\n    for _, candidate in ipairs(python_candidates) do\n        local check = os.execute(candidate .. \" --version >/dev/null 2>&1\")\n        if check == 0 or check == true then\n            -- Verify it's Python 3.7+\n            local handle =\n                io.popen(candidate .. ' -c \"import sys; print(sys.version_info.major, sys.version_info.minor)\"')\n            if handle then\n                local output = handle:read(\"*a\")\n                handle:close()\n                local major, minor = output:match(\"(%d+)%s+(%d+)\")\n                if major and minor then\n                    major = tonumber(major)\n                    minor = tonumber(minor)\n                    if major >= 3 and minor >= 7 then\n                        python_cmd = candidate\n                        break\n                    end\n                end\n            end\n        end\n    end\n\n    if not python_cmd then\n        error(\"Python 3.7+ is required but not found in PATH\")\n    end\n\n    -- Create virtual environment\n    local venv_cmd = python_cmd .. ' -m venv --copies \"' .. rootPath .. '\"'\n    local result = os.execute(venv_cmd)\n    if result ~= 0 and result ~= true then\n        error(\"Failed to create virtual environment\")\n    end\n\n    -- Determine the path separator and bin directory based on OS\n    local bin_dir = \"bin\"\n    local path_sep = \"/\"\n    local script_ext = \"\"\n    local activate_script = \"activate\"\n\n    if RUNTIME.osType == \"windows\" then\n        bin_dir = \"Scripts\"\n        path_sep = \"\\\\\"\n        script_ext = \".bat\"\n        activate_script = \"activate.bat\"\n    end\n\n    local venv_bin = rootPath .. path_sep .. bin_dir\n    local pip_cmd = venv_bin .. path_sep .. \"pip\"\n\n    -- Install pipenv inside virtual environment\n    local install_cmd = '\"' .. pip_cmd .. '\" install --quiet pipenv==' .. version\n    result = os.execute(install_cmd)\n    if result ~= 0 and result ~= true then\n        error(\"Failed to install pipenv==\" .. version)\n    end\n\n    -- Create wrapper scripts directory\n    local wrapper_dir = rootPath .. path_sep .. \"wrapper_bin\"\n    os.execute('mkdir -p \"' .. wrapper_dir .. '\"')\n\n    -- Create wrapper scripts for pipenv executables\n    local executables = { \"pipenv\", \"pipenv-resolver\" }\n\n    if RUNTIME.osType == \"windows\" then\n        -- Windows batch wrapper\n        for _, exe in ipairs(executables) do\n            local wrapper_path = wrapper_dir .. path_sep .. exe .. \".cmd\"\n            local wrapper_file = io.open(wrapper_path, \"w\")\n            if wrapper_file then\n                wrapper_file:write(\"@echo off\\r\\n\")\n                wrapper_file:write('call \"' .. venv_bin .. path_sep .. activate_script .. '\"\\r\\n')\n                wrapper_file:write(\"set PIPENV_IGNORE_VIRTUALENVS=1\\r\\n\")\n                wrapper_file:write('\"' .. venv_bin .. path_sep .. exe .. '\" %*\\r\\n')\n                wrapper_file:close()\n            end\n        end\n    else\n        -- Unix shell wrapper\n        for _, exe in ipairs(executables) do\n            local wrapper_path = wrapper_dir .. path_sep .. exe\n            local wrapper_file = io.open(wrapper_path, \"w\")\n            if wrapper_file then\n                wrapper_file:write(\"#!/usr/bin/env bash\\n\")\n                wrapper_file:write('source \"' .. venv_bin .. \"/\" .. activate_script .. '\"\\n')\n                wrapper_file:write('PIPENV_IGNORE_VIRTUALENVS=1 \"' .. venv_bin .. \"/\" .. exe .. '\" \"$@\"\\n')\n                wrapper_file:close()\n                os.execute('chmod +x \"' .. wrapper_path .. '\"')\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-pipenv/hooks/pre_install.lua",
    "content": "local http = require(\"http\")\nlocal json = require(\"json\")\n\n--- Returns pre-installed information, such as version number.\n--- For pipenv, we install via pip so we just validate the version exists.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Validate version exists on PyPI\n    local resp, err = http.get({\n        url = \"https://pypi.org/pypi/pipenv/\" .. version .. \"/json\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to validate pipenv version: \" .. err)\n    end\n\n    if resp.status_code == 404 then\n        error(\"Pipenv version \" .. version .. \" not found on PyPI\")\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to validate pipenv version: HTTP \" .. resp.status_code)\n    end\n\n    -- No download URL needed - we install via pip in PostInstall\n    return {\n        version = version,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-pipenv/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"pipenv\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-pipenv\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Python Development Workflow for Humans - https://pipenv.pypa.io\"\n\n--- !!! OPTIONAL !!!\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Requires Python 3.7+ to be installed and available in PATH\",\n    \"If the Python interpreter used during installation is removed, pipenv will stop working and needs to be reinstalled\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-poetry/hooks/available.lua",
    "content": "--- Returns a list of available versions of Poetry\n--- Fetches from GitHub releases\n\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    -- Fetch releases from GitHub API\n    local resp, err = http.get({\n        url = \"https://api.github.com/repos/python-poetry/poetry/tags?per_page=100\",\n    })\n    if err ~= nil then\n        error(\"Failed to fetch version list: \" .. err)\n    end\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch version list: HTTP \" .. resp.status_code)\n    end\n\n    local tags = json.decode(resp.body)\n    local versions = {}\n\n    for _, tag in ipairs(tags) do\n        local version = tag.name\n        -- Remove 'v' prefix if present (though poetry doesn't use it)\n        if version:sub(1, 1) == \"v\" then\n            version = version:sub(2)\n        end\n        -- Only include stable versions (no alpha/beta/rc)\n        if version:match(\"^%d+%.%d+%.%d+$\") then\n            table.insert(versions, {\n                version = version,\n            })\n        end\n    end\n\n    return versions\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-poetry/hooks/env_keys.lua",
    "content": "--- Returns environment keys for Poetry\n--- Poetry installs its binary to $POETRY_HOME/bin\n--- Also handles virtualenv activation based on pyproject.toml\n\n--- Helper function to get mise Python bin directory\n--- Returns the PATH prefix to use, or empty string if not found\nlocal function get_mise_python_path_prefix()\n    local handle = io.popen(\"mise which python3 2>/dev/null\")\n    if not handle then\n        return \"\"\n    end\n    local python_path = handle:read(\"*l\")\n    handle:close()\n\n    if not python_path or python_path == \"\" then\n        return \"\"\n    end\n\n    -- Extract the bin directory from the python path\n    local bin_dir = python_path:match(\"(.*/)\")\n    if bin_dir then\n        return \"PATH='\" .. bin_dir .. \":$PATH' \"\n    end\n    return \"\"\nend\n\nfunction PLUGIN:EnvKeys(ctx)\n    local file = require(\"file\")\n    local bin_path = file.join_path(ctx.path, \"bin\")\n\n    local env_keys = {\n        {\n            key = \"PATH\",\n            value = bin_path,\n        },\n        {\n            key = \"POETRY_HOME\",\n            value = ctx.path,\n        },\n    }\n\n    -- Check for pyproject option from tool configuration\n    local pyproject = ctx.options and ctx.options.pyproject\n    if not pyproject or pyproject == \"\" then\n        return env_keys\n    end\n\n    -- Resolve relative path against project root\n    local project_root = os.getenv(\"MISE_PROJECT_ROOT\")\n    if project_root and pyproject:sub(1, 1) ~= \"/\" then\n        pyproject = project_root .. \"/\" .. pyproject\n    end\n\n    -- Check if pyproject.toml exists\n    local f = io.open(pyproject, \"r\")\n    if not f then\n        return env_keys\n    end\n    f:close()\n\n    local pyproject_dir = pyproject:match(\"(.*/)\")\n    if not pyproject_dir then\n        pyproject_dir = \".\"\n    end\n\n    -- Check for uv.lock - if present, let uv manage the venv\n    local uv_lock = io.open(pyproject_dir .. \"uv.lock\", \"r\")\n    if uv_lock then\n        uv_lock:close()\n        return env_keys\n    end\n\n    -- Check MISE_POETRY_VENV_AUTO setting\n    local venv_auto = os.getenv(\"MISE_POETRY_VENV_AUTO\")\n    if venv_auto == \"1\" or venv_auto == \"true\" then\n        -- Only activate if poetry.lock exists\n        local lock_file = io.open(pyproject_dir .. \"poetry.lock\", \"r\")\n        if not lock_file then\n            return env_keys\n        end\n        lock_file:close()\n    end\n\n    -- Get mise Python path prefix to ensure poetry uses the correct Python\n    local path_prefix = get_mise_python_path_prefix()\n\n    -- Get the virtualenv path from poetry\n    local poetry_bin = ctx.path .. \"/bin/poetry\"\n    local handle = io.popen(\n        \"cd '\" .. pyproject_dir .. \"' && \" .. path_prefix .. \"'\" .. poetry_bin .. \"' env info --path 2>/dev/null\"\n    )\n    if not handle then\n        return env_keys\n    end\n\n    local venv_path = handle:read(\"*l\")\n    handle:close()\n\n    if not venv_path or venv_path == \"\" then\n        -- Try to create the virtualenv with mise's Python in PATH\n        os.execute(\"cd '\" .. pyproject_dir .. \"' && \" .. path_prefix .. \"'\" .. poetry_bin .. \"' run true 2>/dev/null\")\n\n        -- Try again to get the path\n        handle = io.popen(\n            \"cd '\" .. pyproject_dir .. \"' && \" .. path_prefix .. \"'\" .. poetry_bin .. \"' env info --path 2>/dev/null\"\n        )\n        if handle then\n            venv_path = handle:read(\"*l\")\n            handle:close()\n        end\n\n        if not venv_path or venv_path == \"\" then\n            return env_keys\n        end\n\n        -- Auto-install if enabled\n        local auto_install = os.getenv(\"MISE_POETRY_AUTO_INSTALL\")\n        if auto_install == \"1\" or auto_install == \"true\" then\n            os.execute(\"cd '\" .. pyproject_dir .. \"' && \" .. path_prefix .. \"'\" .. poetry_bin .. \"' install 2>&1\")\n        end\n    end\n\n    -- Set virtualenv environment variables\n    table.insert(env_keys, { key = \"POETRY_ACTIVE\", value = \"1\" })\n    table.insert(env_keys, { key = \"VIRTUAL_ENV\", value = venv_path })\n    table.insert(env_keys, { key = \"MISE_ADD_PATH\", value = venv_path .. \"/bin\" })\n\n    return env_keys\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-poetry/hooks/post_install.lua",
    "content": "--- Post-installation hook for Poetry\n--- Runs the installer script with the correct version\n\nfunction PLUGIN:PostInstall(ctx)\n    local install_path = ctx.rootPath\n\n    -- Get version from sdkInfo\n    local version = ctx.sdkInfo[\"poetry\"].version\n\n    -- Run the Poetry installer via bash script\n    local script = string.format(\n        [[\n#!/bin/bash\nset -e\n\n# Run the Poetry installer\ncurl -sSL https://install.python-poetry.org | POETRY_HOME=\"%s\" python3 - --version \"%s\"\n\n# Configure poetry for mise compatibility\n# For Poetry >= 2.0.0, use virtualenvs.use-poetry-python false\n# For Poetry >= 1.2.0 and < 2.0.0, use virtualenvs.prefer-active-python true\n\nversion_ge() {\n    printf '%%s\\n%%s\\n' \"$2\" \"$1\" | sort --check=quiet --version-sort\n}\n\nif version_ge \"%s\" \"2.0.0\"; then\n    \"%s/bin/poetry\" config virtualenvs.use-poetry-python false\nelif version_ge \"%s\" \"1.2.0\"; then\n    \"%s/bin/poetry\" config virtualenvs.prefer-active-python true\nfi\n]],\n        install_path,\n        version,\n        version,\n        install_path,\n        version,\n        install_path\n    )\n\n    -- Write and execute the script\n    local script_path = install_path .. \"/install_poetry.sh\"\n    local f = io.open(script_path, \"w\")\n    if f then\n        f:write(script)\n        f:close()\n        local result = os.execute(\"chmod +x \" .. script_path .. \" && \" .. script_path)\n        os.execute(\"rm -f \" .. script_path)\n        if result ~= 0 and result ~= true then\n            error(\"Poetry installation failed\")\n        end\n    else\n        error(\"Failed to create installation script\")\n    end\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-poetry/hooks/pre_install.lua",
    "content": "--- Returns information about the version to install\n--- Poetry is installed via install.python-poetry.org script\n--- No URL is returned as the installation is handled in post_install\n\nfunction PLUGIN:PreInstall(ctx)\n    return {\n        version = ctx.version,\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-poetry/metadata.lua",
    "content": "--- Metadata for the Poetry plugin\n--- Poetry is a Python dependency management and packaging tool\n--- https://python-poetry.org/\n\nPLUGIN = {\n    name = \"poetry\",\n    version = \"0.1.0\",\n    description = \"Python packaging and dependency management made easy\",\n    homepage = \"https://python-poetry.org/\",\n    license = \"MIT\",\n    minRuntimeVersion = \"0.3.0\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-postgres/hooks/available.lua",
    "content": "--- Returns all available PostgreSQL versions from the official FTP server\n--- @param ctx table Context provided by vfox\n--- @return table Available versions\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n\n    local result = {}\n    local seen = {}\n\n    -- Fetch the PostgreSQL source directory listing\n    local resp, err = http.get({\n        url = \"https://ftp.postgresql.org/pub/source/\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch PostgreSQL versions: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"Failed to fetch PostgreSQL versions, status: \" .. resp.status_code)\n    end\n\n    -- Parse HTML to extract version directories\n    -- Format: >v17.2/<, >v16.6/<, >v9.6.24/<\n    for version in string.gmatch(resp.body, \">v([0-9]+%.[0-9]+[%.0-9]*)/<\") do\n        if not seen[version] then\n            seen[version] = true\n            table.insert(result, {\n                version = version,\n            })\n        end\n    end\n\n    -- Sort versions semantically (descending order - newest first)\n    table.sort(result, function(a, b)\n        return compare_versions(b.version, a.version)\n    end)\n\n    return result\nend\n\n--- Compare two version strings semantically\n--- Returns true if v1 < v2 (for ascending sort)\nfunction compare_versions(v1, v2)\n    local parts1 = split_version(v1)\n    local parts2 = split_version(v2)\n\n    local max_len = math.max(#parts1, #parts2)\n    for i = 1, max_len do\n        local p1 = parts1[i] or 0\n        local p2 = parts2[i] or 0\n        if p1 ~= p2 then\n            return p1 < p2\n        end\n    end\n    return false\nend\n\n--- Split a version string into numeric parts\nfunction split_version(version)\n    local parts = {}\n    for part in string.gmatch(version, \"([0-9]+)\") do\n        table.insert(parts, tonumber(part))\n    end\n    return parts\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-postgres/hooks/env_keys.lua",
    "content": "--- Returns environment variables for PostgreSQL\n--- @param ctx table Context provided by vfox\n--- @return table Environment configuration\nfunction PLUGIN:EnvKeys(ctx)\n    local sdkInfo = ctx.sdkInfo[\"postgres\"]\n    local installDir = sdkInfo.path\n\n    local envs = {\n        {\n            key = \"PATH\",\n            value = installDir .. \"/bin\",\n        },\n        {\n            key = \"PGDATA\",\n            value = installDir .. \"/data\",\n        },\n    }\n\n    -- Add LD_LIBRARY_PATH on Linux\n    if RUNTIME.osType == \"linux\" then\n        table.insert(envs, {\n            key = \"LD_LIBRARY_PATH\",\n            value = installDir .. \"/lib\",\n        })\n    end\n\n    return envs\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-postgres/hooks/post_install.lua",
    "content": "local file = require(\"file\")\n\nlocal function path_exists(path)\n    return path ~= nil and path ~= \"\" and file.exists(path)\nend\n\nlocal function shell_quote(value)\n    local str = tostring(value or \"\")\n    return \"'\" .. str:gsub(\"'\", \"'\\\"'\\\"'\") .. \"'\"\nend\n\nlocal function validate_openssl_prefix(prefix)\n    if not path_exists(prefix) then\n        return false\n    end\n\n    if not path_exists(prefix .. \"/include/openssl/ssl.h\") then\n        return false\n    end\n\n    for _, lib_path in ipairs({ \"/lib/libssl.dylib\", \"/lib/libssl.a\", \"/lib/libssl.so\" }) do\n        if path_exists(prefix .. lib_path) then\n            return true\n        end\n    end\n\n    return false\nend\n\nlocal function pkg_config_openssl_prefix()\n    local handle = io.popen(\"pkg-config --variable=prefix openssl 2>/dev/null\")\n    if handle == nil then\n        return nil\n    end\n\n    local prefix = handle:read(\"*l\")\n    local close_ok, _, close_code = handle:close()\n    if close_ok ~= true and close_ok ~= 0 then\n        return nil\n    end\n    if close_code ~= nil and close_code ~= 0 then\n        return nil\n    end\n\n    if prefix ~= nil then\n        prefix = prefix:match(\"^%s*(.-)%s*$\")\n    end\n\n    if prefix ~= nil and prefix ~= \"\" and prefix:match(\"^/\") then\n        return prefix\n    end\n\n    return nil\nend\n\nlocal function find_nix_openssl_prefix()\n    local nix_ssl_cert = os.getenv(\"NIX_SSL_CERT_FILE\")\n    if nix_ssl_cert ~= nil and nix_ssl_cert ~= \"\" then\n        local nix_prefix = nix_ssl_cert:match(\"(/nix/store/[^/]+%-openssl[^/]*)\")\n        if validate_openssl_prefix(nix_prefix) then\n            return nix_prefix\n        end\n    end\n\n    local nix_paths = { \"/nix/var/nix/profiles/default\" }\n    local home = os.getenv(\"HOME\")\n    if home ~= nil and home ~= \"\" then\n        table.insert(nix_paths, 1, home .. \"/.nix-profile\")\n    end\n\n    for _, path in ipairs(nix_paths) do\n        if validate_openssl_prefix(path) then\n            return path\n        end\n    end\n\n    return nil\nend\n\nlocal function find_openssl_prefix(homebrew_prefix)\n    for _, env_var in ipairs({ \"OPENSSL_ROOT_DIR\", \"OPENSSL_DIR\" }) do\n        local override_path = os.getenv(env_var)\n        if validate_openssl_prefix(override_path) then\n            return override_path\n        end\n    end\n\n    local pkg_path = pkg_config_openssl_prefix()\n    if validate_openssl_prefix(pkg_path) then\n        return pkg_path\n    end\n\n    local nix_path = find_nix_openssl_prefix()\n    if nix_path ~= nil then\n        return nix_path\n    end\n\n    local brew = homebrew_prefix or \"/opt/homebrew\"\n    for _, path in ipairs({ brew .. \"/opt/openssl@3\", brew .. \"/opt/openssl\" }) do\n        if validate_openssl_prefix(path) then\n            return path\n        end\n    end\n\n    for _, path in ipairs({\n        \"/usr/local/opt/openssl@3\",\n        \"/usr/local/opt/openssl\",\n        \"/opt/local/libexec/openssl3\",\n        \"/opt/local\",\n        \"/usr/local/ssl\",\n    }) do\n        if validate_openssl_prefix(path) then\n            return path\n        end\n    end\n\n    return nil\nend\n\n--- Compiles and installs PostgreSQL from source\n--- @param ctx PostInstallCtx Context provided by vfox\nfunction PLUGIN:PostInstall(ctx)\n    local sdkInfo = ctx.sdkInfo[\"postgres\"]\n    local version = sdkInfo.version\n    local sdkPath = sdkInfo.path\n\n    -- mise extracts tarball and strips top-level directory, so sdkPath IS the source directory\n\n    -- Build configure options\n    local configureOptions = \"--prefix=\" .. shell_quote(sdkPath)\n    local envPrefix = \"\" -- Environment variables to prepend to configure command\n\n    -- Add common options\n    configureOptions = configureOptions .. \" --with-openssl --with-zlib\"\n\n    -- Try to add UUID support (e2fs on Linux, BSD on macOS)\n    local os_type = RUNTIME.osType\n    local homebrew_prefix = os.getenv(\"HOMEBREW_PREFIX\") or \"/opt/homebrew\"\n\n    if os_type == \"darwin\" then\n        local openssl_path = find_openssl_prefix(homebrew_prefix)\n        -- Homebrew paths\n        local icu_path = homebrew_prefix .. \"/opt/icu4c\"\n        local ossp_uuid_path = homebrew_prefix .. \"/opt/ossp-uuid\"\n        local util_linux_path = homebrew_prefix .. \"/opt/util-linux\"\n\n        -- Build library and include paths\n        local lib_paths = {}\n        local include_paths = {}\n\n        -- Check if OpenSSL exists in supported locations\n        if openssl_path ~= nil then\n            table.insert(lib_paths, openssl_path .. \"/lib\")\n            table.insert(include_paths, openssl_path .. \"/include\")\n        else\n            io.stderr:write(\"Warning: OpenSSL not found in known locations.\\n\")\n            io.stderr:write(\"  Set OPENSSL_ROOT_DIR or OPENSSL_DIR to your OpenSSL installation prefix.\\n\")\n        end\n\n        -- Check if ICU exists in Homebrew (PostgreSQL 17+ requires ICU by default)\n        if path_exists(icu_path .. \"/lib\") then\n            table.insert(lib_paths, icu_path .. \"/lib\")\n            table.insert(include_paths, icu_path .. \"/include\")\n            -- Set PKG_CONFIG_PATH for ICU (prepend to configure command)\n            local pkg_config_path = os.getenv(\"PKG_CONFIG_PATH\") or \"\"\n            if pkg_config_path ~= \"\" then\n                pkg_config_path = icu_path .. \"/lib/pkgconfig:\" .. pkg_config_path\n            else\n                pkg_config_path = icu_path .. \"/lib/pkgconfig\"\n            end\n            envPrefix = \"PKG_CONFIG_PATH=\" .. shell_quote(pkg_config_path) .. \" \"\n        else\n            -- ICU not found, disable it\n            io.stderr:write(\"Warning: ICU not found. Installing without ICU support.\\n\")\n            io.stderr:write(\"  To enable ICU: brew install icu4c\\n\")\n            configureOptions = configureOptions .. \" --without-icu\"\n        end\n\n        -- Check for UUID library: prefer ossp-uuid, then util-linux (e2fs), otherwise skip\n        if path_exists(ossp_uuid_path .. \"/lib\") then\n            configureOptions = configureOptions .. \" --with-uuid=ossp\"\n            table.insert(lib_paths, ossp_uuid_path .. \"/lib\")\n            table.insert(include_paths, ossp_uuid_path .. \"/include\")\n        else\n            if path_exists(util_linux_path .. \"/lib\") then\n                configureOptions = configureOptions .. \" --with-uuid=e2fs\"\n                table.insert(lib_paths, util_linux_path .. \"/lib\")\n                table.insert(include_paths, util_linux_path .. \"/include\")\n            else\n                -- Neither UUID library available\n                io.stderr:write(\"Warning: UUID library not found. Installing without UUID support.\\n\")\n                io.stderr:write(\"  To enable UUID: brew install ossp-uuid\\n\")\n            end\n        end\n\n        if #lib_paths > 0 then\n            configureOptions = configureOptions .. \" --with-libraries=\" .. shell_quote(table.concat(lib_paths, \":\"))\n        end\n        if #include_paths > 0 then\n            configureOptions = configureOptions .. \" --with-includes=\" .. shell_quote(table.concat(include_paths, \":\"))\n        end\n    else\n        -- Linux: use e2fs UUID\n        configureOptions = configureOptions .. \" --with-uuid=e2fs\"\n\n        -- Check if ICU is available on Linux\n        local icu_check = os.execute(\"pkg-config --exists icu-uc 2>/dev/null\")\n        if icu_check ~= 0 and icu_check ~= true then\n            -- ICU not found, disable it\n            io.stderr:write(\"Warning: ICU not found. Installing without ICU support.\\n\")\n            io.stderr:write(\"  To enable ICU: sudo apt install libicu-dev (Debian/Ubuntu)\\n\")\n            configureOptions = configureOptions .. \" --without-icu\"\n        end\n    end\n\n    -- Allow user to override or extend configure options\n    local extraOptions = os.getenv(\"POSTGRES_EXTRA_CONFIGURE_OPTIONS\")\n    if extraOptions ~= nil and extraOptions ~= \"\" then\n        configureOptions = configureOptions .. \" \" .. extraOptions\n    end\n\n    local userOptions = os.getenv(\"POSTGRES_CONFIGURE_OPTIONS\")\n    if userOptions ~= nil and userOptions ~= \"\" then\n        -- User provided full options, use those instead (but keep prefix)\n        configureOptions = \"--prefix=\" .. shell_quote(sdkPath) .. \" \" .. userOptions\n    end\n\n    -- Run configure\n    print(\"Configuring PostgreSQL with: \" .. configureOptions)\n    local configureCmd = string.format(\"cd %s && %s./configure %s\", shell_quote(sdkPath), envPrefix, configureOptions)\n    local status = os.execute(configureCmd)\n    if status ~= 0 and status ~= true then\n        error(\"Failed to configure PostgreSQL\")\n    end\n\n    -- Build PostgreSQL\n    print(\"Building PostgreSQL (this may take several minutes)...\")\n    local makeCmd = string.format(\n        \"cd %s && make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)\",\n        shell_quote(sdkPath)\n    )\n    status = os.execute(makeCmd)\n    if status ~= 0 and status ~= true then\n        error(\"Failed to build PostgreSQL\")\n    end\n\n    -- Install PostgreSQL\n    print(\"Installing PostgreSQL...\")\n    local installCmd = string.format(\"cd %s && make install\", shell_quote(sdkPath))\n    status = os.execute(installCmd)\n    if status ~= 0 and status ~= true then\n        error(\"Failed to install PostgreSQL\")\n    end\n\n    -- Build and install contrib modules\n    print(\"Building contrib modules...\")\n    local contribCmd = string.format(\n        \"cd %s && make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2) && make install\",\n        shell_quote(sdkPath .. \"/contrib\")\n    )\n    status = os.execute(contribCmd)\n    if status ~= 0 and status ~= true then\n        -- Contrib failure is not fatal\n        print(\"Warning: Failed to build some contrib modules\")\n    end\n\n    -- Create data directory\n    local dataDir = sdkPath .. \"/data\"\n    os.execute(string.format(\"mkdir -p %s\", shell_quote(dataDir)))\n\n    -- Run initdb unless skipped\n    local skipInitdb = os.getenv(\"POSTGRES_SKIP_INITDB\")\n    if skipInitdb ~= \"1\" and skipInitdb ~= \"true\" then\n        print(\"Initializing database cluster...\")\n        local initdbCmd =\n            string.format(\"%s -D %s -U postgres\", shell_quote(sdkPath .. \"/bin/initdb\"), shell_quote(dataDir))\n        status = os.execute(initdbCmd)\n        if status ~= 0 and status ~= true then\n            print(\"Warning: initdb failed. You may need to run it manually.\")\n        end\n    else\n        print(\"Skipping initdb (POSTGRES_SKIP_INITDB is set)\")\n    end\n\n    -- Clean up source files to save space\n    print(\"Cleaning up source files...\")\n    local cleanCmd = string.format(\n        \"cd %s && rm -rf src doc contrib config Makefile GNUmakefile configure* aclocal* 2>/dev/null\",\n        shell_quote(sdkPath)\n    )\n    os.execute(cleanCmd)\n\n    print(\"PostgreSQL installation complete!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-postgres/hooks/pre_install.lua",
    "content": "--- Returns pre-install information for PostgreSQL\n--- @param ctx table Context provided by vfox\n--- @return table Pre-install info\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    return {\n        version = version,\n        url = \"https://ftp.postgresql.org/pub/source/v\" .. version .. \"/postgresql-\" .. version .. \".tar.gz\",\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-postgres/metadata.lua",
    "content": "PLUGIN = {}\nPLUGIN.name = \"postgres\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-postgres\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"PostgreSQL database - compiles from source\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Compiles PostgreSQL from source. Requires: C compiler, make, readline, zlib, openssl.\",\n    \"Automatically runs initdb unless POSTGRES_SKIP_INITDB=1 is set.\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-redis/hooks/available.lua",
    "content": "--- Returns all available versions of Redis\n--- @param ctx table Context object\n--- @return table Array of version objects with version and optional note fields\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n\n    local resp, err = http.get({\n        url = \"https://download.redis.io/releases/\",\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch Redis releases: \" .. err)\n    end\n\n    local results = {}\n    local seen = {}\n\n    -- Parse HTML to extract version numbers from redis-X.Y.Z.tar.gz links\n    for version in resp.body:gmatch(\"redis%-(%d+%.%d+%.%d+)%.tar%.gz\") do\n        if not seen[version] then\n            seen[version] = true\n            table.insert(results, {\n                version = version,\n                note = \"\",\n            })\n        end\n    end\n\n    -- Parse version string into numeric components\n    local function parse_version(v)\n        local major, minor, patch = v:match(\"^(%d+)%.(%d+)%.(%d+)$\")\n        return tonumber(major) or 0, tonumber(minor) or 0, tonumber(patch) or 0\n    end\n\n    -- Sort versions using semantic versioning (descending order - newest first)\n    table.sort(results, function(a, b)\n        local a_major, a_minor, a_patch = parse_version(a.version)\n        local b_major, b_minor, b_patch = parse_version(b.version)\n\n        if a_major ~= b_major then\n            return a_major > b_major\n        end\n        if a_minor ~= b_minor then\n            return a_minor > b_minor\n        end\n        return a_patch > b_patch\n    end)\n\n    return results\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-redis/hooks/env_keys.lua",
    "content": "--- Returns environment variables to set for Redis\n--- @param ctx table Context object with path field\n--- @return table Array of environment variable key-value pairs\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n\n    return {\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\",\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-redis/hooks/post_install.lua",
    "content": "--- Compiles Redis from source after extraction\n--- @param ctx table Context object with rootPath field\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n\n    -- Redis doesn't need configure, just make with PREFIX\n    local build_cmd = string.format('cd \"%s\" && make PREFIX=\"%s\" install', rootPath, rootPath)\n\n    print(\"Compiling Redis from source...\")\n    local result = os.execute(build_cmd)\n\n    if not result or result ~= 0 and result ~= true then\n        error(\"Failed to compile Redis. Make sure you have a C compiler (gcc/clang) and make installed.\")\n    end\n\n    -- Clean up source files to save space (keep only bin/)\n    local cleanup_cmd = string.format(\n        'cd \"%s\" && rm -rf src deps tests runtest runtest-cluster runtest-sentinel runtest-moduleapi sentinel.conf redis.conf Makefile 2>/dev/null',\n        rootPath\n    )\n    os.execute(cleanup_cmd)\n\n    print(\"Redis compiled successfully!\")\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-redis/hooks/pre_install.lua",
    "content": "--- Returns download information for a specific Redis version\n--- @param ctx table Context object with version field\n--- @return table Download info with version, url, and optional note\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    return {\n        version = version,\n        url = \"https://download.redis.io/releases/redis-\" .. version .. \".tar.gz\",\n        note = \"Downloading Redis \" .. version .. \" source...\",\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-redis/metadata.lua",
    "content": "PLUGIN = {}\n\nPLUGIN.name = \"redis\"\nPLUGIN.version = \"0.1.0\"\nPLUGIN.homepage = \"https://github.com/mise-plugins/vfox-redis\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Redis - in-memory data structure store, cache, and message broker\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nPLUGIN.notes = {\n    \"Compiles from source - requires C compiler (gcc/clang) and make\",\n}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/hooks/available.lua",
    "content": "local util = require(\"util\")\n\n--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n    return util:getInfo()\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- Note: Be sure to distinguish between environment variable settings for different platforms!\n--- @param ctx {path: string}  Context information (SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n    return {\n        {\n            key = \"PATH\",\n            value = mainPath,\n        },\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/hooks/post_install.lua",
    "content": "--- Extension point, called after PreInstall, can perform additional operations,\n--- such as file operations for the SDK installation directory or compile source code\n--- Currently can be left unimplemented!\nfunction PLUGIN:PostInstall(ctx)\n    -- do nothing\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/hooks/pre_install.lua",
    "content": "local util = require(\"util\")\n--- Returns some pre-installed information, such as version number, download address, local files, etc.\n--- If checksum is provided, vfox will automatically check it for you.\n--- @param ctx {version: string}  (User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n    if #util.RELEASES == 0 then\n        self:Available(ctx)\n    end\n    local releases = util.RELEASES\n    for _, release in ipairs(releases) do\n        if release.version == ctx.version then\n            return release\n        end\n    end\n    return {}\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/hooks/pre_use.lua",
    "content": "--- When user invoke `use` command, this function will be called to get the\n--- valid version information.\n--- @param ctx table Context information\nfunction PLUGIN:PreUse(ctx)\n    --do nothing\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/lib/util.lua",
    "content": "local http = require(\"http\")\nlocal json = require(\"json\")\nlocal util = {}\n\nutil.__index = util\nlocal utilSingleton = setmetatable({}, util)\nutilSingleton.SOURCE_URL = \"https://raw.githubusercontent.com/ahai-code/sdk-sources/main/v.json\"\nutilSingleton.RELEASES = {}\n\nfunction util:compare_versions(v1o, v2o)\n    local v1 = v1o.version\n    local v2 = v2o.version\n    local v1_parts = {}\n    for part in string.gmatch(v1, \"[^.]+\") do\n        table.insert(v1_parts, tonumber(part))\n    end\n\n    local v2_parts = {}\n    for part in string.gmatch(v2, \"[^.]+\") do\n        table.insert(v2_parts, tonumber(part))\n    end\n\n    for i = 1, math.max(#v1_parts, #v2_parts) do\n        local v1_part = v1_parts[i] or 0\n        local v2_part = v2_parts[i] or 0\n        if v1_part > v2_part then\n            return true\n        elseif v1_part < v2_part then\n            return false\n        end\n    end\n\n    return false\nend\n\nfunction util:getInfo()\n    local result = {}\n    local resp, err = http.get({\n        url = utilSingleton.SOURCE_URL,\n    })\n    if err ~= nil then\n        error(\"Failed to get information: \" .. err)\n    end\n    if resp.status_code ~= 200 then\n        error(\"Failed to get information: status_code =>\" .. resp.status_code)\n    end\n    local respInfo = json.decode(resp.body)[RUNTIME.osType]\n    for version, array in pairs(respInfo) do\n        local url = \"\"\n        if string.sub(version, 1, #\"weekly.\") == \"weekly.\" then\n            version = string.gsub(version, \"^weekly.\", \"\")\n        end\n\n        for _, obj in ipairs(array) do\n            if obj.Arch == \"\" then\n                url = obj.Url\n            elseif obj.Arch == RUNTIME.archType then\n                url = obj.Url\n            end\n        end\n\n        table.insert(result, { version = version, note = \"\" })\n        table.insert(utilSingleton.RELEASES, { version = version, url = url })\n    end\n    table.sort(result, function(a, b)\n        return util:compare_versions(a, b)\n    end)\n    return result\nend\n\nreturn utilSingleton\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-vlang/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"vlang\"\n--- Plugin version\nPLUGIN.version = \"0.1.2\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/ahai-code/vfox-vlang\"\n--- Plugin license, please choose a correct license according to your needs.\nPLUGIN.license = \"Apache 2.0\"\n--- Plugin description\nPLUGIN.description = \"Vlang plugin\"\n\n--- !!! OPTIONAL !!!\n--[[\nNOTE:\n    Minimum compatible vfox version.\n    If the plugin is not compatible with the current vfox version,\n    vfox will not load the plugin and prompt the user to upgrade vfox.\n --]]\nPLUGIN.minRuntimeVersion = \"0.3.2\"\n--[[\nNOTE:\n    If configured, vfox will check for updates to the plugin at this address,\n    otherwise it will check for updates at the global registry.\n\n    If you want use the global registry to distribute your plugin, you can remove this field.\n\n    If you develop a plugin based on the template, which will automatically generate a manifest file by CI,\n    you can set this address to the manifest file address, so that the plugin can be updated automatically.\n\n --]]\nPLUGIN.manifestUrl = \"https://github.com/version-fox/ahai-code/vfox-vlang/releases/download/manifest/manifest.json\"\n-- Some things that need user to be attention!\nPLUGIN.notes = {}\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/available.lua",
    "content": "--- List all available versions\n\nlocal function fetch_github_tags(repo_url)\n    -- Use git ls-remote to get tags\n    local cmd = 'git ls-remote --refs --tags \"' .. repo_url .. '\"'\n\n    -- Detect Windows\n    local is_windows = package.config:sub(1, 1) == \"\\\\\"\n\n    -- Redirect stderr appropriately for the platform\n    if is_windows then\n        cmd = cmd .. \" 2>NUL\"\n    else\n        cmd = cmd .. \" 2>/dev/null\"\n    end\n\n    local handle = io.popen(cmd)\n    if not handle then\n        return {}\n    end\n\n    local result = handle:read(\"*a\")\n    handle:close()\n\n    -- If result is empty or nil, return empty table\n    if not result or result == \"\" then\n        return {}\n    end\n\n    local tags = {}\n    for line in result:gmatch(\"[^\\r\\n]+\") do\n        -- Extract tag name from refs/tags/...\n        local tag = line:match(\"refs/tags/(.+)$\")\n        if tag then\n            table.insert(tags, tag)\n        end\n    end\n\n    return tags\nend\n\nlocal function version_compare(a, b)\n    -- Simple version comparison for sorting\n    local function parse_version(v)\n        local parts = {}\n        for part in string.gmatch(v, \"[^%.]+\") do\n            table.insert(parts, tonumber(part) or 0)\n        end\n        return parts\n    end\n\n    local a_parts = parse_version(a)\n    local b_parts = parse_version(b)\n\n    for i = 1, math.max(#a_parts, #b_parts) do\n        local a_val = a_parts[i] or 0\n        local b_val = b_parts[i] or 0\n        if a_val ~= b_val then\n            return a_val > b_val -- Descending order\n        end\n    end\n\n    return false\nend\n\nfunction PLUGIN:Available(ctx)\n    local versions = {}\n\n    -- Get Yarn Berry versions (v2.x+)\n    local berry_tags = fetch_github_tags(\"https://github.com/yarnpkg/berry.git\")\n    local berry_versions = {}\n\n    for _, tag in ipairs(berry_tags) do\n        -- Extract version from @yarnpkg/cli/X.X.X format\n        local version = tag:match(\"@yarnpkg/cli/(.+)$\")\n        if version then\n            table.insert(berry_versions, version)\n        end\n    end\n\n    -- Sort Berry versions in descending order\n    table.sort(berry_versions, version_compare)\n\n    -- Add Berry versions to the list\n    for _, version in ipairs(berry_versions) do\n        table.insert(versions, {\n            version = version,\n        })\n    end\n\n    -- Get Yarn Classic versions (v1.x)\n    local classic_tags = fetch_github_tags(\"https://github.com/yarnpkg/yarn.git\")\n    local classic_versions = {}\n\n    for _, tag in ipairs(classic_tags) do\n        -- Remove 'v' prefix if present\n        local version = tag:match(\"^v(.+)$\") or tag\n        -- Only include 1.x versions (exclude 0.x)\n        if version:match(\"^1%.\") then\n            table.insert(classic_versions, version)\n        end\n    end\n\n    -- Sort Classic versions in descending order\n    table.sort(classic_versions, version_compare)\n\n    -- Add Classic versions to the list\n    for _, version in ipairs(classic_versions) do\n        table.insert(versions, {\n            version = version,\n        })\n    end\n\n    return versions\nend\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/env_keys.lua",
    "content": "--- Environment keys hook\n\nfunction PLUGIN:EnvKeys(ctx)\n    -- Get the SDK installation path\n    local version_path = ctx.path\n\n    -- Return the PATH configuration for yarn binaries\n    return {\n        {\n            key = \"PATH\",\n            value = version_path .. \"/bin\",\n        },\n    }\nend\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/legacy_filenames.lua",
    "content": "--- Get list of legacy filenames\nreturn function(ctx)\n    return {\n        \".yvmrc\",\n    }\nend\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/parse_legacy_file.lua",
    "content": "--- Parse legacy version files\n\nfunction PLUGIN:ParseLegacyFile(ctx)\n    local filepath = ctx.filepath\n    local file = io.open(filepath, \"r\")\n    if file then\n        local version = file:read(\"*l\")\n        file:close()\n        if version then\n            version = version:gsub(\"^v\", \"\"):gsub(\"%s+\", \"\")\n            return {\n                version = version,\n            }\n        end\n    end\n    return {}\nend\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/post_install.lua",
    "content": "--- Post-installation hook\n\n-- os.execute returns 0 in Lua 5.1, true in Lua 5.2+\nlocal function exec_success(result)\n    return result == true or result == 0\nend\n\nlocal function download_file(url, output_path)\n    -- Detect Windows\n    local is_windows = package.config:sub(1, 1) == \"\\\\\"\n    local stderr_redirect = is_windows and \" 2>NUL\" or \" 2>/dev/null\"\n\n    -- Try curl first (more likely to be available on Windows via Git Bash)\n    local curl_cmd = \"curl -sSL -o \" .. output_path .. \" \" .. url .. stderr_redirect\n    local wget_cmd = \"wget -q -O \" .. output_path .. \" \" .. url .. stderr_redirect\n\n    if exec_success(os.execute(curl_cmd)) then\n        return true\n    elseif exec_success(os.execute(wget_cmd)) then\n        return true\n    end\n    return false\nend\n\nfunction PLUGIN:PostInstall(ctx)\n    -- Get install path - it should be in sdkInfo\n    local install_path = nil\n    local version = nil\n\n    -- Try to get path from sdkInfo\n    if ctx.sdkInfo and ctx.sdkInfo.yarn then\n        install_path = ctx.sdkInfo.yarn.path\n        version = ctx.sdkInfo.yarn.version\n    end\n\n    -- Fallback to environment variable\n    if not install_path then\n        install_path = os.getenv(\"MISE_INSTALL_PATH\")\n    end\n    if not version then\n        version = os.getenv(\"MISE_INSTALL_VERSION\") or ctx.version\n    end\n\n    if not install_path or not version then\n        -- For v1, mise handles everything, so this is OK\n        return {}\n    end\n\n    local major_version = string.sub(version, 1, 1)\n\n    if major_version ~= \"1\" then\n        -- Yarn Berry (v2.x+) - download single JS file\n        local yarn_url = \"https://repo.yarnpkg.com/\" .. version .. \"/packages/yarnpkg-cli/bin/yarn.js\"\n\n        -- Detect Windows\n        local is_windows = package.config:sub(1, 1) == \"\\\\\"\n\n        -- Create bin directory (cross-platform)\n        local bin_dir = install_path .. \"/bin\"\n        if is_windows then\n            os.execute('mkdir \"' .. bin_dir .. '\" 2>NUL')\n        else\n            os.execute(\"mkdir -p \" .. bin_dir)\n        end\n\n        -- Download yarn.js\n        local yarn_js_file = bin_dir .. \"/yarn.js\"\n        if not download_file(yarn_url, yarn_js_file) then\n            error(\"Failed to download Yarn v2+\")\n        end\n\n        -- Create wrapper script\n        if is_windows then\n            -- Create yarn.cmd wrapper for Windows\n            local yarn_cmd = bin_dir .. \"/yarn.cmd\"\n            local cmd_file = io.open(yarn_cmd, \"w\")\n            if cmd_file then\n                cmd_file:write(\"@echo off\\n\")\n                cmd_file:write('node \"%~dp0yarn.js\" %*\\n')\n                cmd_file:close()\n            end\n\n            -- Also create yarn without extension for Git Bash\n            local yarn_sh = bin_dir .. \"/yarn\"\n            local sh_file = io.open(yarn_sh, \"w\")\n            if sh_file then\n                sh_file:write(\"#!/bin/sh\\n\")\n                sh_file:write('exec node \"$(dirname \"$0\")/yarn.js\" \"$@\"\\n')\n                sh_file:close()\n            end\n        else\n            -- Create shell wrapper for Unix\n            local yarn_file = bin_dir .. \"/yarn\"\n            local wrapper_file = io.open(yarn_file, \"w\")\n            if wrapper_file then\n                wrapper_file:write(\"#!/bin/sh\\n\")\n                wrapper_file:write('exec node \"$(dirname \"$0\")/yarn.js\" \"$@\"\\n')\n                wrapper_file:close()\n            end\n            -- Make executable\n            os.execute(\"chmod +x \" .. yarn_file)\n        end\n    end\n\n    return {}\nend\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/hooks/pre_install.lua",
    "content": "--- Pre-installation hook\n\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n    local major_version = string.sub(version, 1, 1)\n\n    if major_version == \"1\" then\n        -- Yarn Classic (v1.x) - return tarball URL for mise to handle\n        local archive_url = \"https://classic.yarnpkg.com/downloads/\" .. version .. \"/yarn-v\" .. version .. \".tar.gz\"\n\n        -- Note about GPG verification (skip on Windows)\n        local is_windows = package.config:sub(1, 1) == \"\\\\\"\n        if os.getenv(\"MISE_YARN_SKIP_GPG\") == nil and not is_windows then\n            local stderr_redirect = \" 2>/dev/null\"\n\n            local gpg_check = io.popen(\"command -v gpg\" .. stderr_redirect)\n            local has_gpg = gpg_check and gpg_check:read(\"*a\"):match(\"%S\")\n            if gpg_check then\n                gpg_check:close()\n            end\n\n            if not has_gpg then\n                print(\n                    \"⚠️  Note: GPG verification skipped (gpg not found). Set MISE_YARN_SKIP_GPG=1 to suppress this message\"\n                )\n            end\n            -- Note: We can't do GPG verification when mise handles the download\n            -- This is a tradeoff for simpler code\n        end\n\n        -- Return URL for mise to download and extract\n        return {\n            version = version,\n            url = archive_url,\n        }\n    else\n        -- Yarn Berry (v2.x+) - single JS file, handled in post-install\n        return {\n            version = version,\n        }\n    end\nend\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/embedded-plugins/vfox-yarn/metadata.lua",
    "content": "--- Plugin metadata and configuration for Yarn\n---@meta\n\nPLUGIN = {\n    name = \"yarn\",\n    author = \"mise-plugins\",\n    version = \"0.1.0\",\n    description = \"Yarn package manager plugin for mise\",\n    homepage = \"https://github.com/mise-plugins/mise-yarn\",\n    license = \"MIT\",\n    notes = [[\nThis plugin installs Yarn package manager.\nSupports both Yarn Classic (v1.x) and Yarn Berry (v2.x+).\n    ]],\n    minRuntimeVersion = \"0.5.0\",\n}\n\nreturn PLUGIN\n"
  },
  {
    "path": "crates/vfox/lua/htmlparser/ElementNode.lua",
    "content": "-- vim: ft=lua ts=2\nlocal Set = {}\nSet.mt = {__index = Set}\nfunction Set:new(values)\n\tlocal instance = {}\n\tlocal isSet if getmetatable(values) == Set.mt then isSet = true end\n\tif type(values) == \"table\" then\n\t\tif not isSet and #values > 0 then\n\t\t\tfor _,v in ipairs(values) do\n\t\t\t\tinstance[v] = true\n\t\t\tend\n\t\telse\n\t\t\tfor k in pairs(values) do\n\t\t\t\tinstance[k] = true\n\t\t\tend\n\t\tend\n\telseif values ~= nil then\n\t\tinstance = {[values] = true}\n\tend\n\treturn setmetatable(instance, Set.mt)\nend\n\nfunction Set:add(e)\n\tif e ~= nil then self[e] = true end\n\treturn self\nend\n\nfunction Set:remove(e)\n\tif e ~= nil then self[e] = nil end\n\treturn self\nend\n\nfunction Set:tolist()\n\tlocal res = {}\n\tfor k in pairs(self) do\n\t\ttable.insert(res, k)\n\tend\n\treturn res\nend\n\nSet.mt.__add = function (a, b)\n\tlocal res, a, b = Set:new(), Set:new(a), Set:new(b)\n\tfor k in pairs(a) do res[k] = true end\n\tfor k in pairs(b) do res[k] = true end\n\treturn res\nend\n\n-- Subtraction\nSet.mt.__sub = function (a, b)\n\tlocal res, a, b = Set:new(), Set:new(a), Set:new(b)\n\tfor k in pairs(a) do res[k] = true end\n\tfor k in pairs(b) do res[k] = nil end\n\treturn res\nend\n\n-- Intersection\nSet.mt.__mul = function (a, b)\n\tlocal res, a, b = Set:new(), Set:new(a), Set:new(b)\n\tfor k in pairs(a) do\n\t\tres[k] = b[k]\n\tend\n\treturn res\nend\n\n-- String representation\nSet.mt.__tostring = function (set)\n\tlocal s = \"{\"\n\tlocal sep = \"\"\n\tfor k in pairs(set) do\n\t\ts = s .. sep .. tostring(k)\n\t\tsep = \", \"\n\tend\n\treturn s .. \"}\"\nend\n\n\nlocal ElementNode = {}\nElementNode.mt = {__index = ElementNode}\nfunction ElementNode:new(index, nameortext, node, descend, openstart, openend)\n\tlocal instance = {\n\t\tindex = index,\n\t\tname = nameortext,\n\t\tlevel = 0,\n\t\tparent = nil,\n\t\troot = nil,\n\t\tnodes = {},\n\t\t_openstart = openstart, _openend = openend,\n\t\t_closestart = openstart, _closeend = openend,\n\t\tattributes = {},\n\t\tid = nil,\n\t\tclasses = {},\n\t\tdeepernodes = Set:new(),\n\t\tdeeperelements = {}, deeperattributes = {}, deeperids = {}, deeperclasses = {}\n\t}\n\tif not node then\n\t\tinstance.name = \"root\"\n\t\tinstance.root = instance\n\t\tinstance._text = nameortext\n\t\tlocal length = string.len(nameortext)\n\t\tinstance._openstart, instance._openend = 1, length\n\t\tinstance._closestart, instance._closeend = 1, length\n\telseif descend then\n\t\tinstance.root = node.root\n\t\tinstance.parent = node\n\t\tinstance.level = node.level + 1\n\t\ttable.insert(node.nodes, instance)\n\telse\n\t\tinstance.root = node.root\n\t\tinstance.parent = node.parent or node --XXX: adds some safety but needs more testing for heisenbugs in corner cases\n\t\tinstance.level = node.level\n\t\ttable.insert((node.parent and node.parent.nodes or node.nodes), instance) --XXX: see above about heisenbugs\n\tend\n\treturn setmetatable(instance, ElementNode.mt)\nend\n\nfunction ElementNode:gettext()\n\treturn string.sub(self.root._text, self._openstart, self._closeend)\nend\n\nfunction ElementNode:settext(c)\n\tself.root._text=c\nend\n\nfunction ElementNode:textonly()\n\treturn (self:gettext():gsub(\"<[^>]*>\",\"\"))\nend\n\nfunction ElementNode:getcontent()\n\treturn string.sub(self.root._text, self._openend + 1, self._closestart - 1)\nend\n\nfunction ElementNode:addattribute(k, v)\n\tself.attributes[k] = v\n\tif string.lower(k) == \"id\" then\n\t\tself.id = v\n\t-- class attribute contains \"space-separated tokens\", each of which we'd like quick access to\n\telseif string.lower(k) == \"class\" then\n\t\tfor class in string.gmatch(v, \"%S+\") do\n\t\t\ttable.insert(self.classes, class)\n\t\tend\n\tend\nend\n\nlocal function insert(table, name, node)\n\ttable[name] = table[name] or Set:new()\n\ttable[name]:add(node)\nend\n\nfunction ElementNode:close(closestart, closeend)\n\tif closestart and closeend then\n\t\tself._closestart, self._closeend = closestart, closeend\n\tend\n\t-- inform hihger level nodes about this element's existence in their branches\n\tlocal node = self\n\twhile true do\n\t\tnode = node.parent\n\t\tif not node then break end\n\t\tnode.deepernodes:add(self)\n\t\tinsert(node.deeperelements, string.lower(self.name), self)\n\t\tfor k in pairs(self.attributes) do\n\t\t\tinsert(node.deeperattributes, k, self)\n\t\tend\n\t\tif self.id then\n\t\t\tinsert(node.deeperids, self.id, self)\n\t\tend\n\t\tfor _,v in ipairs(self.classes) do\n\t\t\tinsert(node.deeperclasses, v, self)\n\t\tend\n\tend\nend\n\nlocal function escape(s)\n\t-- escape all ^, $, (, ), %, ., [, ], *, +, - , and ? with a % prefix\n\treturn string.gsub(s, \"([%^%$%(%)%%%.%[%]%*%+%-%?])\", \"%%\" .. \"%1\")\nend\n\nlocal function select(self, s)\n\tif not s or type(s) ~= \"string\" or s == \"\" then return Set:new() end\n\tlocal sets = {[\"\"]\t= self.deeperelements, [\"[\"] = self.deeperattributes,\n\t\t\t\t\t\t\t\t[\"#\"] = self.deeperids,\t\t\t[\".\"] = self.deeperclasses}\n\tlocal function match(t, w)\n\t\tlocal m, e, v\n\t\tif t == \"[\" then w, m, e, v = string.match(w, \n\t\t\t\t\"([^=|%*~%$!%^]+)\" .. -- w = 1 or more characters up to a possible \"=\", \"|\", \"*\", \"~\", \"$\", \"!\", or \"^\"\n\t\t\t\t\"([|%*~%$!%^]?)\" ..   -- m = an optional \"|\", \"*\", \"~\", \"$\", \"!\", or \"^\", preceding the optional \"=\"\n\t\t\t\t\"(=?)\" ..             -- e = the optional \"=\"\n\t\t\t\t\"(.*)\"                -- v = anything following the \"=\", or else \"\"\n\t\t\t)\n\t\tend\n\t\tlocal matched = Set:new(sets[t][w])\n\t\t-- attribute value selectors\n\t\tif e == \"=\" then\n\t\t\tif #v < 2 then v = \"'\" .. v .. \"'\" end -- values should be quoted\n\t\t\tv = string.sub(v, 2, #v - 1) -- strip quotes\n\t\t\tif m == \"!\" then matched = Set:new(self.deepernodes) end -- include those without that attribute\n\t\t\tfor node in pairs(matched) do\n\t\t\t\tlocal a = node.attributes[w]\n\t\t\t\t-- equals\n\t\t\t\tif m == \"\" and a ~= v then matched:remove(node)\n\t\t\t\t-- not equals\n\t\t\t\telseif m == \"!\" and a == v then matched:remove(node)\n\t\t\t\t-- prefix\n\t\t\t\telseif m ==\"|\" and string.match(a, \"^[^-]*\") ~= v then matched:remove(node)\n\t\t\t\t-- contains\n\t\t\t\telseif m ==\"*\" and string.match(a, escape(v)) ~= v then matched:remove(node)\n\t\t\t\t-- word\n\t\t\t\telseif m ==\"~\" then matched:remove(node)\n\t\t\t\t\tfor word in string.gmatch(a, \"%S+\") do\n\t\t\t\t\t\tif word == v then matched:add(node) break end\n\t\t\t\t\tend\n\t\t\t\t-- starts with\n\t\t\t\telseif m ==\"^\" and string.match(a, \"^\" .. escape(v)) ~= v then matched:remove(node)\n\t\t\t\t-- ends with\n\t\t\t\telseif m ==\"$\" and string.match(a, escape(v) .. \"$\") ~= v then matched:remove(node)\n\t\t\t\tend\n\t\t\tend -- for node\n\t\tend -- if v\n\t\treturn matched\n\tend\n\n\tlocal subjects, resultset, childrenonly = Set:new({self})\n\tfor part in string.gmatch(s, \"%S+\") do\n\trepeat\n\t\tif part == \">\" then childrenonly = true --[[goto nextpart]] break end\n\t\tresultset = Set:new()\n\t\tfor subject in pairs(subjects) do\n\t\t\tlocal star = subject.deepernodes\n\t\t\tif childrenonly then star = Set:new(subject.nodes) end\n\t\t\tresultset = resultset + star\n\t\tend\n\t\tchildrenonly = false\n\t\tif part == \"*\" then --[[goto nextpart]] break end\n\t\tlocal excludes, filter = Set:new()\n\t\tlocal start, pos = 0, 0\n\t\twhile true do\n\t\t\tlocal switch, stype, name, eq, quote\n\t\t\tstart, pos, switch, stype, name, eq, quote = string.find(part,\n\t\t\t\t\"(%(?%)?)\" ..         -- switch = a possible ( or ) switching the filter on or off\n\t\t\t\t\"([:%[#.]?)\" ..       -- stype = a possible :, [, #, or .\n\t\t\t\t\"([%w-_\\\\]+)\" ..      -- name = 1 or more alfanumeric chars (+ hyphen, reverse slash and uderscore)\n\t\t\t\t\"([|%*~%$!%^]?=?)\" .. -- eq = a possible |=, *=, ~=, $=, !=, ^=, or =\n\t\t\t\t\"(['\\\"]?)\",           -- quote = a ' or \" delimiting a possible attribute value\n\t\t\t\tpos + 1\n\t\t\t)\n\t\t\tif not name then break end\n\trepeat\n\t\t\tif \":\" == stype then\n\t\t\t\tfilter = name\n\t\t\t\t--[[goto nextname]] break\n\t\t\tend\n\t\t\tif \")\" == switch then\n\t\t\t\tfilter = nil\n\t\t\tend\n\t\t\tif \"[\" == stype and \"\" ~= quote then\n\t\t\t\tlocal value\n\t\t\t\tstart, pos, value = string.find(part, \"(%b\" .. quote .. quote .. \")]\", pos)\n\t\t\t\tname = name .. eq .. value\n\t\t\tend\n\t\t\tlocal matched = match(stype, name)\n\t\t\tif filter == \"not\" then\n\t\t\t\texcludes = excludes + matched\n\t\t\telse\n\t\t\t\tresultset = resultset * matched\n\t\t\tend\n\t\t\t--::nextname::\n\tbreak\n\tuntil true\n\t\tend\n\t\tresultset = resultset - excludes\n\t\tsubjects = Set:new(resultset)\n\t\t--::nextpart::\nbreak\nuntil true\n\tend\n\tresultset = resultset:tolist()\n\ttable.sort(resultset, function (a, b) return a.index < b.index end)\n\treturn resultset\nend\n\nfunction ElementNode:select(s) return select(self, s) end\nElementNode.mt.__call = select\n\nreturn ElementNode\n"
  },
  {
    "path": "crates/vfox/lua/htmlparser/voidelements.lua",
    "content": "-- vim: ft=lua ts=2\nreturn {\n\tarea = true,\n\tbase = true,\n\tbr = true,\n\tcol = true,\n\tcommand = true,\n\tembed = true,\n\thr = true,\n\timg = true,\n\tinput = true,\n\tkeygen = true,\n\tlink = true,\n\tmeta = true,\n\tparam = true,\n\tsource = true,\n\ttrack = true,\n\twbr = true\n}\n"
  },
  {
    "path": "crates/vfox/lua/htmlparser.lua",
    "content": "-- vim: ft=lua ts=2 sw=2\n\n-- Syntactic Sugar {{{\nlocal function rine(val) -- Return (val) If it's Not Empty (non-zero-length)\n\treturn (val and #val>0) and val\nend\nlocal function rit(a) -- Return (a) If it's Table\n\treturn (type(a) == \"table\") and a\nend\nlocal noop = function() end\nlocal esc = function(s) return string.gsub(s, \"([%^%$%(%)%%%.%[%]%*%+%-%?])\", \"%%\" .. \"%1\") end\nlocal str = tostring\nlocal char = string.char\nlocal opts = rit(htmlparser_opts) or {} -- needed for silent/noerr/noout/nonl directives, also needed to be defined before `require` in such case\nlocal prn = opts.silent and noop or function(l,f,...)\n\tlocal fd = (l==\"i\") and \"stdout\" or \"stderr\"\n\tlocal t = (\" [%s] \"):format(l:upper())\n\tio[fd]\n\t\t:write('[HTMLParser]'..t..f:format(...)\n\t\t\t..(opts.nonl or \"\\n\")\n\t\t)\nend\nlocal err = opts.noerr and noop or function(f,...) prn(\"e\",f,...) end\nlocal out = opts.noout and noop or function(f,...) prn(\"i\",f,...) end\nlocal line = debug and function(lvl) return debug.getinfo(lvl or 2).currentline end or noop\nlocal dbg = opts.debug and function(f,...) prn(\"d\",f:gsub(\"#LINE#\",str(line(3))),...) end or noop\n-- }}}\n-- Requires {{{\nlocal ElementNode = require\"htmlparser.ElementNode\"\nlocal voidelements = require\"htmlparser.voidelements\"\n--}}}\nlocal HtmlParser = {}\nlocal function parse(text,limit) -- {{{\n\tlocal opts = rine(opts) -- use top-level opts-table (the one, defined before requiring the module), if exists\n\t\tor rit(htmlparser_opts) -- or defined after requiring (but before calling `parse`)\n\t\tor {} -- fallback otherwise\n\topts.looplimit = opts.looplimit or htmlparser_looplimit\n\n\tlocal text = str(text)\n\tlocal limit = limit or opts.looplimit or 1000\n\tlocal tpl = false\n\n\tif not opts.keep_comments then -- Strip (or not) comments {{{\n\t\ttext = text:gsub(\"<!%-%-.-%-%->\",\"\") -- Many chances commented code will have syntax errors, that'll lead to parser failures\n\tend -- }}}\n\n\tlocal tpr={}\n\n\tif not opts.keep_danger_placeholders then -- {{{ little speedup by cost of potential parsing breakages\n\t\t-- search unused \"invalid\" bytes {{{\n\t\tlocal busy,i={},0;\n\t\trepeat -- {{{\n\t\t\tlocal cc = char(i)\n\t\t\tif not(text:match(cc)) then -- {{{\n\t\t\t\tif not(tpr[\"<\"]) or not(tpr[\">\"]) then -- {{{\n\t\t\t\t\tif not(busy[i]) then -- {{{\n\t\t\t\t\t\tif not(tpr[\"<\"]) then -- {{{\n\t\t\t\t\t\t\ttpr[\"<\"] = cc;\n\t\t\t\t\t\telseif not(tpr[\">\"]) then\n\t\t\t\t\t\t\ttpr[\">\"] = cc;\n\t\t\t\t\t\tend -- }}}\n\t\t\t\t\t\tbusy[i] = true\n\t\t\t\t\t\tdbg(\"c:{%s}||cc:{%d}||tpr[c]:{%s}\",str(c),cc:byte(),str(tpr[c]))\n\t\t\t\t\t\tdbg(\"busy[i]:{%s},i:{%d}\",str(busy[i]),i)\n\t\t\t\t\t\tdbg(\"[FindPH]:#LINE# Success! || i=%d\",i)\n\t\t\t\t\telse -- if !busy\n\t\t\t\t\t\tdbg(\"[FindPH]:#LINE# Busy! || i=%d\",i)\n\t\t\t\t\tend -- if !busy -- }}}\n\t\t\t\t\tdbg(\"c:{%s}||cc:{%d}||tpr[c]:{%s}\",c,cc:byte(),str(tpr[c]))\n\t\t\t\t\tdbg(\"%s\",str(busy[i]))\n\t\t\t\telse -- if < or >\n\t\t\t\t\tdbg(\"[FindPH]:#LINE# Done!\",i)\n\t\t\t\t\tbreak\n\t\t\t\tend -- if < or > -- }}}\n\t\t\telse -- text!match(cc)\n\t\t\t\tdbg(\"[FindPH]:#LINE# Text contains this byte! || i=%d\",i)\n\t\t\tend -- text!match(cc) -- }}}\n\t\t\tlocal skip=1\n\t\t\tif i==31 then\n\t\t\t\tskip=96 -- ASCII\n\t\t\tend\n\t\t\ti=i+skip\n\t\tuntil (i==255) -- }}}\n\t\ti=nil\n\t\t--- }}}\n\n\t\tif not(tpr[\"<\"]) or not(tpr[\">\"]) then\n\t\t\terr(\"Impossible to find at least two unused byte codes in this HTML-code. We need it to escape bracket-contained placeholders inside tags.\")\n\t\t\terr(\"Consider enabling 'keep_danger_placeholders' option (to silence this error, if parser wasn't failed with current HTML-code) or manually replace few random bytes, to free up the codes.\")\n\t\telse\n\t\t\tdbg(\"[FindPH]:#LINE# Found! || '<'=%d, '>'=%d\",tpr[\"<\"]:byte(),tpr[\">\"]:byte())\n\t\tend\n\n--\tdbg(\"tpr[>] || tpr[] || #busy%d\")\n\n\t\t-- g {{{\n\t\tlocal function g(id,...)\n\t\t\tlocal arg={...}\n\t\t\tlocal orig=arg[id]\n\t\t\targ[id]=arg[id]:gsub(\"(.)\",tpr)\n\t\t\tif arg[id] ~= orig then\n\t\t\t\ttpl=true\n\t\t\t\tdbg(\"[g]:#LINE# orig: %s\", str(orig))\n\t\t\t\tdbg(\"[g]:#LINE# replaced: %s\",str(arg[id]))\n\t\t\tend\n\t\t\tdbg(\"[g]:#LINE# called, id: %s, arg[id]: %s, args { \"..((\"{%s}, \"):rep(#arg):gsub(\", $\",\"\"))..\" }\",id,arg[id],...)\n\t\t\tdbg(\"[g]:#LINE# concat(arg): %s\",table.concat(arg))\n\t\t\treturn table.concat(arg)\n\t\tend\n\t\t-- g }}}\n\n\t\t-- tpl-placeholders and attributes {{{\n\t\ttext=text\n\t\t\t:gsub(\n\t\t\t\t\"(=[%s]-)\".. -- only match attr.values, and not random strings between two random apostrophs\n\t\t\t\t\"(%b'')\",\n\t\t\t\tfunction(...)return g(2,...)end\n\t\t\t)\n\t\t\t:gsub(\n\t\t\t\t\"(=[%s]-)\".. -- same for \"\n\t\t\t\t'(%b\"\")',\n\t\t\t\tfunction(...)return g(2,...)end\n\t\t\t) -- Escape \"<\"/\">\" inside attr.values (see issue #50)\n\t\t\t:gsub(\n\t\t\t\t\"(<\".. -- Match \"<\",\n\t\t\t\t(opts.tpl_skip_pattern or \"[^!]\").. -- with exclusion pattern (for example, to ignore comments, which aren't template placeholders, but can legally contain \"<\"/\">\" inside.\n\t\t\t\t\")([^>]+)\".. -- If matched, we want to escape '<'s if we meet them inside tag\n\t\t\t\t\"(>)\",\n\t\t\t\tfunction(...)return g(2,...)end\n\t\t\t)\n\t\t\t:gsub(\n\t\t\t\t\"(\"..\n\t\t\t\t(tpr[\"<\"] or \"__FAILED__\").. -- Here we search for \"<\", we escaped in previous gsub (and don't break things if we have no escaping replacement)\n\t\t\t\t\")(\"..\n\t\t\t\t(opts.tpl_marker_pattern or \"[^%w%s]\").. -- Capture templating symbol\n\t\t\t\t\")([%g%s]-)\".. -- match placeholder's content\n\t\t\t\t\"(%2)(>)\".. -- placeholder's tail\n\t\t\t\t\"([^>]*>)\", -- remainings\n\t\t\t\tfunction(...)return g(5,...)end\n\t\t\t)\n\t\t-- }}}\n\tend -- }}}\n\n\tlocal index = 0\n\tlocal root = ElementNode:new(index, str(text))\n\tlocal node, descend, tpos, opentags = root, true, 1, {}\n\n\twhile true do -- MainLoop {{{\n\t\tif index == limit then -- {{{\n\t\t\terr(\"Main loop reached loop limit (%d). Consider either increasing it or checking HTML-code for syntax errors\", limit)\n\t\t\tbreak\n\t\tend -- }}}\n\t\t-- openstart/tpos Definitions {{{\n\t\tlocal openstart, name\n\t\topenstart, tpos, name = root._text:find(\n\t\t\t\"<\" ..        -- an uncaptured starting \"<\"\n\t\t\t\"([%w-]+)\" .. -- name = the first word, directly following the \"<\"\n\t\t\t\"[^>]*>\",     -- include, but not capture everything up to the next \">\"\n\t\ttpos)\n\t\tdbg(\"[MainLoop]:#LINE# openstart=%s || tpos=%s || name=%s\",str(openstart),str(tpos),str(name))\n\t\t-- }}}\n\t\tif not name then break end\n\t\t-- Some more vars {{{\n\t\tindex = index + 1\n\t\tlocal tag = ElementNode:new(index, str(name), (node or {}), descend, openstart, tpos)\n\t\tnode = tag\n\t\tlocal tagloop\n\t\tlocal tagst, apos = tag:gettext(), 1\n\t\t-- }}}\n\t\twhile true do -- TagLoop {{{\n\t\t\tdbg(\"[TagLoop]:#LINE# tag.name=%s, tagloop=%s\",str(tag.name),str(tagloop))\n\t\t\tif tagloop == limit then -- {{{\n\t\t\t\terr(\"Tag parsing loop reached loop limit (%d). Consider either increasing it or checking HTML-code for syntax errors\", limit)\n\t\t\t\tbreak\n\t\t\tend -- }}}\n\t\t\t-- Attrs {{{\n\t\t\tlocal start, k, eq, quote, v, zsp\n\t\t\tstart, apos, k, zsp, eq, zsp, quote = tagst:find(\n\t\t\t\t\"%s+\" ..         -- some uncaptured space\n\t\t\t\t\"([^%s=/>]+)\" .. -- k = an unspaced string up to an optional \"=\" or the \"/\" or \">\"\n\t\t\t\t\"([%s]-)\"..      -- zero or more spaces\n\t\t\t\t\"(=?)\" ..        -- eq = the optional; \"=\", else \"\"\n\t\t\t\t\"([%s]-)\"..      -- zero or more spaces\n\t\t\t\t[=[(['\"]?)]=],      -- quote = an optional \"'\" or '\"' following the \"=\", or \"\"\n\t\t\tapos)\n\t\t\tdbg(\"[TagLoop]:#LINE# start=%s || apos=%s || k=%s || zsp='%s' || eq='%s', quote=[%s]\",str(start),str(apos),str(k),str(zsp),str(eq),str(quote))\n\t\t\t-- }}}\n\t\t\tif not k or k == \"/>\" or k == \">\" then break end\n\t\t\t-- Pattern {{{\n\t\t\tif eq == \"=\" then\n\t\t\t\tlocal pattern = \"=([^%s>]*)\"\n\t\t\t\tif quote ~= \"\" then\n\t\t\t\t\tpattern = quote .. \"([^\" .. quote .. \"]*)\" .. quote\n\t\t\t\tend\n\t\t\t\tstart, apos, v = tagst:find(pattern, apos)\n\t\t\t\tdbg(\"[TagLoop]:#LINE# start=%s || apos=%s || v=%s || pattern=%s\",str(start),str(apos),str(v),str(pattern))\n\t\t\tend\n\t\t\t-- }}}\n\t\t\tv=v or \"\"\n\t\t\tif tpl then -- {{{\n\t\t\t\tfor rk,rv in pairs(tpr) do\n\t\t\t\t\tv = v:gsub(rv,rk)\n\t\t\t\t\tdbg(\"[TagLoop]:#LINE# rv=%s || rk=%s\",str(rv),str(rk))\n\t\t\t\tend\n\t\t\tend -- }}}\n\n\t\t\tdbg(\"[TagLoop]:#LINE# k=%s || v=%s\",str(k),str(v))\n\t\t\ttag:addattribute(k, v)\n\t\t\ttagloop = (tagloop or 0) + 1\n\t\tend\n\t\t-- }}}\n\t\tif voidelements[tag.name:lower()] then -- {{{\n\t\t\tdescend = false\n\t\t\ttag:close()\n\t\telse\n\t\t\tdescend = true\n\t\t\topentags[tag.name] = opentags[tag.name] or {}\n\t\t\ttable.insert(opentags[tag.name], tag)\n\t\tend\n\t\t-- }}}\n\t\tlocal closeend = tpos\n\t\tlocal closingloop\n\t\twhile true do -- TagCloseLoop {{{\n\t\t\t-- Can't remember why did I add that, so comment it for now (and not remove), in case it will be needed again\n\t\t\t-- (although, it causes #59 and #60, so it will anyway be needed to rework)\n\t\t\t-- if voidelements[tag.name:lower()] then break end -- already closed\n\t\t\tif closingloop == limit then\n\t\t\t\terr(\"Tag closing loop reached loop limit (%d). Consider either increasing it or checking HTML-code for syntax errors\", limit)\n\t\t\t\tbreak\n\t\t\tend\n\n\t\t\tlocal closestart, closing, closename\n\t\t\tclosestart, closeend, closing, closename = root._text:find(\"[^<]*<(/?)([%w-]+)\", closeend)\n\t\t\tdbg(\"[TagCloseLoop]:#LINE# closestart=%s || closeend=%s || closing=%s || closename=%s\",str(closestart),str(closeend),str(closing),str(closename))\n\n\t\t\tif not closing or closing == \"\" then break end\n\n\t\t\ttag = table.remove(opentags[closename] or {}) or tag -- kludges for the cases of closing void or non-opened tags\n\t\t\tclosestart = root._text:find(\"<\", closestart)\n\t\t\tdbg(\"[TagCloseLoop]:#LINE# closestart=%s\",str(closestart))\n\t\t\ttag:close(closestart, closeend + 1)\n\t\t\tnode = tag.parent\n\t\t\tdescend = true\n\t\t\tclosingloop = (closingloop or 0) + 1\n\t\tend -- }}}\n\tend -- }}}\n\tif tpl then -- {{{\n\t\tdbg(\"tpl\")\n\t\tfor k,v in pairs(tpr) do\n\t\t\troot._text = root._text:gsub(v,k)\n\t\tend\n\tend -- }}}\n\treturn root\nend -- }}}\nHtmlParser.parse = parse\nreturn HtmlParser\n"
  },
  {
    "path": "crates/vfox/mise.toml",
    "content": "[tools]\n\"cargo-binstall\" = \"latest\"\n\"cargo:cargo-edit\" = \"latest\"\n\"cargo:git-cliff\" = \"latest\"\n\"npm:prettier\" = \"latest\"\n\n[tasks.build]\nrun = \"cargo build\"\n[tasks.test]\nalias = \"t\"\ndepends = ['test:setup-plugins']\nrun = \"cargo test\"\n[tasks.\"test:setup-plugins\"]\n# No longer needed - using local test plugins instead\nrun = \"true\"\n[tasks.lint-fix]\nrun = \"cargo fmt --all && cargo clippy --fix --all --all-features --allow-dirty --allow-staged -- -D warnings\"\n[tasks.lint]\ndepends = ['lint:prettier', 'lint:clippy', 'lint:fmt']\n[tasks.\"lint:prettier\"]\nrun = \"prettier -c .\"\n[tasks.\"lint:clippy\"]\nrun = 'cargo clippy --all-features -- -D warnings'\n[tasks.\"lint:fmt\"]\nrun = 'cargo fmt --all -- --check'\n[tasks.pre-commit]\ndepends = ['lint:*']\n"
  },
  {
    "path": "crates/vfox/plugins/.gitignore",
    "content": "cmake\nnodejs\n!test-nodejs\n"
  },
  {
    "path": "crates/vfox/plugins/.luarc.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json\",\n  \"runtime\": {\n    \"version\": \"Lua 5.1\"\n  },\n  \"diagnostics\": {\n    \"disable\": [\"duplicate-set-field\"]\n  },\n  \"workspace\": {\n    \"checkThirdParty\": false,\n    \"library\": [\"../types\"]\n  }\n}\n"
  },
  {
    "path": "crates/vfox/plugins/attestation/hooks/pre_install.lua",
    "content": "--- Returns pre-installed information including GitHub artifact attestation metadata.\n--- @param ctx {version: string} Context information\n--- @return table Version information with attestation\nfunction PLUGIN:PreInstall(ctx)\n\treturn {\n\t\tversion = ctx.version,\n\t\turl = \"https://example.com/download/\" .. ctx.version .. \".tar.gz\",\n\t\tattestation = {\n\t\t\tgithub_owner = \"test-owner\",\n\t\t\tgithub_repo = \"test-repo\",\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/attestation/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"attestation\"\n--- Plugin version\nPLUGIN.version = \"0.1.0\"\n--- Plugin repository\nPLUGIN.homepage = \"https://github.com/jdx/mise\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Test plugin that returns attestation metadata.\"\n\n--- !!! OPTIONAL !!!\n--- minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/Injection.lua",
    "content": "--[[\nDo not change any thing in the current file,\nit's just there to show what objects are injected by vfox and what they do.\n\nIt's just handy when developing plugins, IDE can use this object for code hints!\n --]]\nRUNTIME = {\n\t--- Operating system type at runtime (Windows, Linux, Darwin)\n\tosType = \"\",\n\t--- Operating system architecture at runtime (amd64, arm64, etc.)\n\tarchType = \"\",\n\t--- vfox runtime version\n\tversion = \"\",\n}\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/README.md",
    "content": "# vfox-nodejs\n\nNode.js plugin for [vfox](https://vfox.lhan.me/).\n\n## Install\n\nAfter installing [vfox](https://github.com/version-fox/vfox), install the plugin by running:\n\n```bash\nvfox add nodejs\n```\n\n## Mirror\n\nYou can configure the mirror by `VFOX_NODEJS_MIRROR` environment variable. The default value\nis `https://nodejs.org/dist/`.\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/hooks/available.lua",
    "content": "--- Get the available version list.\n--- @param ctx table Empty table, no data provided. Always {}.\n--- @return table Version list\nfunction PLUGIN:Available(ctx)\n\tif os.getenv(\"TEST_VFOX_LOG\") then\n\t\tlocal log = require(\"log\")\n\t\tlog.trace(\"log.trace msg\")\n\t\tlog.debug(\"log.debug msg\")\n\t\tlog.info(\"log.info msg\")\n\t\tlog.warn(\"log.warn msg\")\n\t\tlog.error(\"log.error msg\")\n\t\tlog.info(\"multi\", \"arg\", 123)\n\t\tprint(\"print msg\")\n\t\tio.stderr:write(\"stderr msg\\n\")\n\tend\n\treturn {\n\t\t{\n\t\t\tversion = \"1.0.0\",\n\t\t},\n\t\t{\n\t\t\tversion = \"1.0.1\",\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- Note: Be sure to distinguish between environment variable settings for different platforms!\n--- @param ctx {path: string} Context information (path = SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n\t--- this variable is same as ctx.sdkInfo['plugin-name'].path\n\tlocal version_path = ctx.path\n\tif RUNTIME.osType == \"windows\" then\n\t\treturn {\n\t\t\t{\n\t\t\t\tkey = \"PATH\",\n\t\t\t\tvalue = version_path,\n\t\t\t},\n\t\t}\n\telse\n\t\treturn {\n\t\t\t{\n\t\t\t\tkey = \"PATH\",\n\t\t\t\tvalue = version_path .. \"/bin\",\n\t\t\t},\n\t\t}\n\tend\nend\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/hooks/parse_legacy_file.lua",
    "content": "--- Parse the legacy file found by vfox to determine the version of the tool.\n--- Useful to extract version numbers from files like JavaScript's package.json or Golangs go.mod.\nfunction PLUGIN:ParseLegacyFile(ctx)\n\tlocal filename = ctx.filename\n\tif filename == nil then\n\t\terror(\"ctx.filename is nil\")\n\tend\n\tif filename ~= \".dummy-version\" then\n\t\terror(\"Expected filename to be .dummy-version, got \" .. filename)\n\tend\n\tlocal filepath = ctx.filepath\n\tlocal file = require(\"file\")\n\tlocal content = file.read(filepath)\n\tcontent = content:gsub(\"%s+\", \"\")\n\tif content == \"\" then\n\t\treturn {}\n\tend\n\n\treturn {\n\t\tversion = content,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/hooks/post_install.lua",
    "content": "function PLUGIN:PostInstall(ctx)\n\t--- SDK installation root path\n\tlocal rootPath = ctx.rootPath\n\tlocal runtimeVersion = ctx.runtimeVersion\n\n\t-- Create the installation directory structure for dummy plugin\n\tos.execute(\"mkdir -p \" .. rootPath .. \"/bin\")\n\n\t-- Create a dummy executable\n\tlocal dummy_file = io.open(rootPath .. \"/bin/dummy\", \"w\")\n\tif dummy_file then\n\t\tdummy_file:write(\"#!/bin/sh\\necho 'dummy version 1.0.0'\\n\")\n\t\tdummy_file:close()\n\t\tos.execute(\"chmod +x \" .. rootPath .. \"/bin/dummy\")\n\tend\nend\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/hooks/pre_install.lua",
    "content": "--- Returns some pre-installed information, such as version number, download address, local files, etc.\n--- If checksum is provided, vfox will automatically check it for you.\n--- @param ctx {version: string} Context information (version = User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n\tlocal version = ctx.version\n\n\treturn {\n\t\tversion = version,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/dummy/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"dummy\"\n--- Plugin version\nPLUGIN.version = \"0.3.0\"\n--- Plugin repository\nPLUGIN.homepage = \"https://github.com/version-fox/vfox-nodejs\"\n--- Plugin license\nPLUGIN.license = \"Apache 2.0\"\n--- Plugin description\nPLUGIN.description = \"Dummy plugin for testing.\"\n\n--- !!! OPTIONAL !!!\n--- minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n--- Some things that need user to be attention!\nPLUGIN.notes = {}\n\n--- List legacy configuration filenames for determining the specified version of the tool.\n--- such as \".node-version\", \".nvmrc\", etc.\nPLUGIN.legacyFilenames = {\n\t\".dummy-version\",\n}\n"
  },
  {
    "path": "crates/vfox/plugins/hooks/available.lua",
    "content": "--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n\treturn {\n\t\t{\n\t\t\tversion = \"1.0.0\",\n\t\t},\n\t\t{\n\t\t\tversion = \"1.0.1\",\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/hooks/env_keys.lua",
    "content": "--- Each SDK may have different environment variable configurations.\n--- This allows plugins to define custom environment variables (including PATH settings)\n--- Note: Be sure to distinguish between environment variable settings for different platforms!\n--- @param ctx {path: string} Context information (path = SDK installation directory)\nfunction PLUGIN:EnvKeys(ctx)\n\t--- this variable is same as ctx.sdkInfo['plugin-name'].path\n\tlocal version_path = ctx.path\n\tif RUNTIME.osType == \"windows\" then\n\t\treturn {\n\t\t\t{\n\t\t\t\tkey = \"PATH\",\n\t\t\t\tvalue = version_path,\n\t\t\t},\n\t\t}\n\telse\n\t\treturn {\n\t\t\t{\n\t\t\t\tkey = \"PATH\",\n\t\t\t\tvalue = version_path .. \"/bin\",\n\t\t\t},\n\t\t}\n\tend\nend\n"
  },
  {
    "path": "crates/vfox/plugins/hooks/post_install.lua",
    "content": "function PLUGIN:PostInstall(ctx)\n\t--- SDK installation root path\n\tlocal rootPath = ctx.rootPath\n\tlocal runtimeVersion = ctx.runtimeVersion\n\t--- Other SDK information, the `addition` field returned in PreInstall, obtained by name\n\t--TODO\n\t--local sdkInfo = ctx.sdkInfo['dummy']\n\t--local path = sdkInfo.path\n\t--local version = sdkInfo.version\n\t--local name = sdkInfo.name\nend\n"
  },
  {
    "path": "crates/vfox/plugins/hooks/pre_install.lua",
    "content": "--- Returns some pre-installed information, such as version number, download address, local files, etc.\n--- If checksum is provided, vfox will automatically check it for you.\n--- @param ctx {version: string} Context information (version = User-input version)\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n\tlocal version = ctx.version\n\n\treturn {\n\t\tversion = version,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/test-nodejs/hooks/available.lua",
    "content": "--- Return all available versions provided by this plugin\n--- @param ctx table Empty table used as context, for future extension\n--- @return table Descriptions of available versions and accompanying tool descriptions\nfunction PLUGIN:Available(ctx)\n\t-- Return hardcoded test versions to avoid network calls\n\treturn {\n\t\t{\n\t\t\tversion = \"20.3.0\",\n\t\t\tnote = \"\",\n\t\t\taddition = {\n\t\t\t\t{\n\t\t\t\t\tname = \"npm\",\n\t\t\t\t\tversion = \"9.6.7\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tversion = \"20.1.0\",\n\t\t\tnote = \"\",\n\t\t\taddition = {\n\t\t\t\t{\n\t\t\t\t\tname = \"npm\",\n\t\t\t\t\tversion = \"9.6.4\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tversion = \"20.0.0\",\n\t\t\tnote = \"LTS\",\n\t\t\taddition = {\n\t\t\t\t{\n\t\t\t\t\tname = \"npm\",\n\t\t\t\t\tversion = \"9.6.4\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tversion = \"19.0.0\",\n\t\t\tnote = \"\",\n\t\t\taddition = {\n\t\t\t\t{\n\t\t\t\t\tname = \"npm\",\n\t\t\t\t\tversion = \"9.0.0\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tversion = \"18.0.0\",\n\t\t\tnote = \"LTS\",\n\t\t\taddition = {\n\t\t\t\t{\n\t\t\t\t\tname = \"npm\",\n\t\t\t\t\tversion = \"8.0.0\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/test-nodejs/hooks/env_keys.lua",
    "content": "--- Return environment variables for the tool\n--- @param ctx table See /vfox/ctx.md#ctx-hooks for more information on ctx\n--- @return table Environment variables\nfunction PLUGIN:EnvKeys(ctx)\n\tlocal mainPath = ctx.path\n\treturn {\n\t\t{\n\t\t\tkey = \"PATH\",\n\t\t\tvalue = mainPath .. \"/bin\",\n\t\t},\n\t\t{\n\t\t\tkey = \"NODE_HOME\",\n\t\t\tvalue = mainPath,\n\t\t},\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/test-nodejs/hooks/parse_legacy_file.lua",
    "content": "--- Parse the legacy file to extract the version\n--- @param ctx table See /vfox/ctx.md#ctx-hooks for more information on ctx\n--- @return table Version information\nfunction PLUGIN:ParseLegacyFile(ctx)\n\tlocal filepath = ctx.filepath\n\tlocal file = io.open(filepath, \"r\")\n\tif file == nil then\n\t\treturn {}\n\tend\n\tlocal content = file:read(\"*a\")\n\tfile:close()\n\n\t-- Remove any leading/trailing whitespace and 'v' prefix\n\tcontent = content:gsub(\"%s+\", \"\")\n\tcontent = content:gsub(\"^v\", \"\")\n\n\tif content == \"\" then\n\t\treturn {}\n\tend\n\n\treturn {\n\t\tversion = content,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/test-nodejs/hooks/pre_install.lua",
    "content": "--- Return the URL to download the tool\n--- @param ctx table See /vfox/ctx.md#ctx-hooks for more information on ctx\n--- @return table Version information\nfunction PLUGIN:PreInstall(ctx)\n\tlocal version = ctx.version\n\n\t-- Return simple test data without runtime checks\n\treturn {\n\t\tversion = version,\n\t\turl = \"file:///fake/nodejs/node-v\" .. version .. \".tar.gz\",\n\t\tsha256 = \"fakehash\" .. version,\n\t}\nend\n"
  },
  {
    "path": "crates/vfox/plugins/test-nodejs/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"test-nodejs\"\n--- Plugin version\nPLUGIN.version = \"1.0.0\"\n--- Plugin repository\nPLUGIN.homepage = \"https://nodejs.org\"\n--- Plugin license\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"Test Node.js plugin for vfox tests\"\n\n--- !!! OPTIONAL !!!\n--- minimum compatible vfox version\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n--- Some things that need user to be attention!\nPLUGIN.notes = {}\n\n--- List legacy configuration filenames for determining the specified version of the tool.\n--- such as \".node-version\", \".nvmrc\", etc.\nPLUGIN.legacyFilenames = {\n\t\".node-version\",\n\t\".nvmrc\",\n}\n"
  },
  {
    "path": "crates/vfox/src/bin.rs",
    "content": "#[cfg(feature = \"cli\")]\n#[macro_use]\nextern crate log;\n\n#[cfg(feature = \"cli\")]\nmod cli;\n\n#[allow(clippy::needless_return)]\n#[cfg(feature = \"cli\")]\n#[tokio::main]\nasync fn main() {\n    env_logger::init_from_env(env_logger::Env::default().filter_or(\"VFOX_LOG\", \"info\"));\n    if let Err(err) = cli::run().await {\n        error!(\"{err}\");\n        std::process::exit(1);\n    }\n}\n\n#[cfg(not(feature = \"cli\"))]\nfn main() {\n    panic!(\"cli feature is not enabled\");\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/available.rs",
    "content": "use vfox::{Vfox, VfoxResult};\n\n#[derive(clap::Args)]\npub struct Available {}\n\nimpl Available {\n    pub async fn run(&self) -> VfoxResult<()> {\n        for (name, url) in Vfox::list_available_sdks() {\n            println!(\"{name} {url}\");\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/env_keys.rs",
    "content": "use vfox::{Vfox, VfoxResult};\n\n#[derive(clap::Args)]\npub struct EnvKeys {\n    pub sdk: String,\n    pub version: String,\n}\n\nimpl EnvKeys {\n    pub async fn run(&self) -> VfoxResult<()> {\n        let vfox = Vfox::new();\n        let env_keys = vfox\n            .env_keys(\n                &self.sdk,\n                &self.version,\n                serde_json::Value::Object(Default::default()),\n            )\n            .await?;\n        for env_key in env_keys {\n            println!(\"{}={}\", env_key.key, env_key.value);\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/install.rs",
    "content": "use std::path::PathBuf;\nuse vfox::{Vfox, VfoxResult};\n\n#[derive(clap::Args)]\npub struct Install {\n    pub sdk: String,\n    pub version: String,\n    #[clap(short, long)]\n    pub output_dir: Option<PathBuf>,\n}\n\nimpl Install {\n    pub async fn run(&self) -> VfoxResult<()> {\n        let vfox = Vfox::new();\n        let out = self\n            .output_dir\n            .clone()\n            .unwrap_or_else(|| vfox.install_dir.join(&self.sdk).join(&self.version));\n        info!(\n            \"Installing {} version {} to {out:?}\",\n            self.sdk, self.version\n        );\n        vfox.install(&self.sdk, &self.version, &out).await?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/mod.rs",
    "content": "use clap::Parser;\nuse vfox::VfoxResult;\n\nmod available;\nmod env_keys;\nmod install;\nmod plugins;\n\n#[derive(Parser)]\n#[command(version)]\npub(crate) struct Cli {\n    #[command(subcommand)]\n    command: Commands,\n}\n\n#[derive(clap::Subcommand)]\nenum Commands {\n    Available(available::Available),\n    EnvKeys(env_keys::EnvKeys),\n    Install(install::Install),\n    #[command(alias = \"plugin\")]\n    Plugins(plugins::Plugins),\n}\n\nimpl Commands {\n    pub async fn run(self) -> VfoxResult<()> {\n        match self {\n            Commands::Available(available) => available.run().await,\n            Commands::EnvKeys(env_keys) => env_keys.run().await,\n            Commands::Install(install) => install.run().await,\n            Commands::Plugins(plugins) => plugins.run().await,\n        }\n    }\n}\n\npub async fn run() -> VfoxResult<()> {\n    Cli::parse().command.run().await\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/plugins/list.rs",
    "content": "use vfox::Vfox;\nuse vfox::VfoxResult;\n\n#[derive(clap::Args)]\n#[command(alias = \"ls\")]\npub struct List {}\n\nimpl List {\n    pub async fn run(&self) -> VfoxResult<()> {\n        let vfox = Vfox::new();\n        let sdks = vfox.list_sdks()?;\n        for sdk in sdks {\n            println!(\"{sdk}\");\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/cli/plugins/mod.rs",
    "content": "use vfox::VfoxResult;\n\nmod list;\n\n#[derive(clap::Subcommand)]\npub(crate) enum Commands {\n    // Install(install::Install),\n    List(list::List),\n}\n\n#[derive(clap::Args)]\npub(crate) struct Plugins {\n    #[clap(subcommand)]\n    command: Commands,\n}\n\nimpl Plugins {\n    pub(crate) async fn run(&self) -> VfoxResult<()> {\n        match &self.command {\n            Commands::List(list) => list.run().await,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/config.rs",
    "content": "use std::env::consts::{ARCH, OS};\nuse std::path::PathBuf;\nuse std::sync::{Mutex, MutexGuard};\n\n#[derive(Debug, Clone)]\npub struct Config {\n    pub plugin_dir: PathBuf,\n}\n\nstatic CONFIG: Mutex<Option<Config>> = Mutex::new(None);\n\nimpl Config {\n    pub fn get() -> Self {\n        Self::_get().as_ref().unwrap().clone()\n    }\n\n    fn _get() -> MutexGuard<'static, Option<Config>> {\n        let mut config = CONFIG.lock().unwrap();\n        if config.is_none() {\n            let home = homedir::my_home()\n                .ok()\n                .flatten()\n                .unwrap_or_else(|| PathBuf::from(\"/\"));\n            *config = Some(Config {\n                plugin_dir: home.join(\".version-fox/plugin\"),\n            });\n        }\n        config\n    }\n}\n\npub fn os() -> String {\n    match OS {\n        \"macos\" => \"darwin\".to_string(),\n        os => os.to_string(),\n    }\n}\n\npub fn arch() -> String {\n    match ARCH {\n        \"aarch64\" => \"arm64\".to_string(),\n        \"x86_64\" => \"amd64\".to_string(),\n        arch => arch.to_string(),\n    }\n}\n\n/// Detect the libc environment type at runtime.\n/// Returns `Some(\"gnu\")` on glibc Linux, `Some(\"musl\")` on musl Linux, `None` elsewhere.\n// NOTE: This logic mirrors is_musl_system() in src/platform.rs. Keep in sync.\n#[cfg(target_os = \"linux\")]\npub(crate) fn env_type() -> Option<String> {\n    use once_cell::sync::Lazy;\n    static ENV_TYPE: Lazy<Option<String>> = Lazy::new(|| {\n        // If glibc's dynamic linker exists, this is a glibc system\n        for dir in [\"/lib\", \"/lib64\"] {\n            if has_file_prefix(dir, \"ld-linux-\") {\n                return Some(\"gnu\".to_string());\n            }\n        }\n        // No glibc linker found — check for musl's\n        if has_file_prefix(\"/lib\", \"ld-musl-\") {\n            return Some(\"musl\".to_string());\n        }\n        None\n    });\n    ENV_TYPE.clone()\n}\n\n#[cfg(target_os = \"linux\")]\nfn has_file_prefix(dir: &str, prefix: &str) -> bool {\n    std::fs::read_dir(dir)\n        .map(|entries| {\n            entries\n                .flatten()\n                .any(|e| e.file_name().to_string_lossy().starts_with(prefix))\n        })\n        .unwrap_or(false)\n}\n\n/// On non-Linux platforms, libc variant is not applicable.\n#[cfg(not(target_os = \"linux\"))]\npub(crate) fn env_type() -> Option<String> {\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_os() {\n        let os = os();\n        assert!(!os.is_empty());\n    }\n\n    #[test]\n    fn test_arch() {\n        let arch = arch();\n        assert!(!arch.is_empty());\n    }\n\n    #[test]\n    fn test_env_type() {\n        let et = env_type();\n        match et.as_deref() {\n            Some(\"gnu\") | Some(\"musl\") | None => {}\n            other => panic!(\"unexpected env_type: {other:?}\"),\n        }\n    }\n\n    #[cfg(not(target_os = \"linux\"))]\n    #[test]\n    fn test_env_type_non_linux_returns_none() {\n        assert_eq!(env_type(), None);\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/context.rs",
    "content": "use mlua::{UserData, UserDataFields};\n\n#[derive(Debug)]\npub(crate) struct Context {\n    pub args: Vec<String>,\n    pub(crate) version: Option<String>,\n    // pub(crate) runtime_version: String,\n}\n\nimpl UserData for Context {\n    fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {\n        fields.add_field_method_get(\"args\", |_, t| Ok(t.args.clone()));\n        fields.add_field_method_get(\"version\", |_, t| Ok(t.version.clone()));\n        // fields.add_field_method_get(\"runtimeVersion\", |_, t| Ok(t.runtime_version.clone()));\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/embedded_plugins.rs",
    "content": "// This module provides access to embedded vfox plugin Lua code.\n// The actual code is generated at build time by build.rs\n\ninclude!(concat!(env!(\"OUT_DIR\"), \"/embedded_plugins.rs\"));\n"
  },
  {
    "path": "crates/vfox/src/error.rs",
    "content": "use mlua::Error as MLuaError;\nuse thiserror::Error;\nuse xx::XXError;\n\n#[derive(Error, Debug)]\n#[non_exhaustive]\npub enum VfoxError {\n    #[error(\"{0}\")]\n    Error(String),\n    #[error(transparent)]\n    LuaError(#[from] MLuaError),\n    #[error(\"serde_json\")]\n    SerdeJsonError(#[from] serde_json::Error),\n    #[error(transparent)]\n    XXError(#[from] XXError),\n    #[error(transparent)]\n    ReqwestError(#[from] reqwest::Error),\n    #[error(transparent)]\n    IoError(#[from] std::io::Error),\n    #[error(transparent)]\n    UrlParseError(#[from] url::ParseError),\n    #[error(transparent)]\n    AttestationError(#[from] sigstore_verification::AttestationError),\n}\n\npub type Result<T> = std::result::Result<T, VfoxError>;\n\nimpl From<String> for VfoxError {\n    fn from(s: String) -> Self {\n        VfoxError::Error(s)\n    }\n}\n\nimpl From<&str> for VfoxError {\n    fn from(s: &str) -> Self {\n        VfoxError::Error(s.to_string())\n    }\n}\n\n#[macro_export]\nmacro_rules! error {\n    ($($arg:tt)*) => {\n        return Err(VfoxError::Error(format!($($arg)*)));\n    };\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/available.rs",
    "content": "use mlua::prelude::LuaError;\nuse mlua::{FromLua, Lua, Value};\n\nuse crate::Plugin;\nuse crate::error::Result;\n\nimpl Plugin {\n    #[allow(clippy::needless_return)] // seems to be a clippy bug\n    #[tokio::main(flavor = \"current_thread\")]\n    pub async fn available(&self) -> Result<Vec<AvailableVersion>> {\n        self.available_async().await\n    }\n\n    pub async fn available_async(&self) -> Result<Vec<AvailableVersion>> {\n        debug!(\"[vfox:{}] available_async\", &self.name);\n        let ctx = self.context(None)?;\n        let available = self\n            .eval_async(chunk! {\n                require \"hooks/available\"\n                return PLUGIN:Available($ctx)\n            })\n            .await?;\n\n        Ok(available)\n    }\n}\n\n#[derive(Debug)]\npub struct AvailableVersion {\n    pub version: String,\n    pub note: Option<String>,\n    /// If true, this version is a rolling release (like \"nightly\") that should\n    /// always be considered potentially outdated for `mise up` purposes\n    pub rolling: bool,\n    /// Checksum of the release asset, used to detect changes in rolling releases\n    pub checksum: Option<String>,\n}\n\nimpl FromLua for AvailableVersion {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => {\n                let rolling = table.get::<Option<bool>>(\"rolling\")?.unwrap_or(false);\n                let checksum = table.get::<Option<String>>(\"checksum\")?;\n                Ok(AvailableVersion {\n                    version: table.get::<String>(\"version\")?,\n                    note: table.get::<Option<String>>(\"note\")?,\n                    rolling,\n                    checksum,\n                })\n            }\n            _ => panic!(\"Expected table\"),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::Plugin;\n\n    #[test]\n    fn dummy() {\n        let versions = run(\"dummy\");\n        assert_debug_snapshot!(versions, @r###\"\n        [\n            \"1.0.0\",\n            \"1.0.1\",\n        ]\n        \"###);\n    }\n\n    #[tokio::test]\n    async fn dummy_async() {\n        let versions = run_async(\"dummy\").await;\n        assert_debug_snapshot!(versions, @r###\"\n        [\n            \"1.0.0\",\n            \"1.0.1\",\n        ]\n        \"###);\n    }\n\n    #[tokio::test]\n    async fn test_nodejs_async() {\n        let versions = run_async(\"test-nodejs\").await;\n        assert!(versions.contains(&\"20.0.0\".to_string()));\n    }\n\n    fn run(plugin: &str) -> Vec<String> {\n        let p = Plugin::test(plugin);\n        let r = p.available().unwrap();\n        r.iter().map(|v| v.version.clone()).collect()\n    }\n\n    async fn run_async(plugin: &str) -> Vec<String> {\n        let p = Plugin::test(plugin);\n        let r = p.available_async().await.unwrap();\n        r.iter().map(|v| v.version.clone()).collect()\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/backend_exec_env.rs",
    "content": "use indexmap::IndexMap;\nuse std::path::PathBuf;\n\nuse mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value, prelude::LuaError};\n\nuse crate::{Plugin, error::Result, hooks::env_keys::EnvKey};\n\n#[derive(Debug, Clone)]\npub struct BackendExecEnvContext {\n    pub tool: String,\n    pub version: String,\n    pub install_path: PathBuf,\n    pub options: IndexMap<String, String>,\n}\n\n#[derive(Debug)]\npub struct BackendExecEnvResponse {\n    pub env_vars: Vec<EnvKey>,\n}\n\nimpl Plugin {\n    pub async fn backend_exec_env(\n        &self,\n        ctx: BackendExecEnvContext,\n    ) -> Result<BackendExecEnvResponse> {\n        debug!(\"[vfox:{}] backend_exec_env\", &self.name);\n        self.eval_async(chunk! {\n            require \"hooks/backend_exec_env\"\n            return PLUGIN:BackendExecEnv($ctx)\n        })\n        .await\n    }\n}\n\nimpl IntoLua for BackendExecEnvContext {\n    fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"tool\", self.tool)?;\n        table.set(\"version\", self.version)?;\n        table.set(\n            \"install_path\",\n            self.install_path.to_string_lossy().to_string(),\n        )?;\n        table.set(\"options\", lua.to_value(&self.options)?)?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for BackendExecEnvResponse {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => Ok(BackendExecEnvResponse {\n                env_vars: table.get::<Vec<crate::hooks::env_keys::EnvKey>>(\"env_vars\")?,\n            }),\n            _ => Err(LuaError::FromLuaConversionError {\n                from: value.type_name(),\n                to: \"BackendExecEnvResponse\".to_string(),\n                message: Some(\"Expected table\".to_string()),\n            }),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/backend_install.rs",
    "content": "use indexmap::IndexMap;\nuse std::path::PathBuf;\n\nuse mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value, prelude::LuaError};\n\nuse crate::{Plugin, error::Result};\n\n#[derive(Debug)]\npub struct BackendInstallContext {\n    pub tool: String,\n    pub version: String,\n    pub install_path: PathBuf,\n    pub download_path: PathBuf,\n    pub options: IndexMap<String, String>,\n}\n\n#[derive(Debug)]\npub struct BackendInstallResponse {}\n\nimpl Plugin {\n    pub async fn backend_install(\n        &self,\n        ctx: BackendInstallContext,\n    ) -> Result<BackendInstallResponse> {\n        debug!(\"[vfox:{}] backend_install\", &self.name);\n        self.eval_async(chunk! {\n            require \"hooks/backend_install\"\n            return PLUGIN:BackendInstall($ctx)\n        })\n        .await\n    }\n}\n\nimpl IntoLua for BackendInstallContext {\n    fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"tool\", self.tool)?;\n        table.set(\"version\", self.version)?;\n        table.set(\n            \"install_path\",\n            self.install_path.to_string_lossy().to_string(),\n        )?;\n        table.set(\n            \"download_path\",\n            self.download_path.to_string_lossy().to_string(),\n        )?;\n        table.set(\"options\", lua.to_value(&self.options)?)?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for BackendInstallResponse {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(_) => Ok(BackendInstallResponse {}),\n            _ => Err(LuaError::FromLuaConversionError {\n                from: value.type_name(),\n                to: \"BackendInstallResponse\".to_string(),\n                message: Some(\"Expected table\".to_string()),\n            }),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/backend_list_versions.rs",
    "content": "use crate::{Plugin, error::Result};\nuse mlua::{FromLua, IntoLua, Lua, Value, prelude::LuaError};\n\n#[derive(Debug, Clone)]\npub struct BackendListVersionsContext {\n    pub tool: String,\n}\n\n#[derive(Debug, Clone)]\npub struct BackendListVersionsResponse {\n    pub versions: Vec<String>,\n}\n\nimpl Plugin {\n    pub async fn backend_list_versions(\n        &self,\n        ctx: BackendListVersionsContext,\n    ) -> Result<BackendListVersionsResponse> {\n        debug!(\"[vfox:{}] backend_list_versions\", &self.name);\n        self.eval_async(chunk! {\n            require \"hooks/backend_list_versions\"\n            return PLUGIN:BackendListVersions($ctx)\n        })\n        .await\n    }\n}\n\nimpl IntoLua for BackendListVersionsContext {\n    fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"tool\", self.tool)?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for BackendListVersionsResponse {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => Ok(BackendListVersionsResponse {\n                versions: table.get::<Vec<String>>(\"versions\")?,\n            }),\n            _ => Err(LuaError::FromLuaConversionError {\n                from: value.type_name(),\n                to: \"BackendListVersionsResponse\".to_string(),\n                message: Some(\"Expected table\".to_string()),\n            }),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/env_keys.rs",
    "content": "use mlua::prelude::LuaError;\nuse mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value};\nuse std::collections::BTreeMap;\nuse std::path::PathBuf;\n\nuse crate::Plugin;\nuse crate::error::Result;\nuse crate::sdk_info::SdkInfo;\n\n#[derive(Debug)]\npub struct EnvKey {\n    pub key: String,\n    pub value: String,\n}\n\n#[derive(Debug)]\npub struct EnvKeysContext<T: serde::Serialize> {\n    pub args: Vec<String>,\n    pub version: String,\n    pub path: PathBuf,\n    pub main: SdkInfo,\n    pub sdk_info: BTreeMap<String, SdkInfo>,\n    pub options: T,\n}\n\nimpl Plugin {\n    pub async fn env_keys<T: serde::Serialize>(\n        &self,\n        ctx: EnvKeysContext<T>,\n    ) -> Result<Vec<EnvKey>> {\n        debug!(\"[vfox:{}] env_keys\", &self.name);\n        let env_keys = self\n            .eval_async(chunk! {\n                require \"hooks/env_keys\"\n                return PLUGIN:EnvKeys($ctx)\n            })\n            .await?;\n\n        Ok(env_keys)\n    }\n}\n\nimpl<T: serde::Serialize> IntoLua for EnvKeysContext<T> {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"version\", self.version)?;\n        table.set(\"path\", self.path.to_string_lossy().to_string())?;\n        table.set(\"sdkInfo\", self.sdk_info)?;\n        table.set(\"main\", self.main)?;\n        table.set(\"options\", lua.to_value(&self.options)?)?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for EnvKey {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => Ok(EnvKey {\n                key: table.get::<String>(\"key\")?,\n                value: table.get::<String>(\"value\")?,\n            }),\n            _ => panic!(\"Expected table\"),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/mise_env.rs",
    "content": "use mlua::prelude::LuaError;\nuse mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value};\nuse std::path::PathBuf;\n\nuse crate::Plugin;\nuse crate::error::Result;\nuse crate::hooks::env_keys::EnvKey;\n\n#[derive(Debug)]\npub struct MiseEnvContext<T: serde::Serialize> {\n    pub args: Vec<String>,\n    pub options: T,\n}\n\n/// Result from a mise_env hook call\n/// Supports both legacy format (just array of env keys) and extended format\n/// with cache metadata\n#[derive(Debug, Default)]\npub struct MiseEnvResult {\n    /// Environment variables to set\n    pub env: Vec<EnvKey>,\n    /// Whether this module's output can be cached\n    /// Defaults to false for backward compatibility\n    pub cacheable: bool,\n    /// Files to watch for cache invalidation\n    pub watch_files: Vec<PathBuf>,\n    /// Whether the plugin wants its env vars to be redacted\n    /// When true, mise will redact these values unless the user explicitly opts out\n    pub redact: bool,\n}\n\nimpl Plugin {\n    pub async fn mise_env<T: serde::Serialize>(\n        &self,\n        ctx: MiseEnvContext<T>,\n    ) -> Result<MiseEnvResult> {\n        debug!(\"[vfox:{}] mise_env\", &self.name);\n        let result = self\n            .eval_async(chunk! {\n                require \"hooks/mise_env\"\n                return PLUGIN:MiseEnv($ctx)\n            })\n            .await?;\n\n        Ok(result)\n    }\n}\n\nimpl<T: serde::Serialize> IntoLua for MiseEnvContext<T> {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"options\", lua.to_value(&self.options)?)?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for MiseEnvResult {\n    fn from_lua(value: Value, lua: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            // Extended format: { cacheable = true, watch_files = {...}, env = {...} }\n            Value::Table(table) => {\n                // Check if this is extended format by looking for known keys\n                let has_env = table.contains_key(\"env\")?;\n                let has_cacheable = table.contains_key(\"cacheable\")?;\n                let has_watch_files = table.contains_key(\"watch_files\")?;\n                let has_redact = table.contains_key(\"redact\")?;\n\n                if has_env || has_cacheable || has_watch_files || has_redact {\n                    // Extended format\n                    let env: Vec<EnvKey> = table\n                        .get::<Option<Vec<EnvKey>>>(\"env\")\n                        .map_err(|e| {\n                            LuaError::RuntimeError(format!(\n                                \"Invalid 'env' field in MiseEnv result: expected array of {{key, value}} pairs. Error: {e}\"\n                            ))\n                        })?\n                        .unwrap_or_default();\n                    let cacheable: bool = table\n                        .get::<Option<bool>>(\"cacheable\")\n                        .map_err(|e| {\n                            LuaError::RuntimeError(format!(\n                                \"Invalid 'cacheable' field in MiseEnv result: expected boolean. Error: {e}\"\n                            ))\n                        })?\n                        .unwrap_or(false);\n                    let watch_files: Vec<String> = table\n                        .get::<Option<Vec<String>>>(\"watch_files\")\n                        .map_err(|e| {\n                            LuaError::RuntimeError(format!(\n                                \"Invalid 'watch_files' field in MiseEnv result: expected array of strings. Error: {e}\"\n                            ))\n                        })?\n                        .unwrap_or_default();\n                    let redact: bool = table\n                        .get::<Option<bool>>(\"redact\")\n                        .map_err(|e| {\n                            LuaError::RuntimeError(format!(\n                                \"Invalid 'redact' field in MiseEnv result: expected boolean. Error: {e}\"\n                            ))\n                        })?\n                        .unwrap_or(false);\n\n                    Ok(MiseEnvResult {\n                        env,\n                        cacheable,\n                        watch_files: watch_files.into_iter().map(PathBuf::from).collect(),\n                        redact,\n                    })\n                } else {\n                    // Legacy format: table is actually an array of env keys\n                    // Try to parse as array\n                    let env: Vec<EnvKey> = Vec::from_lua(Value::Table(table), lua).map_err(|e| {\n                        LuaError::RuntimeError(format!(\n                            \"Failed to parse MiseEnv hook result. Expected either:\\n\\\n                             - Legacy format: array of {{key, value}} pairs like {{{{\\\"KEY\\\", \\\"VALUE\\\"}}, ...}}\\n\\\n                             - Extended format: table with 'env' field like {{env = {{}}, cacheable = true}}\\n\\\n                             Error: {e}\"\n                        ))\n                    })?;\n                    Ok(MiseEnvResult {\n                        env,\n                        cacheable: false,\n                        watch_files: vec![],\n                        redact: false,\n                    })\n                }\n            }\n            // Empty/nil result\n            Value::Nil => Ok(MiseEnvResult::default()),\n            _ => Err(LuaError::RuntimeError(\n                \"Expected table or nil from MiseEnv hook\".to_string(),\n            )),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/mise_path.rs",
    "content": "use mlua::{IntoLua, Lua, LuaSerdeExt, Value};\n\nuse crate::Plugin;\nuse crate::error::Result;\n\n#[derive(Debug)]\npub struct MisePathContext<T: serde::Serialize> {\n    pub args: Vec<String>,\n    pub options: T,\n}\n\nimpl Plugin {\n    pub async fn mise_path<T: serde::Serialize>(\n        &self,\n        ctx: MisePathContext<T>,\n    ) -> Result<Vec<String>> {\n        debug!(\"[vfox:{}] mise_path\", &self.name);\n        let path = self\n            .eval_async(chunk! {\n                require \"hooks/mise_path\"\n                return PLUGIN:MisePath($ctx)\n            })\n            .await?;\n\n        Ok(path)\n    }\n}\n\nimpl<T: serde::Serialize> IntoLua for MisePathContext<T> {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"options\", lua.to_value(&self.options)?)?;\n        Ok(Value::Table(table))\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/mod.rs",
    "content": "pub mod available;\npub mod backend_exec_env;\npub mod backend_install;\npub mod backend_list_versions;\npub mod env_keys;\npub mod mise_env;\npub mod mise_path;\npub mod parse_legacy_file;\npub mod post_install;\npub mod pre_install;\npub mod pre_use;\n"
  },
  {
    "path": "crates/vfox/src/hooks/parse_legacy_file.rs",
    "content": "use mlua::prelude::LuaError;\nuse mlua::{FromLua, IntoLua, Lua, MultiValue, Value};\nuse std::path::{Path, PathBuf};\n\nuse crate::Plugin;\nuse crate::error::Result;\n\n#[derive(Debug)]\npub struct LegacyFileContext {\n    pub args: Vec<String>,\n    pub filepath: PathBuf,\n}\n\n#[derive(Debug)]\npub struct ParseLegacyFileResponse {\n    pub version: Option<String>,\n}\n\nimpl Plugin {\n    pub async fn parse_legacy_file(&self, legacy_file: &Path) -> Result<ParseLegacyFileResponse> {\n        debug!(\"[vfox:{}] parse_legacy_file\", &self.name);\n        let ctx = LegacyFileContext {\n            args: vec![],\n            filepath: legacy_file.to_path_buf(),\n        };\n        let legacy_file_response = self\n            .eval_async(chunk! {\n                require \"hooks/available\"\n                require \"hooks/parse_legacy_file\"\n                return PLUGIN:ParseLegacyFile($ctx)\n            })\n            .await?;\n\n        Ok(legacy_file_response)\n    }\n}\n\nimpl IntoLua for LegacyFileContext {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"args\", self.args)?;\n        table.set(\n            \"filename\",\n            self.filepath\n                .file_name()\n                .ok_or(LuaError::RuntimeError(String::from(\n                    \"No basename for legacy file\",\n                )))?\n                .to_os_string()\n                .into_string()\n                .or(Err(LuaError::RuntimeError(String::from(\n                    \"Could not convert basename to string\",\n                ))))?,\n        )?;\n        table.set(\"filepath\", self.filepath.to_string_lossy().to_string())?;\n        table.set(\n            \"getInstalledVersions\",\n            lua.create_async_function(|lua, _input: MultiValue| async move {\n                let plugin_dir = lua.named_registry_value::<PathBuf>(\"plugin_dir\")?;\n                Ok(Plugin::from_dir(plugin_dir.as_path())\n                    .map_err(|e| LuaError::RuntimeError(e.to_string()))?\n                    .available_async()\n                    .await\n                    .map_err(|e| LuaError::RuntimeError(e.to_string()))?\n                    .into_iter()\n                    .map(|v| v.version)\n                    .collect::<Vec<String>>())\n            })?,\n        )?;\n        Ok(Value::Table(table))\n    }\n}\n\nimpl FromLua for ParseLegacyFileResponse {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => Ok(ParseLegacyFileResponse {\n                version: table.get::<Option<String>>(\"version\")?,\n            }),\n            _ => panic!(\"Expected table\"),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::Vfox;\n\n    #[tokio::test]\n    async fn test_parse_legacy_file_test_nodejs() {\n        let vfox = Vfox::test();\n        let response = vfox\n            .parse_legacy_file(\"test-nodejs\", Path::new(\"test/data/.node-version\"))\n            .await\n            .unwrap();\n        let out = format!(\"{response:?}\");\n        assert_snapshot!(out, @r###\"ParseLegacyFileResponse { version: Some(\"20.0.0\") }\"###);\n    }\n\n    #[tokio::test]\n    async fn test_parse_legacy_file_dummy() {\n        let vfox = Vfox::test();\n        let response = vfox\n            .parse_legacy_file(\"dummy\", Path::new(\"test/data/.dummy-version\"))\n            .await\n            .unwrap();\n        let out = format!(\"{response:?}\");\n        assert_snapshot!(out, @r###\"ParseLegacyFileResponse { version: Some(\"1.0.0\") }\"###);\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/post_install.rs",
    "content": "use crate::Plugin;\nuse crate::error::Result;\nuse crate::sdk_info::SdkInfo;\nuse mlua::{IntoLua, Lua, Value};\nuse std::collections::BTreeMap;\nuse std::path::PathBuf;\n\nimpl Plugin {\n    pub async fn post_install(&self, ctx: PostInstallContext) -> Result<()> {\n        debug!(\"[vfox:{}] post_install\", &self.name);\n        self.exec_async(chunk! {\n            require \"hooks/post_install\"\n            PLUGIN:PostInstall($ctx)\n        })\n        .await\n    }\n}\n\npub struct PostInstallContext {\n    pub root_path: PathBuf,\n    pub runtime_version: String,\n    pub sdk_info: BTreeMap<String, SdkInfo>,\n}\n\nimpl IntoLua for PostInstallContext {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"rootPath\", self.root_path.to_string_lossy().to_string())?;\n        table.set(\"runtimeVersion\", self.runtime_version)?;\n        table.set(\"sdkInfo\", self.sdk_info)?;\n        Ok(Value::Table(table))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::Plugin;\n    use tokio::test;\n\n    use super::*;\n\n    #[test]\n    async fn dummy() {\n        let p = Plugin::test(\"dummy\");\n        let ctx = PostInstallContext {\n            root_path: PathBuf::from(\"root_path\"),\n            runtime_version: \"runtime_version\".to_string(),\n            sdk_info: BTreeMap::new(),\n        };\n        p.post_install(ctx).await.unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/pre_install.rs",
    "content": "use std::path::PathBuf;\n\nuse mlua::prelude::LuaError;\nuse mlua::{FromLua, Lua, Table, Value};\n\nuse crate::Plugin;\nuse crate::error::Result;\nuse crate::runtime::Runtime;\n\nimpl Plugin {\n    pub async fn pre_install(&self, version: &str) -> Result<PreInstall> {\n        debug!(\"[vfox:{}] pre_install\", &self.name);\n        let ctx = self.context(Some(version.to_string()))?;\n        let pre_install = self\n            .eval_async(chunk! {\n                require \"hooks/pre_install\"\n                return PLUGIN:PreInstall($ctx)\n            })\n            .await?;\n\n        Ok(pre_install)\n    }\n\n    pub async fn pre_install_for_platform(\n        &self,\n        version: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<PreInstall> {\n        debug!(\n            \"[vfox:{}] pre_install_for_platform os={} arch={}\",\n            &self.name, os, arch\n        );\n        let ctx = self.context(Some(version.to_string()))?;\n        let target_os = os.to_string();\n        let target_arch = arch.to_string();\n        let target_runtime = Runtime::with_platform(self.dir.clone(), os, arch);\n        let pre_install = self\n            .eval_async(chunk! {\n                require \"hooks/pre_install\"\n                -- Override globals with target platform for cross-platform URL generation\n                local saved_os = OS_TYPE\n                local saved_arch = ARCH_TYPE\n                local saved_runtime = RUNTIME\n                OS_TYPE = $target_os\n                ARCH_TYPE = $target_arch\n                RUNTIME = $target_runtime\n                local result = PLUGIN:PreInstall($ctx)\n                -- Restore original values\n                OS_TYPE = saved_os\n                ARCH_TYPE = saved_arch\n                RUNTIME = saved_runtime\n                return result\n            })\n            .await?;\n\n        Ok(pre_install)\n    }\n}\n\n/// The type of attestation that was successfully verified.\n///\n/// This is the vfox-relevant subset of `ProvenanceType` in `src/lockfile.rs`.\n/// `Minisign` is intentionally absent — vfox plugins do not produce Minisign\n/// signatures, so there is no vfox-side variant for it.\n///\n/// When adding a new vfox attestation type, add a variant here **and** add the\n/// corresponding variant to `ProvenanceType` in `src/lockfile.rs`, then update\n/// `verified_attestation_to_provenance()` to bridge the two enums.\n///\n/// Priority order (highest first): GithubAttestations > Slsa > Cosign.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum VerifiedAttestation {\n    /// GitHub artifact attestations (owner/repo, optional signer workflow).\n    GithubAttestations {\n        owner: String,\n        repo: String,\n        signer_workflow: Option<String>,\n    },\n    /// SLSA provenance verification.\n    Slsa { provenance_path: PathBuf },\n    /// Cosign signature/bundle verification.\n    Cosign {\n        sig_or_bundle_path: PathBuf,\n        public_key_path: Option<PathBuf>,\n    },\n}\n\n/// Optional attestation parameters provided by the return value of the preinstall hook.\n#[derive(Debug)]\npub struct PreInstallAttestation {\n    // GitHub\n    pub github_owner: Option<String>,\n    pub github_repo: Option<String>,\n    pub github_signer_workflow: Option<String>,\n    // Cosign\n    pub cosign_sig_or_bundle_path: Option<PathBuf>,\n    pub cosign_public_key_path: Option<PathBuf>,\n    // SLSA\n    pub slsa_provenance_path: Option<PathBuf>,\n    pub slsa_min_level: Option<u8>,\n}\n\nimpl FromLua for PreInstallAttestation {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => {\n                validate_github_artifact_attestation_params(&table)?;\n                validate_cosign_attestation_params(&table)?;\n                validate_slsa_attestation_params(&table)?;\n\n                Ok(PreInstallAttestation {\n                    github_owner: table.get::<Option<String>>(\"github_owner\")?,\n                    github_repo: table.get::<Option<String>>(\"github_repo\")?,\n                    github_signer_workflow: table\n                        .get::<Option<String>>(\"github_signer_workflow\")?,\n                    cosign_sig_or_bundle_path: table\n                        .get::<Option<PathBuf>>(\"cosign_sig_or_bundle_path\")?,\n                    cosign_public_key_path: table\n                        .get::<Option<PathBuf>>(\"cosign_public_key_path\")?,\n                    slsa_provenance_path: table.get::<Option<PathBuf>>(\"slsa_provenance_path\")?,\n                    slsa_min_level: table.get::<Option<u8>>(\"slsa_min_level\")?,\n                })\n            }\n            _ => Err(LuaError::FromLuaConversionError {\n                from: \"table\",\n                to: \"PreInstallAttestation\".into(),\n                message: Some(\"expected table for attestation field\".to_string()),\n            }),\n        }\n    }\n}\n\n/// Validates that if one of the GitHub artifact attestation parameters are set, the other requisite\n/// parameters are also set.\n///\n/// `github_repo` requires `github_owner` and vice versa, and `github_signer_workflow` requires\n/// both aforementioned parameters.\nfn validate_github_artifact_attestation_params(table: &Table) -> std::result::Result<(), LuaError> {\n    if table.contains_key(\"github_owner\")? && !table.contains_key(\"github_repo\")? {\n        return Err(LuaError::FromLuaConversionError {\n            from: \"table\",\n            to: \"PreInstallAttestation\".into(),\n            message: Some(\"github_owner requires github_repo for artifact attestation\".to_string()),\n        });\n    }\n\n    if table.contains_key(\"github_repo\")? && !table.contains_key(\"github_owner\")? {\n        return Err(LuaError::FromLuaConversionError {\n            from: \"table\",\n            to: \"PreInstallAttestation\".into(),\n            message: Some(\"github_repo requires github_owner for artifact attestation\".to_string()),\n        });\n    }\n\n    if table.contains_key(\"github_signer_workflow\")?\n        && (!table.contains_key(\"github_owner\")? || !table.contains_key(\"github_repo\")?)\n    {\n        return Err(LuaError::FromLuaConversionError {\n            from: \"table\",\n            to: \"PreInstallAttestation\".into(),\n            message: Some(\n                \"github_signer_workflow requires github_owner and github_repo for artifact attestation\"\n                    .to_string(),\n            ),\n        });\n    }\n\n    Ok(())\n}\n\n/// Validates that if the public key path is set, then the sig/bundle path must also be set.\nfn validate_cosign_attestation_params(table: &Table) -> std::result::Result<(), LuaError> {\n    if table.contains_key(\"cosign_public_key_path\")?\n        && !table.contains_key(\"cosign_sig_or_bundle_path\")?\n    {\n        return Err(LuaError::FromLuaConversionError {\n            from: \"table\",\n            to: \"PreInstallAttestation\".into(),\n            message: Some(\n                \"cosign_public_key_path requires cosign_sig_or_bundle_path for attestation\"\n                    .to_string(),\n            ),\n        });\n    }\n\n    Ok(())\n}\n\n/// Validates that if the SLSA min level is set, then the provenance path must also be set.\nfn validate_slsa_attestation_params(table: &Table) -> std::result::Result<(), LuaError> {\n    if table.contains_key(\"slsa_min_level\")? && !table.contains_key(\"slsa_provenance_path\")? {\n        return Err(LuaError::FromLuaConversionError {\n            from: \"table\",\n            to: \"PreInstallAttestation\".into(),\n            message: Some(\n                \"slsa_min_level requires slsa_provenance_path for attestation\".to_string(),\n            ),\n        });\n    }\n\n    Ok(())\n}\n\n#[derive(Debug)]\npub struct PreInstall {\n    pub version: String,\n    pub url: Option<String>,\n    pub note: Option<String>,\n    pub sha256: Option<String>,\n    pub md5: Option<String>,\n    pub sha1: Option<String>,\n    pub sha512: Option<String>,\n    pub attestation: Option<PreInstallAttestation>,\n    // pub addition: Option<Table>,\n}\n\nimpl FromLua for PreInstall {\n    fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {\n        match value {\n            Value::Table(table) => {\n                if !table.contains_key(\"version\")? {\n                    return Err(LuaError::FromLuaConversionError {\n                        from: \"table\",\n                        to: \"PreInstall\".into(),\n                        message: Some(\"no version returned from vfox plugin\".to_string()),\n                    });\n                }\n                Ok(PreInstall {\n                    version: table.get::<String>(\"version\")?,\n                    url: table.get::<Option<String>>(\"url\")?,\n                    note: table.get::<Option<String>>(\"note\")?,\n                    sha256: table.get::<Option<String>>(\"sha256\")?,\n                    md5: table.get::<Option<String>>(\"md5\")?,\n                    sha1: table.get::<Option<String>>(\"sha1\")?,\n                    sha512: table.get::<Option<String>>(\"sha512\")?,\n                    attestation: table.get::<Option<PreInstallAttestation>>(\"attestation\")?,\n                    // addition,\n                })\n            }\n            _ => panic!(\"Expected table\"),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::Plugin;\n    use crate::hooks::pre_install::PreInstall;\n    use crate::hooks::pre_install::PreInstallAttestation;\n    use crate::runtime::Runtime;\n    use mlua::{FromLua, Lua};\n    use std::string::ToString;\n    use tokio::test;\n\n    #[test]\n    async fn dummy() {\n        let pre_install = run(\"dummy\", \"1.0.1\").await;\n        assert_debug_snapshot!(pre_install);\n    }\n\n    #[test]\n    async fn test_nodejs() {\n        Runtime::set_os(\"linux\".to_string());\n        Runtime::set_arch(\"x64\".to_string());\n        let pre_install = run(\"test-nodejs\", \"20.0.0\").await;\n        assert_debug_snapshot!(pre_install);\n\n        Runtime::set_os(\"macos\".to_string());\n        Runtime::set_arch(\"arm64\".to_string());\n        let pre_install = run(\"test-nodejs\", \"20.1.0\").await;\n        assert_debug_snapshot!(pre_install);\n\n        Runtime::set_os(\"windows\".to_string());\n        Runtime::set_arch(\"x64\".to_string());\n        let pre_install = run(\"test-nodejs\", \"20.3.0\").await;\n        assert_debug_snapshot!(pre_install);\n\n        Runtime::reset();\n    }\n\n    #[test]\n    async fn test_runtime_env_type_is_nil_for_platform_override() {\n        let plugin = Plugin::test(\"dummy\");\n\n        Runtime::set_env_type(Some(\"gnu\".to_string()));\n\n        let host_env_type: Option<String> = plugin\n            .eval_async(chunk! {\n                return RUNTIME.envType\n            })\n            .await\n            .unwrap();\n        assert_eq!(host_env_type, Some(\"gnu\".to_string()));\n\n        let target_runtime = Runtime::with_platform(plugin.dir.clone(), \"linux\", \"amd64\");\n        let target_os = \"linux\".to_string();\n        let target_arch = \"amd64\".to_string();\n        let target_env_type: Option<String> = plugin\n            .eval_async(chunk! {\n                local saved_os = OS_TYPE\n                local saved_arch = ARCH_TYPE\n                local saved_runtime = RUNTIME\n                OS_TYPE = $target_os\n                ARCH_TYPE = $target_arch\n                RUNTIME = $target_runtime\n                local env_type = RUNTIME.envType\n                OS_TYPE = saved_os\n                ARCH_TYPE = saved_arch\n                RUNTIME = saved_runtime\n                return env_type\n            })\n            .await\n            .unwrap();\n        assert_eq!(target_env_type, None);\n\n        Runtime::reset();\n    }\n\n    #[test]\n    async fn test_attestation_plugin() {\n        let pre_install = run(\"attestation\", \"1.2.3\").await;\n        assert_debug_snapshot!(pre_install);\n    }\n\n    #[test]\n    async fn test_github_attestation_valid() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"github_owner\", \"owner\").unwrap();\n        table.set(\"github_repo\", \"repo\").unwrap();\n        let att = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua).unwrap();\n        assert_eq!(att.github_owner, Some(\"owner\".to_string()));\n        assert_eq!(att.github_repo, Some(\"repo\".to_string()));\n        assert_eq!(att.github_signer_workflow, None);\n    }\n\n    #[test]\n    async fn test_github_attestation_owner_without_repo() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"github_owner\", \"owner\").unwrap();\n        let result = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua);\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(\n            err.contains(\"github_owner requires github_repo\"),\n            \"unexpected error: {err}\"\n        );\n    }\n\n    #[test]\n    async fn test_github_attestation_repo_without_owner() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"github_repo\", \"repo\").unwrap();\n        let result = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua);\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(\n            err.contains(\"github_repo requires github_owner\"),\n            \"unexpected error: {err}\"\n        );\n    }\n\n    #[test]\n    async fn test_github_attestation_signer_without_owner_repo() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"github_signer_workflow\", \"wf.yml\").unwrap();\n        let result = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua);\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(\n            err.contains(\"github_signer_workflow requires github_owner and github_repo\"),\n            \"unexpected error: {err}\"\n        );\n    }\n\n    #[test]\n    async fn test_cosign_public_key_without_sig() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"cosign_public_key_path\", \"/tmp/key.pub\").unwrap();\n        let result = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua);\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(\n            err.contains(\"cosign_public_key_path requires cosign_sig_or_bundle_path\"),\n            \"unexpected error: {err}\"\n        );\n    }\n\n    #[test]\n    async fn test_slsa_min_level_without_provenance() {\n        let lua = Lua::new();\n        let table = lua.create_table().unwrap();\n        table.set(\"slsa_min_level\", 2).unwrap();\n        let result = PreInstallAttestation::from_lua(mlua::Value::Table(table), &lua);\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(\n            err.contains(\"slsa_min_level requires slsa_provenance_path\"),\n            \"unexpected error: {err}\"\n        );\n    }\n\n    async fn run(plugin: &str, v: &str) -> PreInstall {\n        let p = Plugin::test(plugin);\n        p.pre_install(v).await.unwrap()\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/hooks/pre_use.rs",
    "content": "use indexmap::IndexMap;\nuse std::path::Path;\n\nuse crate::error::Result;\nuse crate::sdk_info::SdkInfo;\nuse crate::{Plugin, Vfox};\n\n#[allow(dead_code)]\n#[derive(Debug)]\npub struct PreUseContext {\n    pub installed_sdks: IndexMap<String, SdkInfo>,\n}\n\n#[derive(Debug)]\npub struct PreUseResponse {\n    pub version: Option<String>,\n}\n\nimpl Plugin {\n    pub async fn pre_use(&self, _vfox: &Vfox, _legacy_file: &Path) -> Result<PreUseResponse> {\n        debug!(\"[vfox:{}] pre_use\", &self.name);\n        // let ctx = PreUseContext {\n        //     installed_sdks: vfox.list_installed_versions(&self.name)?,\n        // };\n\n        unimplemented!(\"pre_use hook is not implemented\");\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/http.rs",
    "content": "use reqwest::{Client, ClientBuilder};\nuse std::sync::LazyLock;\n\npub static CLIENT: LazyLock<Client> = LazyLock::new(|| {\n    ClientBuilder::new()\n        .user_agent(format!(\"vfox.rs/{}\", env!(\"CARGO_PKG_VERSION\")))\n        .build()\n        .expect(\"Failed to create reqwest client\")\n});\n"
  },
  {
    "path": "crates/vfox/src/lib.rs",
    "content": "#[cfg(test)]\n#[macro_use]\nextern crate insta;\n#[macro_use]\nextern crate log;\n#[macro_use]\nextern crate mlua;\n\npub use error::Result as VfoxResult;\npub use error::VfoxError;\npub use hooks::pre_install::VerifiedAttestation;\npub use plugin::Plugin;\npub use vfox::InstallResult;\npub use vfox::Vfox;\n\nmod config;\nmod context;\npub mod embedded_plugins;\nmod error;\nmod hooks;\nmod http;\nmod lua_mod;\nmod metadata;\nmod plugin;\nmod registry;\nmod runtime;\nmod sdk_info;\nmod vfox;\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/archiver.rs",
    "content": "use crate::error::Result;\nuse mlua::{ExternalResult, Lua, MultiValue, Table};\nuse std::path::PathBuf;\n\npub fn mod_archiver(lua: &Lua) -> Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    Ok(loaded.set(\n        \"archiver\",\n        lua.create_table_from(vec![(\n            \"decompress\",\n            lua.create_async_function(\n                |_lua: mlua::Lua, input| async move { decompress(&_lua, input) },\n            )?,\n        )])?,\n    )?)\n}\n\nfn decompress(_lua: &Lua, input: MultiValue) -> mlua::Result<()> {\n    let paths: Vec<mlua::Value> = input.into_iter().collect();\n    let archive: PathBuf = PathBuf::from(paths[0].to_string()?);\n    let destination: PathBuf = PathBuf::from(paths[1].to_string()?);\n    let filename = archive.file_name().unwrap().to_str().unwrap();\n    if filename.ends_with(\".zip\") {\n        xx::archive::unzip(&archive, &destination).into_lua_err()?;\n    } else if filename.ends_with(\".tar.gz\") {\n        xx::archive::untar_gz(&archive, &destination).into_lua_err()?;\n    } else if filename.ends_with(\".tar.xz\") {\n        xx::archive::untar_xz(&archive, &destination).into_lua_err()?;\n    } else if filename.ends_with(\".tar.bz2\") {\n        xx::archive::untar_bz2(&archive, &destination).into_lua_err()?;\n    } else {\n        unimplemented!(\"Unsupported archive format {:?}\", archive);\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_zip() {\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let dst_path = temp_dir.path().join(\"unzip\");\n        let dst_path_str = dst_path.to_string_lossy().to_string();\n        let lua = Lua::new();\n        mod_archiver(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local archiver = require(\"archiver\")\n            archiver.decompress(\"test/data/foo.zip\", $dst_path_str)\n        })\n        .exec()\n        .unwrap();\n        assert_eq!(\n            std::fs::read_to_string(dst_path.join(\"foo/test.txt\")).unwrap(),\n            \"yep\\n\"\n        );\n        // TempDir automatically cleans up when dropped\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/cmd.rs",
    "content": "use mlua::Table;\nuse mlua::prelude::*;\nuse std::path::Path;\n\npub fn mod_cmd(lua: &Lua) -> LuaResult<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    let cmd = lua.create_table_from(vec![(\"exec\", lua.create_function(exec)?)])?;\n    loaded.set(\"cmd\", cmd.clone())?;\n    loaded.set(\"vfox.cmd\", cmd)?;\n    Ok(())\n}\n\nfn exec(lua: &Lua, args: mlua::MultiValue) -> LuaResult<String> {\n    use std::process::Command;\n\n    let (command, options) = match args.len() {\n        1 => {\n            let command: String = args.into_iter().next().unwrap().to_string()?;\n            (command, None)\n        }\n        2 => {\n            let mut iter = args.into_iter();\n            let command: String = iter.next().unwrap().to_string()?;\n            let options: Table = iter.next().unwrap().as_table().unwrap().clone();\n            (command, Some(options))\n        }\n        _ => {\n            return Err(mlua::Error::RuntimeError(\n                \"cmd.exec takes 1 or 2 arguments: (command) or (command, options)\".to_string(),\n            ));\n        }\n    };\n\n    let mut cmd = if cfg!(target_os = \"windows\") {\n        Command::new(\"cmd\")\n    } else {\n        Command::new(\"sh\")\n    };\n\n    if cfg!(target_os = \"windows\") {\n        cmd.args([\"/C\", &command]);\n    } else {\n        cmd.args([\"-c\", &command]);\n    }\n\n    // Apply mise-constructed environment if available in Lua registry.\n    // This ensures mise-managed tools are on PATH when called from env module hooks.\n    if let Ok(mise_env) = lua.named_registry_value::<Table>(\"mise_env\") {\n        cmd.env_clear();\n        for pair in mise_env.pairs::<String, String>() {\n            let (key, value) = pair?;\n            cmd.env(key, value);\n        }\n    }\n\n    // Apply options if provided (explicit env vars override mise env)\n    if let Some(options) = options {\n        // Set working directory if specified\n        if let Ok(cwd) = options.get::<String>(\"cwd\") {\n            cmd.current_dir(Path::new(&cwd));\n        }\n\n        // Set environment variables if specified\n        if let Ok(env) = options.get::<Table>(\"env\") {\n            for pair in env.pairs::<String, String>() {\n                let (key, value) = pair?;\n                cmd.env(key, value);\n            }\n        }\n\n        // Set timeout if specified (future feature)\n        if let Ok(_timeout) = options.get::<u64>(\"timeout\") {\n            // TODO: Implement timeout functionality\n            // For now, just ignore the timeout option\n        }\n    }\n\n    let output = cmd\n        .output()\n        .map_err(|e| mlua::Error::RuntimeError(format!(\"Failed to execute command: {e}\")))?;\n\n    let stdout = String::from_utf8_lossy(&output.stdout);\n    let stderr = String::from_utf8_lossy(&output.stderr);\n\n    if output.status.success() {\n        Ok(stdout.to_string())\n    } else {\n        Err(mlua::Error::RuntimeError(format!(\n            \"Command failed with status {}: {}\",\n            output.status, stderr\n        )))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cmd() {\n        let lua = Lua::new();\n        mod_cmd(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local cmd = require(\"cmd\")\n            local result = cmd.exec(\"echo hello world\")\n            assert(result == \"hello world\\n\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_cmd_with_cwd() {\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let temp_path = temp_dir.path();\n        // Canonicalize to resolve symlinks (e.g., /var -> /private/var on macOS)\n        let temp_path_canonical = temp_path\n            .canonicalize()\n            .unwrap_or_else(|_| temp_path.to_path_buf());\n        let temp_dir_str = temp_path_canonical.to_string_lossy().to_string();\n        let expected_path = temp_dir_str.trim_end_matches('/').to_string();\n        let lua = Lua::new();\n        mod_cmd(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local cmd = require(\"cmd\")\n            -- Test with working directory\n            local result = cmd.exec(\"pwd\", {cwd = $temp_dir_str})\n            -- Check that result contains the expected path (handles trailing slashes/newlines)\n            assert(result:find($expected_path) ~= nil, \"Expected result to contain: \" .. $expected_path .. \" but got: \" .. result)\n        })\n        .exec()\n        .unwrap();\n        // TempDir automatically cleans up when dropped\n    }\n\n    #[test]\n    fn test_cmd_with_env() {\n        let lua = Lua::new();\n        mod_cmd(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local cmd = require(\"cmd\")\n            -- Test with environment variables\n            local result = cmd.exec(\"echo $TEST_VAR\", {env = {TEST_VAR = \"hello\"}})\n            assert(result:find(\"hello\") ~= nil)\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_cmd_windows_compatibility() {\n        let lua = Lua::new();\n        mod_cmd(&lua).unwrap();\n\n        let test_command = \"echo hello world\";\n\n        lua.load(format!(\n            r#\"\n            local cmd = require(\"cmd\")\n            local result = cmd.exec(\"{test_command}\")\n            assert(result:find(\"hello world\") ~= nil)\n        \"#\n        ))\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/env.rs",
    "content": "use mlua::Table;\nuse mlua::prelude::*;\n\npub fn mod_env(lua: &Lua) -> LuaResult<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    let env = lua.create_table_from(vec![(\"setenv\", lua.create_function(setenv)?)])?;\n    loaded.set(\"env\", env.clone())?;\n    loaded.set(\"vfox.env\", env)?;\n    Ok(())\n}\n\nfn setenv(_lua: &Lua, (key, val): (String, String)) -> LuaResult<()> {\n    unsafe {\n        std::env::set_var(key, val);\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_env() {\n        let lua = Lua::new();\n        mod_env(&lua).unwrap();\n        if cfg!(windows) {\n            lua.load(mlua::chunk! {\n                local env = require(\"env\")\n                env.setenv(\"TEST_ENV\", \"myvar\")\n                handle = io.popen(\"pwsh -Command \\\"echo $env:TEST_ENV\\\"\")\n                result = handle:read(\"*a\")\n                handle:close()\n                assert(result == \"myvar\\n\")\n            })\n            .exec()\n            .unwrap();\n        } else {\n            lua.load(mlua::chunk! {\n                local env = require(\"env\")\n                env.setenv(\"TEST_ENV\", \"myvar\")\n                handle = io.popen(\"echo $TEST_ENV\")\n                result = handle:read(\"*a\")\n                handle:close()\n                assert(result == \"myvar\\n\")\n            })\n            .exec()\n            .unwrap();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/file.rs",
    "content": "use crate::error::Result;\nuse mlua::{ExternalResult, Lua, MultiValue, Table};\n#[cfg(unix)]\nuse std::os::unix::fs::symlink as _symlink;\n#[cfg(windows)]\nuse std::os::windows::fs::symlink_dir;\n#[cfg(windows)]\nuse std::os::windows::fs::symlink_file;\nuse std::path::Path;\n\nfn join_path(_lua: &Lua, args: MultiValue) -> mlua::Result<String> {\n    let sep = std::path::MAIN_SEPARATOR;\n    let mut parts = vec![];\n    for v in args {\n        let s = v.to_string()?;\n        if !s.is_empty() {\n            parts.push(s);\n        }\n    }\n    Ok(parts.join(&sep.to_string()))\n}\n\npub fn mod_file(lua: &Lua) -> Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    Ok(loaded.set(\n        \"file\",\n        lua.create_table_from(vec![\n            (\n                \"read\",\n                lua.create_async_function(|_lua: mlua::Lua, input| async move {\n                    read(&_lua, input).await\n                })?,\n            ),\n            (\n                \"symlink\",\n                lua.create_async_function(|_lua: mlua::Lua, input| async move {\n                    symlink(&_lua, input).await\n                })?,\n            ),\n            (\"join_path\", lua.create_function(join_path)?),\n            (\n                \"exists\",\n                lua.create_async_function(|_lua: mlua::Lua, input| async move {\n                    exists(&_lua, input).await\n                })?,\n            ),\n        ])?,\n    )?)\n}\n\nasync fn read(_lua: &Lua, input: MultiValue) -> mlua::Result<String> {\n    let args: Vec<String> = input\n        .into_iter()\n        .map(|v| v.to_string())\n        .collect::<mlua::Result<_>>()?;\n    let path = Path::new(&args[0]);\n    std::fs::read_to_string(path).into_lua_err()\n}\n\nasync fn symlink(_lua: &Lua, input: MultiValue) -> mlua::Result<()> {\n    let input: Vec<String> = input\n        .into_iter()\n        .map(|v| v.to_string())\n        .collect::<mlua::Result<_>>()?;\n    let src = Path::new(&input[0]);\n    let dst = Path::new(&input[1]);\n    #[cfg(windows)]\n    {\n        if src.is_dir() {\n            symlink_dir(src, dst).into_lua_err()?;\n        } else {\n            symlink_file(src, dst).into_lua_err()?;\n        }\n    }\n    #[cfg(unix)]\n    _symlink(src, dst).into_lua_err()?;\n    Ok(())\n}\n\nasync fn exists(_lua: &Lua, input: MultiValue) -> mlua::Result<bool> {\n    let args: Vec<String> = input\n        .into_iter()\n        .map(|v| v.to_string())\n        .collect::<mlua::Result<_>>()?;\n    let path = Path::new(&args[0]);\n    std::fs::exists(path).into_lua_err()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fs;\n\n    #[test]\n    fn test_read() {\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let filepath = temp_dir.path().join(\"file-read.txt\");\n        let filepath_str = filepath.to_string_lossy().to_string();\n        fs::write(&filepath, \"hello world\").unwrap();\n        let lua = Lua::new();\n        mod_file(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local file = require(\"file\")\n            local success, contents = pcall(file.read, $filepath_str)\n            if not success then\n                error(\"Failed to read: \" .. contents)\n            end\n            if contents == nil then\n                error(\"contents should not be nil\")\n            elseif contents ~= \"hello world\" then\n                error(\"contents expected to be 'hello world', was actually:\" .. contents)\n            end\n        })\n        .exec()\n        .unwrap();\n        // TempDir automatically cleans up when dropped\n    }\n\n    #[test]\n    fn test_symlink() {\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let src_path = temp_dir.path().join(\"symlink_src\");\n        let dst_path = temp_dir.path().join(\"symlink_dst\");\n        let src_path_str = src_path.to_string_lossy().to_string();\n        let dst_path_str = dst_path.to_string_lossy().to_string();\n        let lua = Lua::new();\n        mod_file(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local file = require(\"file\")\n            file.symlink($src_path_str, $dst_path_str)\n        })\n        .exec()\n        .unwrap();\n        assert_eq!(fs::read_link(&dst_path).unwrap(), src_path);\n        // TempDir automatically cleans up when dropped\n    }\n\n    #[test]\n    fn test_exists() {\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let existing_file = temp_dir.path().join(\"exists.txt\");\n        let existing_file_str = existing_file.to_string_lossy().to_string();\n        let nonexistent_file_str = temp_dir\n            .path()\n            .join(\"nonexistent.txt\")\n            .to_string_lossy()\n            .to_string();\n\n        fs::write(&existing_file, \"test content\").unwrap();\n        let lua = Lua::new();\n        mod_file(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            local file = require(\"file\")\n            local existing_exists = file.exists($existing_file_str)\n            local nonexistent_exists = file.exists($nonexistent_file_str)\n\n            if not existing_exists then\n                error(\"Expected existing file to exist\")\n            end\n            if nonexistent_exists then\n                error(\"Expected nonexistent file to not exist\")\n            end\n        })\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/hooks.rs",
    "content": "use crate::embedded_plugins::EmbeddedPlugin;\nuse crate::error::Result;\nuse mlua::Lua;\nuse std::collections::BTreeSet;\nuse std::path::Path;\n\npub struct HookFunc {\n    _name: &'static str,\n    pub filename: &'static str,\n}\n\n#[rustfmt::skip]\npub const HOOK_FUNCS: [HookFunc; 12] = [\n    HookFunc { _name: \"Available\", filename: \"available\" },\n    HookFunc { _name: \"PreInstall\", filename: \"pre_install\" },\n    HookFunc { _name: \"EnvKeys\", filename: \"env_keys\" },\n    HookFunc { _name: \"PostInstall\", filename: \"post_install\" },\n    HookFunc { _name: \"PreUse\", filename: \"pre_use\" },\n    HookFunc { _name: \"ParseLegacyFile\", filename: \"parse_legacy_file\" },\n    HookFunc { _name: \"PreUninstall\", filename: \"pre_uninstall\" },\n\n    // backend\n    HookFunc { _name: \"BackendListVersions\", filename: \"backend_list_versions\" },\n    HookFunc { _name: \"BackendInstall\", filename: \"backend_install\" },\n    HookFunc { _name: \"BackendExecEnv\", filename: \"backend_exec_env\" },\n\n    // mise\n    HookFunc { _name: \"MiseEnv\", filename: \"mise_env\" },\n    HookFunc { _name: \"MisePath\", filename: \"mise_path\" },\n];\n\npub fn mod_hooks(lua: &Lua, root: &Path) -> Result<BTreeSet<&'static str>> {\n    let mut hooks = BTreeSet::new();\n    for hook in &HOOK_FUNCS {\n        let hook_path = root.join(\"hooks\").join(format!(\"{}.lua\", hook.filename));\n        if hook_path.exists() {\n            lua.load(hook_path).exec()?;\n            hooks.insert(hook.filename);\n        }\n    }\n    Ok(hooks)\n}\n\npub fn hooks_embedded(lua: &Lua, embedded: &EmbeddedPlugin) -> Result<BTreeSet<&'static str>> {\n    let mut hooks = BTreeSet::new();\n\n    // Get package.loaded table to preload hooks\n    let package: mlua::Table = lua.globals().get(\"package\")?;\n    let loaded: mlua::Table = package.get(\"loaded\")?;\n\n    for (hook_name, hook_code) in embedded.hooks {\n        // Execute the hook code to define the function\n        lua.load(*hook_code).exec()?;\n\n        // Also preload into package.loaded so require(\"hooks/<name>\") works\n        // The hook code typically defines a function on the PLUGIN table\n        // We need to register a module that can be required\n        let module_name = format!(\"hooks/{}\", hook_name);\n        // Create a simple module that returns true (the hook code has already been executed)\n        loaded.set(module_name, true)?;\n\n        // Find the matching hook filename from HOOK_FUNCS\n        for hook in &HOOK_FUNCS {\n            if hook.filename == *hook_name {\n                hooks.insert(hook.filename);\n                break;\n            }\n        }\n    }\n    Ok(hooks)\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/html.rs",
    "content": "use mlua::{Lua, Table};\n\npub fn mod_html(lua: &Lua) -> mlua::Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    loaded.set(\n        \"htmlparser.voidelements\",\n        lua.load(include_str!(\"../../lua/htmlparser/voidelements.lua\"))\n            .eval::<Table>()?,\n    )?;\n    loaded.set(\n        \"htmlparser.ElementNode\",\n        lua.load(include_str!(\"../../lua/htmlparser/ElementNode.lua\"))\n            .eval::<Table>()?,\n    )?;\n    loaded.set(\n        \"htmlparser\",\n        lua.load(include_str!(\"../../lua/htmlparser.lua\"))\n            .eval::<Table>()?,\n    )?;\n    loaded.set(\n        \"html\",\n        lua.load(mlua::chunk! {\n            local htmlparser = require(\"htmlparser\")\n            return {\n                parse = function(s)\n                    Node = {\n                        find = function(self, tag)\n                            local nodes = self.node:select(tag)\n                            return Node.new(nodes)\n                        end,\n                        first = function(self)\n                            return Node.new({self.nodes[1]})\n                        end,\n                        eq = function(self, idx)\n                            local node = self.nodes[idx + 1]\n                            return Node.new({node})\n                        end,\n                        each = function(self, f)\n                            for i, node in ipairs(self.nodes) do\n                                f(i - 1, Node.new({node}))\n                            end\n                        end,\n                        text = function(self)\n                            if self.node == nil then\n                                return \"\"\n                            end\n                            return self.node:getcontent()\n                        end,\n                        attr = function(self, key)\n                            if self.node == nil then\n                                return \"\"\n                            end\n                            return self.node.attributes[key]\n                        end,\n                    }\n                    Node.new = function(nodes)\n                        return setmetatable({nodes = nodes, node = nodes[1]}, {__index = Node})\n                    end\n                    local root = htmlparser.parse(s, 100000)\n                    return Node.new({root})\n                end\n            }\n        })\n        .eval::<Table>()?,\n    )?;\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::lua_mod::http::mod_http;\n\n    #[test]\n    fn test_html() {\n        let lua = Lua::new();\n        mod_html(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local html = require(\"html\")\n            local doc = html.parse(\"<html><body><div id='t2' name='123'>456</div><DIV foo='bar'>222</DIV></body></html>\")\n            local f = doc:find(\"div\"):eq(0)\n            local s = doc:find(\"div\"):eq(1)\n            assert(s:text() == \"222\")\n            assert(f:text() == \"456\")\n\n            assert(s:attr(\"foo\") == \"bar\")\n\n            doc:find(\"div\"):each(function(i, e)\n                if i == 0 then\n                    assert(e:text() == \"456\")\n                else\n                    assert(e:text() == \"222\")\n                end\n            end)\n        })\n            .exec()\n            .unwrap();\n    }\n\n    #[tokio::test]\n    #[ignore] // TODO: make this actually work\n    async fn test_html_go() {\n        let lua = Lua::new();\n        mod_html(&lua).unwrap();\n        mod_http(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local http = require(\"http\")\n            local html = require(\"html\")\n\n            table = {}\n\n            resp, err = http.get({\n                url = \"https://go.dev/dl/\"\n            })\n            if err ~= nil or resp.status_code ~= 200 then\n                error(\"parsing release info failed.\" .. err)\n            end\n            local doc = html.parse(resp.body)\n            local listDoc = doc:find(\"div#archive\")\n            listDoc:find(\".toggle\"):each(function(i, selection)\n                local versionStr = selection:attr(\"id\")\n                if versionStr ~= nil then\n                    selection:find(\"table.downloadtable tr\"):each(function(ti, ts)\n                        local td = ts:find(\"td\")\n                        local filename = td:eq(0):text()\n                        local kind = td:eq(1):text()\n                        local os = td:eq(2):text()\n                        local arch = td:eq(3):text()\n                        local checksum = td:eq(5):text()\n                        if kind == \"Archive\" and os == \"Windows\" and arch == \"x86-64\" then\n                            table.insert(result, {\n                                version = string.sub(versionStr, 3),\n                                url = \"https://go.dev/dl/\" .. filename,\n                                note = \"\",\n                                sha256 = checksum,\n                            })\n                        end\n                    end)\n                end\n            end)\n            print(table)\n            // TODO: check results\n        })\n        .exec_async()\n        .await\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/http.rs",
    "content": "use mlua::{BorrowedStr, ExternalResult, Lua, MultiValue, Result, Table};\nuse reqwest::header::{HeaderMap, HeaderName, HeaderValue};\n\nuse crate::http::CLIENT;\n\npub fn mod_http(lua: &Lua) -> Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    loaded.set(\n        \"http\",\n        lua.create_table_from(vec![\n            (\n                \"get\",\n                lua.create_async_function(|lua: mlua::Lua, input| async move {\n                    get(&lua, input).await\n                })?,\n            ),\n            (\n                \"head\",\n                lua.create_async_function(|lua: mlua::Lua, input| async move {\n                    head(&lua, input).await\n                })?,\n            ),\n            (\n                \"download_file\",\n                lua.create_async_function(|_lua: mlua::Lua, input| async move {\n                    download_file(&_lua, input).await\n                })?,\n            ),\n        ])?,\n    )\n}\n\nfn into_headers(table: &Table) -> Result<HeaderMap> {\n    let mut map = HeaderMap::new();\n    for entry in table.pairs::<BorrowedStr, BorrowedStr>() {\n        let (k, v) = entry?;\n        map.insert(\n            HeaderName::from_bytes(k.as_bytes()).into_lua_err()?,\n            HeaderValue::from_str(&v).into_lua_err()?,\n        );\n    }\n    Ok(map)\n}\n\nasync fn get(lua: &Lua, input: Table) -> Result<Table> {\n    let url: String = input.get(\"url\").into_lua_err()?;\n    let headers = match input.get::<Option<Table>>(\"headers\").into_lua_err()? {\n        Some(tbl) => into_headers(&tbl)?,\n        None => HeaderMap::default(),\n    };\n    let resp = CLIENT\n        .get(&url)\n        .headers(headers)\n        .send()\n        .await\n        .into_lua_err()?;\n    let t = lua.create_table()?;\n    t.set(\"status_code\", resp.status().as_u16())?;\n    t.set(\"headers\", get_headers(lua, resp.headers())?)?;\n    t.set(\"body\", resp.text().await.into_lua_err()?)?;\n    Ok(t)\n}\n\nasync fn download_file(_lua: &Lua, input: MultiValue) -> Result<()> {\n    let t: &Table = input.iter().next().unwrap().as_table().unwrap();\n    let url: String = t.get(\"url\").into_lua_err()?;\n    let headers = match t.get::<Option<Table>>(\"headers\").into_lua_err()? {\n        Some(tbl) => into_headers(&tbl)?,\n        None => HeaderMap::default(),\n    };\n    let path: String = input.iter().nth(1).unwrap().to_string()?;\n    let resp = CLIENT\n        .get(&url)\n        .headers(headers)\n        .send()\n        .await\n        .into_lua_err()?;\n    resp.error_for_status_ref().into_lua_err()?;\n    let mut file = tokio::fs::File::create(&path).await.into_lua_err()?;\n    let bytes = resp.bytes().await.into_lua_err()?;\n    tokio::io::AsyncWriteExt::write_all(&mut file, &bytes)\n        .await\n        .into_lua_err()?;\n    Ok(())\n}\n\nasync fn head(lua: &Lua, input: Table) -> Result<Table> {\n    let url: String = input.get(\"url\").into_lua_err()?;\n    let headers = match input.get::<Option<Table>>(\"headers\").into_lua_err()? {\n        Some(tbl) => into_headers(&tbl)?,\n        None => HeaderMap::default(),\n    };\n    let resp = CLIENT\n        .head(&url)\n        .headers(headers)\n        .send()\n        .await\n        .into_lua_err()?;\n    let t = lua.create_table()?;\n    t.set(\"status_code\", resp.status().as_u16())?;\n    t.set(\"headers\", get_headers(lua, resp.headers())?)?;\n    Ok(t)\n}\n\nfn get_headers(lua: &Lua, headers: &reqwest::header::HeaderMap) -> Result<Table> {\n    let t = lua.create_table()?;\n    for (name, value) in headers.iter() {\n        t.set(name.as_str(), value.to_str().into_lua_err()?)?;\n    }\n    Ok(t)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use wiremock::matchers::{header, method, path};\n    use wiremock::{Mock, MockServer, ResponseTemplate};\n\n    #[tokio::test]\n    async fn test_get() {\n        // Start a local mock server\n        let server = MockServer::start().await;\n\n        // Create a mock endpoint\n        Mock::given(method(\"GET\"))\n            .and(path(\"/get\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .set_body_json(serde_json::json!({\n                        \"message\": \"test response\"\n                    }))\n                    .insert_header(\"content-type\", \"application/json\"),\n            )\n            .mount(&server)\n            .await;\n\n        let lua = Lua::new();\n        mod_http(&lua).unwrap();\n\n        let url = server.uri() + \"/get\";\n        lua.load(mlua::chunk! {\n            local http = require(\"http\")\n            local resp = http.get({ url = $url })\n            assert(resp.status_code == 200)\n            assert(type(resp.body) == \"string\")\n        })\n        .exec_async()\n        .await\n        .unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_get_headers() {\n        // Start a local mock server\n        let server = MockServer::start().await;\n\n        // Create a mock endpoint\n        Mock::given(method(\"GET\"))\n            .and(path(\"/get\"))\n            .and(header(\"Authorization\", \"Bearer abc\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .set_body_json(serde_json::json!({\n                        \"message\": \"test response\"\n                    }))\n                    .insert_header(\"content-type\", \"application/json\"),\n            )\n            .mount(&server)\n            .await;\n\n        let lua = Lua::new();\n        mod_http(&lua).unwrap();\n\n        let url = server.uri() + \"/get\";\n        lua.load(mlua::chunk! {\n            local http = require(\"http\")\n            local resp = http.get({\n                url = $url,\n                headers = {\n                    [\"Authorization\"] = \"Bearer abc\"\n                }\n            })\n            assert(resp.status_code == 200)\n            assert(type(resp.body) == \"string\")\n        })\n        .exec_async()\n        .await\n        .unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_head() {\n        let server = MockServer::start().await;\n\n        Mock::given(method(\"HEAD\"))\n            .and(path(\"/get\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .insert_header(\"content-type\", \"application/json\")\n                    .insert_header(\"x-test-header\", \"test-value\"),\n            )\n            .mount(&server)\n            .await;\n\n        let lua = Lua::new();\n        mod_http(&lua).unwrap();\n\n        let url = server.uri() + \"/get\";\n        lua.load(mlua::chunk! {\n            local http = require(\"http\")\n            local resp = http.head({ url = $url })\n            assert(resp.status_code == 200)\n            assert(type(resp.headers) == \"table\")\n            assert(resp.headers[\"content-type\"] == \"application/json\")\n            assert(resp.headers[\"x-test-header\"] == \"test-value\")\n            assert(resp.content_length == nil)\n        })\n        .exec_async()\n        .await\n        .unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_download_file() {\n        let server = MockServer::start().await;\n\n        // Create test content\n        let test_content = r#\"{\"name\": \"vfox-nodejs\", \"version\": \"1.0.0\"}\"#;\n\n        Mock::given(method(\"GET\"))\n            .and(path(\"/index.json\"))\n            .respond_with(\n                ResponseTemplate::new(200)\n                    .set_body_string(test_content)\n                    .insert_header(\"content-type\", \"application/json\"),\n            )\n            .expect(1) // Expect exactly one request\n            .mount(&server)\n            .await;\n\n        let lua = Lua::new();\n        mod_http(&lua).unwrap();\n\n        // Use isolated temp directory for test isolation\n        let temp_dir = tempfile::TempDir::new().unwrap();\n        let path = temp_dir.path().join(\"download_file.txt\");\n        let path_str = path.to_string_lossy().to_string();\n        let url = server.uri() + \"/index.json\";\n\n        lua.load(mlua::chunk! {\n            local http = require(\"http\")\n            err = http.download_file({\n                url = $url,\n                headers = {}\n            }, $path_str)\n            assert(err == nil, [[must be nil]])\n        })\n        .exec_async()\n        .await\n        .unwrap();\n\n        // Add a small delay to ensure file write is completed\n        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;\n\n        // Verify file was downloaded correctly with better error handling\n        let content = tokio::fs::read_to_string(&path)\n            .await\n            .unwrap_or_else(|e| panic!(\"Failed to read file at {:?}: {}\", path, e));\n\n        assert!(\n            content.contains(\"vfox-nodejs\"),\n            \"Expected content to contain 'vfox-nodejs', but got: {:?}\",\n            content\n        );\n\n        // TempDir automatically cleans up when dropped\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/json.rs",
    "content": "use mlua::{ExternalResult, Lua, LuaSerdeExt, Result, Table, Value};\n\npub fn mod_json(lua: &Lua) -> Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    loaded.set(\n        \"json\",\n        lua.create_table_from(vec![\n            (\"encode\", lua.create_function(encode)?),\n            (\"decode\", lua.create_function(decode)?),\n        ])?,\n    )\n}\n\nfn encode(_lua: &Lua, value: Value) -> Result<String> {\n    serde_json::to_string(&value).into_lua_err()\n}\n\nfn decode(lua: &Lua, value: String) -> Result<Value> {\n    let value: serde_json::Value = serde_json::from_str(&value).into_lua_err()?;\n    lua.to_value(&value)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_encode() {\n        let lua = Lua::new();\n        mod_json(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local json = require(\"json\")\n            local obj = { \"a\", 1, \"b\", 2, \"c\", 3 }\n            local jsonStr = json.encode(obj)\n            assert(jsonStr == \"[\\\"a\\\",1,\\\"b\\\",2,\\\"c\\\",3]\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_decode() {\n        let lua = Lua::new();\n        mod_json(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local json = require(\"json\")\n            local obj = json.decode(\"[\\\"a\\\",1,\\\"b\\\",2,\\\"c\\\",3]\")\n            assert(obj[1] == \"a\")\n            assert(obj[2] == 1)\n            assert(obj[3] == \"b\")\n            assert(obj[4] == 2)\n            assert(obj[5] == \"c\")\n            assert(obj[6] == 3)\n        })\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/log.rs",
    "content": "use mlua::{Lua, Result, Table, Value, Variadic};\n\nfn values_to_string(lua: &Lua, args: Variadic<Value>) -> Result<String> {\n    let tostring: mlua::Function = lua.globals().get(\"tostring\")?;\n    let parts: Vec<String> = args\n        .iter()\n        .map(|v| {\n            tostring\n                .call::<String>(v)\n                .unwrap_or_else(|_| \"?\".to_string())\n        })\n        .collect();\n    Ok(parts.join(\"\\t\"))\n}\n\nfn get_plugin_name(lua: &Lua) -> Option<String> {\n    lua.named_registry_value::<String>(\"plugin_name\").ok()\n}\n\nfn format_msg(plugin_name: Option<&str>, msg: &str) -> String {\n    match plugin_name {\n        Some(name) => format!(\"[{}] {}\", name, msg),\n        None => msg.to_string(),\n    }\n}\n\nmacro_rules! create_log_fn {\n    ($lua:expr, $level:expr) => {\n        $lua.create_function(|lua, args: Variadic<Value>| {\n            if log::log_enabled!($level) {\n                let msg = values_to_string(lua, args)?;\n                let name = get_plugin_name(lua);\n                log::log!($level, \"{}\", format_msg(name.as_deref(), &msg));\n            }\n            Ok(())\n        })?\n    };\n}\n\npub fn mod_log(lua: &Lua) -> Result<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n\n    let log_table = lua.create_table()?;\n\n    log_table.set(\"trace\", create_log_fn!(lua, log::Level::Trace))?;\n    log_table.set(\"debug\", create_log_fn!(lua, log::Level::Debug))?;\n\n    let info_fn = create_log_fn!(lua, log::Level::Info);\n    log_table.set(\"info\", info_fn.clone())?;\n\n    log_table.set(\"warn\", create_log_fn!(lua, log::Level::Warn))?;\n    log_table.set(\"error\", create_log_fn!(lua, log::Level::Error))?;\n\n    loaded.set(\"log\", log_table.clone())?;\n\n    // Also register as vfox.log\n    let vfox_table: Table = match loaded.get::<Option<Table>>(\"vfox\")? {\n        Some(t) => t,\n        None => {\n            let t = lua.create_table()?;\n            loaded.set(\"vfox\", t.clone())?;\n            t\n        }\n    };\n    vfox_table.set(\"log\", log_table)?;\n\n    // Override print() to route through info!()\n    lua.globals().set(\"print\", info_fn)?;\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_mod_log_registration() {\n        let lua = Lua::new();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            local log = require(\"log\")\n            assert(type(log) == \"table\")\n            assert(type(log.trace) == \"function\")\n            assert(type(log.debug) == \"function\")\n            assert(type(log.info) == \"function\")\n            assert(type(log.warn) == \"function\")\n            assert(type(log.error) == \"function\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_vfox_log_namespace() {\n        let lua = Lua::new();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            local vfox_log = require(\"vfox\").log\n            assert(type(vfox_log) == \"table\")\n            assert(type(vfox_log.info) == \"function\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_log_functions_execute() {\n        let lua = Lua::new();\n        mod_log(&lua).unwrap();\n\n        // Should not panic with no plugin_name set\n        lua.load(mlua::chunk! {\n            local log = require(\"log\")\n            log.trace(\"trace msg\")\n            log.debug(\"debug msg\")\n            log.info(\"info msg\")\n            log.warn(\"warn msg\")\n            log.error(\"error msg\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_log_with_plugin_name() {\n        let lua = Lua::new();\n        lua.set_named_registry_value(\"plugin_name\", \"test-plugin\")\n            .unwrap();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            local log = require(\"log\")\n            log.info(\"hello from plugin\")\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_log_multiple_args() {\n        let lua = Lua::new();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            local log = require(\"log\")\n            log.info(\"multi\", \"arg\", 123, true, nil)\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_print_override() {\n        let lua = Lua::new();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            print(\"hello\", \"world\", 42)\n        })\n        .exec()\n        .unwrap();\n    }\n\n    #[test]\n    fn test_print_override_with_plugin_name() {\n        let lua = Lua::new();\n        lua.set_named_registry_value(\"plugin_name\", \"my-plugin\")\n            .unwrap();\n        mod_log(&lua).unwrap();\n\n        lua.load(mlua::chunk! {\n            print(\"test message\")\n        })\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/mod.rs",
    "content": "mod archiver;\nmod cmd;\nmod env;\nmod file;\nmod hooks;\nmod html;\nmod http;\nmod json;\nmod log;\nmod semver;\nmod strings;\n\npub use archiver::mod_archiver as archiver;\npub use cmd::mod_cmd as cmd;\npub use env::mod_env as env;\npub use file::mod_file as file;\npub use hooks::hooks_embedded;\npub use hooks::mod_hooks as hooks;\npub use html::mod_html as html;\npub use http::mod_http as http;\npub use json::mod_json as json;\npub use log::mod_log as log;\npub use semver::mod_semver as semver;\npub use strings::mod_strings as strings;\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/semver.rs",
    "content": "use mlua::Table;\nuse mlua::prelude::*;\n\npub fn mod_semver(lua: &Lua) -> LuaResult<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    let semver = lua.create_table_from(vec![\n        (\"compare\", lua.create_function(compare)?),\n        (\"parse\", lua.create_function(parse)?),\n        (\"sort\", lua.create_function(sort)?),\n        (\"sort_by\", lua.create_function(sort_by)?),\n    ])?;\n    loaded.set(\"semver\", semver.clone())?;\n    loaded.set(\"vfox.semver\", semver)?;\n    Ok(())\n}\n\n/// Parse a version string into a table of numeric parts\n/// e.g., \"1.2.3\" -> {1, 2, 3}\nfn parse(_lua: &Lua, version: String) -> LuaResult<Vec<i64>> {\n    Ok(parse_version(&version))\n}\n\n/// Compare two version strings\n/// Returns -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2\nfn compare(_lua: &Lua, (v1, v2): (String, String)) -> LuaResult<i32> {\n    Ok(compare_versions(&v1, &v2))\n}\n\n/// Sort a list of version strings in ascending order\nfn sort(_lua: &Lua, versions: Vec<String>) -> LuaResult<Vec<String>> {\n    let mut versions = versions;\n    versions.sort_by(|a, b| compare_versions(a, b).cmp(&0));\n    Ok(versions)\n}\n\n/// Sort a list of tables by a version field in ascending order\n/// e.g., sort_by({{version = \"1.2\"}, {version = \"1.1\"}}, \"version\")\nfn sort_by(_lua: &Lua, (arr, field): (Vec<Table>, String)) -> LuaResult<Vec<Table>> {\n    let mut items: Vec<(Table, String)> = arr\n        .into_iter()\n        .map(|t| {\n            let version: String = t.get(field.as_str()).unwrap_or_default();\n            (t, version)\n        })\n        .collect();\n\n    items.sort_by(|a, b| compare_versions(&a.1, &b.1).cmp(&0));\n\n    Ok(items.into_iter().map(|(t, _)| t).collect())\n}\n\nfn parse_version(version: &str) -> Vec<i64> {\n    version\n        .split(|c: char| !c.is_ascii_digit())\n        .filter(|s| !s.is_empty())\n        .filter_map(|s| s.parse().ok())\n        .collect()\n}\n\nfn compare_versions(v1: &str, v2: &str) -> i32 {\n    let parts1 = parse_version(v1);\n    let parts2 = parse_version(v2);\n\n    let max_len = parts1.len().max(parts2.len());\n    for i in 0..max_len {\n        let p1 = parts1.get(i).copied().unwrap_or(0);\n        let p2 = parts2.get(i).copied().unwrap_or(0);\n        if p1 != p2 {\n            return if p1 < p2 { -1 } else { 1 };\n        }\n    }\n    0\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_version() {\n        assert_eq!(parse_version(\"1.2.3\"), vec![1, 2, 3]);\n        assert_eq!(parse_version(\"10.20.30\"), vec![10, 20, 30]);\n        assert_eq!(parse_version(\"1.2\"), vec![1, 2]);\n        assert_eq!(parse_version(\"1\"), vec![1]);\n        assert_eq!(parse_version(\"v1.2.3\"), vec![1, 2, 3]);\n        assert_eq!(parse_version(\"1.2.3-beta\"), vec![1, 2, 3]);\n    }\n\n    #[test]\n    fn test_compare_versions() {\n        assert_eq!(compare_versions(\"1.2.3\", \"1.2.3\"), 0);\n        assert_eq!(compare_versions(\"1.2.3\", \"1.2.4\"), -1);\n        assert_eq!(compare_versions(\"1.2.4\", \"1.2.3\"), 1);\n        assert_eq!(compare_versions(\"1.2\", \"1.2.0\"), 0);\n        assert_eq!(compare_versions(\"9.6.9\", \"9.6.24\"), -1);\n        assert_eq!(compare_versions(\"10.0\", \"9.6.24\"), 1);\n        assert_eq!(compare_versions(\"1.08\", \"1.09\"), -1);\n    }\n\n    #[test]\n    fn test_semver_lua() {\n        let lua = Lua::new();\n        mod_semver(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local semver = require(\"semver\")\n\n            -- Test compare\n            assert(semver.compare(\"1.2.3\", \"1.2.3\") == 0, \"equal versions\")\n            assert(semver.compare(\"1.2.3\", \"1.2.4\") == -1, \"less than\")\n            assert(semver.compare(\"1.2.4\", \"1.2.3\") == 1, \"greater than\")\n            assert(semver.compare(\"9.6.9\", \"9.6.24\") == -1, \"numeric comparison\")\n            assert(semver.compare(\"10.0\", \"9.6.24\") == 1, \"major version\")\n\n            -- Test parse\n            local parts = semver.parse(\"1.2.3\")\n            assert(parts[1] == 1 and parts[2] == 2 and parts[3] == 3, \"parse\")\n\n            -- Test sort\n            local versions = semver.sort({\"1.2\", \"1.10\", \"1.1\", \"2.0\"})\n            assert(versions[1] == \"1.1\", \"sort[1]\")\n            assert(versions[2] == \"1.2\", \"sort[2]\")\n            assert(versions[3] == \"1.10\", \"sort[3]\")\n            assert(versions[4] == \"2.0\", \"sort[4]\")\n        })\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/lua_mod/strings.rs",
    "content": "use mlua::prelude::*;\nuse mlua::{Table, Value};\n\npub fn mod_strings(lua: &Lua) -> LuaResult<()> {\n    let package: Table = lua.globals().get(\"package\")?;\n    let loaded: Table = package.get(\"loaded\")?;\n    let strings = lua.create_table_from(vec![\n        (\"split\", lua.create_function(split)?),\n        (\"has_prefix\", lua.create_function(has_prefix)?),\n        (\"has_suffix\", lua.create_function(has_suffix)?),\n        (\"trim\", lua.create_function(trim)?),\n        (\"trim_space\", lua.create_function(trim_space)?),\n        (\"contains\", lua.create_function(contains)?),\n        (\"join\", lua.create_function(join)?),\n    ])?;\n    loaded.set(\"strings\", strings.clone())?;\n    loaded.set(\"vfox.strings\", strings)?;\n    Ok(())\n}\n\nfn split(_lua: &Lua, (s, sep): (String, String)) -> LuaResult<Vec<String>> {\n    Ok(s.split(&sep).map(|s| s.to_string()).collect())\n}\n\nfn has_prefix(_lua: &Lua, (s, prefix): (String, String)) -> LuaResult<bool> {\n    Ok(s.starts_with(&prefix))\n}\n\nfn has_suffix(_lua: &Lua, (s, suffix): (String, String)) -> LuaResult<bool> {\n    Ok(s.ends_with(&suffix))\n}\n\nfn trim(_lua: &Lua, (s, suffix): (String, String)) -> LuaResult<String> {\n    Ok(s.trim_end_matches(&suffix).to_string())\n}\n\nfn trim_space(_lua: &Lua, s: String) -> LuaResult<String> {\n    Ok(s.trim().to_string())\n}\n\nfn contains(_lua: &Lua, (s, substr): (String, String)) -> LuaResult<bool> {\n    Ok(s.contains(&substr))\n}\n\nfn join(_lua: &Lua, (arr, sep): (Vec<Value>, String)) -> LuaResult<String> {\n    let mut res = String::new();\n    for (i, v) in arr.iter().enumerate() {\n        if i > 0 {\n            res.push_str(&sep);\n        }\n        res.push_str(&v.to_string()?);\n    }\n    Ok(res)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_strings() {\n        let lua = Lua::new();\n        mod_strings(&lua).unwrap();\n        lua.load(mlua::chunk! {\n            local strings = require(\"strings\")\n            local str_parts = strings.split(\"hello world\", \" \")\n            print(str_parts[1]) -- hello\n\n            assert(strings.has_prefix(\"hello world\", \"hello\"), [[not strings.has_prefix(\"hello\")]])\n            assert(strings.has_suffix(\"hello world\", \"world\"), [[not strings.has_suffix(\"world\")]])\n            assert(strings.trim(\"hello world\", \"world\") == \"hello \", \"strings.trim()\")\n            assert(strings.contains(\"hello world\", \"hello \") == true, \"strings.contains()\")\n\n            // got = strings.trim_space(tt.input)\n            //\n            // local str = strings.join({\"1\",3,\"4\"},\";\")\n            // assert(str == \"1;3;4\", \"strings.join()\")\n        })\n        .exec()\n        .unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/metadata.rs",
    "content": "use mlua::Table;\nuse std::collections::BTreeSet;\n\nuse crate::error::Result;\nuse crate::error::VfoxError;\n\n#[derive(Debug, Clone)]\npub struct Metadata {\n    pub name: String,\n    pub legacy_filenames: Vec<String>,\n    pub version: String,\n    pub description: Option<String>,\n    pub author: Option<String>,\n    pub license: Option<String>,\n    pub homepage: Option<String>,\n    pub hooks: BTreeSet<&'static str>,\n}\n\nimpl TryFrom<Table> for Metadata {\n    type Error = VfoxError;\n    fn try_from(t: Table) -> Result<Self> {\n        let legacy_filenames = t\n            .get::<Option<Vec<String>>>(\"legacyFilenames\")?\n            .unwrap_or_default();\n        Ok(Metadata {\n            name: t.get(\"name\")?,\n            legacy_filenames,\n            version: t.get(\"version\")?,\n            description: t.get(\"description\")?,\n            author: t.get(\"author\")?,\n            license: t.get(\"license\")?,\n            homepage: t.get(\"homepage\")?,\n            hooks: Default::default(),\n        })\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/plugin.rs",
    "content": "use std::cmp::Ordering;\nuse std::fmt::Display;\nuse std::path::{Path, PathBuf};\n\nuse mlua::{AsChunk, FromLuaMulti, IntoLua, Lua, Table, Value};\nuse once_cell::sync::OnceCell;\n\nuse crate::config::Config;\nuse crate::context::Context;\nuse crate::embedded_plugins::{self, EmbeddedPlugin};\nuse crate::error::Result;\nuse crate::metadata::Metadata;\nuse crate::runtime::Runtime;\nuse crate::sdk_info::SdkInfo;\nuse crate::{VfoxError, config, error, lua_mod};\n\n#[derive(Debug)]\npub enum PluginSource {\n    Filesystem(PathBuf),\n    Embedded(&'static EmbeddedPlugin),\n}\n\n#[derive(Debug)]\npub struct Plugin {\n    pub name: String,\n    pub dir: PathBuf,\n    source: PluginSource,\n    lua: Lua,\n    metadata: OnceCell<Metadata>,\n}\n\nimpl Plugin {\n    pub fn from_dir(dir: &Path) -> Result<Self> {\n        if !dir.exists() {\n            error!(\"Plugin directory not found: {:?}\", dir);\n        }\n        let lua = Lua::new();\n        lua.set_named_registry_value(\"plugin_dir\", dir.to_path_buf())?;\n        let name = dir.file_name().unwrap().to_string_lossy().to_string();\n        lua.set_named_registry_value(\"plugin_name\", name.clone())?;\n        Ok(Self {\n            name,\n            dir: dir.to_path_buf(),\n            source: PluginSource::Filesystem(dir.to_path_buf()),\n            lua,\n            metadata: OnceCell::new(),\n        })\n    }\n\n    pub fn from_embedded(name: &str, embedded: &'static EmbeddedPlugin) -> Result<Self> {\n        let lua = Lua::new();\n        // Use a dummy path for embedded plugins\n        let dummy_dir = PathBuf::from(format!(\"embedded:{}\", name));\n        lua.set_named_registry_value(\"plugin_dir\", dummy_dir.clone())?;\n        lua.set_named_registry_value(\"embedded_plugin\", true)?;\n        lua.set_named_registry_value(\"plugin_name\", name.to_string())?;\n        Ok(Self {\n            name: name.to_string(),\n            dir: dummy_dir,\n            source: PluginSource::Embedded(embedded),\n            lua,\n            metadata: OnceCell::new(),\n        })\n    }\n\n    pub fn from_name(name: &str) -> Result<Self> {\n        // Check filesystem first - allows user to override embedded plugins\n        let dir = Config::get().plugin_dir.join(name);\n        if dir.exists() {\n            return Self::from_dir(&dir);\n        }\n        // Fall back to embedded plugin if available\n        if let Some(embedded) = embedded_plugins::get_embedded_plugin(name) {\n            return Self::from_embedded(name, embedded);\n        }\n        Self::from_dir(&dir)\n    }\n\n    pub fn from_name_or_dir(name: &str, dir: &Path) -> Result<Self> {\n        // Check filesystem first - allows user to override embedded plugins\n        if dir.exists() {\n            return Self::from_dir(dir);\n        }\n        // Fall back to embedded plugin if available\n        if let Some(embedded) = embedded_plugins::get_embedded_plugin(name) {\n            return Self::from_embedded(name, embedded);\n        }\n        Self::from_dir(dir)\n    }\n\n    pub fn is_embedded(&self) -> bool {\n        matches!(self.source, PluginSource::Embedded(_))\n    }\n\n    /// Store an environment map in the Lua registry for use by cmd.exec().\n    /// This allows env module hooks to run commands that find mise-managed tools on PATH.\n    pub fn set_cmd_env(&self, env: &indexmap::IndexMap<String, String>) -> Result<()> {\n        let table = self.lua.create_table()?;\n        for (k, v) in env {\n            table.set(k.as_str(), v.as_str())?;\n        }\n        self.lua.set_named_registry_value(\"mise_env\", table)?;\n        Ok(())\n    }\n\n    pub fn list() -> Result<Vec<String>> {\n        let config = Config::get();\n        if !config.plugin_dir.exists() {\n            return Ok(vec![]);\n        }\n        let plugins = xx::file::ls(&config.plugin_dir)?;\n        let plugins = plugins\n            .iter()\n            .filter_map(|p| {\n                p.file_name()\n                    .and_then(|f| f.to_str())\n                    .map(|s| s.to_string())\n            })\n            .collect();\n        Ok(plugins)\n    }\n\n    pub fn get_metadata(&self) -> Result<Metadata> {\n        Ok(self.load()?.clone())\n    }\n\n    pub fn sdk_info(&self, version: String, install_dir: PathBuf) -> Result<SdkInfo> {\n        Ok(SdkInfo::new(\n            self.get_metadata()?.name.clone(),\n            version,\n            install_dir,\n        ))\n    }\n\n    #[cfg(test)]\n    pub(crate) fn test(name: &str) -> Self {\n        let dir = PathBuf::from(\"plugins\").join(name);\n        Self::from_dir(&dir).unwrap()\n    }\n\n    pub(crate) fn context(&self, version: Option<String>) -> Result<Context> {\n        let ctx = Context {\n            args: vec![],\n            version,\n            // version: \"1.0.0\".to_string(),\n            // runtime_version: \"xxx\".to_string(),\n        };\n        Ok(ctx)\n    }\n\n    pub(crate) async fn exec_async(&self, chunk: impl AsChunk) -> Result<()> {\n        self.load()?;\n        let chunk = self.lua.load(chunk);\n        chunk.exec_async().await?;\n        Ok(())\n    }\n\n    pub(crate) async fn eval_async<R>(&self, chunk: impl AsChunk) -> Result<R>\n    where\n        R: FromLuaMulti,\n    {\n        self.load()?;\n        let chunk = self.lua.load(chunk);\n        let result = chunk.eval_async().await?;\n        Ok(result)\n    }\n\n    // Backend plugin methods\n    fn load(&self) -> Result<&Metadata> {\n        self.metadata.get_or_try_init(|| {\n            debug!(\"[vfox] Getting metadata for {self}\");\n\n            // For filesystem plugins, set Lua package paths\n            if let PluginSource::Filesystem(dir) = &self.source {\n                set_paths(\n                    &self.lua,\n                    &[\n                        dir.join(\"?.lua\"),\n                        dir.join(\"hooks/?.lua\"),\n                        dir.join(\"lib/?.lua\"),\n                    ],\n                )?;\n            }\n\n            // Load standard Lua modules (http, json, etc.) FIRST\n            // These must be available before loading embedded lib files\n            lua_mod::archiver(&self.lua)?;\n            lua_mod::cmd(&self.lua)?;\n            lua_mod::file(&self.lua)?;\n            lua_mod::html(&self.lua)?;\n            lua_mod::http(&self.lua)?;\n            lua_mod::json(&self.lua)?;\n            lua_mod::semver(&self.lua)?;\n            lua_mod::strings(&self.lua)?;\n            lua_mod::env(&self.lua)?;\n            lua_mod::log(&self.lua)?;\n\n            // For embedded plugins, load lib modules AFTER standard modules\n            // (lib files may require http, json, etc.)\n            if let PluginSource::Embedded(embedded) = &self.source {\n                self.load_embedded_libs(embedded)?;\n            }\n\n            let metadata = self.load_metadata()?;\n            self.set_global(\"PLUGIN\", metadata.clone())?;\n            self.set_global(\"RUNTIME\", Runtime::get(self.dir.clone()))?;\n            self.set_global(\"OS_TYPE\", config::os())?;\n            self.set_global(\"ARCH_TYPE\", config::arch())?;\n\n            let mut metadata: Metadata = metadata.try_into()?;\n\n            metadata.hooks = match &self.source {\n                PluginSource::Filesystem(dir) => lua_mod::hooks(&self.lua, dir)?,\n                PluginSource::Embedded(embedded) => lua_mod::hooks_embedded(&self.lua, embedded)?,\n            };\n\n            Ok(metadata)\n        })\n    }\n\n    fn load_embedded_libs(&self, embedded: &EmbeddedPlugin) -> Result<()> {\n        let package: Table = self.lua.globals().get(\"package\")?;\n        let preload: Table = package.get(\"preload\")?;\n\n        // Register lib modules in package.preload so require() works regardless of load order\n        // This allows lib files to require each other without alphabetical ordering issues\n        for (name, code) in embedded.lib {\n            let lua = self.lua.clone();\n            let code = *code;\n            let loader = lua.create_function(move |lua, _: ()| {\n                let module: Value = lua.load(code).eval()?;\n                Ok(module)\n            })?;\n            preload.set(*name, loader)?;\n        }\n\n        Ok(())\n    }\n\n    fn set_global<V>(&self, name: &str, value: V) -> Result<()>\n    where\n        V: IntoLua,\n    {\n        self.lua.globals().set(name, value)?;\n        Ok(())\n    }\n\n    fn load_metadata(&self) -> Result<Table> {\n        match &self.source {\n            PluginSource::Filesystem(_) => {\n                let metadata = self\n                    .lua\n                    .load(\n                        r#\"\n                        require \"metadata\"\n                        return PLUGIN\n                    \"#,\n                    )\n                    .eval()?;\n                Ok(metadata)\n            }\n            PluginSource::Embedded(embedded) => {\n                // Load metadata from embedded string\n                self.lua.load(embedded.metadata).exec()?;\n                let metadata = self.lua.globals().get(\"PLUGIN\")?;\n                Ok(metadata)\n            }\n        }\n    }\n}\n\nfn get_package(lua: &Lua) -> Result<Table> {\n    let package = lua.globals().get::<Table>(\"package\")?;\n    Ok(package)\n}\n\nfn set_paths(lua: &Lua, paths: &[PathBuf]) -> Result<()> {\n    let paths = paths\n        .iter()\n        .map(|p| p.to_string_lossy().to_string())\n        .collect::<Vec<String>>()\n        .join(\";\");\n\n    get_package(lua)?.set(\"path\", paths)?;\n\n    Ok(())\n}\n\nimpl Display for Plugin {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.name)\n    }\n}\n\nimpl PartialEq<Self> for Plugin {\n    fn eq(&self, other: &Self) -> bool {\n        self.dir == other.dir\n    }\n}\n\nimpl Eq for Plugin {}\n\nimpl PartialOrd for Plugin {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for Plugin {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.name.cmp(&other.name)\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/registry.rs",
    "content": "use std::collections::BTreeMap;\nuse std::str::FromStr;\n\nuse once_cell::sync::Lazy;\nuse url::Url;\n\nstatic SDKS: Lazy<BTreeMap<String, Url>> = Lazy::new(|| {\n    [\n        (\"nodejs\", \"https://github.com/version-fox/vfox-nodejs\"),\n        (\"cmake\", \"https://github.com/version-fox/vfox-cmake\"),\n    ]\n    .iter()\n    .map(|(name, url)| (name.to_string(), Url::from_str(url).unwrap()))\n    .collect()\n});\n\npub fn sdk_url(name: &str) -> Option<&Url> {\n    SDKS.get(name)\n}\n\npub fn list_sdks() -> &'static BTreeMap<String, Url> {\n    &SDKS\n}\n"
  },
  {
    "path": "crates/vfox/src/runtime.rs",
    "content": "use crate::config::{arch, env_type, os};\nuse mlua::{UserData, UserDataFields};\nuse once_cell::sync::Lazy;\nuse std::path::PathBuf;\nuse std::sync::Mutex;\n\n#[derive(Debug, Clone)]\npub(crate) struct Runtime {\n    pub(crate) os: String,\n    pub(crate) arch: String,\n    pub(crate) env_type: Option<String>,\n    pub(crate) version: String,\n    pub(crate) plugin_dir_path: PathBuf,\n}\n\nstatic RUNTIME: Lazy<Mutex<Runtime>> = Lazy::new(|| {\n    Mutex::new(Runtime {\n        os: os(),\n        arch: arch(),\n        env_type: env_type(),\n        version: \"0.6.0\".to_string(), // https://github.com/version-fox/vfox/releases\n        plugin_dir_path: PathBuf::new(),\n    })\n});\n\nimpl Runtime {\n    pub(crate) fn get(plugin_dir_path: PathBuf) -> Runtime {\n        let mut runtime = RUNTIME.lock().unwrap().clone();\n        runtime.plugin_dir_path = plugin_dir_path;\n        runtime\n    }\n\n    pub(crate) fn with_platform(plugin_dir_path: PathBuf, os: &str, arch: &str) -> Runtime {\n        let mut runtime = Self::get(plugin_dir_path);\n        runtime.os = os.to_string();\n        runtime.arch = arch.to_string();\n        runtime.env_type = None; // target libc is unknown in cross-platform context\n        runtime\n    }\n\n    #[cfg(test)]\n    pub(crate) fn set_os(os: String) {\n        let mut runtime = RUNTIME.lock().unwrap();\n        runtime.os = os;\n    }\n\n    #[cfg(test)]\n    pub(crate) fn set_arch(arch: String) {\n        let mut runtime = RUNTIME.lock().unwrap();\n        runtime.arch = arch;\n    }\n\n    #[cfg(test)]\n    pub(crate) fn set_env_type(et: Option<String>) {\n        let mut runtime = RUNTIME.lock().unwrap();\n        runtime.env_type = et;\n    }\n\n    #[cfg(test)]\n    pub(crate) fn reset() {\n        let mut runtime = RUNTIME.lock().unwrap();\n        runtime.os = os();\n        runtime.arch = arch();\n        runtime.env_type = env_type();\n    }\n}\n\nimpl UserData for Runtime {\n    fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {\n        fields.add_field_method_get(\"osType\", |_, t| Ok(t.os.clone()));\n        fields.add_field_method_get(\"archType\", |_, t| Ok(t.arch.clone()));\n        fields.add_field_method_get(\"envType\", |_, t| Ok(t.env_type.clone()));\n        fields.add_field_method_get(\"version\", |_, t| Ok(t.version.clone()));\n        fields.add_field_method_get(\"pluginDirPath\", |_, t| Ok(t.plugin_dir_path.clone()));\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/sdk_info.rs",
    "content": "use mlua::{IntoLua, Lua, Value};\nuse std::path::PathBuf;\n\n#[derive(Debug, Clone)]\npub struct SdkInfo {\n    pub name: String,\n    pub version: String,\n    pub path: PathBuf,\n}\n\nimpl SdkInfo {\n    pub fn new(name: String, version: String, path: PathBuf) -> Self {\n        Self {\n            name,\n            version,\n            path,\n        }\n    }\n}\n\nimpl IntoLua for SdkInfo {\n    fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {\n        let table = lua.create_table()?;\n        table.set(\"name\", self.name)?;\n        table.set(\"version\", self.version)?;\n        table.set(\"path\", self.path.to_string_lossy().to_string())?;\n        Ok(Value::Table(table))\n    }\n}\n"
  },
  {
    "path": "crates/vfox/src/vfox.rs",
    "content": "use indexmap::IndexMap;\nuse itertools::Itertools;\nuse reqwest::Url;\nuse std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::sync::mpsc;\nuse tempfile::TempDir;\nuse xx::file;\n\nuse crate::error::Result;\nuse crate::hooks::available::AvailableVersion;\nuse crate::hooks::backend_exec_env::BackendExecEnvContext;\nuse crate::hooks::backend_install::BackendInstallContext;\nuse crate::hooks::backend_list_versions::BackendListVersionsContext;\nuse crate::hooks::env_keys::{EnvKey, EnvKeysContext};\nuse crate::hooks::mise_env::{MiseEnvContext, MiseEnvResult};\nuse crate::hooks::mise_path::MisePathContext;\nuse crate::hooks::parse_legacy_file::ParseLegacyFileResponse;\nuse crate::hooks::post_install::PostInstallContext;\nuse crate::hooks::pre_install::{PreInstall, PreInstallAttestation, VerifiedAttestation};\nuse crate::http::CLIENT;\nuse crate::metadata::Metadata;\nuse crate::plugin::Plugin;\nuse crate::registry;\nuse crate::sdk_info::SdkInfo;\n\n/// Install result containing optional checksum used for verification\n#[derive(Debug, Default)]\npub struct InstallResult {\n    /// The SHA256 checksum if one was provided and verified\n    pub sha256: Option<String>,\n    /// The type of attestation that was successfully verified (if any)\n    pub verified_attestation: Option<VerifiedAttestation>,\n}\n\n#[derive(Debug)]\npub struct Vfox {\n    pub runtime_version: String,\n    pub install_dir: PathBuf,\n    pub plugin_dir: PathBuf,\n    pub cache_dir: PathBuf,\n    pub download_dir: PathBuf,\n    log_tx: Option<mpsc::Sender<String>>,\n}\n\nimpl Vfox {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn log_subscribe(&mut self) -> mpsc::Receiver<String> {\n        let (tx, rx) = mpsc::channel();\n        self.log_tx = Some(tx);\n        rx\n    }\n\n    fn log_emit(&self, msg: String) {\n        if let Some(tx) = &self.log_tx {\n            let _ = tx.send(msg);\n        }\n    }\n\n    pub fn list_available_sdks() -> &'static BTreeMap<String, Url> {\n        registry::list_sdks()\n    }\n\n    pub async fn list_available_versions(&self, sdk: &str) -> Result<Vec<AvailableVersion>> {\n        let sdk = self.get_sdk(sdk)?;\n        sdk.available_async().await\n    }\n\n    pub fn list_installed_versions(&self, sdk: &str) -> Result<Vec<SdkInfo>> {\n        let path = self.install_dir.join(sdk);\n        if !path.exists() {\n            return Ok(Default::default());\n        }\n        let sdk = self.get_sdk(sdk)?;\n        let versions = xx::file::ls(&path)?;\n        versions\n            .into_iter()\n            .filter_map(|p| {\n                p.file_name()\n                    .and_then(|f| f.to_str())\n                    .map(|s| s.to_string())\n            })\n            .sorted()\n            .map(|version| {\n                let path = path.join(&version);\n                sdk.sdk_info(version, path)\n            })\n            .collect::<Result<_>>()\n    }\n    pub fn list_sdks(&self) -> Result<Vec<Plugin>> {\n        if !self.plugin_dir.exists() {\n            return Ok(Default::default());\n        }\n        let plugins = xx::file::ls(&self.plugin_dir)?;\n        plugins\n            .into_iter()\n            .filter_map(|p| {\n                p.file_name()\n                    .and_then(|f| f.to_str())\n                    .map(|s| s.to_string())\n            })\n            .sorted()\n            .map(|name| self.get_sdk(&name))\n            .collect()\n    }\n\n    pub fn get_sdk(&self, name: &str) -> Result<Plugin> {\n        Plugin::from_name_or_dir(name, &self.plugin_dir.join(name))\n    }\n\n    pub fn install_plugin(&self, sdk: &str) -> Result<Plugin> {\n        // Check filesystem first - allows user to override embedded plugins\n        let plugin_dir = self.plugin_dir.join(sdk);\n        if plugin_dir.exists() {\n            return Plugin::from_dir(&plugin_dir);\n        }\n\n        // Fall back to embedded plugin if available\n        if let Some(embedded) = crate::embedded_plugins::get_embedded_plugin(sdk) {\n            return Plugin::from_embedded(sdk, embedded);\n        }\n\n        // Otherwise install from registry\n        let url = registry::sdk_url(sdk).ok_or_else(|| format!(\"Unknown SDK: {sdk}\"))?;\n        self.install_plugin_from_url(url)\n    }\n\n    pub fn install_plugin_from_url(&self, url: &Url) -> Result<Plugin> {\n        let sdk = url\n            .path_segments()\n            .and_then(|mut s| {\n                let filename = s.next_back().unwrap();\n                filename\n                    .strip_prefix(\"vfox-\")\n                    .map(|s| s.to_string())\n                    .or_else(|| Some(filename.to_string()))\n            })\n            .ok_or(\"No filename in URL\")?;\n        let plugin_dir = self.plugin_dir.join(&sdk);\n        if !plugin_dir.exists() {\n            debug!(\"Installing plugin {sdk}\");\n            xx::git::clone(url.as_ref(), &plugin_dir, &Default::default())?;\n        }\n        Plugin::from_dir(&plugin_dir)\n    }\n\n    pub fn uninstall_plugin(&self, sdk: &str) -> Result<()> {\n        let plugin_dir = self.plugin_dir.join(sdk);\n        if plugin_dir.exists() {\n            file::remove_dir_all(&plugin_dir)?;\n        }\n        Ok(())\n    }\n\n    pub async fn install<ID: AsRef<Path>>(\n        &self,\n        sdk: &str,\n        version: &str,\n        install_dir: ID,\n    ) -> Result<InstallResult> {\n        self.install_plugin(sdk)?;\n        let sdk = self.get_sdk(sdk)?;\n        let pre_install = sdk.pre_install(version).await?;\n        let install_dir = install_dir.as_ref();\n        trace!(\"{pre_install:?}\");\n        let mut verified_attestation = None;\n        if let Some(url) = pre_install.url.as_ref().map(|s| Url::from_str(s)) {\n            let file = self.download(&url?, &sdk, version).await?;\n            verified_attestation = self.verify(&pre_install, &file).await?;\n            self.extract(&file, install_dir)?;\n        }\n\n        if sdk.get_metadata()?.hooks.contains(\"post_install\") {\n            let sdk_info = sdk.sdk_info(version.to_string(), install_dir.to_path_buf())?;\n            sdk.post_install(PostInstallContext {\n                root_path: install_dir.to_path_buf(),\n                runtime_version: self.runtime_version.clone(),\n                sdk_info: BTreeMap::from([(sdk_info.name.clone(), sdk_info)]),\n            })\n            .await?;\n        }\n\n        Ok(InstallResult {\n            sha256: pre_install.sha256,\n            verified_attestation,\n        })\n    }\n\n    pub fn uninstall(&self, sdk: &str, version: &str) -> Result<()> {\n        let path = self.install_dir.join(sdk).join(version);\n        file::remove_dir_all(&path)?;\n        Ok(())\n    }\n\n    pub async fn pre_install_for_platform(\n        &self,\n        sdk: &str,\n        version: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<PreInstall> {\n        let sdk = self.get_sdk(sdk)?;\n        sdk.pre_install_for_platform(version, os, arch).await\n    }\n\n    /// Returns the download URL and the highest-priority verified attestation type\n    /// declared by the plugin for the given platform, without performing actual\n    /// verification or installation.\n    pub async fn pre_install_provenance_for_platform(\n        &self,\n        sdk: &str,\n        version: &str,\n        os: &str,\n        arch: &str,\n    ) -> Result<(Option<String>, Option<VerifiedAttestation>)> {\n        let pre = self\n            .pre_install_for_platform(sdk, version, os, arch)\n            .await?;\n        let att = pre.attestation.and_then(attestation_to_verified);\n        // Note: pre.sha256 / pre.sha512 are intentionally not returned here;\n        // checksum verification only happens during `mise install`, not `mise lock`.\n        Ok((pre.url, att))\n    }\n\n    pub async fn metadata(&self, sdk: &str) -> Result<Metadata> {\n        self.get_sdk(sdk)?.get_metadata()\n    }\n\n    pub async fn env_keys<T: serde::Serialize>(\n        &self,\n        sdk: &str,\n        version: &str,\n        options: T,\n    ) -> Result<Vec<EnvKey>> {\n        debug!(\"Getting env keys for {sdk} version {version}\");\n        let sdk = self.get_sdk(sdk)?;\n        let sdk_info = sdk.sdk_info(\n            version.to_string(),\n            self.install_dir.join(&sdk.name).join(version),\n        )?;\n        let ctx = EnvKeysContext {\n            args: vec![],\n            version: version.to_string(),\n            path: sdk_info.path.clone(),\n            sdk_info: BTreeMap::from([(sdk_info.name.clone(), sdk_info.clone())]),\n            main: sdk_info,\n            options,\n        };\n        sdk.env_keys(ctx).await\n    }\n\n    pub async fn mise_env<T: serde::Serialize>(\n        &self,\n        sdk: &str,\n        opts: T,\n        env: &indexmap::IndexMap<String, String>,\n    ) -> Result<MiseEnvResult> {\n        let plugin = self.get_sdk(sdk)?;\n        if !plugin.get_metadata()?.hooks.contains(\"mise_env\") {\n            return Ok(MiseEnvResult::default());\n        }\n        plugin.set_cmd_env(env)?;\n        let ctx = MiseEnvContext {\n            args: vec![],\n            options: opts,\n        };\n        plugin.mise_env(ctx).await\n    }\n\n    pub async fn backend_list_versions(&self, sdk: &str, tool: &str) -> Result<Vec<String>> {\n        let plugin = self.get_sdk(sdk)?;\n        let ctx = BackendListVersionsContext {\n            tool: tool.to_string(),\n        };\n        plugin.backend_list_versions(ctx).await.map(|r| r.versions)\n    }\n\n    pub async fn backend_install(\n        &self,\n        sdk: &str,\n        tool: &str,\n        version: &str,\n        install_path: PathBuf,\n        download_path: PathBuf,\n        options: IndexMap<String, String>,\n    ) -> Result<()> {\n        let plugin = self.get_sdk(sdk)?;\n        let ctx = BackendInstallContext {\n            tool: tool.to_string(),\n            version: version.to_string(),\n            install_path,\n            download_path,\n            options,\n        };\n        plugin.backend_install(ctx).await?;\n        Ok(())\n    }\n\n    pub async fn backend_exec_env(\n        &self,\n        sdk: &str,\n        tool: &str,\n        version: &str,\n        install_path: PathBuf,\n        options: IndexMap<String, String>,\n    ) -> Result<Vec<EnvKey>> {\n        let plugin = self.get_sdk(sdk)?;\n        let ctx = BackendExecEnvContext {\n            tool: tool.to_string(),\n            version: version.to_string(),\n            install_path,\n            options,\n        };\n        plugin.backend_exec_env(ctx).await.map(|r| r.env_vars)\n    }\n\n    pub async fn mise_path<T: serde::Serialize>(\n        &self,\n        sdk: &str,\n        opts: T,\n        env: &indexmap::IndexMap<String, String>,\n    ) -> Result<Vec<String>> {\n        let plugin = self.get_sdk(sdk)?;\n        if !plugin.get_metadata()?.hooks.contains(\"mise_path\") {\n            return Ok(vec![]);\n        }\n        plugin.set_cmd_env(env)?;\n        let ctx = MisePathContext {\n            args: vec![],\n            options: opts,\n        };\n        plugin.mise_path(ctx).await\n    }\n\n    pub async fn parse_legacy_file(\n        &self,\n        sdk: &str,\n        file: &Path,\n    ) -> Result<ParseLegacyFileResponse> {\n        let sdk = self.get_sdk(sdk)?;\n        sdk.parse_legacy_file(file).await\n    }\n\n    async fn download(&self, url: &Url, sdk: &Plugin, version: &str) -> Result<PathBuf> {\n        self.log_emit(format!(\"Downloading {url}\"));\n        let filename = url\n            .path_segments()\n            .and_then(|mut s| s.next_back())\n            .ok_or(\"No filename in URL\")?;\n        let path = self\n            .download_dir\n            .join(format!(\"{sdk}-{version}\"))\n            .join(filename);\n        let resp = CLIENT.get(url.clone()).send().await?;\n        resp.error_for_status_ref()?;\n        file::mkdirp(path.parent().unwrap())?;\n        let mut file = tokio::fs::File::create(&path).await?;\n        let bytes = resp.bytes().await?;\n        tokio::io::AsyncWriteExt::write_all(&mut file, &bytes).await?;\n        file.sync_all().await?;\n        Ok(path)\n    }\n\n    async fn verify(\n        &self,\n        pre_install: &PreInstall,\n        file: &Path,\n    ) -> Result<Option<VerifiedAttestation>> {\n        self.log_emit(format!(\"Verifying {file:?} checksum\"));\n        if let Some(sha256) = &pre_install.sha256 {\n            xx::hash::ensure_checksum_sha256(file, sha256)?;\n        }\n        if let Some(sha512) = &pre_install.sha512 {\n            xx::hash::ensure_checksum_sha512(file, sha512)?;\n        }\n        if let Some(_sha1) = &pre_install.sha1 {\n            unimplemented!(\"sha1\")\n        }\n        if let Some(_md5) = &pre_install.md5 {\n            unimplemented!(\"md5\")\n        }\n        let mut verified: Option<VerifiedAttestation> = None;\n        if let Some(attestation) = &pre_install.attestation {\n            self.log_emit(format!(\"Verify {file:?} attestation\"));\n            if let Some(owner) = &attestation.github_owner\n                && let Some(repo) = &attestation.github_repo\n            {\n                let token = std::env::var(\"MISE_GITHUB_TOKEN\")\n                    .or_else(|_| std::env::var(\"GITHUB_TOKEN\"))\n                    .or(Err(\"GitHub artifact attestation verification requires either the MISE_GITHUB_TOKEN or GITHUB_TOKEN environment variable set\"))?;\n                sigstore_verification::verify_github_attestation(\n                    file,\n                    owner.as_str(),\n                    repo.as_str(),\n                    Some(token.as_str()),\n                    attestation.github_signer_workflow.as_deref(),\n                )\n                .await?;\n                // All configured verifications always execute (no short-circuit).\n                // Priority only affects which variant is *recorded* in `verified`.\n                // GitHub attestations have the highest recording priority.\n                verified = Some(VerifiedAttestation::GithubAttestations {\n                    owner: owner.clone(),\n                    repo: repo.clone(),\n                    signer_workflow: attestation.github_signer_workflow.clone(),\n                });\n            }\n\n            if let Some(sig_or_bundle_path) = &attestation.cosign_sig_or_bundle_path {\n                if let Some(public_key_path) = &attestation.cosign_public_key_path {\n                    sigstore_verification::verify_cosign_signature_with_key(\n                        file,\n                        sig_or_bundle_path,\n                        public_key_path,\n                    )\n                    .await?;\n                } else {\n                    sigstore_verification::verify_cosign_signature(file, sig_or_bundle_path)\n                        .await?;\n                }\n                // Cosign has the lowest recording priority: only record it if no\n                // higher-priority verification was already recorded.\n                if verified.is_none() {\n                    verified = Some(VerifiedAttestation::Cosign {\n                        sig_or_bundle_path: sig_or_bundle_path.clone(),\n                        public_key_path: attestation.cosign_public_key_path.clone(),\n                    });\n                }\n            }\n\n            if let Some(provenance_path) = &attestation.slsa_provenance_path {\n                let min_level = attestation.slsa_min_level.unwrap_or(1u8);\n                sigstore_verification::verify_slsa_provenance(file, provenance_path, min_level)\n                    .await?;\n                // SLSA has mid-tier recording priority: record it unless GitHub\n                // attestation (higher priority) was already recorded.\n                // Note: if Cosign also passed, SLSA supersedes it (SLSA > Cosign).\n                if !matches!(\n                    verified,\n                    Some(VerifiedAttestation::GithubAttestations { .. })\n                ) {\n                    verified = Some(VerifiedAttestation::Slsa {\n                        provenance_path: provenance_path.clone(),\n                    });\n                }\n            }\n        }\n        Ok(verified)\n    }\n\n    fn extract(&self, file: &Path, install_dir: &Path) -> Result<()> {\n        self.log_emit(format!(\"Extracting {file:?} to {install_dir:?}\"));\n        let filename = file.file_name().unwrap().to_string_lossy().to_string();\n        let parent = install_dir.parent().unwrap();\n        file::mkdirp(parent)?;\n        let tmp = TempDir::with_prefix_in(&filename, parent)?;\n        file::remove_dir_all(install_dir)?;\n        let move_to_install = || {\n            let subdirs = file::ls(tmp.path())?;\n            if subdirs.len() == 1 && subdirs.first().unwrap().is_dir() {\n                let subdir = subdirs.first().unwrap();\n                file::mv(subdir, install_dir)?;\n            } else {\n                file::mv(tmp.path(), install_dir)?;\n            }\n            Result::Ok(())\n        };\n        if filename.ends_with(\".tar.gz\") || filename.ends_with(\".tgz\") {\n            xx::archive::untar_gz(file, tmp.path())?;\n            move_to_install()?;\n        } else if filename.ends_with(\".tar.xz\") || filename.ends_with(\".txz\") {\n            xx::archive::untar_xz(file, tmp.path())?;\n            move_to_install()?;\n        } else if filename.ends_with(\".tar.bz2\")\n            || filename.ends_with(\".tbz2\")\n            || filename.ends_with(\".tbz\")\n        {\n            xx::archive::untar_bz2(file, tmp.path())?;\n            move_to_install()?;\n        } else if filename.ends_with(\".zip\") {\n            xx::archive::unzip(file, tmp.path())?;\n            move_to_install()?;\n        } else {\n            file::mv(file, install_dir.join(&filename))?;\n            #[cfg(unix)]\n            file::make_executable(install_dir.join(&filename))?;\n        }\n        Ok(())\n    }\n}\n\n/// Convert a `PreInstallAttestation` to the highest-priority `VerifiedAttestation` variant\n/// declared by the plugin. Priority: GitHub > SLSA > Cosign.\n///\n/// This is used by `pre_install_provenance_for_platform` to report what *type* of attestation\n/// the plugin declares, without actually performing sigstore verification.\nfn attestation_to_verified(att: PreInstallAttestation) -> Option<VerifiedAttestation> {\n    // GitHub attestations have the highest priority\n    if let Some(owner) = att.github_owner\n        && let Some(repo) = att.github_repo\n    {\n        return Some(VerifiedAttestation::GithubAttestations {\n            owner,\n            repo,\n            signer_workflow: att.github_signer_workflow,\n        });\n    }\n    // SLSA is second priority\n    if let Some(provenance_path) = att.slsa_provenance_path {\n        return Some(VerifiedAttestation::Slsa { provenance_path });\n    }\n    // Cosign is third priority\n    if let Some(sig_or_bundle_path) = att.cosign_sig_or_bundle_path {\n        return Some(VerifiedAttestation::Cosign {\n            sig_or_bundle_path,\n            public_key_path: att.cosign_public_key_path,\n        });\n    }\n    None\n}\n\nimpl Default for Vfox {\n    fn default() -> Self {\n        Self {\n            runtime_version: \"1.0.0\".to_string(),\n            plugin_dir: home().join(\".version-fox/plugin\"),\n            cache_dir: home().join(\".version-fox/cache\"),\n            download_dir: home().join(\".version-fox/downloads\"),\n            install_dir: home().join(\".version-fox/installs\"),\n            log_tx: None,\n        }\n    }\n}\n\nfn home() -> PathBuf {\n    homedir::my_home()\n        .ok()\n        .flatten()\n        .unwrap_or_else(|| PathBuf::from(\"/\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    impl Vfox {\n        pub fn test() -> Self {\n            Self {\n                runtime_version: \"1.0.0\".to_string(),\n                plugin_dir: PathBuf::from(\"plugins\"),\n                cache_dir: PathBuf::from(\"test/cache\"),\n                download_dir: PathBuf::from(\"test/downloads\"),\n                install_dir: PathBuf::from(\"test/installs\"),\n                log_tx: None,\n            }\n        }\n    }\n\n    #[tokio::test]\n    async fn test_env_keys() {\n        let vfox = Vfox::test();\n        // dummy plugin already exists in plugins/dummy, no need to install\n        let keys = vfox\n            .env_keys(\n                \"dummy\",\n                \"1.0.0\",\n                serde_json::Value::Object(Default::default()),\n            )\n            .await\n            .unwrap();\n        let output = format!(\"{keys:?}\").replace(\n            &vfox.install_dir.to_string_lossy().to_string(),\n            \"<INSTALL_DIR>\",\n        );\n        assert_snapshot!(output);\n    }\n\n    #[tokio::test]\n    async fn test_install_plugin() {\n        let vfox = Vfox::test();\n        // dummy plugin already exists in plugins/dummy, just verify it's there\n        assert!(vfox.plugin_dir.join(\"dummy\").exists());\n        let plugin = Plugin::from_dir(&vfox.plugin_dir.join(\"dummy\")).unwrap();\n        assert_eq!(plugin.name, \"dummy\");\n    }\n\n    #[tokio::test]\n    async fn test_install() {\n        let vfox = Vfox::test();\n        let install_dir = vfox.install_dir.join(\"dummy\").join(\"1.0.0\");\n        // dummy plugin already exists in plugins/dummy\n        vfox.install(\"dummy\", \"1.0.0\", &install_dir).await.unwrap();\n        // dummy plugin doesn't actually install binaries, so we just check the directory\n        assert!(vfox.install_dir.join(\"dummy\").join(\"1.0.0\").exists());\n        vfox.uninstall(\"dummy\", \"1.0.0\").unwrap();\n        assert!(!vfox.install_dir.join(\"dummy\").join(\"1.0.0\").exists());\n        file::remove_dir_all(vfox.install_dir).unwrap();\n        file::remove_dir_all(vfox.download_dir).unwrap();\n    }\n\n    #[tokio::test]\n    #[ignore] // disable for now\n    async fn test_install_cmake() {\n        let vfox = Vfox::test();\n        vfox.install_plugin(\"cmake\").unwrap();\n        let install_dir = vfox.install_dir.join(\"cmake\").join(\"3.21.0\");\n        vfox.install(\"cmake\", \"3.21.0\", &install_dir).await.unwrap();\n        if cfg!(target_os = \"linux\") {\n            assert!(\n                vfox.install_dir\n                    .join(\"cmake\")\n                    .join(\"3.21.0\")\n                    .join(\"bin\")\n                    .join(\"cmake\")\n                    .exists()\n            );\n        } else if cfg!(target_os = \"macos\") {\n            assert!(\n                vfox.install_dir\n                    .join(\"cmake\")\n                    .join(\"3.21.0\")\n                    .join(\"CMake.app\")\n                    .join(\"Contents\")\n                    .join(\"bin\")\n                    .join(\"cmake\")\n                    .exists()\n            );\n        } else if cfg!(target_os = \"windows\") {\n            assert!(\n                vfox.install_dir\n                    .join(\"cmake\")\n                    .join(\"3.21.0\")\n                    .join(\"bin\")\n                    .join(\"cmake.exe\")\n                    .exists()\n            );\n        }\n        vfox.uninstall_plugin(\"cmake\").unwrap();\n        assert!(!vfox.plugin_dir.join(\"cmake\").exists());\n        vfox.uninstall(\"cmake\", \"3.21.0\").unwrap();\n        assert!(!vfox.install_dir.join(\"cmake\").join(\"3.21.0\").exists());\n        file::remove_dir_all(vfox.plugin_dir.join(\"cmake\")).unwrap();\n        file::remove_dir_all(vfox.install_dir).unwrap();\n        file::remove_dir_all(vfox.download_dir).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_metadata() {\n        let vfox = Vfox::test();\n        // dummy plugin already exists in plugins/dummy\n        let metadata = vfox.metadata(\"dummy\").await.unwrap();\n        let out = format!(\"{metadata:?}\");\n        assert_snapshot!(out);\n    }\n}\n"
  },
  {
    "path": "crates/vfox/test/data/.dummy-version",
    "content": "1.0.0 \n"
  },
  {
    "path": "crates/vfox/test/data/.node-version",
    "content": "v20.0.0\n"
  },
  {
    "path": "crates/vfox/types/mise-plugin.lua",
    "content": "--- LuaCATS type definitions for mise vfox plugins\n--- These annotations provide IDE support via lua-language-server.\n--- See https://luals.github.io/wiki/annotations/\n\n------------------------------------------------------------------------\n-- Globals\n------------------------------------------------------------------------\n\n---@class Runtime\n---@field osType string Operating system type (e.g. \"linux\", \"darwin\", \"windows\")\n---@field archType string Architecture type (e.g. \"amd64\", \"arm64\")\n---@field envType string|nil libc environment type (\"gnu\" on glibc Linux, \"musl\" on musl Linux, nil on other platforms)\n---@field version string Runtime version\n---@field pluginDirPath string Path to the plugin directory\nRUNTIME = {}\n\n--- @deprecated Use RUNTIME.osType instead\n---@type string\nOS_TYPE = \"\"\n\n--- @deprecated Use RUNTIME.archType instead\n---@type string\nARCH_TYPE = \"\"\n\n------------------------------------------------------------------------\n-- PLUGIN table & hook method signatures\n------------------------------------------------------------------------\n\n---@class AvailableVersion\n---@field version string Version string\n---@field note? string Optional note about the version\n---@field rolling? boolean If true, this is a rolling release (e.g. \"nightly\")\n---@field checksum? string Checksum for detecting changes in rolling releases\n\n---@class AvailableCtx\n---@field args string[] Command-line arguments\n\n---@class PreInstallResult\n---@field version string Version string\n---@field url? string Download URL\n---@field note? string Optional note\n---@field sha256? string SHA-256 checksum\n---@field md5? string MD5 checksum\n---@field sha1? string SHA-1 checksum\n---@field sha512? string SHA-512 checksum\n---@field attestation? PreInstallAttestation Optional attestation parameters\n\n---@class PreInstallAttestation\n---@field github_owner? string GitHub repository owner\n---@field github_repo? string GitHub repository name\n---@field github_signer_workflow? string GitHub Actions signer workflow\n---@field cosign_sig_or_bundle_path? string Path to cosign signature or bundle\n---@field cosign_public_key_path? string Path to cosign public key\n---@field slsa_provenance_path? string Path to SLSA provenance\n---@field slsa_min_level? integer Minimum SLSA level\n\n---@class PreInstallCtx\n---@field args string[] Command-line arguments\n---@field version string Requested version\n\n---@class PostInstallCtx\n---@field rootPath string Installation root path\n---@field runtimeVersion string Runtime version\n---@field sdkInfo table<string, SdkInfo> SDK info for installed versions\n\n---@class SdkInfo\n---@field path string Installation path\n---@field version string Installed version\n---@field note? string Optional note\n\n---@class EnvKey\n---@field key string Environment variable name\n---@field value string Environment variable value\n\n---@class EnvKeysCtx\n---@field version string Installed version\n---@field path string Installation path\n---@field sdkInfo table<string, SdkInfo> SDK info for installed versions\n---@field main SdkInfo Main SDK info\n---@field options table Plugin options from mise.toml\n\n---@class ParseLegacyFileCtx\n---@field args string[] Command-line arguments\n---@field filename string Basename of the legacy file\n---@field filepath string Full path to the legacy file\n---@field getInstalledVersions fun(): string[] Returns list of installed versions\n\n---@class ParseLegacyFileResult\n---@field version? string Parsed version string\n\n---@class MiseEnvCtx\n---@field options table Plugin options from mise.toml\n\n---@class MiseEnvResult\n---@field env? EnvKey[] Environment variables to set\n---@field cacheable? boolean Whether the result can be cached (default false)\n---@field watch_files? string[] Files to watch for cache invalidation\n---@field redact? boolean Whether env vars should be redacted in output (default false)\n\n---@class MisePathCtx\n---@field options table Plugin options from mise.toml\n\n---@class BackendListVersionsCtx\n---@field tool string Tool name\n\n---@class BackendListVersionsResult\n---@field versions string[] List of available versions\n\n---@class BackendInstallCtx\n---@field tool string Tool name\n---@field version string Version to install\n---@field install_path string Path where the tool should be installed\n---@field download_path string Path where the tool artifact should be downloaded\n\n---@class BackendInstallResult\n\n---@class BackendExecEnvCtx\n---@field tool string Tool name\n---@field version string Installed version\n---@field install_path string Installation path\n\n---@class BackendExecEnvResult\n---@field env_vars EnvKey[] Environment variables to set\n\n---@class Plugin\n---@field name string Plugin name\n---@field Available? fun(self: Plugin, ctx: AvailableCtx): AvailableVersion[]\n---@field PreInstall? fun(self: Plugin, ctx: PreInstallCtx): PreInstallResult\n---@field PostInstall? fun(self: Plugin, ctx: PostInstallCtx)\n---@field EnvKeys? fun(self: Plugin, ctx: EnvKeysCtx): EnvKey[]\n---@field ParseLegacyFile? fun(self: Plugin, ctx: ParseLegacyFileCtx): ParseLegacyFileResult\n---@field MiseEnv? fun(self: Plugin, ctx: MiseEnvCtx): MiseEnvResult|EnvKey[]\n---@field MisePath? fun(self: Plugin, ctx: MisePathCtx): string[]\n---@field BackendListVersions? fun(self: Plugin, ctx: BackendListVersionsCtx): BackendListVersionsResult\n---@field BackendInstall? fun(self: Plugin, ctx: BackendInstallCtx): BackendInstallResult\n---@field BackendExecEnv? fun(self: Plugin, ctx: BackendExecEnvCtx): BackendExecEnvResult\nPLUGIN = {}\n\n------------------------------------------------------------------------\n-- Built-in modules (available via require)\n------------------------------------------------------------------------\n\n-- http module --------------------------------------------------------\n\n---@class HttpRequestOpts\n---@field url string Request URL\n---@field headers? table<string, string> HTTP headers\n\n---@class HttpResponse\n---@field status_code integer HTTP status code\n---@field headers table<string, string> Response headers\n---@field body string Response body (only for get, not head)\n\n---@class http\n---@field get fun(opts: HttpRequestOpts): HttpResponse Send a GET request\n---@field head fun(opts: HttpRequestOpts): HttpResponse Send a HEAD request (no body)\n---@field download_file fun(opts: HttpRequestOpts, path: string) Download a file to disk\nlocal http = {}\n\n-- json module --------------------------------------------------------\n\n---@class json\n---@field encode fun(value: any): string Encode a value as JSON\n---@field decode fun(str: string): any Decode a JSON string\nlocal json = {}\n\n-- file module --------------------------------------------------------\n\n---@class file\n---@field read fun(path: string): string Read file contents\n---@field exists fun(path: string): boolean Check if a file exists\n---@field symlink fun(src: string, dst: string) Create a symbolic link\n---@field join_path fun(...: string): string Join path components\nlocal file = {}\n\n-- cmd module ---------------------------------------------------------\n\n---@class CmdExecOpts\n---@field cwd? string Working directory\n---@field env? table<string, string> Environment variables\n---@field timeout? integer Timeout in milliseconds\n\n---@class cmd\n---@field exec fun(command: string, opts?: CmdExecOpts): string Execute a shell command\nlocal cmd = {}\n\n-- env module ---------------------------------------------------------\n\n---@class env\n---@field setenv fun(key: string, val: string) Set an environment variable\n---@field getenv fun(key: string): string? Get an environment variable\nlocal env = {}\n\n-- archiver module ----------------------------------------------------\n\n---@class archiver\n---@field decompress fun(archive: string, dest: string) Decompress an archive (.zip, .tar.gz, .tar.xz, .tar.bz2)\nlocal archiver = {}\n\n-- semver module ------------------------------------------------------\n\n---@class semver\n---@field compare fun(v1: string, v2: string): integer Compare two version strings (-1, 0, 1)\n---@field parse fun(version: string): integer[] Parse a version string into numeric parts\n---@field sort fun(versions: string[]): string[] Sort version strings in ascending order\n---@field sort_by fun(arr: table[], field: string): table[] Sort tables by a version field\nlocal semver = {}\n\n-- strings module -----------------------------------------------------\n\n---@class strings\n---@field split fun(s: string, sep: string): string[] Split a string by separator\n---@field has_prefix fun(s: string, prefix: string): boolean Check if string starts with prefix\n---@field has_suffix fun(s: string, suffix: string): boolean Check if string ends with suffix\n---@field trim fun(s: string, suffix: string): string Trim suffix from end of string\n---@field trim_space fun(s: string): string Trim whitespace from both ends\n---@field contains fun(s: string, substr: string): boolean Check if string contains substring\n---@field join fun(arr: any[], sep: string): string Join array elements with separator\nlocal strings = {}\n\n-- html module --------------------------------------------------------\n\n---@class HtmlNode\n---@field find fun(self: HtmlNode, selector: string): HtmlNode Find descendant nodes matching a CSS selector\n---@field first fun(self: HtmlNode): HtmlNode Get the first node\n---@field eq fun(self: HtmlNode, idx: integer): HtmlNode Get node at zero-based index\n---@field each fun(self: HtmlNode, fn: fun(idx: integer, node: HtmlNode)) Iterate over nodes\n---@field text fun(self: HtmlNode): string Get the text content\n---@field attr fun(self: HtmlNode, key: string): string Get an attribute value\n\n---@class html\n---@field parse fun(html_str: string): HtmlNode Parse an HTML string into a node tree\nlocal html = {}\n\n-- log module ---------------------------------------------------------\n\n---@class log\n---@field trace fun(...: any) Log at trace level\n---@field debug fun(...: any) Log at debug level\n---@field info fun(...: any) Log at info level\n---@field warn fun(...: any) Log at warn level\n---@field error fun(...: any) Log at error level\nlocal log = {}\n\nreturn nil\n"
  },
  {
    "path": "default.nix",
    "content": "{ pkgs, lib, fetchFromGitHub, rustPlatform, coreutils, bash, direnv, openssl, git }:\n\nrustPlatform.buildRustPackage {\n  pname = \"mise\";\n  version = \"2026.3.9\";\n\n  src = lib.cleanSource ./.;\n\n  cargoLock = {\n    lockFile = ./Cargo.lock;\n  };\n\n  nativeBuildInputs = with pkgs; [\n    cmakeMinimal\n    clang\n    llvmPackages.libclang\n    pkg-config\n  ];\n  buildInputs = with pkgs; [\n    bash\n    coreutils\n    direnv\n    gawk\n    git\n    gnused\n    openssl\n  ];\n\n  LIBCLANG_PATH = \"${pkgs.llvmPackages.libclang.lib}/lib\";\n\n  prePatch = ''\n    substituteInPlace ./src/test.rs ./test/data/plugins/**/bin/* \\\n      --replace '/usr/bin/env bash' '${bash}/bin/bash'\n    substituteInPlace ./src/fake_asdf.rs ./src/cli/generate/git_pre_commit.rs ./src/cli/generate/snapshots/*.snap \\\n      --replace '/bin/sh' '${bash}/bin/sh'\n    substituteInPlace ./src/env_diff.rs \\\n      --replace '\"bash\"' '\"${bash}/bin/bash\"'\n    substituteInPlace ./src/cli/direnv/exec.rs \\\n      --replace '\"env\"' '\"${coreutils}/bin/env\"' \\\n      --replace 'cmd!(\"direnv\"' 'cmd!(\"${direnv}/bin/direnv\"'\n    substituteInPlace ./src/git.rs ./src/test.rs \\\n      --replace '\"git\"' '\"${git}/bin/git\"'\n  '';\n\n  # Skip the test_plugin_list_urls as it uses the .git folder, which\n  # is excluded by default from Nix.\n  checkPhase = ''\n    RUST_BACKTRACE=full cargo test --all-features -- \\\n      --skip cli::plugins::ls::tests::test_plugin_list_urls \\\n      --skip tera::tests::test_last_modified \\\n      --skip plugins::core::ruby::tests::test_list_versions_matching\n  '';\n\n  meta = with lib; {\n    description = \"The front-end to your dev env\";\n    homepage = \"https://github.com/jdx/mise\";\n    license = licenses.mit;\n    mainProgram = \"mise\";\n  };\n}\n"
  },
  {
    "path": "deny.toml",
    "content": "# This template contains all of the possible sections and their default values\n\n# Note that all fields that take a lint level have these possible values:\n# * deny - An error will be produced and the check will fail\n# * warn - A warning will be produced, but the check will not fail\n# * allow - No warning or error will be produced, though in some cases a note\n# will be\n\n# The values provided in this template are the default values that will be used\n# when any section or field is not specified in your own configuration\n\n# Root options\n\n# The graph table configures how the dependency graph is constructed and thus\n# which crates the checks are performed against\n[graph]\n# If 1 or more target triples (and optionally, target_features) are specified,\n# only the specified targets will be checked when running `cargo deny check`.\n# This means, if a particular package is only ever used as a target specific\n# dependency, such as, for example, the `nix` crate only being used via the\n# `target_family = \"unix\"` configuration, that only having windows targets in\n# this list would mean the nix crate, as well as any of its exclusive\n# dependencies not shared by any other crates, would be ignored, as the target\n# list here is effectively saying which targets you are building for.\ntargets = [\n  # The triple can be any string, but only the target triples built in to\n  # rustc (as of 1.40) can be checked against actual config expressions\n  #\"x86_64-unknown-linux-musl\",\n  # You can also specify which target_features you promise are enabled for a\n  # particular target. target_features are currently not validated against\n  # the actual valid features supported by the target architecture.\n  #{ triple = \"wasm32-unknown-unknown\", features = [\"atomics\"] },\n]\n# When creating the dependency graph used as the source of truth when checks are\n# executed, this field can be used to prune crates from the graph, removing them\n# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate\n# is pruned from the graph, all of its dependencies will also be pruned unless\n# they are connected to another crate in the graph that hasn't been pruned,\n# so it should be used with care. The identifiers are [Package ID Specifications]\n# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)\n#exclude = []\n# If true, metadata will be collected with `--all-features`. Note that this can't\n# be toggled off if true, if you want to conditionally enable `--all-features` it\n# is recommended to pass `--all-features` on the cmd line instead\nall-features = true\n# If true, metadata will be collected with `--no-default-features`. The same\n# caveat with `all-features` applies\nno-default-features = false\n# If set, these feature will be enabled when collecting metadata. If `--features`\n# is specified on the cmd line they will take precedence over this option.\n#features = []\n\n# The output table provides options for how/if diagnostics are outputted\n[output]\n# When outputting inclusion graphs in diagnostics that include features, this\n# option can be used to specify the depth at which feature edges will be added.\n# This option is included since the graphs can be quite large and the addition\n# of features from the crate(s) to all of the graph roots can be far too verbose.\n# This option can be overridden via `--feature-depth` on the cmd line\nfeature-depth = 1\n\n# This section is considered when running `cargo deny check advisories`\n# More documentation for the advisories section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html\n[advisories]\n# The path where the advisory databases are cloned/fetched into\n#db-path = \"$CARGO_HOME/advisory-dbs\"\n# The url(s) of the advisory databases to use\n#db-urls = [\"https://github.com/rustsec/advisory-db\"]\n# A list of advisory IDs to ignore. Note that ignored advisories will still\n# output a note when they are encountered.\nignore = [\n  { id = \"RUSTSEC-2024-0436\", reason = \"subdependency cannot be updated\" },\n  { id = \"RUSTSEC-2024-0370\", reason = \"proc-macro-error dependency from sigstore crate - no safe upgrade available\" },\n  { id = \"RUSTSEC-2023-0071\", reason = \"rsa crate Marvin attack vulnerability from sigstore crate - no safe upgrade available\" },\n  { id = \"RUSTSEC-2025-0119\", reason = \"number_prefix crate is unmaintained - used by indicatif/self_update, no safe upgrade available\" },\n  #\"RUSTSEC-0000-0000\",\n  #{ id = \"RUSTSEC-0000-0000\", reason = \"you can specify a reason the advisory is ignored\" },\n  #\"a-crate-that-is-yanked@0.1.1\", # you can also ignore yanked crate versions if you wish\n  #{ crate = \"a-crate-that-is-yanked@0.1.1\", reason = \"you can specify why you are ignoring the yanked crate\" },\n]\n# If this is true, then cargo deny will use the git executable to fetch advisory database.\n# If this is false, then it uses a built-in git library.\n# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.\n# See Git Authentication for more information about setting up git authentication.\n#git-fetch-with-cli = true\n\n# This section is considered when running `cargo deny check licenses`\n# More documentation for the licenses section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html\n[licenses]\n# List of explicitly allowed licenses\n# See https://spdx.org/licenses/ for list of possible licenses\n# [possible values: any SPDX 3.11 short identifier (+ optional exception)].\nallow = [\n  \"Apache-2.0 WITH LLVM-exception\",\n  \"Apache-2.0\",\n  \"BSD-2-Clause\",\n  \"BSD-3-Clause\",\n  \"BSL-1.0\",\n  \"bzip2-1.0.6\",\n  \"CC0-1.0\",\n  \"CDLA-Permissive-2.0\",\n  \"ISC\",\n  \"MIT\",\n  \"MPL-2.0\",\n  \"OpenSSL\",\n  \"Unicode-3.0\",\n  \"Zlib\",\n]\n# The confidence threshold for detecting a license from license text.\n# The higher the value, the more closely the license text must be to the\n# canonical license text of a valid SPDX license file.\n# [possible values: any between 0.0 and 1.0].\nconfidence-threshold = 0.8\n# Allow 1 or more licenses on a per-crate basis, so that particular licenses\n# aren't accepted for every possible crate as with the normal allow list\nexceptions = [\n  # Each entry is the crate and version constraint, and its specific allow\n  # list\n  #{ allow = [\"Zlib\"], crate = \"adler32\" },\n]\n\n# Some crates don't have (easily) machine readable licensing information,\n# adding a clarification entry for it allows you to manually specify the\n# licensing information\n[[licenses.clarify]]\n# The package spec the clarification applies to\ncrate = \"ring\"\n# The SPDX expression for the license requirements of the crate\nexpression = \"MIT AND ISC AND OpenSSL\"\n# One or more files in the crate's source used as the \"source of truth\" for\n# the license expression. If the contents match, the clarification will be used\n# when running the license check, otherwise the clarification will be ignored\n# and the crate will be checked normally, which may produce warnings or errors\n# depending on the rest of your configuration\nlicense-files = [\n  # Each entry is a crate relative path, and the (opaque) hash of its contents\n  { path = \"LICENSE\", hash = 0xbd0eed23 },\n]\n\n[licenses.private]\n# If true, ignores workspace crates that aren't published, or are only\n# published to private registries.\n# To see how to mark a crate as unpublished (to the official registry),\n# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.\nignore = false\n# One or more private registries that you might publish crates to, if a crate\n# is only published to private registries, and ignore is true, the crate will\n# not have its license(s) checked\nregistries = [\n  #\"https://sekretz.com/registry\n]\n\n# This section is considered when running `cargo deny check bans`.\n# More documentation about the 'bans' section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html\n[bans]\n# Lint level for when multiple versions of the same crate are detected\nmultiple-versions = \"allow\"\n# Lint level for when a crate version requirement is `*`\nwildcards = \"allow\"\n# The graph highlighting used when creating dotgraphs for crates\n# with multiple versions\n# * lowest-version - The path to the lowest versioned duplicate is highlighted\n# * simplest-path - The path to the version with the fewest edges is highlighted\n# * all - Both lowest-version and simplest-path are used\nhighlight = \"all\"\n# The default lint level for `default` features for crates that are members of\n# the workspace that is being checked. This can be overridden by allowing/denying\n# `default` on a crate-by-crate basis if desired.\nworkspace-default-features = \"allow\"\n# The default lint level for `default` features for external crates that are not\n# members of the workspace. This can be overridden by allowing/denying `default`\n# on a crate-by-crate basis if desired.\nexternal-default-features = \"allow\"\n# List of crates that are allowed. Use with care!\nallow = [\n  #\"ansi_term@0.11.0\",\n  #{ crate = \"ansi_term@0.11.0\", reason = \"you can specify a reason it is allowed\" },\n]\n# List of crates to deny\ndeny = [\n  #\"ansi_term@0.11.0\",\n  #{ crate = \"ansi_term@0.11.0\", reason = \"you can specify a reason it is banned\" },\n  # Wrapper crates can optionally be specified to allow the crate when it\n  # is a direct dependency of the otherwise banned crate\n  #{ crate = \"ansi_term@0.11.0\", wrappers = [\"this-crate-directly-depends-on-ansi_term\"] },\n]\n\n# List of features to allow/deny\n# Each entry the name of a crate and a version range. If version is\n# not specified, all versions will be matched.\n#[[bans.features]]\n#crate = \"reqwest\"\n# Features to not allow\n#deny = [\"json\"]\n# Features to allow\n#allow = [\n#    \"rustls\",\n#    \"__rustls\",\n#    \"__tls\",\n#    \"hyper-rustls\",\n#    \"rustls\",\n#    \"rustls-pemfile\",\n#    \"rustls-tls-webpki-roots\",\n#    \"tokio-rustls\",\n#    \"webpki-roots\",\n#]\n# If true, the allowed features must exactly match the enabled feature set. If\n# this is set there is no point setting `deny`\n#exact = true\n\n# Certain crates/versions that will be skipped when doing duplicate detection.\nskip = [\n  #\"ansi_term@0.11.0\",\n  #{ crate = \"ansi_term@0.11.0\", reason = \"you can specify a reason why it can't be updated/removed\" },\n]\n# Similarly to `skip` allows you to skip certain crates during duplicate\n# detection. Unlike skip, it also includes the entire tree of transitive\n# dependencies starting at the specified crate, up to a certain depth, which is\n# by default infinite.\nskip-tree = [\n  #\"ansi_term@0.11.0\", # will be skipped along with _all_ of its direct and transitive dependencies\n  #{ crate = \"ansi_term@0.11.0\", depth = 20 },\n]\n\n# This section is considered when running `cargo deny check sources`.\n# More documentation about the 'sources' section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html\n[sources]\n# Lint level for what to happen when a crate from a crate registry that is not\n# in the allow list is encountered\nunknown-registry = \"warn\"\n# Lint level for what to happen when a crate from a git repository that is not\n# in the allow list is encountered\nunknown-git = \"warn\"\n# List of URLs for allowed crate registries. Defaults to the crates.io index\n# if not specified. If it is specified but empty, no registries are allowed.\nallow-registry = [\"https://github.com/rust-lang/crates.io-index\"]\n# List of URLs for allowed Git repositories\nallow-git = []\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### macOS Patch ###\n# iCloud generated files\n*.icloud\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n### Node Patch ###\n# Serverless Webpack directories\n.webpack/\n\n# Optional stylelint cache\n\n# SvelteKit build / generate output\n.svelte-kit\n\n# VitePress\n.vitepress/cache\n.vitepress/dist\n"
  },
  {
    "path": "docs/.mise.toml",
    "content": "tasks.dev = \"bun run docs:dev\"\ntasks.build = \"bun run docs:build\"\n\n[tasks.\"commit-and-push\"]\ndepends = [\"build\"]\nrun = [\"git ci -pm docs\", \"git push\"]\n\n[tools]\nbun = 'latest'\n"
  },
  {
    "path": "docs/.vitepress/cli_commands.ts",
    "content": "// This file is generated by `mise render-help`\n// Do not edit this file directly\n\nexport type Command = {\n  hide: boolean;\n  subcommands?: {\n    [key: string]: Command;\n  };\n};\nexport const commands: { [key: string]: Command } = {\n  activate: {\n    hide: false,\n  },\n  asdf: {\n    hide: true,\n  },\n  backends: {\n    hide: false,\n    subcommands: {\n      ls: {\n        hide: false,\n      },\n    },\n  },\n  \"bin-paths\": {\n    hide: false,\n  },\n  cache: {\n    hide: false,\n    subcommands: {\n      clear: {\n        hide: false,\n      },\n      path: {\n        hide: false,\n      },\n      prune: {\n        hide: false,\n      },\n    },\n  },\n  completion: {\n    hide: false,\n  },\n  config: {\n    hide: false,\n    subcommands: {\n      get: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      set: {\n        hide: false,\n      },\n    },\n  },\n  current: {\n    hide: true,\n  },\n  deactivate: {\n    hide: false,\n  },\n  direnv: {\n    hide: true,\n    subcommands: {\n      activate: {\n        hide: true,\n      },\n      envrc: {\n        hide: true,\n      },\n      exec: {\n        hide: true,\n      },\n    },\n  },\n  doctor: {\n    hide: false,\n    subcommands: {\n      path: {\n        hide: false,\n      },\n    },\n  },\n  edit: {\n    hide: false,\n  },\n  en: {\n    hide: false,\n  },\n  env: {\n    hide: false,\n  },\n  exec: {\n    hide: false,\n  },\n  fmt: {\n    hide: false,\n  },\n  generate: {\n    hide: false,\n    subcommands: {\n      bootstrap: {\n        hide: false,\n      },\n      config: {\n        hide: false,\n      },\n      devcontainer: {\n        hide: false,\n      },\n      \"git-pre-commit\": {\n        hide: false,\n      },\n      \"github-action\": {\n        hide: false,\n      },\n      \"task-docs\": {\n        hide: false,\n      },\n      \"task-stubs\": {\n        hide: false,\n      },\n      \"tool-stub\": {\n        hide: false,\n      },\n    },\n  },\n  global: {\n    hide: true,\n  },\n  \"hook-env\": {\n    hide: true,\n  },\n  \"hook-not-found\": {\n    hide: true,\n  },\n  implode: {\n    hide: false,\n  },\n  install: {\n    hide: false,\n  },\n  \"install-into\": {\n    hide: false,\n  },\n  latest: {\n    hide: false,\n  },\n  link: {\n    hide: false,\n  },\n  local: {\n    hide: true,\n  },\n  lock: {\n    hide: false,\n  },\n  ls: {\n    hide: false,\n  },\n  \"ls-remote\": {\n    hide: false,\n  },\n  mcp: {\n    hide: false,\n  },\n  outdated: {\n    hide: false,\n  },\n  plugins: {\n    hide: false,\n    subcommands: {\n      install: {\n        hide: false,\n      },\n      link: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      \"ls-remote\": {\n        hide: false,\n      },\n      uninstall: {\n        hide: false,\n      },\n      update: {\n        hide: false,\n      },\n    },\n  },\n  prepare: {\n    hide: false,\n  },\n  prune: {\n    hide: false,\n  },\n  registry: {\n    hide: false,\n  },\n  \"render-help\": {\n    hide: true,\n  },\n  reshim: {\n    hide: false,\n  },\n  run: {\n    hide: false,\n  },\n  search: {\n    hide: false,\n  },\n  \"self-update\": {\n    hide: false,\n  },\n  set: {\n    hide: false,\n  },\n  settings: {\n    hide: false,\n    subcommands: {\n      add: {\n        hide: false,\n      },\n      get: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      set: {\n        hide: false,\n      },\n      unset: {\n        hide: false,\n      },\n    },\n  },\n  shell: {\n    hide: false,\n  },\n  \"shell-alias\": {\n    hide: false,\n    subcommands: {\n      get: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      set: {\n        hide: false,\n      },\n      unset: {\n        hide: false,\n      },\n    },\n  },\n  sync: {\n    hide: false,\n    subcommands: {\n      node: {\n        hide: false,\n      },\n      python: {\n        hide: false,\n      },\n      ruby: {\n        hide: false,\n      },\n    },\n  },\n  tasks: {\n    hide: false,\n    subcommands: {\n      add: {\n        hide: false,\n      },\n      deps: {\n        hide: false,\n      },\n      edit: {\n        hide: false,\n      },\n      info: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      run: {\n        hide: false,\n      },\n      validate: {\n        hide: false,\n      },\n    },\n  },\n  \"test-tool\": {\n    hide: false,\n  },\n  tool: {\n    hide: false,\n  },\n  \"tool-alias\": {\n    hide: false,\n    subcommands: {\n      get: {\n        hide: false,\n      },\n      ls: {\n        hide: false,\n      },\n      set: {\n        hide: false,\n      },\n      unset: {\n        hide: false,\n      },\n    },\n  },\n  \"tool-stub\": {\n    hide: false,\n  },\n  trust: {\n    hide: false,\n  },\n  uninstall: {\n    hide: false,\n  },\n  unset: {\n    hide: false,\n  },\n  unuse: {\n    hide: false,\n  },\n  upgrade: {\n    hide: false,\n  },\n  usage: {\n    hide: true,\n  },\n  use: {\n    hide: false,\n  },\n  version: {\n    hide: false,\n  },\n  watch: {\n    hide: false,\n  },\n  where: {\n    hide: false,\n  },\n  which: {\n    hide: false,\n  },\n};\n"
  },
  {
    "path": "docs/.vitepress/config.ts",
    "content": "import { defineConfig } from \"vitepress\";\nimport { Command, commands } from \"./cli_commands\";\nimport {\n  groupIconMdPlugin,\n  groupIconVitePlugin,\n} from \"vitepress-plugin-group-icons\";\nimport { tabsMarkdownPlugin } from \"vitepress-plugin-tabs\";\nimport { withMermaid } from \"vitepress-plugin-mermaid\";\nimport kdlGrammar from \"./grammars/kdl.tmLanguage.json\";\nimport miseTomlGrammar from \"./grammars/mise-toml.tmLanguage.json\";\n\n// https://vitepress.dev/reference/site-config\nexport default withMermaid(\n  defineConfig({\n    title: \"mise-en-place\",\n    description: \"mise-en-place documentation\",\n    lang: \"en-US\",\n    lastUpdated: true,\n    appearance: true,\n    mermaid: {},\n    sitemap: {\n      hostname: \"https://mise.jdx.dev\",\n    },\n    themeConfig: {\n      // https://vitepress.dev/reference/default-theme-config\n      logo: { light: \"/logo-light.svg\", dark: \"/logo-dark.svg\" },\n      outline: \"deep\",\n      nav: [\n        { text: \"mise-versions\", link: \"https://mise-versions.jdx.dev/\" },\n        { text: \"Dev Tools\", link: \"/dev-tools/\" },\n        { text: \"Environments\", link: \"/environments/\" },\n        { text: \"Tasks\", link: \"/tasks/\" },\n      ],\n      sidebar: [\n        {\n          text: \"Guides\",\n          items: [\n            { text: \"Demo\", link: \"/demo\" },\n            { text: \"Getting Started\", link: \"/getting-started\" },\n            { text: \"Walkthrough\", link: \"/walkthrough\" },\n            { text: \"Installing mise\", link: \"/installing-mise\" },\n            { text: \"IDE Integration\", link: \"/ide-integration\" },\n            { text: \"Continuous Integration\", link: \"/continuous-integration\" },\n          ],\n        },\n        {\n          text: \"Configuration\",\n          items: [\n            { text: \"mise.toml\", link: \"/configuration\" },\n            { text: \"Settings\", link: \"/configuration/settings\" },\n            {\n              text: \"Configuration Environments\",\n              link: \"/configuration/environments\",\n            },\n          ],\n        },\n        {\n          text: \"Dev Tools\",\n          items: [\n            { text: \"Dev Tools Overview\", link: \"/dev-tools/\" },\n            {\n              text: \"Comparison to asdf\",\n              link: \"/dev-tools/comparison-to-asdf\",\n            },\n            { text: \"Shims\", link: \"/dev-tools/shims\" },\n            { text: \"Tool Aliases\", link: \"/dev-tools/aliases\" },\n            { text: \"Tool Stubs\", link: \"/dev-tools/tool-stubs\" },\n            { text: \"Registry\", link: \"/registry\" },\n            { text: \"mise.lock Lockfile\", link: \"/dev-tools/mise-lock\" },\n            { text: \"Prepare\", link: \"/dev-tools/prepare\" },\n            {\n              text: \"Backend Architecture\",\n              link: \"/dev-tools/backend_architecture\",\n            },\n            {\n              text: \"Core tools\",\n              link: \"/core-tools\",\n              collapsed: true,\n              items: [\n                { text: \"Bun\", link: \"/lang/bun\" },\n                { text: \"Deno\", link: \"/lang/deno\" },\n                { text: \"Elixir\", link: \"/lang/elixir\" },\n                { text: \"Erlang\", link: \"/lang/erlang\" },\n                { text: \"Go\", link: \"/lang/go\" },\n                { text: \"Java\", link: \"/lang/java\" },\n                { text: \"Node.js\", link: \"/lang/node\" },\n                { text: \"Python\", link: \"/lang/python\" },\n                { text: \"Ruby\", link: \"/lang/ruby\" },\n                { text: \"Rust\", link: \"/lang/rust\" },\n                { text: \"Swift\", link: \"/lang/swift\" },\n                { text: \"Zig\", link: \"/lang/zig\" },\n              ],\n            },\n            {\n              text: \"Backends\",\n              link: \"/dev-tools/backends/\",\n              collapsed: true,\n              items: [\n                { text: \"aqua\", link: \"/dev-tools/backends/aqua\" },\n                { text: \"asdf\", link: \"/dev-tools/backends/asdf\" },\n                { text: \"cargo\", link: \"/dev-tools/backends/cargo\" },\n                { text: \"conda\", link: \"/dev-tools/backends/conda\" },\n                { text: \"dotnet\", link: \"/dev-tools/backends/dotnet\" },\n                { text: \"forgejo\", link: \"/dev-tools/backends/forgejo\" },\n                { text: \"gem\", link: \"/dev-tools/backends/gem\" },\n                { text: \"github\", link: \"/dev-tools/backends/github\" },\n                { text: \"gitlab\", link: \"/dev-tools/backends/gitlab\" },\n                { text: \"go\", link: \"/dev-tools/backends/go\" },\n                { text: \"http\", link: \"/dev-tools/backends/http\" },\n                { text: \"npm\", link: \"/dev-tools/backends/npm\" },\n                { text: \"pipx\", link: \"/dev-tools/backends/pipx\" },\n                { text: \"spm\", link: \"/dev-tools/backends/spm\" },\n                { text: \"ubi\", link: \"/dev-tools/backends/ubi\" },\n                { text: \"vfox\", link: \"/dev-tools/backends/vfox\" },\n              ],\n            },\n          ],\n        },\n        {\n          text: \"Environments\",\n          items: [\n            { text: \"Environment Variables\", link: \"/environments/\" },\n            { text: \"Shell Aliases\", link: \"/shell-aliases\" },\n            {\n              text: \"Secrets\",\n              link: \"/environments/secrets/\",\n              collapsed: true,\n              items: [\n                { text: \"sops\", link: \"/environments/secrets/sops\" },\n                { text: \"age\", link: \"/environments/secrets/age\" },\n              ],\n            },\n            { text: \"Hooks\", link: \"/hooks\" },\n            { text: \"direnv\", link: \"/direnv\" },\n          ],\n        },\n        {\n          text: \"Tasks\",\n          items: [\n            { text: \"Task Overview\", link: \"/tasks/\" },\n            { text: \"Task Architecture\", link: \"/tasks/architecture\" },\n            { text: \"Running Tasks\", link: \"/tasks/running-tasks\" },\n            { text: \"TOML Tasks\", link: \"/tasks/toml-tasks\" },\n            { text: \"File Tasks\", link: \"/tasks/file-tasks\" },\n            { text: \"Task Arguments\", link: \"/tasks/task-arguments\" },\n            { text: \"Task Configuration\", link: \"/tasks/task-configuration\" },\n            { text: \"Task Templates\", link: \"/tasks/templates\" },\n            { text: \"Monorepo Tasks\", link: \"/tasks/monorepo\" },\n          ],\n        },\n        {\n          text: \"Plugins\",\n          items: [\n            { text: \"Plugin Overview\", link: \"/plugins\" },\n            { text: \"Using Plugins\", link: \"/plugin-usage\" },\n            {\n              text: \"Backend Plugin Development\",\n              link: \"/backend-plugin-development\",\n            },\n            {\n              text: \"Tool Plugin Development\",\n              link: \"/tool-plugin-development\",\n            },\n            {\n              text: \"Environment Plugin Development\",\n              link: \"/env-plugin-development\",\n            },\n            { text: \"Plugin Lua Modules\", link: \"/plugin-lua-modules\" },\n            { text: \"Plugin Publishing\", link: \"/plugin-publishing\" },\n            { text: \"asdf (Legacy) Plugins\", link: \"/asdf-legacy-plugins\" },\n          ],\n        },\n        {\n          text: \"About\",\n          items: [\n            { text: \"About mise\", link: \"/about\" },\n            { text: \"Glossary\", link: \"/glossary\" },\n            { text: \"FAQs\", link: \"/faq\" },\n            { text: \"Troubleshooting\", link: \"/troubleshooting\" },\n            { text: \"Tips & Tricks\", link: \"/tips-and-tricks\" },\n            {\n              text: \"Cookbook\",\n              link: \"/mise-cookbook/\",\n              collapsed: true,\n              items: [\n                { text: \"C++\", link: \"/mise-cookbook/cpp\" },\n                { text: \"Docker\", link: \"/mise-cookbook/docker\" },\n                { text: \"Node\", link: \"/mise-cookbook/nodejs\" },\n                { text: \"Ruby\", link: \"/mise-cookbook/ruby\" },\n                { text: \"Terraform\", link: \"/mise-cookbook/terraform\" },\n                { text: \"Python\", link: \"/mise-cookbook/python\" },\n                { text: \"Presets\", link: \"/mise-cookbook/presets\" },\n                { text: \"Shell tricks\", link: \"/mise-cookbook/shell-tricks\" },\n              ],\n            },\n            { text: \"Team\", link: \"/team\" },\n            { text: \"Contributing\", link: \"/contributing\" },\n            { text: \"External Resources\", link: \"/external-resources\" },\n          ],\n        },\n        {\n          text: \"Advanced\",\n          items: [\n            { text: \"Architecture\", link: \"/architecture\" },\n            { text: \"Paranoid\", link: \"/paranoid\" },\n            { text: \"Templates\", link: \"/templates\" },\n            { text: \"URL Replacements\", link: \"/url-replacements\" },\n            { text: \"Model Context Protocol\", link: \"/mcp\" },\n            { text: \"How I Use mise\", link: \"/how-i-use-mise\" },\n            { text: \"Directory Structure\", link: \"/directories\" },\n            { text: \"Cache Behavior\", link: \"/cache-behavior\" },\n          ],\n        },\n        {\n          text: \"CLI Reference\",\n          collapsed: true,\n          items: [\n            { text: \"CLI Overview\", link: \"/cli/\" },\n            ...cliReference(commands),\n          ],\n        },\n      ],\n\n      socialLinks: [\n        { icon: \"github\", link: \"https://github.com/jdx/mise\" },\n        { icon: \"discord\", link: \"https://discord.gg/UBa7pJUN7Z\" },\n      ],\n\n      editLink: {\n        pattern: \"https://github.com/jdx/mise/edit/main/docs/:path\",\n      },\n      search: {\n        provider: \"algolia\",\n        options: {\n          indexName: \"rtx\",\n          appId: \"1452G4RPSJ\",\n          apiKey: \"ad09b96a7d2a30eddc2771800da7a1cf\",\n          insights: true,\n        },\n      },\n      footer: {\n        message:\n          'Licensed under the MIT License. Maintained by <a href=\"https://github.com/jdx\">@jdx</a> and <a href=\"https://github.com/jdx/mise/graphs/contributors\">friends</a>.',\n        copyright: `Copyright © ${new Date().getFullYear()} <a href=\"https://github.com/jdx\">@jdx</a>`,\n      },\n      carbonAds: {\n        code: \"CWYIPKQN\",\n        placement: \"misejdxdev\",\n      },\n    },\n    markdown: {\n      languages: [\n        // Load base languages needed for embedded support\n        \"toml\",\n        \"shell\",\n        \"bash\",\n        // TODO: Once Shiki bundles KDL (tracked in shikijs/textmate-grammars-themes),\n        // we can import it from 'shiki/langs/kdl' instead of storing locally\n        {\n          ...kdlGrammar,\n          name: \"kdl\",\n          scopeName: \"source.kdl\",\n        } as any,\n        // Custom mise.toml grammar with embedded KDL (usage fields) and bash (run fields)\n        {\n          ...miseTomlGrammar,\n          name: \"mise-toml\",\n          aliases: [\"mise.toml\"],\n          scopeName: \"source.mise-toml\",\n        } as any,\n      ],\n      config(md) {\n        md.use(groupIconMdPlugin);\n        md.use(tabsMarkdownPlugin);\n      },\n    },\n    vite: {\n      plugins: [\n        groupIconVitePlugin({\n          customIcon: {\n            \".toml\": \"vscode-icons:file-type-toml\",\n            brew: \"logos:homebrew\",\n            python: \"logos:python\",\n            node: \"logos:nodejs\",\n            ruby: \"logos:ruby\",\n          },\n        }),\n      ],\n    },\n    head: [\n      // Favicon\n      [\"link\", { rel: \"icon\", href: \"/favicon.ico\", sizes: \"any\" }],\n      [\n        \"link\",\n        {\n          rel: \"icon\",\n          href: \"/favicon-16x16.png\",\n          type: \"image/png\",\n          sizes: \"16x16\",\n        },\n      ],\n      [\n        \"link\",\n        {\n          rel: \"icon\",\n          href: \"/favicon-32x32.png\",\n          type: \"image/png\",\n          sizes: \"32x32\",\n        },\n      ],\n      [\"link\", { rel: \"icon\", href: \"/logo.svg\", type: \"image/svg+xml\" }],\n      [\n        \"link\",\n        {\n          rel: \"apple-touch-icon\",\n          href: \"/apple-touch-icon.png\",\n          sizes: \"180x180\",\n        },\n      ],\n      // Google Fonts\n      [\n        \"link\",\n        {\n          rel: \"preconnect\",\n          href: \"https://fonts.googleapis.com\",\n        },\n      ],\n      [\n        \"link\",\n        {\n          rel: \"preconnect\",\n          href: \"https://fonts.gstatic.com\",\n          crossorigin: \"\",\n        },\n      ],\n      [\n        \"link\",\n        {\n          href: \"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=JetBrains+Mono:wght@400;500;600;700&display=swap\",\n          rel: \"stylesheet\",\n        },\n      ],\n      // Analytics\n      [\n        \"script\",\n        {\n          async: \"\",\n          src: \"https://www.googletagmanager.com/gtag/js?id=G-B69G389C8T\",\n        },\n      ],\n      [\n        \"script\",\n        {},\n        `window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n      gtag('config', 'G-B69G389C8T');`,\n      ],\n      [\n        \"script\",\n        {\n          \"data-goatcounter\": \"https://jdx.goatcounter.com/count\",\n          async: \"\",\n          src: \"//gc.zgo.at/count.js\",\n        },\n      ],\n      // OpenGraph\n      [\"meta\", { property: \"og:site_name\", content: \"mise-en-place\" }],\n      [\"meta\", { property: \"og:type\", content: \"website\" }],\n      [\n        \"meta\",\n        {\n          property: \"og:image\",\n          content: \"https://mise.jdx.dev/android-chrome-512x512.png\",\n        },\n      ],\n      [\"meta\", { name: \"twitter:card\", content: \"summary\" }],\n      [\n        \"meta\",\n        {\n          name: \"twitter:image\",\n          content: \"https://mise.jdx.dev/android-chrome-512x512.png\",\n        },\n      ],\n    ],\n    transformPageData(pageData) {\n      const canonicalUrl = `https://mise.jdx.dev/${pageData.relativePath}`\n        .replace(/index\\.md$/, \"\")\n        .replace(/\\.md$/, \".html\");\n\n      pageData.frontmatter.head ??= [];\n      pageData.frontmatter.head.push([\n        \"link\",\n        { rel: \"canonical\", href: canonicalUrl },\n      ]);\n      pageData.frontmatter.head.push([\n        \"link\",\n        {\n          rel: \"sitemap\",\n          href: \"https://mise.jdx.dev/sitemap.xml\",\n          type: \"application/xml\",\n          title: \"Sitemap\",\n        },\n      ]);\n    },\n  }),\n);\n\nfunction cliReference(commands: { [key: string]: Command }) {\n  return Object.keys(commands)\n    .map((name) => [name, commands[name]] as [string, Command])\n    .filter(([_name, command]) => command.hide !== true)\n    .map(([name, command]) => {\n      const x: any = {\n        text: `mise ${name}`,\n        link: `/cli/${name}`,\n      };\n      if (command.subcommands) {\n        x.collapsed = true;\n        x.items = Object.keys(command.subcommands)\n          .filter(\n            (subcommand) => command.subcommands![subcommand].hide !== true,\n          )\n          .map((subcommand) => ({\n            text: `mise ${name} ${subcommand}`,\n            link: `/cli/${name}/${subcommand}`,\n          }));\n      }\n      return x;\n    });\n}\n"
  },
  {
    "path": "docs/.vitepress/grammars/kdl.tmLanguage.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json\",\n  \"comment\": \"Some of these patterns are taken straight from rust-analyzer: https://github.com/rust-lang/vscode-rust/blob/master/rust-analyzer/editors/code/rust.tmGrammar.json. Some was also taken from https://github.com/arm32x/vscode-sdlang/blob/master/syntaxes/sdlang.tmLanguage.json\",\n  \"name\": \"kdl\",\n  \"patterns\": [\n    {\n      \"include\": \"#forbidden_ident\"\n    },\n    {\n      \"include\": \"#null\"\n    },\n    {\n      \"include\": \"#boolean\"\n    },\n    {\n      \"include\": \"#float_keyword\"\n    },\n    {\n      \"include\": \"#float_fraction\"\n    },\n    {\n      \"include\": \"#float_exp\"\n    },\n    {\n      \"include\": \"#decimal\"\n    },\n    {\n      \"include\": \"#hexadecimal\"\n    },\n    {\n      \"include\": \"#octal\"\n    },\n    {\n      \"include\": \"#binary\"\n    },\n    {\n      \"include\": \"#raw-string\"\n    },\n    {\n      \"include\": \"#string_multi_line\"\n    },\n    {\n      \"include\": \"#string_single_line\"\n    },\n    {\n      \"include\": \"#block_comment\"\n    },\n    {\n      \"include\": \"#block_doc_comment\"\n    },\n    {\n      \"include\": \"#slashdash_block_comment\"\n    },\n    {\n      \"include\": \"#slashdash_comment\"\n    },\n    {\n      \"include\": \"#slashdash_node_comment\"\n    },\n    {\n      \"include\": \"#slashdash_node_with_children_comment\"\n    },\n    {\n      \"include\": \"#line_comment\"\n    },\n    {\n      \"include\": \"#attribute\"\n    },\n    {\n      \"include\": \"#node_name\"\n    },\n    {\n      \"include\": \"#ident_string\"\n    }\n  ],\n  \"repository\": {\n    \"float_fraction\": {\n      \"comment\": \"Floating point literal (fraction)\",\n      \"name\": \"constant.numeric.float.rust\",\n      \"match\": \"\\\\b([0-9\\\\-\\\\+]|\\\\-|\\\\+)[0-9_]*\\\\.[0-9][0-9_]*([eE][+-]?[0-9_]+)?\\\\b\"\n    },\n    \"float_exp\": {\n      \"comment\": \"Floating point literal (exponent)\",\n      \"name\": \"constant.numeric.float.rust\",\n      \"match\": \"\\\\b[0-9][0-9_]*(\\\\.[0-9][0-9_]*)?[eE][+-]?[0-9_]+\\\\b\"\n    },\n    \"decimal\": {\n      \"comment\": \"Integer literal (decimal)\",\n      \"name\": \"constant.numeric.integer.decimal.rust\",\n      \"match\": \"\\\\b[0-9\\\\-\\\\+][0-9_]*\\\\b\"\n    },\n    \"hexadecimal\": {\n      \"comment\": \"Integer literal (hexadecimal)\",\n      \"name\": \"constant.numeric.integer.hexadecimal.rust\",\n      \"match\": \"\\\\b0x[a-fA-F0-9][a-fA-F0-9_]*\\\\b\"\n    },\n    \"octal\": {\n      \"comment\": \"Integer literal (octal)\",\n      \"name\": \"constant.numeric.integer.octal.rust\",\n      \"match\": \"\\\\b0o[0-7][0-7_]*\\\\b\"\n    },\n    \"binary\": {\n      \"comment\": \"Integer literal (binary)\",\n      \"name\": \"constant.numeric.integer.binary.rust\",\n      \"match\": \"\\\\b0b[01][01_]*\\\\b\"\n    },\n    \"forbidden_ident\": {\n      \"name\": \"invalid.illegal.kdl.bad-ident\",\n      \"match\": \"(?<!#)(?:true|false|null|nan|[-]?inf)\"\n    },\n    \"node_name\": {\n      \"name\": \"entity.name.tag\",\n      \"match\": \"((?<={|;)|^)\\\\s*(?![/\\\\\\\\{\\\\}#;\\\\[\\\\]\\\\=])[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]+\\\\d*[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]*\"\n    },\n    \"attribute\": {\n      \"name\": \"entity.other.attribute-name.kdl\",\n      \"match\": \"(?![/\\\\\\\\{\\\\}#;\\\\[\\\\]\\\\=])[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]+\\\\d*[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]*(=)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.separator.key-value.kdl\"\n        }\n      }\n    },\n    \"ident_string\": {\n      \"name\": \"string.unquoted\",\n      \"match\": \"(?![/\\\\\\\\{\\\\}#;\\\\[\\\\]\\\\=])[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]+\\\\d*[<>:\\\\w\\\\-_~,'`!\\\\?@\\\\$%^&*+|.\\\\(\\\\)]*\"\n    },\n    \"float_keyword\": {\n      \"name\": \"constant.language.other.kdl\",\n      \"match\": \"#nan|#inf|#-inf\"\n    },\n    \"null\": {\n      \"name\": \"constant.language.null.kdl\",\n      \"match\": \"#null\"\n    },\n    \"boolean\": {\n      \"name\": \"constant.language.boolean.kdl\",\n      \"match\": \"#true|#false\"\n    },\n    \"string_single_line\": {\n      \"name\": \"string.quoted.double.kdl\",\n      \"begin\": \"\\\"\",\n      \"end\": \"\\\"\",\n      \"patterns\": [\n        {\n          \"name\": \"constant.character.escape.kdl\",\n          \"match\": \"\\\\\\\\(:?[nrtbfs\\\\\\\\\\\"]|u\\\\{[a-fA-F0-9]{1,6}\\\\})\"\n        }\n      ]\n    },\n    \"string_multi_line\": {\n      \"name\": \"string.quoted.triple.kdl\",\n      \"begin\": \"\\\"\\\"\\\"\",\n      \"end\": \"\\\"\\\"\\\"\",\n      \"patterns\": [\n        {\n          \"name\": \"constant.character.escape.kdl\",\n          \"match\": \"\\\\\\\\(:?[nrtbfs\\\\\\\\\\\"]|u\\\\{[a-fA-F0-9]{1,6}\\\\})\"\n        }\n      ]\n    },\n    \"raw-string\": {\n      \"name\": \"string.quoted.other.raw.kdl\",\n      \"begin\": \"(#+)(\\\"\\\"\\\"|\\\")\",\n      \"end\": \"\\\\2\\\\1\"\n    },\n    \"block_doc_comment\": {\n      \"comment\": \"Block documentation comment\",\n      \"name\": \"comment.block.documentation.kdl\",\n      \"begin\": \"/\\\\*[\\\\*!](?![\\\\*/])\",\n      \"end\": \"\\\\*/\",\n      \"patterns\": [\n        {\n          \"include\": \"#block_doc_comment\"\n        },\n        {\n          \"include\": \"#block_comment\"\n        }\n      ]\n    },\n    \"block_comment\": {\n      \"comment\": \"Block comment\",\n      \"name\": \"comment.block.kdl\",\n      \"begin\": \"/\\\\*\",\n      \"end\": \"\\\\*/\",\n      \"patterns\": [\n        {\n          \"include\": \"#block_doc_comment\"\n        },\n        {\n          \"include\": \"#block_comment\"\n        }\n      ]\n    },\n    \"line_comment\": {\n      \"comment\": \"Single-line comment\",\n      \"name\": \"comment.line.double-slash.kdl\",\n      \"begin\": \"//\",\n      \"end\": \"$\"\n    },\n    \"slashdash_comment\": {\n      \"name\": \"comment.block.slashdash.kdl\",\n      \"comment\": \"Slashdash inline comment\",\n      \"begin\": \"(?<!^)\\\\s*/-\\\\s*\",\n      \"end\": \"\\\\s\"\n    },\n    \"slashdash_node_comment\": {\n      \"name\": \"comment.block.slashdash.kdl\",\n      \"comment\": \"Slashdash node comment\",\n      \"begin\": \"(?<=^)\\\\s*/-[^{]+$\",\n      \"end\": \"(?:;|(?<!\\\\\\\\)$)\"\n    },\n    \"slashdash_node_with_children_comment\": {\n      \"name\": \"comment.block.slashdash.kdl\",\n      \"comment\": \"Slashdash node comment\",\n      \"begin\": \"(?<=^)\\\\s*/-[^{]+{\",\n      \"end\": \"\\\\}\"\n    },\n    \"slashdash_block_comment\": {\n      \"name\": \"comment.block.slashdash.kdl\",\n      \"comment\": \"Slashdash block comment\",\n      \"begin\": \"/-\\\\s*{\",\n      \"end\": \"\\\\}\"\n    }\n  },\n  \"scopeName\": \"source.kdl\"\n}\n"
  },
  {
    "path": "docs/.vitepress/grammars/mise-toml.tmLanguage.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json\",\n  \"name\": \"mise.toml\",\n  \"scopeName\": \"source.mise-toml\",\n  \"comment\": \"Custom TOML grammar for mise.toml with embedded KDL (in usage fields) and bash (in run fields)\",\n  \"patterns\": [\n    {\n      \"include\": \"#mise-task-section\"\n    },\n    {\n      \"include\": \"source.toml\"\n    }\n  ],\n  \"repository\": {\n    \"mise-task-section\": {\n      \"patterns\": [\n        {\n          \"include\": \"#usage-field-triple-double\"\n        },\n        {\n          \"include\": \"#usage-field-triple-single\"\n        },\n        {\n          \"include\": \"#run-field-triple-double\"\n        },\n        {\n          \"include\": \"#run-field-triple-single\"\n        }\n      ]\n    },\n    \"usage-field-triple-double\": {\n      \"name\": \"meta.embedded.block.kdl.mise-toml\",\n      \"begin\": \"\\\\b(usage)\\\\s*=\\\\s*(\\\"\\\"\\\")\",\n      \"beginCaptures\": {\n        \"2\": {\n          \"name\": \"punctuation.definition.string.begin.toml\"\n        }\n      },\n      \"end\": \"\\\"\\\"\\\"\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.toml\"\n        }\n      },\n      \"contentName\": \"source.kdl.embedded.toml\",\n      \"patterns\": [\n        {\n          \"include\": \"source.kdl\"\n        }\n      ]\n    },\n    \"usage-field-triple-single\": {\n      \"name\": \"meta.embedded.block.kdl.mise-toml\",\n      \"begin\": \"\\\\b(usage)\\\\s*=\\\\s*(''')\",\n      \"beginCaptures\": {\n        \"2\": {\n          \"name\": \"punctuation.definition.string.begin.toml\"\n        }\n      },\n      \"end\": \"'''\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.toml\"\n        }\n      },\n      \"contentName\": \"source.kdl.embedded.toml\",\n      \"patterns\": [\n        {\n          \"include\": \"source.kdl\"\n        }\n      ]\n    },\n    \"run-field-triple-double\": {\n      \"name\": \"meta.embedded.block.shell.mise-toml\",\n      \"begin\": \"\\\\b(run|run_windows|run_macos|run_linux)\\\\s*=\\\\s*(\\\"\\\"\\\")\",\n      \"beginCaptures\": {\n        \"2\": {\n          \"name\": \"punctuation.definition.string.begin.toml\"\n        }\n      },\n      \"end\": \"\\\"\\\"\\\"\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.toml\"\n        }\n      },\n      \"contentName\": \"source.shell.embedded.toml\",\n      \"patterns\": [\n        {\n          \"include\": \"source.shell\"\n        }\n      ]\n    },\n    \"run-field-triple-single\": {\n      \"name\": \"meta.embedded.block.shell.mise-toml\",\n      \"begin\": \"\\\\b(run|run_windows|run_macos|run_linux)\\\\s*=\\\\s*(''')\",\n      \"beginCaptures\": {\n        \"2\": {\n          \"name\": \"punctuation.definition.string.begin.toml\"\n        }\n      },\n      \"end\": \"'''\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.toml\"\n        }\n      },\n      \"contentName\": \"source.shell.embedded.toml\",\n      \"patterns\": [\n        {\n          \"include\": \"source.shell\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/stars.data.ts",
    "content": "// This file is auto-updated by xtasks/release-plz\n// Current star count from GitHub API\nexport default {\n  load() {\n    return {\n      stars: \"25.5k\",\n    };\n  },\n};\n"
  },
  {
    "path": "docs/.vitepress/theme/HomeHero.vue",
    "content": "<template>\n  <div class=\"custom-hero\">\n    <div class=\"hero-background\">\n      <div class=\"gradient-orb orb-1\"></div>\n      <div class=\"gradient-orb orb-2\"></div>\n      <div class=\"gradient-orb orb-3\"></div>\n    </div>\n    <div class=\"hero-content\">\n      <div class=\"hero-chef-logo\">\n        <img\n          class=\"chef-logo chef-logo-light\"\n          src=\"/logo-full-light.svg\"\n          alt=\"mise\"\n          width=\"280\"\n          height=\"136\"\n        />\n        <img\n          class=\"chef-logo chef-logo-dark\"\n          src=\"/logo-full-dark.svg\"\n          alt=\"mise\"\n          width=\"280\"\n          height=\"136\"\n        />\n      </div>\n      <div class=\"hero-logo\">\n        <div class=\"logo-subtitle\">en-place</div>\n      </div>\n      <p class=\"hero-tagline\">\n        The front-end to your dev env\n        <span class=\"pronunciation\">Pronounced \"MEEZ ahn plahs\"</span>\n      </p>\n      <div class=\"hero-actions\">\n        <a href=\"/getting-started\" class=\"action-button primary\">\n          <span class=\"button-content\">\n            <svg\n              class=\"button-icon\"\n              width=\"20\"\n              height=\"20\"\n              viewBox=\"0 0 24 24\"\n              fill=\"none\"\n              stroke=\"currentColor\"\n              stroke-width=\"2\"\n            >\n              <path d=\"M5 12h14M12 5l7 7-7 7\" />\n            </svg>\n            Getting Started\n          </span>\n        </a>\n        <a href=\"/demo\" class=\"action-button secondary\">\n          <span class=\"button-content\">\n            <svg\n              class=\"button-icon\"\n              width=\"20\"\n              height=\"20\"\n              viewBox=\"0 0 24 24\"\n              fill=\"none\"\n              stroke=\"currentColor\"\n              stroke-width=\"2\"\n            >\n              <polygon points=\"5 3 19 12 5 21 5 3\" />\n            </svg>\n            Watch Demo\n          </span>\n        </a>\n      </div>\n      <div class=\"hero-stats\">\n        <div class=\"stat\">\n          <div class=\"stat-value\">50+</div>\n          <div class=\"stat-label\">Languages</div>\n        </div>\n        <div class=\"stat\">\n          <div class=\"stat-value\">Fast</div>\n          <div class=\"stat-label\">Performance</div>\n        </div>\n        <div class=\"stat\">\n          <div class=\"stat-value\">Simple</div>\n          <div class=\"stat-label\">Configuration</div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.custom-hero {\n  position: relative;\n  padding: 64px 24px 96px;\n  overflow: hidden;\n  min-height: 600px;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.hero-background {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  overflow: hidden;\n}\n\n.gradient-orb {\n  position: absolute;\n  border-radius: 50%;\n  filter: blur(100px);\n  opacity: 0.35;\n  animation: float 20s infinite ease-in-out;\n}\n\n.orb-1 {\n  width: 600px;\n  height: 600px;\n  background: linear-gradient(135deg, #8B2252, #C75B7A);\n  top: -200px;\n  left: -100px;\n  animation-delay: 0s;\n}\n\n.orb-2 {\n  width: 500px;\n  height: 500px;\n  background: linear-gradient(135deg, #C5975B, #D4A76A);\n  bottom: -150px;\n  right: -150px;\n  animation-delay: 5s;\n}\n\n.orb-3 {\n  width: 400px;\n  height: 400px;\n  background: linear-gradient(135deg, #8FA86E, #6B7F4E);\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n  animation-delay: 10s;\n}\n\n@keyframes float {\n  0%,\n  100% {\n    transform: translate(0, 0) scale(1);\n  }\n  33% {\n    transform: translate(30px, -30px) scale(1.1);\n  }\n  66% {\n    transform: translate(-20px, 20px) scale(0.9);\n  }\n}\n\n.hero-content {\n  position: relative;\n  z-index: 1;\n  text-align: center;\n  max-width: 800px;\n  margin: 0 auto;\n}\n\n.hero-chef-logo {\n  margin-bottom: 16px;\n  animation: fadeInDown 0.8s ease-out;\n}\n\n.chef-logo {\n  max-width: 280px;\n  height: auto;\n}\n\n/* Show/hide based on color mode */\n.chef-logo-dark {\n  display: none;\n}\n\n.dark .chef-logo-light {\n  display: none;\n}\n\n.dark .chef-logo-dark {\n  display: inline;\n}\n\n.hero-logo {\n  margin-bottom: 24px;\n  animation: fadeInDown 0.8s ease-out 0.1s both;\n}\n\n.logo-subtitle {\n  font-size: clamp(1.5rem, 5vw, 2.5rem);\n  font-weight: 300;\n  color: var(--vp-c-text-2);\n  margin-top: -8px;\n  letter-spacing: 0.1em;\n  opacity: 0.8;\n}\n\n.hero-tagline {\n  font-size: clamp(1rem, 3vw, 1.35rem);\n  color: var(--vp-c-text-2);\n  margin-bottom: 32px;\n  line-height: 1.6;\n  animation: fadeInUp 0.8s ease-out 0.2s both;\n}\n\n.pronunciation {\n  display: block;\n  font-size: 0.85em;\n  color: var(--vp-c-text-3);\n  margin-top: 8px;\n  font-style: italic;\n}\n\n.hero-actions {\n  display: flex;\n  gap: 16px;\n  justify-content: center;\n  margin-bottom: 48px;\n  flex-wrap: wrap;\n  animation: fadeInUp 0.8s ease-out 0.4s both;\n}\n\n.action-button {\n  display: inline-flex;\n  align-items: center;\n  padding: 14px 28px;\n  border-radius: 12px;\n  font-weight: 600;\n  text-decoration: none;\n  transition: all 0.3s ease;\n  font-size: 1rem;\n  position: relative;\n  overflow: hidden;\n}\n\n.action-button::before {\n  content: \"\";\n  position: absolute;\n  top: 0;\n  left: -100%;\n  width: 100%;\n  height: 100%;\n  background: linear-gradient(\n    90deg,\n    transparent,\n    rgba(255, 255, 255, 0.2),\n    transparent\n  );\n  transition: left 0.5s;\n}\n\n.action-button:hover::before {\n  left: 100%;\n}\n\n.button-content {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  position: relative;\n  z-index: 1;\n}\n\n.button-icon {\n  transition: transform 0.3s ease;\n}\n\n.action-button:hover .button-icon {\n  transform: translateX(4px);\n}\n\n.action-button.primary {\n  background: linear-gradient(135deg, #8B2252, #722F37);\n  color: white;\n  box-shadow: 0 4px 20px rgba(139, 34, 82, 0.3);\n}\n\n.action-button.primary:hover {\n  transform: translateY(-2px);\n  box-shadow: 0 8px 30px rgba(139, 34, 82, 0.4);\n}\n\n.action-button.secondary {\n  background: var(--vp-c-bg-soft);\n  color: var(--vp-c-text-1);\n  border: 2px solid var(--vp-c-divider);\n}\n\n.action-button.secondary:hover {\n  background: var(--vp-c-bg-mute);\n  border-color: var(--vp-c-brand-1);\n  color: var(--vp-c-brand-1);\n  transform: translateY(-2px);\n}\n\n.hero-stats {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n  gap: 24px;\n  animation: fadeInUp 0.8s ease-out 0.6s both;\n}\n\n.stat {\n  padding: 20px;\n  background: var(--vp-c-bg-soft);\n  border-radius: 12px;\n  border: 1px solid var(--vp-c-divider);\n  transition: all 0.3s ease;\n}\n\n.stat:hover {\n  transform: translateY(-4px);\n  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);\n  border-color: var(--vp-c-brand-1);\n}\n\n.stat-value {\n  font-size: 1.75rem;\n  font-weight: 700;\n  background: linear-gradient(135deg, #8B2252, #C5975B);\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: transparent;\n  margin-bottom: 4px;\n}\n\n.stat-label {\n  font-size: 0.875rem;\n  color: var(--vp-c-text-3);\n  text-transform: uppercase;\n  letter-spacing: 0.05em;\n}\n\n@keyframes fadeInDown {\n  from {\n    opacity: 0;\n    transform: translateY(-20px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n@keyframes fadeInUp {\n  from {\n    opacity: 0;\n    transform: translateY(20px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n@media (max-width: 768px) {\n  .custom-hero {\n    padding: 48px 16px 64px;\n  }\n\n  .chef-logo {\n    max-width: 200px;\n  }\n\n  .hero-actions {\n    flex-direction: column;\n    align-items: center;\n  }\n\n  .action-button {\n    width: 100%;\n    max-width: 280px;\n    justify-content: center;\n  }\n\n  .gradient-orb {\n    filter: blur(80px);\n  }\n}\n\n/* Dark mode adjustments */\n.dark .stat {\n  background: rgba(255, 255, 255, 0.03);\n  border-color: rgba(255, 255, 255, 0.1);\n}\n\n.dark .stat:hover {\n  background: rgba(255, 255, 255, 0.05);\n}\n\n.dark .stat-value {\n  background: linear-gradient(135deg, #C75B7A, #D4A76A);\n  -webkit-background-clip: text;\n  background-clip: text;\n  -webkit-text-fill-color: transparent;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/theme/Layout.vue",
    "content": "<template>\n  <DefaultTheme.Layout>\n    <!-- Atmospheric background layer behind the entire hero -->\n    <template #home-hero-before>\n      <div class=\"hero-atmosphere\" aria-hidden=\"true\">\n        <div class=\"hero-glow hero-glow-1\"></div>\n        <div class=\"hero-glow hero-glow-2\"></div>\n        <div class=\"hero-glow hero-glow-3\"></div>\n        <div class=\"hero-grain\"></div>\n      </div>\n    </template>\n\n    <!-- Chef logo as the commanding centerpiece -->\n    <template #home-hero-info-before>\n      <div class=\"hero-chef-logo\">\n        <img\n          class=\"chef-logo chef-logo-light\"\n          src=\"/logo-full-light.svg\"\n          alt=\"mise-en-place\"\n        />\n        <img\n          class=\"chef-logo chef-logo-dark\"\n          src=\"/logo-full-dark.svg\"\n          alt=\"mise-en-place\"\n        />\n      </div>\n    </template>\n\n    <!-- Right column: install + action buttons -->\n    <template #home-hero-info-after>\n      <div class=\"hero-right\">\n        <div class=\"hero-install\">\n          <div class=\"install-label\">Install</div>\n          <div class=\"install-command\" @click=\"copyInstall\">\n            <code>curl https://mise.run | sh</code>\n            <span class=\"install-copy\" :class=\"{ copied }\">\n              {{ copied ? '✓' : '⎘' }}\n            </span>\n          </div>\n          <div class=\"install-alt\">\n            <a href=\"/installing-mise.html\">More install methods →</a>\n          </div>\n        </div>\n        <div class=\"hero-actions\">\n          <a class=\"action-btn action-btn-brand\" href=\"/getting-started.html\">Getting Started</a>\n          <a class=\"action-btn action-btn-alt\" href=\"/demo.html\">Demo</a>\n          <a class=\"action-btn action-btn-alt\" href=\"/about.html\">About</a>\n        </div>\n      </div>\n    </template>\n  </DefaultTheme.Layout>\n</template>\n\n<script setup lang=\"ts\">\nimport DefaultTheme from \"vitepress/theme\";\nimport { ref } from \"vue\";\n\nconst copied = ref(false);\n\nfunction copyInstall() {\n  navigator.clipboard.writeText(\"curl https://mise.run | sh\");\n  copied.value = true;\n  setTimeout(() => (copied.value = false), 2000);\n}\n</script>\n\n<style>\n/* ═══════════════════════════════════════════\n   HERO ATMOSPHERE — radial glows + grain\n   ═══════════════════════════════════════════ */\n.VPHero {\n  position: relative;\n  overflow: hidden;\n}\n\n.hero-atmosphere {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  z-index: 0;\n  overflow: clip;\n  contain: paint;\n}\n\n.hero-glow {\n  position: absolute;\n  border-radius: 50%;\n  filter: blur(80px);\n  opacity: 0.18;\n}\n\n.hero-glow-1 {\n  width: 600px;\n  height: 600px;\n  top: -200px;\n  left: -100px;\n  background: radial-gradient(circle, #8B2252 0%, transparent 70%);\n  animation: glowDrift1 12s ease-in-out infinite;\n}\n\n.hero-glow-2 {\n  width: 500px;\n  height: 500px;\n  top: -100px;\n  right: -80px;\n  background: radial-gradient(circle, #D4A76A 0%, transparent 70%);\n  animation: glowDrift2 15s ease-in-out infinite;\n}\n\n.hero-glow-3 {\n  width: 400px;\n  height: 400px;\n  bottom: -100px;\n  left: 30%;\n  background: radial-gradient(circle, #6B7F4E 0%, transparent 70%);\n  animation: glowDrift3 18s ease-in-out infinite;\n}\n\n/* Dark mode: brighter, moodier glows */\n.dark .hero-glow { opacity: 0.12; }\n.dark .hero-glow-1 {\n  background: radial-gradient(circle, #C75B7A 0%, transparent 70%);\n}\n.dark .hero-glow-2 {\n  background: radial-gradient(circle, #D4A76A 0%, transparent 70%);\n}\n.dark .hero-glow-3 {\n  background: radial-gradient(circle, #8FA86E 0%, transparent 70%);\n}\n\n/* Subtle film grain texture */\n.hero-grain {\n  position: absolute;\n  inset: 0;\n  opacity: 0.03;\n  background-image: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E\");\n  background-repeat: repeat;\n  background-size: 256px 256px;\n}\n\n.dark .hero-grain {\n  opacity: 0.04;\n}\n\n@keyframes glowDrift1 {\n  0%, 100% { transform: translate(0, 0) scale(1); }\n  50% { transform: translate(40px, 30px) scale(1.1); }\n}\n\n@keyframes glowDrift2 {\n  0%, 100% { transform: translate(0, 0) scale(1); }\n  50% { transform: translate(-30px, 40px) scale(1.15); }\n}\n\n@keyframes glowDrift3 {\n  0%, 100% { transform: translate(0, 0) scale(1); }\n  50% { transform: translate(20px, -30px) scale(1.05); }\n}\n\n/* ═══════════════════════════════════════════\n   CHEF LOGO — commanding centerpiece\n   ═══════════════════════════════════════════ */\n.hero-chef-logo {\n  display: flex;\n  justify-content: flex-start;\n  margin-bottom: 12px;\n}\n\n.hero-chef-logo .chef-logo {\n  width: 420px;\n  max-width: 90vw;\n  height: auto;\n  filter: drop-shadow(0 4px 20px rgba(139, 34, 82, 0.15));\n  transition: filter 0.4s ease;\n}\n\n.hero-chef-logo .chef-logo:hover {\n  filter: drop-shadow(0 8px 32px rgba(139, 34, 82, 0.25));\n}\n\n/* Light mode: show light (black) logo, hide dark */\n.hero-chef-logo .chef-logo-dark {\n  display: none;\n}\n\n/* Dark mode: swap logos */\n.dark .hero-chef-logo .chef-logo-light {\n  display: none;\n}\n\n.dark .hero-chef-logo .chef-logo-dark {\n  display: inline;\n}\n\n.dark .hero-chef-logo .chef-logo {\n  filter: drop-shadow(0 4px 24px rgba(199, 91, 122, 0.2));\n}\n\n.dark .hero-chef-logo .chef-logo:hover {\n  filter: drop-shadow(0 8px 40px rgba(199, 91, 122, 0.35));\n}\n\n@keyframes heroLogoIn {\n  from {\n    opacity: 0;\n    transform: translateY(-30px) scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0) scale(1);\n  }\n}\n\n/* ═══════════════════════════════════════════\n   INSTALL COMMAND — signature dish\n   ═══════════════════════════════════════════ */\n.hero-install {\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  margin-top: 0;\n}\n\n.install-label {\n  font-family: \"Roc Grotesk\", sans-serif;\n  font-weight: 400;\n  font-size: 0.75rem;\n  letter-spacing: 0.15em;\n  text-transform: uppercase;\n  color: var(--vp-c-text-3);\n  margin-bottom: 8px;\n}\n\n.install-command {\n  display: flex;\n  align-items: center;\n  gap: 12px;\n  padding: 14px 20px;\n  background: var(--vp-c-bg-soft);\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 10px;\n  cursor: pointer;\n  transition: all 0.25s ease;\n  position: relative;\n}\n\n.install-command:hover {\n  border-color: var(--vp-c-brand-1);\n  box-shadow: 0 4px 20px rgba(139, 34, 82, 0.1);\n  transform: translateY(-1px);\n}\n\n.dark .install-command:hover {\n  box-shadow: 0 4px 20px rgba(199, 91, 122, 0.1);\n}\n\n.install-command code {\n  font-family: \"JetBrains Mono\", var(--vp-font-family-mono);\n  font-size: 0.95rem;\n  color: var(--vp-c-text-1);\n  background: none;\n  padding: 0;\n  letter-spacing: -0.01em;\n}\n\n.install-copy {\n  font-size: 1.1rem;\n  color: var(--vp-c-text-3);\n  transition: all 0.2s ease;\n  user-select: none;\n  min-width: 1.2em;\n  text-align: center;\n}\n\n.install-copy.copied {\n  color: var(--vp-c-success-1);\n}\n\n.install-command:hover .install-copy {\n  color: var(--vp-c-brand-1);\n}\n\n.install-alt {\n  margin-top: 10px;\n  font-size: 0.85rem;\n  font-family: \"Roc Grotesk\", sans-serif;\n}\n\n.install-alt a {\n  color: var(--vp-c-text-3);\n  text-decoration: none;\n  transition: color 0.2s ease;\n}\n\n.install-alt a:hover {\n  color: var(--vp-c-brand-1);\n}\n\n@keyframes heroFadeUp {\n  from {\n    opacity: 0;\n    transform: translateY(16px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\n/* ═══════════════════════════════════════════\n   RESPONSIVE\n   ═══════════════════════════════════════════ */\n@media (max-width: 768px) {\n  .hero-chef-logo .chef-logo {\n    max-width: 280px;\n  }\n\n  .hero-glow-1 { width: 350px; height: 350px; }\n  .hero-glow-2 { width: 300px; height: 300px; }\n  .hero-glow-3 { width: 250px; height: 250px; }\n\n  .install-command code {\n    font-size: 0.85rem;\n  }\n}\n\n@media (max-width: 480px) {\n  .hero-chef-logo .chef-logo {\n    max-width: 220px;\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/theme/MiseLogo.vue",
    "content": "<template>\n  <svg\n    :width=\"width\"\n    :height=\"height\"\n    viewBox=\"0 0 301 300\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    class=\"mise-logo\"\n    :class=\"{ animated }\"\n  >\n    <g class=\"chef-icon\" fill=\"currentColor\">\n      <path d=\"M125.97,222.76c.61.93,1.73,1.51,2.91,1.51.07,0,.13,0,.2,0,.1,0,.2-.02.29-.03,1.08-.15,1.99-.81,2.5-1.8.93-1.84,3.33-6.57,4.91-9.72.53-1.06.52-2.26-.03-3.31-.55-1.05-1.54-1.74-2.72-1.89l-2.73-.35c-1.62-.21-3.45-.45-4.86-.67-1.16-.19-2.22.2-2.92,1.05-.76.93-.97,2.28-.53,3.43.41,1.09,1.33,1.83,2.52,2.02l3.52.57-3.15,6.2c-.52,1.02-.48,2.11.1,3Z\"/>\n      <path d=\"M168.6,216.87c.16,0,.32-.01.48-.03,1.17-.16,2.49-.98,2.68-2.79.34-3.32,2.09-6.11,4.81-7.64,2.75-1.55,6.08-1.62,9.15-.19,1.05.49,2.16.42,3.06-.21.98-.68,1.54-1.92,1.44-3.16-.1-1.18-.79-2.15-1.89-2.66-4.9-2.29-10.35-2.11-14.96.51-4.61,2.61-7.57,7.19-8.13,12.56-.22,2.12,1.39,3.43,3,3.6.12.01.24.02.36.02Z\"/>\n      <path d=\"M225.15,195.99c.39-1.04.18-2.16-.56-3.06-2.82-3.42-6.86-5.11-11.07-4.64-4.24.47-7.97,3.13-9.99,7.12-.81,1.6-.25,3.3,1.38,4.12.52.26,1.09.4,1.65.4.36,0,.72-.06,1.06-.17.83-.27,1.49-.85,1.91-1.68.97-1.91,2.64-3.12,4.6-3.31,2.01-.21,3.96.6,5.33,2.26.74.89,1.79,1.32,2.89,1.17h.11c1.21-.22,2.27-1.08,2.69-2.21Z\"/>\n      <path d=\"M202.14,216.23c-1.12-.23-2.17.09-2.88.88-.78.88-1.04,2.21-.65,3.4.38,1.15,1.28,1.96,2.49,2.21.64.13,1.3.2,1.96.2.45,0,.9-.03,1.35-.09,3.82-.53,7.1-3.25,8.17-6.78,1.42-4.69-1.16-9.92-5.87-11.9-1.09-.46-2.23-.33-3.13.35-.97.74-1.49,2-1.34,3.21.14,1.13.85,2.04,1.95,2.51,2.05.86,2.35,2.53,1.95,3.81-.43,1.38-1.86,2.66-4,2.21Z\"/>\n      <path d=\"M168.94,240.24c.84.44,1.84.53,2.73.25.85-.27,1.52-.84,1.94-1.65l.96-1.84s.03.02.05.02c5.18,2.46,10.77,3.71,16.43,3.71,1.75,0,3.5-.12,5.25-.36,10.4-1.44,19.87-7.18,25.98-15.75.7-.98.82-2.15.34-3.21-.51-1.12-1.62-1.92-2.82-2.03-1.11-.1-2.13.39-2.8,1.33-9.07,12.73-25.24,16.99-39.4,10.45l1.47-2.84c.82-1.59.28-3.27-1.32-4.1-1.52-.79-3.69-.48-4.67,1.41l-5.45,10.51c-.82,1.59-.28,3.28,1.32,4.1Z\"/>\n      <path d=\"M238.75,138.24c-5.14-1.68-10.74-1.47-17.6.68l-8.59-20.6c15.54-10.11,22.39-30.44,15.92-47.45-6.75-17.75-25.63-28.66-43.92-25.42-9.84,1.75-18.95,7.17-25.08,14.88-5.69-7.61-14.02-12.93-22.95-14.62-6.36-1.21-12.78-.81-18.58,1.14-10.97,3.68-29.99,18.28-23.91,47.24-13.45-1.34-31.13,4.26-38.76,19.84-4.53,9.26-5.06,20.2-1.45,30,3.51,9.53,10.43,16.96,19.49,20.89,9.59,4.17,20.87,4.32,30.27.42,2.22,3.97,7,12.91,10.86,20.14,2.57,4.82,4.82,9.03,5.7,10.62-1.62,1.02-3.08,2.19-4.34,3.47-6.3,6.37-8.64,15.99-5.82,23.94,2.81,7.93,11.19,13.64,19.47,13.35,5.19-.21,9.93-2.61,14.46-7.32,8.75,14.26,24.58,24.01,41.44,25.49,1.39.12,2.79.18,4.19.18,2.23,0,4.46-.15,6.68-.46,14.28-1.98,27.34-10.17,35.84-22.47,6.12-8.85,9.4-18.97,9.5-29.26.02-2.17-1.78-3.49-3.54-3.51h-.01c-1.71,0-2.97,1.23-2.98,2.94-.2,20.96-15.35,40.34-35.25,45.07-19.69,4.69-41.74-5.35-51.43-23.39.81-1.11,1.64-2.32,2.67-3.89.7-1.06.63-2.05.45-2.69-.22-.8-.76-1.53-1.48-2-1.53-1.01-3.31-.66-4.3.85l-.17.26c-3.65,5.52-8.19,12.38-15.01,13.51-5.86,1-12.35-3.08-14.44-9.1-2.01-5.79.06-13,5.04-17.53,5.03-4.58,12.42-6.23,20.28-4.55.83.18,1.66.05,2.31-.37.67-.43,1.13-1.14,1.32-2,.36-1.67-.51-3.67-2.58-4.11-5.48-1.18-11.3-.88-16.41.82l-.58-1.04c31.35-34.98,78.27-52.22,88.34-55.63l1.71,4.35c-.77.32-1.68.71-2.52,1.08l-1.3.56c-20.7,8.88-40.47,20.42-58.76,34.3-1.66,1.26-1.55,3.22-.57,4.51.52.68,1.24,1.15,2.03,1.31.9.19,1.79-.03,2.57-.63,11.13-8.45,22.76-15.98,34.56-22.41,5.86-3.19,11.96-6.22,18.13-9.01l2.14-.97c5.49-2.51,11.17-5.09,17.05-5.82,5.78-.73,12.58,1,14.72,6.52,2.03,5.24-1.09,10.87-5.06,13.51-3.4,2.26-8.22,3.3-12.67,2.76.64-2.49,1.04-5.82-.33-8.43-.86-1.64-2.28-2.77-4.23-3.35-3.03-.91-5.73.05-7.42,2.63-2.14,3.27-1.93,8.03.47,10.83.74.87,1.64,1.64,2.68,2.3-3.2,4.93-8.15,8.36-14,9.68-6.32,1.45-13.03.16-18.38-3.54-.75-.51-1.58-.7-2.42-.55-.88.16-1.7.7-2.23,1.47-.46.67-.67,1.46-.58,2.23.1.87.57,1.61,1.35,2.15,6.9,4.76,15.51,6.45,23.64,4.63,8.03-1.79,14.73-6.67,18.88-13.76,4.99.87,10.3.02,13.63-1.08,7.58-2.51,12.97-8.92,13.74-16.32.81-7.78-3.96-14.74-11.87-17.32ZM104.93,157.68c-.13,0-.26,0-.4.03-.33.05-.65.15-.96.31-7.54,3.92-16.69,4.55-25.11,1.73-7.87-2.64-14.05-7.96-17.38-14.97-3.69-7.77-4.05-16.9-.99-25.05,2.9-7.7,8.51-13.68,15.79-16.82,4.74-2.05,12.3-3.65,19.38-2.08,1.34,5.8,3.34,12.17,7.87,15.89,2.38,1.96,5.55,2.85,8.69,2.43,2.95-.46,5.44-1.92,7.01-4.12,3.35-4.7,2.23-10.94-2.61-14.5-4.96-3.66-11.12-5.11-15.5-5.69-2.5-9.67-.96-20.8,4.06-29.11,4.33-7.17,10.82-11.85,18.77-13.52,12.2-2.58,25.08,3.15,32.13,14.26-4.2,7.38-6.36,16.92.07,21.81,1.59,1.21,4.12,1.74,6.62,1.4,2.31-.32,4.27-1.36,5.38-2.86,5.15-6.89-.21-14.38-3.41-18.86l-.09-.12c-.33-.46-.64-.9-.92-1.3,4.53-7.97,12.9-13.22,23.01-14.43,11.26-1.33,22.55,2.69,29.48,10.49,6.44,7.24,9.29,16.55,8.04,26.22-1.2,9.26-6.18,17.68-13.7,23.19l-1.28-3.41c-.72-1.91-2.58-2.35-4.06-1.81-1.54.58-2.77,2.28-2.01,4.32l8.52,19.87c-10.17,3.47-56.95,20.76-89.05,55.58-1.72-3.1-4.78-8.89-7.74-14.5-2.81-5.32-5.47-10.35-6.65-12.45-.55-.99-1.67-1.91-2.98-1.91ZM113.74,107.08c.56.93.64,1.94.25,3.08-.51,1.47-1.39,2.26-2.76,2.47-1.95.2-4.43-1.14-5.63-3.09-1.3-2.11-2.34-4.58-3.26-7.72,5.92,1.13,10.05,3.04,11.39,5.26ZM163.03,81.88c-.34.78-1.05,1.19-2.24,1.29-.36.01-.88-.12-1.32-.6-.68-.74-1.34-2.41-.69-6.18h0c.2-1.18.74-2.67,1.24-3.89,2.57,3.73,3.8,7.53,3,9.39ZM219.83,164.53c-.61-.49-1.17-1.18-1.14-2.01.02-.62.36-.97.61-1.03,0,0,.02,0,.03,0,.21,0,.39.32.44.42.31.61.33,1.49.06,2.63Z\"/>\n    </g>\n  </svg>\n</template>\n\n<script setup lang=\"ts\">\ninterface Props {\n  width?: number | string;\n  height?: number | string;\n  animated?: boolean;\n}\n\nwithDefaults(defineProps<Props>(), {\n  width: 120,\n  height: 120,\n  animated: false,\n});\n</script>\n\n<style scoped>\n.mise-logo {\n  display: inline-block;\n  color: var(--vp-c-text-1);\n  transition: all 0.3s ease;\n}\n\n.mise-logo:hover {\n  transform: scale(1.05);\n  filter: drop-shadow(0 0 8px rgba(139, 34, 82, 0.3));\n}\n\n.mise-logo:hover .chef-icon {\n  animation: gentle-bounce 1s ease-in-out;\n}\n\n@keyframes gentle-bounce {\n  0%,\n  100% {\n    transform: translateY(0);\n  }\n  50% {\n    transform: translateY(-4px);\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/theme/custom.css",
    "content": "/**\n * Customize default theme styling by overriding CSS variables\n * Color palette: Warm culinary aesthetic — burgundy, gold, sage\n */\n\n@font-face {\n  font-family: \"Roc Grotesk\";\n  src: url(\"/fonts/rocgrotesk-light-webfont.woff2\") format(\"woff2\");\n  font-weight: 300;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"Roc Grotesk\";\n  src: url(\"/fonts/rocgrotesk-regular-webfont.woff2\") format(\"woff2\");\n  font-weight: 400;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"Roc Grotesk\";\n  src: url(\"/fonts/rocgrotesk-medium-webfont.woff2\") format(\"woff2\");\n  font-weight: 500;\n  font-style: normal;\n  font-display: swap;\n}\n\n@font-face {\n  font-family: \"Roc Grotesk\";\n  src: url(\"/fonts/rocgrotesk-bold-webfont.woff2\") format(\"woff2\");\n  font-weight: 700;\n  font-style: normal;\n  font-display: swap;\n}\n\n:root {\n  /* Brand Colors - Rich burgundy */\n  --vp-c-brand-1: #8B2252;\n  --vp-c-brand-2: #722F37;\n  --vp-c-brand-3: #5C1A2A;\n  --vp-c-brand-soft: rgba(139, 34, 82, 0.14);\n\n  /* Accent Colors - Sage green */\n  --vp-c-success-1: #8FA86E;\n  --vp-c-success-2: #7A9460;\n  --vp-c-success-3: #6B7F4E;\n  --vp-c-success-soft: rgba(143, 168, 110, 0.14);\n\n  /* Warning Colors - Warm gold */\n  --vp-c-warning-1: #C5975B;\n  --vp-c-warning-2: #B08450;\n  --vp-c-warning-3: #9A7245;\n  --vp-c-warning-soft: rgba(197, 151, 91, 0.14);\n\n  /* Danger Colors - Terra cotta */\n  --vp-c-danger-1: #C44536;\n  --vp-c-danger-2: #B33A2E;\n  --vp-c-danger-3: #A03025;\n  --vp-c-danger-soft: rgba(196, 69, 54, 0.14);\n\n  /* Custom accent */\n  --mise-accent-gold: #D4A76A;\n\n  /* Typography */\n  --vp-font-family-base: \"Roc Grotesk\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n  --vp-font-family-mono: \"JetBrains Mono\", \"Fira Code\", \"SF Mono\", Monaco,\n    \"Cascadia Code\", \"Roboto Mono\", Consolas, \"Courier New\", monospace;\n  --vp-font-family-heading: \"Cormorant Garamond\", Georgia, serif;\n\n\n  /* Custom spacing for better readability */\n  --vp-layout-max-width: 1440px;\n}\n\n/* Dark mode specific customizations */\n.dark {\n  /* Brand overrides for dark mode */\n  --vp-c-brand-1: #C75B7A;\n  --vp-c-brand-2: #B04A68;\n  --vp-c-brand-3: #9A3D5A;\n  --vp-c-brand-soft: rgba(199, 91, 122, 0.14);\n\n  /* Enhanced dark mode colors - deeper for contrast */\n  --vp-c-bg: #141010;\n  --vp-c-bg-soft: #1C1614;\n  --vp-c-bg-mute: #261E1A;\n  --vp-c-bg-alt: #181312;\n\n  /* Warm dividers */\n  --vp-c-divider: #3A2E25;\n  --vp-c-divider-light: #4A3D33;\n\n  /* Text colors with warm undertones */\n  --vp-c-text-1: #EDE6DF;\n  --vp-c-text-2: #C9BFB5;\n  --vp-c-text-3: #9E9288;\n  --vp-c-text-4: #71685E;\n\n  /* Code block enhancements */\n  --vp-code-block-bg: #1F1713;\n  --vp-code-block-divider-color: #3A2E25;\n  --vp-code-copy-code-hover-bg: #3A2E25;\n\n  /* Inline code styling */\n  --vp-c-code-bg: #2D221A;\n  --vp-c-code-color: #C75B7A;\n}\n\n/* Light mode customizations */\n:root:not(.dark) {\n  /* Light mode brand colors */\n  --vp-c-brand-1: #8B2252;\n  --vp-c-brand-2: #722F37;\n  --vp-c-brand-3: #5C1A2A;\n  --vp-c-brand-soft: rgba(139, 34, 82, 0.08);\n\n  /* Adjusted success colors for light mode */\n  --vp-c-success-1: #6B7F4E;\n  --vp-c-success-2: #5A6B40;\n  --vp-c-success-soft: rgba(107, 127, 78, 0.08);\n\n  /* Adjusted warning colors */\n  --vp-c-warning-1: #C5975B;\n  --vp-c-warning-2: #B08450;\n  --vp-c-warning-soft: rgba(197, 151, 91, 0.08);\n\n  /* Cream/warm background colors */\n  --vp-c-bg: #FDF8F3;\n  --vp-c-bg-soft: #F5EDE3;\n  --vp-c-bg-mute: #E8DDD0;\n  --vp-c-bg-alt: #F0E6DA;\n\n  /* Text colors */\n  --vp-c-text-1: #2A1F1A;\n  --vp-c-text-2: #5A4D42;\n  --vp-c-text-3: #7D7068;\n  --vp-c-text-4: #A09489;\n\n  /* Warm dividers */\n  --vp-c-divider: #D4C8B8;\n  --vp-c-divider-light: #C5B8A5;\n\n  /* Light mode code styling */\n  --vp-c-code-bg: #F0E6DA;\n  --vp-c-code-color: #8B2252;\n\n  /* Code blocks in light mode */\n  --vp-code-block-bg: #F5EDE3;\n  --vp-code-block-divider-color: #D4C8B8;\n}\n\n/* Navigation Bar — solid background, no pop-in */\n.VPNav {\n  background-color: var(--vp-c-bg) !important;\n  border-bottom: 1px solid var(--vp-c-divider);\n}\n\n.VPNavBar {\n  background-color: transparent !important;\n}\n\n.VPNavBar .wrapper {\n  background-color: transparent !important;\n}\n\n.VPNavBar .content {\n  background-color: transparent !important;\n}\n\n/* Logo */\n.VPNavBarTitle .VPImage.logo {\n  height: 40px !important;\n  width: auto !important;\n  transition: transform 0.25s ease, filter 0.25s ease;\n}\n\n.VPNavBarTitle:hover .VPImage.logo {\n  transform: scale(1.1);\n  filter: drop-shadow(0 0 10px rgba(139, 34, 82, 0.4));\n}\n\n/* Site Title */\n.VPNavBarTitle .title {\n  font-size: 1.05rem;\n  letter-spacing: -0.02em;\n  margin-left: 0.25rem;\n  color: var(--vp-c-text-1);\n}\n\n/* Mobile adjustments */\n@media (max-width: 768px) {\n  .VPNavBarTitle .title::before {\n    display: none;\n  }\n}\n\n/* GitHub star count badge */\n.VPSocialLinks a[href*=\"github.com/jdx/mise\"] {\n  display: inline-flex !important;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  gap: 0;\n  position: relative;\n  padding-bottom: 12px !important;\n  margin-bottom: -12px !important;\n}\n\n/* Ensure GitHub icon is visible and aligned */\n.VPSocialLinks a[href*=\"github.com/jdx/mise\"] svg {\n  display: block !important;\n  width: 20px;\n  height: 20px;\n  margin-top: 2px;\n}\n\n.VPSocialLinks .star-count {\n  position: absolute;\n  bottom: 0;\n  left: 50%;\n  transform: translateX(-50%);\n  font-size: 0.6rem;\n  font-weight: 600;\n  color: var(--vp-c-text-3);\n  font-family: var(--vp-font-family-mono);\n  letter-spacing: -0.02em;\n  transition: color 0.25s ease;\n  white-space: nowrap;\n  line-height: 1;\n}\n\n.VPSocialLinks a[href*=\"github.com/jdx/mise\"]:hover .star-count {\n  color: var(--vp-c-brand-1);\n}\n\n/* Hide star count on mobile to save space */\n@media (max-width: 640px) {\n  .VPSocialLinks .star-count {\n    display: none;\n  }\n}\n\n/* Cormorant Garamond — all headings */\nh1, h2, h3, h4, h5, h6,\n.vp-doc h1, .vp-doc h2, .vp-doc h3, .vp-doc h4,\n.VPHero .name,\n.VPHome .name,\n.VPFeatures .title,\n.VPDocOutlineTitle,\n.VPSidebarItem.level-0 > .item {\n  font-family: \"Cormorant Garamond\", Georgia, serif !important;\n  letter-spacing: 0.01em;\n  font-weight: 600;\n}\n\n/* Nav — all Roc Grotesk */\n.VPNav,\n.VPNavBar,\n.VPNavBarTitle .title,\n.VPNavBarMenu .VPNavBarMenuLink,\n.VPNavBarMenuGroup .text,\n.VPNavBarSearch,\n.DocSearch-Button {\n  font-family: \"Roc Grotesk\", sans-serif !important;\n  font-weight: 400;\n}\n\n/* Nav bar menu items */\n.VPNavBarMenu .VPNavBarMenuLink {\n  font-size: 1rem;\n  letter-spacing: 0.02em;\n}\n\n/* Buttons — Roc Grotesk */\n.VPButton {\n  font-family: \"Roc Grotesk\", sans-serif !important;\n}\n\n/* \"On this page\" header */\n.VPDocOutlineTitle {\n  font-size: 0.9rem;\n  letter-spacing: 0.06em;\n  text-transform: uppercase;\n  font-weight: 600;\n}\n\n/* Make search button text invisible but maintain layout */\n.DocSearch-Button .DocSearch-Button-Placeholder {\n  visibility: hidden;\n}\n\n/* Body text */\n.vp-doc p,\n.vp-doc li,\n.vp-doc td,\n.vp-doc blockquote {\n  font-size: 1rem;\n  line-height: 1.75;\n  font-weight: 400;\n}\n\n/* Reset mermaid diagrams — don't inherit body text styles */\n.vp-doc .mermaid,\n.vp-doc .mermaid * {\n  font-size: initial !important;\n  font-family: sans-serif !important;\n  font-weight: 400 !important;\n}\n\n/* Tab headers — Roc Grotesk */\n.vp-code-group .tabs label,\n.plugin-tabs--tab {\n  font-family: \"Roc Grotesk\", sans-serif !important;\n  font-weight: 400;\n  font-size: 1rem !important;\n}\n\n/* Reset code sizing — don't inherit body bump */\n.vp-doc :not(pre) > code {\n  font-size: 0.8em !important;\n  font-weight: 400 !important;\n  padding: 2px 5px !important;\n}\n\n.vp-doc div[class*=\"language-\"] code {\n  font-size: 0.85rem !important;\n}\n\n/* h1 sizing */\n.vp-doc h1 {\n  font-size: 2.4rem;\n  line-height: 1.25;\n  font-weight: 600;\n}\n\n/* Site title */\n.VPNavBarTitle .title {\n  font-size: 1.15rem !important;\n  letter-spacing: 0.03em;\n}\n\n/* ═══ Hero section — \"The Chef's Counter\" ═══ */\n.VPHero {\n  padding-top: 76px !important;\n  padding-bottom: 64px !important;\n  position: relative;\n  z-index: 1;\n}\n\n/* Two-column hero layout */\n.VPHero .container {\n  max-width: 1040px !important;\n  margin: 0 auto !important;\n}\n\n.VPHero .main {\n  display: grid !important;\n  grid-template-columns: 1fr 1fr;\n  align-items: center;\n  gap: 0 60px;\n}\n\n/* Left column: logo */\n.VPHero .main .hero-chef-logo {\n  grid-column: 1;\n  grid-row: 1;\n  justify-content: flex-start;\n}\n\n/* Hide the default VitePress hero name and actions */\n.VPHero .name {\n  display: none !important;\n}\n\n.VPHero .actions {\n  display: none !important;\n}\n\n.VPHero .tagline {\n  grid-column: 1;\n  grid-row: 2;\n  font-family: \"Cormorant Garamond\", Georgia, serif !important;\n  font-size: 1.5rem !important;\n  font-weight: 500;\n  font-style: italic;\n  letter-spacing: 0.01em;\n  color: var(--vp-c-text-2);\n  margin-top: -4px !important;\n  text-align: center;\n}\n\n/* Right column wrapper */\n.hero-right {\n  grid-column: 2;\n  grid-row: 1 / 3;\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n  gap: 28px;\n}\n\n/* Custom action buttons in right column */\n.hero-actions {\n  display: flex;\n  gap: 12px;\n  flex-wrap: wrap;\n}\n\n.action-btn {\n  font-family: \"Roc Grotesk\", sans-serif;\n  font-weight: 500;\n  font-size: 0.8rem;\n  text-transform: uppercase;\n  letter-spacing: 0.08em;\n  padding: 10px 24px;\n  border-radius: 6px;\n  text-decoration: none;\n  transition: all 0.25s ease;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  height: 40px;\n  line-height: 1;\n}\n\n.action-btn-brand {\n  background: var(--vp-c-brand-1);\n  color: #fff;\n}\n\n.action-btn-brand:hover {\n  background: var(--vp-c-brand-2);\n  transform: translateY(-2px);\n  box-shadow: 0 4px 16px rgba(139, 34, 82, 0.25);\n}\n\n.action-btn-alt {\n  background: var(--vp-c-bg-soft);\n  color: var(--vp-c-text-1);\n  border: 1px solid var(--vp-c-divider);\n}\n\n.action-btn-alt:hover {\n  border-color: var(--vp-c-brand-1);\n  color: var(--vp-c-brand-1);\n  transform: translateY(-2px);\n}\n\n/* Landing page feature card text */\n.VPFeature .details {\n  font-size: 1rem;\n  line-height: 1.6;\n  font-weight: 400;\n}\n\n/* Button customization */\n.VPButton {\n  font-weight: 500;\n  font-size: 0.8rem;\n  transition: all 0.25s ease !important;\n  border-radius: 6px;\n  letter-spacing: 0.06em;\n  text-transform: uppercase;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.VPButton.brand:hover,\n.VPButton.alt:hover {\n  transform: translateY(-3px) !important;\n}\n\n.VPButton.medium {\n  padding: 0 24px;\n  height: 40px;\n  line-height: 1;\n}\n\n.VPButton.brand {\n  background: linear-gradient(135deg, #8B2252 0%, #722F37 100%);\n  border-color: transparent;\n  box-shadow: 0 2px 8px rgba(139, 34, 82, 0.2);\n}\n\n.VPButton.brand:hover {\n  transform: translateY(-2px);\n  box-shadow: 0 6px 20px rgba(139, 34, 82, 0.3);\n  background: linear-gradient(135deg, #9A2860 0%, #8B2252 100%);\n}\n\n.dark .VPButton.brand {\n  background: linear-gradient(135deg, #C75B7A 0%, #B04A68 100%);\n  box-shadow: 0 2px 8px rgba(199, 91, 122, 0.2);\n}\n\n.dark .VPButton.brand:hover {\n  box-shadow: 0 6px 20px rgba(199, 91, 122, 0.3);\n  background: linear-gradient(135deg, #D46A88 0%, #C75B7A 100%);\n}\n\n.VPButton.alt {\n  border-color: var(--vp-c-divider);\n  background: var(--vp-c-bg-soft);\n}\n\n.VPButton.alt:hover {\n  transform: translateY(-2px);\n  border-color: var(--vp-c-brand-1);\n  box-shadow: 0 4px 12px rgba(139, 34, 82, 0.1);\n}\n\n.VPButton:hover {\n  transform: translateY(-2px);\n}\n\n/* Sidebar — Roc Grotesk */\n.VPSidebar {\n  font-family: \"Roc Grotesk\", sans-serif !important;\n  backdrop-filter: blur(8px);\n}\n\n/* Light mode sidebar background */\n:root:not(.dark) .VPSidebar {\n  background-color: rgba(253, 248, 243, 0.8);\n}\n\n.VPSidebarItem {\n  margin: 0;\n}\n\n.VPSidebarItem.level-0 > .item {\n  padding-top: 2px;\n  padding-bottom: 2px;\n  font-weight: 500;\n  text-transform: uppercase;\n  letter-spacing: 0.025em;\n  font-size: 0.75rem;\n  color: var(--vp-c-text-3);\n}\n\n.VPSidebarItem .link {\n  transition: all 0.2s ease;\n  border-radius: 4px;\n  padding: 2px 6px !important;\n  margin: 0;\n  font-size: 0.875rem;\n  font-weight: 400;\n  line-height: 1.5;\n}\n\n.VPSidebarItem .link:hover {\n  background-color: var(--vp-c-bg-mute);\n  color: var(--vp-c-brand-1);\n}\n\n.VPSidebarItem .link.active {\n  background-color: rgba(139, 34, 82, 0.15) !important;\n  color: var(--vp-c-brand-1) !important;\n  font-weight: 700 !important;\n  border-left: 3px solid var(--vp-c-brand-1) !important;\n  padding-left: 10px !important;\n  border-radius: 0 6px 6px 0 !important;\n  box-shadow: inset 0 0 0 1px rgba(139, 34, 82, 0.08);\n}\n\n.dark .VPSidebarItem .link.active {\n  background-color: rgba(199, 91, 122, 0.22) !important;\n  box-shadow: inset 0 0 0 1px rgba(199, 91, 122, 0.12);\n}\n\n/* Code blocks with better syntax highlighting */\n.vp-code-group {\n  border-radius: 12px;\n  overflow: hidden;\n  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);\n}\n\ndiv[class*=\"language-\"] {\n  border-radius: 8px;\n  border: 1px solid var(--vp-code-block-divider-color);\n  transition:\n    box-shadow 0.3s ease,\n    border-color 0.3s ease;\n}\n\ndiv[class*=\"language-\"]:hover {\n  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);\n}\n\ndiv[class*=\"language-\"] .lang {\n  color: var(--vp-c-brand-1);\n  font-weight: 600;\n  font-size: 0.75rem;\n  text-transform: uppercase;\n  letter-spacing: 0.025em;\n}\n\n/* Copy code button enhancement */\ndiv[class*=\"language-\"] .copy {\n  background-color: var(--vp-c-bg-soft);\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 6px;\n  transition: all 0.2s ease;\n}\n\ndiv[class*=\"language-\"] .copy:hover {\n  background-color: var(--vp-c-brand-1);\n  border-color: var(--vp-c-brand-1);\n  color: white;\n}\n\n/* Custom scrollbar */\n::-webkit-scrollbar {\n  width: 10px;\n  height: 10px;\n}\n\n::-webkit-scrollbar-track {\n  background: var(--vp-c-bg-soft);\n}\n\n::-webkit-scrollbar-thumb {\n  background: var(--vp-c-divider);\n  border-radius: 5px;\n  border: 2px solid var(--vp-c-bg-soft);\n}\n\n::-webkit-scrollbar-thumb:hover {\n  background: var(--vp-c-text-3);\n}\n\n/* ═══ Feature cards — culinary mise cards ═══ */\n.VPFeatures {\n  position: relative;\n  z-index: 1;\n}\n\n.VPFeatures .title {\n  font-family: \"Cormorant Garamond\", Georgia, serif !important;\n  font-size: 1.3rem;\n  font-weight: 600;\n  letter-spacing: 0.02em;\n}\n\n.VPFeature {\n  border: 1px solid var(--vp-c-divider);\n  border-radius: 14px;\n  transition: all 0.35s cubic-bezier(0.22, 1, 0.36, 1) !important;\n  background: var(--vp-c-bg);\n  position: relative;\n  overflow: hidden;\n}\n\n.VPFeature:hover {\n  transform: translateY(-6px) !important;\n}\n\n/* Accent top border — each card gets a color via nth-child */\n.VPFeature::before {\n  content: \"\";\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 3px;\n  background: var(--vp-c-brand-1);\n  opacity: 0;\n  transition: opacity 0.35s ease;\n}\n\n.VPFeatures .items .item:nth-child(1) .VPFeature::before {\n  background: linear-gradient(90deg, #8B2252, #C75B7A);\n}\n\n.VPFeatures .items .item:nth-child(2) .VPFeature::before {\n  background: linear-gradient(90deg, #D4A76A, #C5975B);\n}\n\n.VPFeatures .items .item:nth-child(3) .VPFeature::before {\n  background: linear-gradient(90deg, #6B7F4E, #8FA86E);\n}\n\n.VPFeature:hover {\n  border-color: var(--vp-c-brand-soft);\n  transform: translateY(-6px);\n  box-shadow:\n    0 16px 40px rgba(139, 34, 82, 0.08),\n    0 4px 12px rgba(0, 0, 0, 0.04);\n}\n\n.dark .VPFeature:hover {\n  box-shadow:\n    0 16px 40px rgba(199, 91, 122, 0.06),\n    0 4px 12px rgba(0, 0, 0, 0.2);\n}\n\n.VPFeature:hover::before {\n  opacity: 1;\n}\n\n.VPFeature .icon {\n  font-size: 2.2rem;\n  margin-bottom: 0.75rem;\n  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.VPFeature:hover .icon {\n  transform: scale(1.15) rotate(-3deg);\n}\n\n/* Table styling */\n.vp-doc .vp-table {\n  margin: 1.5rem 0;\n  border-radius: 8px;\n  overflow: hidden;\n  box-shadow: 0 0 0 1px var(--vp-c-divider);\n}\n\n.vp-doc table {\n  border-collapse: collapse;\n  font-family: \"Roc Grotesk\", sans-serif;\n  font-size: 0.95rem;\n  width: 100%;\n  margin: 0;\n  display: table;\n}\n\n.vp-doc th {\n  background: var(--vp-c-bg-soft);\n  font-family: \"Roc Grotesk\", sans-serif;\n  font-weight: 500;\n  text-transform: uppercase;\n  font-size: 0.8rem;\n  letter-spacing: 0.04em;\n  color: var(--vp-c-text-2);\n}\n\n.vp-doc td {\n  font-family: \"Roc Grotesk\", sans-serif !important;\n  font-weight: 400;\n  font-size: 0.95rem !important;\n}\n\n.vp-doc tr {\n  transition: background-color 0.2s ease;\n}\n\n.vp-doc tbody tr:hover {\n  background-color: var(--vp-c-bg-soft);\n}\n\n/* Links with underline animation */\n.vp-doc a {\n  position: relative;\n  color: var(--vp-c-brand-1);\n  text-decoration: none;\n  transition: color 0.2s ease;\n}\n\n.vp-doc a:hover {\n  color: var(--vp-c-brand-2);\n}\n\n.vp-doc a:not(.header-anchor):not(.VPButton)::after {\n  content: \"\";\n  position: absolute;\n  width: 100%;\n  height: 2px;\n  bottom: -2px;\n  left: 0;\n  background-color: var(--vp-c-brand-1);\n  transform: scaleX(0);\n  transform-origin: bottom right;\n  transition: transform 0.25s ease-out;\n}\n\n.vp-doc a:not(.header-anchor):not(.VPButton):hover::after {\n  transform: scaleX(1);\n  transform-origin: bottom left;\n}\n\n/* Tip/Warning/Danger blocks customization */\n.custom-block {\n  border-radius: 8px;\n  border-width: 1px;\n  margin: 1.5rem 0;\n}\n\n.custom-block.tip {\n  border-color: var(--vp-c-success-2);\n  background-color: var(--vp-c-success-soft);\n}\n\n.custom-block.warning {\n  border-color: var(--vp-c-warning-2);\n  background-color: var(--vp-c-warning-soft);\n}\n\n.custom-block.danger {\n  border-color: var(--vp-c-danger-2);\n  background-color: var(--vp-c-danger-soft);\n}\n\n.custom-block-title {\n  font-weight: 700;\n  text-transform: uppercase;\n  letter-spacing: 0.025em;\n  font-size: 0.85rem;\n}\n\n/* Search modal enhancement */\n.VPLocalSearchBox {\n  --vp-local-search-highlight-bg: var(--vp-c-brand-soft);\n  --vp-local-search-highlight-text: var(--vp-c-brand-1);\n}\n\n/* Algolia DocSearch customization */\n.DocSearch {\n  --docsearch-primary-color: var(--vp-c-brand-1) !important;\n  --docsearch-highlight-color: var(--vp-c-brand-1) !important;\n  --docsearch-muted-color: var(--vp-c-text-2) !important;\n  --docsearch-hit-color: var(--vp-c-text-1) !important;\n  --docsearch-hit-active-color: var(--vp-c-text-1) !important;\n  --docsearch-hit-background: var(--vp-c-bg-soft) !important;\n}\n\n/* Warm burgundy background for selected search results */\n.DocSearch-Hit[aria-selected=\"true\"] {\n  background-color: rgba(139, 34, 82, 0.1) !important;\n}\n\n.DocSearch-Hit[aria-selected=\"true\"] a {\n  background-color: rgba(139, 34, 82, 0.1) !important;\n}\n\n.dark .DocSearch-Hit[aria-selected=\"true\"] {\n  background-color: rgba(199, 91, 122, 0.08) !important;\n}\n\n.dark .DocSearch-Hit[aria-selected=\"true\"] a {\n  background-color: rgba(199, 91, 122, 0.08) !important;\n}\n\n/* Page transitions — disabled for snappy feel */\n\n/* Terminal-style elements */\n.terminal {\n  background: #1A1210;\n  color: #D4A76A;\n  padding: 1rem;\n  border-radius: 8px;\n  font-family: var(--vp-font-family-mono);\n  position: relative;\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\n}\n\n.terminal::before {\n  content: \"● ● ●\";\n  position: absolute;\n  top: 0.75rem;\n  left: 1rem;\n  color: #C44536;\n  font-size: 0.75rem;\n  letter-spacing: 0.25rem;\n}\n\n/* Responsive improvements */\n@media (max-width: 768px) {\n  .VPHero .main {\n    grid-template-columns: 1fr !important;\n  }\n\n  .VPHero .main .hero-chef-logo {\n    grid-column: 1;\n    grid-row: auto;\n    justify-content: center;\n  }\n\n  .VPHero .tagline {\n    grid-column: 1;\n    grid-row: auto;\n    text-align: center;\n    font-size: 1.15rem !important;\n  }\n\n  .hero-right {\n    grid-column: 1;\n    grid-row: auto;\n    align-items: center;\n    margin-top: 24px;\n  }\n\n  .hero-actions {\n    justify-content: center;\n  }\n\n  .VPHero {\n    padding-top: 48px !important;\n    padding-bottom: 40px !important;\n  }\n}\n\n/* Loading animation for async content */\n@keyframes pulse {\n  0%,\n  100% {\n    opacity: 1;\n  }\n  50% {\n    opacity: 0.5;\n  }\n}\n\n.loading {\n  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n}\n\n/* Custom badge styles */\n.badge {\n  display: inline-block;\n  padding: 0.25rem 0.5rem;\n  font-size: 0.75rem;\n  font-weight: 600;\n  border-radius: 4px;\n  text-transform: uppercase;\n  letter-spacing: 0.025em;\n}\n\n.badge-new {\n  background-color: var(--vp-c-success-soft);\n  color: var(--vp-c-success-1);\n  border: 1px solid var(--vp-c-success-2);\n}\n\n.badge-beta {\n  background-color: var(--vp-c-warning-soft);\n  color: var(--vp-c-warning-1);\n  border: 1px solid var(--vp-c-warning-2);\n}\n\n.badge-deprecated {\n  background-color: var(--vp-c-danger-soft);\n  color: var(--vp-c-danger-1);\n  border: 1px solid var(--vp-c-danger-2);\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "import type { Theme } from \"vitepress\";\nimport DefaultTheme from \"vitepress/theme\";\nimport { enhanceAppWithTabs } from \"vitepress-plugin-tabs/client\";\nimport \"virtual:group-icons.css\";\nimport \"./custom.css\";\nimport Layout from \"./Layout.vue\";\nimport { onMounted } from \"vue\";\nimport { data as starsData } from \"../stars.data\";\n\nexport default {\n  extends: DefaultTheme,\n  Layout,\n  enhanceApp({ app }) {\n    enhanceAppWithTabs(app);\n  },\n  setup() {\n    onMounted(() => {\n      // Add star count to GitHub social link\n      const addStarCount = () => {\n        const githubLink = document.querySelector(\n          '.VPSocialLinks a[href*=\"github.com/jdx/mise\"]',\n        );\n        if (githubLink && !githubLink.querySelector(\".star-count\")) {\n          const starBadge = document.createElement(\"span\");\n          starBadge.className = \"star-count\";\n          starBadge.innerHTML = starsData.stars;\n          starBadge.title = \"GitHub Stars\";\n          githubLink.appendChild(starBadge);\n        }\n      };\n\n      // Try immediately and after a short delay to ensure DOM is ready\n      addStarCount();\n      setTimeout(addStarCount, 100);\n\n      // Also watch for route changes\n      const observer = new MutationObserver(addStarCount);\n      observer.observe(document.body, { childList: true, subtree: true });\n    });\n  },\n} satisfies Theme;\n"
  },
  {
    "path": "docs/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 jdx\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "docs/README.md",
    "content": "# mise-docs\n\nThis repository contains the documentation website for the runtime executor [mise](https://github.com/jdx/mise). The website is powered by [VitePress](https://vitepress.dev/).\n"
  },
  {
    "path": "docs/about.md",
    "content": "# About\n\n`mise` (pronounced \"meez\") or \"mise-en-place\" is a development environment setup tool.\nThe name refers to a French culinary phrase that roughly translates to \"setup\" or \"put in place\".\nThe idea is that before one begins cooking, they should have all their utensils and ingredients\nready to go in their place.\n\n`mise` does the same for your projects. Using its `mise.toml` config file,\nyou'll have a consistent way to setup and interact with your projects no matter what\nlanguage they're written in.\n\nIts functionality is grouped into 3 categories described below.\n\n`mise` installs and manages dev tools/runtimes like node, python, or terraform both\nsimplifying installing these tools and allowing you to specify which version of these\ntools to use in different projects. `mise` supports [hundreds](/plugins.md) of dev tools.\n\n`mise` manages environment variables letting you specify configuration like\n`AWS_ACCESS_KEY_ID` that may differ between projects. It can also be used to\nautomatically activate a [Python virtualenv](/lang/python) when entering projects too.\n\n`mise` is a task runner that can be used to share common tasks within\na project among developers and make things like running tasks on file changes\neasy.\n\n## Contact\n\n`mise` was initially created by [Jeff Dickey](https://jdx.dev). The goal is\nto make local development of software easy and consistent across languages. Jeff\nhas spent many years building dev tools and thinking about the problems that `mise`\naddresses.\n\nThis project is simply a labor of love. Jeff created it because he wanted to make\nyour life as a developer easier. We hope you find it useful. Feedback is a massive\ndriver for us. If you have anything positive or negative to say-even if it's just\nto say hi-please reach out to me either on [Twitter](https://twitter.com/jdxcode),\n[Mastodon](https://fosstodon.org/@jdx), [Discord](https://discord.gg/UBa7pJUN7Z),\nor `jdx at this domain`.\n"
  },
  {
    "path": "docs/architecture.md",
    "content": "---\noutline: [1, 3]\n---\n\n# mise Architecture\n\nThis document provides a comprehensive overview of mise's architecture, designed primarily for contributors and those interested in understanding how mise works internally.\n\nFor practical development guidance, see the [Contributing Guide](contributing.md).\n\n## System Overview\n\nmise is a Rust-based tool with a modular architecture centered around three core concepts:\n\n1. **Tool Version Management** - Installing and managing different versions of [development tools](dev-tools/)\n2. **Environment Management** - Setting up [environment variables](environments/) and project contexts\n3. **Task Running** - Executing [project tasks](tasks/) with dependency management\n\nThese three pillars work together to provide a unified development environment management experience.\n\n## Core Architecture Components\n\n### Command Layer ([`src/cli/`](https://github.com/jdx/mise/tree/main/src/cli/))\n\nThe CLI layer provides the user interface and delegates to core functionality:\n\n- **Modular Commands**: Each command is a separate module ([`install.rs`](https://github.com/jdx/mise/blob/main/src/cli/install.rs), [`use.rs`](https://github.com/jdx/mise/blob/main/src/cli/use.rs), [`run.rs`](https://github.com/jdx/mise/blob/main/src/cli/run.rs), etc.)\n- **Argument Parsing**: Leverages [`clap`](https://clap.rs) for robust CLI parsing and validation\n- **Async Command Execution**: All commands support concurrent operations\n- **Unified Error Handling**: Consistent error reporting across all commands\n\n**Key Commands Architecture:**\n\n- [`install`](cli/install.md) - Tool installation coordination\n- [`use`](cli/use.md) - Tool activation and configuration management\n- [`run`](cli/run.md) - Task execution with dependency resolution\n- [`env`](cli/env.md) - Environment variable management\n- [`shell`](cli/shell.md) - Shell integration and activation\n\n### Backend System ([`src/backend/`](https://github.com/jdx/mise/tree/main/src/backend/))\n\nThe backend system is mise's core abstraction for tool management, implementing a trait-based architecture:\n\n```rust\npub trait Backend: Debug + Send + Sync {\n    async fn list_remote_versions(&self, config: &Arc<Config>) -> Result<Vec<String>>;\n    async fn install_version(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion>;\n    async fn uninstall_version(&self, tv: &ToolVersion) -> Result<()>;\n    // ... additional methods for lifecycle management\n}\n```\n\n**Backend Categories:**\n\n- **Core Backends**: Native Rust implementations for maximum performance\n- **Language Package Managers**: npm, pipx, cargo, gem, go modules\n- **Universal Installers**: github (GitHub releases), aqua (comprehensive package management)\n- **Plugin Systems**: [backend plugins](backend-plugin-development.md) (enhanced methods), [tool plugins](tool-plugin-development.md) (hook-based), [asdf plugins](asdf-legacy-plugins.md) (legacy)\n\nFor guidance on implementing new backends, see the [Contributing Guide](contributing.md#adding-backends). For detailed backend system design, see [Backend Architecture](dev-tools/backend_architecture.md).\n\n### Configuration System ([`src/config/`](https://github.com/jdx/mise/tree/main/src/config/))\n\nA hierarchical configuration system that merges settings from multiple config files:\n\n**Config Trait Architecture:**\n\n```rust\npub trait ConfigFile: Debug + Send + Sync {\n    fn get_path(&self) -> &Path;\n    fn to_tool_request_set(&self) -> Result<ToolRequestSet>;\n    fn env_entries(&self) -> Result<Vec<EnvDirective>>;\n    fn tasks(&self) -> Vec<&Task>;\n    // ... additional configuration methods\n}\n```\n\n**Concrete Implementations:**\n\n- `MiseToml` - Primary configuration format with full feature support\n- `ToolVersions` - asdf compatibility layer\n- `IdiomaticVersion` - Language-specific version files (`.node-version`, etc.)\n\n**Configuration Hierarchy:** See [Configuration Documentation](configuration.md) for the complete hierarchy and precedence rules.\n\n### Toolset Management ([`src/toolset/`](https://github.com/jdx/mise/tree/main/src/toolset/))\n\nCoordinates tool resolution, installation, and environment setup:\n\n**Core Components:**\n\n- `Toolset` - Immutable collection of resolved tools for a context\n- `ToolVersion` - Represents a specific, resolved tool version (e.g., `node@latest` becomes `node@18.17.0`)\n- `ToolRequest` - User's tool specification (e.g., `node@18`, `python@latest`)\n- `ToolsetBuilder` - Constructs toolsets from configuration with dependency resolution\n\n**Tool Resolution Pipeline:**\n\n1. **Configuration Parsing**: Extract tool requirements from config files\n2. **Version Resolution**: Resolve version specifications (`latest`, `prefix:1.2`, `sub-1:latest`, etc.) to concrete versions\n3. **Backend Selection**: Choose appropriate backend for each tool\n4. **Dependency Analysis**: Resolve tool dependencies (e.g., npm requires Node.js)\n5. **Installation Coordination**: Install missing tools in dependency order\n6. **Environment Configuration**: Set up PATH and environment variables\n\n### Task System ([`src/task/`](https://github.com/jdx/mise/tree/main/src/task/))\n\nSophisticated task execution with dependency graph management:\n\n**Architecture Components:**\n\n- `Task` - Task definition with metadata, dependencies, and execution configuration\n- `Deps` - Dependency graph manager using `petgraph` for DAG operations\n- `TaskFileProvider` - Discovers tasks from files and configuration\n- Parallel execution engine with configurable concurrency\n\n**Task Discovery:**\n\n1. [File-based tasks](tasks/file-tasks.md) from configured directories\n2. [TOML-defined tasks](tasks/toml-tasks.md) in configuration files\n3. Inherited tasks from parent directories\n\n**Dependency Resolution:**\n\n- Uses directed acyclic graph (DAG) for dependency modeling\n- Supports multiple dependency types: `depends`, `depends_post`, `wait_for`\n- Parallel execution within dependency constraints\n- Circular dependency detection and prevention\n\nSee the [Task Documentation](tasks/) for complete usage details and configuration options, and [Task Architecture](tasks/architecture.md) for detailed system design.\n\n### Plugin System ([`src/plugins/`](https://github.com/jdx/mise/tree/main/src/plugins/))\n\nExtensibility layer supporting multiple plugin architectures:\n\n**Plugin Trait:**\n\n```rust\npub trait Plugin: Debug + Send {\n    fn name(&self) -> &str;\n    fn path(&self) -> PathBuf;\n    async fn install(&self, config: &Arc<Config>, pr: &dyn SingleReport) -> Result<()>;\n    async fn update(&self, pr: &dyn SingleReport, gitref: Option<String>) -> Result<()>;\n    // ... lifecycle management methods\n}\n```\n\n**Plugin Types:**\n\n- **Backend Plugins**: Enhanced plugins with backend methods for managing multiple tools\n- **Tool Plugins**: Hook-based plugins using the traditional vfox format\n- **asdf Plugins**: Legacy plugins compatible with the asdf plugin ecosystem (Linux/macOS only)\n\nFor complete plugin documentation, see [Plugin Guide](plugins.md).\n\n### Shell Integration ([`src/shell/`](https://github.com/jdx/mise/tree/main/src/shell/))\n\nShell-specific code generation that abstracts commands like `mise env` and contains all shell differences in one place:\n\n**Shell Trait:**\n\n```rust\npub trait Shell: Display {\n    fn activate(&self, opts: ActivateOptions) -> String;\n    fn set_env(&self, k: &str, v: &str) -> String;\n    fn unset_env(&self, k: &str) -> String;\n    // ... shell-specific methods\n}\n```\n\n**Supported Shells:** See [`mise activate`](cli/activate.md) documentation for the complete list\n**Shell Abstractions:** Environment variable setting, PATH modification, command execution\n\n### Environment Management ([`src/env*.rs`](https://github.com/jdx/mise/tree/main/src/))\n\nHelpers for working with environment variables:\n\n- `EnvDiff` - Tracks and applies environment changes\n- `EnvDirective` - Configuration-based environment variable management\n- `PathEnv` - Intelligent PATH manipulation with precedence rules\n- Context-aware resolution with config layering\n\nFor environment setup and configuration, see [Environment Documentation](environments/).\n\n### Caching System ([`src/cache.rs`](https://github.com/jdx/mise/blob/main/src/cache.rs))\n\nGeneric caching backed by files, using msgpack serialization with zstd compression:\n\n- `CacheManager<T>` - Generic caching with TTL support\n- Data serialized with msgpack and compressed with zstd for efficient storage\n- Automatic cache invalidation based on file timestamps\n- Per-backend cache isolation for data integrity\n\n## Test Architecture\n\nmise employs a multi-layered testing strategy that combines different testing approaches for thorough validation across its complex feature set.\n\n**Testing Strategy Overview:**\n\n1. **Unit Tests** - Rust `#[test]` functions embedded in source files\n2. **End-to-End (E2E) Tests** - Bash-based integration tests with complete environment isolation\n3. **Snapshot Tests** - Using `insta` crate for complex output validation\n\n::: tip Testing Philosophy\n**Most tests in mise are end-to-end tests, and this is generally the preferred approach** for new functionality. E2E tests provide thorough validation of real-world usage scenarios and catch integration issues that unit tests might miss. However, **E2E tests can be challenging to run locally** due to environment dependencies and setup complexity. For development and CI purposes, it's often easier to run tests on GitHub Actions where the environment is consistent and properly configured.\n\nSee the [Contributing Guide](contributing.md#testing) for detailed testing setup and guidelines.\n:::\n\n### Unit Tests ([`src/` modules](https://github.com/jdx/mise/tree/main/src/))\n\n**Structure and Characteristics:**\n\n- **Location**: Embedded within source files using `mod tests` blocks\n- **Test Runner**: Standard Rust `cargo test`\n- **Dependencies**: `pretty_assertions`, `insta`, `test-log`, `ctor`\n- **Coverage**: ~50+ test modules covering all major functionality\n\n```rust\nmod tests {\n    use insta::assert_snapshot;\n    use pretty_assertions::assert_eq;\n    use crate::config::Config;\n    use super::*;\n\n    #[tokio::test]\n    async fn test_hash_to_str() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(hash_to_str(&\"foo\"), \"e1b19adfb2e348a2\");\n    }\n}\n```\n\n**Test Environment Setup:**\n\n- **Global Setup**: Uses `ctor::ctor` in [`src/test.rs`](https://github.com/jdx/mise/blob/main/src/test.rs) for test environment initialization\n- **Isolated Environment**: Each test gets a clean environment with custom `HOME`, cache, and config directories\n- **Async Support**: Extensive use of `#[tokio::test]` for async testing\n\n### End-to-End Tests ([`e2e/`](https://github.com/jdx/mise/tree/main/e2e/))\n\n**Architecture:**\n\n```\ne2e/\n├── run_test          # Single test executor with environment isolation\n├── run_all_tests     # Test orchestrator with parallel execution\n├── assert.sh         # Rich assertion library\n├── cli/              # CLI command tests\n│   ├── test_use      # Testing tool activation and configuration\n│   ├── test_install  # Testing tool installation\n│   ├── test_upgrade  # Testing tool upgrades\n│   ├── test_uninstall # Testing tool removal\n│   └── test_version  # Testing version commands\n├── backend/          # Backend-specific tests\n│   ├── test_aqua     # Testing aqua package manager\n│   ├── test_asdf     # Testing asdf plugin compatibility\n│   └── test_npm      # Testing npm backend\n├── tasks/            # Task system tests\n│   ├── test_task_deps # Testing task dependencies\n│   ├── test_task_run_depends # Testing task execution order\n│   ├── test_task_ls  # Testing task listing\n│   └── test_task_info # Testing task metadata\n├── config/           # Configuration tests\n│   ├── test_config_ls # Testing configuration listing\n│   └── test_config_set # Testing configuration updates\n└── [other domains]/  # Additional test categories\n```\n\n**Environment Isolation System:**\n\nEach test runs in complete isolation with temporary directories:\n\n```bash\nsetup_isolated_env() {\n  TEST_ISOLATED_DIR=\"$(mktemp --tmpdir --directory \"$(basename \"$TEST\").XXXXXX\")\"\n  TEST_HOME=\"$TEST_ISOLATED_DIR/home\"\n  MISE_DATA_DIR=\"$TEST_HOME/.local/share/mise\"\n  MISE_CACHE_DIR=\"$TEST_HOME/.cache/mise\"\n  # ... complete environment isolation\n}\n```\n\n**Rich Assertion Framework:**\n\nThe [`assert.sh`](https://github.com/jdx/mise/blob/main/e2e/assert.sh) provides rich test utilities:\n\n```bash\n# Basic assertions\nassert \"command\" \"expected_output\"\nassert_contains \"command\" \"substring\"\nassert_fail \"command\" \"error_message\"\n\n# JSON testing\nassert_json \"command\" '{\"key\": \"value\"}'\nassert_json_partial_object \"command\" \"field1,field2\" '{\"field1\": \"value1\"}'\n\n# File system assertions\nassert_directory_exists \"path\"\nassert_directory_empty \"path\"\n```\n\n**Test Categories:**\n\n- **CLI Tests**: Validate all command-line interfaces and argument parsing\n- **Backend Tests**: Test tool installation, version resolution, and backend integration\n- **Task Tests**: Validate task execution, dependency resolution, and parallel execution\n- **Configuration Tests**: Test configuration parsing, hierarchy, and environment variable handling\n\n### Windows Testing\n\n**Windows-Specific Tests ([`e2e-win/`](https://github.com/jdx/mise/tree/main/e2e-win/)):**\n\n- **Language**: PowerShell scripts (`.ps1`)\n- **Focus**: Windows-specific functionality and cross-platform compatibility\n- **Coverage**: Core tools like Go, Java, Node.js, Python, Rust\n\n```powershell\nDescribe \"go\" {\n    It \"installs go\" {\n        mise install go@latest\n        go version | Should -Match \"go version\"\n    }\n}\n```\n\n### Snapshot Testing ([`src/snapshots/`](https://github.com/jdx/mise/tree/main/src/snapshots/))\n\n**Implementation:**\n\n- **Crate**: Uses `insta` for snapshot testing with 11 snapshot files\n- **Format**: Stores expected outputs as `.snap` files\n- **Coverage**: Complex outputs like directory listings, configuration parsing, environment diffs\n\n```rust\n#[tokio::test]\nasync fn test_parse() {\n    let diff = DirenvDiff::parse(input).unwrap();\n    assert_snapshot!(diff);  // Creates/validates snapshot\n}\n```\n\n### Test Infrastructure Features\n\n**Performance and Utility Tests ([`xtasks/test/`](https://github.com/jdx/mise/tree/main/xtasks/test/)):**\n\n- **Performance Testing**: `perf` script for benchmarking\n- **Coverage Testing**: `coverage` script for test coverage analysis\n- **E2E Runner**: `e2e` script with filtering capabilities\n\n**Test Data Management ([`test/`](https://github.com/jdx/mise/tree/main/test/)):**\n\n```\ntest/\n├── config/           # Test-specific configs\n├── cwd/              # Test working directories\n├── data/             # Test plugins and mock data\n├── fixtures/         # Sample configuration files\n├── plugins/          # Test plugin definitions\n└── state/            # Test state directory\n```\n\n**Test Execution Modes:**\n\n- **Fast Tests**: Regular tests that run in CI\n- **Slow Tests**: Marked with `_slow` suffix, skipped unless `TEST_ALL=1`\n- **Tranche Support**: Tests can be split across parallel runners using `TEST_TRANCHE_COUNT`\n\n**Developer Experience Features:**\n\n- **Environment Safety**: Complete isolation prevents tests from affecting user's actual mise installation\n- **Parallel Execution**: E2E tests support parallel execution with proper isolation\n- **Rich Reporting**: Detailed test timing, environment preservation on failure for debugging\n- **Cross-Platform Validation**: Automated testing on multiple operating systems\n\n**Running Tests:**\n\n```bash\n# Run all unit tests\ncargo test\n\n# Run all E2E tests\n./e2e/run_all_tests\n\n# Run specific E2E test\n./e2e/run_test test_install\n\n# Run with coverage\n./xtasks/test/coverage\n\n# Performance testing\n./xtasks/test/perf\n```\n\nFor complete development setup and testing procedures, see the [Contributing Guide](contributing.md).\n\nThis robust test architecture ensures mise's reliability across its complex feature set, including tool management, environment configuration, task execution, and multi-platform support.\n\n## Related Architecture Documentation\n\nFor deeper understanding of specific subsystems:\n\n- **[Task Architecture](tasks/architecture.md)** - Detailed design of the task dependency system, parallel execution engine, and task discovery mechanisms\n- **[Backend Architecture](dev-tools/backend_architecture.md)** - In-depth guide to backend types, the trait system, and how different installation methods work\n"
  },
  {
    "path": "docs/asdf-legacy-plugins.md",
    "content": "# asdf (Legacy) Plugins\n\n::: warning\nasdf plugins are considered legacy. For new tools, prefer [vfox plugins](/dev-tools/backends/vfox.html) which are written in Lua, work cross-platform (including Windows), and have access to built-in modules. See the [feature comparison](/dev-tools/backends/asdf.html#feature-comparison-asdf-vs-vfox) and [hook migration table](/dev-tools/backends/asdf.html#hook-migration-asdf-to-vfox) for details.\n:::\n\nmise maintains compatibility with the asdf plugin ecosystem through its asdf backend. These plugins are considered legacy because they have limitations compared to mise's modern plugin system.\n\n## What are asdf (Legacy) Plugins?\n\nasdf plugins are shell script-based plugins that follow the asdf plugin specification. They were the original way to extend tool management in the asdf ecosystem and are now supported by mise for backward compatibility.\n\n## Limitations\n\nasdf plugins have several limitations compared to mise's modern plugin system:\n\n- **Platform Support**: Only work on Linux and macOS (no Windows support)\n- **Performance**: Shell script execution is slower than mise's native backends\n- **Features**: Limited compared to modern backends like aqua, github, or tool/backend plugins\n- **Maintenance**: Harder to maintain and debug\n- **Security**: Less secure than sandboxed modern backends\n\n## When to Use asdf (Legacy) Plugins\n\nOnly use asdf plugins when:\n\n- The tool is not available through modern backends (aqua, github, etc.)\n- You need compatibility with existing asdf workflows\n- The tool requires complex shell-based installation logic that can't be handled by modern backends\n\n**For new tools, consider these alternatives first:**\n\n1. [aqua backend](dev-tools/backends/aqua.md) - Preferred for GitHub releases\n2. [github backend](dev-tools/backends/github.md) - Simple GitHub releases\n3. [Language package managers](dev-tools/backends/) - npm, pipx, cargo, gem, etc.\n4. [backend plugins](backend-plugin-development.md) - Enhanced plugins with backend methods\n5. [tool plugins](tool-plugin-development.md) - Hook-based cross-platform plugins\n\n## Installing asdf (Legacy) Plugins\n\n### From the Registry\n\nMost popular asdf plugins are available through mise's registry:\n\n```bash\n# Install from registry shorthand\nmise use postgres@15\n\n# This is equivalent to\nmise use asdf:mise-plugins/mise-postgres@15\n```\n\n### From Git Repository\n\n```bash\n# Install plugin directly from repository\nmise plugin install <plugin-name> <git-url>\n\n# Example: PostgreSQL plugin\nmise plugin install postgres https://github.com/mise-plugins/mise-postgres\n```\n\n### Manual Installation\n\n```bash\n# Add plugin manually\nmise plugin add postgres https://github.com/mise-plugins/mise-postgres\n\n# Install tool version\nmise install postgres@15.0.0\n\n# Use the tool\nmise use postgres@15.0.0\n```\n\n## Plugin Structure\n\nasdf plugins follow this directory structure:\n\n```\nplugin-name/\n├── bin/\n│   ├── list-all          # List all available versions\n│   ├── download          # Download source code/binary\n│   ├── install           # Install the tool\n│   ├── latest-stable     # Get latest stable version [optional]\n│   ├── help.overview     # Plugin description [optional]\n│   ├── help.deps         # Plugin dependencies [optional]\n│   ├── help.config       # Plugin configuration [optional]\n│   ├── help.links        # Plugin links [optional]\n│   ├── list-legacy-filenames  # Legacy version files [optional]\n│   ├── parse-legacy-file # Parse legacy version files [optional]\n│   ├── post-plugin-add   # Post plugin addition hook [optional]\n│   ├── post-plugin-update # Post plugin update hook [optional]\n│   ├── pre-plugin-remove # Pre plugin removal hook [optional]\n│   └── exec-env          # Set execution environment [optional]\n├── lib/                  # Shared library code [optional]\n└── README.md\n```\n\n## Required Scripts\n\n### bin/list-all\n\nLists all available versions of the tool:\n\n```bash\n#!/usr/bin/env bash\n# List all available versions\ncurl -s https://api.github.com/repos/owner/repo/releases |\n  grep '\"tag_name\":' |\n  sed -E 's/.*\"([^\"]+)\".*/\\1/' |\n  sort -V\n```\n\n### bin/download\n\nDownloads the tool source/binary:\n\n```bash\n#!/usr/bin/env bash\nset -e\n\n# Input variables from mise\n# ASDF_INSTALL_TYPE (version or ref)\n# ASDF_INSTALL_VERSION (version number or git ref)\n# ASDF_INSTALL_PATH (where to install)\n# ASDF_DOWNLOAD_PATH (where to download)\n\nversion=\"$ASDF_INSTALL_VERSION\"\ndownload_path=\"$ASDF_DOWNLOAD_PATH\"\n\n# Download logic here\ncurl -Lo \"$download_path/archive.tar.gz\" \\\n  \"https://github.com/owner/repo/archive/v${version}.tar.gz\"\n```\n\n### bin/install\n\nInstalls the tool:\n\n```bash\n#!/usr/bin/env bash\nset -e\n\n# Input variables from mise\n# ASDF_INSTALL_TYPE (version or ref)\n# ASDF_INSTALL_VERSION (version number or git ref)\n# ASDF_INSTALL_PATH (where to install)\n# ASDF_DOWNLOAD_PATH (where source is downloaded)\n\ninstall_path=\"$ASDF_INSTALL_PATH\"\ndownload_path=\"$ASDF_DOWNLOAD_PATH\"\n\n# Extract and install\ncd \"$download_path\"\ntar -xzf archive.tar.gz --strip-components=1\nmake install PREFIX=\"$install_path\"\n```\n\n## Optional Scripts\n\n### bin/exec-env\n\nSet environment variables when executing tools:\n\n```bash\n#!/usr/bin/env bash\n\n# Set environment variables\nexport TOOL_HOME=\"$ASDF_INSTALL_PATH\"\nexport PATH=\"$ASDF_INSTALL_PATH/bin:$PATH\"\n```\n\n### bin/latest-stable\n\nGet the latest stable version:\n\n```bash\n#!/usr/bin/env bash\ncurl -s https://api.github.com/repos/owner/repo/releases/latest |\n  grep '\"tag_name\":' |\n  sed -E 's/.*\"([^\"]+)\".*/\\1/'\n```\n\n### bin/list-legacy-filenames\n\nList legacy version file names:\n\n```bash\n#!/usr/bin/env bash\necho \".tool-version\"\necho \".tool-versions\"\n```\n\n### bin/parse-legacy-file\n\nParse legacy version files:\n\n```bash\n#!/usr/bin/env bash\ncat \"$1\" | head -n 1\n```\n\n## Environment Variables\n\nasdf plugins have access to these environment variables:\n\n- `ASDF_INSTALL_TYPE` - `version` or `ref`\n- `ASDF_INSTALL_VERSION` - Version number or git ref\n- `ASDF_INSTALL_PATH` - Installation directory\n- `ASDF_DOWNLOAD_PATH` - Download directory\n- `ASDF_PLUGIN_PATH` - Plugin directory\n- `ASDF_PLUGIN_PREV_REF` - Previous git ref (for updates)\n- `ASDF_PLUGIN_POST_REF` - New git ref (for updates)\n- `ASDF_CMD_FILE` - Path to executable being run\n\n## Best Practices\n\n### Error Handling\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail  # Exit on error, undefined vars, pipe failures\n\n# Check dependencies\ncommand -v curl >/dev/null 2>&1 || {\n  echo \"Error: curl is required\" >&2\n  exit 1\n}\n```\n\n### Cross-Platform Compatibility\n\n```bash\n#!/usr/bin/env bash\n\n# Detect platform\ncase \"$(uname -s)\" in\n  Darwin*) platform=\"darwin\" ;;\n  Linux*)  platform=\"linux\" ;;\n  *)       echo \"Unsupported platform\" >&2; exit 1 ;;\nesac\n\ncase \"$(uname -m)\" in\n  x86_64) arch=\"amd64\" ;;\n  arm64)  arch=\"arm64\" ;;\n  *)      echo \"Unsupported architecture\" >&2; exit 1 ;;\nesac\n```\n\n### Version Parsing\n\n```bash\n#!/usr/bin/env bash\n\n# Parse semantic version\nparse_version() {\n  local version=\"$1\"\n  # Remove 'v' prefix if present\n  version=\"${version#v}\"\n  echo \"$version\"\n}\n```\n\n## Testing Plugins\n\n### Local Development\n\n```bash\n# Link plugin for development\nmise plugin add my-plugin /path/to/local/plugin\n\n# Test basic functionality\nmise list-all my-plugin\nmise install my-plugin@1.0.0\nmise which my-plugin\n```\n\n### Debugging\n\n```bash\n# Enable debug mode\nexport MISE_DEBUG=1\n\n# Or use --verbose flag\nmise install --verbose my-plugin@1.0.0\n```\n\n## Example Plugin\n\nHere's a minimal example for a fictional tool:\n\n```bash\n#!/usr/bin/env bash\n# bin/list-all\ncurl -s \"https://api.github.com/repos/example/tool/releases\" |\n  grep '\"tag_name\":' |\n  sed -E 's/.*\"v([^\"]+)\".*/\\1/' |\n  sort -V\n```\n\n```bash\n#!/usr/bin/env bash\n# bin/download\nset -e\nversion=\"$ASDF_INSTALL_VERSION\"\nplatform=$(uname -s | tr '[:upper:]' '[:lower:]')\narch=$(uname -m)\n\nurl=\"https://github.com/example/tool/releases/download/v${version}/tool-${platform}-${arch}.tar.gz\"\ncurl -fSL \"$url\" -o \"$ASDF_DOWNLOAD_PATH/tool.tar.gz\"\n```\n\n```bash\n#!/usr/bin/env bash\n# bin/install\nset -e\ncd \"$ASDF_DOWNLOAD_PATH\"\ntar -xzf tool.tar.gz\ncp tool \"$ASDF_INSTALL_PATH/bin/\"\nchmod +x \"$ASDF_INSTALL_PATH/bin/tool\"\n```\n\n## Migration Path\n\nConsider migrating from asdf plugins to modern alternatives:\n\n1. **Check if tool is available in [aqua registry](https://aquaproj.github.io/aqua-registry/)**\n2. **Use [github backend](dev-tools/backends/github.md) for simple GitHub releases**\n3. **Create a [mise plugin](tool-plugin-development.md) for complex tools** - use the [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template) for a quick start\n4. **Use language-specific package managers** (npm, pipx, cargo, gem)\n\n## Community Resources\n\n- **[asdf Plugin List](https://github.com/asdf-vm/asdf-plugins)** - Official asdf plugin registry\n- **[mise-plugins Organization](https://github.com/mise-plugins)** - Community-maintained plugins\n- **[Plugin Template (asdf)](https://github.com/asdf-vm/asdf-plugin-template)** - Template for creating asdf plugins\n- **[Plugin Template (mise)](https://github.com/jdx/mise-tool-plugin-template)** - Modern template for creating mise plugins with Lua\n\n## Security Considerations\n\nasdf plugins execute arbitrary shell scripts, which poses security risks:\n\n- **Only install plugins from trusted sources**\n- **Review plugin code before installation**\n- **Avoid plugins with complex installation scripts when possible**\n- **Consider using modern backends for better security**\n\n## Next Steps\n\n- [Explore modern backends](dev-tools/backends/) for better alternatives\n- [Learn about backend plugins](backend-plugin-development.md) for enhanced functionality\n- [Learn about tool plugins](tool-plugin-development.md) for cross-platform support\n- [Check the registry](registry.md) for available tools\n"
  },
  {
    "path": "docs/backend-plugin-development.md",
    "content": "# Backend Plugin Development\n\n::: tip\nThe [mise-backend-plugin-template](https://github.com/jdx/mise-backend-plugin-template) provides a ready-to-use starting point with LuaCATS type definitions, stylua formatting, and hk linting pre-configured.\n:::\n\nBackend plugins in mise use enhanced backend methods to manage multiple tools using the `plugin:tool` format. These plugins are perfect for package managers, tool families, and custom installations that need to manage multiple related tools.\n\n## What are Backend Plugins?\n\nBackend plugins extend the standard vfox plugin system with enhanced backend methods. They support:\n\n- **Multiple Tools**: One plugin can manage multiple tools. For example, `vfox-npm` is the plugin which could install different types of tools like `prettier`, `eslint`, and other npm packages\n- **Cross-Platform Support**: Works on Windows, macOS, and Linux\n- **Flexible Architecture**: Modern plugin system with dedicated backend methods for enhanced functionality\n\n## Plugin Architecture\n\nBackend plugins are generally a git repository but can also be a directory (via `mise link`).\n\nBackend plugins are implemented in Lua (version 5.1 at the moment). They use three main backend methods implemented as individual files:\n\n- `hooks/backend_list_versions.lua` - Lists available versions for a tool\n- `hooks/backend_install.lua` - Installs a specific version of a tool\n- `hooks/backend_exec_env.lua` - Sets up environment variables for a tool\n\n## Backend Methods\n\n### BackendListVersions\n\nLists available versions for a tool:\n\n```lua\nfunction PLUGIN:BackendListVersions(ctx)\n    local tool = ctx.tool\n    local versions = {}\n\n    -- Your logic to fetch versions for the tool\n    -- Example: query an API, parse a registry, etc.\n\n    return {versions = versions}\nend\n```\n\n> [!WARNING]\n> **Version sorting**: The versions returned by `BackendListVersions` should be in ascending order (oldest to newest), sorted semantically (version `3.10.0` should not come before `3.2.0`). Mise does not apply any additional sorting to the versions returned by this method.\n\n### BackendInstall\n\nInstalls a specific version of a tool:\n\n```lua\nfunction PLUGIN:BackendInstall(ctx)\n    local tool = ctx.tool\n    local version = ctx.version\n    local install_path = ctx.install_path\n    local download_path = ctx.download_path\n    local options = ctx.options\n\n    -- Your logic to install the tool\n    -- Example: download files, extract archives, etc.\n    -- Access custom options via options[\"key\"] or options.key\n\n    return {}\nend\n```\n\n### BackendExecEnv\n\nSets up environment variables for a tool:\n\n```lua\nfunction PLUGIN:BackendExecEnv(ctx)\n    local install_path = ctx.install_path\n    local options = ctx.options\n\n    -- Your logic to set up environment variables\n    -- Example: add bin directories to PATH\n    -- Access custom options via options[\"key\"] or options.key\n\n    return {\n        env_vars = {\n            {key = \"PATH\", value = install_path .. \"/bin\"}\n        }\n    }\nend\n```\n\n## Creating a Backend Plugin\n\n### Using the Template Repository\n\nUse the dedicated [mise-backend-plugin-template](https://github.com/jdx/mise-backend-plugin-template) for creating backend plugins:\n\n```bash\n# Option 1: Use GitHub's template feature (recommended)\n# Visit https://github.com/jdx/mise-backend-plugin-template\n# Click \"Use this template\" to create your repository\n\n# Option 2: Clone and modify\ngit clone https://github.com/jdx/mise-backend-plugin-template my-backend-plugin\ncd my-backend-plugin\nrm -rf .git\ngit init\n```\n\nThe template includes:\n\n- Complete backend plugin structure with all required hooks\n- Modern development tooling (hk, stylua, luacheck, actionlint)\n- Comprehensive documentation and examples\n- CI/CD setup with GitHub Actions\n- Multiple implementation patterns for different backend types\n\n### 1. Plugin Structure\n\nCreate a directory with this structure:\n\n```\nmy-backend-plugin/\n├── metadata.lua                    # Plugin metadata\n├── hooks/\n│   ├── backend_list_versions.lua   # BackendListVersions hook\n│   ├── backend_install.lua         # BackendInstall hook\n│   └── backend_exec_env.lua        # BackendExecEnv hook\n└── Injection.lua                   # Runtime injection (auto-generated)\n```\n\n### 2. Basic metadata.lua\n\n```lua\nPLUGIN = {\n    name = \"vfox-npm\",\n    version = \"1.0.0\",\n    description = \"Backend plugin for npm packages\",\n    author = \"Your Name\"\n}\n```\n\n## Real-World Example: vfox-npm\n\nHere's the complete implementation of the vfox-npm plugin that manages npm packages:\n\n### metadata.lua\n\n```lua\nPLUGIN = {\n    name = \"vfox-npm\",\n    version = \"1.0.0\",\n    description = \"Backend plugin for npm packages\",\n    author = \"jdx\"\n}\n```\n\n### hooks/backend_list_versions.lua\n\n```lua\nfunction PLUGIN:BackendListVersions(ctx)\n    local cmd = require(\"cmd\")\n    local json = require(\"json\")\n\n    local result = cmd.exec(\"npm view \" .. ctx.tool .. \" versions --json\")\n    local versions = json.decode(result)\n\n    return {versions = versions}\nend\n```\n\n### hooks/backend_install.lua\n\n```lua\nfunction PLUGIN:BackendInstall(ctx)\n    local tool = ctx.tool\n    local version = ctx.version\n    local install_path = ctx.install_path\n\n    -- Install the package directly using npm install\n    local cmd = require(\"cmd\")\n    local npm_cmd = \"npm install \" .. tool .. \"@\" .. version .. \" --no-package-lock --no-save --silent\"\n    local result = cmd.exec(npm_cmd, {cwd = install_path})\n\n    -- If we get here, the command succeeded\n    return {}\nend\n```\n\n### hooks/backend_exec_env.lua\n\n```lua\nfunction PLUGIN:BackendExecEnv(ctx)\n    local file = require(\"file\")\n    return {\n        env_vars = {\n            {key = \"PATH\", value = file.join_path(ctx.install_path, \"node_modules\", \".bin\")}\n        }\n    }\nend\n```\n\n## Usage Example\n\nThe plugin name doesn't have to match the repository name. The backend prefix will match whatever name the backend plugin was installed as.\n\n```bash\n# Install the plugin\nmise plugin install vfox-npm https://github.com/jdx/vfox-npm\n\n# List available versions\nmise ls-remote vfox-npm:prettier\n\n# Install a specific version\nmise install vfox-npm:prettier@3.0.0\n\n# Use in a project\nmise use vfox-npm:prettier@latest\n\n# Execute the tool\nmise exec -- prettier --help\n```\n\n> **Tip**: This naming flexibility could potentially be used to have a very complex plugin backend that would behave differently based on what it was named. For example, you could install the same plugin with different names to configure different behaviors or access different tool registries.\n\n## Context Variables\n\nBackend plugins receive context through the `ctx` parameter passed to each hook function:\n\n### BackendListVersions Context\n\n| Variable   | Description   | Example      |\n| ---------- | ------------- | ------------ |\n| `ctx.tool` | The tool name | `\"prettier\"` |\n\n### BackendInstall Context\n\n| Variable            | Description            | Example                                                            |\n| ------------------- | ---------------------- | ------------------------------------------------------------------ |\n| `ctx.tool`          | The tool name          | `\"prettier\"`                                                       |\n| `ctx.version`       | The requested version  | `\"3.0.0\"`                                                          |\n| `ctx.install_path`  | Installation directory | `\"/home/user/.local/share/mise/installs/vfox-npm-prettier/3.0.0\"`  |\n| `ctx.download_path` | Download directory     | `\"/home/user/.local/share/mise/downloads/vfox-npm-prettier/3.0.0\"` |\n\n### BackendExecEnv Context\n\n| Variable           | Description            | Example                                                           |\n| ------------------ | ---------------------- | ----------------------------------------------------------------- |\n| `ctx.tool`         | The tool name          | `\"prettier\"`                                                      |\n| `ctx.version`      | The requested version  | `\"3.0.0\"`                                                         |\n| `ctx.install_path` | Installation directory | `\"/home/user/.local/share/mise/installs/vfox-npm-prettier/3.0.0\"` |\n\n## Testing Your Plugin\n\n### Local Development\n\n```bash\n# Link your plugin for development\nmise plugin link my-plugin /path/to/my-plugin\n\n# Test listing versions\nmise ls-remote my-plugin:some-tool\n\n# Test installation\nmise use my-plugin:some-tool@1.0.0\n\n# Test execution\nmise exec -- some-tool --version\n```\n\n### Debug Mode\n\nUse debug mode to see detailed plugin execution:\n\n```bash\nmise --debug install my-plugin:some-tool@1.0.0\n```\n\n## Best Practices\n\n### Error Handling\n\nProvide more meaningful error messages:\n\n```lua\nfunction PLUGIN:BackendListVersions(ctx)\n    local tool = ctx.tool\n\n    -- Validate tool name\n    if not tool or tool == \"\" then\n        error(\"Tool name cannot be empty\")\n    end\n\n    -- Execute command with error checking\n    local cmd = require(\"cmd\")\n    local result = cmd.exec(\"npm view \" .. tool .. \" versions --json 2>/dev/null\")\n    if not result or result:match(\"npm ERR!\") then\n        error(\"Failed to fetch versions for \" .. tool .. \": \" .. (result or \"no output\"))\n    end\n\n    -- Parse JSON response\n    local json = require(\"json\")\n    local success, npm_versions = pcall(json.decode, result)\n    if not success or not npm_versions then\n        error(\"Failed to parse versions for \" .. tool)\n    end\n\n    -- Return versions or error if none found\n    local versions = {}\n    if type(npm_versions) == \"table\" then\n        for i = #npm_versions, 1, -1 do\n            table.insert(versions, npm_versions[i])\n        end\n    end\n\n    if #versions == 0 then\n        error(\"No versions found for \" .. tool)\n    end\n\n    return {versions = versions}\nend\n```\n\n### Regex Parsing\n\nParse versions with regex:\n\n```lua\nlocal function parse_version(version_string)\n    -- Remove prefixes like 'v' or 'release-'\n    return version_string:gsub(\"^v\", \"\"):gsub(\"^release%-\", \"\")\nend\n```\n\n### Path Handling\n\nUse cross-platform path handling:\n\n```lua\nlocal function join_path(...)\n    local sep = package.config:sub(1,1) -- Get OS path separator\n    return table.concat({...}, sep)\nend\n\nlocal bin_path = join_path(install_path, \"bin\")\n```\n\n### Cross-Platform Commands\n\nHandle different operating systems:\n\n```lua\nlocal function create_dir(path)\n    local cmd = RUNTIME.osType == \"Windows\" and \"mkdir\" or \"mkdir -p\"\n    os.execute(cmd .. \" \" .. path)\nend\n```\n\n## Advanced Features\n\n### Conditional Installation\n\nDifferent installation logic based on tool or version:\n\n```lua\nfunction PLUGIN:BackendInstall(ctx)\n    local tool = ctx.tool\n    local version = ctx.version\n    local install_path = ctx.install_path\n\n    -- Create install directory\n    os.execute(\"mkdir -p \" .. install_path)\n\n    if tool == \"special-tool\" then\n        -- Special installation logic\n        local cmd = require(\"cmd\")\n        local npm_cmd = \"cd \" .. install_path .. \" && npm install \" .. tool .. \"@\" .. version .. \" --no-package-lock --no-save --silent 2>/dev/null\"\n        local result = cmd.exec(npm_cmd)\n        if result:match(\"npm ERR!\") then\n            error(\"Failed to install \" .. tool .. \"@\" .. version)\n        end\n    else\n        -- Default installation logic\n        local cmd = require(\"cmd\")\n        local npm_cmd = \"cd \" .. install_path .. \" && npm install \" .. tool .. \"@\" .. version .. \" --no-package-lock --no-save --silent 2>/dev/null\"\n        local result = cmd.exec(npm_cmd)\n        if result:match(\"npm ERR!\") then\n            error(\"Failed to install \" .. tool .. \"@\" .. version)\n        end\n    end\n\n    return {}\nend\n```\n\n### Environment Detection\n\nvfox automatically injects runtime information into your plugin:\n\n```lua\nfunction PLUGIN:BackendInstall(ctx)\n    -- Platform-specific installation using injected RUNTIME object\n    if RUNTIME.osType == \"darwin\" then\n        -- macOS installation logic\n    elseif RUNTIME.osType == \"linux\" then\n        -- Linux installation logic\n    elseif RUNTIME.osType == \"windows\" then\n        -- Windows installation logic\n    end\n\n    return {}\nend\n```\n\nThe `RUNTIME` object provides:\n\n- `RUNTIME.osType`: Operating system type (Windows, Linux, Darwin)\n- `RUNTIME.archType`: Architecture (amd64, arm64, etc.)\n- `RUNTIME.envType`: libc environment type (`\"gnu\"` on glibc Linux, `\"musl\"` on musl Linux, `nil` on Windows/macOS and undetected systems)\n- `RUNTIME.version`: vfox runtime version\n- `RUNTIME.pluginDirPath`: Plugin directory path\n\n### Multiple Environment Variables\n\nSet multiple environment variables:\n\n```lua\nfunction PLUGIN:BackendExecEnv(ctx)\n    -- Add node_modules/.bin to PATH for npm-installed binaries\n    local bin_path = ctx.install_path .. \"/node_modules/.bin\"\n    return {\n        env_vars = {\n            {key = \"PATH\", value = bin_path},\n            {key = ctx.tool:upper() .. \"_HOME\", value = ctx.install_path},\n            {key = ctx.tool:upper() .. \"_VERSION\", value = ctx.version}\n        }\n    }\nend\n```\n\n## Performance Optimization\n\n### Caching\n\nTODO: We need caching support for [Shared Lua modules](plugin-lua-modules.md).\n\n## Next Steps\n\n- [Start with the backend plugin template](https://github.com/jdx/mise-backend-plugin-template)\n- [Learn about Tool Plugin Development](tool-plugin-development.md)\n- [Explore available Lua modules](plugin-lua-modules.md)\n- [Publishing your plugin](plugin-publishing.md)\n- [View the vfox-npm plugin source](https://github.com/jdx/vfox-npm)\n"
  },
  {
    "path": "docs/cache-behavior.md",
    "content": "# Cache Behavior\n\nmise makes use of caching in many places in order to be efficient. The details about how long to keep\ncache for should eventually all be configurable. There may be gaps in the current behavior where\nthings are hardcoded, but I'm happy to add more settings to cover whatever config is needed.\n\nBelow I explain the behavior it uses around caching. If you're seeing behavior where things don't appear\nto be updating, this is a good place to start.\n\n## Plugin/Runtime Cache\n\nEach plugin has a cache that's stored in `~/$MISE_CACHE_DIR/<PLUGIN>`. It stores\nthe list of versions available for that plugin (`mise ls-remote <PLUGIN>`), the idiomatic filenames (see below),\nthe list of aliases, the bin directories within each runtime installation, and the result of\nrunning `exec-env` after the runtime was installed.\n\nRemote versions are updated daily by default. The file is zlib messagepack, if you want to view it you can\nrun the following (requires [msgpack-cli](https://github.com/msgpack/msgpack-cli)).\n\n```sh\ncat ~/$MISE_CACHE_DIR/node/remote_versions.msgpack.z | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;' | msgpack-cli decode\n```\n\nNote that the caching of `exec-env` may be problematic if the script isn't simply exporting\nstatic values. The vast majority of `exec-env` scripts only export static values.\n\nCaching `exec-env` massively improved the performance of mise since it requires calling bash\nevery time mise is initialized.\n\n## Environment Caching\n\nFor more advanced caching needs (including dynamic environment providers like secret managers),\nmise provides the [`env_cache`](/configuration/settings.html#env_cache) setting. When enabled,\nmise caches the computed environment to disk with encryption.\n\n```toml\n# ~/.config/mise/config.toml\n[settings]\nenv_cache = true\nenv_cache_ttl = \"1h\"  # optional, default is 1h\n```\n\nCache invalidation happens automatically when:\n\n- Any config file changes (mise.toml, .tool-versions, etc.)\n- Tool versions change\n- Settings change\n- mise version changes\n- TTL expires (configurable via `env_cache_ttl`)\n- Any watched files change (from modules or `_.source` directives)\n\nEnv plugins (vfox modules) can declare themselves cacheable by returning `{cacheable = true, watch_files = [...]}`\nfrom their `MiseEnv` hook. See [Env Plugin Development](/env-plugin-development.html) for details.\n\nDirectives can opt out of caching by setting `cacheable = false`:\n\n```toml\n[env]\nTIMESTAMP = { value = \"{{ now() }}\", cacheable = false }\n_.source = { file = \"dynamic.sh\", cacheable = false }\n```\n\n## Cache auto-pruning\n\nmise will automatically delete old files in its cache directory (configured with [`cache_prune_age`](https://mise.jdx.dev/configuration/settings.html#cache_prune_age)). Much of\nthe contents are also ignored by mise if they are >24 hours old or a few days. For this reason, it's likely wasteful to store this directory in CI jobs.\n"
  },
  {
    "path": "docs/cli/activate.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise activate`\n\n- **Usage**: `mise activate [FLAGS] [SHELL_TYPE]`\n- **Source code**: [`src/cli/activate.rs`](https://github.com/jdx/mise/blob/main/src/cli/activate.rs)\n\nInitializes mise in the current shell session\n\nThis should go into your shell's rc file or login shell.\nOtherwise, it will only take effect in the current session.\n(e.g. ~/.zshrc, ~/.zprofile, ~/.zshenv, ~/.bashrc, ~/.bash_profile, ~/.profile, ~/.config/fish/config.fish, or $PROFILE for powershell)\n\nTypically, this can be added with something like the following:\n\n```\necho 'eval \"$(mise activate zsh)\"' >> ~/.zshrc\n```\n\nHowever, this requires that \"mise\" is in your PATH. If it is not, you need to\nspecify the full path like this:\n\n```\necho 'eval \"$(/path/to/mise activate zsh)\"' >> ~/.zshrc\n```\n\nCustomize status output with `status` settings.\n\n## Arguments\n\n### `[SHELL_TYPE]`\n\nShell type to generate the script for\n\n**Choices:**\n\n- `bash`\n- `elvish`\n- `fish`\n- `nu`\n- `xonsh`\n- `zsh`\n- `pwsh`\n\n## Flags\n\n### `-q --quiet`\n\nSuppress non-error messages\n\n### `--no-hook-env`\n\nDo not automatically call hook-env\n\nThis can be helpful for debugging mise. If you run `eval \"$(mise activate --no-hook-env)\"`, then you can call `mise hook-env` manually which will output the env vars to stdout without actually modifying the environment. That way you can do things like `mise hook-env --trace` to get more information or just see the values that hook-env is outputting.\n\n### `--shims`\n\nUse shims instead of modifying PATH\nEffectively the same as:\n\n```\nPATH=\"$HOME/.local/share/mise/shims:$PATH\"\n```\n\n`mise activate --shims` does not support all the features of `mise activate`.\nSee <https://mise.jdx.dev/dev-tools/shims.html#shims-vs-path> for more information\n\nExamples:\n\n```\neval \"$(mise activate bash)\"\neval \"$(mise activate zsh)\"\nmise activate fish | source\nexecx($(mise activate xonsh))\n(&mise activate pwsh) | Out-String | Invoke-Expression\n```\n"
  },
  {
    "path": "docs/cli/backends/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise backends ls`\n\n- **Usage**: `mise backends ls`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/backends/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/backends/ls.rs)\n\nList built-in backends\n\nExamples:\n\n```\n$ mise backends ls\naqua\nasdf\ncargo\ncore\ndotnet\ngem\ngo\nnpm\npipx\nspm\nubi\nvfox\n```\n"
  },
  {
    "path": "docs/cli/backends.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise backends`\n\n- **Usage**: `mise backends <SUBCOMMAND>`\n- **Aliases**: `b`\n- **Source code**: [`src/cli/backends/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/backends/mod.rs)\n\nManage backends\n\n## Subcommands\n\n- [`mise backends ls`](/cli/backends/ls.md)\n"
  },
  {
    "path": "docs/cli/bin-paths.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise bin-paths`\n\n- **Usage**: `mise bin-paths [TOOL@VERSION]…`\n- **Source code**: [`src/cli/bin_paths.rs`](https://github.com/jdx/mise/blob/main/src/cli/bin_paths.rs)\n\nList all the active runtime bin paths\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to look up\ne.g.: ruby@3\n"
  },
  {
    "path": "docs/cli/cache/clear.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise cache clear`\n\n- **Usage**: `mise cache clear [PLUGIN]…`\n- **Aliases**: `c`\n- **Source code**: [`src/cli/cache/clear.rs`](https://github.com/jdx/mise/blob/main/src/cli/cache/clear.rs)\n\nDeletes all cache files in mise\n\n## Arguments\n\n### `[PLUGIN]…`\n\nPlugin(s) to clear cache for e.g.: node, python\n"
  },
  {
    "path": "docs/cli/cache/path.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise cache path`\n\n- **Usage**: `mise cache path`\n- **Aliases**: `dir`\n- **Source code**: [`src/cli/cache/path.rs`](https://github.com/jdx/mise/blob/main/src/cli/cache/path.rs)\n\nShow the cache directory path\n"
  },
  {
    "path": "docs/cli/cache/prune.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise cache prune`\n\n- **Usage**: `mise cache prune [-v --verbose…] [--dry-run] [PLUGIN]…`\n- **Aliases**: `p`\n- **Source code**: [`src/cli/cache/prune.rs`](https://github.com/jdx/mise/blob/main/src/cli/cache/prune.rs)\n\nRemoves stale mise cache files\n\nBy default, this command will remove files that have not been accessed in 30 days.\nChange this with the MISE_CACHE_PRUNE_AGE environment variable.\n\n## Arguments\n\n### `[PLUGIN]…`\n\nPlugin(s) to clear cache for e.g.: node, python\n\n## Flags\n\n### `-v --verbose…`\n\nShow pruned files\n\n### `--dry-run`\n\nJust show what would be pruned\n"
  },
  {
    "path": "docs/cli/cache.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise cache`\n\n- **Usage**: `mise cache <SUBCOMMAND>`\n- **Source code**: [`src/cli/cache/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/cache/mod.rs)\n\nManage the mise cache\n\nRun `mise cache` with no args to view the current cache directory.\n\n## Subcommands\n\n- [`mise cache clear [PLUGIN]…`](/cli/cache/clear.md)\n- [`mise cache path`](/cli/cache/path.md)\n- [`mise cache prune [-v --verbose…] [--dry-run] [PLUGIN]…`](/cli/cache/prune.md)\n"
  },
  {
    "path": "docs/cli/completion.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise completion`\n\n- **Usage**: `mise completion [--include-bash-completion-lib] [SHELL]`\n- **Source code**: [`src/cli/completion.rs`](https://github.com/jdx/mise/blob/main/src/cli/completion.rs)\n\nGenerate shell completions\n\n## Arguments\n\n### `[SHELL]`\n\nShell type to generate completions for\n\n**Choices:**\n\n- `bash`\n- `fish`\n- `powershell`\n- `zsh`\n\n## Flags\n\n### `--include-bash-completion-lib`\n\nInclude the bash completion library in the bash completion script\n\nThis is required for completions to work in bash, but it is not included by default\nyou may source it separately or enable this flag to enable it in the script.\n\nExamples:\n\n```\nmise completion bash --include-bash-completion-lib > ~/.local/share/bash-completion/completions/mise\nmise completion zsh  > /usr/local/share/zsh/site-functions/_mise\nmise completion fish > ~/.config/fish/completions/mise.fish\nmise completion powershell >> $PROFILE\n```\n"
  },
  {
    "path": "docs/cli/config/get.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise config get`\n\n- **Usage**: `mise config get [-f --file <FILE>] [KEY]`\n- **Source code**: [`src/cli/config/get.rs`](https://github.com/jdx/mise/blob/main/src/cli/config/get.rs)\n\nDisplay the value of a setting in a mise.toml file\n\n## Arguments\n\n### `[KEY]`\n\nThe path of the config to display\n\n## Flags\n\n### `-f --file <FILE>`\n\nThe path to the mise.toml file to edit\n\nIf not provided, the nearest mise.toml file will be used\n\nExamples:\n\n```\n$ mise toml get tools.python\n3.12\n```\n"
  },
  {
    "path": "docs/cli/config/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise config ls`\n\n- **Usage**: `mise config ls [FLAGS]`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/config/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/config/ls.rs)\n\nList config files currently in use\n\n## Flags\n\n### `-J --json`\n\nOutput in JSON format\n\n### `--no-header`\n\nDo not print table header\n\n### `--tracked-configs`\n\nList all tracked config files\n\nExamples:\n\n```\n$ mise config ls\nPath                        Tools\n~/.config/mise/config.toml  pitchfork\n~/src/mise/mise.toml        actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta\n```\n"
  },
  {
    "path": "docs/cli/config/set.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise config set`\n\n- **Usage**: `mise config set [-f --file <FILE>] [-t --type <TYPE>] <KEY> [VALUE]`\n- **Source code**: [`src/cli/config/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/config/set.rs)\n\nSet the value of a setting in a mise.toml file\n\n## Arguments\n\n### `<KEY>`\n\nThe path of the config to display\n\n### `[VALUE]`\n\nThe value to set the key to (optional if provided as KEY=VALUE)\n\n## Flags\n\n### `-f --file <FILE>`\n\nThe path to the mise.toml file to edit\n\nIf not provided, the nearest mise.toml file will be used\n\n### `-t --type <TYPE>`\n\n**Choices:**\n\n- `infer`\n- `string`\n- `integer`\n- `float`\n- `bool`\n- `list`\n- `set`\n\n**Default:** `infer`\n\nExamples:\n\n```\n$ mise config set tools.python 3.12\n$ mise config set settings.always_keep_download true\n$ mise config set env.TEST_ENV_VAR ABC\n$ mise config set settings.disable_tools --type list node,rust\n\n# Type for `settings` is inferred\n$ mise config set settings.jobs 4\n```\n"
  },
  {
    "path": "docs/cli/config.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise config`\n\n- **Usage**: `mise config [FLAGS] <SUBCOMMAND>`\n- **Aliases**: `cfg`\n- **Source code**: [`src/cli/config/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/config/mod.rs)\n\nManage config files\n\n## Flags\n\n### `-J --json`\n\nOutput in JSON format\n\n### `--no-header`\n\nDo not print table header\n\n### `--tracked-configs`\n\nList all tracked config files\n\n## Subcommands\n\n- [`mise config get [-f --file <FILE>] [KEY]`](/cli/config/get.md)\n- [`mise config ls [FLAGS]`](/cli/config/ls.md)\n- [`mise config set [-f --file <FILE>] [-t --type <TYPE>] <KEY> [VALUE]`](/cli/config/set.md)\n\nExamples:\n\n```\n$ mise config ls\nPath                        Tools\n~/.config/mise/config.toml  pitchfork\n~/src/mise/mise.toml        actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta\n```\n"
  },
  {
    "path": "docs/cli/deactivate.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise deactivate`\n\n- **Usage**: `mise deactivate`\n- **Source code**: [`src/cli/deactivate.rs`](https://github.com/jdx/mise/blob/main/src/cli/deactivate.rs)\n\nDisable mise for current shell session\n\nThis can be used to temporarily disable mise in a shell session.\n\nExamples:\n\n```\nmise deactivate\n```\n"
  },
  {
    "path": "docs/cli/doctor/path.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise doctor path`\n\n- **Usage**: `mise doctor path [-f --full]`\n- **Source code**: [`src/cli/doctor/path.rs`](https://github.com/jdx/mise/blob/main/src/cli/doctor/path.rs)\n\nPrint the current PATH entries mise is providing\n\n## Flags\n\n### `-f --full`\n\nPrint all entries including those not provided by mise\n\nExamples:\n\n```\nGet the current PATH entries mise is providing\n$ mise doctor path\n/home/user/.local/share/mise/installs/node/24.0.0/bin\n/home/user/.local/share/mise/installs/rust/1.90.0/bin\n/home/user/.local/share/mise/installs/python/3.10.0/bin\n```\n"
  },
  {
    "path": "docs/cli/doctor.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise doctor`\n\n- **Usage**: `mise doctor [-J --json] <SUBCOMMAND>`\n- **Aliases**: `dr`\n- **Source code**: [`src/cli/doctor/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/doctor/mod.rs)\n\nCheck mise installation for possible problems\n\n## Flags\n\n### `-J --json`\n\n## Subcommands\n\n- [`mise doctor path [-f --full]`](/cli/doctor/path.md)\n\nExamples:\n\n```\n$ mise doctor\n[WARN] plugin node is not installed\n```\n"
  },
  {
    "path": "docs/cli/edit.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise edit`\n\n- **Usage**: `mise edit [-n --dry-run] [-t --tool-versions <TOOL_VERSIONS>] [PATH]`\n- **Source code**: [`src/cli/edit.rs`](https://github.com/jdx/mise/blob/main/src/cli/edit.rs)\n\nEdit mise.toml interactively\n\n## Arguments\n\n### `[PATH]`\n\nPath to the config file to create\n\n## Flags\n\n### `-n --dry-run`\n\nShow what would be generated without writing to file\n\n### `-t --tool-versions <TOOL_VERSIONS>`\n\nPath to a .tool-versions file to import tools from\n\nExamples:\n\n```\nmise edit             # edit mise.toml interactively\nmise edit .mise.toml  # edit a specific file\nmise edit -y          # skip interactive editor\nmise edit -n          # preview without writing\n```\n"
  },
  {
    "path": "docs/cli/en.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise en`\n\n- **Usage**: `mise en [-s --shell <SHELL>] [DIR]`\n- **Source code**: [`src/cli/en.rs`](https://github.com/jdx/mise/blob/main/src/cli/en.rs)\n\nStarts a new shell with the mise environment built from the current configuration\n\nThis is an alternative to `mise activate` that allows you to explicitly start a mise session.\nIt will have the tools and environment variables in the configs loaded.\nNote that changing directories will not update the mise environment.\n\n## Arguments\n\n### `[DIR]`\n\nDirectory to start the shell in\n\n**Default:** `.`\n\n## Flags\n\n### `-s --shell <SHELL>`\n\nShell to start\n\nDefaults to $SHELL\n\nExamples:\n\n```\n$ mise en .\n$ node -v\nv20.0.0\n\nSkip loading bashrc:\n$ mise en -s \"bash --norc\"\n\nSkip loading zshrc:\n$ mise en -s \"zsh -f\"\n```\n"
  },
  {
    "path": "docs/cli/env.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise env`\n\n- **Usage**: `mise env [FLAGS] [TOOL@VERSION]…`\n- **Aliases**: `e`\n- **Source code**: [`src/cli/env.rs`](https://github.com/jdx/mise/blob/main/src/cli/env.rs)\n\nExports env vars to activate mise a single time\n\nUse this if you don't want to permanently install mise. It's not necessary to\nuse this if you have `mise activate` in your shell rc file.\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to use\n\n## Flags\n\n### `-D --dotenv`\n\nOutput in dotenv format\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-s --shell <SHELL>`\n\nShell type to generate environment variables for\n\n**Choices:**\n\n- `bash`\n- `elvish`\n- `fish`\n- `nu`\n- `xonsh`\n- `zsh`\n- `pwsh`\n\n### `--json-extended`\n\nOutput in JSON format with additional information (source, tool)\n\n### `--redacted`\n\nOnly show redacted environment variables\n\n### `--values`\n\nOnly show values of environment variables\n\nExamples:\n\n```\neval \"$(mise env -s bash)\"\neval \"$(mise env -s zsh)\"\nmise env -s fish | source\nexecx($(mise env -s xonsh))\n```\n"
  },
  {
    "path": "docs/cli/exec.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise exec`\n\n- **Usage**: `mise exec [FLAGS] [TOOL@VERSION]… [-- COMMAND]…`\n- **Aliases**: `x`\n- **Source code**: [`src/cli/exec.rs`](https://github.com/jdx/mise/blob/main/src/cli/exec.rs)\n\nExecute a command with tool(s) set\n\nuse this to avoid modifying the shell session or running ad-hoc commands with mise tools set.\n\nTools will be loaded from mise.toml, though they can be overridden with &lt;RUNTIME> args\nNote that only the plugin specified will be overridden, so if a `mise.toml` file\nincludes \"node 20\" but you run `mise exec python@3.11`; it will still load node@20.\n\nThe \"--\" separates runtimes from the commands to pass along to the subprocess.\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to start e.g.: node@20 python@3.10\n\n### `[-- COMMAND]…`\n\nCommand string to execute (same as --command)\n\n## Flags\n\n### `-c --command <C>`\n\nCommand string to execute\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `--fresh-env`\n\nBypass the environment cache and recompute the environment\n\n### `--no-prepare`\n\nSkip automatic dependency preparation\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\n\nExamples:\n\n```\n$ mise exec node@20 -- node ./app.js  # launch app.js using node-20.x\n$ mise x node@20 -- node ./app.js     # shorter alias\n\n# Specify command as a string:\n$ mise exec node@20 python@3.11 --command \"node -v && python -V\"\n\n# Run a command in a different directory:\n$ mise x -C /path/to/project node@20 -- node ./app.js\n```\n"
  },
  {
    "path": "docs/cli/fmt.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise fmt`\n\n- **Usage**: `mise fmt [FLAGS]`\n- **Source code**: [`src/cli/fmt.rs`](https://github.com/jdx/mise/blob/main/src/cli/fmt.rs)\n\nFormats mise.toml\n\nSorts keys and cleans up whitespace in mise.toml\n\n## Flags\n\n### `-a --all`\n\nFormat all files from the current directory\n\n### `-c --check`\n\nCheck if the configs are formatted, no formatting is done\n\n### `-s --stdin`\n\nRead config from stdin and write its formatted version into stdout\n\nExamples:\n\n```\nmise fmt\n```\n"
  },
  {
    "path": "docs/cli/generate/bootstrap.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate bootstrap`\n\n- **Usage**: `mise generate bootstrap [FLAGS]`\n- **Source code**: [`src/cli/generate/bootstrap.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/bootstrap.rs)\n\nGenerate a script to download+execute mise\n\nThis is designed to be used in a project where contributors may not have mise installed.\n\n## Flags\n\n### `-l --localize`\n\nSandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\n\nThis is necessary if users may use a different version of mise outside the project.\n\n### `-V --version <VERSION>`\n\nSpecify mise version to fetch\n\n### `-w --write <WRITE>`\n\ninstead of outputting the script to stdout, write to a file and make it executable\n\n### `--localized-dir <LOCALIZED_DIR>`\n\nDirectory to put localized data into\n\n**Default:** `.mise`\n\nExamples:\n\n```\nmise generate bootstrap >./bin/mise\nchmod +x ./bin/mise\n./bin/mise install – automatically downloads mise to .mise if not already installed\n```\n"
  },
  {
    "path": "docs/cli/generate/config.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate config`\n\n- **Usage**: `mise generate config [-n --dry-run] [-t --tool-versions <TOOL_VERSIONS>] [PATH]`\n- **Source code**: [`src/cli/generate/config.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/config.rs)\n\nGenerate a mise.toml file\n\n## Arguments\n\n### `[PATH]`\n\nPath to the config file to create\n\n## Flags\n\n### `-n --dry-run`\n\nShow what would be generated without writing to file\n\n### `-t --tool-versions <TOOL_VERSIONS>`\n\nPath to a .tool-versions file to import tools from\n\nExamples:\n\n```\nmise edit             # edit mise.toml interactively\nmise edit .mise.toml  # edit a specific file\nmise edit -y          # skip interactive editor\nmise edit -n          # preview without writing\n```\n"
  },
  {
    "path": "docs/cli/generate/devcontainer.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate devcontainer`\n\n- **Usage**: `mise generate devcontainer [FLAGS]`\n- **Source code**: [`src/cli/generate/devcontainer.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/devcontainer.rs)\n\nGenerate a devcontainer to execute mise\n\n## Flags\n\n### `-i --image <IMAGE>`\n\nThe image to use for the devcontainer\n\n### `-m --mount-mise-data`\n\nBind the mise-data-volume to the devcontainer\n\n### `-n --name <NAME>`\n\nThe name of the devcontainer\n\n### `-w --write`\n\nwrite to .devcontainer/devcontainer.json\n\nExamples:\n\n```\nmise generate devcontainer\n```\n"
  },
  {
    "path": "docs/cli/generate/git-pre-commit.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate git-pre-commit`\n\n- **Usage**: `mise generate git-pre-commit [FLAGS]`\n- **Aliases**: `pre-commit`\n- **Source code**: [`src/cli/generate/git_pre_commit.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/git_pre_commit.rs)\n\nGenerate a git pre-commit hook\n\nThis command generates a git pre-commit hook that runs a mise task like `mise run pre-commit`\nwhen you commit changes to your repository.\n\nStaged files are passed to the task as `STAGED`.\n\nFor more advanced pre-commit functionality, see mise's sister project: <https://hk.jdx.dev/>\n\n## Flags\n\n### `-t --task <TASK>`\n\nThe task to run when the pre-commit hook is triggered\n\n**Default:** `pre-commit`\n\n### `-w --write`\n\nwrite to .git/hooks/pre-commit and make it executable\n\n### `--hook <HOOK>`\n\nWhich hook to generate (saves to .git/hooks/$hook)\n\n**Default:** `pre-commit`\n\nExamples:\n\n```\nmise generate git-pre-commit --write --task=pre-commit\ngit commit -m \"feat: add new feature\" # runs `mise run pre-commit`\n```\n"
  },
  {
    "path": "docs/cli/generate/github-action.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate github-action`\n\n- **Usage**: `mise generate github-action [FLAGS]`\n- **Source code**: [`src/cli/generate/github_action.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/github_action.rs)\n\nGenerate a GitHub Action workflow file\n\nThis command generates a GitHub Action workflow file that runs a mise task like `mise run ci`\nwhen you push changes to your repository.\n\n## Flags\n\n### `-t --task <TASK>`\n\nThe task to run when the workflow is triggered\n\n**Default:** `ci`\n\n### `-w --write`\n\nwrite to .github/workflows/$name.yml\n\n### `--name <NAME>`\n\nthe name of the workflow to generate\n\n**Default:** `ci`\n\nExamples:\n\n```\nmise generate github-action --write --task=ci\ngit commit -m \"feat: add new feature\"\ngit push # runs `mise run ci` on GitHub\n```\n"
  },
  {
    "path": "docs/cli/generate/task-docs.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate task-docs`\n\n- **Usage**: `mise generate task-docs [FLAGS]`\n- **Source code**: [`src/cli/generate/task_docs.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/task_docs.rs)\n\nGenerate documentation for tasks in a project\n\n## Flags\n\n### `-i --inject`\n\ninserts the documentation into an existing file\n\nThis will look for a special comment, `<!-- mise-tasks -->`, and replace it with the generated documentation.\nIt will replace everything between the comment and the next comment, `<!-- /mise-tasks -->` so it can be\nrun multiple times on the same file to update the documentation.\n\n### `-I --index`\n\nwrite only an index of tasks, intended for use with `--multi`\n\n### `-m --multi`\n\nrender each task as a separate document, requires `--output` to be a directory\n\n### `-o --output <OUTPUT>`\n\nwrites the generated docs to a file/directory\n\n### `-r --root <ROOT>`\n\nroot directory to search for tasks\n\n### `-s --style <STYLE>`\n\n**Choices:**\n\n- `simple`\n- `detailed`\n\n**Default:** `simple`\n\nExamples:\n\n```\nmise generate task-docs\n```\n"
  },
  {
    "path": "docs/cli/generate/task-stubs.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate task-stubs`\n\n- **Usage**: `mise generate task-stubs [-d --dir <DIR>] [-m --mise-bin <MISE_BIN>]`\n- **Source code**: [`src/cli/generate/task_stubs.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/task_stubs.rs)\n\nGenerates shims to run mise tasks\n\nBy default, this will build shims like ./bin/&lt;task>. These can be paired with `mise generate bootstrap`\nso contributors to a project can execute mise tasks without installing mise into their system.\n\n## Flags\n\n### `-d --dir <DIR>`\n\nDirectory to create task stubs inside of\n\n**Default:** `bin`\n\n### `-m --mise-bin <MISE_BIN>`\n\nPath to a mise bin to use when running the task stub.\n\nUse `--mise-bin=./bin/mise` to use a mise bin generated from `mise generate bootstrap`\n\n**Default:** `mise`\n\nExamples:\n\n```\n$ mise tasks add test -- echo 'running tests'\n$ mise generate task-stubs\n$ ./bin/test\nrunning tests\n```\n"
  },
  {
    "path": "docs/cli/generate/tool-stub.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate tool-stub`\n\n- **Usage**: `mise generate tool-stub [FLAGS] <OUTPUT>`\n- **Source code**: [`src/cli/generate/tool_stub.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/tool_stub.rs)\n\nGenerate a tool stub for HTTP-based tools\n\nThis command generates tool stubs that can automatically download and execute\ntools from HTTP URLs. It can detect checksums, file sizes, and binary paths\nautomatically by downloading and analyzing the tool.\n\nWhen generating stubs with platform-specific URLs, the command will append new\nplatforms to existing stub files rather than overwriting them. This allows you\nto incrementally build cross-platform tool stubs.\n\n## Arguments\n\n### `<OUTPUT>`\n\nOutput file path for the tool stub\n\n## Flags\n\n### `-b --bin <BIN>`\n\nBinary path within the extracted archive\n\nIf not specified and the archive is downloaded, will auto-detect the most likely binary\n\n### `--bootstrap`\n\nWrap stub in a bootstrap script that installs mise if not already present\n\nWhen enabled, generates a bash script that:\n1. Checks if mise is installed at the expected path\n2. If not, downloads and installs mise using the embedded installer\n3. Executes the tool stub using mise\n\n### `--bootstrap-version <BOOTSTRAP_VERSION>`\n\nSpecify mise version for the bootstrap script\n\nBy default, uses the latest version from the install script.\nUse this to pin to a specific version (e.g., \"2025.1.0\").\n\n### `--fetch`\n\nFetch checksums and sizes for an existing tool stub file\n\nThis reads an existing stub file and fills in any missing checksum/size fields by downloading the files. URLs must already be present in the stub.\n\n### `--http <HTTP>`\n\nHTTP backend type to use\n\n**Default:** `http`\n\n### `--lock`\n\nResolve and embed lockfile data (exact version + platform URLs/checksums) into an existing stub file for reproducible installs without runtime API calls\n\n### `--platform-bin… <PLATFORM_BIN>`\n\nPlatform-specific binary paths in the format platform:path\n\nExamples: --platform-bin windows-x64:tool.exe --platform-bin linux-x64:bin/tool\n\n### `--platform-url… <PLATFORM_URL>`\n\nPlatform-specific URLs in the format platform:url or just url (auto-detect platform)\n\nWhen the output file already exists, new platforms will be appended to the existing platforms table. Existing platform URLs will be updated if specified again.\n\nIf only a URL is provided (without platform:), the platform will be automatically detected from the URL filename.\n\nExamples: --platform-url linux-x64:https://... --platform-url <https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz>\n\n### `--skip-download`\n\nSkip downloading for checksum and binary path detection (faster but less informative)\n\n### `-u --url <URL>`\n\nURL for downloading the tool\n\nExample: <https://github.com/owner/repo/releases/download/v2.0.0/tool-linux-x64.tar.gz>\n\n### `--version <VERSION>`\n\nVersion of the tool\n\n**Default:** `latest`\n\nExamples:\n\n```\nGenerate a tool stub for a single URL:\n$ mise generate tool-stub ./bin/gh --url \"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_linux_amd64.tar.gz\"\n\nGenerate a tool stub with platform-specific URLs:\n$ mise generate tool-stub ./bin/rg \\\n    --platform-url linux-x64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz \\\n    --platform-url darwin-arm64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-aarch64-apple-darwin.tar.gz\n\nAppend additional platforms to an existing stub:\n$ mise generate tool-stub ./bin/rg \\\n    --platform-url linux-x64:https://example.com/rg-linux.tar.gz\n$ mise generate tool-stub ./bin/rg \\\n    --platform-url darwin-arm64:https://example.com/rg-darwin.tar.gz\n# The stub now contains both platforms\n\nUse auto-detection for platform from URL:\n$ mise generate tool-stub ./bin/node \\\n    --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\n# Platform 'macos-arm64' will be auto-detected from the URL\n\nGenerate with platform-specific binary paths:\n$ mise generate tool-stub ./bin/tool \\\n    --platform-url linux-x64:https://example.com/tool-linux.tar.gz \\\n    --platform-url windows-x64:https://example.com/tool-windows.zip \\\n    --platform-bin windows-x64:tool.exe\n\nGenerate without downloading (faster):\n$ mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --skip-download\n\nFetch checksums for an existing stub:\n$ mise generate tool-stub ./bin/jq --fetch\n# This will read the existing stub and download files to fill in any missing checksums/sizes\n\nGenerate a bootstrap stub that installs mise if needed:\n$ mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --bootstrap\n# The stub will check for mise and install it automatically before running the tool\n\nGenerate a bootstrap stub with a pinned mise version:\n$ mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --bootstrap --bootstrap-version 2025.1.0\n\nLock an existing tool stub with pinned version and platform URLs/checksums:\n$ mise generate tool-stub ./bin/node --lock\n\nBump the version in a locked stub:\n$ mise generate tool-stub ./bin/node --lock --version 22\n# Resolves the latest node 22.x, pins it, and updates platform URLs/checksums\n```\n"
  },
  {
    "path": "docs/cli/generate.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise generate`\n\n- **Usage**: `mise generate <SUBCOMMAND>`\n- **Aliases**: `gen`\n- **Source code**: [`src/cli/generate/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/generate/mod.rs)\n\nGenerate files for various tools/services\n\n## Subcommands\n\n- [`mise generate bootstrap [FLAGS]`](/cli/generate/bootstrap.md)\n- [`mise generate config [-n --dry-run] [-t --tool-versions <TOOL_VERSIONS>] [PATH]`](/cli/generate/config.md)\n- [`mise generate devcontainer [FLAGS]`](/cli/generate/devcontainer.md)\n- [`mise generate git-pre-commit [FLAGS]`](/cli/generate/git-pre-commit.md)\n- [`mise generate github-action [FLAGS]`](/cli/generate/github-action.md)\n- [`mise generate task-docs [FLAGS]`](/cli/generate/task-docs.md)\n- [`mise generate task-stubs [-d --dir <DIR>] [-m --mise-bin <MISE_BIN>]`](/cli/generate/task-stubs.md)\n- [`mise generate tool-stub [FLAGS] <OUTPUT>`](/cli/generate/tool-stub.md)\n"
  },
  {
    "path": "docs/cli/implode.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise implode`\n\n- **Usage**: `mise implode [-n --dry-run] [--config]`\n- **Source code**: [`src/cli/implode.rs`](https://github.com/jdx/mise/blob/main/src/cli/implode.rs)\n\nRemoves mise CLI and all related data\n\nSkips config directory by default.\n\n## Flags\n\n### `-n --dry-run`\n\nList directories that would be removed without actually removing them\n\n### `--config`\n\nAlso remove config directory\n"
  },
  {
    "path": "docs/cli/index.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise`\n\n**Usage**: `mise [FLAGS] [TASK] <SUBCOMMAND>`\n\n- **Usage**: `mise [FLAGS] [TASK] <SUBCOMMAND>`\n\n## Arguments\n\n### `[TASK]`\n\nTask to run.\n\nShorthand for `mise tasks run <TASK>`.\n\n## Global Flags\n\n### `-C --cd <DIR>`\n\nChange directory before running command\n\n### `-E --env… <ENV>`\n\nSet the environment for loading `mise.<ENV>.toml`\n\n### `-j --jobs <JOBS>`\n\nHow many jobs to run in parallel [default: 8]\n\n### `-q --quiet`\n\nSuppress non-error messages\n\n### `-v --verbose…`\n\nShow extra output (use -vv for even more)\n\n### `-y --yes`\n\nAnswer yes to all confirmation prompts\n\n### `--raw`\n\nRead/write directly to stdin/stdout/stderr instead of by line\n\n### `--locked`\n\nRequire lockfile URLs to be present during installation\n\nFails if tools don't have pre-resolved URLs in the lockfile for the current platform.\nThis prevents API calls to GitHub, aqua registry, etc.\nCan also be enabled via MISE_LOCKED=1 or settings.locked=true\n\n### `--silent`\n\nSuppress all task output and mise non-error messages\n\n## Flags\n\n### `--no-config`\n\nDo not load any config files\n\nCan also use `MISE_NO_CONFIG=1`\n\n### `--no-env`\n\nDo not load environment variables from config files\n\nCan also use `MISE_NO_ENV=1`\n\n### `--no-hooks`\n\nDo not execute hooks from config files\n\nCan also use `MISE_NO_HOOKS=1`\n\n### `--output <OUTPUT>`\n\n## Subcommands\n\n- [`mise activate [FLAGS] [SHELL_TYPE]`](/cli/activate.md)\n- [`mise tool-alias [-p --plugin <PLUGIN>] [--no-header] <SUBCOMMAND>`](/cli/tool-alias.md)\n- [`mise tool-alias get <PLUGIN> <ALIAS>`](/cli/tool-alias/get.md)\n- [`mise tool-alias ls [--no-header] [TOOL]`](/cli/tool-alias/ls.md)\n- [`mise tool-alias set <ARGS>…`](/cli/tool-alias/set.md)\n- [`mise tool-alias unset <PLUGIN> [ALIAS]`](/cli/tool-alias/unset.md)\n- [`mise backends <SUBCOMMAND>`](/cli/backends.md)\n- [`mise backends ls`](/cli/backends/ls.md)\n- [`mise bin-paths [TOOL@VERSION]…`](/cli/bin-paths.md)\n- [`mise cache <SUBCOMMAND>`](/cli/cache.md)\n- [`mise cache clear [PLUGIN]…`](/cli/cache/clear.md)\n- [`mise cache path`](/cli/cache/path.md)\n- [`mise cache prune [-v --verbose…] [--dry-run] [PLUGIN]…`](/cli/cache/prune.md)\n- [`mise completion [--include-bash-completion-lib] [SHELL]`](/cli/completion.md)\n- [`mise config [FLAGS] <SUBCOMMAND>`](/cli/config.md)\n- [`mise config get [-f --file <FILE>] [KEY]`](/cli/config/get.md)\n- [`mise config ls [FLAGS]`](/cli/config/ls.md)\n- [`mise config set [-f --file <FILE>] [-t --type <TYPE>] <KEY> [VALUE]`](/cli/config/set.md)\n- [`mise deactivate`](/cli/deactivate.md)\n- [`mise doctor [-J --json] <SUBCOMMAND>`](/cli/doctor.md)\n- [`mise doctor path [-f --full]`](/cli/doctor/path.md)\n- [`mise en [-s --shell <SHELL>] [DIR]`](/cli/en.md)\n- [`mise env [FLAGS] [TOOL@VERSION]…`](/cli/env.md)\n- [`mise exec [FLAGS] [TOOL@VERSION]… [-- COMMAND]…`](/cli/exec.md)\n- [`mise fmt [FLAGS]`](/cli/fmt.md)\n- [`mise generate <SUBCOMMAND>`](/cli/generate.md)\n- [`mise generate bootstrap [FLAGS]`](/cli/generate/bootstrap.md)\n- [`mise generate config [-n --dry-run] [-t --tool-versions <TOOL_VERSIONS>] [PATH]`](/cli/generate/config.md)\n- [`mise generate devcontainer [FLAGS]`](/cli/generate/devcontainer.md)\n- [`mise generate git-pre-commit [FLAGS]`](/cli/generate/git-pre-commit.md)\n- [`mise generate github-action [FLAGS]`](/cli/generate/github-action.md)\n- [`mise generate task-docs [FLAGS]`](/cli/generate/task-docs.md)\n- [`mise generate task-stubs [-d --dir <DIR>] [-m --mise-bin <MISE_BIN>]`](/cli/generate/task-stubs.md)\n- [`mise generate tool-stub [FLAGS] <OUTPUT>`](/cli/generate/tool-stub.md)\n- [`mise implode [-n --dry-run] [--config]`](/cli/implode.md)\n- [`mise edit [-n --dry-run] [-t --tool-versions <TOOL_VERSIONS>] [PATH]`](/cli/edit.md)\n- [`mise install [FLAGS] [TOOL@VERSION]…`](/cli/install.md)\n- [`mise install-into <TOOL@VERSION> <PATH>`](/cli/install-into.md)\n- [`mise latest [-i --installed] <TOOL@VERSION>`](/cli/latest.md)\n- [`mise link [-f --force] <TOOL@VERSION> <PATH>`](/cli/link.md)\n- [`mise lock [FLAGS] [TOOL]…`](/cli/lock.md)\n- [`mise ls [FLAGS] [INSTALLED_TOOL]…`](/cli/ls.md)\n- [`mise ls-remote [--all] [-J --json] [TOOL@VERSION] [PREFIX]`](/cli/ls-remote.md)\n- [`mise mcp`](/cli/mcp.md)\n- [`mise outdated [FLAGS] [TOOL@VERSION]…`](/cli/outdated.md)\n- [`mise plugins [FLAGS] <SUBCOMMAND>`](/cli/plugins.md)\n- [`mise plugins install [FLAGS] [NEW_PLUGIN] [GIT_URL]`](/cli/plugins/install.md)\n- [`mise plugins link [-f --force] <NAME> [DIR]`](/cli/plugins/link.md)\n- [`mise plugins ls [-o --outdated] [-u --urls]`](/cli/plugins/ls.md)\n- [`mise plugins ls-remote [-u --urls] [--only-names]`](/cli/plugins/ls-remote.md)\n- [`mise plugins uninstall [-a --all] [-p --purge] [PLUGIN]…`](/cli/plugins/uninstall.md)\n- [`mise plugins update [-j --jobs <JOBS>] [PLUGIN]…`](/cli/plugins/update.md)\n- [`mise prepare [FLAGS] [PROVIDER]`](/cli/prepare.md)\n- [`mise prune [FLAGS] [INSTALLED_TOOL]…`](/cli/prune.md)\n- [`mise registry [FLAGS] [NAME]`](/cli/registry.md)\n- [`mise reshim [-f --force]`](/cli/reshim.md)\n- [`mise run [FLAGS]`](/cli/run.md)\n- [`mise search [FLAGS] [NAME]`](/cli/search.md)\n- [`mise self-update [FLAGS] [VERSION]`](/cli/self-update.md)\n- [`mise set [FLAGS] [ENV_VAR]…`](/cli/set.md)\n- [`mise settings [FLAGS] [SETTING] [VALUE] <SUBCOMMAND>`](/cli/settings.md)\n- [`mise settings add [-l --local] <SETTING> [VALUE]`](/cli/settings/add.md)\n- [`mise settings get [-l --local] <SETTING>`](/cli/settings/get.md)\n- [`mise settings ls [FLAGS] [SETTING]`](/cli/settings/ls.md)\n- [`mise settings set [-l --local] <SETTING> [VALUE]`](/cli/settings/set.md)\n- [`mise settings unset [-l --local] <KEY>`](/cli/settings/unset.md)\n- [`mise shell [FLAGS] <TOOL@VERSION>…`](/cli/shell.md)\n- [`mise shell-alias [--no-header] <SUBCOMMAND>`](/cli/shell-alias.md)\n- [`mise shell-alias get <shell_alias>`](/cli/shell-alias/get.md)\n- [`mise shell-alias ls [--no-header]`](/cli/shell-alias/ls.md)\n- [`mise shell-alias set <shell_alias> [COMMAND]`](/cli/shell-alias/set.md)\n- [`mise shell-alias unset <shell_alias>`](/cli/shell-alias/unset.md)\n- [`mise sync <SUBCOMMAND>`](/cli/sync.md)\n- [`mise sync node [FLAGS]`](/cli/sync/node.md)\n- [`mise sync python [--pyenv] [--uv]`](/cli/sync/python.md)\n- [`mise sync ruby [--brew]`](/cli/sync/ruby.md)\n- [`mise tasks [FLAGS] [TASK] <SUBCOMMAND>`](/cli/tasks.md)\n- [`mise tasks add [FLAGS] <TASK> [-- RUN]…`](/cli/tasks/add.md)\n- [`mise tasks deps [--dot] [--hidden] [TASKS]…`](/cli/tasks/deps.md)\n- [`mise tasks edit [-p --path] <TASK>`](/cli/tasks/edit.md)\n- [`mise tasks info [-J --json] <TASK>`](/cli/tasks/info.md)\n- [`mise tasks ls [FLAGS]`](/cli/tasks/ls.md)\n- [`mise tasks run [FLAGS] [TASK] [ARGS]…`](/cli/tasks/run.md)\n- [`mise tasks validate [--errors-only] [--json] [TASKS]…`](/cli/tasks/validate.md)\n- [`mise test-tool [FLAGS] [TOOLS]…`](/cli/test-tool.md)\n- [`mise tool [FLAGS] <TOOL>`](/cli/tool.md)\n- [`mise tool-stub <FILE> [ARGS]…`](/cli/tool-stub.md)\n- [`mise trust [FLAGS] [CONFIG_FILE]`](/cli/trust.md)\n- [`mise uninstall [FLAGS] [INSTALLED_TOOL@VERSION]…`](/cli/uninstall.md)\n- [`mise unset [-f --file <FILE>] [-g --global] [ENV_KEY]…`](/cli/unset.md)\n- [`mise unuse [FLAGS] <INSTALLED_TOOL@VERSION>…`](/cli/unuse.md)\n- [`mise upgrade [FLAGS] [INSTALLED_TOOL@VERSION]…`](/cli/upgrade.md)\n- [`mise use [FLAGS] [TOOL@VERSION]…`](/cli/use.md)\n- [`mise version [-J --json]`](/cli/version.md)\n- [`mise watch [FLAGS] [TASK] [ARGS]…`](/cli/watch.md)\n- [`mise where <TOOL@VERSION>`](/cli/where.md)\n- [`mise which [FLAGS] [BIN_NAME]`](/cli/which.md)\n"
  },
  {
    "path": "docs/cli/install-into.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise install-into`\n\n- **Usage**: `mise install-into <TOOL@VERSION> <PATH>`\n- **Source code**: [`src/cli/install_into.rs`](https://github.com/jdx/mise/blob/main/src/cli/install_into.rs)\n\nInstall a tool version to a specific path\n\nUsed for building a tool to a directory for use outside of mise\n\n## Arguments\n\n### `<TOOL@VERSION>`\n\nTool to install e.g.: node@20\n\n### `<PATH>`\n\nPath to install the tool into\n\nExamples:\n\n```\n# install node@20.0.0 into ./mynode\n$ mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v\n20.0.0\n```\n"
  },
  {
    "path": "docs/cli/install.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise install`\n\n- **Usage**: `mise install [FLAGS] [TOOL@VERSION]…`\n- **Aliases**: `i`\n- **Source code**: [`src/cli/install.rs`](https://github.com/jdx/mise/blob/main/src/cli/install.rs)\n\nInstall a tool version\n\nInstalls a tool version to `~/.local/share/mise/installs/<PLUGIN>/<VERSION>`\nInstalling alone will not activate the tools so they won't be in PATH.\nTo install and/or activate in one command, use `mise use` which will create a `mise.toml` file\nin the current directory to activate this tool when inside the directory.\nAlternatively, run `mise exec <TOOL>@<VERSION> -- <COMMAND>` to execute a tool without creating config files.\n\nTools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1`\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to install e.g.: node@20\n\n## Flags\n\n### `-f --force`\n\nForce reinstall even if already installed\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `-n --dry-run`\n\nShow what would be installed without actually installing\n\n### `-v --verbose…`\n\nShow installation output\n\nThis argument will print plugin output such as download, configuration, and compilation output.\n\n### `--before <BEFORE>`\n\nOnly install versions released before this date\n\nSupports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\n\n### `--dry-run-code`\n\nLike --dry-run but exits with code 1 if there are tools to install\n\nThis is useful for scripts to check if tools need to be installed.\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\n\n### `--shared <SHARED>`\n\n[experimental] Install tool(s) to a shared directory\n\nInstalls to the specified directory instead of the default install location.\nMay require elevated permissions depending on the path.\n\n### `--system`\n\n[experimental] Install tool(s) to the system-wide shared directory\n\nInstalls to /usr/local/share/mise/installs (or MISE_SYSTEM_DATA_DIR/installs).\nMay require elevated permissions (e.g. sudo).\n\nExamples:\n\n```\nmise install node@20.0.0  # install specific node version\nmise install node@20      # install fuzzy node version\nmise install node         # install version specified in mise.toml\nmise install              # installs everything specified in mise.toml\n```\n"
  },
  {
    "path": "docs/cli/latest.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise latest`\n\n- **Usage**: `mise latest [-i --installed] <TOOL@VERSION>`\n- **Source code**: [`src/cli/latest.rs`](https://github.com/jdx/mise/blob/main/src/cli/latest.rs)\n\nGets the latest available version for a plugin\n\nSupports prefixes such as `node@20` to get the latest version of node 20.\n\n## Arguments\n\n### `<TOOL@VERSION>`\n\nTool to get the latest version of\n\n## Flags\n\n### `-i --installed`\n\nShow latest installed instead of available version\n\nExamples:\n\n```\n$ mise latest node@20  # get the latest version of node 20\n20.0.0\n\n$ mise latest node     # get the latest stable version of node\n20.0.0\n```\n"
  },
  {
    "path": "docs/cli/link.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise link`\n\n- **Usage**: `mise link [-f --force] <TOOL@VERSION> <PATH>`\n- **Aliases**: `ln`\n- **Source code**: [`src/cli/link.rs`](https://github.com/jdx/mise/blob/main/src/cli/link.rs)\n\nSymlinks a tool version into mise\n\nUse this for adding installs either custom compiled outside mise or built with a different tool.\n\n## Arguments\n\n### `<TOOL@VERSION>`\n\nTool name and version to create a symlink for\n\n### `<PATH>`\n\nThe local path to the tool version\ne.g.: ~/.nvm/versions/node/v20.0.0\n\n## Flags\n\n### `-f --force`\n\nOverwrite an existing tool version if it exists\n\nExamples:\n\n```\n# build node-20.0.0 with node-build and link it into mise\n$ node-build 20.0.0 ~/.nodes/20.0.0\n$ mise link node@20.0.0 ~/.nodes/20.0.0\n\n# have mise use the node version provided by Homebrew\n$ brew install node\n$ mise link node@brew $(brew --prefix node)\n$ mise use node@brew\n```\n"
  },
  {
    "path": "docs/cli/lock.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise lock`\n\n- **Usage**: `mise lock [FLAGS] [TOOL]…`\n- **Source code**: [`src/cli/lock.rs`](https://github.com/jdx/mise/blob/main/src/cli/lock.rs)\n\nUpdate lockfile checksums and URLs for all specified platforms\n\nUpdates checksums and download URLs for all platforms already specified in the lockfile.\nIf no lockfile exists, shows what would be created based on the current configuration.\nThis allows you to refresh lockfile data for platforms other than the one you're currently on.\nOperates on the lockfile in the current config root. Use TOOL arguments to target specific tools.\n\n## Arguments\n\n### `[TOOL]…`\n\nTool(s) to update in lockfile\ne.g.: node python\nIf not specified, all tools in lockfile will be updated\n\n## Flags\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n\n### `-n --dry-run`\n\nShow what would be updated without making changes\n\n### `-p --platform… <PLATFORM>`\n\nComma-separated list of platforms to target\ne.g.: linux-x64,macos-arm64,windows-x64\nIf not specified, all platforms already in lockfile will be updated\n\n### `--local`\n\nUpdate mise.local.lock instead of mise.lock\nUse for tools defined in .local.toml configs\n\nExamples:\n\n```\nmise lock                       # update lockfile for all common platforms\nmise lock node python           # update only node and python\nmise lock --platform linux-x64  # update only linux-x64 platform\nmise lock --dry-run             # show what would be updated\nmise lock --local               # update mise.local.lock for local configs\n```\n"
  },
  {
    "path": "docs/cli/ls-remote.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise ls-remote`\n\n- **Usage**: `mise ls-remote [--all] [-J --json] [TOOL@VERSION] [PREFIX]`\n- **Source code**: [`src/cli/ls_remote.rs`](https://github.com/jdx/mise/blob/main/src/cli/ls_remote.rs)\n\nList runtime versions available for install.\n\nNote that the results may be cached, run `mise cache clean` to clear the cache and get fresh results.\n\n## Arguments\n\n### `[TOOL@VERSION]`\n\nTool to get versions for\n\n### `[PREFIX]`\n\nThe version prefix to use when querying the latest version\nsame as the first argument after the \"@\"\n\n## Flags\n\n### `--all`\n\nShow all installed plugins and versions\n\n### `-J --json`\n\nOutput in JSON format (includes version metadata like created_at timestamps when available)\n\nExamples:\n\n```\n$ mise ls-remote node\n18.0.0\n20.0.0\n\n$ mise ls-remote node@20\n20.0.0\n20.1.0\n\n$ mise ls-remote node 20\n20.0.0\n20.1.0\n\n$ mise ls-remote github:cli/cli --json\n[{\"version\":\"2.62.0\",\"created_at\":\"2024-11-14T15:40:35Z\"},{\"version\":\"2.61.0\",\"created_at\":\"2024-10-23T19:22:15Z\"}]\n```\n"
  },
  {
    "path": "docs/cli/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise ls`\n\n- **Usage**: `mise ls [FLAGS] [INSTALLED_TOOL]…`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/ls.rs)\n\nList installed and active tool versions\n\nThis command lists tools that mise \"knows about\".\nThese may be tools that are currently installed, or those\nthat are in a config file (active) but may or may not be installed.\n\nIt's a useful command to get the current state of your tools.\n\n## Arguments\n\n### `[INSTALLED_TOOL]…`\n\nOnly show tool versions from [TOOL]\n\n## Flags\n\n### `-c --current`\n\nOnly show tool versions currently specified in a mise.toml\n\n### `-g --global`\n\nOnly show tool versions currently specified in the global mise.toml\n\n### `-i --installed`\n\nOnly show tool versions that are installed (Hides tools defined in mise.toml but not installed)\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-l --local`\n\nOnly show tool versions currently specified in the local mise.toml\n\n### `-m --missing`\n\nDisplay missing tool versions\n\n### `--all-sources`\n\nDisplay all tracked config sources for tools\n\n### `--no-header`\n\nDon't display headers\n\n### `--outdated`\n\nDisplay whether a version is outdated\n\n### `--prefix <PREFIX>`\n\nDisplay versions matching this prefix\n\n### `--prunable`\n\nList only tools that can be pruned with `mise prune`\n\nExamples:\n\n```\n$ mise ls\nnode    20.0.0 ~/src/myapp/.tool-versions latest\npython  3.11.0 ~/.tool-versions           3.10\npython  3.10.0\n\n$ mise ls --current\nnode    20.0.0 ~/src/myapp/.tool-versions 20\npython  3.11.0 ~/.tool-versions           3.11.0\n\n$ mise ls --json\n{\n  \"node\": [\n    {\n      \"version\": \"20.0.0\",\n      \"install_path\": \"/Users/jdx/.mise/installs/node/20.0.0\",\n      \"source\": {\n        \"type\": \"mise.toml\",\n        \"path\": \"/Users/jdx/mise.toml\"\n      }\n    }\n  ],\n  \"python\": [...]\n}\n\n$ mise ls --all-sources\nnode    20.0.0  ~/src/myapp/mise.toml  20\n                ~/.config/mise/config.toml  latest\n```\n"
  },
  {
    "path": "docs/cli/mcp.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise mcp`\n\n- **Usage**: `mise mcp`\n- **Source code**: [`src/cli/mcp.rs`](https://github.com/jdx/mise/blob/main/src/cli/mcp.rs)\n\n[experimental] Run Model Context Protocol (MCP) server\n\nThis command starts an MCP server that exposes mise functionality\nto AI assistants over stdin/stdout using JSON-RPC protocol.\n\nThe MCP server provides access to:\n- Installed and available tools\n- Task definitions and execution\n- Environment variables\n- Configuration information\n- Task execution via the run_task tool\n\nResources available:\n- mise://tools - List all tools (use ?include_inactive=true to include inactive tools)\n- mise://tasks - List all tasks with their configurations\n- mise://env - List all environment variables\n- mise://config - Show configuration files and project root\n\nTools available:\n- install_tool - Install a tool with an optional version (not yet implemented)\n- run_task - Execute a mise task with optional arguments\n\nNote: This is primarily intended for integration with AI assistants like Claude,\nCursor, or other tools that support the Model Context Protocol.\n\nExamples:\n\n```\n# Start the MCP server (typically used by AI assistant tools)\n$ mise mcp\n\n# Example integration with Claude Desktop (add to claude_desktop_config.json):\n{\n  \"mcpServers\": {\n    \"mise\": {\n      \"command\": \"mise\",\n      \"args\": [\"mcp\"],\n      \"env\": {\n        \"MISE_EXPERIMENTAL\": \"1\"\n      }\n    }\n  }\n}\n\n# Interactive testing with JSON-RPC commands:\n$ echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | mise mcp\n\n# Resources you can query:\n- mise://tools - List active tools\n- mise://tools?include_inactive=true - List all installed tools\n- mise://tasks - List all tasks\n- mise://env - List environment variables\n- mise://config - Show configuration info\n\n# Tools available:\n- install_tool - Install a tool (not yet implemented)\n- run_task - Execute a mise task with optional arguments\n  Example: {\"task\": \"build\", \"args\": [\"--verbose\"]}\n```\n"
  },
  {
    "path": "docs/cli/outdated.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise outdated`\n\n- **Usage**: `mise outdated [FLAGS] [TOOL@VERSION]…`\n- **Source code**: [`src/cli/outdated.rs`](https://github.com/jdx/mise/blob/main/src/cli/outdated.rs)\n\nShows outdated tool versions\n\nSee `mise upgrade` to upgrade these versions.\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to show outdated versions for\ne.g.: node@20 python@3.10\nIf not specified, all tools in global and local configs will be shown\n\n## Flags\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-l --bump`\n\nCompares against the latest versions available, not what matches the current config\n\nFor example, if you have `node = \"20\"` in your config by default `mise outdated` will only\nshow other 20.x versions, not 21.x or 22.x versions.\n\nUsing this flag, if there are 21.x or newer versions it will display those instead of 20.x.\n\n### `--local`\n\nOnly show outdated tools defined in local config files\n\nThis will only show tools that are defined in project-local mise.toml and\nwill skip tools defined in the global config (~/.config/mise/config.toml).\n\n### `--no-header`\n\nDon't show table header\n\nExamples:\n\n```\n$ mise outdated\nPlugin  Requested  Current  Latest\npython  3.11       3.11.0   3.11.1\nnode    20         20.0.0   20.1.0\n\n$ mise outdated node\nPlugin  Requested  Current  Latest\nnode    20         20.0.0   20.1.0\n\n$ mise outdated --json\n{\"python\": {\"requested\": \"3.11\", \"current\": \"3.11.0\", \"latest\": \"3.11.1\"}, ...}\n\n$ mise outdated --local\nPlugin  Requested  Current  Latest\nnode    20         20.0.0   20.1.0\n```\n"
  },
  {
    "path": "docs/cli/plugins/install.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins install`\n\n- **Usage**: `mise plugins install [FLAGS] [NEW_PLUGIN] [GIT_URL]`\n- **Aliases**: `i`, `a`, `add`\n- **Source code**: [`src/cli/plugins/install.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/install.rs)\n\nInstall a plugin\n\nnote that mise automatically can install plugins when you install a tool\ne.g.: `mise install cmake@3.30` will autoinstall the cmake plugin\n\nThis behavior can be modified in ~/.config/mise/config.toml\n\n## Arguments\n\n### `[NEW_PLUGIN]`\n\nThe name of the plugin to install\ne.g.: cmake, poetry\nCan specify multiple plugins: `mise plugins install cmake poetry`\n\n### `[GIT_URL]`\n\nThe git url of the plugin\n\n## Flags\n\n### `-a --all`\n\nInstall all missing plugins\nThis will only install plugins that have matching shorthands.\ni.e.: they don't need the full git repo url\n\n### `-f --force`\n\nReinstall even if plugin exists\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n\n### `-v --verbose…`\n\nShow installation output\n\nExamples:\n\n```\n# install the poetry via shorthand\n$ mise plugins install poetry\n\n# install the poetry plugin using a specific git url\n$ mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git\n\n# install the poetry plugin using the git url only\n# (poetry is inferred from the url)\n$ mise plugins install https://github.com/mise-plugins/mise-poetry.git\n\n# install the poetry plugin using a specific ref\n$ mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git#11d0c1e\n```\n"
  },
  {
    "path": "docs/cli/plugins/link.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins link`\n\n- **Usage**: `mise plugins link [-f --force] <NAME> [DIR]`\n- **Aliases**: `ln`\n- **Source code**: [`src/cli/plugins/link.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/link.rs)\n\nSymlinks a plugin into mise\n\nThis is used for developing a plugin.\n\n## Arguments\n\n### `<NAME>`\n\nThe name of the plugin\ne.g.: cmake, poetry\n\n### `[DIR]`\n\nThe local path to the plugin\ne.g.: ./vfox-cmake\n\n## Flags\n\n### `-f --force`\n\nOverwrite existing plugin\n\nExamples:\n\n```\n# essentially just `ln -s ./vfox-cmake ~/.local/share/mise/plugins/cmake`\n$ mise plugins link cmake ./vfox-cmake\n\n# infer plugin name as \"cmake\"\n$ mise plugins link ./vfox-cmake\n```\n"
  },
  {
    "path": "docs/cli/plugins/ls-remote.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins ls-remote`\n\n- **Usage**: `mise plugins ls-remote [-u --urls] [--only-names]`\n- **Aliases**: `list-remote`, `list-all`\n- **Source code**: [`src/cli/plugins/ls_remote.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/ls_remote.rs)\n\nList all available remote plugins\n\nThe full list is here: <https://github.com/jdx/mise/blob/main/registry/>\n\nExamples:\n\n```\nmise plugins ls-remote\n```\n\n## Flags\n\n### `-u --urls`\n\nShow the git url for each plugin e.g.: <https://github.com/mise-plugins/mise-poetry.git>\n\n### `--only-names`\n\nOnly show the name of each plugin by default it will show a \"*\" next to installed plugins\n"
  },
  {
    "path": "docs/cli/plugins/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins ls`\n\n- **Usage**: `mise plugins ls [-o --outdated] [-u --urls]`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/plugins/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/ls.rs)\n\nList installed plugins\n\nCan also show remotely available plugins to install.\n\n## Flags\n\n### `-o --outdated`\n\nShow plugins with available updates\nChecks the remote for newer versions and only displays plugins that are outdated\n\n### `-u --urls`\n\nShow the git url for each plugin\ne.g.: <https://github.com/mise-plugins/vfox-cmake.git>\n\nExamples:\n\n```\n$ mise plugins ls\ncmake\npoetry\n\n$ mise plugins ls --urls\ncmake     https://github.com/mise-plugins/vfox-cmake.git\npoetry    https://github.com/mise-plugins/vfox-poetry.git\n```\n"
  },
  {
    "path": "docs/cli/plugins/uninstall.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins uninstall`\n\n- **Usage**: `mise plugins uninstall [-a --all] [-p --purge] [PLUGIN]…`\n- **Aliases**: `remove`, `rm`\n- **Source code**: [`src/cli/plugins/uninstall.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/uninstall.rs)\n\nRemoves a plugin\n\n## Arguments\n\n### `[PLUGIN]…`\n\nPlugin(s) to remove\n\n## Flags\n\n### `-a --all`\n\nRemove all plugins\n\n### `-p --purge`\n\nAlso remove the plugin's installs, downloads, and cache\n\nExamples:\n\n```\nmise plugins uninstall cmake\n```\n"
  },
  {
    "path": "docs/cli/plugins/update.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins update`\n\n- **Usage**: `mise plugins update [-j --jobs <JOBS>] [PLUGIN]…`\n- **Aliases**: `up`, `upgrade`\n- **Source code**: [`src/cli/plugins/update.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/update.rs)\n\nUpdates a plugin to the latest version\n\nnote: this updates the plugin itself, not the runtime versions\n\n## Arguments\n\n### `[PLUGIN]…`\n\nPlugin(s) to update\n\n## Flags\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\nDefault: 4\n\nExamples:\n\n```\nmise plugins update              # update all plugins\nmise plugins update cmake       # update only cmake\nmise plugins update cmake#beta  # specify a ref\n```\n"
  },
  {
    "path": "docs/cli/plugins.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise plugins`\n\n- **Usage**: `mise plugins [FLAGS] <SUBCOMMAND>`\n- **Aliases**: `p`\n- **Source code**: [`src/cli/plugins/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/plugins/mod.rs)\n\nManage plugins\n\n## Flags\n\n### `-c --core`\n\nThe built-in plugins only\nNormally these are not shown\n\n### `-u --urls`\n\nShow the git url for each plugin\ne.g.: <https://github.com/mise-plugins/vfox-cmake.git>\n\n### `--user`\n\nList installed plugins\n\nThis is the default behavior but can be used with --core\nto show core and user plugins\n\n## Subcommands\n\n- [`mise plugins install [FLAGS] [NEW_PLUGIN] [GIT_URL]`](/cli/plugins/install.md)\n- [`mise plugins link [-f --force] <NAME> [DIR]`](/cli/plugins/link.md)\n- [`mise plugins ls [-o --outdated] [-u --urls]`](/cli/plugins/ls.md)\n- [`mise plugins ls-remote [-u --urls] [--only-names]`](/cli/plugins/ls-remote.md)\n- [`mise plugins uninstall [-a --all] [-p --purge] [PLUGIN]…`](/cli/plugins/uninstall.md)\n- [`mise plugins update [-j --jobs <JOBS>] [PLUGIN]…`](/cli/plugins/update.md)\n"
  },
  {
    "path": "docs/cli/prepare.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise prepare`\n\n- **Usage**: `mise prepare [FLAGS] [PROVIDER]`\n- **Aliases**: `prep`\n- **Source code**: [`src/cli/prepare.rs`](https://github.com/jdx/mise/blob/main/src/cli/prepare.rs)\n\n[experimental] Ensure project dependencies are ready\n\nRuns all applicable prepare steps for the current project.\nThis checks if dependency lockfiles are newer than installed outputs\n(e.g., package-lock.json vs node_modules/) and runs install commands\nif needed.\n\nProviders with `auto = true` are automatically invoked before `mise x` and `mise run`\nunless skipped with the --no-prepare flag.\n\n## Arguments\n\n### `[PROVIDER]`\n\nProvider to operate on (runs only this provider, or use with --explain)\n\n## Flags\n\n### `--explain`\n\nShow why a provider is fresh or stale (requires a provider argument)\n\n### `-f --force`\n\nForce run all prepare steps even if outputs are fresh\n\n### `-n --dry-run`\n\nOnly check if prepare is needed, don't run commands\n\n### `--list`\n\nShow what prepare steps are available\n\n### `--only… <ONLY>`\n\nRun specific prepare rule(s) only\n\n### `--skip… <SKIP>`\n\nSkip specific prepare rule(s)\n\nExamples:\n\n```\nmise prepare              # Run all applicable prepare steps\nmise prepare npm          # Run only npm prepare\nmise prepare npm --explain # Show why npm is fresh or stale\nmise prepare --dry-run    # Show what would run without executing\nmise prepare --force      # Force run even if outputs are fresh\nmise prepare --list       # List available prepare providers\nmise prepare --skip npm   # Skip npm prepare\n```\n\nConfiguration:\n\n```\nConfigure prepare providers in mise.toml:\n\n```toml\n# Built-in npm provider (auto-detects lockfile)\n[prepare.npm]\nauto = true              # Auto-run before mise x/run\n\n# Custom provider\n[prepare.codegen]\nauto = true\nsources = [\"schema/*.graphql\"]\noutputs = [\"src/generated/\"]\nrun = \"npm run codegen\"\n\n[prepare]\ndisable = [\"npm\"]        # Disable specific providers at runtime\n```\n```\n"
  },
  {
    "path": "docs/cli/prune.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise prune`\n\n- **Usage**: `mise prune [FLAGS] [INSTALLED_TOOL]…`\n- **Source code**: [`src/cli/prune.rs`](https://github.com/jdx/mise/blob/main/src/cli/prune.rs)\n\nDelete unused versions of tools\n\nmise tracks which config files have been used in ~/.local/state/mise/tracked-configs\nVersions which are no longer the latest specified in any of those configs are deleted.\nVersions installed only with environment variables `MISE_<PLUGIN>_VERSION` will be deleted,\nas will versions only referenced on the command line `mise exec <PLUGIN>@<VERSION>`.\n\nYou can list prunable tools with `mise ls --prunable`\n\n## Arguments\n\n### `[INSTALLED_TOOL]…`\n\nPrune only these tools\n\n## Flags\n\n### `-n --dry-run`\n\nDo not actually delete anything\n\n### `--configs`\n\nPrune only tracked and trusted configuration links that point to non-existent configurations\n\n### `--dry-run-code`\n\nLike --dry-run but exits with code 1 if there are tools to prune\n\nThis is useful for scripts to check if tools need to be pruned.\n\n### `--tools`\n\nPrune only unused versions of tools\n\nExamples:\n\n```\n$ mise prune --dry-run\nrm -rf ~/.local/share/mise/versions/node/20.0.0\nrm -rf ~/.local/share/mise/versions/node/20.0.1\n```\n"
  },
  {
    "path": "docs/cli/registry.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise registry`\n\n- **Usage**: `mise registry [FLAGS] [NAME]`\n- **Source code**: [`src/cli/registry.rs`](https://github.com/jdx/mise/blob/main/src/cli/registry.rs)\n\nList available tools to install\n\nThis command lists the tools available in the registry as shorthand names.\n\nFor example, `poetry` is shorthand for `asdf:mise-plugins/mise-poetry`.\n\n## Arguments\n\n### `[NAME]`\n\nShow only the specified tool's full name\n\n## Flags\n\n### `-b --backend <BACKEND>`\n\nShow only tools for this backend\n\n### `--hide-aliased`\n\nHide aliased tools\n\n### `-J --json`\n\nOutput in JSON format\n\nExamples:\n\n```\n$ mise registry\nnode    core:node\npoetry  asdf:mise-plugins/mise-poetry\nubi     cargo:ubi-cli\n\n$ mise registry poetry\nasdf:mise-plugins/mise-poetry\n```\n"
  },
  {
    "path": "docs/cli/reshim.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise reshim`\n\n- **Usage**: `mise reshim [-f --force]`\n- **Source code**: [`src/cli/reshim.rs`](https://github.com/jdx/mise/blob/main/src/cli/reshim.rs)\n\nCreates new shims based on bin paths from currently installed tools.\n\nThis creates new shims in ~/.local/share/mise/shims for CLIs that have been added.\nmise will try to do this automatically for commands like `npm i -g` but there are\nother ways to install things (like using yarn or pnpm for node) that mise does\nnot know about and so it will be necessary to call this explicitly.\n\nIf you think mise should automatically call this for a particular command, please\nopen an issue on the mise repo. You can also setup a shell function to reshim\nautomatically (it's really fast so you don't need to worry about overhead):\n\n```\nnpm() {\n  command npm \"$@\"\n  mise reshim\n}\n```\n\nNote that this creates shims for _all_ installed tools, not just the ones that are\ncurrently active in mise.toml.\n\n## Flags\n\n### `-f --force`\n\nRemoves all shims before reshimming\n\nExamples:\n\n```\n$ mise reshim\n$ ~/.local/share/mise/shims/node -v\nv20.0.0\n```\n"
  },
  {
    "path": "docs/cli/run.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise run`\n\n- **Usage**: `mise run [FLAGS]`\n- **Aliases**: `r`\n- **Source code**: [`src/cli/run.rs`](https://github.com/jdx/mise/blob/main/src/cli/run.rs)\n\nRun task(s)\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n```\n[tasks.build]\nrun = \"npm run build\"\nsources = [\"src/**/*.ts\"]\noutputs = [\"dist/**/*.js\"]\n```\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n```\n$ cat .mise/tasks/build&lt;&lt;EOF\n#!/usr/bin/env bash\nnpm run build\nEOF\n$ mise run build\n```\n\n## Flags\n\n### `-c --continue-on-error`\n\nContinue running tasks even if one fails\n\n### `-C --cd <CD>`\n\nChange to this directory before executing the command\n\n### `-f --force`\n\nForce the tasks to run even if outputs are up to date\n\n### `-j --jobs <JOBS>`\n\nNumber of tasks to run in parallel\n[default: 4]\nConfigure with `jobs` config or `MISE_JOBS` env var\n\n### `-n --dry-run`\n\nDon't actually run the task(s), just print them in order of execution\n\n### `-o --output <OUTPUT>`\n\nChange how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors\n\n### `-q --quiet`\n\nDon't show extra output\n\n### `-r --raw`\n\nRead/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var\n\n### `-s --shell <SHELL>`\n\nShell to use to run toml tasks\n\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task.\n\n### `-S --silent`\n\nDon't show any output except for errors\n\n### `-t --tool… <TOOL@VERSION>`\n\nTool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\n\n### `--fresh-env`\n\nBypass the environment cache and recompute the environment\n\n### `--no-cache`\n\nDo not use cache on remote tasks\n\n### `--no-prepare`\n\nSkip automatic dependency preparation\n\n### `--no-timings`\n\nHides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`\n\n### `--skip-deps`\n\nRun only the specified tasks skipping all dependencies\n\n### `--timeout <TIMEOUT>`\n\nTimeout for the task to complete\ne.g.: 30s, 5m\n\nExamples:\n\n```\n# Runs the \"lint\" tasks. This needs to either be defined in mise.toml\n# or as a standalone script. See the project README for more information.\n$ mise run lint\n\n# Forces the \"build\" tasks to run even if its sources are up-to-date.\n$ mise run --force build\n\n# Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n# This forces `--jobs=1` to prevent interleaving of output.\n$ mise run --raw test\n\n# Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n$ mise run lint ::: test ::: check\n\n# Execute multiple tasks each with their own arguments.\n$ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n```\n"
  },
  {
    "path": "docs/cli/search.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise search`\n\n- **Usage**: `mise search [FLAGS] [NAME]`\n- **Source code**: [`src/cli/search.rs`](https://github.com/jdx/mise/blob/main/src/cli/search.rs)\n\nSearch for tools in the registry\n\nThis command searches a tool in the registry.\n\nBy default, it will show all tools that fuzzy match the search term. For\nnon-fuzzy matches, use the `--match-type` flag.\n\n## Arguments\n\n### `[NAME]`\n\nThe tool to search for\n\n## Flags\n\n### `-i --interactive`\n\nShow interactive search\n\n### `-m --match-type <MATCH_TYPE>`\n\nMatch type: equal, contains, or fuzzy\n\n**Choices:**\n\n- `equal`\n- `contains`\n- `fuzzy`\n\n**Default:** `fuzzy`\n\n### `--no-header`\n\nDon't display headers\n\nExamples:\n\n```\n$ mise search jq\nTool  Description\njq    Command-line JSON processor. https://github.com/jqlang/jq\njqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\njiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\ngojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\n\n$ mise search --interactive\nTool\nSearch a tool\n❯ jq    Command-line JSON processor. https://github.com/jqlang/jq\n  jqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\n  jiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\n  gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\n/jq \nesc clear filter • enter confirm\n```\n"
  },
  {
    "path": "docs/cli/self-update.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise self-update`\n\n- **Usage**: `mise self-update [FLAGS] [VERSION]`\n- **Source code**: [`src/cli/self_update.rs`](https://github.com/jdx/mise/blob/main/src/cli/self_update.rs)\n\nUpdates mise itself.\n\nUses the GitHub Releases API to find the latest release and binary.\nBy default, this will also update any installed plugins.\nUses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits.\n\nThis command is not available if mise is installed via a package manager.\n\n## Arguments\n\n### `[VERSION]`\n\nUpdate to a specific version\n\n## Flags\n\n### `-f --force`\n\nUpdate even if already up to date\n\n### `-y --yes`\n\nSkip confirmation prompt\n\n### `--no-plugins`\n\nDisable auto-updating plugins\n"
  },
  {
    "path": "docs/cli/set.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise set`\n\n- **Usage**: `mise set [FLAGS] [ENV_VAR]…`\n- **Source code**: [`src/cli/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/set.rs)\n\nSet environment variables in mise.toml\n\nBy default, this command modifies `mise.toml` in the current directory.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee <https://mise.jdx.dev/configuration.html#target-file-for-write-operations>\n\nUse `-E <env>` to create/modify environment-specific config files like `mise.<env>.toml`.\n\n## Arguments\n\n### `[ENV_VAR]…`\n\nEnvironment variable(s) to set\ne.g.: NODE_ENV=production\n\n## Flags\n\n### `-E --env <ENV>`\n\nCreate/modify an environment-specific config file like .mise.&lt;env>.toml\n\n### `-g --global`\n\nSet the environment variable in the global config file\n\n### `--age-encrypt`\n\n[experimental] Encrypt the value with age before storing\n\n### `--age-key-file <PATH>`\n\n[experimental] Age identity file for encryption\n\nDefaults to ~/.config/mise/age.txt if it exists\n\n### `--age-recipient… <RECIPIENT>`\n\n[experimental] Age recipient (x25519 public key) for encryption\n\nCan be used multiple times. Requires --age-encrypt.\n\n### `--age-ssh-recipient… <PATH_OR_PUBKEY>`\n\n[experimental] SSH recipient (public key or path) for age encryption\n\nCan be used multiple times. Requires --age-encrypt.\n\n### `--file <FILE>`\n\nThe TOML file to update\n\nCan be a file path or directory. If a directory is provided, will create/use mise.toml in that directory.\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`.\n\n### `--no-redact`\n\nShow raw values instead of redacting secrets\n\n### `--prompt`\n\nPrompt for environment variable values\n\n### `--stdin`\n\nRead the value from stdin (for multiline input)\n\nWhen using --stdin, provide a single key without a value. The value will be read from stdin until EOF.\n\nExamples:\n\n```\n$ mise set NODE_ENV=production\n\n$ mise set NODE_ENV\nproduction\n\n$ mise set -E staging NODE_ENV=staging\n# creates or modifies mise.staging.toml\n\n$ mise set\nkey       value       source\nNODE_ENV  production  ~/.config/mise/config.toml\n\n$ mise set --prompt PASSWORD\nEnter value for PASSWORD: [hidden input]\n\nMultiline Values (--stdin):\n\n$ cat private.key | mise set --stdin MY_KEY\n\n$ printf \"line1\\nline2\" | mise set --stdin MY_KEY\n\n[experimental] Age Encryption:\n\n$ mise set --age-encrypt API_KEY=secret\n\n$ mise set --age-encrypt --prompt API_KEY\nEnter value for API_KEY: [hidden input]\n```\n"
  },
  {
    "path": "docs/cli/settings/add.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings add`\n\n- **Usage**: `mise settings add [-l --local] <SETTING> [VALUE]`\n- **Source code**: [`src/cli/settings/add.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/add.rs)\n\nAdds a setting to the configuration file\n\nUsed with an array setting, this will append the value to the array.\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<SETTING>`\n\nThe setting to set\n\n### `[VALUE]`\n\nThe value to set (optional if provided as KEY=VALUE)\n\n## Flags\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\nExamples:\n\n```\nmise settings add disable_hints python_multi\n```\n"
  },
  {
    "path": "docs/cli/settings/get.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings get`\n\n- **Usage**: `mise settings get [-l --local] <SETTING>`\n- **Source code**: [`src/cli/settings/get.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/get.rs)\n\nShow a current setting\n\nThis is the contents of a single entry in ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool-alias get`\n\n## Arguments\n\n### `<SETTING>`\n\nThe setting to show\n\n## Flags\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\nExamples:\n\n```\n$ mise settings get idiomatic_version_file\ntrue\n```\n"
  },
  {
    "path": "docs/cli/settings/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings ls`\n\n- **Usage**: `mise settings ls [FLAGS] [SETTING]`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/settings/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/ls.rs)\n\nShow current settings\n\nThis is the contents of ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool-alias`\n\n## Arguments\n\n### `[SETTING]`\n\nName of setting\n\n## Flags\n\n### `-a --all`\n\nList all settings\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\n### `-T --toml`\n\nOutput in TOML format\n\n### `--json-extended`\n\nOutput in JSON format with sources\n\nExamples:\n\n```\n$ mise settings ls\nidiomatic_version_file = false\n...\n\n$ mise settings ls python\ndefault_packages_file = \"~/.default-python-packages\"\n...\n```\n"
  },
  {
    "path": "docs/cli/settings/set.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings set`\n\n- **Usage**: `mise settings set [-l --local] <SETTING> [VALUE]`\n- **Aliases**: `create`\n- **Source code**: [`src/cli/settings/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/set.rs)\n\nAdd/update a setting\n\nThis modifies the contents of ~/.config/mise/config.toml by default.\nWith `--local`, modifies the local config file instead.\nSee <https://mise.jdx.dev/configuration.html#target-file-for-write-operations>\n\n## Arguments\n\n### `<SETTING>`\n\nThe setting to set\n\n### `[VALUE]`\n\nThe value to set (optional if provided as KEY=VALUE)\n\n## Flags\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\nExamples:\n\n```\nmise settings idiomatic_version_file=true\n```\n"
  },
  {
    "path": "docs/cli/settings/unset.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings unset`\n\n- **Usage**: `mise settings unset [-l --local] <KEY>`\n- **Aliases**: `rm`, `remove`, `delete`, `del`\n- **Source code**: [`src/cli/settings/unset.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/unset.rs)\n\nClears a setting\n\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<KEY>`\n\nThe setting to remove\n\n## Flags\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\nExamples:\n\n```\nmise settings unset idiomatic_version_file\n```\n"
  },
  {
    "path": "docs/cli/settings.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise settings`\n\n- **Usage**: `mise settings [FLAGS] [SETTING] [VALUE] <SUBCOMMAND>`\n- **Source code**: [`src/cli/settings/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/settings/mod.rs)\n\nShow current settings\n\nThis is the contents of ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool-alias`\n\n## Arguments\n\n### `[SETTING]`\n\nName of setting\n\n### `[VALUE]`\n\nSetting value to set\n\n## Global Flags\n\n### `-l --local`\n\nUse the local config file instead of the global one\n\n## Flags\n\n### `-a --all`\n\nList all settings\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-T --toml`\n\nOutput in TOML format\n\n### `--json-extended`\n\nOutput in JSON format with sources\n\n## Subcommands\n\n- [`mise settings add [-l --local] <SETTING> [VALUE]`](/cli/settings/add.md)\n- [`mise settings get [-l --local] <SETTING>`](/cli/settings/get.md)\n- [`mise settings ls [FLAGS] [SETTING]`](/cli/settings/ls.md)\n- [`mise settings set [-l --local] <SETTING> [VALUE]`](/cli/settings/set.md)\n- [`mise settings unset [-l --local] <KEY>`](/cli/settings/unset.md)\n\nExamples:\n```\n# list all settings\n$ mise settings\n\n# get the value of the setting \"always_keep_download\"\n$ mise settings always_keep_download\n\n# set the value of the setting \"always_keep_download\" to \"true\"\n$ mise settings always_keep_download=true\n\n# set the value of the setting \"node.mirror_url\" to \"https://npm.taobao.org/mirrors/node\"\n$ mise settings node.mirror_url https://npm.taobao.org/mirrors/node\n```\n"
  },
  {
    "path": "docs/cli/shell-alias/get.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell-alias get`\n\n- **Usage**: `mise shell-alias get <shell_alias>`\n- **Source code**: [`src/cli/shell_alias/get.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell_alias/get.rs)\n\nShow the command for a shell alias\n\n## Arguments\n\n### `<shell_alias>`\n\nThe alias to show\n\nExamples:\n\n```\n$ mise shell-alias get ll\nls -la\n```\n"
  },
  {
    "path": "docs/cli/shell-alias/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell-alias ls`\n\n- **Usage**: `mise shell-alias ls [--no-header]`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/shell_alias/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell_alias/ls.rs)\n\nList shell aliases\n\nShows the shell aliases that are set in the current directory.\nThese are defined in `mise.toml` under the `[shell_alias]` section.\n\n## Flags\n\n### `--no-header`\n\nDon't show table header\n\nExamples:\n\n```\n$ mise shell-alias ls\nalias    command\nll       ls -la\ngs       git status\n```\n"
  },
  {
    "path": "docs/cli/shell-alias/set.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell-alias set`\n\n- **Usage**: `mise shell-alias set <shell_alias> [COMMAND]`\n- **Aliases**: `add`, `create`\n- **Source code**: [`src/cli/shell_alias/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell_alias/set.rs)\n\nAdd/update a shell alias\n\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<shell_alias>`\n\nThe alias name\n\n### `[COMMAND]`\n\nThe command to run (optional if provided as ALIAS=COMMAND)\n\nExamples:\n\n```\nmise shell-alias set ll \"ls -la\"\nmise shell-alias set gs \"git status\"\n```\n"
  },
  {
    "path": "docs/cli/shell-alias/unset.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell-alias unset`\n\n- **Usage**: `mise shell-alias unset <shell_alias>`\n- **Aliases**: `rm`, `remove`, `delete`, `del`\n- **Source code**: [`src/cli/shell_alias/unset.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell_alias/unset.rs)\n\nRemoves a shell alias\n\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<shell_alias>`\n\nThe alias to remove\n\nExamples:\n\n```\nmise shell-alias unset ll\n```\n"
  },
  {
    "path": "docs/cli/shell-alias.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell-alias`\n\n- **Usage**: `mise shell-alias [--no-header] <SUBCOMMAND>`\n- **Source code**: [`src/cli/shell_alias/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell_alias/mod.rs)\n\nManage shell aliases.\n\n## Flags\n\n### `--no-header`\n\nDon't show table header\n\n## Subcommands\n\n- [`mise shell-alias get <shell_alias>`](/cli/shell-alias/get.md)\n- [`mise shell-alias ls [--no-header]`](/cli/shell-alias/ls.md)\n- [`mise shell-alias set <shell_alias> [COMMAND]`](/cli/shell-alias/set.md)\n- [`mise shell-alias unset <shell_alias>`](/cli/shell-alias/unset.md)\n"
  },
  {
    "path": "docs/cli/shell.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise shell`\n\n- **Usage**: `mise shell [FLAGS] <TOOL@VERSION>…`\n- **Aliases**: `sh`\n- **Source code**: [`src/cli/shell.rs`](https://github.com/jdx/mise/blob/main/src/cli/shell.rs)\n\nSets a tool version for the current session.\n\nOnly works in a session where mise is already activated.\n\nThis works by setting environment variables for the current shell session\nsuch as `MISE_NODE_VERSION=20` which is \"eval\"ed as a shell function created by `mise activate`.\n\n## Arguments\n\n### `<TOOL@VERSION>…`\n\nTool(s) to use\n\n## Flags\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `-u --unset`\n\nRemoves a previously set version\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\n\nExamples:\n\n```\n$ mise shell node@20\n$ node -v\nv20.0.0\n```\n"
  },
  {
    "path": "docs/cli/sync/node.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise sync node`\n\n- **Usage**: `mise sync node [FLAGS]`\n- **Source code**: [`src/cli/sync/node.rs`](https://github.com/jdx/mise/blob/main/src/cli/sync/node.rs)\n\nSymlinks all tool versions from an external tool into mise\n\nFor example, use this to import all Homebrew node installs into mise\n\nThis won't overwrite any existing installs but will overwrite any existing symlinks\n\n## Flags\n\n### `--brew`\n\nGet tool versions from Homebrew\n\n### `--nodenv`\n\nGet tool versions from nodenv\n\n### `--nvm`\n\nGet tool versions from nvm\n\nExamples:\n\n```\nbrew install node@18 node@20\nmise sync node --brew\nmise use -g node@18 - uses Homebrew-provided node\n```\n"
  },
  {
    "path": "docs/cli/sync/python.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise sync python`\n\n- **Usage**: `mise sync python [--pyenv] [--uv]`\n- **Source code**: [`src/cli/sync/python.rs`](https://github.com/jdx/mise/blob/main/src/cli/sync/python.rs)\n\nSymlinks all tool versions from an external tool into mise\n\nFor example, use this to import all pyenv installs into mise\n\nThis won't overwrite any existing installs but will overwrite any existing symlinks\n\n## Flags\n\n### `--pyenv`\n\nGet tool versions from pyenv\n\n### `--uv`\n\nSync tool versions with uv (2-way sync)\n\nExamples:\n\n```\npyenv install 3.11.0\nmise sync python --pyenv\nmise use -g python@3.11.0 - uses pyenv-provided python\n\nuv python install 3.11.0\nmise install python@3.10.0\nmise sync python --uv\nmise x python@3.11.0 -- python -V - uses uv-provided python\nuv run -p 3.10.0 -- python -V - uses mise-provided python\n```\n"
  },
  {
    "path": "docs/cli/sync/ruby.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise sync ruby`\n\n- **Usage**: `mise sync ruby [--brew]`\n- **Source code**: [`src/cli/sync/ruby.rs`](https://github.com/jdx/mise/blob/main/src/cli/sync/ruby.rs)\n\nSymlinks all ruby tool versions from an external tool into mise\n\n## Flags\n\n### `--brew`\n\nGet tool versions from Homebrew\n\nExamples:\n\n```\nbrew install ruby\nmise sync ruby --brew\nmise use -g ruby - Use the latest version of Ruby installed by Homebrew\n```\n"
  },
  {
    "path": "docs/cli/sync.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise sync`\n\n- **Usage**: `mise sync <SUBCOMMAND>`\n- **Source code**: [`src/cli/sync/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/sync/mod.rs)\n\nSynchronize tools from other version managers with mise\n\n## Subcommands\n\n- [`mise sync node [FLAGS]`](/cli/sync/node.md)\n- [`mise sync python [--pyenv] [--uv]`](/cli/sync/python.md)\n- [`mise sync ruby [--brew]`](/cli/sync/ruby.md)\n"
  },
  {
    "path": "docs/cli/tasks/add.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks add`\n\n- **Usage**: `mise tasks add [FLAGS] <TASK> [-- RUN]…`\n- **Source code**: [`src/cli/tasks/add.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/add.rs)\n\nCreate a new task\n\nAdds a task to the local mise.toml file.\nSee <https://mise.jdx.dev/configuration.html#target-file-for-write-operations>\n\n## Arguments\n\n### `<TASK>`\n\nTasks name to add\n\n### `[-- RUN]…`\n\n## Flags\n\n### `-a --alias… <ALIAS>`\n\nOther names for the task\n\n### `-d --depends… <DEPENDS>`\n\nAdd dependencies to the task\n\n### `-D --dir <DIR>`\n\nRun the task in a specific directory\n\n### `-f --file`\n\nCreate a file task instead of a toml task\n\n### `-H --hide`\n\nHide the task from `mise tasks` and completions\n\n### `-q --quiet`\n\nDo not print the command before running\n\n### `-r --raw`\n\nDirectly connect stdin/stdout/stderr\n\n### `-s --sources… <SOURCES>`\n\nGlob patterns of files this task uses as input\n\n### `-w --wait-for… <WAIT_FOR>`\n\nWait for these tasks to complete if they are to run\n\n### `--depends-post… <DEPENDS_POST>`\n\nDependencies to run after the task runs\n\n### `--description <DESCRIPTION>`\n\nDescription of the task\n\n### `--outputs… <OUTPUTS>`\n\nGlob patterns of files this task creates, to skip if they are not modified\n\n### `--run-windows <RUN_WINDOWS>`\n\nCommand to run on windows\n\n### `--shell <SHELL>`\n\nRun the task in a specific shell\n\n### `--silent`\n\nDo not print the command or its output\n\nExamples:\n\n```\nmise tasks add pre-commit --depends \"test\" --depends \"render\" -- echo pre-commit\n```\n"
  },
  {
    "path": "docs/cli/tasks/deps.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks deps`\n\n- **Usage**: `mise tasks deps [--dot] [--hidden] [TASKS]…`\n- **Source code**: [`src/cli/tasks/deps.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/deps.rs)\n\nDisplay a tree visualization of a dependency graph\n\n## Arguments\n\n### `[TASKS]…`\n\nTasks to show dependencies for\nCan specify multiple tasks by separating with spaces\ne.g.: mise tasks deps lint test check\n\n## Flags\n\n### `--dot`\n\nDisplay dependencies in DOT format\n\n### `--hidden`\n\nShow hidden tasks\n\nExamples:\n\n```\n# Show dependencies for all tasks\n$ mise tasks deps\n\n# Show dependencies for the \"lint\", \"test\" and \"check\" tasks\n$ mise tasks deps lint test check\n\n# Show dependencies in DOT format\n$ mise tasks deps --dot\n```\n"
  },
  {
    "path": "docs/cli/tasks/edit.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks edit`\n\n- **Usage**: `mise tasks edit [-p --path] <TASK>`\n- **Source code**: [`src/cli/tasks/edit.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/edit.rs)\n\nEdit a task with $EDITOR\n\nThe task will be created as a standalone script if it does not already exist.\n\n## Arguments\n\n### `<TASK>`\n\nTask to edit\n\n## Flags\n\n### `-p --path`\n\nDisplay the path to the task instead of editing it\n\nExamples:\n\n```\nmise tasks edit build\nmise tasks edit test\n```\n"
  },
  {
    "path": "docs/cli/tasks/info.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks info`\n\n- **Usage**: `mise tasks info [-J --json] <TASK>`\n- **Source code**: [`src/cli/tasks/info.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/info.rs)\n\nGet information about a task\n\n## Arguments\n\n### `<TASK>`\n\nName of the task to get information about\n\n## Flags\n\n### `-J --json`\n\nOutput in JSON format\n\nExamples:\n\n```\n$ mise tasks info\nName: test\nAliases: t\nDescription: Test the application\nSource: ~/src/myproj/mise.toml\n\n$ mise tasks info test --json\n{\n  \"name\": \"test\",\n  \"aliases\": \"t\",\n  \"description\": \"Test the application\",\n  \"source\": \"~/src/myproj/mise.toml\",\n  \"depends\": [],\n  \"env\": {},\n  \"dir\": null,\n  \"hide\": false,\n  \"raw\": false,\n  \"sources\": [],\n  \"outputs\": [],\n  \"run\": [\n    \"echo \\\"testing!\\\"\"\n  ],\n  \"file\": null,\n  \"usage_spec\": {}\n}\n```\n"
  },
  {
    "path": "docs/cli/tasks/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks ls`\n\n- **Usage**: `mise tasks ls [FLAGS]`\n- **Source code**: [`src/cli/tasks/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/ls.rs)\n\nList available tasks to execute\nThese may be included from the config file or from the project's .mise/tasks directory\nmise will merge all tasks from all parent directories into this list.\n\nSo if you have global tasks in `~/.config/mise/tasks/*` and project-specific tasks in\n~/myproject/.mise/tasks/*, then they'll both be available but the project-specific\ntasks will override the global ones if they have the same name.\n\n## Flags\n\n### `-g --global`\n\nOnly show global tasks\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-l --local`\n\nOnly show non-global tasks\n\n### `-x --extended`\n\nShow all columns\n\n### `--all`\n\nLoad all tasks from the entire monorepo, including sibling directories.\nBy default, only tasks from the current directory hierarchy are loaded.\n\n### `--hidden`\n\nShow hidden tasks\n\n### `--no-header`\n\nDo not print table header\n\n### `--sort <COLUMN>`\n\nSort by column. Default is name.\n\n**Choices:**\n\n- `name`\n- `alias`\n- `description`\n- `source`\n\n### `--sort-order <SORT_ORDER>`\n\nSort order. Default is asc.\n\n**Choices:**\n\n- `asc`\n- `desc`\n\nExamples:\n\n```\nmise tasks ls\n```\n"
  },
  {
    "path": "docs/cli/tasks/run.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks run`\n\n- **Usage**: `mise tasks run [FLAGS] [TASK] [ARGS]…`\n- **Aliases**: `r`\n- **Source code**: [`src/cli/tasks/run.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/run.rs)\n\nRun task(s)\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n```\n[tasks.build]\nrun = \"npm run build\"\nsources = [\"src/**/*.ts\"]\noutputs = [\"dist/**/*.js\"]\n```\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n```\n$ cat .mise/tasks/build&lt;&lt;EOF\n#!/usr/bin/env bash\nnpm run build\nEOF\n$ mise run build\n```\n\n## Arguments\n\n### `[TASK]`\n\nTasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\n\n**Default:** `default`\n\n### `[ARGS]…`\n\nArguments to pass to the tasks. Use \":::\" to separate tasks\n\n## Flags\n\n### `-c --continue-on-error`\n\nContinue running tasks even if one fails\n\n### `-C --cd <CD>`\n\nChange to this directory before executing the command\n\n### `-f --force`\n\nForce the tasks to run even if outputs are up to date\n\n### `-j --jobs <JOBS>`\n\nNumber of tasks to run in parallel\n[default: 4]\nConfigure with `jobs` config or `MISE_JOBS` env var\n\n### `-n --dry-run`\n\nDon't actually run the task(s), just print them in order of execution\n\n### `-o --output <OUTPUT>`\n\nChange how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors\n\n### `-q --quiet`\n\nDon't show extra output\n\n### `-r --raw`\n\nRead/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var\n\n### `-s --shell <SHELL>`\n\nShell to use to run toml tasks\n\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task.\n\n### `-S --silent`\n\nDon't show any output except for errors\n\n### `-t --tool… <TOOL@VERSION>`\n\nTool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\n\n### `--fresh-env`\n\nBypass the environment cache and recompute the environment\n\n### `--no-cache`\n\nDo not use cache on remote tasks\n\n### `--no-prepare`\n\nSkip automatic dependency preparation\n\n### `--no-timings`\n\nHides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`\n\n### `--skip-deps`\n\nRun only the specified tasks skipping all dependencies\n\n### `--timeout <TIMEOUT>`\n\nTimeout for the task to complete\ne.g.: 30s, 5m\n\nExamples:\n\n```\n# Runs the \"lint\" tasks. This needs to either be defined in mise.toml\n# or as a standalone script. See the project README for more information.\n$ mise run lint\n\n# Forces the \"build\" tasks to run even if its sources are up-to-date.\n$ mise run --force build\n\n# Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n# This forces `--jobs=1` to prevent interleaving of output.\n$ mise run --raw test\n\n# Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n$ mise run lint ::: test ::: check\n\n# Execute multiple tasks each with their own arguments.\n$ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n```\n"
  },
  {
    "path": "docs/cli/tasks/validate.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks validate`\n\n- **Usage**: `mise tasks validate [--errors-only] [--json] [TASKS]…`\n- **Source code**: [`src/cli/tasks/validate.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/validate.rs)\n\nValidate tasks for common errors and issues\n\n## Arguments\n\n### `[TASKS]…`\n\nTasks to validate\nIf not specified, validates all tasks\n\n## Flags\n\n### `--errors-only`\n\nOnly show errors (skip warnings)\n\n### `--json`\n\nOutput validation results in JSON format\n\nExamples:\n\n```\n# Validate all tasks\n$ mise tasks validate\n\n# Validate specific tasks\n$ mise tasks validate build test\n\n# Output results as JSON\n$ mise tasks validate --json\n\n# Only show errors (skip warnings)\n$ mise tasks validate --errors-only\n```\n\nValidation Checks:\n\nThe validate command performs the following checks:\n\n  • Circular Dependencies: Detects dependency cycles\n  • Missing References: Finds references to non-existent tasks\n  • Usage Spec Parsing: Validates #USAGE directives and specs\n  • Timeout Format: Checks timeout values are valid durations\n  • Alias Conflicts: Detects duplicate aliases across tasks\n  • File Existence: Verifies file-based tasks exist\n  • Directory Templates: Validates directory paths and templates\n  • Shell Commands: Checks shell executables exist\n  • Glob Patterns: Validates source and output patterns\n  • Run Entries: Ensures tasks reference valid dependencies\n"
  },
  {
    "path": "docs/cli/tasks.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tasks`\n\n- **Usage**: `mise tasks [FLAGS] [TASK] <SUBCOMMAND>`\n- **Aliases**: `t`\n- **Source code**: [`src/cli/tasks/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/tasks/mod.rs)\n\nManage tasks\n\n## Arguments\n\n### `[TASK]`\n\nTask name to get info of\n\n## Global Flags\n\n### `-g --global`\n\nOnly show global tasks\n\n### `-J --json`\n\nOutput in JSON format\n\n### `-l --local`\n\nOnly show non-global tasks\n\n### `-x --extended`\n\nShow all columns\n\n### `--all`\n\nLoad all tasks from the entire monorepo, including sibling directories.\nBy default, only tasks from the current directory hierarchy are loaded.\n\n### `--hidden`\n\nShow hidden tasks\n\n### `--no-header`\n\nDo not print table header\n\n### `--sort <COLUMN>`\n\nSort by column. Default is name.\n\n**Choices:**\n\n- `name`\n- `alias`\n- `description`\n- `source`\n\n### `--sort-order <SORT_ORDER>`\n\nSort order. Default is asc.\n\n**Choices:**\n\n- `asc`\n- `desc`\n\n## Subcommands\n\n- [`mise tasks add [FLAGS] <TASK> [-- RUN]…`](/cli/tasks/add.md)\n- [`mise tasks deps [--dot] [--hidden] [TASKS]…`](/cli/tasks/deps.md)\n- [`mise tasks edit [-p --path] <TASK>`](/cli/tasks/edit.md)\n- [`mise tasks info [-J --json] <TASK>`](/cli/tasks/info.md)\n- [`mise tasks ls [FLAGS]`](/cli/tasks/ls.md)\n- [`mise tasks run [FLAGS] [TASK] [ARGS]…`](/cli/tasks/run.md)\n- [`mise tasks validate [--errors-only] [--json] [TASKS]…`](/cli/tasks/validate.md)\n\nExamples:\n\n```\nmise tasks ls\n```\n"
  },
  {
    "path": "docs/cli/test-tool.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise test-tool`\n\n- **Usage**: `mise test-tool [FLAGS] [TOOLS]…`\n- **Source code**: [`src/cli/test_tool.rs`](https://github.com/jdx/mise/blob/main/src/cli/test_tool.rs)\n\nTest a tool installs and executes\n\n## Arguments\n\n### `[TOOLS]…`\n\nTool(s) to test\n\n## Flags\n\n### `-a --all`\n\nTest every tool specified in registry/\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `--all-config`\n\nTest all tools specified in config files\n\n### `--include-non-defined`\n\nAlso test tools not defined in registry/, guessing how to test it\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\n\nExamples:\n\n```\nmise test-tool ripgrep\n```\n"
  },
  {
    "path": "docs/cli/tool-alias/get.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-alias get`\n\n- **Usage**: `mise tool-alias get <PLUGIN> <ALIAS>`\n- **Source code**: [`src/cli/tool_alias/get.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_alias/get.rs)\n\nShow an alias for a plugin\n\nThis is the contents of a tool_alias.&lt;PLUGIN> entry in ~/.config/mise/config.toml\n\n## Arguments\n\n### `<PLUGIN>`\n\nThe plugin to show the alias for\n\n### `<ALIAS>`\n\nThe alias to show\n\nExamples:\n\n```\n$ mise tool-alias get node lts-hydrogen\n20.0.0\n```\n"
  },
  {
    "path": "docs/cli/tool-alias/ls.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-alias ls`\n\n- **Usage**: `mise tool-alias ls [--no-header] [TOOL]`\n- **Aliases**: `list`\n- **Source code**: [`src/cli/tool_alias/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_alias/ls.rs)\n\nList tool version aliases\nShows the aliases that can be specified.\nThese can come from user config or from plugins in `bin/list-aliases`.\n\nFor user config, aliases are defined like the following in `~/.config/mise/config.toml`:\n\n```\n[tool_alias.node.versions]\nlts = \"22.0.0\"\n```\n\n## Arguments\n\n### `[TOOL]`\n\nShow aliases for &lt;TOOL>\n\n## Flags\n\n### `--no-header`\n\nDon't show table header\n\nExamples:\n\n```\n$ mise tool-alias ls\nnode  lts-jod      22\n```\n"
  },
  {
    "path": "docs/cli/tool-alias/set.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-alias set`\n\n- **Usage**: `mise tool-alias set <ARGS>…`\n- **Aliases**: `add`, `create`\n- **Source code**: [`src/cli/tool_alias/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_alias/set.rs)\n\nAdd/update an alias for a backend/plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<PLUGIN>`\n\nThe backend/plugin to set the alias for\n\n### `<ALIAS>`\n\nThe alias to set\n\n### `[VALUE]`\n\nThe value to set the alias to\n\nExamples:\n\n```\nmise tool-alias set maven asdf:mise-plugins/mise-maven\nmise tool-alias set node lts-jod 22.0.0\n```\n"
  },
  {
    "path": "docs/cli/tool-alias/unset.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-alias unset`\n\n- **Usage**: `mise tool-alias unset <PLUGIN> [ALIAS]`\n- **Aliases**: `rm`, `remove`, `delete`, `del`\n- **Source code**: [`src/cli/tool_alias/unset.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_alias/unset.rs)\n\nClears an alias for a backend/plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\n\n## Arguments\n\n### `<PLUGIN>`\n\nThe backend/plugin to remove the alias from\n\n### `[ALIAS]`\n\nThe alias to remove\n\nExamples:\n\n```\nmise tool-alias unset maven\nmise tool-alias unset node lts-jod\n```\n"
  },
  {
    "path": "docs/cli/tool-alias.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-alias`\n\n- **Usage**: `mise tool-alias [-p --plugin <PLUGIN>] [--no-header] <SUBCOMMAND>`\n- **Source code**: [`src/cli/tool_alias/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_alias/mod.rs)\n\nManage tool version aliases.\n\n## Flags\n\n### `-p --plugin <PLUGIN>`\n\nfilter aliases by plugin\n\n### `--no-header`\n\nDon't show table header\n\n## Subcommands\n\n- [`mise tool-alias get <PLUGIN> <ALIAS>`](/cli/tool-alias/get.md)\n- [`mise tool-alias ls [--no-header] [TOOL]`](/cli/tool-alias/ls.md)\n- [`mise tool-alias set <ARGS>…`](/cli/tool-alias/set.md)\n- [`mise tool-alias unset <PLUGIN> [ALIAS]`](/cli/tool-alias/unset.md)\n"
  },
  {
    "path": "docs/cli/tool-stub.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool-stub`\n\n- **Usage**: `mise tool-stub <FILE> [ARGS]…`\n- **Source code**: [`src/cli/tool_stub.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool_stub.rs)\n\nExecute a tool stub\n\nTool stubs are executable files containing TOML configuration that specify which tool to run and how to run it. They provide a convenient way to create portable, self-contained executables that automatically manage tool installation and execution.\n\nA tool stub consists of: - A shebang line: #!/usr/bin/env -S mise tool-stub - TOML configuration specifying the tool, version, and options - Optional comments describing the tool's purpose\n\nExample stub file: #!/usr/bin/env -S mise tool-stub # Node.js v20 development environment\n\ntool = \"node\" version = \"20.0.0\" bin = \"node\"\n\nThe stub will automatically install the specified tool version if missing and execute it with any arguments passed to the stub.\n\nFor more information, see: <https://mise.jdx.dev/dev-tools/tool-stubs.html>\n\n## Arguments\n\n### `<FILE>`\n\nPath to the TOML tool stub file to execute\n\nThe stub file must contain TOML configuration specifying the tool and version to run. At minimum, it should specify a 'version' field. Other common fields include 'tool', 'bin', and backend-specific options.\n\n### `[ARGS]…`\n\nArguments to pass to the tool\n\nAll arguments after the stub file path will be forwarded to the underlying tool. Use '--' to separate mise arguments from tool arguments if needed.\n"
  },
  {
    "path": "docs/cli/tool.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise tool`\n\n- **Usage**: `mise tool [FLAGS] <TOOL>`\n- **Source code**: [`src/cli/tool.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool.rs)\n\nGets information about a tool\n\n## Arguments\n\n### `<TOOL>`\n\nTool name to get information about\n\n## Flags\n\n### `-J --json`\n\nOutput in JSON format\n\n### `--active`\n\nOnly show active versions\n\n### `--backend`\n\nOnly show backend field\n\n### `--config-source`\n\nOnly show config source\n\n### `--description`\n\nOnly show description field\n\n### `--installed`\n\nOnly show installed versions\n\n### `--requested`\n\nOnly show requested versions\n\n### `--tool-options`\n\nOnly show tool options\n\nExamples:\n\n```\n$ mise tool node\nBackend:            core\nInstalled Versions: 20.0.0 22.0.0\nActive Version:     20.0.0\nRequested Version:  20\nConfig Source:      ~/.config/mise/mise.toml\nTool Options:       [none]\n```\n"
  },
  {
    "path": "docs/cli/trust.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise trust`\n\n- **Usage**: `mise trust [FLAGS] [CONFIG_FILE]`\n- **Source code**: [`src/cli/trust.rs`](https://github.com/jdx/mise/blob/main/src/cli/trust.rs)\n\nMarks a config file as trusted\n\nThis means mise will parse the file with potentially dangerous\nfeatures enabled.\n\nThis includes:\n- environment variables\n- templates\n- `path:` plugin versions\n\n## Arguments\n\n### `[CONFIG_FILE]`\n\nThe config file to trust\n\n## Flags\n\n### `-a --all`\n\nTrust all config files in the current directory and its parents\n\n### `--ignore`\n\nDo not trust this config and ignore it in the future\n\n### `--show`\n\nShow the trusted status of config files from the current directory and its parents.\nDoes not trust or untrust any files.\n\n### `--untrust`\n\nNo longer trust this config, will prompt in the future\n\nExamples:\n\n```\n# trusts ~/some_dir/mise.toml\n$ mise trust ~/some_dir/mise.toml\n\n# trusts mise.toml in the current or parent directory\n$ mise trust\n```\n"
  },
  {
    "path": "docs/cli/uninstall.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise uninstall`\n\n- **Usage**: `mise uninstall [FLAGS] [INSTALLED_TOOL@VERSION]…`\n- **Source code**: [`src/cli/uninstall.rs`](https://github.com/jdx/mise/blob/main/src/cli/uninstall.rs)\n\nRemoves installed tool versions\n\nThis only removes the installed version, it does not modify mise.toml.\n\n## Arguments\n\n### `[INSTALLED_TOOL@VERSION]…`\n\nTool(s) to remove\n\n## Flags\n\n### `-a --all`\n\nDelete all installed versions\n\n### `-n --dry-run`\n\nDo not actually delete anything\n\n### `--dry-run-code`\n\nLike --dry-run but exits with code 1 if there are tools to uninstall\n\nThis is useful for scripts to check if tools need to be uninstalled.\n\nExamples:\n\n```\n# will uninstall specific version\n$ mise uninstall node@18.0.0\n\n# will uninstall the current node version (if only one version is installed)\n$ mise uninstall node\n\n# will uninstall all installed versions of node\n$ mise uninstall --all node@18.0.0 # will uninstall all node versions\n```\n"
  },
  {
    "path": "docs/cli/unset.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise unset`\n\n- **Usage**: `mise unset [-f --file <FILE>] [-g --global] [ENV_KEY]…`\n- **Source code**: [`src/cli/unset.rs`](https://github.com/jdx/mise/blob/main/src/cli/unset.rs)\n\nRemove environment variable(s) from the config file.\n\nBy default, this command modifies `mise.toml` in the current directory.\n\n## Arguments\n\n### `[ENV_KEY]…`\n\nEnvironment variable(s) to remove\ne.g.: NODE_ENV\n\n## Flags\n\n### `-f --file <FILE>`\n\nSpecify a file to use instead of `mise.toml`\n\n### `-g --global`\n\nUse the global config file\n\nExamples:\n\n```\n# Remove NODE_ENV from the current directory's config\n$ mise unset NODE_ENV\n\n# Remove NODE_ENV from the global config\n$ mise unset NODE_ENV -g\n```\n"
  },
  {
    "path": "docs/cli/unuse.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise unuse`\n\n- **Usage**: `mise unuse [FLAGS] <INSTALLED_TOOL@VERSION>…`\n- **Aliases**: `rm`, `remove`\n- **Source code**: [`src/cli/unuse.rs`](https://github.com/jdx/mise/blob/main/src/cli/unuse.rs)\n\nRemoves installed tool versions from mise.toml\n\nBy default, this will use the `mise.toml` file that has the tool defined.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee <https://mise.jdx.dev/configuration.html#target-file-for-write-operations>\n\nIn the following order:\n- If `--global` is set, it will use the global config file.\n- If `--path` is set, it will use the config file at the given path.\n- If `--env` is set, it will use `mise.<env>.toml`.\n- If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n- If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n- Otherwise just \"mise.toml\" or global config if cwd is home directory.\n\nWill also prune the installed version if no other configurations are using it.\n\n## Arguments\n\n### `<INSTALLED_TOOL@VERSION>…`\n\nTool(s) to remove\n\n## Flags\n\n### `-e --env <ENV>`\n\nCreate/modify an environment-specific config file like .mise.&lt;env>.toml\n\n### `-g --global`\n\nUse the global config file (`~/.config/mise/config.toml`) instead of the local one\n\n### `-p --path <PATH>`\n\nSpecify a path to a config file or directory\n\nIf a directory is specified, it will look for a config file in that directory following the rules above.\n\n### `--no-prune`\n\nDo not also prune the installed version\n\nExamples:\n\n```\n# will uninstall specific version\n$ mise unuse node@18.0.0\n\n# will uninstall specific version from global config\n$ mise unuse -g node@18.0.0\n\n# will uninstall specific version from .mise.local.toml\n$ mise unuse --env local node@20\n\n# will uninstall specific version from .mise.staging.toml\n$ mise unuse --env staging node@20\n```\n"
  },
  {
    "path": "docs/cli/upgrade.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise upgrade`\n\n- **Usage**: `mise upgrade [FLAGS] [INSTALLED_TOOL@VERSION]…`\n- **Aliases**: `up`\n- **Source code**: [`src/cli/upgrade.rs`](https://github.com/jdx/mise/blob/main/src/cli/upgrade.rs)\n\nUpgrades outdated tools\n\nBy default, this keeps the range specified in mise.toml. So if you have node@20 set, it will\nupgrade to the latest 20.x.x version available. See the `--bump` flag to use the latest version\nand bump the version in mise.toml.\n\nThis will update mise.lock if it is enabled, see <https://mise.jdx.dev/configuration/settings.html#lockfile>\n\n## Arguments\n\n### `[INSTALLED_TOOL@VERSION]…`\n\nTool(s) to upgrade\ne.g.: node@20 python@3.10\nIf not specified, all current tools will be upgraded\n\n## Flags\n\n### `-i --interactive`\n\nDisplay multiselect menu to choose which tools to upgrade\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `-l --bump`\n\nUpgrades to the latest version available, bumping the version in mise.toml\n\nFor example, if you have `node = \"20.0.0\"` in your mise.toml but 22.1.0 is the latest available,\nthis will install 22.1.0 and set `node = \"22.1.0\"` in your config.\n\nIt keeps the same precision as what was there before, so if you instead had `node = \"20\"`, it\nwould change your config to `node = \"22\"`.\n\n### `-n --dry-run`\n\nJust print what would be done, don't actually do it\n\n### `-x --exclude… <INSTALLED_TOOL>`\n\nTool(s) to exclude from upgrading\ne.g.: go python\n\n### `--before <BEFORE>`\n\nOnly upgrade to versions released before this date\n\nSupports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\nThis can be useful for reproducibility or security purposes.\n\nThis only affects fuzzy version matches like \"20\" or \"latest\".\nExplicitly pinned versions like \"22.5.0\" are not filtered.\n\n### `--dry-run-code`\n\nLike --dry-run but exits with code 1 if there are outdated tools\n\nThis is useful for scripts to check if tools need to be upgraded.\n\n### `--local`\n\nOnly upgrade tools defined in local config files\n\nThis will only upgrade tools that are defined in project-local mise.toml and\nwill skip tools defined in the global config (~/.config/mise/config.toml).\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\n\nExamples:\n\n```\n# Upgrades node to the latest version matching the range in mise.toml\n$ mise upgrade node\n\n# Upgrades node to the latest version and bumps the version in mise.toml\n$ mise upgrade node --bump\n\n# Upgrades all tools to the latest versions\n$ mise upgrade\n\n# Upgrades all tools to the latest versions and bumps the version in mise.toml\n$ mise upgrade --bump\n\n# Just print what would be done, don't actually do it\n$ mise upgrade --dry-run\n\n# Upgrades node and python to the latest versions\n$ mise upgrade node python\n\n# Upgrade all tools except go\n$ mise upgrade --exclude go\n\n# Show a multiselect menu to choose which tools to upgrade\n$ mise upgrade --interactive\n\n# Only upgrade tools defined in local mise.toml, not global ones\n$ mise upgrade --local\n```\n"
  },
  {
    "path": "docs/cli/use.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise use`\n\n- **Usage**: `mise use [FLAGS] [TOOL@VERSION]…`\n- **Aliases**: `u`\n- **Source code**: [`src/cli/use.rs`](https://github.com/jdx/mise/blob/main/src/cli/use.rs)\n\nInstalls a tool and adds the version to mise.toml.\n\nThis will install the tool version if it is not already installed.\nBy default, this will use a `mise.toml` file in the current directory.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee <https://mise.jdx.dev/configuration.html#target-file-for-write-operations>\n\nIn the following order:\n- If `--global` is set, it will use the global config file.\n- If `--path` is set, it will use the config file at the given path.\n- If `--env` is set, it will use `mise.<env>.toml`.\n- If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n- If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n- Otherwise just \"mise.toml\" or global config if cwd is home directory.\n\nUse the `--global` flag to use the global config file instead.\n\n## Arguments\n\n### `[TOOL@VERSION]…`\n\nTool(s) to add to config file\n\ne.g.: node@20, cargo:ripgrep@latest npm:prettier@3\nIf no version is specified, it will default to @latest\n\nTool options can be set with this syntax:\n\n```\nmise use ubi:BurntSushi/ripgrep[exe=rg]\n```\n\n## Flags\n\n### `-e --env <ENV>`\n\nCreate/modify an environment-specific config file like .mise.&lt;env>.toml\n\n### `-f --force`\n\nForce reinstall even if already installed\n\n### `-g --global`\n\nUse the global config file (`~/.config/mise/config.toml`) instead of the local one\n\n### `-j --jobs <JOBS>`\n\nNumber of jobs to run in parallel\n[default: 4]\n\n### `-n --dry-run`\n\nPerform a dry run, showing what would be installed and modified without making changes\n\n### `-p --path <PATH>`\n\nSpecify a path to a config file or directory\n\nIf a directory is specified, it will look for a config file in that directory following the rules above.\n\n### `--before <BEFORE>`\n\nOnly install versions released before this date\n\nSupports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\n\n### `--dry-run-code`\n\nLike --dry-run but exits with code 1 if there are changes to make\n\nThis is useful for scripts to check if tools need to be added or removed.\n\n### `--fuzzy`\n\nSave fuzzy version to config file\n\ne.g.: `mise use --fuzzy node@20` will save 20 as the version\nthis is the default behavior unless `MISE_PIN=1`\n\n### `--pin`\n\nSave exact version to config file\ne.g.: `mise use --pin node@20` will save 20.0.0 as the version\nSet `MISE_PIN=1` to make this the default behavior\n\nConsider using mise.lock as a better alternative to pinning in mise.toml:\n<https://mise.jdx.dev/configuration/settings.html#lockfile>\n\n### `--raw`\n\nDirectly pipe stdin/stdout/stderr from plugin to user Sets `--jobs=1`\n\n### `--remove… <PLUGIN>`\n\nRemove the plugin(s) from config file\n\nExamples:\n```\n\n# run with no arguments to use the interactive selector\n$ mise use\n\n# set the current version of node to 20.x in mise.toml of current directory\n# will write the fuzzy version (e.g.: 20)\n$ mise use node@20\n\n# set the current version of node to 20.x in ~/.config/mise/config.toml\n# will write the precise version (e.g.: 20.0.0)\n$ mise use -g --pin node@20\n\n# sets .mise.local.toml (which is intended not to be committed to a project)\n$ mise use --env local node@20\n\n# sets .mise.staging.toml (which is used if MISE_ENV=staging)\n$ mise use --env staging node@20\n```\n"
  },
  {
    "path": "docs/cli/version.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise version`\n\n- **Usage**: `mise version [-J --json]`\n- **Aliases**: `v`\n- **Source code**: [`src/cli/version.rs`](https://github.com/jdx/mise/blob/main/src/cli/version.rs)\n\nDisplay the version of mise\n\nDisplays the version, os, architecture, and the date of the build.\n\nIf the version is out of date, it will display a warning.\n\n## Flags\n\n### `-J --json`\n\nPrint the version information in JSON format\n\nExamples:\n\n```\nmise version\nmise --version\nmise -v\nmise -V\n```\n"
  },
  {
    "path": "docs/cli/watch.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise watch`\n\n- **Usage**: `mise watch [FLAGS] [TASK] [ARGS]…`\n- **Aliases**: `w`\n- **Source code**: [`src/cli/watch.rs`](https://github.com/jdx/mise/blob/main/src/cli/watch.rs)\n\nRun task(s) and watch for changes to rerun it\n\nThis command uses the `watchexec` tool to watch for changes to files and rerun the specified task(s).\nIt must be installed for this command to work, but you can install it with `mise use -g watchexec@latest`.\n\nFor more advanced process management (daemon management, auto-restart, readiness checks,\ncron scheduling), see mise's sister project: https://pitchfork.jdx.dev\n\n## Arguments\n\n### `[TASK]`\n\nTasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: `mise run task1 arg1 arg2 ::: task2 arg1 arg2`\n\n### `[ARGS]…`\n\nTask and arguments to run\n\n## Flags\n\n### `--skip-deps`\n\nRun only the specified tasks skipping all dependencies\n\n### `-w --watch… <PATH>`\n\nWatch a specific file or directory\n\nBy default, Watchexec watches the current directory.\n\nWhen watching a single file, it's often better to watch the containing directory instead, and filter on the filename. Some editors may replace the file with a new one when saving, and some platforms may not detect that or further changes.\n\nUpon starting, Watchexec resolves a \"project origin\" from the watched paths. See the help for '--project-origin' for more information.\n\nThis option can be specified multiple times to watch multiple files or directories.\n\nThe special value '/dev/null', provided as the only path watched, will cause Watchexec to not watch any paths. Other event sources (like signals or key events) may still be used.\n\n### `-W --watch-non-recursive… <PATH>`\n\nWatch a specific directory, non-recursively\n\nUnlike '-w', folders watched with this option are not recursed into.\n\nThis option can be specified multiple times to watch multiple directories non-recursively.\n\n### `-F --watch-file <PATH>`\n\nWatch files and directories from a file\n\nEach line in the file will be interpreted as if given to '-w'.\n\nFor more complex uses (like watching non-recursively), use the argfile capability: build a file containing command-line options and pass it to watchexec with `@path/to/argfile`.\n\nThe special value '-' will read from STDIN; this in incompatible with '--stdin-quit'.\n\n### `-c --clear <MODE>`\n\nClear screen before running command\n\nIf this doesn't completely clear the screen, try '--clear=reset'.\n\n**Choices:**\n\n- `clear`\n- `reset`\n\n### `-o --on-busy-update <MODE>`\n\nWhat to do when receiving events while the command is running\n\nDefault is to 'do-nothing', which ignores events while the command is running, so that changes that occur due to the command are ignored, like compilation outputs. You can also use 'queue' which will run the command once again when the current run has finished if any events occur while it's running, or 'restart', which terminates the running command and starts a new one. Finally, there's 'signal', which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.\n\nThe signal can be specified with the '--signal' option.\n\n**Choices:**\n\n- `queue`\n- `do-nothing`\n- `restart`\n- `signal`\n\n**Default:** `do-nothing`\n\n### `-r --restart`\n\nRestart the process if it's still running\n\nThis is a shorthand for '--on-busy-update=restart'.\n\n### `-s --signal <SIGNAL>`\n\nSend a signal to the process when it's still running\n\nSpecify a signal to send to the process when it's still running. This implies '--on-busy-update=signal'; otherwise the signal used when that mode is 'restart' is controlled by '--stop-signal'.\n\nSee the long documentation for '--stop-signal' for syntax.\n\nSignals are not supported on Windows at the moment, and will always be overridden to 'kill'. See '--stop-signal' for more on Windows \"signals\".\n\n### `--stop-signal <SIGNAL>`\n\nSignal to send to stop the command\n\nThis is used by 'restart' and 'signal' modes of '--on-busy-update' (unless '--signal' is provided). The restart behaviour is to send the signal, wait for the command to exit, and if it hasn't exited after some time (see '--timeout-stop'), forcefully terminate it.\n\nThe default on unix is \"SIGTERM\".\n\nInput is parsed as a full signal name (like \"SIGTERM\"), a short signal name (like \"TERM\"), or a signal number (like \"15\"). All input is case-insensitive.\n\nOn Windows this option is technically supported but only supports the \"KILL\" event, as Watchexec cannot yet deliver other events. Windows doesn't have signals as such; instead it has termination (here called \"KILL\" or \"STOP\") and \"CTRL+C\", \"CTRL+BREAK\", and \"CTRL+CLOSE\" events. For portability the unix signals \"SIGKILL\", \"SIGINT\", \"SIGTERM\", and \"SIGHUP\" are respectively mapped to these.\n\n### `--stop-timeout <TIMEOUT>`\n\nTime to wait for the command to exit gracefully\n\nThis is used by the 'restart' mode of '--on-busy-update'. After the graceful stop signal is sent, Watchexec will wait for the command to exit. If it hasn't exited after this time, it is forcefully terminated.\n\nTakes a unit-less value in seconds, or a time span value such as \"5min 20s\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n\nThe default is 10 seconds. Set to 0 to immediately force-kill the command.\n\nThis has no practical effect on Windows as the command is always forcefully terminated; see '--stop-signal' for why.\n\n**Default:** `10s`\n\n### `--map-signal… <SIGNAL:SIGNAL>`\n\nTranslate signals from the OS to signals to send to the command\n\nTakes a pair of signal names, separated by a colon, such as \"TERM:INT\" to map SIGTERM to SIGINT. The first signal is the one received by watchexec, and the second is the one sent to the command. The second can be omitted to discard the first signal, such as \"TERM:\" to not do anything on SIGTERM.\n\nIf SIGINT or SIGTERM are mapped, then they no longer quit Watchexec. Besides making it hard to quit Watchexec itself, this is useful to send pass a Ctrl-C to the command without also terminating Watchexec and the underlying program with it, e.g. with \"INT:INT\".\n\nThis option can be specified multiple times to map multiple signals.\n\nSignal syntax is case-insensitive for short names (like \"TERM\", \"USR2\") and long names (like \"SIGKILL\", \"SIGHUP\"). Signal numbers are also supported (like \"15\", \"31\"). On Windows, the forms \"STOP\", \"CTRL+C\", and \"CTRL+BREAK\" are also supported to receive, but Watchexec cannot yet deliver other \"signals\" than a STOP.\n\n### `-d --debounce <TIMEOUT>`\n\nTime to wait for new events before taking action\n\nWhen an event is received, Watchexec will wait for up to this amount of time before handling it (such as running the command). This is essential as what you might perceive as a single change may actually emit many events, and without this behaviour, Watchexec would run much too often. Additionally, it's not infrequent that file writes are not atomic, and each write may emit an event, so this is a good way to avoid running a command while a file is partially written.\n\nAn alternative use is to set a high value (like \"30min\" or longer), to save power or bandwidth on intensive tasks, like an ad-hoc backup script. In those use cases, note that every accumulated event will build up in memory.\n\nTakes a unit-less value in milliseconds, or a time span value such as \"5sec 20ms\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n\nThe default is 50 milliseconds. Setting to 0 is highly discouraged.\n\n**Default:** `50ms`\n\n### `--stdin-quit`\n\nExit when stdin closes\n\nThis watches the stdin file descriptor for EOF, and exits Watchexec gracefully when it is closed. This is used by some process managers to avoid leaving zombie processes around.\n\n### `--no-vcs-ignore`\n\nDon't load gitignores\n\nAmong other VCS exclude files, like for Mercurial, Subversion, Bazaar, DARCS, Fossil. Note that Watchexec will detect which of these is in use, if any, and only load the relevant files. Both global (like '~/.gitignore') and local (like '.gitignore') files are considered.\n\nThis option is useful if you want to watch files that are ignored by Git.\n\n### `--no-project-ignore`\n\nDon't load project-local ignores\n\nThis disables loading of project-local ignore files, like '.gitignore' or '.ignore' in the\nwatched project. This is contrasted with '--no-vcs-ignore', which disables loading of Git\nand other VCS ignore files, and with '--no-global-ignore', which disables loading of global\nor user ignore files, like '~/.gitignore' or '~/.config/watchexec/ignore'.\n\nSupported project ignore files:\n\n  - Git: .gitignore at project root and child directories, .git/info/exclude, and the file pointed to by `core.excludesFile` in .git/config.\n  - Mercurial: .hgignore at project root and child directories.\n  - Bazaar: .bzrignore at project root.\n  - Darcs: _darcs/prefs/boring\n  - Fossil: .fossil-settings/ignore-glob\n  - Ripgrep/Watchexec/generic: .ignore at project root and child directories.\n\nVCS ignore files (Git, Mercurial, Bazaar, Darcs, Fossil) are only used if the corresponding\nVCS is discovered to be in use for the project/origin. For example, a .bzrignore in a Git\nrepository will be discarded.\n\n### `--no-global-ignore`\n\nDon't load global ignores\n\nThis disables loading of global or user ignore files, like '~/.gitignore',\n'~/.config/watchexec/ignore', or '%APPDATA%\\Bazzar\\2.0\\ignore'. Contrast with\n'--no-vcs-ignore' and '--no-project-ignore'.\n\nSupported global ignore files\n\n  - Git (if core.excludesFile is set): the file at that path\n  - Git (otherwise): the first found of $XDG_CONFIG_HOME/git/ignore, %APPDATA%/.gitignore, %USERPROFILE%/.gitignore, $HOME/.config/git/ignore, $HOME/.gitignore.\n  - Bazaar: the first found of %APPDATA%/Bazzar/2.0/ignore, $HOME/.bazaar/ignore.\n  - Watchexec: the first found of $XDG_CONFIG_HOME/watchexec/ignore, %APPDATA%/watchexec/ignore, %USERPROFILE%/.watchexec/ignore, $HOME/.watchexec/ignore.\n\nLike for project files, Git and Bazaar global files will only be used for the corresponding\nVCS as used in the project.\n\n### `--no-default-ignore`\n\nDon't use internal default ignores\n\nWatchexec has a set of default ignore patterns, such as editor swap files, `*.pyc`, `*.pyo`, `.DS_Store`, `.bzr`, `_darcs`, `.fossil-settings`, `.git`, `.hg`, `.pijul`, `.svn`, and Watchexec log files.\n\n### `--no-discover-ignore`\n\nDon't discover ignore files at all\n\nThis is a shorthand for '--no-global-ignore', '--no-vcs-ignore', '--no-project-ignore', but even more efficient as it will skip all the ignore discovery mechanisms from the get go.\n\nNote that default ignores are still loaded, see '--no-default-ignore'.\n\n### `--ignore-nothing`\n\nDon't ignore anything at all\n\nThis is a shorthand for '--no-discover-ignore', '--no-default-ignore'.\n\nNote that ignores explicitly loaded via other command line options, such as '--ignore' or '--ignore-file', will still be used.\n\n### `-p --postpone`\n\nWait until first change before running command\n\nBy default, Watchexec will run the command once immediately. With this option, it will instead wait until an event is detected before running the command as normal.\n\n### `--delay-run <DURATION>`\n\nSleep before running the command\n\nThis option will cause Watchexec to sleep for the specified amount of time before running the command, after an event is detected. This is like using \"sleep 5 && command\" in a shell, but portable and slightly more efficient.\n\nTakes a unit-less value in seconds, or a time span value such as \"2min 5s\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n\n### `--poll <INTERVAL>`\n\nPoll for filesystem changes\n\nBy default, and where available, Watchexec uses the operating system's native file system watching capabilities. This option disables that and instead uses a polling mechanism, which is less efficient but can work around issues with some file systems (like network shares) or edge cases.\n\nOptionally takes a unit-less value in milliseconds, or a time span value such as \"2s 500ms\", to use as the polling interval. If not specified, the default is 30 seconds. Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n\nAliased as '--force-poll'.\n\n### `--shell <SHELL>`\n\nUse a different shell\n\nBy default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix-likes, and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec detects is the running shell.\n\nWith this option, you can override that and use a different shell, for example one with more features or one which has your custom aliases and functions.\n\nIf the value has spaces, it is parsed as a command line, and the first word used as the shell program, with the rest as arguments to the shell.\n\nThe command is run with the '-c' flag (except for 'cmd' on Windows, where it's '/C').\n\nThe special value 'none' can be used to disable shell use entirely. In that case, the command provided to Watchexec will be parsed, with the first word being the executable and the rest being the arguments, and executed directly. Note that this parsing is rudimentary, and may not work as expected in all cases.\n\nUsing 'none' is a little more efficient and can enable a stricter interpretation of the input, but it also means that you can't use shell features like globbing, redirection, control flow, logic, or pipes.\n\nExamples:\n\nUse without shell:\n\n$ watchexec -n -- zsh -x -o shwordsplit scr\n\nUse with powershell core:\n\n$ watchexec --shell=pwsh -- Test-Connection localhost\n\nUse with CMD.exe:\n\n$ watchexec --shell=cmd -- dir\n\nUse with a different unix shell:\n\n$ watchexec --shell=bash -- 'echo $BASH_VERSION'\n\nUse with a unix shell and options:\n\n$ watchexec --shell='zsh -x -o shwordsplit' -- scr\n\n### `-n`\n\nShorthand for '--shell=none'\n\n### `--emit-events-to <MODE>`\n\nConfigure event emission\n\nWatchexec can emit event information when running a command, which can be used by the child\nprocess to target specific changed files.\n\nOne thing to take care with is assuming inherent behaviour where there is only chance.\nNotably, it could appear as if the `RENAMED` variable contains both the original and the new\npath being renamed. In previous versions, it would even appear on some platforms as if the\noriginal always came before the new. However, none of this was true. It's impossible to\nreliably and portably know which changed path is the old or new, \"half\" renames may appear\n(only the original, only the new), \"unknown\" renames may appear (change was a rename, but\nwhether it was the old or new isn't known), rename events might split across two debouncing\nboundaries, and so on.\n\nThis option controls where that information is emitted. It defaults to 'none', which doesn't\nemit event information at all. The other options are 'environment' (deprecated), 'stdio',\n'file', 'json-stdio', and 'json-file'.\n\nThe 'stdio' and 'file' modes are text-based: 'stdio' writes absolute paths to the stdin of\nthe command, one per line, each prefixed with `create:`, `remove:`, `rename:`, `modify:`,\nor `other:`, then closes the handle; 'file' writes the same thing to a temporary file, and\nits path is given with the $WATCHEXEC_EVENTS_FILE environment variable.\n\nThere are also two JSON modes, which are based on JSON objects and can represent the full\nset of events Watchexec handles. Here's an example of a folder being created on Linux:\n\n```json\n  {\n```\n\"tags\": [\n  {\n    \"kind\": \"path\",\n    \"absolute\": \"/home/user/your/new-folder\",\n    \"filetype\": \"dir\"\n  },\n  {\n    \"kind\": \"fs\",\n    \"simple\": \"create\",\n    \"full\": \"Create(Folder)\"\n  },\n  {\n    \"kind\": \"source\",\n    \"source\": \"filesystem\",\n  }\n],\n\"metadata\": {\n  \"notify-backend\": \"inotify\"\n}\n```\n  }\n```\n\nThe fields are as follows:\n\n  - `tags`, structured event data.\n  - `tags[].kind`, which can be:\n```\n* 'path', along with:\n  + `absolute`, an absolute path.\n  + `filetype`, a file type if known ('dir', 'file', 'symlink', 'other').\n* 'fs':\n  + `simple`, the \"simple\" event type ('access', 'create', 'modify', 'remove', or 'other').\n  + `full`, the \"full\" event type, which is too complex to fully describe here, but looks like 'General(Precise(Specific))'.\n* 'source', along with:\n  + `source`, the source of the event ('filesystem', 'keyboard', 'mouse', 'os', 'time', 'internal').\n* 'keyboard', along with:\n  + `keycode`. Currently only the value 'eof' is supported.\n* 'process', for events caused by processes:\n  + `pid`, the process ID.\n* 'signal', for signals sent to Watchexec:\n  + `signal`, the normalised signal name ('hangup', 'interrupt', 'quit', 'terminate', 'user1', 'user2').\n* 'completion', for when a command ends:\n  + `disposition`, the exit disposition ('success', 'error', 'signal', 'stop', 'exception', 'continued').\n  + `code`, the exit, signal, stop, or exception code.\n```\n  - `metadata`, additional information about the event.\n\nThe 'json-stdio' mode will emit JSON events to the standard input of the command, one per\nline, then close stdin. The 'json-file' mode will create a temporary file, write the\nevents to it, and provide the path to the file with the $WATCHEXEC_EVENTS_FILE\nenvironment variable.\n\nFinally, the 'environment' mode was the default until 2.0. It sets environment variables\nwith the paths of the affected files, for filesystem events:\n\n$WATCHEXEC_COMMON_PATH is set to the longest common path of all of the below variables,\nand so should be prepended to each path to obtain the full/real path. Then:\n\n  - $WATCHEXEC_CREATED_PATH is set when files/folders were created\n  - $WATCHEXEC_REMOVED_PATH is set when files/folders were removed\n  - $WATCHEXEC_RENAMED_PATH is set when files/folders were renamed\n  - $WATCHEXEC_WRITTEN_PATH is set when files/folders were modified\n  - $WATCHEXEC_META_CHANGED_PATH is set when files/folders' metadata were modified\n  - $WATCHEXEC_OTHERWISE_CHANGED_PATH is set for every other kind of pathed event\n\nMultiple paths are separated by the system path separator, ';' on Windows and ':' on unix.\nWithin each variable, paths are deduplicated and sorted in binary order (i.e. neither\nUnicode nor locale aware).\n\nThis is the legacy mode, is deprecated, and will be removed in the future. The environment\nis a very restricted space, while also limited in what it can usefully represent. Large\nnumbers of files will either cause the environment to be truncated, or may error or crash\nthe process entirely. The $WATCHEXEC_COMMON_PATH is also unintuitive, as demonstrated by the\nmultiple confused queries that have landed in my inbox over the years.\n\n**Choices:**\n\n- `environment`\n- `stdio`\n- `file`\n- `json-stdio`\n- `json-file`\n- `none`\n\n**Default:** `none`\n\n### `--only-emit-events`\n\nOnly emit events to stdout, run no commands.\n\nThis is a convenience option for using Watchexec as a file watcher, without running any commands. It is almost equivalent to using `cat` as the command, except that it will not spawn a new process for each event.\n\nThis option requires `--emit-events-to` to be set, and restricts the available modes to `stdio` and `json-stdio`, modifying their behaviour to write to stdout instead of the stdin of the command.\n\n### `-E --env… <KEY=VALUE>`\n\nAdd env vars to the command\n\nThis is a convenience option for setting environment variables for the command, without setting them for the Watchexec process itself.\n\nUse key=value syntax. Multiple variables can be set by repeating the option.\n\n### `--wrap-process <MODE>`\n\nConfigure how the process is wrapped\n\nBy default, Watchexec will run the command in a process group in Unix, and in a Job Object in Windows.\n\nSome Unix programs prefer running in a session, while others do not work in a process group.\n\nUse 'group' to use a process group, 'session' to use a process session, and 'none' to run the command directly. On Windows, either of 'group' or 'session' will use a Job Object.\n\n**Choices:**\n\n- `group`\n- `session`\n- `none`\n\n**Default:** `group`\n\n### `-N --notify`\n\nAlert when commands start and end\n\nWith this, Watchexec will emit a desktop notification when a command starts and ends, on supported platforms. On unsupported platforms, it may silently do nothing, or log a warning.\n\n### `--color <MODE>`\n\nWhen to use terminal colours\n\nSetting the environment variable `NO_COLOR` to any value is equivalent to `--color=never`.\n\n**Choices:**\n\n- `auto`\n- `always`\n- `never`\n\n**Default:** `auto`\n\n### `--timings`\n\nPrint how long the command took to run\n\nThis may not be exactly accurate, as it includes some overhead from Watchexec itself. Use the `time` utility, high-precision timers, or benchmarking tools for more accurate results.\n\n### `-q --quiet`\n\nDon't print starting and stopping messages\n\nBy default Watchexec will print a message when the command starts and stops. This option disables this behaviour, so only the command's output, warnings, and errors will be printed.\n\n### `--bell`\n\nRing the terminal bell on command completion\n\n### `--project-origin <DIRECTORY>`\n\nSet the project origin\n\nWatchexec will attempt to discover the project's \"origin\" (or \"root\") by searching for a variety of markers, like files or directory patterns. It does its best but sometimes gets it it wrong, and you can override that with this option.\n\nThe project origin is used to determine the path of certain ignore files, which VCS is being used, the meaning of a leading '/' in filtering patterns, and maybe more in the future.\n\nWhen set, Watchexec will also not bother searching, which can be significantly faster.\n\n### `--workdir <DIRECTORY>`\n\nSet the working directory\n\nBy default, the working directory of the command is the working directory of Watchexec. You can change that with this option. Note that paths may be less intuitive to use with this.\n\n### `-e --exts… <EXTENSIONS>`\n\nFilename extensions to filter to\n\nThis is a quick filter to only emit events for files with the given extensions. Extensions can be given with or without the leading dot (e.g. 'js' or '.js'). Multiple extensions can be given by repeating the option or by separating them with commas.\n\n### `-f --filter… <PATTERN>`\n\nFilename patterns to filter to\n\nProvide a glob-like filter pattern, and only events for files matching the pattern will be emitted. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\n\n### `--filter-file… <PATH>`\n\nFiles to load filters from\n\nProvide a path to a file containing filters, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '--filter' option.\n\nThis can also be used via the $WATCHEXEC_FILTER_FILES environment variable.\n\n### `-J --filter-prog… <EXPRESSION>`\n\n[experimental] Filter programs.\n\n/!\\ This option is EXPERIMENTAL and may change and/or vanish without notice.\n\nProvide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in '--emit-events-to' and must return a boolean. Invalid programs will make watchexec fail to start; use '-v' to see program runtime errors.\n\nIn addition to the jaq stdlib, watchexec adds some custom filter definitions:\n\n- 'path | file_meta' returns file metadata or null if the file does not exist.\n\n- 'path | file_size' returns the size of the file at path, or null if it does not exist.\n\n- 'path | file_read(bytes)' returns a string with the first n bytes of the file at path. If the file is smaller than n bytes, the whole file is returned. There is no filter to read the whole file at once to encourage limiting the amount of data read and processed.\n\n- 'string | hash', and 'path | file_hash' return the hash of the string or file at path. No guarantee is made about the algorithm used: treat it as an opaque value.\n\n- 'any | kv_store(key)', 'kv_fetch(key)', and 'kv_clear' provide a simple key-value store. Data is kept in memory only, there is no persistence. Consistency is not guaranteed.\n\n- 'any | printout', 'any | printerr', and 'any | log(level)' will print or log any given value to stdout, stderr, or the log (levels = error, warn, info, debug, trace), and pass the value through (so '[1] | log(\"debug\") | .[]' will produce a '1' and log '[1]').\n\nAll filtering done with such programs, and especially those using kv or filesystem access, is much slower than the other filtering methods. If filtering is too slow, events will back up and stall watchexec. Take care when designing your filters.\n\nIf the argument to this option starts with an '@', the rest of the argument is taken to be the path to a file containing a jaq program.\n\nJaq programs are run in order, after all other filters, and short-circuit: if a filter (jaq or not) rejects an event, execution stops there, and no other filters are run. Additionally, they stop after outputting the first value, so you'll want to use 'any' or 'all' when iterating, otherwise only the first item will be processed, which can be quite confusing!\n\nFind user-contributed programs or submit your own useful ones at &lt;https://github.com/watchexec/watchexec/discussions/592>.\n\n## Examples:\n\nRegexp ignore filter on paths:\n\n'all(.tags[] | select(.kind == \"path\"); .absolute | test(\"[.]test[.]js$\")) | not'\n\nPass any event that creates a file:\n\n'any(.tags[] | select(.kind == \"fs\"); .simple == \"create\")'\n\nPass events that touch executable files:\n\n'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | metadata | .executable)'\n\nIgnore files that start with shebangs:\n\n'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | read(2) == \"#!\") | not'\n\n### `-i --ignore… <PATTERN>`\n\nFilename patterns to filter out\n\nProvide a glob-like filter pattern, and events for files matching the pattern will be excluded. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\n\n### `--ignore-file… <PATH>`\n\nFiles to load ignores from\n\nProvide a path to a file containing ignores, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '--ignore' option.\n\nThis can also be used via the $WATCHEXEC_IGNORE_FILES environment variable.\n\n### `--fs-events… <EVENTS>`\n\nFilesystem events to filter to\n\nThis is a quick filter to only emit events for the given types of filesystem changes. Choose from 'access', 'create', 'remove', 'rename', 'modify', 'metadata'. Multiple types can be given by repeating the option or by separating them with commas. By default, this is all types except for 'access'.\n\nThis may apply filtering at the kernel level when possible, which can be more efficient, but may be more confusing when reading the logs.\n\n**Choices:**\n\n- `access`\n- `create`\n- `remove`\n- `rename`\n- `modify`\n- `metadata`\n\n**Default:** `create,remove,rename,modify,metadata`\n\n### `--no-meta`\n\nDon't emit fs events for metadata changes\n\nThis is a shorthand for '--fs-events create,remove,rename,modify'. Using it alongside the '--fs-events' option is non-sensical and not allowed.\n\n### `--print-events`\n\nPrint events that trigger actions\n\nThis prints the events that triggered the action when handling it (after debouncing), in a human readable form. This is useful for debugging filters.\n\nUse '-vvv' instead when you need more diagnostic information.\n\n### `--manual`\n\nShow the manual page\n\nThis shows the manual page for Watchexec, if the output is a terminal and the 'man' program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).\n\nExamples:\n\n```\n$ mise watch build\nRuns the \"build\" tasks. Will re-run the tasks when any of its sources change.\nUses \"sources\" from the tasks definition to determine which files to watch.\n\n$ mise watch build --glob src/**/*.rs\nRuns the \"build\" tasks but specify the files to watch with a glob pattern.\nThis overrides the \"sources\" from the tasks definition.\n\n$ mise watch build --clear\nExtra arguments are passed to watchexec. See `watchexec --help` for details.\n\n$ mise watch serve --watch src --exts rs --restart\nStarts an api server, watching for changes to \"*.rs\" files in \"./src\" and kills/restarts the server when they change.\n```\n"
  },
  {
    "path": "docs/cli/where.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise where`\n\n- **Usage**: `mise where <TOOL@VERSION>`\n- **Source code**: [`src/cli/where.rs`](https://github.com/jdx/mise/blob/main/src/cli/where.rs)\n\nDisplay the installation path for a tool\n\nThe tool must be installed for this to work.\n\n## Arguments\n\n### `<TOOL@VERSION>`\n\nTool(s) to look up\ne.g.: ruby@3\nif \"@&lt;PREFIX>\" is specified, it will show the latest installed version\nthat matches the prefix\notherwise, it will show the current, active installed version\n\nExamples:\n\n```\n# Show the latest installed version of node\n# If it is is not installed, errors\n$ mise where node@20\n/home/jdx/.local/share/mise/installs/node/20.0.0\n\n# Show the current, active install directory of node\n# Errors if node is not referenced in any .tool-version file\n$ mise where node\n/home/jdx/.local/share/mise/installs/node/20.0.0\n```\n"
  },
  {
    "path": "docs/cli/which.md",
    "content": "<!-- @generated by usage-cli from usage spec -->\n# `mise which`\n\n- **Usage**: `mise which [FLAGS] [BIN_NAME]`\n- **Source code**: [`src/cli/which.rs`](https://github.com/jdx/mise/blob/main/src/cli/which.rs)\n\nShows the path that a tool's bin points to.\n\nUse this to figure out what version of a tool is currently active.\n\n## Arguments\n\n### `[BIN_NAME]`\n\nThe bin to look up\n\n## Flags\n\n### `-t --tool <TOOL@VERSION>`\n\nUse a specific tool@version\ne.g.: `mise which npm --tool=node@20`\n\n### `--plugin`\n\nShow the plugin name instead of the path\n\n### `--version`\n\nShow the version instead of the path\n\nExamples:\n\n```\n$ mise which node\n/home/username/.local/share/mise/installs/node/20.0.0/bin/node\n\n$ mise which node --plugin\nnode\n\n$ mise which node --version\n20.0.0\n```\n"
  },
  {
    "path": "docs/components/registry.vue",
    "content": "<template>\n  <input\n    class=\"filter\"\n    type=\"text\"\n    placeholder=\"Filter by Short or Full\"\n    v-model=\"filter\"\n    autofocus=\"autofocus\"\n  />\n  <table class=\"full-width\">\n    <thead>\n      <tr>\n        <th>Short</th>\n        <th>Full</th>\n        <th>OS</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr v-if=\"filteredData.length === 0\">\n        <td colspan=\"3\" class=\"no-matches\">No matches found</td>\n      </tr>\n      <tr\n        v-else\n        v-for=\"(entry, index) in filteredData\"\n        :key=\"`backend-${index}`\"\n      >\n        <td v-html=\"highlightMatches(entry.short)\"></td>\n        <td>\n          <span v-for=\"(backend, index) in entry.backends\">\n            <a\n              :href=\"`${backend.url}`\"\n              v-html=\"highlightMatches(backend.name)\"\n            ></a>\n            <span v-if=\"index < entry.backends.length - 1\"><br /></span>\n          </span>\n        </td>\n        <td>\n          <span v-for=\"(os, index) in entry.os\"\n            >{{ os }}<span v-if=\"index < entry.os.length - 1\">, </span>\n          </span>\n        </td>\n      </tr>\n    </tbody>\n  </table>\n</template>\n\n<script>\nimport { data } from \"/registry.data.ts\";\n\nexport default {\n  data() {\n    return {\n      filter:\n        new URLSearchParams(globalThis?.location?.search).get(\"filter\") || \"\",\n      data: data,\n    };\n  },\n  computed: {\n    filteredData() {\n      if (this.filter.trim() === \"\") return this.data;\n      return this.data.filter((entry) => {\n        const searchTerm = this.filter.toLowerCase();\n        const short = entry.short.toString().toLowerCase();\n\n        return (\n          short.includes(searchTerm) ||\n          entry.backends.some((b) => b.name.toLowerCase().includes(searchTerm))\n        );\n      });\n    },\n  },\n  watch: {\n    filter(newFilter = \"\") {\n      const url = new URL(window.location);\n      url.hash = \"tools\";\n      if (newFilter.trim() === \"\") {\n        url.searchParams.delete(\"filter\");\n      } else {\n        url.searchParams.set(\"filter\", newFilter);\n      }\n      window.history.pushState({}, \"\", url);\n    },\n  },\n  methods: {\n    highlightMatches(text) {\n      if (this.filter.trim() === \"\") return text;\n      const matchExists = text\n        .toLowerCase()\n        .includes(this.filter.toLowerCase());\n      if (!matchExists) return text;\n\n      const re = new RegExp(this.filter, \"ig\");\n      return text.replace(\n        re,\n        (matchedText) =>\n          `<span style=\"background-color: rgba(173, 216, 230, 0.2)\">${matchedText}</span>`,\n      );\n    },\n  },\n};\n</script>\n\n<style scoped>\n.filter {\n  width: 100%;\n  padding: 10px;\n  margin-bottom: 10px;\n  border-radius: 10px;\n  background: var(--vp-c-bg-soft);\n  font-size: 15px;\n  color: var(--vp-c-text-2);\n}\n\n.full-width {\n  width: 100%;\n  table-layout: fixed;\n  min-height: 500px;\n}\n\n.full-width th:nth-child(1),\n.full-width td:nth-child(1) {\n  min-width: 25%;\n  width: 25%;\n}\n\n.full-width th:nth-child(2),\n.full-width td:nth-child(2) {\n  min-width: 55%;\n  width: 55%;\n}\n\n.full-width th:nth-child(3),\n.full-width td:nth-child(3) {\n  min-width: 20%;\n}\n\n.full-width th,\n.full-width td {\n  word-wrap: break-word; /* Allows text to wrap within cells */\n}\n\n.no-matches {\n  text-align: center;\n  font-style: italic;\n  color: var(--vp-c-text-2);\n}\n</style>\n"
  },
  {
    "path": "docs/components/setting.vue",
    "content": "<script setup>\ndefineProps([\"setting\", \"level\"]);\n</script>\n\n<template>\n  <h2 v-if=\"level === 2\" :id=\"setting.key\">\n    <code>{{ setting.key }}</code\n    ><a :href=\"`#${setting.key}`\" class=\"header-anchor\"></a>\n    <span v-if=\"setting.deprecated\" class=\"VPBadge warning\">deprecated</span>\n  </h2>\n  <h3 v-if=\"level === 3\" :id=\"setting.key\">\n    <code>{{ setting.key }}</code\n    ><a :href=\"`#${setting.key}`\" class=\"header-anchor\"></a>\n    <span v-if=\"setting.deprecated\" class=\"VPBadge warning\">deprecated</span>\n  </h3>\n  <h4 v-if=\"level === 4\" :id=\"setting.key\">\n    <code>{{ setting.key }}</code\n    ><a :href=\"`#${setting.key}`\" class=\"header-anchor\"></a>\n    <span v-if=\"setting.deprecated\" class=\"VPBadge warning\">deprecated</span>\n  </h4>\n\n  <ul>\n    <li>\n      Type: <code>{{ setting.type }}</code>\n      <span v-if=\"setting.optional\">(optional)</span>\n    </li>\n    <li v-if=\"setting.env\">\n      Env: <code>{{ setting.env }}</code>\n      <span v-if=\"setting.parseEnv\">({{ setting.parseEnv }} separated)</span>\n    </li>\n    <li>\n      Default: <code>{{ setting.default }}</code>\n    </li>\n    <li v-if=\"setting.deprecated\">Deprecated: {{ setting.deprecated }}</li>\n    <li v-if=\"setting.enum\">\n      Choices:\n      <ul>\n        <li v-for=\"choice in setting.enum\">\n          <template v-if=\"typeof choice === 'object' && choice !== null && 'value' in choice\">\n            <code>{{ choice.value }}</code><template v-if=\"choice.description\"> – {{ choice.description }}</template>\n          </template>\n          <template v-else>\n            <code>{{ choice }}</code>\n          </template>\n        </li>\n      </ul>\n    </li>\n  </ul>\n\n  <span v-html=\"setting.docs\"></span>\n</template>\n"
  },
  {
    "path": "docs/components/settings.vue",
    "content": "<script setup>\nimport { data } from \"/settings.data.ts\";\nimport Setting from \"/components/setting.vue\";\nconst { child, prefix } = defineProps([\"child\", \"level\", \"prefix\"]);\n\nconst settings = child\n  ? (data.find((f) => f.key === child)?.settings ?? [])\n  : prefix\n    ? data.filter((f) => f.key === prefix || f.key.startsWith(`${prefix}_`) || f.key.startsWith(`${prefix}.`))\n    : data;\n\n// Check if there are any settings to display\nconst hasSettings =\n  settings.some((f) => f.type) || settings.some((f) => !f.type);\n</script>\n\n<!--  <ul>-->\n<!--    <li v-for=\"setting in settings\">-->\n<!--      <a v-if=\"!settings.settings\" :href=\"`#${ setting.key }`\"><code>{{ setting.key }}</code></a>-->\n<!--      <ul v-if=\"setting.settings\">-->\n<!--        <li v-for=\"child in setting.settings\">-->\n<!--          <a :href=\"`#${ child.key }`\"><code>{{ child.key }}</code></a>-->\n<!--        </li>-->\n<!--      </ul>-->\n<!--    </li>-->\n<!--  </ul>-->\n\n<template>\n  <div v-if=\"!hasSettings\" class=\"no-settings\">\n    <p>No settings available.</p>\n  </div>\n\n  <template v-else>\n    <Setting\n      v-for=\"setting in settings.filter((f) => f.type)\"\n      :setting=\"setting\"\n      :key=\"setting.key\"\n      :level=\"level\"\n    />\n\n    <div v-for=\"child in settings.filter((f) => !f.type)\">\n      <h2 :id=\"child.key\">\n        <code>{{ child.key }}</code>\n        <a :href=\"`#${child.key}`\" class=\"header-anchor\"></a>\n      </h2>\n      <Setting\n        v-for=\"setting in child.settings\"\n        :setting=\"setting\"\n        :key=\"setting.key\"\n        :level=\"level + 1\"\n      />\n    </div>\n  </template>\n</template>\n"
  },
  {
    "path": "docs/configuration/environments.md",
    "content": "# Config Environments\n\nIt's possible to have separate `mise.toml` files in the same directory for different\nenvironments like `development` and `production`. To enable, set `MISE_ENV` to an\nenvironment like `development` or `production` using one of these methods:\n\n- CLI flag: `-E development` or `--env development`\n- Environment variable: `MISE_ENV=development`\n- `.miserc.toml` file: `env = [\"development\"]`\n\nmise will then look for a `mise.{MISE_ENV}.toml` file in the current directory,\nparent directories and the `MISE_CONFIG_DIR` directory.\n\n## Setting MISE_ENV in .miserc.toml\n\nYou can set `MISE_ENV` in a `.miserc.toml` file, which is loaded very early before\nother config files are discovered. This allows you to commit your environment\nconfiguration to version control:\n\n```toml\n# .miserc.toml\nenv = [\"development\"]\n```\n\nFile locations searched (in order of precedence):\n\n1. `.miserc.toml` and `.config/miserc.toml` in current directory and parent directories\n2. `~/.config/mise/miserc.toml` (global)\n3. `/etc/mise/miserc.toml` (system)\n\nNote: `MISE_ENV` cannot be set in `mise.toml` because it determines which config\nfiles to load in the first place.\n\nmise will also look for \"local\" files like `mise.local.toml` and `mise.{MISE_ENV}.local.toml`\nin the current directory and parent directories.\nThese are intended to not be committed to version control.\n(Add `mise.local.toml` and `mise.*.local.toml` to your `.gitignore` file.)\n\nThe priority of these files goes in this order (top overrides bottom):\n\n- `mise.{MISE_ENV}.local.toml`\n- `mise.local.toml`\n- `mise.{MISE_ENV}.toml`\n- `mise.toml`\n\nIf `MISE_OVERRIDE_CONFIG_FILENAMES` is set, that will be used instead of all of this.\n\nYou can also use paths like `mise/config.{MISE_ENV}.toml` or `.config/mise.{MISE_ENV}.toml` Those rules\nfollow the order in [Configuration](/configuration).\n\nUse `mise config` to see which files are being used.\n\nThe rules around which file is written are different because we ultimately need to choose one. See\nthe docs for [`mise use`](/cli/use.html) for more information.\n\nMultiple environments can be specified, e.g. `MISE_ENV=ci,test` with the last one taking precedence.\n"
  },
  {
    "path": "docs/configuration/settings.md",
    "content": "# Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n\nThe following is a list of all of mise's settings. These can be set via `mise settings key=value`,\nby directly modifying `~/.config/mise/config.toml` or local config, or via environment variables.\n\nSome of them also can be set via global CLI flags.\n\n<Settings :level=\"2\" />\n"
  },
  {
    "path": "docs/configuration.md",
    "content": "# Configuration\n\nLearn how to configure mise for your project with `mise.toml` files, environment variables, and various configuration options to manage your development environment.\n\n## `mise.toml`\n\n`mise.toml` is the config file for mise. They can be at any of the following file paths (in order of precedence, top overrides configuration of lower paths):\n\n- `mise.local.toml` - used for local config, this should not be committed to source control\n- `mise.toml`\n- `mise/config.toml`\n- `.mise/config.toml`\n- `.config/mise.toml` - use this in order to group config files into a common directory\n- `.config/mise/config.toml`\n- `.config/mise/conf.d/*.toml` - all files in this directory will be loaded in alphabetical order\n\n::: tip\nRun [`mise cfg`](/cli/config.html) to figure out what order mise is loading files on your particular setup. This is often\na lot easier than figuring out mise's rules.\n:::\n\nNotes:\n\n- Paths which start with `mise` can be dotfiles, e.g.: `.mise.toml` or `.mise/config.toml`.\n- This list doesn't include [Configuration Environments](/configuration/environments) which allow for environment-specific config files like `mise.development.toml`—set with `MISE_ENV=development`.\n- See [`LOCAL_CONFIG_FILENAMES` in `src/config/mod.rs`](https://github.com/jdx/mise/blob/main/src/config/mod.rs) for the actual code for these paths and their precedence. Some legacy paths are not listed here for brevity.\n\n## Configuration Hierarchy\n\nmise uses a sophisticated hierarchical configuration system that merges settings from multiple sources. Understanding this hierarchy helps you organize your development environments effectively.\n\n### How Configuration Merging Works\n\nThese files recurse upwards, so if you have a `~/src/work/myproj/mise.toml` file, what is defined\nthere will override anything set in\n`~/src/work/mise.toml` or `~/.config/mise.toml`. The config contents are merged together.\n\n### Configuration Resolution Process\n\nWhen mise needs configuration, it follows this process:\n\n1. **Walks up the directory tree** from your current location to the root (or `MISE_CEILING_PATHS`)\n2. **Collects all config files** it finds along the way\n3. **Merges them in order** with more specific (closer to your current directory) settings overriding broader ones\n4. **Applies environment-specific configs** like `mise.dev.toml` if `MISE_ENV` is set\n\n### Visual Configuration Hierarchy\n\n```\n/\n├── etc/mise/                         # System-wide config (highest precedence)\n│   ├── conf.d/*.toml                 # System fragments, loaded alphabetically\n│   ├── config.toml                   # System defaults\n│   └── config.<env>.toml             # Env-specific system config (MISE_ENV or -E)\n└── home/user/\n    ├── .config/mise/\n    │   ├── conf.d/*.toml             # User fragments, loaded alphabetically\n    │   ├── config.toml               # Global user config\n    │   ├── config.<env>.toml         # Env-specific user config\n    │   ├── config.local.toml         # User-local overrides\n    │   └── config.<env>.local.toml   # Env-specific user-local overrides\n    └── work/\n        ├── mise.toml                 # Work-wide settings\n        └── myproject/\n            ├── mise.local.toml       # Local overrides (git-ignored)\n            ├── mise.toml             # Project config\n            ├── mise.<env>.toml       # Env-specific project config\n            ├── mise.<env>.local.toml # Env-specific project local overrides\n            └── backend/\n                └── mise.toml         # Service-specific config (lowest precedence)\n```\n\n### Merge Behavior by Section\n\nDifferent configuration sections merge in different ways:\n\n**Tools** (`[tools]`): Additive with overrides\n\n```toml\n# Global: node@18, python@3.11\n# Project: node@20, go@1.21\n# Result: node@20, python@3.11, go@1.21\n```\n\n**Environment Variables** (`[env]`): Additive with overrides\n\n```toml\n# Global: NODE_ENV=development\n# Project: NODE_ENV=production, API_URL=localhost\n# Result: NODE_ENV=production, API_URL=localhost\n```\n\n**Tasks** (`[tasks]`): Completely replaced per task\n\n```toml\n# Global: [tasks.test] = \"npm test\"\n# Project: [tasks.test] = \"yarn test\"\n# Result: \"yarn test\" (completely replaces global)\n```\n\n**Settings** (`[settings]`): Additive with overrides\n\n```toml\n# Global: experimental = true\n# Project: jobs = 4\n# Result: experimental = true, jobs = 4\n```\n\n::: tip\nRun `mise config` to see what files mise has loaded in order of precedence.\n:::\n\n### Target File for Write Operations\n\nWhen commands like [`mise use`](/cli/use), [`mise set`](/cli/set), or [`mise unuse`](/cli/unuse) need to write to a config file, they use the **lowest precedence file in the highest precedence directory**. This means:\n\n- If both `mise.toml` and `mise.local.toml` exist, writes go to `mise.toml`\n- If both `mise.toml` and `mise.production.toml` exist, writes go to `mise.toml`\n- If only `mise.local.toml` exists, writes go to `mise.local.toml`\n\nThis behavior ensures that shared configuration (`mise.toml`) is updated by default, while local overrides (`mise.local.toml`) and environment-specific configs remain untouched unless explicitly targeted.\n\n::: info Example\n\n```bash\n# With both mise.toml and mise.local.toml present:\n$ mise use node@22              # writes to mise.toml\n$ mise use --env local node@20  # writes to mise.local.toml\n$ mise set NODE_ENV=production  # writes to mise.toml\n```\n\n:::\n\nHere is what a `mise.toml` looks like:\n\n```toml\n[env]\nNODE_ENV = 'production'\n\n[tools]\nterraform = '1.0.0'\nerlang = '24.0'\n\n[tasks.build]\nrun = 'echo \"running build tasks\"'\n```\n\n`mise.toml` files are hierarchical. The configuration in a file in the current directory will\noverride conflicting configuration in parent directories. For example, if `~/src/myproj/mise.toml`\ndefines the following:\n\n```toml\n[tools]\nnode = '20'\npython = '3.10'\n```\n\nAnd `~/src/myproj/backend/mise.toml` defines:\n\n```toml\n[tools]\nnode = '18'\nruby = '3.1'\n```\n\nThen when inside of `~/src/myproj/backend`, `node` will be `18`, `python` will be `3.10`, and `ruby`\nwill be `3.1`. You can check the active versions with `mise ls --current`.\n\nYou can also have environment specific config files like `.mise.production.toml`, see\n[Configuration Environments](/configuration/environments) for more details.\n\n### `[tools]` - Dev tools\n\nSee [Tools](/dev-tools/). In addition to specifying versions, each tool entry can include options such as:\n\n- `os`: Restrict installation to certain operating systems\n- `install_env`: Environment vars used during install\n- `postinstall`: Command to run after installation completes for that specific tool\n\nExamples:\n\n```toml\n[tools]\nnode = { version = \"22\", postinstall = \"corepack enable\" }\n```\n\n### `[env]` - Arbitrary Environment Variables\n\nSee [environments](/environments/).\n\n### `[tasks.*]` - Run files or shell scripts\n\nSee [Tasks](/tasks/).\n\n### `[settings]` - Mise Settings\n\nSee [Settings](/configuration/settings) for the full list of settings.\n\n### `[plugins]` - Specify Custom Plugin Repository URLs\n\nUse `[plugins]` to add/modify plugin shortnames. Note that this will only modify\n_new_ plugin installations. Existing plugins can use any URL.\n\n```toml\n[plugins]\nelixir = \"https://github.com/my-org/mise-elixir.git\"\nnode = \"https://github.com/my-org/mise-node.git#DEADBEEF\" # supports specific gitref\n\"vfox-backend:myplugin\" = \"https://github.com/jdx/vfox-npm\"\n```\n\nThe plugin type prefix (e.g., `asdf:`, `vfox:` or `vfox-backend:`) is optional. If omitted, mise will fall back to\neither using `asdf` or `vfox` if the URL contains `vfox-` in the repo name.\n\nIf you simply want to install a plugin from a specific URL once, it's better to use\n`mise plugin install <NAME> <GIT_URL>`. Add this section to `mise.toml` if you want\nto share the plugin location/revision with other developers in your project.\n\nThis is similar\nto [`MISE_SHORTHANDS`](https://github.com/jdx/mise#mise_shorthands_fileconfigmiseshorthandstoml)\nbut doesn't require a separate file.\n\n### `[tool_alias]` - Tool version aliases\n\n::: tip\n`[alias]` has been renamed to `[tool_alias]` to distinguish it from `[shell_alias]`.\nThe old `[alias]` key still works but is deprecated.\n:::\n\nThe following makes `mise install node@my_custom_node` install node-20.x\nthis can also be specified in a [plugin](/dev-tools/aliases.md).\nnote adding an alias will also add a symlink, in this case:\n\n```sh\n~/.local/share/mise/installs/node/20 -> ./20.x.x\n```\n\n```toml\n[tool_alias.node.versions]\nmy_custom_node = '20'\n```\n\n### `[shell_alias]` - Shell aliases\n\nDefine shell aliases that are set when entering a directory and unset when leaving:\n\n```toml\n[shell_alias]\nll = \"ls -la\"\ngs = \"git status\"\ndev = \"npm run dev\"\n```\n\nThese work similar to environment variables—they're set dynamically based on your current directory.\nSee [Shell Aliases](/shell-aliases) for more details.\n\n### Minimum mise version\n\nSpecify the minimum supported version of mise required for the configuration file.\n\nYou can set a hard minimum (errors if unmet) or a soft minimum (warns and continues):\n\n```toml\n# (equivalent to hard)\nmin_version = '2024.11.1'\n\n# new object form\nmin_version = { hard = '2024.11.1' }\n\n# soft recommendation\nmin_version = { soft = '2024.11.1' }\n\n# both\nmin_version = { hard = '2024.11.1', soft = '2024.9.0' }\n```\n\nWhen a soft minimum is not met, mise will print a warning and (if available) show self-update instructions. When a hard minimum is not met, mise errors and shows self-update instructions.\n\n### Monorepo root <Badge type=\"warning\" text=\"experimental\" />\n\nMark a configuration file as a monorepo root to enable target path syntax for tasks. Requires `MISE_EXPERIMENTAL=1`.\n\n```toml\nexperimental_monorepo_root = true\n```\n\nWhen enabled:\n\n- Tasks in subdirectories are available with namespaced paths (e.g., `//projects/frontend:build`)\n- Subdirectory tasks use tools from parent configs\n- Tasks are only loaded when needed (e.g., when running them, or with `mise tasks ls --all`)\n- All descendant config files are **implicitly trusted** when the root is trusted\n- Eliminates the need to individually trust each subdirectory's configuration\n\nSee [Monorepo Tasks](/tasks/monorepo) for detailed usage and examples.\n\n### `mise.toml` schema\n\n- You can find the JSON schema for `mise.toml` in [schema/mise.json](https://github.com/jdx/mise/blob/main/schema/mise.json) or at <https://mise.jdx.dev/schema/mise.json>.\n- Some editors can load it automatically to provide autocompletion and validation for when editing a `mise.toml` file ([VSCode](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings), [IntelliJ](https://www.jetbrains.com/help/idea/json.html#ws_json_using_schemas), [neovim](https://github.com/b0o/SchemaStore.nvim), etc.). It is also available in the [JSON schema store](https://www.schemastore.org/).\n- Note that for `included tasks` (see [task configuration](/tasks/task-configuration), there is another schema: <https://mise.jdx.dev/schema/mise-task.json>)\n\n## Global config: `~/.config/mise/config.toml`\n\nmise can be configured in `~/.config/mise/config.toml`. It's like local `mise.toml` files except\nthat\nit is used for all directories.\n\n```toml [~/.config/mise/config.toml]\n[tools]\n# global tool versions go here\n# you can set these with `mise use -g`\nnode = 'lts'\npython = ['3.10', '3.11']\n\n[settings]\n# tools can read the versions files used by other version managers\n# for example, .nvmrc in the case of node's nvm\nidiomatic_version_file_enable_tools = ['node']\n\n# configure `mise install` to always keep the downloaded archive\nalways_keep_download = false        # deleted after install by default\nalways_keep_install = false         # deleted on failure by default\n\n# configure how frequently (in minutes) to fetch updated plugin repository changes\n# this is updated whenever a new runtime is installed\n# (note: this isn't currently implemented but there are plans to add it: https://github.com/jdx/mise/discussions/6735)\nplugin_autoupdate_last_check_duration = '1 week' # set to 0 to disable updates\n\n# config files with these prefixes will be trusted by default\ntrusted_config_paths = [\n    '~/work/my-trusted-projects',\n]\n\nverbose = false       # set to true to see full installation output, see `MISE_VERBOSE`\nhttp_timeout = \"30s\"  # set the timeout for http requests as duration string, see `MISE_HTTP_TIMEOUT`\njobs = 4              # number of plugins or runtimes to install in parallel. The default is `4`.\nraw = false           # set to true to directly pipe plugins to stdin/stdout/stderr\nyes = false           # set to true to automatically answer yes to all prompts\n\nnot_found_auto_install = true # see MISE_NOT_FOUND_AUTO_INSTALL\ntask.output = \"prefix\" # see Tasks Runner for more information\nparanoid = false       # see MISE_PARANOID\n\nshorthands_file = '~/.config/mise/shorthands.toml' # path to the shorthands file, see `MISE_SHORTHANDS_FILE`\ndisable_default_shorthands = false # disable the default shorthands, see `MISE_DISABLE_DEFAULT_SHORTHANDS`\ndisable_tools = ['node']           # disable specific tools, generally used to turn off core tools\n\nenv_file = '.env' # load env vars from a dotenv file, see `MISE_ENV_FILE`\n\nexperimental = true # enable experimental features\n\n# configure messages displayed when entering directories with config files\nstatus = {\n  missing_tools = \"if_other_versions_installed\",\n  show_env = false,\n  show_tools = false,\n}\n\n# \"_\" is a special key for information you'd like to put into mise.toml that mise will never parse\n[_]\nfoo = \"bar\"\n```\n\n## System config: `/etc/mise/config.toml`\n\nSimilar to `~/.config/mise/config.toml` but for all users on the system. This is useful for\nsetting defaults for all users.\n\n## `.tool-versions`\n\nThe `.tool-versions` file is asdf's config file and it can be used in mise just like `mise.toml`.\nIt isn't as flexible so it's recommended to use `mise.toml` instead. It can be useful if you\nalready have a lot of `.tool-versions` files or work on a team that uses asdf.\n\nHere is an example with all the supported syntax:\n\n```text\nnode        20.0.0       # comments are allowed\nruby        3            # can be fuzzy version\nshellcheck  latest       # also supports \"latest\"\njq          1.6\nerlang      ref:master   # compile from vcs ref\ngo          prefix:1.19  # uses the latest 1.19.x version—needed in case \"1.19\" is an exact match\nshfmt       path:./shfmt # use a custom runtime\nnode        lts          # use lts version of node (not supported by all plugins)\n\nnode        sub-2:lts      # install 2 versions behind the latest lts (e.g.: 18 if lts is 20)\npython      sub-0.1:latest # install python-3.10 if the latest is 3.11\n```\n\nSee [the asdf docs](https://asdf-vm.com/manage/configuration.html#tool-versions) for more info on\nthis file format.\n\n## Scopes\n\nBoth `mise.toml` and `.tool-versions` support \"scopes\" which modify the behavior of the version:\n\n- `ref:<SHA>` - compile from a vcs (usually git) ref\n- `prefix:<PREFIX>` - use the latest version that matches the prefix. Useful for Go since `1.20`\n  would only match `1.20` exactly but `prefix:1.20` will match `1.20.1` and `1.20.2` etc.\n- `path:<PATH>` - use a custom compiled version at the given path. One use-case is to re-use\n  Homebrew tools (e.g.: `path:/opt/homebrew/opt/node@20`).\n- `sub-<PARTIAL_VERSION>:<ORIG_VERSION>` - subtracts PARTIAL_VERSION from ORIG_VERSION. This can\n  be used to express something like \"2 versions behind lts\" such as `sub-2:lts`. Or 1 minor\n  version behind the latest version: `sub-0.1:latest`.\n\n## Idiomatic version files\n\nmise supports \"idiomatic version files\" just like asdf. They're language-specific files\nlike `.node-version`\nand `.python-version`. These are ideal for setting the runtime version of a project without forcing\nother developers to use a specific tool like mise or asdf.\n\nThey support aliases, which means you can have an `.nvmrc` file with `lts/hydrogen` and it will work\nin mise and nvm. Here are some of the supported idiomatic version files:\n\n| Plugin     | Idiomatic Files                           |\n| ---------- | ----------------------------------------- |\n| atmos      | `.atmos-version`                          |\n| bun        | `.bun-version`, `package.json`            |\n| crystal    | `.crystal-version`                        |\n| deno       | `.deno-version`, `package.json`           |\n| dotnet     | `global.json`                             |\n| elixir     | `.exenv-version`                          |\n| go         | `.go-version`                             |\n| java       | `.java-version`, `.sdkmanrc`              |\n| node       | `.nvmrc`, `.node-version`, `package.json` |\n| npm        | `package.json`                            |\n| opentofu   | `.opentofu-version`                       |\n| packer     | `.packer-version`                         |\n| pnpm       | `package.json`                            |\n| python     | `.python-version`, `.python-versions`     |\n| ruby       | `.ruby-version`, `Gemfile`                |\n| terraform  | `.terraform-version`, `main.tf`           |\n| terragrunt | `.terragrunt-version`                     |\n| terramate  | `.terramate-version`                      |\n| yarn       | `.yvmrc`, `package.json`                  |\n\nIn mise, these are disabled by default, see <https://github.com/jdx/mise/discussions/4345> for rationale.\n\n- `mise settings add idiomatic_version_file_enable_tools python` for a specific tool such as Python ([docs](/configuration/settings.html#idiomatic_version_file_enable_tools))\n\nThere is a performance cost to having these when they're parsed as it's performed by the plugin in\n`bin/parse-version-file`. However, these are [cached](/cache-behavior) so it's not a huge deal.\nYou may not even notice.\n\n::: info\nasdf called these \"legacy version files\". I think this was a bad name since it implies\nthat they shouldn't be used—which is definitely not the case IMO. I prefer the term \"idiomatic\"\nversion files since they are version files not specific to asdf/mise and can be used by other tools.\n(`.nvmrc` being a notable exception, which is tied to a specific tool.)\n:::\n\n## Settings\n\nSee [Settings](/configuration/settings) for the full list of settings.\n\n## Tasks\n\nSee [Tasks](/tasks/) for the full list of configuration options.\n\n## Environment variables\n\n::: tip\nNormally environment variables in mise are used to set [settings](/configuration/settings) so most\nenvironment variables are in that doc. The following are environment variables that are not settings.\n\nA setting in mise is generally something that can be configured either as an environment variable\nor set in a config file.\n:::\n\nmise can also be configured via environment variables. The following options are available:\n\n### `MISE_DATA_DIR`\n\nDefault: `~/.local/share/mise` or `$XDG_DATA_HOME/mise`\n\nThis is the directory where mise stores plugins and tool installs. These are not supposed to be\nshared\nacross machines.\n\n### `MISE_CACHE_DIR`\n\nDefault (Linux): `~/.cache/mise` or `$XDG_CACHE_HOME/mise`\nDefault (macOS): `~/Library/Caches/mise` or `$XDG_CACHE_HOME/mise`\n\nThis is the directory where mise stores internal cache. This is not supposed to be shared\nacross machines. It may be deleted at any time mise is not running.\n\n### `MISE_TMP_DIR`\n\nDefault: [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir.html) implementation\nin rust\n\nThis is used for temporary storage such as when installing tools.\n\n### `MISE_SYSTEM_CONFIG_DIR`\n\nDefault: `/etc/mise`\n\nThis is the directory where mise stores system-wide configuration.\n`MISE_SYSTEM_DIR` is also supported as a legacy alias.\n\n### `MISE_GLOBAL_CONFIG_FILE`\n\nDefault: `$MISE_CONFIG_DIR/config.toml` (Usually ~/.config/mise/config.toml)\n\nThis is the path to the config file.\n\n### `MISE_GLOBAL_CONFIG_ROOT`\n\nDefault: `$HOME`\n\n::: v-pre\nThis is the path which is used as `{{config_root}}` for the global config file.\n:::\n\n### `MISE_ENV_FILE`\n\nSet to a filename to read from env from a dotenv file. e.g.: `MISE_ENV_FILE=.env`.\nUses [dotenvy](https://crates.io/crates/dotenvy) under the hood.\n\n### `MISE_${PLUGIN}_VERSION`\n\nSet the version for a runtime. For example, `MISE_NODE_VERSION=20` will use <node@20.x> regardless\nof what is set in `mise.toml`/`.tool-versions`.\n\n### `MISE_TRUSTED_CONFIG_PATHS`\n\nThis is a list of paths that mise will automatically mark as\ntrusted. They can be separated with `:`.\n\n### `MISE_CEILING_PATHS`\n\nThis is a list of paths where mise will stop searching for\nconfiguration files and file tasks. This is useful to stop\nmise searching for files in slow loading directories. They are separated according to platform conventions for the PATH environment variable. On most Unix platforms, the separator is `:` and on Windows it is `;`.\n\n### `MISE_LOG_LEVEL=trace|debug|info|warn|error`\n\nThese change the verbosity of mise.\n\nYou can also use `MISE_DEBUG=1`, `MISE_TRACE=1`, and `MISE_QUIET=1` as well as\n`--log-level=trace|debug|info|warn|error`.\n\n### `MISE_LOG_FILE=~/mise.log`\n\nOutput logs to a file.\n\n### `MISE_LOG_FILE_LEVEL=trace|debug|info|warn|error`\n\nSame as `MISE_LOG_LEVEL` but for the log _file_ output level. This is useful if you want\nto store the logs but not have them litter your display.\n\n### `MISE_LOG_HTTP=1`\n\nDisplay HTTP requests/responses in the logs.\n\n### `MISE_QUIET=1`\n\nEquivalent to `MISE_LOG_LEVEL=warn`.\n\n### `MISE_HTTP_TIMEOUT`\n\nSet the timeout for http requests in seconds. The default is `30`.\n\n### `MISE_RAW=1`\n\nSet to \"1\" to directly pipe plugin scripts to stdin/stdout/stderr. By default stdin is disabled\nbecause when installing a bunch of plugins in parallel you won't see the prompt. Use this if a\nplugin accepts input or otherwise does not seem to be installing correctly.\n\nSets `MISE_JOBS=1` because only 1 plugin script can be executed at a time.\n\n### `MISE_FISH_AUTO_ACTIVATE=1`\n\nConfigures the vendor_conf.d script for fish shell to automatically activate.\nThis file is automatically used in homebrew and potentially other installs to\nautomatically activate mise without configuring.\n\nDefaults to enabled, set to \"0\" to disable.\n"
  },
  {
    "path": "docs/contact.md",
    "content": "# Contact\n\n`mise` is mostly built and maintained by me, [Jeff Dickey](https://jdx.dev). The goal is\nto make local development of software easy and consistent across languages. I\nhave spent many years building dev tools and thinking about the problems that `mise`\naddresses.\n\nI try to use the first-person in these docs since the reality is it's generally me\nwriting them and I think it makes it more interesting having a bit of my personality\nin the text.\n\nThis project is simply a labor of love. I am making it because I want to make\nyour life as a developer easier. I hope you find it useful. Feedback is a massive\ndriver for me. If you have anything positive or negative to say-even if it's just\nto say hi-please reach out to me either on [Twitter](https://twitter.com/jdxcode),\n[Mastodon](https://fosstodon.org/@jdx), [Discord](https://discord.gg/UBa7pJUN7Z),\nor `jdx at this domain`.\n"
  },
  {
    "path": "docs/continuous-integration.md",
    "content": "# Continuous integration\n\nYou can use Mise in continuous integration environments to provision the environment with the tools the project needs.\nWe recommend that your project pins the tools to a specific version to ensure the environment is reproducible.\n\n## Any CI provider\n\nContinuous integration pipelines allow running arbitrary commands. You can use this to install Mise and run `mise install` to install the tools:\n\n```yaml\nscript: |\n  curl https://mise.run | sh\n  mise install\n```\n\nTo ensure you run the version of the tools installed by Mise, make sure you run them through the `mise x` command:\n\n```yaml\nscript: |\n  mise x -- npm test\n```\n\nAlternatively, you can add the [shims](/dev-tools/shims.md) directory to your `PATH`, if the CI provider allows it.\n\n### Bootstrapping\n\nAn alternative to calling `curl https://mise.run | sh` is to use [`mise generate bootstrap`](/cli/generate/bootstrap.html) to generate a script that runs and install `mise`.\n\n```shell\nmise generate bootstrap -l -w\n```\n\nAdd the `.mise/` to your `.gitignore` and commit the generated `./bin/mise` file. You can now use `./bin/mise` to install and run `mise` directly in CI.\n\n```yaml\nscript: |\n  ./bin/mise install\n  ./bin/mise x -- npm test\n```\n\n## GitHub Actions\n\nIf you use GitHub Actions, we provide a [mise-action](https://github.com/jdx/mise-action) that wraps the installation of Mise and the tools. All you need to do is to add the action to your workflow:\n\n```yaml\nname: test\non:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - main\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: jdx/mise-action@v3\n        with:\n          version: 2024.12.14 # [default: latest] mise version to install\n          install: true # [default: true] run `mise install`\n          cache: true # [default: true] cache mise using GitHub's cache\n          experimental: true # [default: false] enable experimental features\n          # automatically write this mise.toml file\n          mise_toml: |\n            [tools]\n            shellcheck = \"0.9.0\"\n          # or, if you prefer .tool-versions:\n          tool_versions: |\n            shellcheck 0.9.0\n      - run: shellcheck scripts/*.sh\n```\n\n## GitLab CI\n\nYou can use any docker image with `mise` installed to run your CI jobs.\nHere's an example using `debian-slim` as base image:\n::: details Example Dockerfile\n\n```dockerfile\nFROM debian:12-slim\n\nRUN apt-get update  \\\n    && apt-get -y --no-install-recommends install  \\\n      # install any tools you need\n      sudo curl git ca-certificates build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\nRUN curl https://mise.run | MISE_VERSION=v... MISE_INSTALL_PATH=/usr/local/bin/mise sh\n```\n\n:::\n\nWhen configuring your job, you can cache some of the [Mise directories](/directories).\n\n```yaml\nbuild-job:\n  stage: build\n  image: mise-debian-slim # Use the image you created\n  variables:\n    MISE_DATA_DIR: $CI_PROJECT_DIR/.mise/mise-data\n  cache:\n    - key:\n        prefix: mise-\n        files: [\"mise.toml\", \"mise.lock\"] # mise.lock is optional, only if using `lockfile = true`\n      paths:\n        - $MISE_DATA_DIR\n  script:\n    - mise install\n    - mise exec --command 'npm build'\n```\n\n### Example with the bootstrap script\n\nAn alternative is to use [`mise generate bootstrap`](/cli/generate/bootstrap.html) to easily [bootstrap](#bootstrapping) `mise` on GitLab CI.\n\n```\nmise generate bootstrap -l -w\n```\n\nYou can now use a generic docker image such as this one to run and install `mise` in CI.\n\n::: details Example Dockerfile\n\n```dockerfile\nFROM debian:12-slim\n\nRUN apt-get update  \\\n    && apt-get -y --no-install-recommends install sudo curl git ca-certificates build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n```\n\n:::\n\nHere's an example of a `.gitlab-ci.yml` file:\n\n```yaml\n.mise-cache: &mise-cache\n  key:\n    prefix: mise-\n    files: [\"mise.toml\", \"./bin/mise\"]\n  paths:\n    - .mise/installs\n    - .mise/mise-2025.1.3\n\nbuild-job:\n  stage: build\n  image: my-debian-slim-image # Use the image you created\n  cache:\n    - <<: *mise-cache\n      policy: pull-push\n  script:\n    - ./bin/mise install\n    - ./bin/mise exec --command 'npm build'\n```\n\n## Xcode Cloud\n\nIf you are using Xcode Cloud, you can use custom `ci_post_clone.sh` [build script](https://developer.apple.com/documentation/xcode/writing-custom-build-scripts) to install Mise. Here's an example:\n\n```bash\n#!/bin/sh\ncurl https://mise.run | sh\nexport PATH=\"$HOME/.local/bin:$PATH\"\n\nmise install # Installs the tools in mise.toml\neval \"$(mise activate bash --shims)\" # Adds the activated tools to $PATH\n\nswiftlint {args}\n```\n"
  },
  {
    "path": "docs/contributing.md",
    "content": "---\noutline: [1, 3]\n---\n\n# Contributing\n\nBefore submitting a PR, unless it's something obvious, consider creating a\n[discussion](https://github.com/jdx/mise/discussions)\nor simply mention what you plan to do in the\n[Discord](https://discord.gg/UBa7pJUN7Z).\nPRs are often either rejected or need to change significantly after submission\nso make sure before you start working on something it won't be a wasted effort.\n\n## Contributing Guidelines\n\n1. **Before starting**: Create a discussion or discuss in Discord for non-obvious changes\n2. **Test thoroughly**: Ensure both unit and E2E tests pass\n3. **Follow conventions**: Use existing code style and patterns\n4. **Update documentation**: Add/update docs for new features\n\n### Pull Request Workflow\n\n1. **PR titles**: Must follow conventional commit format (validated\n   automatically)\n   - For new tools in registry: Use `registry: add tool-name (backend:full/name)`\n2. **Auto-formatting**: Code will be automatically formatted by autofix.ci\n3. **CI checks**: All tests must pass across Linux, macOS, and Windows\n4. **Coverage**: New code should maintain or improve test coverage\n5. **Dependencies**: New dependencies are validated with cargo-deny\n\n### Development Tips\n\n1. **Disable mise during development**: If you use mise in your shell, disable\n   it when running tests to avoid conflicts\n2. **Test specific features**: Use `cargo test test_name` for targeted testing\n4. **Update snapshots**: Use `mise run snapshots` when changing test outputs\n5. **Rate limiting**: Set `MISE_GITHUB_TOKEN` to avoid GitHub API rate limits\n   during development\n\n## Packaging and Self-Update Instructions\n\nWhen mise is installed via a package manager, in-app self-update is disabled and users should update via their package manager. Packaging should install a TOML file with platform-specific instructions at `lib/mise-self-update-instructions.toml` (or `lib/mise/mise-self-update-instructions.toml`). Example contents:\n\n```toml\n# Debian/Ubuntu (APT)\nmessage = \"To update mise from the APT repository, run:\\n\\n  sudo apt update && sudo apt install --only-upgrade mise\\n\"\n```\n\n```toml\n# Fedora/CentOS Stream (DNF)\nmessage = \"To update mise from COPR, run:\\n\\n  sudo dnf upgrade mise\\n\"\n```\n\n## Testing\n\nmise has a comprehensive test suite with multiple types of tests to ensure\nreliability and functionality across different platforms and scenarios.\n\n### Unit Tests\n\nUnit tests are fast, focused tests for individual components and functions:\n\n```bash\n# Run all unit tests\ncargo test --all-features\n\n# Run specific unit tests\ncargo test <test_name>\n```\n\n**Unit test structure:**\n\n- Located in `src/` directory alongside source code\n- Use Rust's built-in test framework\n- Test individual functions and modules\n- Fast execution (used for quick feedback during development)\n\n### E2E Tests\n\nEnd-to-end tests validate the complete functionality of mise in realistic\nscenarios:\n\n```bash\n# Run all E2E tests\nmise run test:e2e\n\n# Run specific E2E test\n./e2e/run_test test_name\n\n# Run E2E tests matching pattern\n./e2e/run_test task  # runs tests matching *task*\n\n# Run all tests including slow ones\nTEST_ALL=1 mise run test:e2e\n```\n\n**E2E test structure:**\n\n- Located in `e2e/` directory\n- Organized by functionality:\n  - `e2e/cli/` - Command-line interface tests\n  - `e2e/core/` - Core functionality tests\n  - `e2e/env/` - Environment variable tests\n  - `e2e/tasks/` - Task runner tests\n  - `e2e/config/` - Configuration tests\n  - `e2e/tools/` - Tool management tests\n  - `e2e/shell/` - Shell integration tests\n  - `e2e/backend/` - Backend tests\n  - `e2e/plugins/` - Plugin tests\n\n**E2E test categories:**\n\n- **Fast tests** (`test_*`): Run in normal test suites\n- **Slow tests** (`test_*_slow`): Only run when `TEST_ALL=1` is set\n- **Isolated environment**: Each test runs in a clean, isolated environment\n\n### Coverage Tests\n\nCoverage tests measure how much of the codebase is covered by tests:\n\n```bash\n# Run coverage tests\nmise run test:coverage\n\n# Coverage tests run in parallel tranches for CI\nTEST_TRANCHE=0 TEST_TRANCHE_COUNT=8 mise run test:coverage\n```\n\n### Windows E2E Tests\n\nWindows has its own test suite written in PowerShell:\n\n```powershell\n# Run all Windows E2E tests\npwsh e2e-win\\run.ps1\n\n# Run specific Windows tests\npwsh e2e-win\\run.ps1 task  # run tests matching *task*\n```\n\n### Plugin Tests\n\nTest plugin functionality across different backends:\n\n```bash\n# Test specific plugin\nmise test-tool ripgrep\n\n# Test all plugins in registry\nmise test-tool --all\n\n# Test all plugins in config files\nmise test-tool --all-config\n\n# Test with parallel jobs\nmise test-tool --all --jobs 4\n```\n\n### Test Environment Setup\n\nTests run in isolated environments to avoid conflicts:\n\n```bash\n# Disable mise during development testing\nexport MISE_DISABLE_TOOLS=1\n\n# Run tests with specific environment\nMISE_TRUSTED_CONFIG_PATHS=$PWD cargo test\n```\n\n### Test Assertions\n\nThe E2E tests use a custom assertion framework (`e2e/assert.sh`):\n\n```bash\n# Basic assertions\nassert \"command\" \"expected_output\"\nassert_contains \"command\" \"substring\"\nassert_fail \"command\" \"expected_error\"\n\n# JSON assertions\nassert_json \"command\" '{\"key\": \"value\"}'\nassert_json_partial_array \"command\" \"fields\" '[{...}]'\n\n# File/directory assertions\nassert_directory_exists \"/path/to/dir\"\nassert_directory_not_exists \"/path/to/dir\"\nassert_empty \"command\"\n```\n\n### Running Specific Test Categories\n\n```bash\n# Run all tests (unit + e2e)\nmise run test\n\n# Run only unit tests\nmise run test:unit\n\n# Run only e2e tests\nmise run test:e2e\n\n# Run tests with shuffle (for detecting order dependencies)\nmise run test:shuffle\n\n# Run nightly tests (with bleeding edge Rust)\nrustup default nightly && mise run test\n```\n\n### Running Individual Tests\n\n#### Running Single Unit Tests\n\n```bash\n# Run a specific unit test by name\ncargo test test_name\n\n# Run tests matching a pattern\ncargo test pattern\n\n# Run tests in a specific module\ncargo test module_name\n\n# Run a single test with output\ncargo test test_name -- --nocapture\n```\n\n#### Running Single E2E Tests\n\n```bash\n# Run a specific E2E test by name\n./e2e/run_test test_name\n\n# Run E2E tests matching a pattern\nmise run test:e2e pattern\n\n# Examples:\n./e2e/run_test test_use                    # Run specific test\n./e2e/run_test test_config_set            # Run config-related test\nmise run test:e2e task                     # Run all tests matching \"task\"\n```\n\n#### Testing Individual Plugins\n\n```bash\n# Test a specific plugin\nmise test-tool ripgrep\n\n# Test a plugin with verbose output\nmise test-tool ripgrep --raw\n\n# Test multiple plugins\nmise test-tool ripgrep jq terraform\n```\n\n### Performance Testing\n\n```bash\n# Run performance benchmarks\nmise run test:perf\n\n# Build performance test workspace\nmise run test:build-perf-workspace\n```\n\n### Snapshot Testing\n\nUsed for testing output consistency:\n\n```bash\n# Update test snapshots when output changes\nmise run snapshots\n\n# Use cargo-insta for snapshot testing\ncargo insta test --accept --unreferenced delete\n```\n\n## Development Setup\n\n### Prerequisites\n\n- [Rust](https://www.rust-lang.org/) (latest stable, we don't use mise to\n  manage rust)\n- mise\n\n### Getting Started\n\n```bash\n# Clone the repository\ngit clone https://github.com/jdx/mise.git\ncd mise\n\n# Install dependencies\nmise install\n\n# Build the project\nmise run build\n```\n\n### Development Shim\n\nCreate a development shim to easily run mise during development:\n\n```bash\n# Create ~/.local/bin/@mise\n#!/bin/sh\nexec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- \"$@\"\n```\n\nThen use `@mise` to run the development version:\n\n```bash\n@mise --help\neval \"$(@mise activate zsh)\"\n```\n\n## Project Structure\n\n```text\nmise/\n├── src/           # Main Rust source code\n├── e2e/           # End-to-end tests\n├── docs/          # Documentation\n├── tasks.toml     # Development tasks\n├── mise.toml      # Project configuration\n├── Cargo.toml     # Rust project configuration\n└── xtasks/        # Additional build scripts\n```\n\n## Available Development Tasks\n\nUse `mise tasks` to see all available development tasks:\n\n### Common Tasks\n\n- `mise run build` - Build the project\n- `mise run test` - Run all tests (unit + E2E)\n- `mise run test:unit` - Run unit tests only\n- `mise run test:e2e` - Run E2E tests only\n- `mise run lint` - Run linting\n- `mise run lint:fix` - Run linting with fixes\n- `mise run format` - Format code\n- `mise run clean` - Clean build artifacts\n- `mise run snapshots` - Update test snapshots\n- `mise run render` - Generate documentation and completions\n\n### Documentation Tasks\n\n- `mise run docs` - Start documentation development server\n- `mise run docs:build` - Build documentation\n- `mise run render:help` - Generate help documentation\n- `mise run render:completions` - Generate shell completions\n\n### Release Tasks\n\n- `mise run release` - Create a release\n- `mise run ci` - Run CI tasks (format, build, test)\n\n## Setup\n\nShouldn't require anything special I'm aware of, but `mise run build` is a good\nsanity check to run and make sure it's all working.\n\n## Pre-commit Hooks & Code Quality\n\nmise uses [hk](https://hk.jdx.dev) as its git hook manager for\nlinting and code quality checks. hk is a modern alternative to lefthook written\nby the same author as mise.\n\n### hk Configuration\n\nThe project uses `hk.pkl` (written in the Pkl configuration language) to define\nlinting rules:\n\n```bash\n# Run all linting checks\nhk check --all\n\n# Run linting with fixes\nhk fix --all\n\n# Run specific linter\nhk check --step shellcheck\n```\n\n### Available Linters in hk\n\n- **prettier**: Code formatting for multiple languages\n- **clippy**: Rust linting with `cargo clippy`\n- **shellcheck**: Shell script linting\n- **shfmt**: Shell script formatting\n- **pkl**: Pkl configuration file validation\n\n### Using hk in Development\n\n```bash\n# Run linting (used in CI and pre-commit)\nmise run lint  # This runs hk check --all\n\n# Run linting with fixes\nhk fix --all\n\n# Check specific file types\nhk check --step prettier\nhk check --step shellcheck\n```\n\n### Setting Up Pre-commit Hooks\n\n```bash\n# Set up git hooks to run hk on pre-commit\nhk install --mise\n```\n\n### Running Checks Manually\n\n```bash\n# Run all checks\nhk check --all\n\n# Run checks with fixes\nhk fix --all\n\n# Run checks on specific files\nhk check --files=\"src/**/*.rs\"\n```\n\n## Running the CLI\n\nI use the following shim in `~/.local/bin/@mise`:\n\n```sh\n#!/bin/sh\nexec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- \"$@\"\n```\n\n::: info\nDon't forget to change the manifest path to the correct path for your setup.\n:::\n\nThen if that is in PATH just use `@mise` to run mise by compiling it on the fly.\n\n```sh\n@mise --help\neval \"$(@mise activate zsh)\"\n@mise activate fish | source\n```\n\n## Releasing\n\nRun `mise run release -x [minor|patch]`. (minor if it is the first release in a\nmonth)\n\n## Linting\n\n- Lint codebase: `mise run lint`\n- Lint and fix codebase: `mise run lint:fix`\n\n## Generating readme and shell completion files\n\n```sh\nmise run render\n```\n\n## Dependency Management\n\nmise uses several tools to validate dependencies and code quality:\n\n- **cargo-deny**: Validates licenses, security advisories, and dependency\n  duplicates\n- **cargo-msrv**: Verifies minimum supported Rust version compatibility\n- **cargo-machete**: Detects unused dependencies in Cargo.toml\n\nThese checks run automatically in CI and can be run locally:\n\n```bash\n# Run checks (tools are automatically available via mise.toml)\ncargo deny check\ncargo msrv verify\ncargo machete --with-metadata\n```\n\n## Conventional Commits\n\nmise uses [Conventional Commits](https://www.conventionalcommits.org/) for\nconsistent commit messages and automated changelog generation. All commits\nshould follow this format:\n\n```text\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n### Commit Types\n\n- **feat**: New features (🚀 Features)\n- **fix**: Bug fixes (🐛 Bug Fixes)\n- **refactor**: Code refactoring (🚜 Refactor)\n- **docs**: Documentation changes (📚 Documentation)\n- **style**: Code style changes (🎨 Styling)\n- **perf**: Performance improvements (⚡ Performance)\n- **test**: Testing changes (🧪 Testing)\n- **chore**: Maintenance tasks, dependency updates\n- **revert**: Reverting previous changes (◀️ Revert)\n\n### Examples\n\n```bash\nfeat(cli): add new command for listing plugins\nfix(parser): handle edge case in version parsing\nrefactor(config): simplify configuration loading logic\ndocs(readme): update installation instructions\ntest(e2e): add tests for new plugin functionality\nchore(deps): update dependencies to latest versions\n```\n\n### Scopes\n\nCommon scopes used in mise:\n\n- `cli` - Command line interface changes\n- `config` - Configuration system changes\n- `parser` - Parsing logic changes\n- `deps` - Dependency updates\n- `security` - Security-related changes\n\n### Breaking Changes\n\n#### Breaking Change Policy\n\nBreaking changes are rarely accepted into mise and are only performed in\nexceptional situations where there is no better alternative. When a breaking\nchange is necessary, the process includes:\n\n1. **CLI warnings**: Users receive deprecation warnings in the CLI\n2. **Migration period**: Several months are provided for users to migrate\n3. **Documentation**: Clear migration guides are provided\n4. **Community notice**: Announcements in Discord and GitHub discussions\n\nFor breaking changes, add `!` after the type or include `BREAKING CHANGE:` in\nthe footer:\n\n```bash\nfeat(api)!: remove deprecated configuration options\n# OR\nfeat(api): remove deprecated configuration options\n\nBREAKING CHANGE: The old configuration format is no longer supported\n```\n\n## CI/CD & Pull Request Automation\n\nmise uses several automated workflows to maintain code quality and streamline\ndevelopment:\n\n### Automated Code Formatting\n\n- **autofix.ci**: Automatically formats code and fixes linting issues in PRs\n- Runs `mise run render` and `mise run lint-fix` automatically\n- Commits fixes directly to the PR branch\n\n### PR Title Validation\n\n- **semantic-pr-lint**: Validates PR titles follow conventional commit format\n- PR titles must match: `<type>[optional scope]: <description>`\n- Example: `feat(cli): add new command for listing plugins`\n\n### Continuous Integration\n\n- **Cross-platform testing**: Ubuntu, macOS, and Windows\n- **Unit tests**: Fast component-level tests\n- **E2E tests**: Full integration testing with multiple test tranches\n- **Dependency validation**: `cargo deny`, `cargo msrv`, `cargo machete`\n\n### Release Automation\n\n- **release-plz**: Automated release management based on conventional commits\n- Automatically creates release PRs and publishes releases\n- Runs daily via scheduled workflow\n- Handles version bumping and changelog generation\n\n## Adding a new setting\n\nTo add a new setting, add it to\n[`settings.toml`](https://github.com/jdx/mise/blob/main/settings.toml) in the\nroot of the project and run `mise run render` to update the codebase.\n\n## Adding Tools\n\nAdding tools to mise involves adding entries to the\n[registry/](https://github.com/jdx/mise/blob/main/registry/) file. This\nallows users to install tools using short names like `mise use ripgrep` instead\nof the full backend specification.\n\n### Quick Start\n\n1. **Choose the right backend** for your tool:\n\n   - **[aqua](dev-tools/backends/aqua.md)** - Preferred for GitHub releases with security\n     features\n   - **[github](dev-tools/backends/github.md)** - Simple GitHub releases following\n     standard conventions\n   - **Language package managers** - `npm`, `pipx`, `cargo`, `gem`, etc. for\n     ecosystem-specific tools\n   - **[Core tools](core-tools.md)** - Built-in support for major languages\n     (not user-contributed)\n\n2. **Add to registry/**:\n\n   ```toml\n   [tools.your-tool]\n   description = \"Brief description of the tool\"\n   backends = [\"aqua:owner/repo\", \"github:owner/repo\"]\n   test = [\"your-tool --version\", \"{{version}}\"]\n   ```\n\n3. **Test the tool** works properly with `mise test-tool your-tool`\n\n### Guidelines and Requirements\n\nWhen adding a new tool, the following requirements apply (automatically\nenforced by [GitHub Actions workflow](https://github.com/jdx/mise/blob/main/.github/workflows/registry_comment.yml)):\n\n- **New asdf plugins are not accepted** - Use aqua/github instead\n- **A test is required in `registry/`** - Must include a `test` field to\n  verify installation\n- **Tools may be rejected if they are not notable** - The tool should be\n  reasonably popular and well-maintained. There are no specific guidelines for this and\n  a lot of factors are taken into account. @jdx won't explain why a given tool wasn't\n  accepted.\n\n### Registry Format\n\nThe `registry/` file uses this format:\n\n```toml\n# Tool name \"your-tool\" (becomes the short name for `mise use`)\n[tools.your-tool]\ndescription = \"Tool description\"\nbackends = [\n    \"aqua:owner/repo\",           # Preferred backend first\n    \"github:owner/repo\",         # Fallback backends\n    \"npm:package-name\"           # Multiple backends supported\n]\ntest = [\n    \"your-tool --version\",       # Command to run\n    \"{{version}}\"                # Expected output pattern\n]\naliases = [\"alt-name\"] # Optional alternative names\nos = [\"linux\", \"macos\"] # Optional OS restrictions\n```\n\n### Backend Priority\n\nList backends in order of preference. Users will get the first available\nbackend, but can override with explicit syntax like `mise use aqua:owner/repo`.\n\n### Tool Testing\n\nAll tools must include a test to verify proper installation:\n\n```toml\ntest = [\n    \"command-to-run\",\n    \"expected-output-pattern\"\n]\n```\n\nThe test command should be reliable and the output pattern should use\n`{{version}}` to match any version number.\n\n### Registry Examples\n\nRecent tool additions:\n\n- **DuckDB**: Simple github backend ([#4248](https://github.com/jdx/mise/pull/4248))\n\n  ```toml\n  [tools.duckdb]\n  backends = [\"github:duckdb/duckdb\"]\n  test = [\"duckdb --version\", \"{{version}}\"]\n  ```\n\n- **Biome**: Multiple backends ([#4283](https://github.com/jdx/mise/pull/4283))\n\n  ```toml\n  [tools.biome]\n  backends = [\"aqua:biomejs/biome\", \"github:biomejs/biome\"]\n  test = [\"biome --version\", \"Version: {{version}}\"]\n  ```\n\n## Adding Backends\n\n:::warning Backend vs Tool Confusion\n**Most contributors want to add tools, not backends.** Before reading this\nsection, make sure you actually need a new backend. Tools are individual\nsoftware packages (like `node` or `ripgrep`), while backends are installation\nmechanisms (like `aqua` or `github`). If you want to add a specific tool to mise,\nsee [Adding Tools](#adding-tools) instead.\n:::\n\n:::warning Core Backend Acceptance Policy\n**New backends are unlikely to be accepted into mise core.** They require\na lot of maintenance so it's generally better to use the [backend plugin system](backend-plugin-development.md) to add backends without core changes. A new backend would only be accepted for a major package manager\nor tool that would greatly enhance mise's capabilities.\n\nIf you need a custom backend:\n\n1. **Discuss with jdx first** in [Discord](https://discord.gg/UBa7pJUN7Z) or by\n   creating a [discussion](https://github.com/jdx/mise/discussions)\n2. **Consider if existing backends** (github, aqua, npm, pipx, etc.) can meet your\n   needs\n3. **Create a plugin** - use the [plugin system](tool-plugin-development.md) to create plugins for private/custom tools without core changes. Start with the [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template) for a quick setup\n\nMost tool installation needs can be met by existing backends, especially\n[github](dev-tools/backends/github.md) for GitHub releases and\n[aqua](dev-tools/backends/aqua.md) for comprehensive package management.\n:::\n\nBackends are mise's abstraction for different tool installation methods. Each\nbackend implements the `Backend` trait to provide consistent functionality\nacross different installation systems.\n\n### Backend Types\n\n- **Core Backends** (`src/backend/core/`) - Built-in language runtimes like\n  Node.js, Python, Ruby\n- **Package Manager Backends** (`src/backend/`) - npm, pipx, cargo, gem, go\n  modules\n- **Universal Installers** (`src/backend/`) - github, aqua for GitHub releases and\n  package management\n- **Plugin Backends** (`src/backend/`) - plugins can provide custom backends or individual tools\n\n### Implementation Steps\n\n1. **Create the backend module** in `src/backend/` (e.g., `my_backend.rs`)\n\n2. **Implement the Backend trait**:\n\n   ```rust\n   use crate::backend::{Backend, BackendType};\n   use crate::install_context::InstallContext;\n\n   #[derive(Debug)]\n   pub struct MyBackend {\n       // backend-specific fields\n   }\n\n   impl Backend for MyBackend {\n       fn get_type(&self) -> BackendType { BackendType::MyBackend }\n\n       async fn list_remote_versions(&self) -> Result<Vec<String>> {\n           // Implementation for listing available versions\n       }\n\n       async fn install_version(&self, ctx: &InstallContext,\n                                 tv: &ToolVersion) -> Result<()> {\n           // Implementation for installing a specific version\n       }\n\n       async fn uninstall_version(&self, tv: &ToolVersion) -> Result<()> {\n           // Implementation for uninstalling a version\n       }\n\n       // ... other required methods\n   }\n   ```\n\n3. **Register the backend** in `src/backend/mod.rs`:\n\n   - Add your backend to the imports\n   - Add it to the backend registry/factory function\n   - Add the `BackendType` enum variant\n\n4. **Add CLI argument parsing** in `src/cli/args/backend_arg.rs` if needed\n\n5. **Update the registry** in `registry/` if it should be available as a\n   shorthand\n\n### Testing Requirements\n\n- **Integration tests** in `e2e/backend/test_my_backend`\n- **Test both installation and usage** of tools from your backend\n- **Windows testing** if the backend supports Windows\n\n### Documentation\n\n- **Update backend documentation** in `docs/dev-tools/backends/`\n- **Add usage examples** showing how to install tools with your backend\n- **Update the registry documentation** if adding new shorthand tools\n\n### Implementation Examples\n\nLook at existing backends for patterns:\n\n- `src/backend/github.rs` - Simple GitHub release installer\n- `src/backend/npm.rs` - Package manager integration\n- `src/backend/core/node.rs` - Full language runtime implementation\n\nFor detailed architecture information, see\n[Backend Architecture](dev-tools/backend_architecture.md).\n\n## Testing packaging\n\nThis is only necessary to test if actually changing the packaging setup.\n\n### Ubuntu (apt)\n\nThis is for arm64, but you can change the arch to amd64 if you want.\n\n```sh\ndocker run -ti --rm ubuntu\napt update -y\napt install -y curl\ninstall -dm 755 /etc/apt/keyrings\ncurl -fSso /etc/apt/keyrings/mise-archive-keyring.pub https://mise.jdx.dev/gpg-key.pub\necho \"deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.pub arch=arm64] \\\nhttps://mise.jdx.dev/deb stable main\" >/etc/apt/sources.list.d/mise.list\napt update -y\napt install -y mise\nmise -V\n```\n\n### Fedora (dnf)\n\n```sh\ndocker run -ti --rm fedora\ndnf copr enable -y jdxcode/mise && dnf install -y mise && mise -v\n```\n\n### RHEL (dnf)\n\n```sh\ndocker run -ti --rm registry.access.redhat.com/ubi9/ubi:latest\ndnf copr enable -y jdxcode/mise && dnf install -y mise && mise -v\n```\n"
  },
  {
    "path": "docs/core-tools.md",
    "content": "# Core Tools\n\n`mise` comes with some plugins built into the CLI written in Rust. These are new and will improve over\ntime.\n\nThey can be easily overridden by installing an asdf/vfox plugin with the same name, e.g.: `mise plugin install python https://github.com/asdf-community/asdf-python`.\n\nYou can see the core plugins with `mise registry -b core`.\n\n- [Bun](/lang/bun)\n- [Deno](/lang/deno)\n- [Elixir](/lang/elixir)\n- [Erlang](/lang/erlang)\n- [Go](/lang/go)\n- [Java](/lang/java)\n- [NodeJS](/lang/node)\n- [Python](/lang/python)\n- [Ruby](/lang/ruby)\n- [Rust](/lang/rust)\n- [Swift](/lang/swift) <Badge type=\"warning\" text=\"experimental\" />\n- [Zig](/lang/zig)\n"
  },
  {
    "path": "docs/demo.md",
    "content": "# Demo\n\nThe following demo shows:\n\n- how to use `mise exec` to run a command with a specific version of a tool\n- how you can use `mise` to install many other tools such as `jq`, `terraform`, or `go`.\n- how to use `mise` to manage multiple versions of `node` on the same system.\n\n<video style=\"max-width: 100%; height: auto;\" controls=\"controls\" src=\"./tapes/demo.mp4\" />\n\n## Transcript\n\n`mise exec <tool> -- <command>` allows you to run any tools with mise\n\n```shell\nmise exec node@24 -- node -v\n# mise node@24.x.x ✓ installed\n# v24.x.x\n```\n\nnode is only available in the mise environment, not globally\n\n```shell\nnode -v\n# bash: node: command not found\n```\n\n---\n\nHere is another example where we run terraform with `mise exec`\n\n```shell\nmise exec terraform -- terraform -v\n# mise terraform@1.11.3 ✓ installed\n# Terraform v1.11.3\n```\n\n---\n\n`mise exec` is great for running one-off commands, however it can be convenient to activate mise. When activated, mise will automatically update your `PATH` to include the tools you have installed, making them available directly.\n\nWe will start by installing node@lts and make it the global default\n\n```shell\nmise use --global node@lts\n# v22.14.0\n```\n\n```shell\nnode -v\n# v22.14.0\n```\n\n```shell\nwhich node\n# /root/.local/share/mise/installs/node/22.14.0/bin/node\n```\n\nNote that we get back the path to the real node here, not a shim.\n\n---\n\nWe can also install other tools with mise. For example, we will install terraform, jq, and go\n\n```shell\nmise use -g terraform jq go\n# mise jq@1.7.1 ✓ installed\n# mise terraform@1.11.3 ✓ installed\n# mise go@1.24.1 ✓ installed\n# mise ~/.config/mise/config.toml tools: go@1.24.1, jq@1.7.1, terraform@1.11.3\n```\n\n```shell\nterraform -v\n# Terraform v1.11.3\n```\n\n```shell\njq --version\n# jq-1.7\n```\n\n```shell\ngo version\n# go version go1.24.1 linux/amd64\n```\n\n```shell\nmise ls\n# Tool       Version  Source                      Requested\n# go         1.24.1   ~/.config/mise/config.toml  latest\n# jq         1.7.1    ~/.config/mise/config.toml  latest\n# node       22.14.0  ~/.config/mise/config.toml  lts\n# terraform  1.11.3   ~/.config/mise/config.toml  latest\n```\n\n---\n\nLet's enter a project directory where we will set up node@23\n\n```shell\ncd myproj\nmise use node@23 pnpm@10\n# mise node@23.10.0 ✓ installed\n# mise pnpm@10.7.0 ✓ installed\n```\n\n```shell\nnode -v\n# v23.10.0\npnpm -v\n# 10.7.0\n```\n\nAs expected, `node -v` is now v23.x\n\n```shell\ncat mise.toml\n# [tools]\n# node = \"23\"\n# pnpm = \"10\"\n```\n\nWe will leave this directory. The node version will revert to the global LTS version\n\n```shell\ncd ..\nnode -v\n# v22.14.0\n```\n"
  },
  {
    "path": "docs/dev-tools/aliases.md",
    "content": "# Tool Aliases\n\n::: tip\n`[alias]` has been renamed to `[tool_alias]` to distinguish it from `[shell_alias]`.\nThe old `[alias]` key still works but is deprecated.\n\nFor shell command aliases (like `alias ll='ls -la'`), see [Shell Aliases](/shell-aliases).\n:::\n\n## Aliased Backends\n\nTools can be aliased so that something like `node` which normally maps to `core:node` can be changed\nto something like `asdf:company/our-custom-node` instead.\n\n```toml [~/.config/mise/config.toml]\n[tool_alias]\nnode = 'asdf:company/our-custom-node' # shorthand for https://github.com/company/our-custom-node\nerlang = 'asdf:https://github.com/company/our-custom-erlang'\n```\n\n## Aliased Versions\n\nmise supports aliasing the versions of runtimes. One use-case for this is to define aliases for LTS\nversions of runtimes. For example, you may want to specify `lts-hydrogen` as the version for <node@20.x>\nso you can use set it with `node lts-hydrogen` in `mise.toml`/`.tool-versions`.\n\nUser aliases can be created by adding a `tool_alias.<PLUGIN>` section to `~/.config/mise/config.toml`:\n\n```toml\n[tool_alias.node.versions]\nmy_custom_20 = '20'\n```\n\nPlugins can also provide aliases via a `bin/list-aliases` script. Here is an example showing node.js\nversions:\n\n```bash\n#!/usr/bin/env bash\n\necho \"lts-hydrogen 18\"\necho \"lts-gallium 16\"\necho \"lts-fermium 14\"\n```\n\n::: info\nBecause this is mise-specific functionality not currently used by asdf it isn't likely to be in any\nplugin currently, but plugin authors can add this script without impacting asdf users.\n:::\n\n## Templates\n\nAlias values can be templates, see [Templates](/templates) for details.\n\n```toml\n[tool_alias.node.versions]\ncurrent = \"{{exec(command='node --version')}}\"\n```\n"
  },
  {
    "path": "docs/dev-tools/backend_architecture.md",
    "content": "# Backend Architecture\n\nUnderstanding how mise's backend system works can help you choose the right backend for your tools and troubleshoot issues when they arise. Most users don't need to explicitly choose backends since the [mise registry](../registry.md) defines smart defaults, but understanding the system helps when you need specific tools or want to optimize performance.\n\n## What are Backends?\n\nBackends are mise's way of supporting different tool installation methods. Each backend knows how to:\n\n- List available versions of tools\n- Download and install specific versions\n- Set up the environment for installed tools\n- Manage tool lifecycles (updates, uninstalls)\n\nThink of backends as \"adapters\" that let mise work with different package managers and installation systems.\n\n## The Backend Trait System\n\nAll backends implement a common interface (called a \"trait\" in Rust), which means they all provide the same basic functionality:\n\n```rust\npub trait Backend {\n    async fn list_remote_versions(&self) -> Result<Vec<String>>;\n    async fn install_version(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()>;\n    async fn uninstall_version(&self, tv: &ToolVersion) -> Result<()>;\n    // ... other methods\n}\n```\n\nThis design allows mise to treat all backends uniformly while each backend handles the specifics of its installation method.\n\n## Backend Types\n\n### Core Tools\n\nBuilt directly into mise, written in Rust for performance and reliability:\n\n- **Node.js, Python, Ruby, Go, Java, etc.** - Native implementations\n- **Benefits**: Fastest performance, no external dependencies, best integration\n- **Drawbacks**: Require much more maintenance; new core tool contributions are likely to be rejected unless they're for very popular tools like Node.js, Python, or Go\n\n::: info\nCore tools like Node.js and Java are implemented as backends even though they represent single tools. This consistent backend architecture allows mise to handle all tools uniformly, whether they're complex ecosystems or individual tools.\n:::\n\n### Language Package Managers\n\nLeverage existing language ecosystems:\n\n- **npm** - npm packages (`npm:prettier`, `npm:typescript`)\n- **pipx** - Python packages (`pipx:black`, `pipx:poetry`)\n- **cargo** - Rust crates (`cargo:ripgrep`, `cargo:fd-find`)\n- **gem** - Ruby gems (`gem:bundler`, `gem:rails`)\n- **go** - Go modules (`go:github.com/golangci/golangci-lint/cmd/golangci-lint`)\n\n### Universal Installers\n\n#### aqua - Comprehensive Package Manager\n\nRegistry-based package manager with strong security features:\n\n- **Usage**: `aqua:golangci/golangci-lint`\n- **Requirements**: Tools must be available in the [aqua registry](https://github.com/aquaproj/aqua-registry)\n- **Sources**: Primarily GitHub but supports other sources through registry configuration\n- **Security**: Comprehensive checksums, signatures, and verification\n\n#### ubi - Universal Binary Installer (Deprecated)\n\n::: warning\nThe ubi backend is deprecated. Use the [github backend](/dev-tools/backends/github) instead.\n:::\n\nZero-configuration installer that works with any GitHub/GitLab repository following standard conventions:\n\n- **Usage**: `ubi:BurntSushi/ripgrep` → migrate to `github:BurntSushi/ripgrep`\n- **Requirements**: Repository must follow standard release tarball conventions\n- **Sources**: Primarily GitHub releases, with GitLab support (rarely used in mise)\n- **Configuration**: None required - automatically detects and downloads appropriate binaries\n\n### Plugin Systems\n\nSupport for external plugin ecosystems:\n\n- **Tool Plugins** - Hook-based plugins for single tools (`my-tool`) - a superset of vfox plugins functionality\n- **asdf Plugins** - Legacy plugin ecosystem (`asdf:postgres`, `asdf:redis`) - generally Linux/macOS only\n- **Backend Plugins** - Enhanced plugins using the `plugin:tool` format (`my-plugin:some-tool`) - enables private/custom tools with backend methods\n\n## How Backend Selection Works\n\nWhen you specify a tool, mise determines the backend using this priority:\n\n1. **Explicit backend**: `mise use aqua:golangci/golangci-lint`\n2. **Environment variable override**: `MISE_BACKENDS_<TOOL>` (see below)\n3. **Registry lookup**: `mise use golangci-lint` → checks registry for default backend\n4. **Core tools**: `mise use node` → uses built-in core backend\n5. **Fallback**: If not found, suggests available backends\n\nThe [mise registry](../registry.md) defines a priority order for which backend to use for each tool, so typically end-users don't need to know which backend to choose unless they want tools not available in the registry or want to override the default selection.\n\n### Environment Variable Overrides\n\nYou can override the backend for any tool using the `MISE_BACKENDS_<TOOL>` environment variable pattern. The tool name is converted to SHOUTY_SNAKE_CASE (uppercase with underscores replacing hyphens).\n\n```bash\n# Use vfox backend for php\nexport MISE_BACKENDS_PHP='vfox:mise-plugins/vfox-php'\nmise install php@latest\n```\n\n### Registry System\n\nThe [registry](../registry.md) (`mise registry`) maps short names to full backend specifications with a preferred priority order:\n\n```toml\n# ~/.config/mise/config.toml\n[tool_alias]\ngo = \"core:go\"                    # Use core backend\nterraform = \"aqua:hashicorp/terraform\"  # Use aqua backend\n```\n\n## Backend Capabilities Comparison\n\n| Feature                   | Core | npm/pipx/cargo | aqua | ubi | Backend Plugins | Tool Plugins (vfox) | asdf Plugins (legacy) |\n| ------------------------- | ---- | -------------- | ---- | --- | --------------- | ------------------- | --------------------- |\n| **Speed**                 | ✅   | ⚠️             | ✅   | ✅  | ⚠️              | ⚠️                  | ⚠️                    |\n| **Security**              | ✅   | ⚠️             | ✅   | ⚠️  | ⚠️              | ⚠️                  | ⚠️                    |\n| **Windows Support**       | ✅   | ✅             | ✅   | ✅  | ✅              | ✅                  | ❌                    |\n| **Env Var Support**       | ✅   | ❌             | ❌   | ❌  | ✅              | ✅                  | ✅                    |\n| **Custom Scripts**        | ✅   | ❌             | ❌   | ❌  | ✅              | ✅                  | ✅                    |\n| **Built-in Modules**      | ✅   | ❌             | ❌   | ❌  | ✅              | ✅                  | ❌                    |\n| **Security Attestations** | ❌   | ❌             | ✅   | ❌  | ✅              | ✅                  | ❌                    |\n| **Multi-tool Plugins**    | ❌   | ❌             | ❌   | ❌  | ✅              | ❌                  | ❌                    |\n| **Progress/Logging**      | ✅   | ✅             | ✅   | ✅  | ✅              | ✅                  | ❌                    |\n\n## When to Use Each Backend\n\n### Use **Core Tools** when\n\n- Available for your tool (check the [registry](../registry.md))\n- You want the fastest performance\n- You're using major programming languages\n\nCore tools should generally always be used when available, as they provide the best performance and integration with mise.\n\n### Use **Language Package Managers** when\n\n- Installing tools specific to that language ecosystem\n- The tool is primarily distributed through that package manager\n- You want automatic dependency management\n\n### Use **aqua** when\n\n- Installing pre-compiled binaries or static packages (no compilation needed)\n- You want comprehensive security features (checksums, signatures)\n- You need Windows support\n- The tool is already available in the [aqua registry](https://github.com/aquaproj/aqua-registry)\n- You're willing to contribute tools to the aqua registry for tools not yet available\n\n### Use **github** when\n\n- Installing pre-compiled binaries from GitHub releases\n- The repository follows standard conventions for release tarballs\n- You want zero configuration - no registry setup required\n- You need simple, fast binary installation\n- The tool doesn't require complex build processes or environment setup\n\n::: info\nThe `ubi` backend still works but is deprecated in favor of `github`. Replace `ubi:owner/repo` with `github:owner/repo`.\n:::\n\n### Use **Backend Plugins** when\n\n- You need to manage multiple tools with one plugin\n- Want enhanced backend methods for better performance\n- Need the `plugin:tool` format for flexibility\n- Working with custom or private tools\n- Want modern plugin architecture with backend methods\n\n### Use **Tool Plugins** when\n\n- Creating traditional single-tool plugins\n- Need fine-grained control over installation hooks\n- Want to use the vfox hook system\n- Tool requires complex installation logic or build processes\n- Tool requires environment variable setup (like `JAVA_HOME`, `GOROOT`, etc.)\n- You need cross-platform support including Windows\n\n### Use **asdf Plugins** when\n\n- Tool requires compilation from source\n- Need complex installation logic or build processes\n- Tool requires environment variable setup (like `JAVA_HOME`, `GOROOT`, etc.)\n- No other backend supports the tool\n- Migrating from existing asdf setup\n- Working on Linux/macOS (no Windows support)\n\n## Backend Dependencies\n\nSome backends have dependencies on others:\n\n```mermaid\ngraph TD\n    A[npm backend] --> B[Node.js]\n    C[pipx backend] --> D[pipx]\n    E[cargo backend] --> F[Rust]\n    G[gem backend] --> H[Ruby]\n```\n\nmise automatically handles these dependencies, installing Node.js before npm tools, pipx before pipx tools, etc.\n\n## Configuration and Overrides\n\n### Disable Backends\n\n```toml\n# ~/.config/mise/config.toml\n[settings]\ndisable_backends = [\"asdf\", \"vfox\"] # Don't use these backends\n```\n\n### Force Backend for Tool\n\n```toml\n# mise.toml\n[tools]\n\"core:node\" = \"20\"     # Explicitly use core backend\n\"aqua:yarn\" = \"latest\" # Use aqua backend instead of default (vfox)\n```\n\n### Backend-Specific Settings\n\nSome backends support additional configuration:\n\n```toml\n# mise.toml\n[tools]\npython = { version = \"3.12\", virtualenv = \".venv\" }  # Core backend options\nblack = { version = \"latest\", python = \"3.12\" }      # pipx backend options\n```\n\n## Troubleshooting Backend Issues\n\n### Debug Backend Selection\n\n```bash\nmise doctor                   # Check backend configuration\nmise tool python              # See which backend is used for a tool\nmise config get tools         # Verify tool configurations\n```\n"
  },
  {
    "path": "docs/dev-tools/backends/aqua.md",
    "content": "# Aqua Backend\n\n[Aqua](https://aquaproj.github.io/) tools may be used natively in mise. aqua is the ideal backend\nto use for new tools since they don't require plugins, they work on windows, they offer security\nfeatures in addition to checksums. aqua installs also show more progress bars, which is nice.\n\nYou do not need to separately install aqua. The aqua CLI is not used in mise at all. What is used is\nthe [aqua registry](https://github.com/aquaproj/aqua-registry) which is a bunch of yaml files that get compiled into the mise binary on release.\nHere's an example of one of these files: [`aqua:hashicorp/terraform`](https://github.com/aquaproj/aqua-registry/blob/main/pkgs/hashicorp/terraform/registry.yaml).\nmise has a reimplementation of aqua that knows how to work with these files to install tools.\n\nAs of this writing, aqua is relatively new to mise and because a lot of tools are being converted from\nasdf to aqua, there may be some configuration in aqua tools that need to be tightened up. I put some\ncommon issues below and would strongly recommend contributing changes back to the aqua registry if you\nnotice problems. The maintainer is super responsive and great to work with.\n\nIf all else fails, you can disable aqua entirely with [`MISE_DISABLE_BACKENDS=aqua`](/configuration/settings.html#disable_backends).\n\nCurrently aqua tools don't support setting environment variables or doing more than simply downloading\nbinaries though (and I'm not sure this functionality would ever get added), so some tools will likely\nalways require plugins like asdf/vfox.\n\nThe code for this is inside the mise repository at [`./src/backend/aqua.rs`](https://github.com/jdx/mise/blob/main/src/backend/aqua.rs).\n\n## Usage\n\nThe following installs the latest version of ripgrep and sets it as the active version on PATH:\n\n```sh\n$ mise use -g aqua:BurntSushi/ripgrep\n$ rg --version\nripgrep 14.1.1\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"aqua:BurntSushi/ripgrep\" = \"latest\"\n```\n\nSome tools will default to use aqua if they're specified in [registry/](https://github.com/jdx/mise/blob/main/registry/)\nto use the aqua backend. To see these tools, run `mise registry | grep aqua:`.\n\n## Tool Options\n\n### `symlink_bins`\n\nSome tools bundle extra executables that you may not want exposed on PATH. For example, `aws-cli` bundles\nPython, which can conflict with your intended Python version.\n\nSetting `symlink_bins = true` creates a filtered `.mise-bins` directory and exposes only the binaries mise\nintends to expose for that Aqua package, instead of every discovered executable from the install.\n\n```toml\n[tools]\naws-cli = { version = \"latest\", symlink_bins = true }\n```\n\nWhen enabled:\n\n- If the aqua registry defines a `files` field, only those binaries are exposed (e.g., `aws` and `aws_completer` for aws-cli)\n- Otherwise, mise falls back to exposing the inferred primary binary for the package\n- A `.mise-bins` subdirectory is created with symlinks to the exposed binaries\n- Bundled dependencies and other extra executables, such as Python in `aws-cli`, are not added to PATH\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"aqua\" :level=\"3\" />\n\n## Security Verification\n\nAqua backend supports multiple security verification methods to ensure the integrity and authenticity of downloaded tools. mise provides **native Rust implementation** for all verification methods, eliminating the need for external CLI tools like `cosign`, `slsa-verifier`, or `gh`.\n\n### GitHub Artifact Attestations\n\nGitHub Artifact Attestations provide cryptographic proof that artifacts were built by specific GitHub Actions workflows. mise verifies these attestations natively to ensure the authenticity and integrity of downloaded tools.\n\n**Requirements:**\n\n- The tool must have `github_artifact_attestations` configuration in the aqua registry for attestations to be verified\n- No external tools required - verification is handled natively by mise\n\n**Configuration:**\n\n```bash\n# Enable/disable GitHub artifact attestations verification (default: true)\nexport MISE_AQUA_GITHUB_ATTESTATIONS=true\n```\n\n**Registry Configuration Example:**\n\n```yaml\npackages:\n  - type: github_release\n    repo_owner: cli\n    repo_name: cli\n    github_artifact_attestations:\n      signer_workflow: cli/cli/.github/workflows/deployment.yml\n```\n\n### Cosign Verification\n\nmise natively verifies Cosign signatures without requiring the `cosign` CLI tool to be installed.\n\n**Configuration:**\n\n```bash\n# Enable/disable Cosign verification (default: true)\nexport MISE_AQUA_COSIGN=true\n\n# Pass extra arguments to the verification process\nexport MISE_AQUA_COSIGN_EXTRA_ARGS=\"--key /path/to/key.pub\"\n```\n\n### SLSA Provenance Verification\n\nmise natively verifies SLSA (Supply-chain Levels for Software Artifacts) provenance without requiring the `slsa-verifier` CLI tool.\n\n**Configuration:**\n\n```bash\n# Enable/disable SLSA verification (default: true)\nexport MISE_AQUA_SLSA=true\n```\n\n### Other Security Methods\n\nAqua also supports:\n\n- **Minisign verification**: Uses minisign for signature verification\n- **Checksum verification**: Verifies SHA256/SHA512/SHA1/MD5 checksums (always enabled)\n\n### Verification Process\n\nDuring tool installation, mise will:\n\n1. Download the tool and any signature/attestation files\n2. Perform native verification using the configured methods\n3. Display verification status with progress indicators\n4. Abort installation if any verification fails\n\n**Example output during installation:**\n\n```\n✓ Downloaded cli/cli v2.50.0\n✓ GitHub artifact attestations verified\n✓ Tool installed successfully\n```\n\n### Troubleshooting\n\nIf verification fails:\n\n1. **Check network connectivity**: Verification requires downloading attestation data\n2. **Verify tool configuration**: Ensure the aqua registry has correct verification settings\n3. **Disable specific verification**: Temporarily disable problematic verification methods\n4. **Enable debug logging**: Use `MISE_DEBUG=1` to see detailed verification logs\n\n**Common issues:**\n\n- **No attestations found**: The tool may not have attestations configured in the registry\n- **Verification timeout**: Network issues or slow attestation services\n- **Certificate validation**: Clock skew or certificate chain issues\n\nTo disable all verification temporarily:\n\n```bash\nexport MISE_AQUA_GITHUB_ATTESTATIONS=false\nexport MISE_AQUA_COSIGN=false\nexport MISE_AQUA_SLSA=false\nexport MISE_AQUA_MINISIGN=false\n```\n\n## Common aqua issues\n\nHere's some common issues I've seen when working with aqua tools.\n\n### Supported env missing\n\nThe aqua registry defines supported envs for each tool of the os/arch. I've noticed some of these\nare simply missing os/arch combos that are in fact supported—possibly because it was added after\nthe registry was created for that tool.\n\nThe fix is simple, just edit the `supported_envs` section of `registry.yaml` for the tool in question.\n\n### Using `version_filter` instead of `version_prefix`\n\nThis is a weird one that causes weird issues in mise. In general in mise we like versions like\n`1.2.3` with no decoration like `v1.2.3` or `cli-v1.2.3`. This consistency not only makes `mise.toml`\ncleaner but, it also helps make things like `mise up` function right because it's able to parse it as\nsemver without dealing with a bunch of edge-cases.\n\nReally if you notice aqua tools are giving you versions that aren't simple triplets, it's worth fixing.\n\nOne common thing I've seen is registries using a `version_filter` expression like `Version startsWith \"Version startsWith \"atlascli/\"\"`.\n\nThis ultimately causes the version to be `atlascli/1.2.3` which is not what we want. The fix is to use\n`version_prefix` instead of `version_filter` and just put the prefix in the `version_prefix` field.\nIn this example, it would be `atlascli/`. mise will automatically strip this out and add it back in,\nwhich it can't do with `version_filter`.\n"
  },
  {
    "path": "docs/dev-tools/backends/asdf.md",
    "content": "# asdf Backend\n\n::: warning\nasdf plugins are considered legacy. For new tools, prefer [vfox plugins](/dev-tools/backends/vfox.html) which are written in Lua, work cross-platform (including Windows), and have access to built-in modules for HTTP, JSON, HTML parsing, and more.\n:::\n\n`asdf` is the original backend for mise.\n\nIt relies on asdf plugins for each tool. asdf plugins are more risky to use because they're typically written by a single developer unrelated to the tool vendor. They also generally do not function on Windows because they're written\nin bash which is often not available on Windows and the scripts generally are not written to be cross-platform.\n\nasdf plugins are not used for tools inside the [registry](https://github.com/jdx/mise/blob/main/registry/) whenever possible. Sometimes it is not possible to use more secure backends like aqua/github because tools have complex install setups or need to export env vars.\n\nAll of these are hosted in the mise-plugins org to secure the supply chain so you do not need to rely on plugins maintained by anyone except me.\n\nBecause of the extra complexity of asdf tools and security concerns we are actively moving tools in\nthe registry away from asdf where possible to backends like aqua and github which don't require plugins.\nThat said, not all tools can function with github/aqua if they have a unique installation process or\nneed to set env vars other than `PATH`.\n\n## Feature Comparison: asdf vs vfox\n\n| Feature                         | asdf Plugins       | vfox Plugins         |\n| ------------------------------- | ------------------ | -------------------- |\n| **Language**                    | Bash scripts       | Lua                  |\n| **Windows Support**             | ❌                 | ✅                   |\n| **Built-in HTTP module**        | ❌ (requires curl) | ✅                   |\n| **Built-in JSON module**        | ❌ (requires jq)   | ✅                   |\n| **Built-in HTML parsing**       | ❌                 | ✅                   |\n| **Built-in archive extraction** | ❌                 | ✅                   |\n| **Built-in semver module**      | ❌                 | ✅                   |\n| **Built-in logging**            | ❌                 | ✅                   |\n| **Post-install hooks**          | ❌                 | ✅                   |\n| **Security attestations**       | ❌                 | ✅ (cosign, SLSA)    |\n| **Multi-tool plugins**          | ❌                 | ✅ (backend plugins) |\n| **Lock file support**           | ❌                 | ✅                   |\n| **Rolling version checksums**   | ❌                 | ✅                   |\n\n## Hook Migration: asdf to vfox\n\n| asdf Script                 | vfox Hook                | Notes                                                            |\n| --------------------------- | ------------------------ | ---------------------------------------------------------------- |\n| `bin/list-all`              | `Available`              | Return structured version objects instead of plain text          |\n| `bin/download`              | `PreInstall`             | Return URL and checksum; mise handles the download               |\n| `bin/install`               | `PostInstall`            | Runs after mise downloads and extracts the tool                  |\n| `bin/exec-env`              | `EnvKeys`                | Return structured key/value pairs instead of `export` statements |\n| `bin/list-legacy-filenames` | `PLUGIN.legacyFilenames` | Set in `metadata.lua` instead of a script                        |\n| `bin/parse-legacy-file`     | `ParseLegacyFile`        | Return structured result instead of plain text                   |\n\n## Writing asdf (legacy) plugins for mise\n\nSee the asdf documentation for more information on [writing plugins](https://asdf-vm.com/plugins/create.html).\n"
  },
  {
    "path": "docs/dev-tools/backends/cargo.md",
    "content": "# Cargo Backend\n\nYou may install packages directly from [Cargo Crates](https://crates.io/) even if there\nisn't an asdf plugin for it.\n\nThe code for this is inside the mise repository at [`./src/backend/cargo.rs`](https://github.com/jdx/mise/blob/main/src/backend/cargo.rs).\n\n## Dependencies\n\nThis relies on having `cargo` installed. You can either install it on your\nsystem via [rustup](https://rustup.rs/):\n\n```sh\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n```\n\nOr you can install it via mise:\n\n```sh\nmise use -g rust\n```\n\n## Usage\n\nThe following installs the latest version of [eza](https://crates.io/crates/eza) and\nsets it as the active version on PATH:\n\n```sh\n$ mise use -g cargo:eza\n$ eza --version\neza - A modern, maintained replacement for ls\nv0.17.1 [+git]\nhttps://github.com/eza-community/eza\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"cargo:eza\" = \"latest\"\n```\n\n### Using Git\n\nYou can install any package from a Git repository using the `mise` command. This allows you to\ninstall a particular tag, branch, or commit revision:\n\n```sh\n# Install a specific tag\nmise use cargo:https://github.com/username/demo@tag:<release_tag>\n\n# Install the latest from a branch\nmise use cargo:https://github.com/username/demo@branch:<branch_name>\n\n# Install a specific commit revision\nmise use cargo:https://github.com/username/demo@rev:<commit_hash>\n```\n\nThis will execute a `cargo install` command with the corresponding Git options.\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"cargo\" :level=\"3\" />\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `cargo` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `features`\n\nInstall additional components (passed as `cargo install --features`):\n\n```toml\n[tools]\n\"cargo:cargo-edit\" = { version = \"latest\", features = \"add\" }\n```\n\n### `default-features`\n\nDisable default features (passed as `cargo install --no-default-features`):\n\n```toml\n[tools]\n\"cargo:cargo-edit\" = { version = \"latest\", default-features = false }\n```\n\n### `bin`\n\nSelect the CLI bin name to install when multiple are available (passed as `cargo install --bin`):\n\n```toml\n[tools]\n\"cargo:https://github.com/username/demo\" = { version = \"tag:v1.0.0\", bin = \"demo\" }\n```\n\n### `crate`\n\nSelect the crate name to install when multiple are available (passed as\n`cargo install --git=<repo> <crate>`):\n\n```toml\n[tools]\n\"cargo:https://github.com/username/demo\" = { version = \"tag:v1.0.0\", crate = \"demo\" }\n```\n\n### `locked`\n\nUse Cargo.lock (passes `cargo install --locked`) when building CLI. This is the default behavior,\npass `false` to disable:\n\n```toml\n[tools]\n\"cargo:https://github.com/username/demo\" = { version = \"latest\", locked = false }\n```\n"
  },
  {
    "path": "docs/dev-tools/backends/conda.md",
    "content": "# Conda Backend <Badge type=\"warning\" text=\"experimental\" />\n\nYou may install packages directly from [conda-forge](https://conda-forge.org/) and other\nAnaconda channels without needing conda or mamba installed.\n\nThis backend fetches pre-built packages from the anaconda.org API and extracts them directly,\nmaking it a lightweight way to install conda packages as standalone CLI tools.\n\nThe code for this is inside the mise repository at [`./src/backend/conda.rs`](https://github.com/jdx/mise/blob/main/src/backend/conda.rs).\n\n## Dependencies\n\nNone. Unlike other conda tools, this backend does not require conda, mamba, or micromamba\nto be installed. It downloads and extracts packages directly from anaconda.org.\n\n## Usage\n\nThe following installs the latest version of [ruff](https://anaconda.org/conda-forge/ruff)\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g conda:ruff\n$ ruff --version\nruff 0.8.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"conda:ruff\" = \"latest\"\n```\n\n### Specifying a Version\n\n```sh\nmise use -g conda:ruff@0.7.0\n```\n\n### Using a Different Channel\n\nBy default, packages are installed from `conda-forge`. You can specify a different channel:\n\n```sh\nmise use -g \"conda:ruff[channel=bioconda]\"\n```\n\nOr in `mise.toml`:\n\n```toml\n[tools]\n\"conda:ruff\" = { version = \"latest\", channel = \"bioconda\" }\n```\n\n## Platform Support\n\nThe conda backend automatically selects the appropriate package for your platform:\n\n| Platform    | Conda Subdir  |\n| ----------- | ------------- |\n| Linux x64   | linux-64      |\n| Linux ARM64 | linux-aarch64 |\n| macOS x64   | osx-64        |\n| macOS ARM64 | osx-arm64     |\n| Windows x64 | win-64        |\n\nIf a platform-specific package is not available, the backend will fall back to `noarch` packages.\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"conda\" :level=\"3\" />\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `conda` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `channel`\n\nOverride the conda channel for a specific package:\n\n```toml\n[tools]\n\"conda:bioconductor-deseq2\" = { version = \"latest\", channel = \"bioconda\" }\n```\n\n## Common Channels\n\n- `conda-forge` - Community-maintained packages (default)\n- `bioconda` - Bioinformatics packages\n- `nvidia` - NVIDIA CUDA packages\n\n## Limitations\n\n- Only installs single packages, not full conda environments with dependencies\n- Best suited for standalone CLI tools that don't require complex dependency trees\n- Does not manage Python environments or package dependencies like full conda/mamba\n"
  },
  {
    "path": "docs/dev-tools/backends/dotnet.md",
    "content": "# Dotnet backend\n\nThe code for this is inside the mise repository at [`./src/backend/dotnet.rs`](https://github.com/jdx/mise/blob/main/src/backend/dotnet.rs).\n\n::: tip Important\nThe dotnet backend requires having the .NET runtime installed. You can install it using mise:\n\n```sh\n# Install the latest version\nmise use dotnet\n\n# Or install a specific version (8, 9, etc.)\nmise use dotnet@8\nmise use dotnet@9\n```\n\nThis will install the .NET runtime, which is required for dotnet tools to work properly.\n:::\n\n## Usage\n\nThe following installs the latest version of [GitVersion.Tool](https://gitversion.net/) and\nsets it as the active version on PATH:\n\n```sh\n$ mise use dotnet:GitVersion.Tool@5.12.0\n$ dotnet-gitversion /version\n5.12.0+Branch.support-5.x.Sha.3f75764963eb3d7956dcd5a40488c074dd9faf9e\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"dotnet:GitVersion.Tool\" = \"5.12.0\"\n```\n\n```sh\n$ mise use dotnet:GitVersion.Tool\n$ dotnet-gitversion /version\n6.1.0+Branch.main.Sha.8856e3041dbb768118a55a31ad4e465ae70c6767\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"dotnet:GitVersion.Tool\" = \"latest\"\n```\n\n### Supported Dotnet Syntax\n\n| Description                           | Usage                           |\n| ------------------------------------- | ------------------------------- |\n| Dotnet shorthand latest version       | `dotnet:GitVersion.Tool`        |\n| Dotnet shorthand for specific version | `dotnet:GitVersion.Tool@5.12.0` |\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"dotnet\" :level=\"3\" />\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `dotnet` backend—these\ngo in `[tools]` in `mise.toml`.\n"
  },
  {
    "path": "docs/dev-tools/backends/forgejo.md",
    "content": "# Forgejo Backend\n\nYou may install Codeberg and other Forgejo compatible release assets directly using the `forgejo` backend. This backend downloads release assets from Forgejo repositories and is ideal for tools that distribute pre-built binaries through Forgejo releases.\n\nBy default, the Forgejo backend uses the public Codeberg instance at [https://codeberg.org](https://codeberg.org). For other or self-hosted Forgejo instances, you can specify a custom API URL using the `api_url` tool option.\n\nThe code for this is inside of the mise repository at [`./src/backend/forgejo.rs`](https://github.com/jdx/mise/blob/main/src/backend/forgejo.rs).\n\n## Usage\n\nThe following installs the latest version of a tool from Forgejo releases\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g forgejo:forgejo/runner[api_url=https://code.forgejo.org/api/v1,bin=forgejo-runner,bin=forgejo-runner]\n$ forgejo-runner -v\nforgejo-runner version v12.4.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"forgejo:forgejo/runner\" = {\n  version = \"latest\",\n  api_url = \"https://code.forgejo.org/api/v1\",\n  bin = \"forgejo-runner\",\n}\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `forgejo` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### Asset Autodetection\n\nWhen no `asset_pattern` is specified, mise automatically selects the best asset for your platform. The system scores assets based on:\n\n- **OS compatibility** (linux, macos, windows)\n- **Architecture compatibility** (x64, arm64, x86, arm)\n- **Libc variant** (gnu or musl for Linux, msvc for Windows)\n- **Archive format preference** (tar.gz, zip, etc.)\n- **Build type** (avoids debug/test builds)\n\nFor most tools, you can simply install without specifying patterns:\n\n```sh\nmise install forgejo:user/repo\n```\n\n::: tip\nThe autodetection logic is implemented in [`src/backend/asset_detector.rs`](https://github.com/jdx/mise/blob/main/src/backend/asset_detector.rs), which is shared by the Forgejo, GitHub and GitLab backends.\n:::\n\n### `asset_pattern`\n\nSpecifies the pattern to match against release asset names. This is useful when there are multiple assets for your OS/arch combination or when you need to override autodetection.\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", asset_pattern = \"tool_*_linux_x64.tar.gz\" }\n```\n\n### `version_prefix`\n\nSpecifies a custom version prefix for release tags. By default, mise handles the common `v` prefix (e.g., `v1.0.0`), but some repositories use different prefixes like `release-`, `version-`, or no prefix at all.\n\nWhen `version_prefix` is configured, mise will:\n\n- Filter available versions with the prefix and strip it\n- Add the prefix when searching for releases\n- Try both prefixed and non-prefixed versions during installation\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", version_prefix = \"release-\" }\n```\n\n**Examples:**\n\n- With `version_prefix = \"release-\"`:\n  - User specifies `1.0.0` → mise searches for `release-1.0.0` tag\n  - Available versions show as `1.0.0` (prefix stripped)\n- With `version_prefix = \"\"` (empty string):\n  - User specifies `1.0.0` → mise searches for `1.0.0` tag (no prefix)\n  - Useful for repositories that don't use any prefix\n\n### Platform-specific Asset Patterns\n\nFor different asset patterns per platform:\n\n```toml\n[tools.\"forgejo:user/repo\"]\nversion = \"latest\"\n\n[tools.\"forgejo:user/repo\".platforms]\nlinux-x64 = { asset_pattern = \"tool_*_linux_x64.tar.gz\" }\nmacos-arm64 = { asset_pattern = \"tool_*_macOS_arm64.tar.gz\" }\n```\n\n### `checksum`\n\nVerify the downloaded file with a checksum:\n\n```toml\n[tools.\"forgejo:owner/repo\"]\nversion = \"1.0.0\"\nasset_pattern = \"tool-1.0.0-x64.tar.gz\"\nchecksum = \"sha256:a1b2c3d4e5f6789...\"\n```\n\n_Instead of specifying the checksum here, you can use [mise.lock](/dev-tools/mise-lock) to manage checksums._\n\n### Platform-specific Checksums\n\n```toml\n[tools.\"forgejo:user/repo\"]\nversion = \"latest\"\n\n[tools.\"forgejo:user/repo\".platforms]\nlinux-x64 = {\n  asset_pattern = \"tool_*_linux_x64.tar.gz\",\n  checksum = \"sha256:a1b2c3d4e5f6789...\",\n}\nmacos-arm64 = {\n  asset_pattern = \"tool_*_macOS_arm64.tar.gz\",\n  checksum = \"sha256:b2c3d4e5f6789...\",\n}\n```\n\n### `size`\n\nVerify the downloaded asset size:\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", size = \"12345678\" }\n```\n\n### `strip_components`\n\nNumber of directory components to strip when extracting archives:\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", strip_components = 1 }\n```\n\n::: info\nIf `strip_components` is not explicitly set, mise will automatically detect when to apply `strip_components = 1`. This happens when the extracted archive contains exactly one directory at the root level and no files. This is common with tools like ripgrep that package their binaries in a versioned directory (e.g., `mytool-14.1.0-x86_64-unknown-linux-musl/mytool`). The auto-detection ensures the binary is placed directly in the install path where mise expects it.\n:::\n\n### `bin`\n\nRename the downloaded binary to a specific name. This is useful when downloading single binaries that have platform-specific names:\n\n```toml\n[tools.\"forgejo:user/repo\"]\nversion = \"2.29.1\"\nbin = \"my-tool\"  # Rename the downloaded binary to my-tool\n```\n\n::: info\nWhen downloading single binaries (not archives), mise automatically removes OS/arch suffixes from the filename. For example, `docker-compose-linux-x86_64` becomes `docker-compose` automatically. Use the `bin` option only when you need a specific custom name.\n:::\n\n### `rename_exe`\n\nRename the executable after extraction from an archive. This is useful when the archive contains a binary with a platform-specific name that you want to rename:\n\n```toml\n[tools.\"forgejo:user/repo\"]\nversion = \"latest\"\nasset_pattern = \"tool_linux.zip\"\nrename_exe = \"tool\"  # Rename the extracted binary to tool\n```\n\n::: tip\nUse `rename_exe` for archives where the binary inside has a different name than desired. Use `bin` for single binary downloads (non-archives).\n:::\n\n### `bin_path`\n\nSpecify the directory containing binaries within the extracted archive, or where to place the downloaded file. This supports Tera templating with variables like `{{ version }}`, `{{ os }}`, `{{ arch }}`, and arch aliases (`{{ darwin_os }}`, `{{ amd64_arch }}`, `{{ x86_64_arch }}`, `{{ gnu_arch }}`):\n\n```toml\n[tools.\"forgejo:user/repo\"]\nversion = \"latest\"\nbin_path = \"tool-{{ version }}/bin\" # expands to tool-1.0.0/bin\n```\n\n**Binary path lookup order:**\n\n1. If `bin_path` is specified, use that directory\n2. If `bin_path` is not set, look for a `bin/` directory in the install path\n3. If the install path root contains an executable file, use the install path root\n4. If no `bin/` directory exists, search subdirectories for `bin/` directories\n5. If no `bin/` directories are found, searches immediate subdirectories for any executable files. If an executable is found directly within a subdirectory, that entire subdirectory is considered a binary path.\n6. If no executables are found, use the root of the extracted directory\n\n### `filter_bins`\n\nComma-separated list of binaries to symlink into a filtered `.mise-bins` directory. This is useful when the tool comes with extra binaries that you do not want to expose on PATH.\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", filter_bins = \"tool\" }\n```\n\nWhen enabled:\n\n- A `.mise-bins` subdirectory is created with symlinks only to the specified binaries\n- Other binaries (like `tool-helper` or `tool-server`) are not exposed on PATH\n\n### `api_url`\n\nFor other Forgejo compatible or self-hosted instances, specify the API URL:\n\n```toml\n[tools]\n\"forgejo:user/repo\" = { version = \"latest\", api_url = \"https://forgejo.mycompany.com/api/v1\" }\n```\n\n## Self-hosted Forgejo\n\nIf you are using a self-hosted Forgejo instance, set the `api_url` tool option and optionally the `MISE_FORGEJO_ENTERPRISE_TOKEN` environment variable for authentication:\n\n```sh\nexport MISE_FORGEJO_ENTERPRISE_TOKEN=\"your-token\"\n```\n\n## Supported Forgejo Syntax\n\n- **Forgejo shorthand for latest release version:** `forgejo:user/repo`\n- **Forgejo shorthand for specific release version:** `forgejo:user/repo@2.40.1`\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"forgejo\" :level=\"3\" />\n"
  },
  {
    "path": "docs/dev-tools/backends/gem.md",
    "content": "# gem Backend\n\nmise can be used to install CLIs from RubyGems. The code for this is inside of the mise repository at [`./src/backend/gem.rs`](https://github.com/jdx/mise/blob/main/src/backend/gem.rs).\n\n## Dependencies\n\nThis relies on having `gem` (provided with ruby) installed. You can install it with or without mise.\nHere is how to install `ruby` with mise:\n\n```sh\nmise use -g ruby\n```\n\n## Usage\n\nThe following installs the latest version of [rubocop](https://rubygems.org/gems/rubocop) and sets it as the active version on PATH:\n\n```sh\nmise use -g gem:rubocop\nrubocop --version\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"gem:rubocop\" = \"latest\"\n```\n\n## Ruby upgrades\n\nIf the ruby version used by a gem package changes, (by mise or system ruby), you may need to\nreinstall the gem. This can be done with:\n\n```sh\nmise install -f gem:rubocop\n```\n\nOr you can reinstall all gems with:\n\n```sh\nmise install -f \"gem:*\"\n```\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"gem\" :level=\"3\" />\n"
  },
  {
    "path": "docs/dev-tools/backends/github.md",
    "content": "# GitHub Backend\n\nYou may install GitHub release assets directly using the `github` backend. This backend downloads release assets from GitHub repositories and is ideal for tools that distribute pre-built binaries through GitHub releases.\n\nThe code for this is inside of the mise repository at [`./src/backend/github.rs`](https://github.com/jdx/mise/blob/main/src/backend/github.rs).\n\n## Usage\n\nThe following installs the latest version of ripgrep from GitHub releases\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g github:BurntSushi/ripgrep\n$ rg --version\nripgrep 14.1.1\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"github:BurntSushi/ripgrep\" = \"latest\"\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `github` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### Asset Autodetection\n\nWhen no `asset_pattern` is specified, mise automatically selects the best asset for your platform. The system scores assets based on:\n\n- **OS compatibility** (linux, macos, windows)\n- **Architecture compatibility** (x64, arm64, x86, arm)\n- **Libc variant** (gnu or musl for Linux, msvc for Windows)\n- **Archive format preference** (tar.gz, zip, etc.)\n- **Build type** (avoids debug/test builds)\n\nFor most tools, you can simply install without specifying patterns:\n\n```sh\nmise install github:user/repo\n```\n\n::: tip\nThe autodetection logic is implemented in [`src/backend/asset_matcher.rs`](https://github.com/jdx/mise/blob/main/src/backend/asset_matcher.rs), which is shared by both the GitHub and GitLab backends.\n:::\n\n### `asset_pattern`\n\nSpecifies the pattern to match against release asset names. This is useful when there are multiple assets for your OS/arch combination or when you need to override autodetection.\n\n```toml\n[tools]\n\"github:cli/cli\" = { version = \"latest\", asset_pattern = \"gh_*_linux_x64.tar.gz\" }\n```\n\n### `version_prefix`\n\nSpecifies a custom version prefix for release tags. By default, mise handles the common `v` prefix (e.g., `v1.0.0`), but some repositories use different prefixes like `release-`, `version-`, or no prefix at all.\n\nWhen `version_prefix` is configured, mise will:\n\n- Filter available versions with the prefix and strip it\n- Add the prefix when searching for releases\n- Try both prefixed and non-prefixed versions during installation\n\n```toml\n[tools]\n\"github:user/repo\" = { version = \"latest\", version_prefix = \"release-\" }\n```\n\n**Examples:**\n\n- With `version_prefix = \"release-\"`:\n  - User specifies `1.0.0` → mise searches for `release-1.0.0` tag\n  - Available versions show as `1.0.0` (prefix stripped)\n- With `version_prefix = \"\"` (empty string):\n  - User specifies `1.0.0` → mise searches for `1.0.0` tag (no prefix)\n  - Useful for repositories that don't use any prefix\n\n### Platform-specific Asset Patterns\n\nFor different asset patterns per platform:\n\n```toml\n[tools.\"github:cli/cli\"]\nversion = \"latest\"\n\n[tools.\"github:cli/cli\".platforms]\nlinux-x64 = { asset_pattern = \"gh_*_linux_x64.tar.gz\" }\nmacos-arm64 = { asset_pattern = \"gh_*_macOS_arm64.tar.gz\" }\n```\n\n### `checksum`\n\nVerify the downloaded file with a checksum:\n\n```toml\n[tools.\"github:owner/repo\"]\nversion = \"1.0.0\"\nasset_pattern = \"tool-1.0.0-x64.tar.gz\"\nchecksum = \"sha256:a1b2c3d4e5f6789...\"\n```\n\n_Instead of specifying the checksum here, you can use [mise.lock](/dev-tools/mise-lock) to manage checksums._\n\n### Platform-specific Checksums\n\n```toml\n[tools.\"github:cli/cli\"]\nversion = \"latest\"\n\n[tools.\"github:cli/cli\".platforms]\nlinux-x64 = {\n  asset_pattern = \"gh_*_linux_x64.tar.gz\",\n  checksum = \"sha256:a1b2c3d4e5f6789...\",\n}\nmacos-arm64 = {\n  asset_pattern = \"gh_*_macOS_arm64.tar.gz\",\n  checksum = \"sha256:b2c3d4e5f6789...\",\n}\n```\n\n### `size`\n\nVerify the downloaded asset size:\n\n```toml\n[tools]\n\"github:cli/cli\" = { version = \"latest\", size = \"12345678\" }\n```\n\n### `strip_components`\n\nNumber of directory components to strip when extracting archives:\n\n```toml\n[tools]\n\"github:cli/cli\" = { version = \"latest\", strip_components = 1 }\n```\n\n::: info\nIf `strip_components` is not explicitly set, mise will automatically detect when to apply `strip_components = 1`. This happens when the extracted archive contains exactly one directory at the root level and no files. This is common with tools like ripgrep that package their binaries in a versioned directory (e.g., `ripgrep-14.1.0-x86_64-unknown-linux-musl/rg`). The auto-detection ensures the binary is placed directly in the install path where mise expects it.\n:::\n\n### `bin`\n\nRename the downloaded binary to a specific name. This is useful when downloading single binaries that have platform-specific names:\n\n```toml\n[tools.\"github:docker/compose\"]\nversion = \"2.29.1\"\nbin = \"docker-compose\"  # Rename the downloaded binary to docker-compose\n```\n\n::: info\nWhen downloading single binaries (not archives), mise automatically removes OS/arch suffixes from the filename. For example, `docker-compose-linux-x86_64` becomes `docker-compose` automatically. Use the `bin` option only when you need a specific custom name.\n:::\n\n### `rename_exe`\n\nRename the executable after extraction from an archive. This is useful when the archive contains a binary with a platform-specific name that you want to rename:\n\n```toml\n[tools.\"github:yt-dlp/yt-dlp\"]\nversion = \"latest\"\nasset_pattern = \"yt-dlp_linux.zip\"\nrename_exe = \"yt-dlp\"  # Rename the extracted binary to yt-dlp\n```\n\n::: tip\nUse `rename_exe` for archives where the binary inside has a different name than desired. Use `bin` for single binary downloads (non-archives).\n:::\n\n### `no_app`\n\nSkip macOS .app bundle assets during autodetection and prefer standalone CLI binaries instead. This is useful when a repository provides both a macOS .app bundle (often an Xcode extension or GUI application) and a standalone command-line tool:\n\n```toml\n[tools.\"github:nicklockwood/SwiftFormat\"]\nversion = \"latest\"\nrename_exe = \"swiftformat\"\nno_app = true  # Skip SwiftFormat.for.Xcode.app.zip, use swiftformat.zip instead\n```\n\nWhen `no_app = true`:\n\n- Assets containing `.app.` (e.g., `Tool.app.zip`, `Tool.for.Xcode.app.zip`) are penalized during autodetection\n- Standalone archives (e.g., `tool.zip`, `tool-macos.tar.gz`) are preferred\n- Only affects macOS; has no effect on Linux/Windows\n\n::: info\nWithout this option, mise's autodetection might select .app bundles on macOS, which can be problematic if the bundle contains a GUI application or Xcode extension rather than a standalone CLI tool.\n:::\n\n### `bin_path`\n\nSpecify the directory containing binaries within the extracted archive, or where to place the downloaded file. This supports Tera templating with variables like `{{ version }}`, `{{ os }}`, `{{ arch }}`, and arch aliases (`{{ darwin_os }}`, `{{ amd64_arch }}`, `{{ x86_64_arch }}`, `{{ gnu_arch }}`):\n\n```toml\n[tools.\"github:cli/cli\"]\nversion = \"latest\"\nbin_path = \"cli-{{ version }}/bin\" # expands to cli-1.0.0/bin\n```\n\n**Binary path lookup order:**\n\n1. If `bin_path` is specified, use that directory\n2. If `bin_path` is not set, look for a `bin/` directory in the install path\n3. If the install path root contains an executable file, use the install path root\n4. If no `bin/` directory exists, search subdirectories for `bin/` directories\n5. If no `bin/` directories are found, searches immediate subdirectories for any executable files. If an executable is found directly within a subdirectory, that entire subdirectory is considered a binary path.\n6. If no executables are found, use the root of the extracted directory\n\n### `filter_bins`\n\nComma-separated list of binaries to symlink into a filtered `.mise-bins` directory. This is useful when the tool comes with extra binaries that you do not want to expose on PATH.\n\n```toml\n[tools]\n\"github:jgm/pandoc\" = { version = \"latest\", filter_bins = \"pandoc\" }\n```\n\nWhen enabled:\n\n- A `.mise-bins` subdirectory is created with symlinks only to the specified binaries\n- Other binaries (like `pandoc-lua` or `pandoc-server`) are not exposed on PATH\n\n### `api_url`\n\nFor GitHub Enterprise or self-hosted GitHub instances, specify the API URL:\n\n```toml\n[tools]\n\"github:myorg/mytool\" = { version = \"latest\", api_url = \"https://github.mycompany.com/api/v3\" }\n```\n\n## Self-hosted GitHub\n\nIf you are using a self-hosted GitHub instance, set the `api_url` tool option and optionally the `MISE_GITHUB_ENTERPRISE_TOKEN` environment variable for authentication:\n\n```sh\nexport MISE_GITHUB_ENTERPRISE_TOKEN=\"your-token\"\n```\n\n## Supported GitHub Syntax\n\n- **GitHub shorthand for latest release version:** `github:cli/cli`\n- **GitHub shorthand for specific release version:** `github:cli/cli@2.40.1`\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"github\" :level=\"3\" />\n"
  },
  {
    "path": "docs/dev-tools/backends/gitlab.md",
    "content": "# GitLab Backend\n\nYou may install GitLab release assets directly using the `gitlab` backend. This backend downloads release assets from GitLab repositories and is ideal for tools that distribute pre-built binaries through GitLab releases.\n\nThe code for this is inside of the mise repository at [`./src/backend/github.rs`](https://github.com/jdx/mise/blob/main/src/backend/github.rs).\n\n## Usage\n\nThe following installs the latest version of gitlab-runner from GitLab releases\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g gitlab:gitlab-org/gitlab-runner\n$ gitlab-runner --version\ngitlab-runner 16.8.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"gitlab:gitlab-org/gitlab-runner\" = { version = \"latest\", asset_pattern = \"gitlab-runner-linux-x64\" }\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `gitlab` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### Asset Autodetection\n\nWhen no `asset_pattern` is specified, mise automatically selects the best asset for your platform. The system scores assets based on:\n\n- **OS compatibility** (linux, macos, windows)\n- **Architecture compatibility** (x64, arm64, x86, arm)\n- **Libc variant** (gnu or musl for Linux, msvc for Windows)\n- **Archive format preference** (tar.gz, zip, etc.)\n- **Build type** (avoids debug/test builds)\n\nFor most tools, you can simply install without specifying patterns:\n\n```sh\nmise install gitlab:user/repo\n```\n\n::: tip\nThe autodetection logic is implemented in [`src/backend/asset_matcher.rs`](https://github.com/jdx/mise/blob/main/src/backend/asset_matcher.rs), which is shared by both the GitHub and GitLab backends.\n:::\n\n### `asset_pattern`\n\nSpecifies the pattern to match against release asset names. This is useful when there are multiple assets for your OS/arch combination or when you need to override autodetection.\n\n```toml\n[tools.\"gitlab:gitlab-org/gitlab-runner\"]\nversion = \"latest\"\nasset_pattern = \"gitlab-runner-linux-x64\"\n```\n\n### `version_prefix`\n\nSpecifies a custom version prefix for release tags. By default, mise handles the common `v` prefix (e.g., `v1.0.0`), but some repositories use different prefixes like `release-`, `version-`, or no prefix at all.\n\nWhen `version_prefix` is configured, mise will:\n\n- Filter available versions with the prefix and strip it\n- Add the prefix when searching for releases\n- Try both prefixed and non-prefixed versions during installation\n\n```toml\n[tools]\n\"gitlab:user/repo\" = { version = \"latest\", version_prefix = \"release-\" }\n```\n\n**Examples:**\n\n- With `version_prefix = \"release-\"`:\n  - User specifies `1.0.0` → mise searches for `release-1.0.0` tag\n  - Available versions show as `1.0.0` (prefix stripped)\n- With `version_prefix = \"\"` (empty string):\n  - User specifies `1.0.0` → mise searches for `1.0.0` tag (no prefix)\n  - Useful for repositories that don't use any prefix\n\n### Platform-specific Asset Patterns\n\nFor different asset patterns per platform:\n\n```toml\n[tools.\"gitlab:gitlab-org/gitlab-runner\"]\nversion = \"latest\"\n\n[tools.\"gitlab:gitlab-org/gitlab-runner\".platforms]\nlinux-x64 = { asset_pattern = \"gitlab-runner-linux-x64\" }\nmacos-arm64 = { asset_pattern = \"gitlab-runner-macos-arm64\" }\n```\n\n### `checksum`\n\nVerify the downloaded file with a checksum:\n\n```toml\n[tools.\"gitlab:owner/repo\"]\nversion = \"1.0.0\"\nasset_pattern = \"tool-1.0.0-x64.tar.gz\"\nchecksum = \"sha256:a1b2c3d4e5f6789...\"\n```\n\n_Instead of specifying the checksum here, you can use [mise.lock](/dev-tools/mise-lock) to manage checksums._\n\n### Platform-specific Checksums\n\n```toml\n[tools.\"gitlab:gitlab-org/gitlab-runner\"]\nversion = \"latest\"\n\n[tools.\"gitlab:gitlab-org/gitlab-runner\".platforms]\nlinux-x64 = {\n  asset_pattern = \"gitlab-runner-linux-x64\",\n  checksum = \"sha256:a1b2c3d4e5f6789...\",\n}\nmacos-arm64 = {\n  asset_pattern = \"gitlab-runner-macos-arm64\",\n  checksum = \"sha256:b2c3d4e5f6789...\",\n}\n```\n\n### `size`\n\nVerify the downloaded asset size:\n\n```toml\n[tools]\n\"gitlab:gitlab-org/gitlab-runner\" = { version = \"latest\", size = \"12345678\" }\n```\n\n### Platform-specific Size\n\nYou can specify different sizes for different platforms:\n\n```toml\n[tools.\"gitlab:gitlab-org/gitlab-runner\"]\nversion = \"latest\"\n\n[tools.\"gitlab:gitlab-org/gitlab-runner\".platforms]\nlinux-x64 = { size = \"12345678\" }\nmacos-arm64 = { size = \"9876543\" }\n```\n\n### `strip_components`\n\nNumber of directory components to strip when extracting archives:\n\n```toml\n[tools]\n\"gitlab:gitlab-org/gitlab-runner\" = { version = \"latest\", strip_components = 1 }\n```\n\n::: info\nIf `strip_components` is not explicitly set, mise will automatically detect when to apply `strip_components = 1`. This happens when the extracted archive contains exactly one directory at the root level and no files. This is common with tools like ripgrep that package their binaries in a versioned directory (e.g., `ripgrep-14.1.0-x86_64-unknown-linux-musl/rg`). The auto-detection ensures the binary is placed directly in the install path where mise expects it.\n:::\n\n### `bin`\n\nRename the downloaded binary to a specific name. This is useful when downloading single binaries that have platform-specific names:\n\n```toml\n[tools.\"gitlab:myorg/mytool\"]\nversion = \"1.0.0\"\nasset_pattern = \"mytool-linux-x86_64\"\nbin = \"mytool\"  # Rename from mytool-linux-x86_64 to mytool\n```\n\n::: info\nWhen downloading single binaries (not archives), mise automatically removes OS/arch suffixes from the filename. For example, `mytool-linux-x86_64` becomes `mytool` automatically. Use the `bin` option only when you need a specific custom name.\n:::\n\n### `rename_exe`\n\nRename the executable after extraction from an archive. This is useful when the archive contains a binary with a platform-specific name that you want to rename:\n\n```toml\n[tools.\"gitlab:myorg/mytool\"]\nversion = \"latest\"\nasset_pattern = \"mytool_linux.zip\"\nrename_exe = \"mytool\"  # Rename the extracted binary to mytool\n```\n\n::: tip\nUse `rename_exe` for archives where the binary inside has a different name than desired. Use `bin` for single binary downloads (non-archives).\n:::\n\n### `bin_path`\n\nSpecify the directory containing binaries within the extracted archive, or where to place the downloaded file. This supports Tera templating with variables like `{{ version }}`, `{{ os }}`, `{{ arch }}`, and arch aliases (`{{ darwin_os }}`, `{{ amd64_arch }}`, `{{ x86_64_arch }}`, `{{ gnu_arch }}`):\n\n```toml\n[tools.\"gitlab:gitlab-org/gitlab-runner\"]\nversion = \"latest\"\nbin_path = \"gitlab-runner-{{ version }}/bin\" # expands to gitlab-runner-1.0.0/bin\n```\n\n**Binary path lookup order:**\n\n1. If `bin_path` is specified, use that directory\n2. If `bin_path` is not set, look for a `bin/` directory in the install path\n3. If the install path root contains an executable file, use the install path root\n4. If no `bin/` directory exists, search subdirectories for `bin/` directories\n5. If no `bin/` directories are found, searches immediate subdirectories for any executable files. If an executable is found directly within a subdirectory, that entire subdirectory is considered a binary path.\n6. If no executables are found, use the root of the extracted directory\n\n### `filter_bins`\n\nComma-separated list of binaries to symlink into a filtered `.mise-bins` directory. This is useful when the tool comes with extra binaries that you do not want to expose on PATH.\n\n```toml\n[tools]\n\"gitlab:myorg/mytool\" = { version = \"1.0.0\", filter_bins = \"mybin\" }\n```\n\nWhen enabled:\n\n- A `.mise-bins` subdirectory is created with symlinks only to the specified binaries\n- Other binaries are not exposed on PATH\n\n### `api_url`\n\nFor self-hosted GitLab instances, specify the API URL:\n\n```toml\n[tools]\n\"gitlab:myorg/mytool\" = { version = \"latest\", api_url = \"https://gitlab.mycompany.com/api/v4\" }\n```\n\n## Private GitLab repositories\n\nIf you want to install a tool from a private repository on `gitlab.com`, set the `MISE_GITLAB_TOKEN` environment variable for authentication:\n\n```sh\nexport MISE_GITLAB_TOKEN=\"your-token\"\n```\n\n## Self-hosted GitLab\n\nIf you are using a self-hosted GitLab instance, set the `api_url` tool option and optionally the `MISE_GITLAB_ENTERPRISE_TOKEN` environment variable for authentication:\n\n```sh\nexport MISE_GITLAB_ENTERPRISE_TOKEN=\"your-token\"\n```\n\n## Supported GitLab Syntax\n\n- **GitLab shorthand for latest release version:** `gitlab:gitlab-org/gitlab-runner`\n- **GitLab shorthand for specific release version:** `gitlab:gitlab-org/gitlab-runner@16.8.0`\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"gitlab\" :level=\"3\" />\n"
  },
  {
    "path": "docs/dev-tools/backends/go.md",
    "content": "# Go Backend\n\nYou may install packages directly via [go install](https://go.dev/doc/install) even if there\nisn't an asdf plugin for it.\n\nThe code for this is inside of the mise repository at [`./src/backend/go.rs`](https://github.com/jdx/mise/blob/main/src/backend/go.rs).\n\n## Dependencies\n\nThis relies on having `go` installed. Which you can install via mise:\n\n```sh\nmise use -g go\n```\n\n::: tip\nAny method of installing `go` is fine if you want to install go some other way.\nmise will use whatever `go` is on PATH.\n:::\n\n## Usage\n\nThe following installs the latest version of [hivemind](https://github.com/DarthSim/hivemind) and\nsets it as the active version on PATH:\n\n```sh\n$ mise use -g go:github.com/DarthSim/hivemind\n$ hivemind --help\nHivemind version 1.1.0\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `go` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `tags`\n\nSpecify go build tags (passed as `go install --tags`):\n\n```toml\n[tools]\n\"go:github.com/golang-migrate/migrate/v4/cmd/migrate\" = { version = \"latest\", tags = \"postgres\" }\n```\n"
  },
  {
    "path": "docs/dev-tools/backends/http.md",
    "content": "# HTTP Backend\n\nYou may install tools directly from HTTP URLs using the `http` backend. This backend downloads files from any HTTP/HTTPS URL and is ideal for tools that distribute pre-built binaries or archives through direct download links.\n\nThe code for this is inside of the mise repository at [`./src/backend/http.rs`](https://github.com/jdx/mise/blob/main/src/backend/http.rs).\n\n## Usage\n\nThe following installs a tool from a direct HTTP URL:\n\n```sh\nmise use -g http:my-tool[url=https://example.com/releases/my-tool-v1.0.0.tar.gz]@1.0.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"http:my-tool\" = { version = \"1.0.0\", url = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\" }\n```\n\n## Supported HTTP Syntax\n\n- **HTTP with URL parameter:** `http:my-tool[url=https://example.com/releases/my-tool-v1.0.0.tar.gz]@1.0.0`\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `http` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `url` (Required)\n\nSpecifies the HTTP URL to download the tool from. The URL supports templating with variables like `version`, `os()`, and `arch()`:\n\n```toml\n[tools]\n\"http:my-tool\" = { version = \"1.0.0\", url = \"https://example.com/releases/my-tool-v{{version}}.tar.gz\" }\n```\n\nYou can also use static URLs without templating:\n\n```toml\n[tools]\n\"http:my-tool\" = { version = \"1.0.0\", url = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\" }\n```\n\n#### Template Variables\n\nThe following template functions are available in URLs (use double curly braces, e.g., `version` becomes <code v-pre>{{version}}</code>):\n\n- `version` - The tool version\n- `os()` - Operating system: `macos`, `linux`, or `windows`\n- `arch()` - Architecture: `x64` or `arm64`\n- `os_family()` - OS family: `unix` or `windows`\n\nThe `os()` and `arch()` functions support remapping for tools that use different naming conventions:\n\n```toml\n[tools]\n# HashiCorp tools use \"darwin\" instead of \"macos\" and \"amd64\" instead of \"x64\"\n\"http:sentinel\" = {\n  version = \"latest\",\n  url = 'https://releases.hashicorp.com/sentinel/{{version}}/sentinel_{{version}}_{{os(macos=\"darwin\")}}_{{arch(x64=\"amd64\")}}.zip',\n}\n```\n\nThis produces URLs like:\n\n- macOS arm64: `sentinel_0.26.3_darwin_arm64.zip`\n- macOS x64: `sentinel_0.26.3_darwin_amd64.zip`\n- Linux x64: `sentinel_0.26.3_linux_amd64.zip`\n\n### Platform-specific URLs\n\nFor tools that need different downloads per platform, use the table format:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"http:my-tool\".platforms]\nmacos-x64 = { url = \"https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz\" }\nmacos-arm64 = { url = \"https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz\" }\nlinux-x64 = { url = \"https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz\" }\n```\n\n::: tip\nYou can use either `macos` or `darwin`, and `x64` or `amd64` for platform keys. `macos` and `x64` are preferred in documentation and examples, but all variants are accepted.\n\nOS/architecture values use mise's conventions: `linux`, `macos`, `windows` for operating systems and `x64`, `arm64` for architectures. For platform-specific URLs, use the appropriate platform key (e.g., `macos-x64`, `linux-arm64`) and specify the full URL for each platform.\n\nIf you mess up and use something like `darwin-aarch64` mise will try to figure out what\nyou meant and do the right thing anyhow.\n:::\n\n### `checksum`\n\nVerify the downloaded file with a checksum:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\"\nchecksum = \"sha256:a1b2c3d4e5f6789...\"\n```\n\n_Instead of specifying the checksum here, you can use [mise.lock](/dev-tools/mise-lock) to manage checksums._\n\n### Platform-specific Checksums\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"http:my-tool\".platforms]\nmacos-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz\",\n  checksum = \"sha256:a1b2c3d4e5f6789...\",\n}\nmacos-arm64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz\",\n  checksum = \"sha256:b2c3d4e5f6789...\",\n}\nlinux-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz\",\n  checksum = \"sha256:c3d4e5f6789...\",\n}\n```\n\n### `size`\n\nVerify the downloaded file size:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\"\nsize = \"12345678\"\n```\n\n### Platform-specific Size\n\nYou can specify different sizes for different platforms:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"http:my-tool\".platforms]\nmacos-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz\",\n  size = \"12345678\",\n}\nmacos-arm64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz\",\n  size = \"9876543\",\n}\nlinux-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz\",\n  size = \"11111111\",\n}\n```\n\n### `strip_components`\n\nNumber of directory components to strip when extracting archives:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\"\nstrip_components = 1\n```\n\n::: info\nIf `strip_components` is not explicitly set, mise will automatically detect when to apply `strip_components = 1`. This happens when the extracted archive contains exactly one directory at the root level and no files. This is common with tools like ripgrep that package their binaries in a versioned directory (e.g., `ripgrep-14.1.0-x86_64-unknown-linux-musl/rg`). The auto-detection ensures the binary is placed directly in the install path where mise expects it.\n:::\n\n### `bin`\n\nRename the downloaded binary to a specific name. This is useful when downloading single binaries that have platform-specific names:\n\n```toml\n[tools.\"http:docker-compose\"]\nversion = \"2.29.1\"\nurl = \"https://github.com/docker/compose/releases/download/v{{ version }}/docker-compose-linux-x86_64\"\nbin = \"docker-compose\"  # Rename from docker-compose-linux-x86_64 to docker-compose\n```\n\n::: info\nWhen downloading single binaries (not archives), mise automatically removes OS/arch suffixes from the filename. For example, `docker-compose-linux-x86_64` becomes `docker-compose` automatically. Use the `bin` option only when you need a specific custom name.\n:::\n\n### `rename_exe`\n\nRename the executable inside an extracted archive to a specific name. This is useful when archives contain binaries with platform-specific names or when installing kubectl plugins that need specific naming:\n\n```toml\n[tools.\"http:openunison-cli\"]\nversion = \"1.0.0\"\nurl = \"https://nexus.tremolo.io/repository/openunison-cli/openunison-cli-v{{version}}-linux.zip\"\nrename_exe = \"kubectl-openunison-cli\"  # Rename extracted binary for kubectl plugin\n```\n\nThis works by searching for the first executable in the extracted directory (or `bin_path` if specified) and renaming it to the specified name.\n\n::: tip\nUse `bin` for renaming single binary downloads, and `rename_exe` for renaming executables inside archives.\n:::\n\n### `format`\n\nExplicitly specify the archive format when the URL lacks a file extension or has an incorrect extension:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v1.0.0\"\nformat = \"tar.xz\"  # Explicitly specify the format\n```\n\n::: info\nIf `format` is not specified, mise will automatically detect the format from the file extension in the URL. Only use `format` when the URL doesn't have a proper extension or when you need to override the detected format.\n:::\n\n### Platform-specific Format\n\nYou can specify different formats for different platforms:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"http:my-tool\".platforms]\nmacos-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-macos-x64\",\n  format = \"tar.xz\",\n}\nlinux-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-linux-x64\",\n  format = \"tar.gz\",\n}\nwindows-x64 = {\n  url = \"https://example.com/releases/my-tool-v1.0.0-windows-x64\",\n  format = \"zip\",\n}\n```\n\n### `version_list_url`\n\nFetch available versions from a remote URL. This enables `mise ls-remote` to list available versions for HTTP-based tools:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v{{version}}.tar.gz\"\nversion_list_url = \"https://example.com/releases/versions.txt\"\n```\n\nThe version list URL can return data in multiple formats:\n\n- **Plain text**: A single version number (e.g., `2.0.53`)\n- **Line-separated**: One version per line\n- **JSON array of strings**: `[\"1.0.0\", \"1.1.0\", \"2.0.0\"]`\n- **JSON array of objects**: `[{\"version\": \"1.0.0\"}, {\"tag_name\": \"v2.0.0\"}]`\n- **JSON object with versions array**: `{\"versions\": [\"1.0.0\", \"2.0.0\"]}`\n\nVersion prefixes like `v` are automatically stripped.\n\n### `version_regex`\n\nExtract versions from the version list URL response using a regular expression:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v{{version}}.tar.gz\"\nversion_list_url = \"https://example.com/releases/\"\nversion_regex = 'my-tool-v(\\d+\\.\\d+\\.\\d+)\\.tar\\.gz'\n```\n\nThe first capturing group is used as the version. If no capturing group is present, the entire match is used.\n\n### `version_json_path`\n\nExtract versions from JSON responses using a jq-like path expression:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v{{version}}.tar.gz\"\nversion_list_url = \"https://api.example.com/releases\"\nversion_json_path = \".[].tag_name\"\n```\n\nSupported path expressions:\n\n- `.` - root value\n- `.[]` - iterate over array elements\n- `.[].field` - extract field from each array element\n- `.field` - extract field from object\n- `.field[]` - iterate over array in field\n- `.field.subfield` - nested field access\n- `.data.versions[]` - complex nested paths\n- `.[?field=value]` - filter array elements where field equals value\n\nExamples:\n\n```toml\n# GitHub releases API format\nversion_json_path = \".[].tag_name\"\n\n# Nested versions array\nversion_json_path = \".data.versions[]\"\n\n# Release info objects\nversion_json_path = \".releases[].info.version\"\n\n# Filter for stable releases only (e.g., Flutter)\nversion_json_path = \".releases[?channel=stable].version\"\n```\n\nThe filter syntax `[?field=value]` allows filtering JSON arrays before extraction. This is useful for APIs that return multiple release channels (stable, beta, dev) and you only want specific ones.\n\n### `version_expr`\n\nExtract versions using an [expr-lang](https://expr-lang.org/) expression. This provides the most flexibility for complex version extraction logic:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"latest\"\nurl = \"https://example.com/releases/my-tool-v{{ version }}.tar.gz\"\nversion_list_url = \"https://example.com/versions.txt\"\nversion_expr = 'split(body, \"\\n\")'\n```\n\nThe expression receives the HTTP response body as the `body` variable and should return an array of version strings.\n\nExample expressions:\n\n```toml\n# Split newline-separated versions\nversion_expr = 'split(body, \"\\n\")'\n\n# Split and filter empty lines\nversion_expr = 'filter(split(body, \"\\n\"), # != \"\")'\n\n# Parse JSON and extract object keys (useful for HashiCorp-style JSON)\n# e.g., {\"versions\": {\"1.0.0\": {}, \"2.0.0\": {}}}\nversion_expr = 'keys(fromJSON(body).versions)'\n```\n\nThe [expr-lang](https://expr-lang.org/) library provides built-in functions including:\n\n- **`fromJSON(string)`**: Parse a JSON string into a value\n- **`toJSON(value)`**: Convert a value to a JSON string\n- **`keys(map)`**: Get the keys of an object/map as an array\n- **`values(map)`**: Get the values of an object/map as an array\n- **`len(value)`**: Get the length of a string, array, or map\n\n::: tip\n`version_expr` takes precedence over `version_regex` and `version_json_path` if multiple are specified. Use it when the other options aren't flexible enough for your use case.\n:::\n\n### `bin_path`\n\nSpecify the directory containing binaries within the extracted archive, or where to place the downloaded file. This supports templating with `{{version}}`:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nurl = \"https://example.com/releases/my-tool-v1.0.0.tar.gz\"\nbin_path = \"my-tool-{{version}}/bin\" # expands to my-tool-1.0.0/bin\n```\n\n**Binary path lookup order:**\n\n1. If `bin_path` is specified, use that directory\n2. If `bin_path` is not set, look for a `bin/` directory in the install path\n3. If no `bin/` directory exists, search subdirectories for `bin/` directories\n4. If no `bin/` directories are found, use the root of the extracted directory\n\n## Caching Behavior\n\nThe HTTP backend implements an intelligent caching system to optimize disk usage and installation speed:\n\n### Cache Location\n\nDownloaded and extracted files are cached in `$MISE_CACHE_DIR/http-tarballs/` instead of being stored separately for each tool installation. By default:\n\n- **Linux**: `~/.cache/mise/http-tarballs/`\n- **macOS**: `~/Library/Caches/mise/http-tarballs/`\n\n### Cache Key Generation\n\nCache keys are generated based on the file content to ensure identical downloads are shared across tools:\n\n1. **Blake3 hash of file content**: When no checksum is provided, mise calculates a Blake3 hash of the downloaded file\n2. **Extraction options**: `strip_components` is included in the cache key since it affects the extracted structure\n\nExample cache directory structure:\n\n```\n~/.cache/mise/http-tarballs/\n├── 71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f/\n│   ├── extracted/\n│   │   └── bin/my-tool\n│   └── metadata.json\n└── 1c2af379bdf1fed266bc44b49271e2df5b0dafae09f1cc744b3505ec50c84719_strip_1/\n    ├── extracted/\n    │   └── my-tool\n    └── metadata.json\n```\n\n### Symlinked Installations\n\nTool installations are symlinks to the cached extracted content:\n\n```bash\n~/.local/share/mise/installs/http-my-tool/1.0.0 → ~/.cache/mise/http-tarballs/71f774.../extracted\n```\n\nThis approach provides several benefits:\n\n- **Space efficiency**: Multiple tools using the same tarball share a single cached copy\n- **Faster installations**: Cache hits avoid re-downloading and re-extracting files\n- **Consistency**: Identical file content always uses the same cache entry\n\n### Cache Metadata\n\nEach cache entry includes a `metadata.json` file with information about the cached content:\n\n```json\n{\n  \"url\": \"https://example.com/releases/my-tool-v1.0.0.tar.gz\",\n  \"checksum\": \"sha256:a1b2c3d4e5f6789...\",\n  \"size\": 1024000,\n  \"extracted_at\": 1703001234,\n  \"platform\": \"macos-arm64\"\n}\n```\n\n### Cache Management\n\nThe HTTP backend cache follows mise's standard cache management:\n\n- Cache entries can be cleared with `mise cache clear`\n- The cache directory respects the `MISE_CACHE_DIR` environment variable\n- **Autopruner**: mise automatically cleans up unused cache entries after 30 days of inactivity\n- Manual cleanup is available with `mise cache clear` if needed\n"
  },
  {
    "path": "docs/dev-tools/backends/index.md",
    "content": "# Backends\n\nBackends are package managers or ecosystems that mise uses to install [tools](/dev-tools/index.html) and [plugins](/plugins.html). Each backend can install and manage multiple tools from its ecosystem. For example, the `npm` backend can install many different tools like `npm:prettier`, or the `pipx` backend can install tools like `pipx:black`. This allows mise to support a wide variety of tools and languages by leveraging different package managers and their ecosystems.\n\nWhen you run the [`mise use`](/cli/use.html) command, mise will determine the appropriate backend to use based on the tool you are trying to manage. The backend will then handle the installation, configuration, and any other necessary steps to ensure the tool is ready to use.\n\nFor more details on how backends fit into mise's overall design, see the [backend architecture documentation](/dev-tools/backend_architecture.html).\n\nBelow is a list of the available backends in mise:\n\n- [asdf](/dev-tools/backends/asdf) (provide tools through [plugins](/plugins.html))\n- [aqua](/dev-tools/backends/aqua)\n- [cargo](/dev-tools/backends/cargo)\n- [conda](/dev-tools/backends/conda) <Badge type=\"warning\" text=\"experimental\" />\n- [dotnet](/dev-tools/backends/dotnet) <Badge type=\"warning\" text=\"experimental\" />\n- [forgejo](/dev-tools/backends/forgejo)\n- [gem](/dev-tools/backends/gem)\n- [github](/dev-tools/backends/github)\n- [gitlab](/dev-tools/backends/gitlab)\n- [go](/dev-tools/backends/go)\n- [http](/dev-tools/backends/http)\n- [npm](/dev-tools/backends/npm)\n- [pipx](/dev-tools/backends/pipx)\n- [s3](/dev-tools/backends/s3) <Badge type=\"warning\" text=\"experimental\" />\n- [spm](/dev-tools/backends/spm) <Badge type=\"warning\" text=\"experimental\" />\n- [ubi](/dev-tools/backends/ubi)\n- [vfox](/dev-tools/backends/vfox) (provide tools through [plugins](/plugins.html))\n- [custom backends](/backend-plugin-development) (build your own backend with a plugin which itself provides many tools)\n"
  },
  {
    "path": "docs/dev-tools/backends/npm.md",
    "content": "# npm Backend\n\nYou may install packages directly from [npmjs.org](https://npmjs.org/) even if there\nisn't an asdf plugin for it.\n\nThe code for this is inside of the mise repository at [`./src/backend/npm.rs`](https://github.com/jdx/mise/blob/main/src/backend/npm.rs).\n\n## Dependencies\n\nThis relies on having `npm` installed for resolving package versions.\nIf you use `bun` or `pnpm` as the package manager, they must also be installed.\n\nHere is how to install `npm` with mise:\n\n```sh\nmise use -g node\n```\n\nTo install `bun` or `pnpm`:\n\n```sh\nmise use -g bun\n# or\nmise use -g pnpm\n```\n\n## Usage\n\nThe following installs the latest version of [prettier](https://www.npmjs.com/package/prettier)\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g npm:prettier\n$ prettier --version\n3.1.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"npm:prettier\" = \"latest\"\n```\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"npm\" :level=\"3\" />\n"
  },
  {
    "path": "docs/dev-tools/backends/pipx.md",
    "content": "# pipx Backend\n\npipx is a tool for running Python CLIs in isolated virtualenvs. This is necessary for Python CLIs\nbecause it prevents conflicting dependencies between CLIs or between a CLI and Python projects. In essence,\nthis backend lets you add Python CLIs to mise.\n\nTo be clear, pipx is not pip and it's not used to manage Python dependencies generally.\nmise is a tool manager, not a dependency manager like pip, uv, or poetry. You can, however, use mise to install said package\nmanagers. You'd want to use the pipx backend to install a CLI like \"black\", not a library like \"NumPy\" or \"requests\".\n\nSomewhat confusingly, the pipx backend will actually default to using [`uvx`](https://docs.astral.sh/uv/guides/tools/) (the equivalent of pipx for uv)\nif uv is installed. This should just mean that it installs much faster, but see below to disable or configure\nsince occasionally tools don't work with uvx.\n\nThe pipx backend supports the following sources:\n\n- PyPI\n- Git\n- GitHub\n- Http\n\nThe code for this is inside of the mise repository at [`./src/backend/pipx.rs`](https://github.com/jdx/mise/blob/main/src/backend/pipx.rs).\n\n## Dependencies\n\nThis relies on having `uv` (recommended) or `pipx` installed.\n\nIf you have `uv` installed, mise will use `uv tool install` under the hood and you don't need to install `pipx` to run the commands containing \"pipx:\".\n\nIn case you need `pipx` for other reasons, you can install it with or without mise.\nHere is how to install `pipx` with mise:\n\n```sh\nmise use -g python\npip install --user pipx\n```\n\n[Other installation instructions](https://pipx.pypa.io/latest/installation/)\n\n## Usage\n\nThe following installs the latest version of [black](https://github.com/psf/black)\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g pipx:psf/black\n$ black --version\nblack, 24.3.0\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"pipx:psf/black\" = \"latest\"\n```\n\n## Python upgrades\n\nIf the python version used by a pipx package changes, (by mise or system python), you may need to\nreinstall the package. This can be done with:\n\n```sh\nmise install -f pipx:psf/black\n```\n\nOr you can reinstall all pipx packages with:\n\n```sh\nmise install -f \"pipx:*\"\n```\n\nmise _should_ do this automatically when using `mise up python`.\n\n### Supported Pipx Syntax\n\n| Description                           | Usage                                                  |\n| ------------------------------------- | ------------------------------------------------------ |\n| PyPI shorthand latest version         | `pipx:black`                                           |\n| PyPI shorthand for specific version   | `pipx:black@24.3.0`                                    |\n| GitHub shorthand for latest version   | `pipx:psf/black`                                       |\n| GitHub shorthand for specific version | `pipx:psf/black@24.3.0`                                |\n| Git syntax for latest version         | `pipx:git+https://github.com/psf/black.git`            |\n| Git syntax for a branch               | `pipx:git+https://github.com/psf/black.git@main`       |\n| Https with zipfile                    | `pipx:https://github.com/psf/black/archive/18.9b0.zip` |\n\nOther syntax may work but is unsupported and untested.\n\n## Settings\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable listed.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"pipx\" :level=\"3\" />\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `pipx` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `extras`\n\nInstall additional components.\n\n```toml\n[tools]\n\"pipx:harlequin\" = { version = \"latest\", extras = \"postgres,s3\" }\n```\n\n### `pipx_args`\n\nAdditional arguments to pass to `pipx` when installing the package.\n\n```toml\n[tools]\n\"pipx:black\" = { version = \"latest\", pipx_args = \"--preinstall\" }\n```\n\n### `uvx`\n\nSet to `false` to always disable uv for this tool.\n\n```toml\n[tools]\n\"pipx:ansible\" = { version = \"latest\", uvx = \"false\", pipx_args = \"--include-deps\" }\n```\n\n### `uvx_args`\n\nAdditional arguments to pass to `uvx` when installing the package.\n\n```toml\n[tools]\n\"pipx:ansible-core\" = { version = \"latest\", uvx_args = \"--with ansible\" }\n```\n"
  },
  {
    "path": "docs/dev-tools/backends/s3.md",
    "content": "# S3 Backend <Badge type=\"warning\" text=\"experimental\" />\n\nYou may install tools directly from Amazon S3 or S3-compatible storage (like MinIO) using the `s3` backend. This backend is ideal for enterprise teams hosting proprietary tools in private S3 buckets.\n\nThe code for this is inside of the mise repository at [`./src/backend/s3.rs`](https://github.com/jdx/mise/blob/main/src/backend/s3.rs).\n\n::: warning\nThe S3 backend is experimental and requires `experimental = true` in your mise settings.\n:::\n\n## Usage\n\nThe following installs a tool from an S3 bucket:\n\n```sh\nmise use -g \"s3:my-tool[url=s3://my-bucket/tools/my-tool-v1.0.0.tar.gz]@1.0.0\"\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"s3:my-tool\" = { version = \"1.0.0\", url = \"s3://my-bucket/tools/my-tool-v1.0.0.tar.gz\" }\n```\n\n## Authentication\n\nThe S3 backend uses the AWS SDK default credential chain. Credentials are loaded from (in order):\n\n1. Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`\n2. AWS credentials file: `~/.aws/credentials`\n3. IAM roles (when running on AWS infrastructure)\n\n```sh\n# Set credentials via environment variables\nexport AWS_ACCESS_KEY_ID=\"your-access-key\"\nexport AWS_SECRET_ACCESS_KEY=\"your-secret-key\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n\nmise install\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `s3` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `url` (Required)\n\nSpecifies the S3 URL to download the tool from. The URL supports templating with `{{ version }}`:\n\n```toml\n[tools]\n\"s3:my-tool\" = { version = \"1.0.0\", url = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\" }\n```\n\n### `endpoint`\n\nSpecify a custom S3-compatible endpoint for services like MinIO, DigitalOcean Spaces, or self-hosted S3:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nendpoint = \"http://minio.internal:9000\"\n```\n\n### `region`\n\nSpecify the AWS region for the S3 bucket:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nregion = \"us-west-2\"\n```\n\n### Platform-specific URLs\n\nFor tools that need different downloads per platform, use the table format:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"s3:my-tool\".platforms]\nmacos-x64 = { url = \"s3://my-bucket/tools/my-tool-v1.0.0-macos-x64.tar.gz\" }\nmacos-arm64 = { url = \"s3://my-bucket/tools/my-tool-v1.0.0-macos-arm64.tar.gz\" }\nlinux-x64 = { url = \"s3://my-bucket/tools/my-tool-v1.0.0-linux-x64.tar.gz\" }\n```\n\n### `checksum`\n\nVerify the downloaded file with a checksum:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\nurl = \"s3://my-bucket/tools/my-tool-v1.0.0.tar.gz\"\nchecksum = \"sha256:a1b2c3d4e5f6789...\"\n```\n\n_Instead of specifying the checksum here, you can use [mise.lock](/dev-tools/mise-lock) to manage checksums._\n\n### `bin_path`\n\nSpecify the directory containing binaries within the extracted archive:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\nurl = \"s3://my-bucket/tools/my-tool-v1.0.0.tar.gz\"\nbin_path = \"my-tool-{{ version }}/bin\"\n```\n\n### `format`\n\nExplicitly specify the archive format when the URL lacks a file extension:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"1.0.0\"\nurl = \"s3://my-bucket/tools/my-tool-v1.0.0\"\nformat = \"tar.gz\"\n```\n\n## Version Discovery\n\nThe S3 backend supports two methods for discovering available versions.\n\n### Manifest File\n\nFetch available versions from a JSON manifest file stored in S3:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"latest\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nversion_list_url = \"s3://my-bucket/tools/versions.json\"\n```\n\nThe manifest file can be a JSON array of version strings:\n\n```json\n[\"1.0.0\", \"1.1.0\", \"2.0.0\"]\n```\n\nOr a JSON array of objects (use `version_json_path` to extract versions):\n\n```json\n[{ \"version\": \"1.0.0\" }, { \"version\": \"1.1.0\" }, { \"version\": \"2.0.0\" }]\n```\n\n### `version_json_path`\n\nExtract versions from JSON responses using a jq-like path expression:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"latest\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nversion_list_url = \"s3://my-bucket/tools/releases.json\"\nversion_json_path = \".[].version\"\n```\n\n### `version_expr`\n\nExtract versions using an [expr-lang](https://expr-lang.org/) expression for complex version extraction logic:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"latest\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nversion_list_url = \"s3://my-bucket/tools/versions.txt\"\nversion_expr = 'split(body, \"\\n\")'\n```\n\nThe expression receives the response body as the `body` variable and should return an array of version strings.\n\n### S3 Object Listing\n\nDiscover versions by listing objects in the S3 bucket:\n\n```toml\n[tools.\"s3:my-tool\"]\nversion = \"latest\"\nurl = \"s3://my-bucket/tools/my-tool-v{{ version }}.tar.gz\"\nversion_prefix = \"tools/my-tool-v\"\nversion_regex = \"my-tool-v([0-9.]+)\"\n```\n\n- `version_prefix`: The S3 key prefix to list objects from\n- `version_regex`: A regular expression to extract version numbers from object keys (first capturing group is used)\n\n## Custom Endpoint Example (MinIO)\n\nHere's a complete example using MinIO as an S3-compatible backend:\n\n```toml\n[tools.\"s3:my-internal-tool\"]\nversion = \"latest\"\nurl = \"s3://tools-bucket/releases/my-tool-{{ version }}.tar.gz\"\nendpoint = \"http://minio.internal:9000\"\nregion = \"us-east-1\"\nversion_list_url = \"s3://tools-bucket/releases/versions.json\"\nbin_path = \"bin\"\n```\n\nWith environment variables:\n\n```sh\nexport AWS_ACCESS_KEY_ID=\"minio-access-key\"\nexport AWS_SECRET_ACCESS_KEY=\"minio-secret-key\"\nmise install\n```\n\n## Comparison with HTTP Backend\n\n| Feature           | S3 Backend                                          | HTTP Backend      |\n| ----------------- | --------------------------------------------------- | ----------------- |\n| Authentication    | AWS credentials (env vars, ~/.aws/credentials, IAM) | HTTP auth headers |\n| Version discovery | S3 listing or manifest file                         | HTTP endpoint     |\n| Custom endpoints  | Yes (MinIO, etc.)                                   | N/A               |\n| Use case          | Private/enterprise tools                            | Public downloads  |\n"
  },
  {
    "path": "docs/dev-tools/backends/spm.md",
    "content": "# SPM Backend <Badge type=\"warning\" text=\"experimental\" />\n\nYou may install executables managed by [Swift Package Manager](https://www.swift.org/documentation/package-manager) directly from GitHub or GitLab releases.\n\nThe code for this is inside of the mise repository at [`./src/backend/spm.rs`](https://github.com/jdx/mise/blob/main/src/backend/spm.rs).\n\n## Dependencies\n\nThis relies on having `swift` installed. You can either install it [manually](https://www.swift.org/install) or [with mise](/lang/swift).\n\n> [!NOTE]\n> If you have Xcode installed and selected in your system via `xcode-select`, Swift is already available through the toolchain embedded in the Xcode installation.\n\n## Usage\n\nThe following installs the latest version of `tuist`\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g spm:tuist/tuist\n$ tuist --help\nOVERVIEW: Generate, build and test your Xcode projects.\n\nUSAGE: tuist <subcommand>\n...\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"spm:tuist/tuist\" = \"latest\"\n```\n\n### Supported Syntax\n\n| Description                                   | Usage                                           |\n| --------------------------------------------- | ----------------------------------------------- |\n| GitHub shorthand for latest release version   | `spm:tuist/tuist`                               |\n| GitHub shorthand for specific release version | `spm:tuist/tuist@4.15.0`                        |\n| GitHub url for latest release version         | `spm:https://github.com/tuist/tuist.git`        |\n| GitHub url for specific release version       | `spm:https://github.com/tuist/tuist.git@4.15.0` |\n\nOther syntax may work but is unsupported and untested.\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the backend — these\ngo in `[tools]` in `mise.toml`.\n\n### `provider`\n\nSet the provider type to use for fetching assets and release information. Either `github` or `gitlab` (default is `github`).\nEnsure the `provider` is set to the correct type if you use shorthand notation and `api_url` for self-hosted repositories\nas the type probably cannot be derived correctly from the URL.\n\n```toml\n[tools]\n\"spm:patricklorran/ios-settings\" = { version = \"latest\", provider = \"gitlab\" }\n```\n\n### `api_url`\n\nSet the URL for the provider's API. This is useful when using a self-hosted instance.\n\n```toml\n[tools]\n\"spm:acme/my-tool\" = { version = \"latest\", provider = \"gitlab\", api_url = \"https://gitlab.acme.com/api/v4\" }\n```\n"
  },
  {
    "path": "docs/dev-tools/backends/ubi.md",
    "content": "# Ubi Backend\n\n::: warning\nThe ubi backend is **deprecated**. Please use the [github backend](/dev-tools/backends/github) instead.\n\nTo migrate, replace `ubi:owner/repo` with `github:owner/repo` in your configuration files.\n:::\n\nYou may install GitHub Releases and URL packages directly using [ubi](https://github.com/houseabsolute/ubi) backend. ubi is directly compiled into\nthe mise codebase so it does not need to be installed separately to be used.\n\nubi doesn't require plugins or even any configuration for each tool. What it does is try to deduce what\nthe proper binary/tarball is from GitHub releases and downloads the right one. As long as the vendor\nuses a somewhat standard labeling scheme for their releases, ubi should be able to figure it out.\n\nThe code for this is inside of the mise repository at [`./src/backend/ubi.rs`](https://github.com/jdx/mise/blob/main/src/backend/ubi.rs).\n\n## Usage\n\nThe following installs the latest version of goreleaser\nand sets it as the active version on PATH:\n\n```sh\n$ mise use -g ubi:goreleaser/goreleaser\n$ goreleaser --version\n1.25.1\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"ubi:goreleaser/goreleaser\" = \"latest\"\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `ubi` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `exe`\n\nThe `exe` option allows you to specify the executable name in the archive. This is useful when the\narchive contains multiple executables.\n\nIf you get an error like `could not find any files named cli in the downloaded zip file`, you can\nuse the `exe` option to specify the executable name:\n\n```toml\n[tools]\n\"ubi:cli/cli\" = { version = \"latest\", exe = \"gh\" } # github's cli\n```\n\n### `rename_exe`\n\nThe `rename_exe` option allows you to specify the name of the executable once it has been extracted.\n\nuse the `rename_exe` option to specify the target executable name:\n\n```toml\n[tools]\n\"ubi:cli/cli\" = { version = \"latest\", exe = \"gh\", rename_exe = \"github\" } # github's cli\n```\n\n### `matching`\n\nSet a string to match against the release filename when there are multiple files for your\nOS/arch, i.e. \"gnu\", \"musl\", or \"msvc\". Note that this is only used when there is more than one\nmatching release filename for your OS/arch. If only one release asset matches your OS/arch,\nthen this will be ignored.\n\n```toml\n[tools]\n\"ubi:BurntSushi/ripgrep\" = { version = \"latest\", matching = \"musl\" }\n```\n\n### `matching_regex`\n\nSet a regular expression string that will be matched against release filenames before matching\nagainst OS/arch. If the pattern yields a single match, that release will be selected. If no matches\nare found, this will result in an error.\n\n```toml\n[tools]\n\"ubi:shader-slang/slang\" = { version = \"latest\", matching_regex = \"\\\\d+\\\\.tar\" }\n```\n\n### `provider`\n\nSet the provider type to use for fetching assets and release information. Either `github` or `gitlab` (default is `github`).\nEnsure the `provider` is set to the correct type if you use `api_url` as the type probably cannot be derived correctly\nfrom the URL.\n\n```toml\n[tools]\n\"ubi:gitlab-org/cli\" = { version = \"latest\", exe = \"glab\", provider = \"gitlab\" }\n```\n\n### `api_url`\n\nSet the URL for the provider's API. This is useful when using a self-hosted instance.\n\n```toml\n[tools]\n\"ubi:acme/my-tool\" = {\n  version = \"latest\",\n  provider = \"gitlab\",\n  api_url = \"https://gitlab.acme.com/api/v4\",\n}\n```\n\n### `extract_all`\n\nSet to `true` to extract all files in the tarball instead of just the \"bin\". Not compatible with `exe` nor `rename_exe`.\n\n```toml\n[tools]\n\"ubi:helix-editor/helix\" = { version = \"latest\", extract_all = \"true\" }\n```\n\n### `bin_path`\n\nThe directory in the tarball where the binary(s) are located. This is useful when the binary is not in the root of the tarball.\nThis only makes sense when `extract_all` is set to `true`.\n\n```toml\n[tools]\n\"ubi:BurntSushi/ripgrep\" = {\n  version = \"latest\",\n  extract_all = \"true\",\n  bin_path = \"target/release\",\n}\n```\n\n**Binary path lookup order:**\n\n1. If `bin_path` is specified, use that directory\n2. If `extract_all` is set to `true`, use the install path root\n3. If `bin_path` is not set, look for a `bin/` directory in the install path\n4. If no `bin/` directory exists, use the root of the extracted directory\n\n### `tag_regex`\n\nSet a regex to filter out tags that don't match the regex. This is useful when a vendor has a bunch of\nreleases for unrelated CLIs in the same repo. For example, `cargo-bins/cargo-binstall` has a bunch of\nreleases for unrelated CLIs that are not `cargo-binstall`. This option can be used to filter out those\nreleases.\n\n```toml\n[tools]\n\"ubi:cargo-bins/cargo-binstall\" = { version = \"latest\", tag_regex = '^\\d+\\.' }\n```\n\n## Self-hosted GitHub/GitLab\n\nIf you are using a self-hosted GitHub/GitLab instance, you can set the `provider` and `api_url` tool options.\nAdditionally, you can set the `MISE_GITHUB_ENTERPRISE_TOKEN` or `MISE_GITLAB_ENTERPRISE_TOKEN` environment variable to\nauthenticate with the API.\n\n## Supported Ubi Syntax\n\n- **GitHub shorthand for latest release version:** `ubi:goreleaser/goreleaser`\n- **GitHub shorthand for specific release version:** `ubi:goreleaser/goreleaser@1.25.1`\n- **URL syntax:** `ubi:https://github.com/goreleaser/goreleaser/releases/download/v1.16.2/goreleaser_Darwin_arm64.tar.gz`\n\n## Troubleshooting ubi\n\n### `ubi` resolver can't find os/arch\n\nSometimes vendors use strange formats for their releases that ubi can't figure out, possibly for a\nspecific os/arch combination. For example this recently happened in [this ticket](https://github.com/houseabsolute/ubi/issues/79) because a vendor used\n\"mac\" instead of the more common \"macos\" or \"darwin\" tags.\n\nTry using ubi by itself to see if the issue is related to mise or ubi:\n\n```sh\nubi -p jdx/mise\n./bin/mise -v # yes this technically means you could do `mise use ubi:jdx/mise` though I don't know why you would\n```\n\n### `ubi` picks the wrong tarball\n\nAnother issue is that a GitHub release may have a bunch of tarballs, some that don't contain the CLI\nyou want, you can use the `matching` field in order to specify a string to match against the release.\n\n```sh\nmise use ubi:tamasfe/taplo[matching=full]\n# or with ubi directly\nubi -p tamasfe/taplo -m full\n```\n\n### `ubi` can't find the binary in the tarball\n\nubi assumes that the repo name is the same as the binary name, however that is often not the case.\nFor example, BurntSushi/ripgrep gives us a binary named `rg` not `ripgrep`. In this case, you can\nspecify the binary name with the `exe` field:\n\n```sh\nmise use ubi:BurntSushi/ripgrep[exe=rg]\n# or with ubi directly\nubi -p BurntSushi/ripgrep -e rg\n```\n\n### `ubi` uses weird versions\n\nThis issue is actually with mise and not with ubi. mise needs to be able to list the available versions\nof the tools so that \"latest\" points to whatever is the actual latest release of the CLI. What sometimes\nhappens is vendors will have GitHub releases for unrelated things. For example, `cargo-bins/cargo-binstall`\nis the repo for cargo-binstall, however it has a bunch of releases for unrelated CLIs that are not\ncargo-binstall. We need to filter these out and that can be specified with the `tag_regex` tool option:\n\n```sh\nmise use 'ubi:cargo-bins/cargo-binstall[tag_regex=^\\d+\\.]'\n```\n\nNow when running `mise ls-remote ubi:cargo-bins/cargo-binstall[tag_regex=^\\d+\\.]` you should only see\nversions starting with a number. Note that this command is cached so you likely will need to run `mise cache clear` first.\n"
  },
  {
    "path": "docs/dev-tools/backends/vfox.md",
    "content": "# Vfox Backend\n\n::: tip\nVfox is the recommended plugin system for mise. It provides cross-platform support, built-in modules, and a modern hook-based architecture.\n:::\n\n[Vfox](https://github.com/version-fox/vfox) plugins may be used in mise to install tools.\n\n## Why vfox?\n\n- **Cross-platform** — plugins work on Windows, macOS, and Linux without platform-specific code\n- **Built-in modules** — HTTP, JSON, HTML parsing, archive extraction, semver comparison, and logging are all available out of the box, no external dependencies needed\n- **Security** — [tool plugins](../../tool-plugin-development.md) support attestation verification (GitHub artifact attestations, cosign signatures, SLSA provenance) for downloaded artifacts. When a tool plugin's `PreInstall` hook returns an `attestation` table, mise verifies it during install and records the result in `mise.lock`, protecting against downgrade attacks on subsequent installs. Backend plugins do not currently support attestation\n- **Modern architecture** — structured hooks with typed contexts, backend plugins for multi-tool management, rolling version checksums, and lock file support\n\nThe code for this is inside the mise repository at [`./src/backend/vfox.rs`](https://github.com/jdx/mise/blob/main/src/backend/vfox.rs).\n\n## Dependencies\n\nNo dependencies are required for vfox. Vfox lua code is read via a lua interpreter built into mise.\n\n## Usage\n\nThe following installs the latest version of cmake and sets it as the active version on PATH:\n\n```sh\n$ mise use -g vfox:version-fox/vfox-cmake\n$ cmake --version\ncmake version 3.21.3\n```\n\nThe version will be set in `~/.config/mise/config.toml` with the following format:\n\n```toml\n[tools]\n\"vfox:version-fox/vfox-cmake\" = \"latest\"\n```\n\n## Default plugin backend\n\nOn Windows, mise uses vfox plugins by default.\nIf you'd like to use plugins by default even on Linux/macOS, set the following settings:\n\n```sh\nmise settings add disable_backends asdf\n```\n\nNow you can list available plugins with `mise registry`:\n\n```sh\n$ mise registry | grep vfox:\nclang                         vfox:mise-plugins/vfox-clang\ncmake                         vfox:mise-plugins/vfox-cmake\ncrystal                       vfox:mise-plugins/vfox-crystal\ndart                          vfox:mise-plugins/vfox-dart\ndotnet                        vfox:mise-plugins/vfox-dotnet\netcd                          aqua:etcd-io/etcd vfox:mise-plugins/vfox-etcd\nflutter                       vfox:mise-plugins/vfox-flutter\ngradle                        aqua:gradle/gradle vfox:mise-plugins/vfox-gradle\ngroovy                        vfox:mise-plugins/vfox-groovy\nkotlin                        vfox:mise-plugins/vfox-kotlin\nmaven                         aqua:apache/maven vfox:mise-plugins/vfox-maven\nphp                           vfox:mise-plugins/vfox-php\nscala                         vfox:mise-plugins/vfox-scala\nterraform                     aqua:hashicorp/terraform vfox:mise-plugins/vfox-terraform\nvlang                         vfox:mise-plugins/vfox-vlang\n```\n\nAnd they will be installed when running commands such as `mise use -g cmake` without needing to\nspecify `vfox:cmake`.\n\n## Plugins\n\nIn addition to the standard vfox plugins, mise supports modern plugins that can manage multiple tools using the `plugin:tool` format. These plugins are perfect for:\n\n- Installing tools from private repositories\n- Package managers (npm, pip, etc.)\n- Custom tool families\n\n### Example: Plugin Usage\n\n```bash\n# Install a plugin\nmise plugin install my-plugin https://github.com/username/my-plugin\n\n# Use the plugin:tool format\nmise install my-plugin:some-tool@1.0.0\nmise use my-plugin:some-tool@latest\n```\n\n### Install from Zip File\n\n```bash\n# Install a plugin from a zip file over HTTPS\nmise plugin install <plugin-name> <zip-url>\n# Example: Installing a plugin from a zip file\nmise plugin install vfox-cmake https://github.com/mise-plugins/vfox-cmake/archive/refs/heads/main.zip\n```\n\nFor more information, see:\n\n- [Using Plugins](../../plugin-usage.md) - End-user guide\n- [Plugin Development](../../tool-plugin-development.md) - Developer guide\n- [Plugin Template](https://github.com/jdx/mise-tool-plugin-template) - Quick start template for creating plugins\n"
  },
  {
    "path": "docs/dev-tools/comparison-to-asdf.md",
    "content": "# Comparison to asdf\n\nmise can be used as a drop-in replacement for asdf. It supports the same `.tool-versions` files that\nyou may have used with asdf and can use asdf plugins through\nthe [asdf backend](/dev-tools/backends/asdf.html).\n\nIt will not, however, reuse existing asdf directories\n(so you'll need to either reinstall them or move them), and 100% compatibility is not a design goal.\nThat said,\nif you're coming from asdf-bash (0.15 and below), mise actually\nhas [fewer breaking changes than asdf-go (0.16 and above)](https://asdf-vm.com/guide/upgrading-to-v0-16.html)\ndespite 100% compatibility not being a design goal of mise.\n\nCasual users coming from asdf have generally found mise to just be a faster, easier to use asdf.\n\n:::tip\nMake sure you have a look at [environments](/environments/) and [tasks](/tasks/) which\nare major portions of mise that have no asdf equivalent.\n:::\n\n## Migrate from asdf to mise\n\nIf you're moving from asdf to mise, please\nreview [#how-do-i-migrate-from-asdf](/faq.html#how-do-i-migrate-from-asdf) for guidance.\n\n## asdf in go (0.16+)\n\nasdf has gone through a rewrite in go. Because this is quite new as of this writing (2025-01-01),\nI'm going to keep information about 0.16+ asdf versions (which I call \"asdf-go\" vs \"asdf-bash\") in\nthis section and the rest of this doc will apply to asdf-bash (0.15 and below).\n\nIn terms of performance, mise is still faster than the go asdf, however the difference is much\ncloser. asdf is likely fast enough that the difference in overhead between asdf-go and mise may not\neven be enough to notice for you—after all there are plenty of people still using asdf-bash that\nclaim they don't even notice how slow it is (don't ask me how):\n\n![asdf vs mise exec performance comparison chart](./asdf-mise-exec-perf.jpg)\n\nI don't think performance is a good enough reason to switch though now that asdf-go is a thing. It's\na reason, but it's a minor one. The improved security in mise, better DX, and lack of reliance on\nshims are all more important than performance.\n\nGiven they went through the trouble of rewriting asdf—that's also an indication they want to keep\nworking on it (which is awesome that they're doing that btw). This does mean that some of what's\nwritten here may go out of date if they address some of the problems\nwith asdf.\n\n## Supply chain security\n\nasdf plugins are not secure. This is explained\nin [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md), but the quick explanation is\nthat asdf plugins involve shell code which can essentially do anything on your machine. It's\ndangerous code. What's worse is asdf plugins are rarely written by the tool vendor (who you need to\ntrust anyway to use the tool), which means for every asdf plugin you use you'll be trusting a random\ndeveloper to not go rogue and to not get hacked themselves and publish changes to a plugin with an\nexploit.\n\nmise still uses asdf plugins for some tools, but we're actively reducing that count as well as\nmoving things into the [mise-plugins org](https://github.com/mise-plugins). It looks like asdf has a\nsimilar model with their asdf-community org, but it isn't. asdf gives plugin authors commit access\nto their plugin in [asdf-community](https://github.com/asdf-community) when they move it in, which I\nfeel like defeats the purpose of having a dedicated org in the first place. By the end of 2025 I\nwould like for there to no longer be any asdf plugins in the registry that aren't owned by me.\n\nI've also been adopting extra security verification steps when vendors offer that ability such as\ngpg verification on node installs, and native Cosign/SLSA/Minisign/GitHub attestation verification for aqua tools.\n\n## UX\n\n![CleanShot 2024-01-28 at 12 36 20@2x](https://github.com/jdx/mise-docs/assets/216188/47f381d7-1566-4b78-9260-3b85a21dd6ec)\n\nSome commands are the same in asdf but others have been changed. Everything that's possible\nin asdf should be possible in mise but may use slightly different syntax. mise has more forgiving\ncommands,\nsuch as using fuzzy-matching, e.g.: `mise install node@20`. While in asdf you _can_ run\n`asdf install node latest:20`, you can't use `latest:20` in a `.tool-versions` file or many other\nplaces.\nIn `mise` you can use fuzzy-matching everywhere.\n\nasdf requires several steps to install a new runtime if the plugin isn't installed, e.g.:\n\n```sh\nasdf plugin add node\nasdf install node latest:20\nasdf local node latest:20\n```\n\nIn `mise` this can all be done in a single step which installs the plugin, installs the runtime,\nand sets the version:\n\n```sh\nmise use node@20\n```\n\nIf you have an existing `.tool-versions` file, or `.mise.toml`, you can install all plugins\nand runtimes with a single command:\n\n```sh\nmise install\n```\n\nI've found asdf to be particularly rigid and difficult to learn. It also made strange decisions like\nhaving `asdf list all` but `asdf latest --all` (why is one a flag and one a positional argument?).\n`mise` makes heavy use of aliases so you don't need to remember if it's `mise plugin add node` or\n`mise plugin install node`. If I can guess what you meant, then I'll try to get mise to respond\nin the right way.\n\nThat said, there are a lot of great things about asdf. It's the best multi-runtime manager out there\nand I've really been impressed with the plugin system. Most of the design decisions the authors made\nwere very good. I really just have 2 complaints: the shims and the fact it's written in Bash.\n\n## Performance\n\nasdf made (what I consider) a poor design decision to use shims that go between a call to a runtime\nand the runtime itself. e.g.: when you call `node` it will call an asdf shim file\n`~/.asdf/shims/node`,\nwhich then calls `asdf exec`, which then calls the correct version of node.\n\nThese shims have terrible performance, adding ~120ms to every runtime call. `mise activate` does not\nuse shims and instead\nupdates `PATH` so that it doesn't have any overhead when simply calling binaries. These shims are\nthe main reason that I wrote this. Note that in the demo GIF at the top of this README\nthat `mise` isn't actually used when calling `node -v` for this reason. The performance is\nidentical to running node without using mise.\n\nI don't think it's possible for asdf to fix these issues. The author of asdf did a great writeup\nof [performance problems](https://stratus3d.com/blog/2022/08/11/asdf-performance/). asdf is written\nin bash which certainly makes it challenging to be performant, however I think the real problem is\nthe\nshim design. I don't think it's possible to fix that without a complete rewrite.\n\nmise does call an internal command `mise hook-env` every time the directory has changed, but because\nit's written in Rust, this is very quick—taking ~10ms on my machine. 4ms if there are no changes,\n14ms if it's\na full reload.\n\ntl;dr: asdf adds overhead (~120ms) when calling a runtime, mise adds a small amount of overhead (~\n5ms)\nwhen the prompt loads.\n\n## Windows support\n\nasdf does not run on Windows at all. With mise, tools using non-asdf backends can support Windows.\nOf course, this means the tool\nvendor must provide Windows binaries but if they do, and the backend isn't asdf, the tool should\nwork on Windows.\n\n## Security\n\nasdf plugins are insecure. They typically are written by individuals with no ties to the vendors\nthat provide the underlying tool.\nWhere possible, mise does not use asdf plugins and instead uses backends like aqua and github which do\nnot require separate plugins.\n\nAqua tools include native Cosign/SLSA/Minisign/GitHub attestation verification built into mise.\nSee [SECURITY](https://github.com/jdx/mise/blob/main/SECURITY.md) for more information.\n\n## Command Compatibility\n\nIn nearly all places you can use the exact syntax that works in asdf, however this likely won't\nshow up in the help or CLI reference. If you're coming from asdf and comfortable with that way of\nworking you can almost always use the same syntax with mise, e.g.:\n\n```sh\nmise install node 20.0.0\nmise local node 20.0.0\n```\n\nUPDATE (2025-01-01): asdf-go (0.16+) actually got rid of `asdf global|local` entirely in favor of\n`asdf set` which we can't support since we already have a command named `mise set`. mise command\ncompatibility will likely not be as good with asdf-go 0.16+.\n\nIt's not recommended though. You almost always want to modify config files and install things so\n`mise use node@20` saves an extra command. Also, the \"@\" in the command is preferred since it allows\nyou to install multiple tools at once: `mise use|install node@20 node@18`. Also, there are edge\ncases\nwhere it's not possible—or at least very challenging—for us to definitively know which syntax is\nbeing\nused and so we default to mise-style. While there aren't many of these, asdf-compatibility is done\nas a \"best-effort\" in order to make transitioning from asdf feel familiar for those users who can\nrely on their muscle memory. Ensuring asdf-syntax works with everything is not a design goal.\n\n## Extra backends\n\nmise has support for backends other than asdf plugins. For example you can install CLIs\ndirectly from cargo and npm:\n\n```sh\nmise use -g cargo:ripgrep@14\nmise use -g npm:prettier@3\n```\n"
  },
  {
    "path": "docs/dev-tools/index.md",
    "content": "# Dev Tools\n\n> _Like [asdf](https://asdf-vm.com) (or [nvm](https://github.com/nvm-sh/nvm)\n> or [pyenv](https://github.com/pyenv/pyenv) but for any language), it manages dev tools like node,\n> python, cmake, terraform, and [hundreds more](/registry.html)._\n\n`mise` is a tool that manages installations of programming language runtimes and other tools for local development. For example, it can be used to manage multiple versions of Node.js, Python, Ruby, Go, etc. on the same machine.\n\nOnce [activated](/getting-started.html#activate-mise), mise can automatically switch between different versions of tools based on the directory you're in.\nThis means that if you have a project that requires Node.js 18 and another that requires Node.js 22, mise will automatically switch between them as you move between the two projects. See tools available for mise with in the [registry](/registry).\n\nTo know which tool version to use, mise will typically look for a `mise.toml` file in the current directory and its parents. To get an idea of how tools are specified, here is an example of a [mise.toml](/configuration.html) file:\n\n```toml [mise.toml]\n[tools]\nnode = '22'\npython = '3'\nruby = 'latest'\n```\n\nIt's also compatible\nwith asdf `.tool-versions` files as well as [idiomatic version files](/configuration#idiomatic-version-files) like `.node-version` and\n`.ruby-version`. See [configuration](/configuration) for more details.\n\nWhen specifying tool versions, you can also refer to environment variables defined in your config hierarchy,\nincluding values produced by env directives like `_.source`, `_.file`, or env modules. These are resolved\nbefore tool version templates are rendered.\n\n::: info\nmise is inspired by [asdf](https://asdf-vm.com) and can leverage asdf's\nvast [plugin ecosystem](https://github.com/mise-plugins/registry)\nunder the hood. However, [it is _much_ faster than asdf and has a more friendly user experience](./comparison-to-asdf).\n:::\n\n## How it works\n\nmise manages development tools through a sophisticated but user-friendly system that automatically handles tool installation, version management, and environment setup.\n\n### Tool Resolution Flow\n\nWhen you enter a directory or run a command, mise follows this process:\n\n1. **Configuration Discovery**: mise walks up the directory tree looking for configuration files (`mise.toml`, `.tool-versions`, etc.) and merges them hierarchically\n2. **Tool Resolution**: mise resolves version specifications (like `node@latest` or `python@3`) to specific versions using registries and version lists\n3. **Backend Selection**: mise chooses the appropriate [backend](/dev-tools/backend_architecture) to handle each tool (core, asdf, aqua, etc.)\n4. **Installation Check**: mise verifies if the required tool versions are installed, automatically installing missing ones\n5. **Environment Setup**: mise configures your `PATH` and environment variables to use the resolved tool versions\n\n### Environment Integration\n\nmise provides several ways to integrate with your development environment:\n\n**Automatic Activation**: With `mise activate`, mise hooks into your shell prompt and automatically updates your environment when you change directories:\n\n```bash\neval \"$(mise activate zsh)\"  # In your ~/.zshrc\ncd my-project               # Automatically loads mise.toml tools\n```\n\n**On-Demand Execution**: Use `mise exec` to run commands with mise's environment without permanent activation:\n\n```bash\nmise exec -- node my-script.js  # Runs with tools from mise.toml\n```\n\n**Shims**: mise can create lightweight wrapper scripts that automatically use the correct tool versions:\n\n```bash\nmise activate --shims  # Creates shims instead of modifying PATH\n```\n\n### Path Management\n\nmise modifies your `PATH` environment variable to prioritize the correct tool versions:\n\n```bash\n# Before mise\necho $PATH\n/usr/local/bin:/usr/bin:/bin\n\n# After mise activation in a project with node@20\necho $PATH\n/home/user/.local/share/mise/installs/node/20.11.0/bin:/usr/local/bin:/usr/bin:/bin\n```\n\nThis ensures that when you run `node`, you get the version specified in your project configuration, not a system-wide installation.\n\n### Configuration Hierarchy\n\nmise supports nested configuration that cascades from broad to specific settings:\n\n```bash\n~/.config/mise/config.toml      # Global defaults\n~/work/mise.toml                # Work-specific tools\n~/work/project/mise.toml        # Project-specific overrides\n~/work/project/.tool-versions   # Legacy asdf compatibility\n```\n\nEach level can override or extend the previous ones, giving you fine-grained control over tool versions across different contexts.\n\n## Tool Options\n\nTool options allow you to customize how tools are installed and configured. They support nested configurations for better organization, particularly useful for platform-specific settings.\n\n### Table Format (Recommended)\n\nThe cleanest way to specify nested options is using TOML tables:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"http:my-tool\".platforms]\nmacos-x64 = {\n  url = \"https://example.com/my-tool-macos-x64.tar.gz\",\n  checksum = \"sha256:abc123\",\n}\nlinux-x64 = {\n  url = \"https://example.com/my-tool-linux-x64.tar.gz\",\n  checksum = \"sha256:def456\",\n}\n```\n\n### Dotted Notation\n\nYou can also use dotted notation for simpler nested configurations:\n\n```toml\n[tools.\"http:my-tool\"]\nversion = \"1.0.0\"\nplatforms.macos-x64.url = \"https://example.com/my-tool-macos-x64.tar.gz\"\nplatforms.linux-x64.url = \"https://example.com/my-tool-linux-x64.tar.gz\"\nsimple_option = \"value\"\n```\n\n### Generic Nested Support\n\nAny backend can use nested options for organizing complex configurations:\n\n```toml\n[tools.\"custom:my-backend\"]\nversion = \"1.0.0\"\n\n[tools.\"custom:my-backend\".database]\nhost = \"localhost\"\nport = 5432\n\n[tools.\"custom:my-backend\".cache.redis]\nhost = \"redis.example.com\"\nport = 6379\n```\n\nInternally, nested options are flattened to dot notation (e.g., `platforms.macos-x64.url`, `database.host`, `cache.redis.port`) for backend access.\n\n### Tool postinstall commands\n\nRun a command immediately after a tool finishes installing by adding a `postinstall` field to that tool's configuration. This is separate from `[hooks].postinstall` and applies only to when a specific tool is installed.\n\n```toml\n[tools]\nnode = { version = \"22\", postinstall = \"corepack enable\" }\n```\n\nBehavior:\n\n- The command runs once the install completes successfully for that tool/version.\n- The tool's bin path is on PATH during the command, so you can invoke the installed tool directly.\n- Environment variables include `MISE_TOOL_INSTALL_PATH` pointing to the tool's install directory.\n- If the install fails, the `postinstall` command is not run.\n\n## OS-Specific Tools\n\nYou can restrict tools to specific operating systems using the `os` field:\n\n```toml\n[tools]\n# Only install on Linux and macOS\nripgrep = { version = \"latest\", os = [\"linux\", \"macos\"] }\n\n# Only install on Windows\n\"npm:windows-terminal\" = { version = \"latest\", os = [\"windows\"] }\n\n# Works with other options\n\"cargo:usage-cli\" = {\n    version = \"latest\",\n    os = [\"linux\", \"macos\"],\n    install_env = { RUST_BACKTRACE = \"1\" }\n}\n```\n\nThe `os` field accepts an array of operating system identifiers:\n\n- `\"linux\"` - All Linux distributions\n- `\"macos\"` - macOS (Darwin)\n- `\"windows\"` - Windows\n\nIf a tool specifies an `os` restriction and the current operating system is not in the list, mise will skip installing and using that tool.\n\n## Caching and Performance\n\nmise uses intelligent caching to minimize overhead:\n\n- **Version lists**: Cached daily to avoid repeated API calls\n- **Installation artifacts**: Cached downloads to speed up reinstalls\n- **Environment resolution**: Cached environment setups for faster shell prompts\n- **Plugin metadata**: Cached plugin information for quicker operations\n\nThis ensures that mise adds minimal latency to your daily development workflow.\n\n::: info\nAfter activating, mise will update env vars like PATH whenever the directory is changed or the prompt is _displayed_.\nSee the [FAQ](/faq#what-does-mise-activate-do).\n:::\n\nAfter activating, every time your prompt displays it will call `mise hook-env` to fetch new\nenvironment variables.\nThis should be very fast. It exits early if the directory wasn't changed or\n`mise.toml`/`.tool-versions` files haven't been modified.\n\n`mise` modifies `PATH` ahead of time so the runtimes are called directly. This means that calling a tool has zero overhead and commands like `which node` returns the real path to the binary.\nOther tools like asdf only support shim files to dynamically locate runtimes when they're called which adds a small delay and can cause issues with some commands. See [shims](/dev-tools/shims) for more information.\n\n## Common commands\n\nHere are some of the most important commands when it comes to working with dev tools. Click the\nheader\nfor each command to go to its reference documentation page to see all available flags/options and\nmore\nexamples.\n\n### [`mise use`](/cli/use)\n\nFor some users, `mise use` might be the only command you need to learn. It will do the following:\n\n- Install the tool's plugin if needed\n- Install the specified version\n- Set the version as active (i.e. update the `PATH`)\n- Update the current configuration file (`mise.toml` or `.tool-versions`)\n\n```shell\n> cd my-project\n> mise use node@24\n# download node, verify signature...\nmise node@24.x.x ✓ installed\nmise ~/my-project/mise.toml tools: node@24.x.x # mise.toml created/updated\n\n> which node\n~/.local/share/installs/node/24.x.x/bin/node\n```\n\n`mise use node@24` will install the latest version of node-24 and create/update the\n`mise.toml`\nconfig file in the local directory. Anytime you're in that directory, that version of `node` will be\nused.\n\n`mise use -g node@24` will do the same but update the [global config](/configuration.html#global-config-config-mise-config-toml) (~/.config/mise/config.toml) so\nunless there is a config file in the local directory hierarchy, node-24 will be the default version\nfor\nthe user.\n\n### [`mise install`](/cli/install)\n\n`mise install` will install but not activate tools—meaning it will download/build/compile the tool\ninto `~/.local/share/mise/installs` but you won't be able to use it without \"setting\" the version\nin a `.mise-toml` or `.tool-versions` file.\n\n::: tip\nIf you're coming from `asdf`, there is no need to also run `mise plugin add` to first install\nthe plugin, that will be done automatically if needed. Of course, you can manually install plugins\nif you wish or you want to use a plugin not in the default registry.\n:::\n\nThere are many ways it can be used:\n\n- `mise install node@20.0.0` - install a specific version\n- `mise install node@20` - install the latest version matching this prefix\n- `mise install node` - install whatever version of node currently specified in `mise.toml` (or other\n  config files)\n- `mise install` - install all plugins and tools specified in the config files\n\n### [`mise exec`|`mise x`](/cli/exec)\n\n`mise x` can be used for one-off commands using specific tools. e.g.: if you want to run a script\nwith python3.12:\n\n```sh\nmise x python@3.12 -- ./myscript.py\n```\n\nPython will be installed if it is not already. `mise x` will read local/global\n`.mise-toml`/`.tool-versions` files\nas well, so if you don't want to use `mise activate` or shims you can use mise by just prefixing\ncommands with\n`mise x --`:\n\n```sh\n$ mise use node@20\n$ mise x -- node -v\n20.x.x\n```\n\n::: tip\nIf you use this a lot, an alias can be helpful:\n\n```sh\nalias mx=\"mise x --\"\n```\n\n:::\n\nSimilarly, `mise run` can be used to [execute tasks](/tasks/) which will also activate the mise\nenvironment with all of your tools.\n\n## Auto-Install Mechanisms\n\nmise provides several mechanisms to automatically install missing tools or versions as needed. Below, these are grouped by how and when they are triggered, with relevant settings for each. All mechanisms require the global [auto_install](/configuration/settings.html#auto_install) setting to be enabled (**all auto_install settings are enabled by default**).\n\n### On-Demand Execution ([`mise x`](/cli/exec), [`mise r`](/cli/run))\n\nWhen you run a command like [`mise x`](/cli/exec) or [`mise r`](/cli/run), mise will automatically install any missing tool versions required to execute the command.\n\n- **When it triggers:** Whenever you use [`mise x`](/cli/exec) or [`mise r`](/cli/run) with a tool/version that is not yet installed.\n- **How to control:**\n  - Setting: [`exec_auto_install`](/configuration/settings.html#exec_auto_install) (default: true)\n  - Setting: [`task_auto_install`](/configuration/settings.html#task_auto_install) (default: true)\n\n### Command Not Found Handler (Shell Integration)\n\nIf you type a command in your shell (e.g., `node`) and it is not found, mise can attempt to auto-install the missing tool version if it knows which tool provides that binary.\n\n- **When it triggers:** When a command is not found in the shell and the handler is enabled.\n- **How to control:**\n  - Setting: [`not_found_auto_install`](/configuration/settings.html#not_found_auto_install) (default: true)\n- **Limitation:** Only works for tools that already have at least one version installed, since mise cannot know which tool provides a binary otherwise.\n\n::: tip\nDisable auto_install for specific tools by setting [`auto_install_disable_tools`](/configuration/settings.html#auto_install_disable_tools) to a list of tool names.\n:::\n"
  },
  {
    "path": "docs/dev-tools/mise-lock.md",
    "content": "# mise.lock Lockfile\n\n`mise.lock` is a lockfile that pins exact versions and checksums of tools for reproducible environments. Lockfiles are not created automatically—you must run `mise lock` to generate them. Once a lockfile exists, mise will keep it updated as tools are installed or upgraded.\n\n## Overview\n\nThe lockfile serves similar purposes to `package-lock.json` in npm or `Cargo.lock` in Rust:\n\n- **Reproducible builds**: Ensures everyone on your team uses exactly the same tool versions\n- **Security**: Verifies tool integrity with checksums when supported by the backend\n- **Version pinning**: Locks tools to specific versions while allowing flexibility in `mise.toml`\n- **Avoids API rate limits**: By storing download URLs, future installs use the lockfile and do not need to call GitHub (or other providers), avoiding rate limits and the need for `GITHUB_TOKEN` in most cases\n\n## Enabling Lockfiles\n\nLockfiles are controlled by the `lockfile` setting:\n\n```sh\n# Enable lockfiles globally\nmise settings lockfile=true\n\n# Or set in mise.toml\n[settings]\nlockfile = true\n```\n\n## How It Works\n\n1. **Lockfile Updates**: Once a `mise.lock` file exists, running `mise install` or `mise use` updates it with the exact versions installed\n2. **Version Resolution**: If a `mise.lock` exists, mise will prefer locked versions over version ranges in `mise.toml`\n3. **Checksum Verification**: For supported backends, mise stores and verifies checksums of downloaded tools\n\n## File Format\n\n`mise.lock` is a TOML file with a platform-based format that organizes asset information by platform:\n\n```toml\n# Example mise.lock\n[[tools.node]]\nversion = \"20.11.0\"\nbackend = \"core:node\"\n\n[tools.node.platforms.linux-x64]\nchecksum = \"sha256:a6c213b7a2c3b8b9c0aaf8d7f5b3a5c8d4e2f4a5b6c7d8e9f0a1b2c3d4e5f6a7\"\nsize = 23456789\nurl = \"https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-x64.tar.xz\"\n\n[[tools.python]]\nversion = \"3.11.7\"\nbackend = \"core:python\"\n\n[tools.python.platforms.linux-x64]\nchecksum = \"sha256:def456...\"\nsize = 12345678\n\n# Tool with backend-specific options\n[[tools.ripgrep]]\nversion = \"14.1.1\"\nbackend = \"aqua:BurntSushi/ripgrep\"\noptions = { exe = \"rg\" }\n\n[tools.ripgrep.platforms.linux-x64]\nchecksum = \"sha256:4cf9f2741e6c465ffdb7c26f38056a59e2a2544b51f7cc128ef28337eeae4d8e\"\nsize = 1234567\n\n```\n\n### Platform Information\n\nEach platform in a tool's `[tools.name.platforms]` section uses a key format like `\"os-arch\"` (e.g., `\"linux-x64\"`, `\"macos-arm64\"`) and can contain:\n\n- **`checksum`** (optional): SHA256 or Blake3 hash for integrity verification\n- **`size`** (optional): File size in bytes for download validation\n- **`url`** (optional): Original download URL for reference or re-downloading\n\n### Tool Entry Fields\n\nEach tool entry (`[[tools.name]]`) can contain:\n\n- **`version`** (required): The exact version of the tool\n- **`backend`** (optional): The backend used to install the tool (e.g., `core:node`, `aqua:BurntSushi/ripgrep`)\n- **`options`** (optional): Backend-specific options that identify the artifact (e.g., `{exe = \"rg\", matching = \"musl\"}`)\n- **`platforms`** (optional): Platform-specific metadata (checksums, URLs, sizes)\n\n### Platform Keys\n\nThe platform key format is generally `os-arch` but can be customized by backends:\n\n- **Standard format**: `linux-x64`, `macos-arm64`, `windows-x64`\n- **Backend-specific**: Some backends like Java may use more specific platform identifiers\n- **Tool-specific**: Backends like `ubi` may include additional tool-specific information in the platform key\n\n## Environment-Specific Lockfiles\n\nWhen using [environment-specific configuration files](/configuration/environments) (e.g., `mise.test.toml`), each environment gets its own lockfile:\n\n| Config file            | Lockfile               |\n| ---------------------- | ---------------------- |\n| `mise.toml`            | `mise.lock`            |\n| `mise.test.toml`       | `mise.test.lock`       |\n| `mise.staging.toml`    | `mise.staging.lock`    |\n| `mise.local.toml`      | `mise.local.lock`      |\n| `mise.test.local.toml` | `mise.test.local.lock` |\n\nFor example, with `MISE_ENV=test`:\n\n```sh\nMISE_ENV=test mise lock  # creates mise.lock AND mise.test.lock\n```\n\nTools from `mise.toml` go to `mise.lock`, tools from `mise.test.toml` go to `mise.test.lock`.\n\n**Resolution**: When `MISE_ENV=test`, mise reads `mise.test.lock` for tools defined in `mise.test.toml` and `mise.lock` for tools in `mise.toml`. Environment-specific lockfiles are strictly scoped to their corresponding config — they only contain tools defined in that config.\n\nThis design means CI environments that don't set `MISE_ENV` only depend on `mise.lock`, so dev tool version bumps in `mise.dev.lock` won't invalidate CI caches.\n\nBoth `mise.lock` and `mise.<env>.lock` files should be committed to version control. `mise.local.lock` and `mise.<env>.local.lock` should be gitignored alongside their corresponding config files.\n\n## Local Lockfiles\n\nTools defined in `mise.local.toml` (which is typically gitignored) use a separate `mise.local.lock` file. This keeps local tool configurations separate from the committed lockfile.\n\n```sh\n# mise.local.toml tools go to mise.local.lock\nmise use --path mise.local.toml node@22\n\n# Regular mise.toml tools go to mise.lock\nmise use --path mise.toml node@20\n```\n\nUse `mise lock --local` to update the local lockfile for all platforms:\n\n```sh\nmise lock --local              # update mise.local.lock\nmise lock --local node python  # update specific tools in mise.local.lock\n```\n\n## Strict Lockfile Mode\n\nThe `locked` setting enforces that all tools have pre-resolved URLs in the lockfile before installation. This prevents API calls to GitHub, aqua registry, etc., ensuring fully reproducible installations.\n\n```sh\n# Enable strict mode\nmise settings locked=true\n\n# Or via environment variable\nMISE_LOCKED=1 mise install\n```\n\nWhen enabled, `mise install` will fail if a tool doesn't have a URL for the current platform in the lockfile. To fix this, first populate the lockfile with URLs:\n\n```sh\nmise lock                    # generate URLs for all platforms\nmise lock --platform linux-x64,macos-arm64  # or specific platforms\n```\n\nThis is useful for CI environments where you want to guarantee reproducible builds without any external API dependencies.\n\n## Workflow\n\n### Initial Setup\n\n```sh\n# Generate the lockfile\nmise lock\n\n# Install tools using locked versions\nmise install\n```\n\n### Daily Usage\n\n```sh\n# Install exact versions from lockfile\nmise install\n\n# Update tools and lockfile\nmise upgrade\n```\n\n### Updating Versions\n\nWhen you want to update tool versions:\n\n```sh\n# Update tool version in mise.toml\nmise use node@24\n\n# This will update both the installation and mise.lock\n```\n\n## Backend Support\n\nBackend support for lockfile features varies:\n\n- ✅ **Full support** (version + checksum + size + URL): `aqua`, `http`, `github`, `gitlab`\n  - _Provenance support_: `aqua`, `github`, `core:ruby` (precompiled binaries), `core:zig` (install-time)\n- ⚠️ **Partial support** (version + URL + provenance): `vfox` (tool plugins only)\n- ⚠️ **Partial support** (version + checksum + size): `ubi`\n- 📝 **Basic support** (version + checksum): `core` (some tools)\n- 📝 **Version only**: `asdf`, `npm`, `cargo`, `pipx`\n- 📝 **Planned**: More backends will add full asset tracking support over time\n\n## Best Practices\n\n### Version Control\n\n```sh\n# Always commit the lockfile\ngit add mise.lock\ngit commit -m \"Update tool versions\"\n```\n\n### Team Workflow\n\n1. **Team Lead**: Updates `mise.toml` with new version ranges\n2. **Team Lead**: Runs `mise install` to update `mise.lock`\n3. **Team Lead**: Commits both files\n4. **Team Members**: Pull changes and run `mise install` to get exact versions\n\n### CI/CD\n\n```yaml\n# Example GitHub Actions\n- name: Install tools\n  run: |\n    mise install  # Uses exact versions from mise.lock\n\n- name: Cache lockfile\n  uses: actions/cache@v5\n  with:\n    key: mise-lock-${{ hashFiles('mise.lock') }}\n```\n\n## Troubleshooting\n\n### Regenerating Checksums\n\nIf checksums become invalid or you need to regenerate them:\n\n```sh\n# Remove all tools and reinstall\nmise uninstall --all\nmise install\n```\n\n### Lockfile Conflicts\n\nWhen merging branches with different lockfiles:\n\n1. Resolve conflicts in `mise.lock`\n2. Run `mise install` to verify everything works\n3. Commit the resolved lockfile\n\n### Disabling for Specific Projects\n\n```toml\n# In project's mise.toml\n[settings]\nlockfile = false\n```\n\n## Migration from Other Tools\n\n### From asdf\n\n```sh\n# Convert .tool-versions to mise.toml\nmise config generate\n\n# Enable lockfiles and generate the lockfile\nmise settings lockfile=true\nmise lock\nmise install\n```\n\n### From package.json engines\n\n```sh\n# Set versions based on package.json\nmise use node@$(jq -r '.engines.node' package.json)\n```\n\n## See Also\n\n- [Configuration Settings](/configuration/settings) - All available settings\n- [Tool Version Management](/dev-tools/) - How tool versions work\n- [Backends](/dev-tools/backends/) - Backend-specific checksum support\n"
  },
  {
    "path": "docs/dev-tools/prepare.md",
    "content": "# Prepare <Badge type=\"warning\" text=\"experimental\" />\n\nThe `mise prepare` command ensures project dependencies are ready by hashing source files\n(e.g., `package-lock.json`) and running install commands when changes are detected.\n\n## Quick Start\n\n```bash\n# Enable experimental features\nexport MISE_EXPERIMENTAL=1\n\n# Run all applicable prepare steps\nmise prepare\n\n# Or use the alias\nmise prep\n```\n\n## Configuration\n\nConfigure prepare providers in `mise.toml`:\n\n```toml\n# Built-in npm provider (auto-detects lockfile)\n[prepare.npm]\nauto = true  # Auto-run before mise x/run\n\n# Built-in providers for other package managers\n[prepare.yarn]\n[prepare.pnpm]\n[prepare.bun]\n[prepare.go]\n[prepare.pip]\n[prepare.poetry]\n[prepare.uv]\n[prepare.bundler]\n[prepare.composer]\n\n# Custom provider\n[prepare.codegen]\nauto = true\nsources = [\"schema/*.graphql\"]\noutputs = [\"src/generated/\"]\nrun = \"npm run codegen\"\n\n# Disable specific providers\n[prepare]\ndisable = [\"npm\"]\n```\n\n## Built-in Providers\n\nmise includes built-in providers for common package managers:\n\n| Provider   | Sources                                 | Outputs               | Command                              |\n| ---------- | --------------------------------------- | --------------------- | ------------------------------------ |\n| `npm`      | `package.json`, `package-lock.json`     | `node_modules/`       | `npm install`                        |\n| `yarn`     | `package.json`, `yarn.lock`             | `node_modules/`       | `yarn install`                       |\n| `pnpm`     | `package.json`, `pnpm-lock.yaml`        | `node_modules/`       | `pnpm install`                       |\n| `bun`      | `package.json`, `bun.lock`, `bun.lockb` | `node_modules/`       | `bun install`                        |\n| `go`       | `go.mod`                                | `vendor/` or `go.sum` | `go mod vendor` or `go mod download` |\n| `pip`      | `requirements.txt`                      | `.venv/`              | `pip install -r requirements.txt`    |\n| `poetry`   | `pyproject.toml`, `poetry.lock`         | `.venv/`              | `poetry install`                     |\n| `uv`       | `pyproject.toml`, `uv.lock`             | `.venv/`              | `uv sync`                            |\n| `bundler`  | `Gemfile`, `Gemfile.lock`               | `vendor/bundle/`      | `bundle install`                     |\n| `composer` | `composer.json`, `composer.lock`        | `vendor/`             | `composer install`                   |\n\nBuilt-in providers are only active when explicitly configured in `mise.toml` and their lockfile exists.\n\n## Custom Providers\n\nCreate custom providers for project-specific build steps:\n\n```toml\n[prepare.codegen]\nsources = [\"schema/*.graphql\", \"codegen.yml\"]\noutputs = [\"src/generated/\"]\nrun = \"npm run codegen\"\ndescription = \"Generate GraphQL types\"\n\n[prepare.prisma]\nsources = [\"prisma/schema.prisma\"]\noutputs = [\"node_modules/.prisma/\"]\nrun = \"npx prisma generate\"\n```\n\n### Provider Options\n\n| Option        | Type     | Description                                                               |\n| ------------- | -------- | ------------------------------------------------------------------------- |\n| `auto`        | bool     | Auto-run before `mise x` and `mise run` (default: false)                  |\n| `sources`     | string[] | Files/patterns to check for changes                                       |\n| `outputs`     | string[] | Files/directories that must exist for the provider to be considered fresh |\n| `run`         | string   | Command to run when stale                                                 |\n| `env`         | table    | Environment variables to set                                              |\n| `dir`         | string   | Working directory for the command                                         |\n| `description` | string   | Description shown in output                                               |\n| `depends`     | string[] | Other provider names that must complete before this one runs              |\n| `timeout`     | string   | Timeout for the run command, e.g., `\"30s\"`, `\"5m\"` (default: no timeout)  |\n\n## Freshness Checking\n\nmise uses blake3 content hashing to determine if sources have changed since the last\nsuccessful run. Hashes are stored in `.mise/prepare-state.toml`.\n\n1. Compute blake3 hashes of all source files\n2. Compare against stored hashes from the last successful run\n3. If any file was added, removed, or changed, the provider is stale\n\nThis means:\n\n- If you modify `package-lock.json`, `node_modules/` will be considered stale\n- If `node_modules/` doesn't exist, the provider is always stale\n- If sources don't exist, the provider is considered fresh (nothing to do)\n- On first run (no stored state), the provider is always considered stale\n\n## Auto-Prepare\n\nWhen `auto = true` is set on a provider, it will automatically run before:\n\n- `mise run` (task execution)\n- `mise x` (exec command)\n\nThis ensures dependencies are always up-to-date before running tasks or commands.\n\nTo skip auto-prepare for a single invocation:\n\n```bash\nmise run --no-prepare build\nmise x --no-prepare -- npm test\n```\n\n## Staleness Warnings\n\nWhen using `mise activate`, mise will warn you if any auto-enabled providers have stale dependencies:\n\n```\nmise WARN prepare: npm may need update, run `mise prep`\n```\n\nThis can be disabled with:\n\n```toml\n[settings]\nstatus.show_prepare_stale = false\n```\n\n## CLI Usage\n\n```bash\n# Run all applicable prepare steps\nmise prepare\n\n# Run only a specific provider\nmise prepare npm\n\n# Show why a provider is fresh or stale\nmise prepare npm --explain\n\n# Show what would run without executing\nmise prepare --dry-run\n\n# Force run even if outputs are fresh\nmise prepare --force\n\n# List available prepare providers\nmise prepare --list\n\n# Skip specific providers\nmise prepare --skip npm\n```\n\n## Dependencies\n\nProviders can declare dependencies on other providers using the `depends` field. A provider\nwill wait for all its dependencies to complete successfully before running.\n\n```toml\n[prepare.uv]\nauto = true\n\n[prepare.ansible-galaxy]\nauto = true\ndepends = [\"uv\"]\nrun = \"ansible-galaxy install -f requirements.yml\"\nsources = [\"requirements.yml\"]\noutputs = [\".galaxy-installed\"]\n```\n\nIn this example, `ansible-galaxy` will wait for `uv` to finish before starting.\n\nProviders without `depends` run in parallel as before. If a dependency fails, all providers\nthat depend on it are skipped. Circular dependencies are detected and the affected providers\nare skipped with a warning.\n\n## Parallel Execution\n\nPrepare providers run in parallel, respecting the `jobs` setting for concurrency limits.\nThis speeds up preparation when multiple providers need to run (e.g., both npm and pip).\nProviders with `depends` will wait for their dependencies to complete before starting,\nwhile independent providers run concurrently.\n\n```toml\n[settings]\njobs = 4  # Run up to 4 providers in parallel\n```\n\n## Example: Full-Stack Project\n\n```toml\n# mise.toml for a project with Node.js frontend and Python backend\n\n[prepare.npm]\nauto = true\n\n[prepare.poetry]\nauto = true\n\n[prepare.prisma]\nauto = true\ndepends = [\"npm\"]  # needs node_modules first\nsources = [\"prisma/schema.prisma\"]\noutputs = [\"node_modules/.prisma/\"]\nrun = \"npx prisma generate\"\n\n[prepare.frontend-codegen]\ndepends = [\"npm\"]  # needs node_modules first\nsources = [\"schema.graphql\", \"codegen.ts\"]\noutputs = [\"src/generated/\"]\nrun = \"npm run codegen\"\n```\n\nRunning `mise prep` will install npm and poetry dependencies in parallel, then run prisma\nand frontend-codegen (also in parallel, since they only depend on npm, not each other).\n"
  },
  {
    "path": "docs/dev-tools/shims.md",
    "content": "# Shims\n\nThere are several ways for the `mise` context (dev tools, environment variables) to be loaded into your shell:\n\n- `mise activate` (also called [\"mise PATH activation\"](#path-activation)) where `mise` updates your `PATH` and other environment variables every time your prompt is displayed.\n- [`mise activate --shims`](#mise-activate-shims) which uses shims to load dev tools.\n- Using [`mise x|exec`](/cli/exec) or [`mise r|run`](/cli/run) for ad-hoc commands or tasks (see [\"neither shims nor PATH\"](#neither-shims-nor-path)).\n\nThis page will help you understand the differences between these methods and how to use them. In particular, it will help you decide if you should use shims or `mise activate` in your shell.\n\n## Overview of the `mise` activation methods {#overview}\n\n### PATH activation {#path-activation}\n\nMise's \"PATH\" activation method updates environment variables every time the prompt is displayed. In particular, it updates the `PATH` environment variable, which is used by your shell to search for the programs it can run.\n\n::: info\nThis is the method used when you add the `echo 'eval \"$(mise activate bash)\"' >> ~/.bashrc` line to your shell rc file (in this case, for bash).\n:::\n\nFor example, by default, your `PATH` variable might look like this:\n\n```sh\necho $PATH\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nIf using [`mise activate`](/cli/activate.html), `mise` will automatically add the required tools to `PATH`.\n\n```sh\nPATH=\"$HOME/.local/share/mise/installs/python/3.13.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\"\n```\n\nIn this example, the python `bin` directory was added at the beginning of the `PATH`, making it available in the current shell session.\n\nWhile the `PATH` design of `mise` works great in most cases, there are some situations where `shims` are preferable. This is the case when you are not using an interactive shell (for example, when using `mise` in an IDE or a script).\n\n### Shims {#mise-activate-shims}\n\n::: warning\n`mise activate --shims` does not support all the features of `mise activate`.<br>\nSee [shims vs path](/dev-tools/shims.html#shims-vs-path) for more information.\n:::\n\nWhen using shims, `mise` places small executables (`shims`) in a directory that is included in your `PATH`. You can think of `shims` as symlinks to the mise binary that intercept commands and load the appropriate context.\n\n```sh\nls -l ~/.local/share/mise/shims/node\n# [...] ~/.local/share/mise/shims/node -> ~/.local/bin/mise\n```\n\nBy default, the shim directory is located at `~/.local/share/mise/shims`. When installing a tool (for example, `node`), `mise` will add some entries for every binary provided by this tool in the `shims` directory (for example, `~/.local/share/mise/shims/node`).\n\n```sh\nmise use -g node@20\nnpm install -g prettier@3.1.0\n\n~/.local/share/mise/shims/node -v\n# v20.0.0\n~/.local/share/mise/shims/prettier -v\n# 3.1.0\n```\n\nTo avoid calling `~/.local/share/mise/shims/node`, you can add the `shims` directory to your `PATH`.\n\n```sh\nexport PATH=\"$HOME/.local/share/mise/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\"\n```\n\nThis will effectively make all dev tools available in your current shell session as well as non-interactive environments.\n\n::: tip\n[`mise activate --shims`](/cli/activate.html#shims) is a shorthand for adding the shims directory to PATH.\n:::\n\n## How to add mise shims to PATH\n\nThe recommended way to add `shims` to `PATH` is to call [`mise activate --shims`](/cli/activate.html#shims) in one of your shell initialization file. For example, you can do the following:\n\n::: code-group\n\n```sh [bash]\n# note that bash will read from ~/.profile or ~/.bash_profile if the latter exists\n# ergo, you may want to check to see which is defined on your system and only append to the existing file\necho 'eval \"$(mise activate bash --shims)\"' >> ~/.bash_profile # this sets up non-interactive sessions\necho 'eval \"$(mise activate bash)\"' >> ~/.bashrc       # this sets up interactive sessions\n```\n\n```sh [zsh]\necho 'eval \"$(mise activate zsh --shims)\"' >> ~/.zprofile # this sets up non-interactive sessions\necho 'eval \"$(mise activate zsh)\"' >> ~/.zshrc    # this sets up interactive sessions\n```\n\n```sh [fish]\necho 'mise activate fish --shims | source' >> ~/.config/fish/config.fish\necho 'mise activate fish | source' >> ~/.config/fish/fish.config\n```\n\n:::\n\nIn this example, we use [`mise activate --shims`](/cli/activate.html#shims) in the non-interactive shell configuration file (like `.bash_profile` or `.zprofile`) and `mise activate` in the interactive shell configuration file (like `.bashrc` or `.zshrc`)\n\n::: info\n[`mise activate`](/cli/activate.html) will remove the shims directory from the `PATH` so it's fine\nto call [`mise activate --shims`](/cli/activate.html#shims) in your shell profile file then later call `mise activate` in an interactive session.\n:::\n\n- You can also decide to use only `shims` if you prefer, though this comes with some [limitations](/dev-tools/shims.html#shims-vs-path).\n- An alternative to [`mise activate --shims`](/cli/activate.html#shims) is to use `export PATH=\"$HOME/.local/share/mise/shims:$PATH\"`. This can be helpful if `mise` is not yet available at that point in time.\n\n### mise reshim\n\nTo force `mise` to update the content of the `shims` directory, you can manually call `mise reshim`.\n\nNote that `mise` already runs a reshim anytime a tool is installed/updated/removed, so you don't need to use it for those scenarios. It is also done by default when using most tools such as `npm`.\n\n`mise reshim` only creates/removes the shims. Some users sometimes use it as a\n\"fix it\" button, but it is only necessary if `~/.local/share/mise/shims` doesn't contain something it should.\n\nDo not add additional executable in the `mise` directory, `mise` will delete them with the next reshim.\n\n## Shims vs PATH {#shims-vs-path}\n\nThe following features are affected when shims are used **instead** of [PATH activation](#path-activation):\n\n- [Env vars](/environments/) defined in mise are only available to mise tools\n- Most [hooks](/hooks.html) won't trigger\n- The unix `which` command points to the shim, obscuring the real executable\n\nIn general, using PATH (`mise activate`) instead of shims for _interactive_ situations is recommended.\n\nThe way `activate` works is every time the prompt is displayed, mise-en-place will determine what PATH and other\nenv vars should be and export them. This is why it doesn't work well for non-interactive situations like scripts. The prompt never gets displayed so you have to manually call `mise hook-env` to get mise to update\nthe env vars. (though there are exceptions, see [hook on `cd`](#hook-on-cd))\n\n### Env vars and shims\n\nA downside of shims is that the environment variables are only loaded when a shim is called. This means if you\nset an [environment variable](/environments/) in `mise.toml`, it will only be used when a shim is called.\n\nThe following example only works under `mise activate`:\n\n```sh\n$ mise set NODE_ENV=production\n$ echo $NODE_ENV\nproduction\n```\n\nBut this will work in either:\n\n```sh\n$ mise set NODE_ENV=production\n$ node -p process.env.NODE_ENV\nproduction\n```\n\nAlso, [`mise x|exec`](/cli/exec.html) and [`mise r|run`](/cli/run.html) can be used to get the environment even if you don't need any mise tools:\n\n```sh\n$ mise set NODE_ENV=production\n$ mise x -- bash -c \"echo \\$NODE_ENV\"\nproduction\n$ mise r some_task_that_uses_NODE_ENV\nproduction\n```\n\n::: tip\nIn general, [tasks](/tasks/) are a good way to ensure that the mise environment is always loaded.\n:::\n\n### Hooks and shims\n\nThe [hooks](/hooks.html) `cd`, `enter`, `exit`, and `watch_files` only trigger with `mise activate`. However `preinstall` and `postinstall` still work with shims because they don't require shell integration.\n\n### `which`\n\n`which` is a command that a lot of users find great value in. Using shims effectively \"break\" `which` and cause it to show the location of the shim. A workaround is to use `mise which`, which will show the actual location. Some users prefer the \"cleanliness\" of running `which node` and getting back a real path with a version number inside of it. e.g:\n\n```sh\n$ which node\n~/.mise/installs/node/20/bin/node\n```\n\n### Performance\n\nTruthfully, you're probably not going to notice a difference in performance when using shims vs. using `mise activate`.\n\n- Since mise runs every time the prompt is displayed with `mise activate`, you'll pay a few ms cost\n  every time the prompt is displayed. Regardless of whether you're actively using a mise tool, you'll\n  pay that penalty every time you run any command. It does have some short-circuiting logic to make it faster\n  if there are no changes, but it doesn't help much unless you have a very complex setup.\n- shims have basically the same performance profile but run when the shim is called. This makes some situations\n  better, and some worse.\n\nIf you are calling a shim from within a bash script like this:\n\n```sh\nfor i in {1..500}; do\n    node script.js\ndone\n```\n\nYou'll pay the mise penalty every time you call it within the loop. However, if you did the same thing\nbut call a subprocess from within a shim (say, node creating a node subprocess), you will _not_ pay a new\npenalty. This is because when a shim is called, mise sets up the environment with PATH for all tools and\nthose PATH entries will be before the shim directory.\n\nIn other words, which is better in terms of performance just depends on how you're calling mise. Really\nthough most users will not notice a few ms lag on their terminal caused by `mise activate`.\n\nThe only difference between these would be that using `hook-env` you will need to call\nit again if you change directories but with shims that won't be necessary. The shims directory will be\nremoved by `mise activate` automatically so you won't need to worry about dealing with shims in your PATH.\n\n## Neither shims nor PATH {#neither-shims-nor-path}\n\nThere are many ways to load the mise environment that don't require either, chiefly:\n[`mise x|exec`](/cli/exec.html), [`mise r|run`](/cli/run.html) or [`mise en`](/cli/en.html).\n\nThese will both load all the tools and env vars before executing something. This might\nbe ideal because you don't need to modify your shell rc file at all and the environment is always loaded\nexplicitly. Some might find this is a \"clean\" way of working.\n\nThe obvious downside is that anytime one wants to use `mise` they need to prefix it with `mise exec|run`. Though, you can easily alias them to `mx|mr`.\n\n- This is what one prefers if they like things to be precise over \"easy\".\n- Or perhaps if you're just wanting to use mise on a single project because that's what your team uses and prefer\n  not to use it to manage anything else on your system. Using a shell extension for that use-case\n  would be overkill.\n\n::: info This is the method Jeff uses\n\n> Part of the reason for this is I often need to make sure I'm on my development version of mise. If you\n> work on mise yourself I would recommend working in a similar way and disabling `mise activate` or shims\n> while you are working on it.\n>\n> See [How I use mise](https://mise.jdx.dev/how-i-use-mise.html) for more information.\n\n:::\n\n## Hook on `cd` {#hook-on-cd}\n\nFor some shells (`bash`, `zsh`, `fish`, `xonsh`), `mise` hooks into the `cd` command, while in others, it only runs when the prompt is displayed. This relies on `chpwd` in `zsh`, `PROMPT_COMMAND` in `bash`, `fish_prompt` in `fish`, and `on_chdir` in `xonsh`.\n\nThe upside is that it doesn't run as frequently but since mise is written in Rust the cost for executing\nmise is negligible (a few ms).\n\n::: details Running several commands in a single line\n\nIf you run a set of commands in a single line like the following:\n\n```sh\ncd ~\ncd ~/src/proj1 && node -v && cd ~/src/proj2 && node -v\n```\n\nIf using `mise activate`, in shell without hook on cd, this will use the tools from `~`, not from `~/src/proj1` or `~/src/proj2` even after the directory changed.\n\nThis is because, in these shells `mise` runs just before your prompt gets displayed whereas in others, it hooks on `cd`. Note that shims _will_ always work with the inline example above.\n\n:::\n\n## Using mise in rc files\n\nrc files like `.zshrc` are unusual. It's a script but also runs only for interactive sessions. If you need\nto access tools provided by mise inside of an rc file you have 2 options:\n\n::: code-group\n\n```sh [hook-env]\neval \"$(mise activate zsh)\"\neval \"$(mise hook-env -s zsh)\"\nnode some_script.js\n```\n\n```sh [shims]\neval \"$(mise activate zsh --shims)\" # should be first\neval \"$(mise activate zsh)\"\nnode some_script.js\n```\n\n:::\n"
  },
  {
    "path": "docs/dev-tools/tool-stubs.md",
    "content": "# Tool Stubs\n\nTool stubs allow you to create executable files with embedded TOML configuration for tool execution. They provide a convenient way to define tool versions, backends, and execution parameters directly within executable scripts. They are also a good way to have some tools in mise lazy-load since the tools are only fetched when called and not when calling something like `mise install`.\n\nThis feature is inspired by [dotslash](https://github.com/facebook/dotslash), which pioneered the concept of executable files with embedded configuration for portable tool execution.\n\n## Overview\n\nA tool stub is an executable file that begins with a shebang line pointing to `mise tool-stub` and contains TOML configuration specifying which tool to execute and how to execute it. When the stub is run, mise automatically installs the specified tool version (if needed) and executes it with the provided arguments.\n\nTool stubs can use any mise backend but because they default to http—and http backend tools have things like urls and don't require a version—the http stubs look a bit different than non-http stubs.\n\n::: tip\nTool stubs are particularly useful for adding less-commonly used tools to your mise setup. Since tools are only installed when their stub is first executed, you can define many tools without the overhead of installing them all upfront. This is perfect for specialized tools, testing utilities, or project-specific binaries that you might not use every day.\n:::\n\n## Tool (non-http) Stubs\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n# Optional comment describing the tool\n\nversion = \"1.0.0\"\ntool = \"python\"\nbin = \"python\"\n```\n\n::: info Why use `env -S`?\nThe `-S` flag tells `env` to split the command line on spaces, allowing multiple arguments to be passed to the interpreter. This is necessary because shebangs on Unix systems traditionally only support a single argument after the interpreter path. Using `env -S mise tool-stub` allows the shebang to work correctly by splitting it into `env` → `mise` → `tool-stub`.\n:::\n\n## Configuration Fields\n\nTool stub configuration is essentially a subset of what can be done in `mise.toml` [tools] sections, with the addition of a `tool` field to specify which tool to use. All the same options available for tool configuration in `mise.toml` are supported in tool stubs.\n\n### Optional Fields\n\n- `tool` - Explicit tool name or backend specification (e.g., \"python\", \"github:cli/cli\"). This is the only field unique to tool stubs - it specifies which tool entry from the configuration to use. If omitted and a `url` field is present, defaults to the HTTP backend.\n- `version` - The version of the tool to use\n- `bin` - The binary name to execute within the tool (defaults to the stub filename)\n\n## HTTP Stubs\n\nFor multi-platform tarballs:\n\n```toml\n#!/usr/bin/env -S mise tool-stub\nurl = \"https://example.com/releases/1.0.0/tool-linux-x64.tar.gz\"\n```\n\nFor platform-specific tarballs:\n\n```toml\n#!/usr/bin/env -S mise tool-stub\n[platforms.linux-x64]\nurl = \"https://example.com/releases/1.0.0/tool-linux-x64.tar.gz\"\n\n[platforms.darwin-arm64]\nurl = \"https://example.com/releases/1.0.0/tool-macos-arm64.tar.gz\"\n```\n\n### Platform-Specific Binary Paths\n\nDifferent platforms may have different binary structures or names. You can specify platform-specific `bin` fields when the binary path differs between platforms:\n\n```toml\n#!/usr/bin/env -S mise tool-stub\n# Global bin field used when platforms have the same structure\nbin = \"bin/tool\"\n\n[platforms.linux-x64]\nurl = \"https://example.com/tool-linux.tar.gz\"\n# Uses global bin field: \"bin/tool\"\n\n[platforms.windows-x64]\nurl = \"https://example.com/tool-windows.zip\"\nbin = \"tool.exe\"  # Platform-specific binary for Windows\n```\n\nThe tool stub generator automatically detects when platforms have different binary paths and will generate platform-specific `bin` fields when needed, or use a global `bin` field when all platforms have the same binary structure.\n\n::: tip\ntool stubs default to the HTTP backend if no `tool` field is specified and a `url` field is present.\nSee the [HTTP backend documentation](/dev-tools/backends/http) for full details on configuring HTTP-based tools.\n:::\n\n## Generating Tool Stubs (http)\n\nWhile you can manually create tool stubs with TOML configuration, mise provides a [`mise generate tool-stub`](/cli/generate/tool-stub) command to automatically create stubs for HTTP-based tools.\n\n::: tip Incremental Building\nWhen using platform-specific URLs, the tool stub generator will append new platforms to existing stub files rather than overwriting them. This allows you to incrementally build cross-platform tool stubs by running the command multiple times with different platforms.\n:::\n\n### Basic Generation\n\nGenerate a tool stub for a tool distributed via HTTP:\n\n```bash\nmise generate tool-stub ./bin/gh --url \"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_linux_amd64.tar.gz\"\n```\n\nThis will:\n\n- Download the archive to detect checksums (for security)\n- Extract it to auto-detect the binary path\n- Generate an executable stub with complete TOML configuration\n\n### Platform-Specific Generation\n\nFor tools with different URLs per platform, you can generate all platforms at once:\n\n```bash\nmise generate tool-stub ./bin/rg \\\n  --platform-url linux-x64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz \\\n  --platform-url darwin-arm64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-aarch64-apple-darwin.tar.gz\n```\n\n**Auto-Platform Detection**: If the URL contains platform information, you can omit the platform prefix and let mise auto-detect it:\n\n```bash\n# Auto-detect platform from URL (detects as 'macos-arm64')\nmise generate tool-stub ./bin/node \\\n  --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\n\n# Auto-detect platform from URL (detects as 'linux-x64')\nmise generate tool-stub ./bin/node \\\n  --platform-url https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz\n```\n\nOr build them incrementally by adding platforms one at a time:\n\n```bash\n# Start with Linux support (explicit platform)\nmise generate tool-stub ./bin/rg \\\n  --platform-url linux-x64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz\n\n# Later, add macOS support using auto-detection (appends to existing file)\nmise generate tool-stub ./bin/rg \\\n  --platform-url https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-aarch64-apple-darwin.tar.gz\n\n# Add Windows support using auto-detection (appends to existing file)\nmise generate tool-stub ./bin/rg \\\n  --platform-url https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-pc-windows-msvc.zip\n```\n\nThe generator will preserve existing configuration and merge new platforms into the `[platforms]` table. If you specify a platform that already exists, its URL will be updated.\n\n### Generation Options\n\n- `--version VERSION` - Specify tool version (defaults to \"latest\").\n- `--bin PATH` - Override auto-detected binary path\n- `--platform-url PLATFORM:URL` - Add platform-specific URL (can be used multiple times)\n- `--platform-url URL` - Add platform-specific URL with auto-detected platform from URL filename\n- `--platform-bin PLATFORM:PATH` - Set platform-specific binary path\n- `--skip-download` - Skip downloading for faster generation (no checksums or binary detection)\n- `--lock` - Resolve and embed lockfile data (pinned version + platform URLs/checksums) into an existing stub\n\n### Supported Archive Formats\n\nThe generator automatically detects and extracts various archive formats:\n\n- `.tar.gz` / `.tgz` (gzip compressed tarballs)\n- `.tar.xz` / `.txz` (xz compressed tarballs)\n- `.tar.bz2` / `.tbz2` (bzip2 compressed tarballs)\n- `.tar.zst` / `.tzst` (zstd compressed tarballs)\n- `.zip` (zip archives)\n- `.7z` (7-zip archives, Windows only)\n\n### Generated Stub Example\n\nRunning the generation command produces an executable stub like:\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n\nversion = \"latest\"\nbin = \"bin/gh\"\nurl = \"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_linux_amd64.tar.gz\"\nchecksum = \"blake3:a1b2c3d4e5f6...\"\nsize = 12345678\n```\n\nThe generator automatically:\n\n- Calculates BLAKE3 checksums for integrity verification\n- Detects file sizes\n- Identifies the correct binary path within archives\n- Uses the output filename as the tool name\n\n## Examples\n\n### Basic Node.js Stub\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n# Node.js v20 tool stub\n\ntool = \"node\"\nversion = \"20.0.0\"\nbin = \"node\"\n```\n\n### Python with Custom Binary Name\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n# Python tool accessible as 'py'\n\ntool = \"python\"\nversion = \"3.11\"\nbin = \"python\"\n```\n\n### GitHub Release Backend\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n# GitHub CLI tool\n\ntool = \"github:cli/cli\"\nversion = \"latest\"\n```\n\n### Locked Tool Stub\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n\ntool = \"node\"\nversion = \"20.18.1\"\nbin = \"node\"\n\n[lock.platforms.linux-x64]\nurl = \"https://nodejs.org/dist/v20.18.1/node-v20.18.1-linux-x64.tar.xz\"\nchecksum = \"sha256:abc123...\"\n\n[lock.platforms.macos-arm64]\nurl = \"https://nodejs.org/dist/v20.18.1/node-v20.18.1-darwin-arm64.tar.gz\"\nchecksum = \"sha256:def456...\"\n```\n\nThe `[lock]` section is generated by `mise generate tool-stub --lock` and provides\nreproducible downloads with checksum verification. The tool/version fields are still\nused for backend resolution, while lock data provides the download shortcuts.\n\n::: tip\nLocking is especially useful for avoiding GitHub API rate limits when users don't have a `GITHUB_TOKEN` set. With locked stubs, tools can be installed without any API calls at runtime.\n:::\n\n#### Locking a Stub\n\n```bash\n# Create a stub with a fuzzy version\nmise generate tool-stub ./bin/node --version 20\n\n# Lock it to pin the exact version and add platform URLs/checksums\nmise generate tool-stub ./bin/node --lock\n```\n\nThis resolves the version, fetches URLs for all common platforms (linux-x64, linux-arm64, macos-x64, macos-arm64, windows-x64), and writes them into a `[lock]` section in the stub.\n\n#### Bumping a Locked Version\n\nTo bump the version of a locked stub, pass `--version` along with `--lock`:\n\n```bash\n# Bump to the latest node 22.x and re-lock\nmise generate tool-stub ./bin/node --lock --version 22\n```\n\n### HTTP Backend with Platform Support\n\n```bash\n#!/usr/bin/env -S mise tool-stub\n# Custom HTTP tool with platform-specific downloads\n\nversion = \"1.0.0\"\n\n[platforms.linux-x64]\nurl = \"https://releases.example.com/v{{version}}/tool-linux-x64.tar.gz\"\n\n[platforms.darwin-arm64]\nurl = \"https://releases.example.com/v{{version}}/tool-macos-arm64.tar.gz\"\n```\n\n## Usage\n\n### Direct Execution\n\nMake the stub executable and run it directly:\n\n```bash\nchmod +x ./bin/my-tool\n./bin/my-tool --version\n```\n\n### Via mise Command\n\nExecute using the [`mise tool-stub`](/cli/tool-stub) command—useful for testing if something isn't working right:\n\n```bash\nmise tool-stub ./bin/my-tool --version\n```\n\n## Caching\n\nTool stubs implement intelligent caching which reduces the overhead mise has when running stubs:\n\n- Binary paths are cached based on stub file path and modification time\n- Cache is automatically invalidated when the stub file changes\n- Missing binaries trigger cache cleanup automatically\n\nCached stubs have ~4ms of overhead.\n\n## Alternative: Creating Simple Stubs with `mise x`\n\nFor basic use cases, you can quickly create simple tool stubs using the [`mise x`](/cli/exec) command as an alternative to writing TOML configuration manually:\n\n```bash\n# Create bin directory\nmkdir -p ./bin\n\n# Create a simple Node.js stub\ncat > ./bin/node << 'EOF'\n#!/usr/bin/env bash\nexec mise x node@20 -- \"$@\"\nEOF\nchmod +x ./bin/node\n\n# Create a Python stub with specific version\ncat > ./bin/python << 'EOF'\n#!/usr/bin/env bash\nexec mise x python@3.11 -- \"$@\"\nEOF\nchmod +x ./bin/python\n```\n\nThis approach is ideal for simple tool execution without the need for custom options, environment variables, or platform-specific settings. For more complex configurations, use the full TOML configuration format described above.\n"
  },
  {
    "path": "docs/directories.md",
    "content": "# Directory Structure\n\nThe following are the directories that mise uses.\n\n::: tip\nIf you often find yourself using these directories (as I do), I suggest setting all of them to `~/.mise` for easy access.\n:::\n\n## `~/.config/mise`\n\n- Override: `$MISE_CONFIG_DIR`\n- Default: `${XDG_CONFIG_HOME:-$HOME/.config}/mise`\n\nThis directory stores the global configuration file `~/.config/mise/config.toml`. This is intended to go into your\ndotfiles repo to share across machines.\n\n## `~/.cache/mise`\n\n- Override: `$MISE_CACHE_DIR`\n- Default: `${XDG_CACHE_HOME:-$HOME/.cache}/mise`, _macOS: `~/Library/Caches/mise`._\n\nStores internal cache that mise uses for things like the list of all available versions of a\nplugin. Do not share this across machines. You may delete this directory any time mise isn't actively installing something.\nDo this with `mise cache clear`.\nSee [Cache Behavior](/cache-behavior) for more information.\n\n## `~/.local/state/mise`\n\n- Override: `$MISE_STATE_DIR`\n- Default: `${XDG_STATE_HOME:-$HOME/.local/state}/mise`\n\nUsed for storing state local to the machine such as which config files are trusted. These should not be shared across\nmachines.\n\n## `~/.local/share/mise`\n\n- Override: `$MISE_DATA_DIR`\n- Default: `${XDG_DATA_HOME:-$HOME/.local/share}/mise`\n\nThis is the main directory that mise uses and is where plugins and tools are installed into.\nIt is nearly identical to `~/.asdf` in asdf, so much so that you may be able to get by\nsymlinking these together and using asdf and mise simultaneously. (Supporting this isn't a\nproject goal, however).\n\nThis directory _could_ be shared across machines but only if they run the same OS/arch. In general I wouldn't advise\ndoing so.\n\n### `~/.local/share/mise/downloads`\n\nThis is where plugins may optionally cache downloaded assets such as tarballs. Use the\n`always_keep_downloads` setting to prevent mise from removing files from here.\n\n### `~/.local/share/mise/plugins`\n\nmise installs plugins to this directory when running `mise plugins install`. If you are working on a\nplugin, I suggest\nsymlinking it manually by running:\n\n```sh\nln -s ~/src/mise-my-tool ~/.local/share/mise/plugins/my-tool\n```\n\n### `~/.local/share/mise/installs`\n\nThis is where tools are installed to when running `mise install`. For example, `mise install\nnode@20.0.0` will install to `~/.local/share/mise/installs/node/20.0.0`\n\nThis will also create other symlinks to this directory for version prefixes (\"20\" and \"20.15\")\nand matching aliases (\"lts\", \"latest\").\nFor example:\n\n```sh\n$ tree ~/.local/share/mise/installs/node\n20 -> ./20.15.0\n20.15 -> ./20.15.0\nlts -> ./20.15.0\nlatest -> ./20.15.0\n```\n\nYou can set the `MISE_INSTALLS_DIR` environment variable to override this location.\n\n### `~/.local/share/mise/shims`\n\nThis is where mise places shims. Generally these are used for IDE integration or if `mise activate`\ndoes not work for some reason.\n"
  },
  {
    "path": "docs/direnv.md",
    "content": "# direnv <Badge type=\"warning\" text=\"deprecated\" />\n\n[direnv](https://direnv.net) and mise both manage environment variables based on directory. Because\nthey both analyze\nthe current environment variables before and after their respective \"hook\" commands are run, they\ncan sometimes conflict with each other.\n\n::: warning\nThe official stance is you should not use direnv with mise. Issues arising\nfrom incompatibilities are not considered bugs. If mise has feature gaps\nthat direnv resolves, please open an issue so we can close those gaps.\nWhile that's the official stance, the reality is mise and direnv usually\nwill work together just fine despite this. It's only more advanced use-cases\nwhere problems arise.\n:::\n\nIf you have an issue, it's likely to do with the ordering of PATH. This means it would\nreally only be a problem if you were trying to manage the same tool with direnv and mise. For\nexample,\nyou may use `layout python` in an `.envrc` but also be maintaining a `.tool-versions` file with\npython\nin it as well.\n\nA more typical usage of direnv would be to set some arbitrary environment variables, or add\nunrelated\nbinaries to PATH. In these cases, mise will not interfere with direnv.\n\n## mise inside of direnv (`use mise` in `.envrc`)\n\n::: warning\n`use mise` is deprecated and no longer supported. If `mise activate` does\nnot fit your use-case please post an issue.\n:::\n\nIf you do encounter issues with `mise activate`, or just want to use direnv in an alternate way,\nthis is a simpler setup that's less likely to cause issues—at the cost of functionality.\n\nThis may be required if you want to use direnv's `layout python` with mise. Otherwise there are\nsituations where mise will override direnv's PATH. `use mise` ensures that direnv always has\ncontrol.\n\nTo do this, first use `mise` to build a `use_mise` function that you can use in `.envrc` files:\n\n```sh\nmise direnv activate > ~/.config/direnv/lib/use_mise.sh\n```\n\nNow in your `.envrc` file add the following:\n\n```sh\nuse mise\n```\n\ndirenv will now call mise to export its environment variables. You'll need to make sure to\nadd `use_mise`\nto all projects that use mise (or use direnv's `source_up` to load it from a subdirectory). You can\nalso add `use mise` to `~/.config/direnv/direnvrc`.\n\nNote that in this method direnv typically won't know to refresh `.tool-versions` files\nunless they're at the same level as a `.envrc` file. You'll likely always want to have\na `.envrc` file next to your `.tool-versions` for this reason. To make this a little\neasier to manage, I encourage _not_ actually using `.tool-versions` at all, and instead\nsetting environment variables entirely in `.envrc`:\n\n```sh\nexport MISE_NODE_VERSION=20.0.0\nexport MISE_PYTHON_VERSION=3.11\n```\n\nOf course if you use `mise activate`, then these steps won't have been necessary and you can use\nmise\nas if direnv was not used.\n\nIf you continue to struggle, you can also try using the [shims method](dev-tools/shims.md).\n\n### Do you need direnv?\n\nWhile making mise compatible with direnv is, and will always be a major goal of this project, I also\nwant mise to be capable of replacing direnv if needed. This is why mise includes support for\nmanaging\nenv vars and [virtualenv](lang/python.md#automatic-virtualenv-activation)\nfor python using `mise.toml`.\n"
  },
  {
    "path": "docs/env-plugin-development.md",
    "content": "# Environment Plugin Development\n\nEnvironment plugins are a special type of mise plugin that provide environment variables and PATH modifications without managing tool versions. They're ideal for integrating external services, managing secrets, and standardizing environment configuration across teams.\n\nUnlike [tool plugins](tool-plugin-development.md) and [backend plugins](backend-plugin-development.md), environment plugins:\n\n- ✅ Don't implement version management (`Available`, `PreInstall`, `PostInstall` hooks)\n- ✅ Only implement environment hooks (`MiseEnv`, `MisePath`)\n- ✅ Are configured via `env._.<plugin-name>` syntax\n- ✅ Can accept configuration options as TOML values\n- ✅ Execute on every environment activation\n\n## Quick Start\n\nThe fastest way to create an environment plugin is to use the [mise-env-plugin-template](https://github.com/jdx/mise-env-plugin-template).\n\n::: tip\nThe [mise-env-plugin-template](https://github.com/jdx/mise-env-plugin-template) provides a ready-to-use starting point with LuaCATS type definitions, stylua formatting, and hk linting pre-configured.\n:::\n\nTo get started:\n\n```bash\n# Clone the template\ngit clone https://github.com/jdx/mise-env-plugin-template my-env-plugin\ncd my-env-plugin\n\n# Customize for your use case\n# Edit metadata.lua, hooks/mise_env.lua, hooks/mise_path.lua\n```\n\n## Plugin Structure\n\nEnvironment plugins are implemented in Lua (version 5.1 at the moment). A minimal environment plugin has this structure:\n\n```\nmy-env-plugin/\n├── metadata.lua           # Plugin metadata\n└── hooks/\n    ├── mise_env.lua      # Returns environment variables (required)\n    └── mise_path.lua     # Returns PATH entries (optional)\n```\n\n### metadata.lua\n\nThe `metadata.lua` file defines your plugin's basic information:\n\n```lua\nPLUGIN = {}\n\n--- Plugin name (required)\nPLUGIN.name = \"my-env-plugin\"\n\n--- Plugin version (required)\nPLUGIN.version = \"1.0.0\"\n\n--- Plugin description (required)\nPLUGIN.description = \"Provides environment variables for my service\"\n\n--- Plugin homepage (optional)\nPLUGIN.homepage = \"https://github.com/username/my-env-plugin\"\n\n--- Plugin license (optional)\nPLUGIN.license = \"MIT\"\n\n--- Minimum mise/vfox version required (optional)\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n```\n\n### hooks/mise_env.lua\n\nThe `MiseEnv` hook returns environment variables to set:\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    -- Access configuration from mise.toml via ctx.options\n    local api_url = ctx.options.api_url or \"https://api.example.com\"\n    local debug = ctx.options.debug or false\n\n    -- Return array of environment variables\n    return {\n        {\n            key = \"API_URL\",\n            value = api_url\n        },\n        {\n            key = \"DEBUG\",\n            value = tostring(debug)\n        },\n        {\n            key = \"SERVICE_TOKEN\",\n            value = get_token_from_somewhere()  -- Your custom logic\n        }\n    }\nend\n```\n\n::: tip\nWhen `cmd.exec()` is called from `MiseEnv` or `MisePath` hooks, it inherits the mise-constructed environment — including `_.path` entries and environment variables from preceding directives. If the module directive is configured with `tools = true` (e.g., `_.my-plugin = { tools = true }`), tool installation bin paths are also included, so mise-managed tools are directly callable (e.g., `cmd.exec(\"node --version\")`).\n:::\n\n**Return value**: Either a simple array of env keys, or a table with caching metadata.\n\nSimple format - array of tables, each with:\n\n- `key` (string, required): Environment variable name\n- `value` (string, required): Environment variable value\n\nExtended format - table with:\n\n- `env` (array, required): Array of `{key, value}` tables (same as simple format)\n- `cacheable` (boolean, optional): If `true`, mise can cache this plugin's output. Default: `false`\n- `watch_files` (array of strings, optional): File paths to watch for changes. If any file's mtime changes, the cache is invalidated.\n\nExample using extended format with caching:\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    local config_path = ctx.options.config_file or \"config.json\"\n    local config = load_config(config_path)\n\n    return {\n        cacheable = true,\n        watch_files = {config_path},\n        env = {\n            {key = \"API_URL\", value = config.api_url},\n            {key = \"API_KEY\", value = config.api_key}\n        }\n    }\nend\n```\n\nWhen `cacheable = true`, mise will cache the environment variables and only re-execute the plugin when:\n\n- Any file in `watch_files` changes\n- The mise configuration changes\n- The cache TTL expires (configured via `env_cache_ttl` setting)\n\n::: tip\nFor caching to work, users must enable the `env_cache` setting:\n\n```toml\n# ~/.config/mise/config.toml\n[settings]\nenv_cache = true\n```\n\n:::\n\n### hooks/mise_path.lua\n\nThe `MisePath` hook returns directories to add to PATH (optional):\n\n```lua\nfunction PLUGIN:MisePath(ctx)\n    -- Return array of paths to prepend to PATH\n    local paths = {\n        \"/opt/my-service/bin\"\n    }\n\n    -- Optionally add user-configured path\n    if ctx.options.custom_bin_path then\n        table.insert(paths, ctx.options.custom_bin_path)\n    end\n\n    return paths\nend\n```\n\n**Return value**: Array of strings (directory paths)\n\n## Context Object\n\nBoth hooks receive a `ctx` parameter with:\n\n- **`ctx.options`**: TOML table of user configuration from `mise.toml`\n\nFor environment plugins, `ctx.options` is the primary way to accept user configuration.\n\n## Configuration in mise.toml\n\nUsers configure environment plugins using the `env._` directive:\n\nSimple activation with no options:\n\n```toml\n[env]\n_.my-env-plugin = {}\n```\n\nWith configuration options:\n\n```toml\n[env]\n_.my-env-plugin = {\n  api_url = \"https://prod.api.example.com\",\n  debug = false,\n  custom_bin_path = \"/custom/path/bin\",\n}\n```\n\nAll fields in the TOML table are passed to your hooks as `ctx.options`.\n\n## Complete Example: Secret Manager Plugin\n\nHere's a complete example of a plugin that fetches secrets from an external service:\n\n**metadata.lua**:\n\n```lua\nPLUGIN = {}\nPLUGIN.name = \"vault-secrets\"\nPLUGIN.version = \"1.0.0\"\nPLUGIN.description = \"Fetch secrets from HashiCorp Vault\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\n```\n\n**hooks/mise_env.lua**:\n\n```lua\nlocal http = require(\"http\")\nlocal json = require(\"json\")\n\nfunction PLUGIN:MiseEnv(ctx)\n    local vault_url = ctx.options.vault_url or error(\"vault_url required\")\n    local secrets_path = ctx.options.secrets_path or error(\"secrets_path required\")\n    local vault_token = os.getenv(\"VAULT_TOKEN\") or error(\"VAULT_TOKEN not set\")\n\n    -- Fetch secrets from Vault\n    local url = vault_url .. \"/v1/\" .. secrets_path\n    local response = http.get({\n        url = url,\n        headers = {\n            [\"X-Vault-Token\"] = vault_token\n        }\n    })\n\n    if response.status_code ~= 200 then\n        error(\"Failed to fetch secrets: \" .. response.status_code)\n    end\n\n    local data = json.decode(response.body)\n    local env_vars = {}\n\n    -- Convert Vault secrets to environment variables\n    for key, value in pairs(data.data.data) do\n        table.insert(env_vars, {\n            key = key,\n            value = value\n        })\n    end\n\n    return env_vars\nend\n```\n\n**Usage in mise.toml**:\n\n```toml\n[env]\n_.vault-secrets = {\n  vault_url = \"https://vault.example.com\",\n  secrets_path = \"secret/data/myapp/production\",\n}\n```\n\n## Available Lua Modules\n\nEnvironment plugins have access to mise's built-in Lua modules:\n\n- **`http`**: Make HTTP requests\n- **`json`**: Encode/decode JSON\n- **`file`**: Read/write files\n- **`cmd`**: Execute shell commands\n- **`strings`**: String manipulation utilities\n- **`env`**: Access environment variables\n\nSee [Plugin Lua Modules](/plugin-lua-modules.html) for complete documentation.\n\n## Best Practices\n\n### 1. Provide Sensible Defaults\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    local api_url = ctx.options.api_url or \"https://api.example.com\"\n    local timeout = ctx.options.timeout or 30\n\n    -- ...\nend\n```\n\n### 2. Validate Required Options\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    if not ctx.options.api_key then\n        error(\"api_key is required in mise.toml configuration\")\n    end\n\n    -- ...\nend\n```\n\n### 3. Handle Errors Gracefully\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    local response = http.get({url = ctx.options.api_url})\n\n    if response.status_code ~= 200 then\n        error(\"API request failed: \" .. response.status_code .. \" - \" .. response.body)\n    end\n\n    -- ...\nend\n```\n\n### 4. Use Built-in Caching for Expensive Operations\n\nFor plugins that fetch data from external services, use mise's built-in caching by returning the extended format with `cacheable = true`:\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    local config_file = ctx.options.config_file or \"secrets.json\"\n\n    -- Fetch secrets (mise will cache the result)\n    local secrets = fetch_secrets(ctx.options)\n\n    return {\n        cacheable = true,\n        watch_files = {config_file},  -- Re-fetch if config changes\n        env = secrets\n    }\nend\n```\n\nThis is preferred over manual caching because:\n\n- mise handles cache invalidation automatically\n- Cache is encrypted with session-scoped keys\n- Integrates with `mise cache clear` and `mise cache prune`\n- Respects the `env_cache_ttl` setting\n\nNote: Users must enable `env_cache = true` in their settings for caching to work.\n\n### 5. Support Multiple Environments\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    local env_name = ctx.options.environment or \"development\"\n\n    -- Load different config based on environment\n    local config = load_config(env_name)\n\n    return {\n        {key = \"ENV\", value = env_name},\n        {key = \"API_URL\", value = config.api_url},\n        -- ...\n    }\nend\n```\n\n## Testing Your Plugin\n\n### Local Testing\n\n1. Link your plugin for development:\n\n```bash\nmise plugin link my-env-plugin /path/to/my-env-plugin\n```\n\n2. Configure it in `mise.toml`:\n\n```toml\n[env]\n_.my-env-plugin = { test_option = \"value\" }\n```\n\n3. Test the environment:\n\n```bash\n# See environment variables\nmise env | grep MY_\n\n# Run a command with the environment\nmise exec -- env | grep MY_\n\n# Debug with MISE_DEBUG\nMISE_DEBUG=1 mise env\n```\n\n### Common Issues\n\n**Plugin not found**: Make sure you've installed/linked the plugin:\n\n```bash\nmise plugin ls\n```\n\n**Hook not executing**: Enable debug logging:\n\n```bash\nMISE_DEBUG=1 mise env\n```\n\n**Options not passed**: Verify TOML syntax in `mise.toml`:\n\n```toml\n[env]\n# Correct: TOML table\n_.my-plugin = { key = \"value\" }\n\n# Wrong: String value\n_.my-plugin = \"value\"  # This won't work\n```\n\n## Publishing Your Plugin\n\nOnce your environment plugin is ready:\n\n1. **Create a GitHub repository** for your plugin\n2. **Add a README** with usage instructions\n3. **Tag releases** following semantic versioning\n4. (Optional) share the repository URL so others can install it directly with `mise plugin install`.\n\nSee [Plugin Publishing](/plugin-publishing.html) for detailed instructions.\n\n## Examples\n\n- [mise-env-sample](https://github.com/jdx/mise-env-plugin-template) - Simple example showing basic usage\n- The [mise-plugins](https://github.com/mise-plugins) organization currently hosts tool plugins only—add your environment plugin there (or share it with the community) so others can learn from more examples\n\n## Migration from Tool Plugins\n\nIf you have an existing tool plugin that only sets environment variables, you can simplify it to an environment-only plugin:\n\n**Before** (tool plugin with unused hooks):\n\n```\nmy-plugin/\n├── metadata.lua\n└── hooks/\n    ├── available.lua        # Returns empty list\n    ├── pre_install.lua      # Not used\n    ├── post_install.lua     # Not used\n    └── env_keys.lua         # Actually sets env vars\n```\n\n**After** (environment plugin):\n\n```\nmy-plugin/\n├── metadata.lua\n└── hooks/\n    └── mise_env.lua         # Clean and focused\n```\n\n## Related Documentation\n\n- [Plugin Overview](/plugins.html) - Overview of all plugin types\n- [Tool Plugin Development](/tool-plugin-development.html) - For plugins that manage tool versions\n- [Backend Plugin Development](/backend-plugin-development.html) - For multi-tool backends\n- [Plugin Lua Modules](/plugin-lua-modules.html) - Available Lua APIs\n- [Plugin Publishing](/plugin-publishing.html) - Publishing your plugin\n- [Environment Variables](/environments/) - How mise manages environments\n"
  },
  {
    "path": "docs/environments/index.md",
    "content": "# Environments\n\n> Like [direnv](https://github.com/direnv/direnv) it\n> manages _environment variables_ for\n> different project directories.\n\nUse mise to specify environment variables used for different projects.\n\nTo get started, create a `mise.toml` file in the root of your project directory:\n\n```toml [mise.toml]\n[env]\nNODE_ENV = 'production'\n```\n\nTo clear an env var, set it to `false`:\n\n```toml [mise.toml]\n[env]\nNODE_ENV = false # unset a previously set NODE_ENV\n```\n\nYou can also use the CLI to get/set env vars:\n\n```sh\nmise set NODE_ENV=development\n# mise set NODE_ENV\n# development\n\nmise set\n# key       value        source\n# NODE_ENV  development  mise.toml\n\ncat mise.toml\n# [env]\n# NODE_ENV = 'development'\n\nmise unset NODE_ENV\n```\n\nAdditionally, the [mise env [--json] [--dotenv]](/cli/env.html) command can be used to export the environment variables in various formats (including `PATH` and environment variables set by tools or plugins).\n\n## Using environment variables\n\nEnvironment variables are available when using [`mise x|exec`](/cli/exec.html), or with [`mise r|run`](/cli/run.html) (i.e. with [tasks](/tasks/)):\n\n```shell\nmise set MY_VAR=123\nmise exec -- echo $MY_VAR\n# 123\n```\n\nYou can of course combine them with [tools](/dev-tools/):\n\n```sh\nmise use node@24\nmise set MY_VAR=123\ncat mise.toml\n# [tools]\n# node = '24'\n# [env]\n# MY_VAR = '123'\nmise exec -- node --eval 'console.log(process.env.MY_VAR)'\n# 123\n```\n\nIf [mise is activated](/getting-started.html#activate-mise), it will automatically set environment variables in the current shell session when you `cd` into a directory.\n\n```shell\ncd /path/to/project\nmise set NODE_ENV=production\ncat mise.toml\n# [env]\n# NODE_ENV = 'production'\n\necho $NODE_ENV\n# production\n```\n\nIf you are using [`shims`](/dev-tools/shims.html), the environment variables will be available when using the shim:\n\n```shell\nmise set NODE_ENV=production\nmise use node@24\n# using the absolute path for the example\n~/.local/share/mise/shims/node --eval 'console.log(process.env.NODE_ENV)'\n```\n\nFinally, you can also use [`mise en`](/cli/en.html) to start a new shell session with the environment variables set.\n\n```shell\nmise set FOO=bar\nmise en\n> echo $FOO\n# bar\n```\n\n## Environment in tasks\n\nIt is also possible to define environment inside a task\n\n```toml [mise.toml]\n[tasks.print]\nrun = \"echo $MY_VAR\"\nenv = { _.file = '/path/to/file.env', \"MY_VAR\" = \"my variable\" }\n```\n\n## Lazy eval\n\nEnvironment variables typically are resolved before tools—that way you can configure tool installation\nwith environment variables. However, sometimes you want to access environment variables produced by\ntools. To do that, turn the value into a map with `tools = true`:\n\n```toml\n[env]\nMY_VAR = { value = \"tools path: {{env.PATH}}\", tools = true }\n_.path = { path = [\"{{env.GEM_HOME}}/bin\"], tools = true } # directives may also set tools = true\nNODE_VERSION = { value = \"{{ tools.node.version }}\", tools = true }\n```\n\n## Redactions\n\nVariables can be redacted from the output by setting `redact = true`:\n\n```toml\n[env]\nSECRET = { value = \"my_secret\", redact = true }\n_.file = { path = \".env.json\", redact = true }\n```\n\nYou can also use the `redactions` array to mark multiple environment variables as sensitive:\n\n```toml\nredactions = [\"SECRET_*\", \"*_TOKEN\", \"PASSWORD\"]\n[env]\nSECRET_KEY = \"sensitive_value\"\nAPI_TOKEN = \"token_123\"\nPASSWORD = \"my_password\"\n```\n\n### Viewing Redacted Environment Variables\n\nThe `mise env` command provides flags to work with redacted variables:\n\n```bash\n# Show only redacted environment variables\nmise env --redacted\n\n# Show only values (useful for piping)\nmise env --values\n\n# Show only values of redacted variables\nmise env --redacted --values\n```\n\n::: warning\nRedactions work by intercepting task output line-by-line, so they require a non-`raw` output mode.\nTasks with `raw = true` bypass this interception (stdout/stderr are passed directly to the terminal), so redactions cannot be applied.\n\nBy default, `mise run` uses the `replacing` output mode which shows a progress spinner rather than full output.\nIn CI environments, you may want to use `prefix` or `interleave` output instead so you can see full task logs\nwhile still having redactions applied:\n\n```bash\nMISE_TASK_OUTPUT=prefix mise run mytask\n```\n\nOr set it globally in your config:\n\n```toml\n[settings]\ntask.output = \"prefix\"\n```\n\n:::\n\n::: danger\nBecause mise may output sensitive values that could show up in CI logs you'll need to configure your CI setup\nto know which values are sensitive.\n\nFor example, when using GitHub Actions, you should use `::add-mask::` to prevent secrets from appearing in logs:\n\n```bash\n# In a GitHub Actions workflow\nfor value in $(mise env --redacted --values); do\n  echo \"::add-mask::$value\"\ndone\n```\n\nNote: If you're using [mise-action](https://github.com/jdx/mise-action), it will automatically redact values marked with `redact = true` or matching patterns in the `redactions` array.\n:::\n\n## Required Variables\n\nYou can mark environment variables as required by setting `required = true`. This ensures that the variable is defined either before mise runs or in a later config file (like `mise.local.toml`):\n\n```toml\n[env]\nDATABASE_URL = { required = true }\nAPI_KEY = { required = true }\n```\n\nYou can also provide help text to guide users on how to set the variable:\n\n```toml\n[env]\nDATABASE_URL = {\n  required = \"Set DATABASE_URL to your PostgreSQL connection string (e.g., postgres://user:pass@localhost/dbname)\",\n}\nAPI_KEY = {\n  required = \"Get your API key from https://example.com/api-keys\",\n}\nAWS_REGION = {\n  required = \"Set to your AWS region (e.g., us-east-1, eu-west-1)\",\n}\n```\n\nWhen a required variable is missing, mise will show the help text in the error message to assist users.\n\n### Required Variable Behavior\n\nWhen a variable is marked as `required = true`, mise validates that it is defined through one of these sources:\n\n1. **Pre-existing environment** - Variable was set before running mise\n2. **Later config file** - Variable is defined in a config file processed after the one declaring it as required\n\n```toml\n# In mise.toml\n[env]\nDATABASE_URL = { required = true }\n```\n\n```toml\n# In mise.local.toml (processed later)\n[env]\nDATABASE_URL = \"postgres://prod.example.com/db\"  # This satisfies the requirement\n```\n\n### Validation Behavior\n\n- **Regular commands** (like `mise env`): Fail with clear error messages when required variables are missing\n- **Shell activation** (`hook-env`): Warns about missing required variables but continues execution to avoid breaking shell setup\n\n```bash\n# This will fail if DATABASE_URL is not pre-defined or in a later config\n$ mise env\nError: Required environment variable 'DATABASE_URL' is not defined...\n\n# This will warn but continue (used by shell activation)\n$ mise hook-env --shell bash\nmise WARN Required environment variable 'DATABASE_URL' is not defined...\n# Shell activation continues successfully\n```\n\n### Use Cases\n\nRequired variables are useful for:\n\n- **Database connections** - Ensure critical connection strings are explicitly set\n- **API keys** - Require explicit configuration of sensitive credentials\n- **Environment-specific settings** - Force explicit configuration per environment\n- **Team collaboration** - Document which variables team members must configure\n\n```toml\n[env]\n# API keys (must be set in environment or mise.local.toml)\nSTRIPE_API_KEY = { required = true }\nSENTRY_DSN = { required = true }\n\n# Database connection (must be set in environment or mise.local.toml)\nDATABASE_URL = { required = true }\n\n# Feature flags (must be explicitly configured)\nENABLE_BETA_FEATURES = { required = true }\n```\n\n## `config_root`\n\n`config_root` is the canonical project root directory that mise uses when resolving relative paths inside configuration files. Generally, when you use relative paths in mise you're referring to this directory.\n\n- When your config lives at nested paths like `.config/mise/config.toml` or `.mise/config.toml`, `config_root` points to the project directory that contains those files (for example, `/path/to/project`).\n- When your config lives at the project root (for example, `mise.toml`), `config_root` is simply the current directory.\n- Relative paths in environment directives are resolved against `config_root` so they behave consistently regardless of where the config file itself lives.\n\nHere's some example config files and their `config_root`:\n\n| Config File                                 | `config_root` |\n| ------------------------------------------- | ------------- |\n| `~/src/foo/.config/mise/conf.d/config.toml` | `~/src/foo`   |\n| `~/src/foo/.config/mise/config.toml`        | `~/src/foo`   |\n| `~/src/foo/.mise/config.toml`               | `~/src/foo`   |\n| `~/src/foo/mise.toml`                       | `~/src/foo`   |\n\nYou can see the implementation in [config_root.rs](https://github.com/jdx/mise/blob/main/src/config/config_file/config_root.rs).\n\nExamples:\n\n```toml\n[env]\n# These are equivalent and both resolve against the project root\n_.path = [\"tools/bin\", \"{{config_root}}/tools/bin\"]\n\n# Likewise, a relative source path resolves against the project root\n_.source = \"scripts/env.sh\"          # == \"{{config_root}}/scripts/env.sh\"\n```\n\n## `env._` directives\n\n`env._.*` define special behavior for setting environment variables. (e.g.: reading env vars\nfrom a file). Since nested environment variables do not make sense,\nwe make use of this fact by creating a key named \"\\_\" which is a\nTOML table for the configuration of these directives.\n\n### `env._.file`\n\nIn `mise.toml`: `env._.file` can be used to specify a [dotenv](https://dotenv.org) file to load.\n\n```toml\n[env]\n_.file = '.env'\n```\n\n::: info\nThis uses [dotenvy](https://crates.io/crates/dotenvy) under the hood. If you have problems with\nthe way `env._.file` works, you will likely need to post an issue there,\nnot to mise since there is not much mise can do about the way that crate works.\n:::\n\nThe `env._.file` directive supports:\n\n- A single file as a string or an object\n- Multiple files as an array of strings and objects\n- Using relative or absolute paths\n- Using `dotenv`, `json`, or `yaml` file formats\n- The `redact` and `tools` options\n\n```toml\n[env]\n_.file = '.env.yaml'\n```\n\n```toml\n[env]\n# Load env from the dotenv file after tools have defined environment variables\n_.file = { path = \".env\", tools = true }\n```\n\n```toml\n[env]\n_.file = [\n    # Load env from the json file relative to this config file\n    '.env.json',\n    # Load env from the dotenv file at an absolute path\n    '/User/bob/.env',\n    # Load env from the yaml file relative to this config file and redacts the values\n    { path = \".secrets.yaml\", redact = true }\n]\n```\n\nYou can set [`MISE_ENV_FILE=.env`](/configuration#mise-env-file) to automatically load dotenv files in any\ndirectory.\n\nSee [secrets](/environments/secrets/) for ways to read encrypted files with `env._.file`.\n\n### `env._.path`\n\n`PATH` is treated specially. Use `env._.path` to add extra directories to the `PATH`, making any executables in those directories available in the shell without needing to type the full path:\n\n```toml\n[env]\n_.path = './bin'\n```\n\nThe `env._.path` directive supports:\n\n- A single path as a string or an object\n- Multiple paths as an array of strings and objects\n- Using relative or absolute paths\n- The `tools` option\n\n```toml\n[env]\n_.path = 'scripts'\n```\n\n```toml\n[env]\n# Define this path directory after tools have defined environment variables\n_.path = { path = [\"{{env.GEM_HOME}}/bin\"], tools = true }\n```\n\n```toml\n[env]\n_.path = [\n    # adds an absolute path\n    \"~/.local/share/bin\",\n    # adds a path relative to the project root (config_root)\n    \"{{config_root}}/node_modules/.bin\",\n    # adds a relative path (equivalent to \"{{config_root}}/tools/bin\")\n    \"tools/bin\",\n]\n```\n\nRelative paths like `tools/bin` or `./tools/bin` are resolved against <span v-pre>`{{config_root}}`</span>. For example, with a config file at `/path/to/project/.config/mise/config.toml`, `tools/bin` resolves to `/path/to/project/tools/bin`.\n\n### `env._.source`\n\nSource an external bash script and pull exported environment variables out of it:\n\n```toml\n[env]\n_.source = \"./script.sh\"\n```\n\n::: info\nThis **must** be a script that runs in bash as if it were executed like this:\n\n```sh\nsource ./script.sh\n```\n\nThe shebang will be **ignored**. See [#1448](https://github.com/jdx/mise/discussions/6734)\nfor a potential alternative that would work with binaries or other script languages.\n:::\n\nThe `env._.source` directive supports:\n\n- A single source as a string or an object\n- Multiple sources as an array of strings and objects\n- Using relative or absolute paths\n- The `redact` and `tools` options\n\n```toml\n[env]\n_.source = 'source.sh'\n```\n\n```toml\n[env]\n# Source this file after tools have defined environment variables\n_.source = { path = \"my/env.sh\", tools = true }\n```\n\n```toml\n[env]\n_.source = [\n    # Sources the file relative to the config root\n    './scripts/base.sh',\n    # Sources a file at an absolute path\n    '/User/bob/env.sh',\n    # Sources the file relative to the config root and redacts the values\n    { path = \".secrets.sh\", redact = true }\n]\n```\n\n## Plugin-provided `env._` Directives\n\nPlugins can provide their own `env._` directives that dynamically set environment variables and modify your PATH. This is particularly useful for:\n\n- Integrating with external secret management systems\n- Setting environment variables based on dynamic conditions\n- Managing complex PATH configurations\n- Providing team-wide environment standardization\n\n### Basic Usage\n\nSimple plugin activation:\n\n```toml\n[env]\n_.my-plugin = {}\n```\n\nPlugin with configuration options:\n\n```toml\n[env]\n_.my-plugin = { option1 = \"value1\", option2 = \"value2\" }\n```\n\n### How It Works\n\nWhen you use `env._.<plugin-name>`, mise:\n\n1. Loads the plugin from your installed plugins\n2. Calls the plugin's `MiseEnv` hook to get environment variables\n3. Calls the plugin's `MisePath` hook to get PATH entries (if defined)\n4. Applies these to your environment when running `mise env` or using shell integration\n\nThe configuration options you provide (the TOML table after `=`) are passed to the plugin's hooks via `ctx.options`, allowing plugins to be configured per-project or per-environment.\n\n### Example: Secret Management Plugin\n\n```toml\n[env]\n# Fetch secrets from a vault\n_.vault-secrets = {\n  vault_url = \"https://vault.example.com\",\n  secrets_path = \"secret/myapp\"\n}\n```\n\nThe plugin could then fetch secrets from HashiCorp Vault and expose them as environment variables.\n\n### Example: Dynamic Environment Plugin\n\n```toml\n[env]\n# Set environment based on git branch\n_.git-env = { production_branch = \"main\" }\n```\n\nThe plugin could detect the current git branch and set `ENVIRONMENT=production` when on `main`, or `ENVIRONMENT=development` otherwise.\n\n### Creating Environment Plugins\n\nSee [Environment Plugins](/plugins#environment-plugins) in the Plugins documentation for a complete guide to creating your own environment plugins.\n\nFor a working example, see the [mise-env-plugin-template](https://github.com/jdx/mise-env-plugin-template) repository.\n\n## Multiple `env._` Directives\n\nIt may be necessary to use multiple `env._` directives, however TOML fails with this syntax\nbecause it has 2 identical keys in a table:\n\n```toml\n[env]\n_.source = \"./script_1.sh\"\n_.source = \"./script_2.sh\" # invalid // [!code error]\n```\n\nFor this use-case, you can optionally make `[env]` an array-of-tables instead by using `[[env]]` instead:\n\n```toml\n[[env]]\n_.source = \"./script_1.sh\"\n[[env]]\n_.source = \"./script_2.sh\"\n```\n\nIt works identically but you can have multiple tables.\n\n## Templates\n\nEnvironment variable values can be templates, see [Templates](/templates) for details.\n\n```toml\n[env]\nLD_LIBRARY_PATH = \"/some/path:{{env.LD_LIBRARY_PATH}}\"\n```\n\n## Using env vars in other env vars\n\nYou can use the value of an environment variable in later env vars:\n\n```toml\n[env]\nMY_PROJ_LIB = \"{{config_root}}/lib\"\nLD_LIBRARY_PATH = \"/some/path:{{env.MY_PROJ_LIB}}\"\n```\n\nOf course the ordering matters when doing this.\n\n## Shell-style variable expansion\n\nAs a simpler alternative to Tera templates for referencing env vars, you can use shell-style `$VAR` syntax\nby enabling the [`env_shell_expand`](/configuration/settings.html#env_shell_expand) setting:\n\n```toml\n[settings]\nenv_shell_expand = true\n\n[env]\nMY_PROJ_LIB = \"{{config_root}}/lib\"\nLD_LIBRARY_PATH = \"$MY_PROJ_LIB:$LD_LIBRARY_PATH\"\n```\n\nSupported syntax:\n\n| Syntax            | Description                                                                           |\n| ----------------- | ------------------------------------------------------------------------------------- |\n| `$VAR`            | Expands to the value of `VAR`                                                         |\n| `${VAR}`          | Same, useful when followed by alphanumeric characters (e.g., `${VAR}_suffix`)         |\n| `${VAR:-default}` | Uses `default` if `VAR` is unset or empty                                             |\n| `${VAR:-}`        | Expands to empty string if `VAR` is unset (suppresses the undefined variable warning) |\n\nExpansion runs after Tera template rendering, so both syntaxes can be mixed.\nUndefined variables without a default are left unexpanded and produce a warning.\n\nThe setting is a 3-way toggle:\n\n- **`true`** — enable shell expansion\n- **`false`** — disable shell expansion, no warning\n- **unset** (default) — disable shell expansion but warn if `$` is detected\n\n<!-- TODO(2026.7.0): update this to say shell expansion is enabled by default -->\n\n::: tip\nShell expansion will become the default behavior in the 2026.7.0 release. Set `env_shell_expand = true` now to opt in early, or `env_shell_expand = false` to preserve the current behavior.\n:::\n"
  },
  {
    "path": "docs/environments/secrets/age.md",
    "content": "# Direct age Encryption <Badge type=\"warning\" text=\"experimental\" />\n\nEncrypt individual environment variable values directly in `mise.toml` using [age](https://github.com/FiloSottile/age) encryption. The age tool is not required—mise has support built-in.\n\nThis is a simple method of storing encrypted environment variables directly in `mise.toml`. You can use it simply by running `mise set --age-encrypt <key>=<value>`. By default, mise will use your ssh key (`~/.ssh/id_ed25519` or `~/.ssh/id_rsa`) if it exists.\n\n- **Inline storage**: values live alongside other env vars in `mise.toml`\n- **Multiple recipients**: x25519 age keys and SSH recipients\n- **Automatic decryption**: at runtime when identities are available\n\n## Quick start\n\n1. [optional] Generate an age key (if you want to create a new age key and don't want to use your ssh key):\n\n```bash\nage-keygen -o ~/.config/mise/age.txt\n# Note the public key output for encryption\n```\n\n2. Encrypt a value:\n\n```bash\nmise set --age-encrypt --prompt DB_PASSWORD\n# Enter value for DB_PASSWORD: [hidden input]\n```\n\n::: warning\nIt's recommended to use `--prompt` to avoid accidentally exposing the value to your shell history. You don't have to though, you can use `mise set --age-encrypt DB_PASSWORD=\"password123\"`.\n:::\n\n3. Values are stored encrypted in `mise.toml` as an age directive:\n\n```toml\n[env]\nDB_PASSWORD = { age = { value = \"<base64>\" } }\n```\n\n4. Decryption happens automatically:\n\n```bash\nmise env  # Variables are decrypted automatically\n```\n\n## CLI flags\n\n- `--age-encrypt` — enable age encryption for the value\n- `--age-recipient <KEY>` — x25519 recipient (can be set multiple times)\n- `--age-ssh-recipient <PATH|KEY>` — SSH public key or path to `.pub`/private key (can be set multiple times)\n- `--age-key-file <PATH>` — use recipients derived from an age identity file\n- `--prompt` — prompt for the value to avoid accidentally exposing it to your shell history\n\nIf no recipients are provided explicitly, mise will try defaults (see below).\n\n## Storage format\n\nEncrypted values are stored as base64 along with a `format` field:\n\n- `format = \"raw\"` — uncompressed ciphertext (typically for small values)\n- `format = \"zstd\"` — zstd-compressed ciphertext (used when ciphertext > 1KB)\n\n## Decryption identities\n\nmise looks for identities in this order:\n\n1. `MISE_AGE_KEY` environment variable\n   - Can contain one or more raw `AGE-SECRET-KEY-...` lines, or an age identity file payload\n2. `settings.age.identity_files` (list of paths)\n3. `settings.age.key_file` (single path)\n4. Default `~/.config/mise/age.txt` if it exists\n5. SSH identities from `settings.age.ssh_identity_files` and common defaults (`~/.ssh/id_ed25519`, `~/.ssh/id_rsa`)\n\nDecrypted values are always marked as redacted.\n\nIf no identities are found or decryption fails, mise returns the encrypted value as-is (non-strict behavior).\n\n## Defaults for recipients (encryption)\n\nWhen `--age-encrypt` is used without explicit recipients, mise attempts to derive recipients from:\n\n- The public keys corresponding to identities in the default key file `~/.config/mise/age.txt`\n- Public keys inferred from SSH private keys if a corresponding `.pub` file exists\n\nIf none are found, the command fails with an error asking you to provide recipients or configure `settings.age.key_file`.\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"age\" :level=\"2\" />\n\n## Notes\n\n- Feature is experimental; flags and behavior may change.\n- `mise set KEY` will print the decrypted value\n"
  },
  {
    "path": "docs/environments/secrets/index.md",
    "content": "# Secrets\n\nUse mise to manage sensitive environment variables securely. There are multiple supported approaches:\n\n- **[fnox](https://github.com/jdx/fnox)** <Badge type=\"tip\" text=\"recommended\" /> — Full-featured secret manager with remote secret storage (e.g.: 1Password, AWS Secrets Manager) and remote encryption (e.g.: AWS KMS). This is a separate project by @jdx that works well alongside mise. There's no direct integration with mise and fnox, you set it up separately.\n- [sops](/environments/secrets/sops) <Badge type=\"warning\" text=\"experimental\" /> — Encrypt entire files and load them via `env._.file`\n- [Direct age encryption](/environments/secrets/age) <Badge type=\"warning\" text=\"experimental\" /> — Encrypt individual env vars inline in `mise.toml`\n"
  },
  {
    "path": "docs/environments/secrets/sops.md",
    "content": "# sops <Badge type=\"warning\" text=\"experimental\" />\n\nmise reads encrypted secret files and makes values available as environment variables via `env._.file`.\n\n- **Formats**: `.env.json`, `.env.yaml`, `.env.toml`\n- **Encryption**: [sops](https://getsops.io) backed by [age](https://github.com/FiloSottile/age)\n\n## Example\n\n```json\n{\n  \"AWS_ACCESS_KEY_ID\": \"AKIAIOSFODNN7EXAMPLE\",\n  \"AWS_SECRET_ACCESS_KEY\": \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\"\n}\n```\n\n```toml [mise.toml]\n[env]\n_.file = \".env.json\"\n```\n\nmise will automatically decrypt the file if it is sops-encrypted.\n\n## Encrypt with sops\n\n:::: info\nCurrently age is the only sops encryption method supported.\n::::\n\n1. Install tools: `mise use -g sops age`\n\n2. Generate an age key and note the public key:\n\n```sh\nage-keygen -o ~/.config/mise/age.txt\n# Public key: <public key>\n```\n\n3. Encrypt the file:\n\n```sh\nsops encrypt -i --age \"<public key>\" .env.json\n```\n\n:::: tip\nThe `-i` overwrites the file. The encrypted file is safe to commit. Set `SOPS_AGE_KEY_FILE=~/.config/mise/age.txt` or `MISE_SOPS_AGE_KEY_FILE=~/.config/mise/age.txt` to decrypt/edit with sops.\n::::\n\n4. Reference it in config:\n\n```toml\n[env]\n_.file = \".env.json\"\n```\n\nNow `mise env` exposes the values.\n\n## Environment Variables\n\nmise supports both mise-specific environment variables and standard SOPS ones:\n\n**Mise-specific variables (highest priority):**\n\n- `MISE_SOPS_AGE_KEY` - Age private key content directly\n- `MISE_SOPS_AGE_KEY_FILE` - Path to age private key file\n\n**Standard SOPS variables (fallback):**\n\n- `SOPS_AGE_KEY_FILE` - Path to age private key file\n- `SOPS_AGE_KEY` - Age private key content directly\n\n**Precedence order:**\n\n1. `MISE_SOPS_AGE_KEY` (mise setting or env var, checked first)\n2. `MISE_SOPS_AGE_KEY_FILE` or `sops.age_key_file` (mise setting or env var)\n3. `SOPS_AGE_KEY_FILE` (standard)\n4. `SOPS_AGE_KEY` (standard, direct key content)\n5. Default: `~/.config/mise/age.txt`\n\nThis allows you to override SOPS settings specifically for mise while keeping your standard SOPS configuration intact for other tools.\n\n## Redaction\n\nMark secrets from files as sensitive:\n\n```toml\n[env]\n_.file = { path = \".env.json\", redact = true }\n```\n\nWork with redacted values:\n\n```bash\nmise env --redacted\nmise env --redacted --values\n```\n\n### CI masking (GitHub Actions)\n\n```yaml\n- name: Mask secrets\n  run: |\n    for value in $(mise env --redacted --values); do\n      echo \"::add-mask::$value\"\n    done\n- name: Use secrets safely\n  run: |\n    mise exec -- ./deploy.sh\n```\n\nIf you use [mise-action](https://github.com/jdx/mise-action), values marked `redact = true` are masked automatically.\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"sops\" :level=\"2\" />\n"
  },
  {
    "path": "docs/errors.md",
    "content": "# Errors\n\nTODO\n"
  },
  {
    "path": "docs/external-resources.md",
    "content": "# External Resources\n\nLinks to articles, videos, and other resources that are relevant to mise.\n\n- 2025-04-09 - Keeping your Swift apps' sensitive data secret - <https://tuist.dev/blog/2025/04/09/secrets>\n- 2025-02-17 - hk: git hook manager that pairs well with mise - <https://hk.jdx.dev>\n- 2025-02-17 - pitchfork: process manager for developers that pairs well with mise - <https://pitchfork.jdx.dev>\n- 2025-02-04 - A Mise guide for Swift developers - <https://tuist.dev/blog/2025/02/04/mise>\n- 2025-01-26 - devtools.fm: Jeff Dickey - Mise, Usage, and Pitchfork and the Future of Polyglot Tools - <https://www.devtools.fm/episode/129>\n- 2025-01-12 - [fr] Mise-En-Place: Simplifiez la Gestion de vos Environnements et Tâches – <https://blog.stephane-robert.info/docs/developper/autres-outils/mise-en-place/>\n- 2024-11-20 - Migrating from nvm to mise - <https://dev.to/hverlin/migrating-from-nvm-to-mise-4mfp>\n- 2024-06-27 - Managing Development Tool Versions with mise - <https://haril.dev/en/blog/2024/06/27/Easy-devtools-version-management-mise>\n- 2024-06-09 - Replacing pyenv, nvm, direnv with Mise - <https://arunmozhi.in/2024/09/06/replacing-pyenv-nvm-direnv-with-mise>\n- 2024-04-14 - Shims: How they work in mise-en-place: <https://jdx.dev/posts/2024-04-13-shims-how-they-work-in-mise-en-place/>\n- 2024-04-07 - Lalaluka stream: Grroxy, Cook, and jdx/mise - <https://www.youtube.com/watch?v=zA1hjrLQiPw>\n- 2024-20-02 - Can Mise replace Volta? - <https://ricostacruz.com/posts/mise-vs-volta>\n- 2024-01-14 - Manage all your runtime versions with one tool (asdf, mise) - <https://blog.andreyfadeev.com/p/manage-all-your-runtime-versions>\n- 2023-12-30 - You should be using mise - <https://andrei-calazans.com/posts/you-should-be-using-rtx/>\n- 2023-03-04 - Beginner's Guide to rtx (mise) - <https://dev.to/jdxcode/beginners-guide-to-rtx-ac4>\n"
  },
  {
    "path": "docs/faq.md",
    "content": "# FAQs\n\n## I don't want to put a `mise.toml`/`.tool-versions` file into my project since git shows it as an untracked file\n\nUse [`mise.local.toml`](https://mise.jdx.dev/configuration.html#mise-toml) and put that into your global gitignore file. This file should never be committed.\n\nIf you really want to use a `mise.toml` or `.tool-versions`, here are 3 ways to make git ignore these files:\n\n- Adding `mise.toml` to project's `.git/info/exclude`. This file is local to your project so\n  there is no need to commit it.\n- Adding `mise.toml` to project's `.gitignore` file. This has the downside that you need to\n  commit the change to the ignore file.\n- Adding `mise.toml` to global gitignore (`core.excludesFile`). This will cause git to\n  ignore `mise.toml` files in all projects. You can explicitly add one to a project if needed\n  with `git add --force mise.toml`.\n\n## What is the difference between \"nodejs\" and \"node\" (or \"golang\" and \"go\")?\n\nThese are aliased. For example, `mise use nodejs@14.0` is the same as `mise install node@14.0`. This\nmeans it is not possible to have these be different plugins.\n\nThis is for convenience so you don't need to remember which one is the \"official\" name. However if\nsomething with the aliasing is acting up, submit a ticket or just stick to using \"node\" and \"go\".\nUnder the hood, when mise reads a config file or takes CLI input it will swap out \"nodejs\" and\n\"golang\".\n\n## What does `mise activate` do?\n\nIt registers a shell hook to run `mise hook-env` every time the shell prompt is displayed.\n`mise hook-env` checks the current env vars (most importantly `PATH` but there are others like\n`GOROOT` or `JAVA_HOME` for some tools) and adds/removes/updates the ones that have changed.\n\nFor example, if you `cd` into a different directory that has `java 18` instead of `java 17`\nspecified, just before the next prompt is displayed the shell runs: `eval \"$(mise hook-env)\"`\nwhich will execute something like this in the current shell session:\n\n```sh\nexport JAVA_HOME=$HOME/.local/share/installs/java/18\nexport PATH=$HOME/.local/share/installs/java/18/bin:$PATH\n```\n\nIn reality updating `PATH` is a bit more complex than that because it also needs to remove java-17,\nbut you get the idea.\n\nYou may think that is excessive to run `mise hook-env` every time the prompt is displayed\nand it should only run on `cd`, however there are plenty of\nsituations where it needs to run without the directory changing, for example if `.tool-versions` or\n`mise.toml` was just edited in the current shell.\n\nBecause it runs on prompt display, if you attempt to use `mise activate` in a\nnon-interactive session (like a bash script), it will never call `mise hook-env` and in effect will\nnever modify PATH because it never displays a prompt. For this type of setup, you can either call\n`mise hook-env` manually every time you wish to update PATH, or use [shims](/dev-tools/shims.md)\ninstead (preferred).\nOr if you only need to use mise for certain commands, just prefix the commands with\n[`mise x --`](./cli/exec).\nFor example, `mise x -- npm test` or `mise x -- ./my_script.sh`.\n\n`mise hook-env` will exit early in different situations if no changes have been made. This prevents\nadding latency to your shell prompt every time you run a command. You can run `mise hook-env`\nyourself\nto see what it outputs, however it is likely nothing if you're in a shell that has already been\nactivated.\n\n`mise activate` also creates a shell function (in most shells) called `mise`.\nThis is a trick that makes it possible for `mise shell`\nand `mise deactivate` to work without wrapping them in `eval \"$(mise shell)\"`.\n\n## Windows support?\n\n::: warning\nWhile mise runs great in WSL, native Windows is also supported, though via the use of shims until\nsomeone adds [powershell](https://github.com/jdx/mise/discussions/6733) support.\n\nAs you'll need to use shims, this means you won't have environment variables from mise.toml unless you run mise via\n[`mise x`](/cli/exec) or [`mise run`](/cli/run)—though that's actually how I use mise on my mac so\nfor me that's my preferred workflow anyway.\n:::\n\n## How do I use mise with http proxies?\n\nShort answer: just set `http_proxy` and `https_proxy` environment variables. These should be\nlowercase.\n\nThis may not work with all plugins if they are not configured to use these env vars.\nIf you're having a proxy-related issue installing something specific you should post an issue on the\nplugin's repository.\n\n## How do the shorthand plugin names map to repositories?\n\ne.g.: how does `mise plugin install elixir` know to fetch <https://github.com/asdf-vm/asdf-elixir>?\n\nWe maintain [an index](https://github.com/mise-plugins/registry) of shorthands that mise uses as a\nbase.\nThis is regularly updated every time that mise has a release. This repository is stored directly\ninto\nthe codebase in [registry/](https://github.com/jdx/mise/blob/main/registry/).\n\n## Does \"node@20\" mean the newest available version of node?\n\nIt depends on the command. Normally, for most commands and inside of config files, \"node@20\" will\npoint to the latest _installed_ version of node-20.x. You can find this version by running\n`mise latest --installed node@20` or by seeing what the `~/.local/share/mise/installs/node/20`\nsymlink\npoints to:\n\n```sh\n$ ls -l ~/.local/share/mise/installs/node/20\n[...] /home/jdx/.local/share/mise/installs/node/20 -> node-v20.0.0-linux-x64\n```\n\nThere are some exceptions to this, such as the following:\n\n- `mise install node@20`\n- `mise latest node@20`\n- `mise upgrade node@20`\n\nThese will use the latest _available_ version of node-20.x. This generally makes sense because you\nwouldn't want to install a version that is already installed.\n\n## How do I migrate from asdf?\n\n- Install mise and set up `mise activate` as described in the [getting started guide](/getting-started)\n- remove asdf from your shell rc file\n- Run `mise install` in a directory with an asdf `.tool-versions` file and mise will install the tools\n\n::: info\nNote that `mise` does not consider `~/.tool-versions` files to be a global config file like `asdf` does. `mise` uses a\n`~/.config/mise/config.toml` file for global configuration.\n:::\n\nHere is an example script you can use to migrate your global `.tool-versions` file to mise:\n\n```shell\nmv ~/.tool-versions ~/.tool-versions.bak\ncat ~/.tool-versions.bak | tr -s ' ' | tr ' ' '@' | xargs -n2 mise use -g\n```\n\nOnce you are comfortable with mise, you can remove the `.tool-versions.bak` file and [uninstall `asdf`](https://asdf-vm.com/manage/core.html#uninstall)\n\n## How compatible is mise with asdf?\n\nmise should be able to read/install any `.tool-versions` file used by asdf. Any asdf plugin\nshould be usable in mise. The commands in mise are slightly\ndifferent, such as `mise install node@20.0.0` vs `asdf install node 20.0.0`—this is done so\nmultiple tools can be specified at once. However, asdf-style syntax is still supported: (`mise\ninstall node 20.0.0`). This is the case for most commands, though the help for the command may\nsay that asdf-style syntax is supported. When in doubt, just try asdf syntax and see if it works—it probably does.\n\n::: info\nUPDATE (2025-01-01): mise was designed to be compatible with the asdf written in bash (<=0.15). The new asdf written in go (>=0.16)\nhas commands mise does not support like `asdf set`. `mise set` is an existing command that is completely different than `asdf set`—in mise that sets env vars.\n\nThis isn't important for usability reasons so much as making it so plugins continue to work that\ncall asdf commands inside of the plugin code.\n:::\n\nUsing commands like `mise use` may output `.tool-versions` files that are not compatible with asdf,\nsuch as using fuzzy versions. You can set `--pin` or `MISE_PIN=1` to make `mise use` output asdf-compatible versions\nin `.tool-versions`. Alternatively, you can have `mise.toml` and `.tool-versions` sitting side-by-side. `mise.toml` tools\nwill override tools defined in a `.tool-versions` in the same directory.\n\nThat said, in general compatibility with asdf is no longer a design goal. It's long been the case\nthat there is no reason to prefer asdf to mise so users should migrate. While plenty of users have\nteams which use both in tandem, issues with such a setup are unlikely to be prioritized.\n\n## How do I disable/force CLI color output?\n\nmise uses [console.rs](https://docs.rs/console/latest/console/fn.colors_enabled.html) which\nhonors the [clicolors spec](https://bixense.com/clicolors/):\n\n- `CLICOLOR != 0`: ANSI colors are supported and should be used when the program isn't piped.\n- `CLICOLOR == 0`: Don't output ANSI color escape codes.\n- `CLICOLOR_FORCE != 0`: ANSI colors should be enabled no matter what.\n\n## Is mise secure?\n\nProviding a secure supply chain is incredibly important. mise already provides a more secure\nexperience when compared to asdf. Security-oriented evaluations and contributions are welcome.\nWe also urge users to look after the plugins they use, and urge plugin authors to look after\nthe users they serve.\n\nFor more details see [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md).\n\n## What is usage?\n\nusage (<https://usage.jdx.dev/>) is a spec and CLI for defining CLI tools.\n\nArguments, flags, environment variables, and config files can all be defined in a Usage spec. It can be thought of like OpenAPI (swagger) for CLIs.\n\n`usage` can be installed with `mise` using `mise use -g usage` and is required to get the autocompletion working. See [autocompletion](/installing-mise.html#autocompletion).\n\nYou can leverage usage in file tasks to get auto-completion working, see [file tasks arguments](/tasks/file-tasks.html#arguments).\n\n## What is pitchfork?\n\npitchfork (<https://pitchfork.jdx.dev/>) is a process manager for developers.\n\nIt handles daemon management with features like automatic restarts on failure, smart readiness checks, shell-based auto-start/stop when entering project directories, and cron-style scheduling for periodic tasks.\n\n## VSCode for windows extension with error `spawn EINVAL`\n\nIn VSCode, many extensions will throw an \"error spawn EINVAL\" due to a [Node.js security fix](https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2#command-injection-via-args-parameter-of-child_processspawn-without-shell-option-enabled-on-windows-cve-2024-27980---high).\n\nThe default `exe` shim mode should resolve this. If you're using an older mode, you can change [windows_shim_mode](https://mise.jdx.dev/configuration/settings.html#windows_shim_mode) to `exe`, `hardlink`, or `symlink`.\n\n## How does mise versioning work?\n\nmise uses [Calver](https://calver.org/) versioning (`2024.1.0`).\nBreaking changes will be few but when they do happen,\nthey will be communicated in the CLI with plenty of notice whenever possible.\n\nRather than have SemVer major releases to communicate change in large releases,\nnew functionality and changes can be opted-into with settings like `experimental = true`.\nThis way plugin authors and users can\ntest out new functionality immediately without waiting for a major release.\n\nThe numbers in Calver (YYYY.MM.RELEASE) simply represent the date of the release—not compatibility\nor how many new features were added.\nEach release will be small and incremental.\n"
  },
  {
    "path": "docs/getting-started.md",
    "content": "<!-- markdownlint-disable MD034 -->\n\n# Getting Started\n\nGet up and running with mise in minutes.\n\n## 1. Install `mise` CLI {#installing-mise-cli}\n\nSee [installing mise](/installing-mise) for other ways to install mise (`macport`, `apt`, `yum`, `nix`, etc.).\n\n:::tabs key:installing-mise\n== Linux/macOS\n\n```shell\ncurl https://mise.run | sh\n```\n\nBy default, mise installs to `~/.local/bin`, but it can go anywhere.\nVerify the installation:\n\n```shell\n~/.local/bin/mise --version\n# mise 2024.x.x\n```\n\n- `~/.local/bin` does not need to be in `PATH`. mise will automatically add its own directory to `PATH`\n  when [activated](#activate-mise).\n\n== Brew\n\n```shell\nbrew install mise\n```\n\n== Windows\n::: code-group\n\n```shell [winget]\nwinget install jdx.mise\n```\n\n```shell [scoop]\n# https://github.com/ScoopInstaller/Main/pull/6374\nscoop install mise\n```\n\n```shell [chocolatey]\nchoco install mise\n```\n\n== Debian/Ubuntu (apt)\n\n```sh\nsudo apt update -y && sudo apt install -y curl\nsudo install -dm 755 /etc/apt/keyrings\ncurl -fSs https://mise.jdx.dev/gpg-key.pub | sudo tee /etc/apt/keyrings/mise-archive-keyring.asc 1> /dev/null\necho \"deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.asc] https://mise.jdx.dev/deb stable main\" | sudo tee /etc/apt/sources.list.d/mise.list\nsudo apt update -y\nsudo apt install -y mise\n```\n\n== Fedora 41+, RHEL/CentOS Stream 9+ (dnf)\n\n```sh\nsudo dnf copr enable jdxcode/mise\nsudo dnf install mise\n```\n\nSee the [copr page](https://copr.fedorainfracloud.org/coprs/jdxcode/mise/) for more information.\n\n== Snap (beta)\n\n```sh\nsudo snap install mise --classic --beta\n```\n\nSee the [snapcraft.io page](https://snapcraft.io/mise) for more information.\n\n:::\n\n`mise` respects [`MISE_DATA_DIR`](/configuration) and [`XDG_DATA_HOME`](/configuration) if you'd like\nto change these locations.\n\n## 2. mise `exec` and `run` {#mise-exec-run}\n\nOnce installed, you can start using mise right away to install and run [tools](/dev-tools/), launch [tasks](/tasks/), and manage [environment variables](/environments/).\n\nThe quickest way to run a tool at a specific version is [`mise x|exec`](/cli/exec.html). For example, to launch a Python 3 REPL:\n\n::: tip\nIf `mise` isn't on `PATH` yet, use `~/.local/bin/mise` instead.\n:::\n\n```sh\nmise exec python@3 -- python\n# this will download and install Python if it is not already installed\n# Python 3.13.2\n# >>> ...\n```\n\nor run node 24:\n\n```sh\nmise exec node@24 -- node -v\n# v24.x.x\n```\n\nTo install a tool permanently, use [`mise u|use`](/cli/use.html):\n\n```shell\nmise use --global node@24 # install node 24 and set it as the global default\nmise exec -- node my-script.js\n# run my-script.js with node 24...\n```\n\n[`mise r|run`](/cli/run.html) lets you run [tasks](/tasks/) or scripts with the full mise context (tools + env vars) loaded.\n\n::: tip\nYou can set a shell alias in your shell's rc file like `alias x=\"mise x --\"` to save some keystrokes.\n:::\n\n## 3. Activate `mise` <Badge text=\"optional\" /> {#activate-mise}\n\n`mise exec` works great for one-off commands, but for interactive shells you'll probably want to activate mise so tools and environment variables are loaded automatically.\n\nThere are two approaches:\n\n- [`mise activate`](/cli/activate) — updates your `PATH` and environment every time your prompt runs. Recommended for interactive shells.\n- [Shims](dev-tools/shims.md) — symlinks that intercept commands and load the right environment. Better for CI/CD, IDEs, and scripts. Note that [shims don't support all features of `mise activate`](/dev-tools/shims.html#shims-vs-path).\n\nYou can also skip both and call `mise exec` or `mise run` directly.\nSee [this guide](dev-tools/shims.md) for more information.\n\nHere is how to activate mise for your shell:\n\n:::tabs key:installing-mise\n\n== https://mise.run\n\n::: code-group\n\n```sh [bash]\necho 'eval \"$(~/.local/bin/mise activate bash)\"' >> ~/.bashrc\n```\n\n```sh [zsh]\necho 'eval \"$(~/.local/bin/mise activate zsh)\"' >> ~/.zshrc\n```\n\n```sh [fish]\necho '~/.local/bin/mise activate fish | source' >> ~/.config/fish/config.fish\n```\n\n== Brew\n\n::: code-group\n\n```sh [bash]\necho 'eval \"$(mise activate bash)\"' >> ~/.bashrc\n```\n\n```sh [zsh]\necho 'eval \"$(mise activate zsh)\"' >> ~/.zshrc\n```\n\n```sh [fish]\n# do nothing! mise is automatically activated when using brew and fish\n# you can disable this behavior with `set -Ux MISE_FISH_AUTO_ACTIVATE 0`\n```\n\n== Windows\n\nAdd the following to your PowerShell profile (`$PROFILE`):\n\n```powershell\n(&mise activate pwsh) | Out-String | Invoke-Expression\n```\n\nIn case you need to open your PowerShell profile:\n\n```powershell\n# create profile if it doesn't already exist\nif (-not (Test-Path $profile)) { New-Item $profile -Force }\n# open the profile\nInvoke-Item $profile\n```\n\n- If not using PowerShell, add `<homedir>\\AppData\\Local\\mise\\shims` to `PATH`.\n\n== Other package managers\n\n::: code-group\n\n```sh [bash]\necho 'eval \"$(mise activate bash)\"' >> ~/.bashrc\n```\n\n```sh [zsh]\necho 'eval \"$(mise activate zsh)\"' >> ~/.zshrc\n```\n\n```sh [fish]\necho 'mise activate fish | source' >> ~/.config/fish/config.fish\n```\n\n:::\n\nRestart your shell session after modifying your rc file. Run [`mise dr|doctor`](/cli/doctor.html) to verify everything is set up correctly.\n\nWith mise activated, tools are available directly on `PATH`:\n\n```sh\nmise use --global node@24\nnode -v\n# v24.x.x\n```\n\nWhen you ran `mise use --global node@24`, mise updated your global config:\n\n```toml [~/.config/mise/config.toml]\n[tools]\nnode = \"24\"\n```\n\n## 4. Use tools from backends (npm, pipx, core, aqua, github) {#tool-backends}\n\n```mermaid\nflowchart LR\n  subgraph Backends\n    core\n    aqua\n    github\n    npm\n    pipx\n  end\n\n  core --> node[\"core:node\"]\n  core --> python[\"core:python\"]\n  aqua -->gh[\"aqua:cli/cli\"]\n  github -->ripgrep[\"github:BurntSushi/ripgrep\"]\n  github -->ruff[\"github:astral-sh/ruff\"]\n  npm --> prettier[\"npm:prettier\"]\n  npm --> claude_code[\"npm:@anthropic-ai/claude-code\"]\n  pipx -->black[\"pipx:black\"]\n  pipx -->pycowsay[\"pipx:pycowsay\"]\n  aqua -->terraform[\"aqua:hashicorp/terraform\"]\n\n  subgraph Tools\n    node\n    python\n    gh\n    ripgrep\n    ruff\n    prettier\n    claude_code\n    black\n    pycowsay\n    terraform\n  end\n```\n\nBackends are the package ecosystems that mise pulls tools from. With `mise use`, you can install from any of them.\n\nInstall [claude-code](https://www.npmjs.com/package/@anthropic-ai/claude-code) from npm:\n\n```sh\n# one-off\nmise exec npm:@anthropic-ai/claude-code -- claude --version\n\n# or install globally\nmise use --global npm:@anthropic-ai/claude-code\nclaude --version\n```\n\nInstall [black](https://github.com/psf/black) from PyPI via pipx:\n\n```sh\n# one-off\nmise exec pipx:black -- black --version\n\n# or install globally\nmise use --global pipx:black\nblack --version\n```\n\nInstall [ripgrep](https://github.com/BurntSushi/ripgrep) directly from GitHub releases:\n\n```sh\n# one-off\nmise exec github:BurntSushi/ripgrep -- rg --version\n\n# or install globally\nmise use --global github:BurntSushi/ripgrep\nrg --version\n```\n\nSee [Backends](/dev-tools/backends/) for more ecosystems and details.\n\n## 5. Setting environment variables {#environment-variables}\n\nDefine environment variables in `mise.toml` — they'll be loaded whenever mise is activated or when using `mise exec`:\n\n```toml [mise.toml]\n[env]\nNODE_ENV = \"production\"\n```\n\n```sh\nmise exec -- node --eval 'console.log(process.env.NODE_ENV)'\n\n# or if mise is activated in your shell\necho \"node env: $NODE_ENV\"\n# node env: production\n```\n\n## 6. Run a task {#run-a-task}\n\nDefine tasks in `mise.toml` and run them with `mise run`:\n\n```toml [mise.toml]\n[tasks]\nhello = \"echo hello from mise\"\n```\n\n```sh\nmise run hello\n# hello from mise\n```\n\n:::tip\nmise automatically installs all tools from `mise.toml` before running a task.\n:::\n\nSee [tasks](/tasks/) for more on defining and running tasks.\n\n## 7. Next steps {#next-steps}\n\nFollow the [walkthrough](/walkthrough) for more examples on how to use mise.\n\n### Set up autocompletion {#autocompletion}\n\nSee [autocompletion](/installing-mise.html#autocompletion) to learn how to set up autocompletion for your shell.\n\n### GitHub API rate limiting {#github-api-rate-limiting}\n\n::: warning\nMany tools in mise require the GitHub API. Unauthenticated requests are often rate limited — if you see 4xx errors, set `MISE_GITHUB_TOKEN` or `GITHUB_TOKEN` to a [personal access token](https://github.com/settings/tokens/new?description=MISE_GITHUB_TOKEN) (no scopes required).\n:::\n"
  },
  {
    "path": "docs/glossary.md",
    "content": "# Glossary\n\nThis glossary defines key terms and concepts used throughout the mise documentation.\n\n## Core Concepts\n\n**Activation**\n: The process of loading mise's context (tools, environment variables, PATH modifications) into your shell session. Typically done via `eval \"$(mise activate bash)\"` in your shell rc file. See [Installing mise](/installing-mise) for setup instructions.\n\n**Backend**\n: A package manager or ecosystem that mise uses to install and manage tools. Each backend knows how to fetch, install, and manage tools from its respective source. See [Backends](#backends) below and [Backend Architecture](/dev-tools/backend_architecture) for details.\n\n**Core Tools**\n: Built-in tool implementations written in Rust that ship with mise. These provide first-class support for popular languages like Node.js, Python, Ruby, Go, and others. See [Core tools](/core-tools) for the full list.\n\n**mise.toml**\n: The primary configuration file for mise projects. Contains tool versions, environment variables, tasks, and hooks. See [Configuration](/configuration) for the full specification.\n\n**mise.local.toml**\n: A user-local configuration file that overrides `mise.toml`. Typically added to `.gitignore` for personal settings that shouldn't be shared with the team.\n\n**Plugin**\n: An extension that adds functionality to mise, such as managing additional tools or setting up environment variables. See [Plugins](/plugins) for an overview.\n\n**Registry**\n: The collection of tool aliases that map user-friendly short names to their full backend specifications. For example, `aws-cli` maps to `aqua:aws/aws-cli`. See [Registry](/registry).\n\n**Tool**\n: A development tool or runtime that mise can install and manage, such as `node`, `python`, `terraform`, or `jq`.\n\n**Tool Request**\n: A user's specification for a tool version, which may be fuzzy or use aliases. Examples: `node@18`, `python@latest`, `go@1.21`. These get resolved to concrete Tool Versions.\n\n**Tool Version**\n: A concrete, resolved version of a tool. For example, `node@18` (tool request) might resolve to `node@18.19.0` (tool version).\n\n**Toolset**\n: An immutable collection of resolved tools for a specific context, containing all the Tool Versions that should be active for a directory or project.\n\n## Backends\n\nmise supports multiple backends for installing tools from different sources:\n\n**aqua**\n: Backend using the [aqua-proj](https://aquaproj.github.io/) registry. Supports SLSA provenance verification and provides access to thousands of tools. See [aqua backend](/dev-tools/backends/aqua).\n\n**asdf**\n: Legacy backend compatible with [asdf](https://asdf-vm.com/) shell-script plugins. Linux and macOS only. Slower than native backends but provides access to the asdf plugin ecosystem. See [asdf backend](/dev-tools/backends/asdf).\n\n**cargo**\n: Installs Rust tools by compiling them with `cargo install`. See [cargo backend](/dev-tools/backends/cargo).\n\n**conda**\n: Installs packages from Conda repositories. See [conda backend](/dev-tools/backends/conda).\n\n**dotnet**\n: Installs .NET tools. See [dotnet backend](/dev-tools/backends/dotnet).\n\n**gem**\n: Installs Ruby gems as tools. See [gem backend](/dev-tools/backends/gem).\n\n**github**\n: Installs tools directly from GitHub releases. See [github backend](/dev-tools/backends/github).\n\n**gitlab**\n: Installs tools directly from GitLab releases. See [gitlab backend](/dev-tools/backends/gitlab).\n\n**go**\n: Installs Go tools using `go install`. See [go backend](/dev-tools/backends/go).\n\n**http**\n: Installs tools from arbitrary HTTP/HTTPS URLs. See [http backend](/dev-tools/backends/http).\n\n**npm**\n: Installs Node.js packages and CLI tools from the npm registry. See [npm backend](/dev-tools/backends/npm).\n\n**pipx**\n: Installs Python CLI tools in isolated environments using pipx. See [pipx backend](/dev-tools/backends/pipx).\n\n**spm**\n: Installs tools via Swift Package Manager. See [spm backend](/dev-tools/backends/spm).\n\n**ubi**\n: Universal Binary Installer for tools distributed as single binaries. See [ubi backend](/dev-tools/backends/ubi).\n\n**vfox**\n: Backend compatible with [VersionFox](https://vfox.lhan.me/) plugins. See [vfox backend](/dev-tools/backends/vfox).\n\n## Shell Integration\n\n**hook-env**\n: The `mise hook-env` command that exports environment changes for shell integration. Called automatically by the shell hook installed via `mise activate`.\n\n**PATH Activation**\n: The default method of shell integration where mise updates the `PATH` environment variable at each prompt to include the appropriate tool binaries.\n\n**Reshim**\n: The process of updating the shims directory after tools are installed or removed. Run `mise reshim` if shims get out of sync.\n\n**Shims**\n: Small executable scripts that intercept tool commands and delegate to mise, which loads the appropriate tool context before execution. An alternative to PATH activation. See [Shims](/dev-tools/shims).\n\n## Configuration\n\n**config_root**\n: The canonical project root directory that mise uses when resolving relative paths in configuration files. Set via the `MISE_PROJECT_ROOT` environment variable or detected automatically.\n\n**Configuration Environments**\n: Environment-specific configuration files like `mise.dev.toml` or `mise.prod.toml`, activated via the `MISE_ENV` environment variable. See [Configuration Environments](/configuration/environments).\n\n**Configuration Hierarchy**\n: The system where mise.toml files at different levels (system, global, project) are merged together, with files closer to the current directory taking precedence over parent directories.\n\n**Settings**\n: Global mise configuration options stored in `~/.config/mise/settings.toml` that define behavior across all projects. See [Settings](/configuration/settings).\n\n**Templates**\n: Dynamic values in configuration using Tera template syntax, like <span v-pre>`{{env.HOME}}`</span> or <span v-pre>`{{arch()}}`</span>. See [Templates](/templates).\n\n## Environment Variables\n\n**env.\\_ directives**\n: Special environment configuration directives for advanced setup:\n\n- `env._.file` - Load variables from a file (e.g., `.env`)\n- `env._.path` - Prepend directories to PATH\n- `env._.source` - Source a shell script\n\n**Lazy Evaluation**\n: Environment variables configured with `tools = true` that can access tool-provided environment variables. These are evaluated after tools are loaded.\n\n**Redaction**\n: Marking sensitive environment variables with `redact = true` to hide their values from mise output and logs.\n\n## Hooks\n\n**Hooks**\n: Scripts that automatically execute during mise activation at specific events. An experimental feature. See [Hooks](/hooks).\n\n**cd hook**\n: Runs whenever you change directories while mise is active.\n\n**enter hook**\n: Runs when entering a directory where a mise.toml becomes active.\n\n**leave hook**\n: Runs when leaving a directory where a mise.toml was active.\n\n**postinstall hook**\n: Runs after a tool is successfully installed.\n\n**preinstall hook**\n: Runs before a tool installation begins.\n\n**watch_files hook**\n: Runs when specified files change. Requires `mise activate` for file watching.\n\n## Tasks\n\n**Dependency Graph**\n: A Directed Acyclic Graph (DAG) used internally to resolve task execution order based on dependencies.\n\n**File Tasks**\n: Tasks defined as standalone executable scripts in directories like `mise-tasks/` or `.mise/tasks/`. See [File Tasks](/tasks/file-tasks).\n\n**Task**\n: A reusable command defined in mise.toml or as a standalone script that executes within the mise environment. See [Tasks](/tasks/).\n\n**Task Dependencies**\n: Relationships between tasks defined via `depends` (run before), `depends_post` (run after), or `wait_for` (wait but don't trigger). See [Task Configuration](/tasks/task-configuration).\n\n**TOML Tasks**\n: Tasks defined directly in the `[tasks]` section of mise.toml files. See [TOML Tasks](/tasks/toml-tasks).\n\n## Directories & Environment\n\n**MISE_CACHE_DIR**\n: Directory where mise caches downloaded files and metadata. Defaults to `~/.cache/mise` on Linux, `~/Library/Caches/mise` on macOS.\n\n**MISE_DATA_DIR**\n: Directory where mise stores installed tools and other persistent data. Defaults to `~/.local/share/mise`.\n\n**MISE_PROJECT_ROOT**\n: Environment variable automatically set to the root directory of the current project (where the mise.toml is located).\n\n## Other Terms\n\n**Aliases**\n: Alternative names for tool versions, allowing shortcuts like `lts` for Node.js LTS versions. See [Tool Aliases](/dev-tools/aliases).\n\n**direnv**\n: An external tool for environment management that mise can work alongside. See [direnv integration](/direnv).\n\n**mise-en-place**\n: French culinary phrase meaning \"everything in its place\" - the philosophy behind mise. Chefs prepare all ingredients before cooking; developers should have all tools ready before coding.\n\n**mise.lock**\n: A lockfile that records exact resolved versions for reproducible environments across machines and CI. See [mise.lock](/dev-tools/mise-lock).\n\n**Tool Options**\n: Configuration in mise.toml that changes tool behavior, such as setting a Python `virtualenv` path or Node.js `corepack` preferences.\n"
  },
  {
    "path": "docs/hooks.md",
    "content": "# Hooks <Badge type=\"warning\" text=\"experimental\" />\n\nYou can have mise automatically execute scripts during a `mise activate` session. You cannot use these\nwithout the `mise activate` shell hook installed in your shell—except the `preinstall` and `postinstall` hooks.\nThe configuration goes into `mise.toml`.\n\n## CD hook\n\nThis hook is run anytimes the directory is changed.\n\n```toml\n[hooks]\ncd = \"echo 'I changed directories'\"\n```\n\n## Enter hook\n\nThis hook is run when the project is entered. Changing directories while in the project will not trigger this hook again.\n\n```toml\n[hooks]\nenter = \"echo 'I entered the project'\"\n```\n\n## Leave hook\n\nThis hook is run when the project is left. Changing directories while in the project will not trigger this hook.\n\n```toml\n[hooks]\nleave = \"echo 'I left the project'\"\n```\n\n## Preinstall/postinstall hook\n\nThese hooks are run before and after tools are installed (respectively). Unlike other hooks, these hooks do not require `mise activate`.\n\n```toml\n[hooks]\npreinstall = \"echo 'I am about to install tools'\"\npostinstall = \"echo 'I just installed tools'\"\n```\n\nThe `postinstall` hook receives a `MISE_INSTALLED_TOOLS` environment variable containing a JSON array of the tools that were just installed:\n\n```toml\n[hooks]\npostinstall = '''\necho \"Installed: $MISE_INSTALLED_TOOLS\"\n# Example output: [{\"name\":\"node\",\"version\":\"20.10.0\"},{\"name\":\"python\",\"version\":\"3.12.0\"}]\n'''\n```\n\n## Tool-level postinstall\n\nIndividual tools can define their own postinstall scripts using the `postinstall` option. These run immediately after each tool is installed (before other tools in the same session are installed):\n\n```toml\n[tools]\nnode = { version = \"20\", postinstall = \"npm install -g pnpm\" }\npython = { version = \"3.12\", postinstall = \"pip install pipx\" }\n```\n\nTool-level postinstall scripts receive the following environment variables:\n\n- `MISE_TOOL_NAME`: The short name of the tool (e.g., \"node\", \"python\")\n- `MISE_TOOL_VERSION`: The version that was installed (e.g., \"20.10.0\", \"3.12.0\")\n- `MISE_TOOL_INSTALL_PATH`: The path where the tool was installed\n\n## Task hooks\n\nInstead of inline scripts, hooks can reference mise tasks. The task is executed as a subprocess\nvia `mise run`, so it reuses the full task system including dependencies, environment variables,\nand file-based task definitions.\n\n```toml\n[tasks.setup]\nrun = \"echo 'setting up project'\"\ndepends = [\"install-deps\"]\n\n[hooks]\nenter = { task = \"setup\" }\n```\n\nYou can mix task references with inline scripts in arrays:\n\n```toml\n[hooks]\nenter = [\"echo 'entering project'\", { task = \"setup\" }]\n```\n\nTask hooks work with all hook types (`enter`, `leave`, `cd`, `preinstall`, `postinstall`).\n\n## Watch files hook\n\nWhile using `mise activate` you can have mise watch files for changes and execute a script or task when a file changes.\n\n```toml\n[[watch_files]]\npatterns = [\"src/**/*.rs\"]\nrun = \"cargo fmt\"\n```\n\nYou can also reference a mise task instead of an inline script:\n\n```toml\n[[watch_files]]\npatterns = [\"uv.lock\"]\ntask = \"sync-deps\"\n```\n\nEach `[[watch_files]]` entry should have either `run` or `task`, but not both.\n\nThis hook will have the following environment variables set:\n\n- `MISE_WATCH_FILES_MODIFIED`: A colon-separated list of the files that have been modified. Colons are escaped with a backslash.\n\n## Hook execution\n\nHooks are executed with the following environment variables set:\n\n- `MISE_ORIGINAL_CWD`: The directory that the user is in.\n- `MISE_PROJECT_ROOT`: The root directory of the project.\n- `MISE_PREVIOUS_DIR`: The directory that the user was in before the directory change (only if a directory change occurred).\n- `MISE_INSTALLED_TOOLS`: A JSON array of tools that were installed (only for `postinstall` hooks).\n\n## Shell hooks\n\nHooks can be executed in the current shell, for example if you'd like to add bash completions when entering a directory:\n\n```toml\n[hooks.enter]\nshell = \"bash\"\nscript = \"source completions.sh\"\n```\n\n::: warning\nI feel this should be obvious but in case it's not, this isn't going to do any sort of cleanup\nwhen you _leave_ the directory like using `[env]` does in `mise.toml`. You're literally just\nexecuting shell code when you enter the directory which mise has no way to track at all.\nI don't think there is a solution to this problem and it's likely the reason direnv has never\nimplemented something similar.\n\nI think in most situations this is probably fine, though worth keeping in mind.\n\n:::\n\n## Multiple hooks syntax\n\nYou can use arrays to define multiple hooks in the same file:\n\n```toml\n[hooks]\nenter = [\n  \"echo 'I entered the project'\",\n  \"echo 'I am in the project'\"\n]\n\n[[hooks.cd]]\nscript = \"echo 'I changed directories'\"\n[[hooks.cd]]\nscript = \"echo 'I also directories'\"\n```\n"
  },
  {
    "path": "docs/how-i-use-mise.md",
    "content": "# How I use mise\n\nThis is a very different doc than the rest of the site. It's not my\nintention to make this valuable to anyone. In fact it may end up being\nuseful to 0 people.\n\nI'm probably the strangest user of mise out there. My use case is the\nmost atypical for a number of reasons I'll get to. That said, I often\nfind myself saying to friends \"you know the way I use mise...\" and thought\nit might be useful to actually write down the way I use it in case\nanyone is interested.\n\nThis is an advanced article. I'm not going to take the time to explain\nthe tools and techniques here. If you're curious, open a discussion or ask\nme in the Discord.\n\n## My setup\n\nI use a mac with fish shell and am a heavy homebrew user. I've been using\nboth for over a decade.\n\nMy main editor(s) are JetBrains products (IntelliJ, RustRover, Webstorm).\nI also use nvim as a secondary editor (Astronvim with some minimal config).\nI probably spend 70% of my time in JetBrains.\n\nI tend to keep a terminal open (kitty) while working in JetBrains. I do not\noften run tests or builds with in the IDE. Not sure why, just never been\nin the habit of that. (Because of that these docs and possibly mise support in\nIDEs may not be what it should be-it's just not how I work personally).\n\n## `mise activate`\n\nUnlike most mise users, I don't use `mise activate` or\nshims at all unless I'm explicitly testing them-and that's rarely the\ncase. It certainly doesn't go into my `~/.config/fish/config.fish`.\n\nBecause I work on mise itself, I often need to rebuild it and run the code from my repo. For this, I have the following bash shim located in\n`~/bin/@mise`:\n\n```fish\n#!/usr/bin/env bash\nset -euo pipefail\n\nexec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- \"$@\"\n```\n\n:::info\nThe \"@\" prefix I use for things that will perform a rebuild-i.e.: they're slow.\n:::\n\nThis way I can easily test mise in any directory with `@mise`. I probably\nrun this more often than without just out of habit. For example, if I want to test `mise activate` in zsh:\n\n```sh\nzsh\neval \"$(@mise activate zsh)\"\n```\n\n## Minimal tools\n\nMight be surprising to folks but I don't use too many mise plugins. Well\nI have a lot in my config, but I don't actually use them. They're for\ntesting.\n\nI tend to basically just use core plugins. I like mise for managing\nthings where I really care about the major version (like node). If it's\nsomething like `shfmt` or `jq` I don't really care about the version.\nI just want the latest and for me, I find `brew` to be better suited to\nthat purpose.\n\nI recognize that some people really like locking down their versions\nacross a team to keep things consistent. I think that's great too.\nPart of this is that I'm currently at Amazon where the tooling story\nis complicated let's just say-not in a bad way, just one where\nintegrating mise into the setup isn't as straightforward as a smaller\ncompany would be.\n\nOutside of Amazon I have a handful of open source projects, mostly\nmise-related and mostly fairly simple. Also mostly rust where I don't\nuse mise anyways.\n\nThe one big exception here is node which I quite like mise for. I assume\nothers do to because it's by far the most popular language. You'd\nprobably guess that since it's my example in nearly all of the docs.\n\nThat said, part of the reason for doing that in the docs is that it's 4\ncharacters and everyone knows what it is.\n\n## `.mise.local.toml`\n\nI'm a heavy user of this concept. I rarely like to actually commit `mise.toml`\nfiles into projects. I tend to see my mise config as my personal config that\nI use within other projects that I don't particularly want to share with others.\n\nOf course, this goes into my global gitconfig so I can easily add this to\nshared projects without submitting a PR.\n\nOne day when tasks is out of experimental, I may do this a lot less since I\nthink tasks are one thing I really want to share. For me, the `[tools]`\nsection is just so easy to write I don't mind doing it and don't like\nimposing the way that **I** setup my machine on others.\n\nThere is a social aspect of this as well that I'm conscious of. I'm\nthe author of `mise`. To me it's a little self-serving to go into a project\nand add a config for my own project. I'd love if _someone else_ did that\ninstead.\n\n## `~/.mise`\n\nI often need to access mise's internals so I do the following:\n\n```sh\nln -s ~/.mise ~/.config/mise\nln -s ~/.mise ~/.local/share/mise\nln -s ~/.mise ~/.local/state/mise\nln -s ~/.mise/cache ~/.cache/mise\n```\n\nIt is good that mise generally follows XDG spec, but for tools that I interact\nwith a lot I like to put them at the top level like this. Obviously,\nmise doesn't mind if all of these point to the same place or else it would\nnot work for me.\n"
  },
  {
    "path": "docs/ide-integration.md",
    "content": "# IDE Integration\n\nCode editors and IDEs work differently than interactive shells.\n\nUsually, they will either inherit the environment from your current shell (this is the case if you start it from a terminal like `nvim .` or `code .`) or will have [their own way](https://github.com/microsoft/vscode-docs/blob/906acccd6180d8425577f8297ed29e221ad3daca/docs/supporting/faq.md?plain=1#L238) to set up the environment.\n\nOnce you have launched the IDE, it won't reload the environment variables or the `PATH` provided by `mise` if you update your mise configuration files. Therefore, we cannot rely on the default `mise activate` method to automatically set up the editor.\n\nThere are a few ways to make `mise` work with your editor:\n\n- Some editors or IDE plugins have direct support for `mise` and can let you select the tools/sdk path from the IDE settings. This will let you access to the tool binaries but won't load the environment variables.\n- Most editors (and language plugins) will look for tools on the `PATH` and run them in the context of your project. Therefore, adding the `mise` shims to the `PATH` might be enough (see [below](#adding-shims-to-path-default-shell)). This will run the tool provided by mise and load the environment variables.\n- In other cases, you may need to manually indicate the path to the tools provided by `mise` in the IDE settings. This can be done by using [`mise which <tool>`](./cli/which.md) or [`mise where`](./cli/where). You can also provide the path to the tool shim (e.g. `~/.local/share/mise/shims/node`) if the plugin supports it as this will also load the environment variables when the tool is run.\n- Finally, some custom plugins have been developed to work with `mise`. You can find them in the [IDE Plugins](#ide-plugins) section.\n\n## Adding shims to PATH in your default shell profile {#adding-shims-to-path-default-shell}\n\nIDEs work better with [shims](./dev-tools/shims) than they do environment variable modifications. The simplest way is\nto add the mise shim directory to `PATH`.\n\nFor IntelliJ and VSCode—and likely others, you can modify your default shell's login (aka \"profile\")\nscript. Your default shell can be found with:\n\n::: code-group\n\n```shell [macos]\ndscl . -read /Users/$USER UserShell\n```\n\n```shell [linux]\ngetent passwd $USER | cut -d: -f7\n```\n\n:::\n\nYou can change your default shell with `chsh -s /path/to/shell` but you may need\nto first add it to `/etc/shells`. Once you know the right one, modify the appropriate file:\n\n::: code-group\n\n```zsh\n# ~/.zprofile\neval \"$(mise activate zsh --shims)\"\n```\n\n```bash\n# ~/.bash_profile or ~/.bash_login or ~/.profile\neval \"$(mise activate bash --shims)\"\n```\n\n```fish\n# ~/.config/fish/config.fish\nif status is-interactive\n  mise activate fish | source\nelse\n  mise activate fish --shims | source\nend\n```\n\n:::\n\n::: warning\nDo not use /bin/bash or /usr/bin/bash on macOS. bash is complicated, decades old, and mise isn't able to use as many features.\nUnless you consider yourself an expert on bash and know why I (and Apple for that matter) admonish using bash, just use zsh on macOS.\n:::\n\nOn Linux this is read when logging into the machine, so changing it requires logging out and back in for it to work. See #vscode below\nfor how to get VSCode to read the login file.\n\nThis assumes that `mise` is on `PATH`. If it is not, you'll need to use the absolute path (\ne.g.: `eval \"$($HOME/.local/bin/mise activate zsh --shims)\"`).\n\nHere is an example showing that VSCode will use `node` provided by `mise`:\n\n::: tabs\n=== VSCode\n\n![vscode using shims](./shims-vscode.png)\n\n=== IntelliJ\n![intellij using shims](./shims-intellij.png)\n:::\n\nAs mentioned above, using `shims` doesn't work with all mise features. For example, arbitrary [env vars](./environments/) in `[env]` will\nonly be set if a shim is executed. For this we need tighter integration with the IDE and/or a custom plugin.\n\n## IDE Plugins\n\nHere are some community plugins that have been developed to work with `mise`:\n\n- Emacs: [mise.el](https://github.com/liuyinz/mise.el)\n- IntelliJ: [intellij-mise](https://github.com/134130/intellij-mise)\n- VSCode: [mise-vscode](https://github.com/hverlin/mise-vscode)\n\n## Vim\n\n```vim\n\" Prepend mise shims to PATH\nlet $PATH = $HOME . '/.local/share/mise/shims:' . $PATH\n```\n\n## Neovim\n\n```lua\n-- Prepend mise shims to PATH\nvim.env.PATH = vim.env.HOME .. \"/.local/share/mise/shims:\" .. vim.env.PATH\n```\n\nFor a better Treesitter and LSP integration, check out the [neovim cookbook](./mise-cookbook/neovim.md).\n\n## emacs\n\n### Traditional shims way\n\n```lisp\n;; CLI tools installed by Mise\n;; See: https://www.emacswiki.org/emacs/ExecPath\n(setenv \"PATH\" (concat (getenv \"PATH\") \":/home/user/.local/share/mise/shims\"))\n(setq exec-path (append exec-path '(\"/home/user/.local/share/mise/shims\")))\n```\n\n### Use with package [mise.el](https://github.com/eki3z/mise.el)\n\n<https://github.com/eki3z/mise.el>\n\n> A GNU Emacs library which uses the mise tool to determine per-directory/project environment variables and then set those environment variables on a per-buffer basis.\n\n```lisp\n(require 'mise)\n(add-hook 'after-init-hook #'global-mise-mode)\n```\n\n## JetBrains Editors (IntelliJ, RustRover, PyCharm, WebStorm, RubyMine, GoLand, etc)\n\n### IntelliJ Plugin\n\n<https://github.com/134130/intellij-mise>\n\nThis plugin can automatically configure the IDE to use the tools provided by mise. It has also some support for running mise tasks and loading environment variables in the run configurations.\n\n### Direct SDK selection\n\nSome JetBrains IDEs (or language plugins) have direct support for `mise`. This allows you to select the SDK version from the IDE settings.\nExample for Java:\n\n![SDK settings](./intellij-sdk-selection.png)\n\n### SDK selection using asdf layout\n\nSome plugins cannot find SDK installed by `mise` yet but might have support for asdf.\nIn that case, a workaround is to symlink the mise tool directory which has same layout as asdf:\n\n```sh\nln -s ~/.local/share/mise ~/.asdf\n```\n\nThen they should show up on in Project Settings:\n\n![project settings](https://github.com/jdx/mise-docs/assets/216188/b34a0e3f-7af8-45c9-85b8-2c72bd1dc226)\n\nOr in the case of node (possibly other languages), it's under \"Languages & Frameworks\":\n\n![languages & frameworks](https://github.com/jdx/mise-docs/assets/216188/9926be1c-ab88-451a-8ace-edf2dac564b5)\n\n## VSCode\n\n### VSCode Automation Profile for macOS\n\nUnlike Linux, macOS does not read the login shell profile (`~/.profile`, or `~/.zprofile`) when logging into the machine. You'll likely\nwant to add this setting to VSCode config in order to have it load your shims:\n\n```json\n    \"terminal.integrated.automationProfile.osx\": {\n        \"path\": \"/usr/bin/zsh\",\n        \"args\": [\"--login\"]\n    }\n```\n\n:::tip\nYou can also use `[\"--login\", \"--interactive\"]` if you want to include `~/.zshrc`.\n:::\n\n### VSCode Plugin\n\nThere is a [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=hverlin.mise-vscode) which can configure other extensions for you, without having to modify your shell profile to add the shims to `PATH`.\n\nIn addition, it provides additional features such as:\n\n- Automatic configuration of other extensions to use tools provided by `mise`\n- Manage `mise` tasks, tools, and environment variables directly from VSCode\n- Load environment variables from `mise.toml` files in VSCode\n- Support for autocompletion and snippets for `mise.toml` file\n- Integration with VSCode tasks\n\n<https://github.com/hverlin/mise-vscode/> ([Documentation](https://hverlin.github.io/mise-vscode/))\n\n### Use [`mise exec`](./cli/exec) in launch Configuration\n\nWhile modifying your default shell profile is likely the easiest solution, you can also set\nthe tools in `launch.json`:\n\n::: details mise exec launch.json example\n\n```json\n{\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Launch Program\",\n      \"program\": \"${file}\",\n      \"args\": [],\n      \"osx\": {\n        \"runtimeExecutable\": \"mise\"\n      },\n      \"linux\": {\n        \"runtimeExecutable\": \"mise\"\n      },\n      \"runtimeArgs\": [\"exec\", \"--\", \"node\"]\n    }\n  ]\n}\n```\n\n:::\n\n## Xcode\n\nXcode projects can run system commands from script build phases and schemes. Since Xcode sandboxes\nthe execution of the script using the tool `/usr/bin/sandbox-exec`, don't expect Mise and the\nautomatically-activated tools to work out of the box. First, you'll need to\nadd `$(SRCROOT)/mise.toml` to the list of **Input files**. This is necessary for Xcode to allow\nreads to that file. Then, you can use `mise activate` to activate the tools you need:\n\n```bash\n# -C ensures that Mise loads the configuration from the Mise configuration\n# file in the project's root directory.\neval \"$($HOME/.local/bin/mise activate -C $SRCROOT bash --shims)\"\n\nswiftlint\n```\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\nlayout: home\ntitle: Home\n\nhero:\n  name: mise-en-place\n  tagline: The front-end to your dev env\n  actions:\n    - theme: brand\n      text: Getting Started\n      link: /getting-started\n    - theme: alt\n      text: Demo\n      link: /demo\n    - theme: alt\n      text: About\n      link: /about\n\nfeatures:\n  - title: Dev Tools\n    link: /dev-tools/\n    icon: 🔪\n    details: A polyglot tool version manager. Replaces asdf, nvm, pyenv, rbenv, and more — one tool for every language.\n  - title: Environments\n    details: Switch sets of environment variables per project directory. A smarter, simpler replacement for direnv.\n    icon: 🫕\n    link: /environments/\n  - title: Tasks\n    link: /tasks/\n    details: A powerful task runner that replaces make and npm scripts. Define, compose, and run with ease.\n    icon: 🍳\n---\n"
  },
  {
    "path": "docs/installing-mise.md",
    "content": "# Installing Mise\n\nIf you are new to `mise`, follow the [Getting Started](/getting-started) guide first.\n\n## Installation Methods\n\nThis page lists various ways to install `mise` on your system.\n\n| Platform              | Recommended    | Alternative     |\n| --------------------- | -------------- | --------------- |\n| macOS                 | Homebrew       | mise.run        |\n| Linux (Debian/Ubuntu) | apt            | mise.run        |\n| Linux (Fedora/RHEL)   | dnf            | mise.run        |\n| Linux (Arch)          | pacman         | mise.run        |\n| Linux (Alpine)        | apk            | mise.run        |\n| Windows               | Scoop          | winget          |\n| Any (Rust users)      | cargo binstall | cargo install   |\n| CI/Docker             | mise.run       | GitHub Releases |\n\n::: tip Which methods auto-update?\nPackage managers (apt, dnf, brew, pacman, etc.) update mise when you update system packages. Other methods can be updated with `mise self-update`.\n:::\n\n### <https://mise.run>\n\nNote that it isn't necessary for `mise` to be on `PATH`. If you run the activate script in your\nshell's rc\nfile, mise will automatically add itself to `PATH`.\n\n```sh\ncurl https://mise.run | sh\n```\n\nor with options\n\n```sh\ncurl https://mise.run | MISE_INSTALL_PATH=/usr/local/bin/mise sh\n```\n\n#### Shell-specific installation + activation\n\nFor a more streamlined setup, you can use shell-specific endpoints that will install mise and automatically configure activation in your shell's configuration file:\n\n::: code-group\n\n```sh [zsh]\ncurl https://mise.run/zsh | sh\n# Installs mise and adds activation to ~/.zshrc\n```\n\n```sh [bash]\ncurl https://mise.run/bash | sh\n# Installs mise and adds activation to ~/.bashrc\n```\n\n```sh [fish]\ncurl https://mise.run/fish | sh\n# Installs mise and adds activation to ~/.config/fish/config.fish\n```\n\n:::\n\nThese shell-specific installers will:\n\n- Install mise using the same logic as the main installer\n- Automatically detect your shell's configuration file\n- Add the activation line if it's not already present\n- Skip adding activation if it's already configured (safe to run multiple times)\n\nOptions:\n\n- `MISE_DEBUG=1` – enable debug logging\n- `MISE_QUIET=1` – disable non-error output\n- `MISE_INSTALL_PATH=/some/path` – change the binary path (default: `~/.local/bin/mise`)\n- `MISE_VERSION=v2025.12.0` – install a specific version\n\nIf you want to verify the install script hasn't been tampered with:\n\n```sh\ngpg --keyserver hkps://keys.openpgp.org --recv-keys 24853EC9F655CE80B48E6C3A8B81C9D17413A06D\ncurl https://mise.jdx.dev/install.sh.sig | gpg --decrypt > install.sh\n# ensure the above is signed with the mise release key\nsh ./install.sh\n```\n\n::: tip\nAs long as you don't change the version with `MISE_VERSION`, the install script will be pinned to whatever the latest\nversion was when it was downloaded with checksums inside the file. This makes downloading the file and putting it into\na project a great way to ensure that anyone installing with that script fetches the exact same mise bin.\n:::\n\nSupported os/arch:\n\n- `macos-x64`\n- `macos-arm64`\n- `linux-x64`\n- `linux-x64-musl`\n- `linux-arm64`\n- `linux-arm64-musl`\n- `linux-armv6`\n- `linux-armv6-musl`\n- `linux-armv7`\n- `linux-armv7-musl`\n\nIf you need something else, compile it with `cargo install mise` (see below).\n\n### apk\n\nFor Alpine Linux:\n\n```sh\napk add mise\n```\n\n_mise lives in\nthe [community repository](https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/mise/APKBUILD)._\n\n### apt\n\nOn Ubuntu 26.04+, mise is available via a PPA:\n\n```sh\nsudo add-apt-repository -y ppa:jdxcode/mise\nsudo apt update -y\nsudo apt install -y mise\n```\n\nFor older Ubuntu/Debian versions:\n\n```sh\nsudo apt update -y && sudo apt install -y curl\nsudo install -dm 755 /etc/apt/keyrings\ncurl -fSs https://mise.jdx.dev/gpg-key.pub | sudo tee /etc/apt/keyrings/mise-archive-keyring.asc 1> /dev/null\necho \"deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.asc] https://mise.jdx.dev/deb stable main\" | sudo tee /etc/apt/sources.list.d/mise.list\nsudo apt update -y\nsudo apt install -y mise\n```\n\n### pacman\n\nFor Arch Linux:\n\n```sh\nsudo pacman -S mise\n```\n\n[Arch package](https://archlinux.org/packages/extra/x86_64/mise/)\n\n### Cargo\n\nBuild from source with Cargo:\n\n```sh\ncargo install mise\n```\n\nDo it faster with [cargo-binstall](https://github.com/cargo-bins/cargo-binstall):\n\n```sh\ncargo install cargo-binstall\ncargo binstall mise\n```\n\nBuild from the latest commit in main:\n\n```sh\ncargo install mise --git https://github.com/jdx/mise --branch main\n```\n\n### dnf\n\n#### Fedora 41+, RHEL 9+, CentOS Stream 9+\n\n```sh\ndnf copr enable jdxcode/mise\ndnf install mise\n```\n\n[COPR package page](https://copr.fedorainfracloud.org/coprs/jdxcode/mise/)\n\n### Snap (Linux, currently in beta)\n\n```sh\nsudo snap install mise --classic --beta\n```\n\n[snapcraft.io page](https://snapcraft.io/mise)\n\n### Docker\n\nSee the [Docker cookbook](/mise-cookbook/docker) for tips on using mise with Docker.\n\n::: details Example Dockerfile\n\n```dockerfile\nFROM debian:13-slim\n\nRUN apt-get update \\\n    && apt-get -y --no-install-recommends install sudo curl git ca-certificates build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\nSHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\nENV MISE_DATA_DIR=\"/mise\"\nENV MISE_CONFIG_DIR=\"/mise\"\nENV MISE_CACHE_DIR=\"/mise/cache\"\nENV MISE_INSTALL_PATH=\"/usr/local/bin/mise\"\nENV PATH=\"/mise/shims:$PATH\"\nRUN curl https://mise.run | sh\nRUN mise trust -a && mise install\n```\n\n:::\n\n### Homebrew\n\n```sh\nbrew install mise\n```\n\n[Homebrew formula](https://formulae.brew.sh/formula/mise)\n\n### npm\n\nmise is available on npm as a precompiled binary. This isn't a Node.js package—just distributed\nvia npm. This is useful for JS projects that want to setup mise via `package.json` or `npx`.\n\n```sh\nnpm install -g @jdxcode/mise\n```\n\nUse npx if you just want to test it out for a single command without fully installing:\n\n```sh\nnpx @jdxcode/mise exec python@3.11 -- python some_script.py\n```\n\n[npm package](https://www.npmjs.com/package/@jdxcode/mise)\n\n### GitHub Releases\n\nDownload the latest release from [GitHub](https://github.com/jdx/mise/releases).\n\n```sh\ncurl -L https://github.com/jdx/mise/releases/download/v2025.12.0/mise-v2025.12.0-linux-x64 > /usr/local/bin/mise\nchmod +x /usr/local/bin/mise\n```\n\n### MacPorts\n\n```sh\nsudo port install mise\n```\n\n[MacPorts port](https://ports.macports.org/port/mise/)\n\n### nix\n\nFor the Nix package manager, at release 24.05 or later:\n\n```sh\nnix-env -iA mise\n```\n\nYou can also import the package directly using\n`mise-flake.packages.${system}.mise`. It supports all default Nix\nsystems.\n\n::: tip NixOS compiles from source by default\nFor precompiled binaries, enable [nix-ld](https://github.com/Mic92/nix-ld) and disable [`all_compile`](/configuration/settings.html#all_compile).\n:::\n\n### yum (RHEL 8, CentOS Stream 8, Amazon Linux 2)\n\n```sh\nyum install -y yum-utils\nyum-config-manager --add-repo https://mise.jdx.dev/rpm/mise.repo\nyum install -y mise\n```\n\n### zypper\n\n```sh\nsudo wget https://mise.jdx.dev/rpm/mise.repo -O /etc/zypp/repos.d/mise.repo\nsudo zypper refresh\nsudo zypper install mise\n```\n\n### Windows - Scoop\n\nThis is the recommended way to install mise on Windows. It will automatically add your shims to PATH.\n\n```sh\nscoop install mise\n```\n\n[Scoop manifest](https://github.com/ScoopInstaller/Main/blob/master/bucket/mise.json)\n\n### Windows - winget\n\n```sh\nwinget install jdx.mise\n```\n\n[winget manifest](https://github.com/microsoft/winget-pkgs/tree/master/manifests/j/jdx/mise)\n\n### Windows - Chocolatey\n\n::: info\nchocolatey version is currently outdated.\n:::\n\n```sh\nchoco install mise\n```\n\n### Windows - manual\n\nDownload the latest release from [GitHub](https://github.com/jdx/mise/releases) and add the binary\nto your PATH.\n\nIf your shell does not support `mise activate`, you would want to edit PATH to include the shims directory (by default: `%LOCALAPPDATA%\\mise\\shims`).\n\n## Shells\n\n### Bash\n\n```sh\necho 'eval \"$(mise activate bash)\"' >> ~/.bashrc\n```\n\n### Zsh\n\n```sh\necho 'eval \"$(mise activate zsh)\"' >> \"${ZDOTDIR-$HOME}/.zshrc\"\n```\n\n### Fish\n\n```sh\necho 'mise activate fish | source' >> ~/.config/fish/config.fish\n```\n\n::: tip\nFor homebrew and possibly other installs mise is automatically activated so\nthis is not necessary.\n\nSee [`MISE_FISH_AUTO_ACTIVATE=1`](/configuration#mise-fish-auto-activate-1) for more information.\n:::\n\n### PowerShell\n\n::: warning\nSee [about_Profiles](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles) docs to find your actual profile location.\nYou will need to first create the parent directory if it does not exist.\n:::\n\n```powershell\necho '(&mise activate pwsh) | Out-String | Invoke-Expression' >> $HOME\\Documents\\PowerShell\\Microsoft.PowerShell_profile.ps1\n```\n\n### Nushell\n\nNu\ndoes [not support `eval`](https://www.nushell.sh/book/how_nushell_code_gets_run.html#eval-function)\nInstall Mise by appending `env.nu` and `config.nu`:\n\n```nushell\n'\nlet mise_path = $nu.default-config-dir | path join mise.nu\n^mise activate nu | save $mise_path --force\n' | save $nu.env-path --append\n\"\\nuse ($nu.default-config-dir | path join mise.nu)\" | save $nu.config-path --append\n```\n\nIf you prefer to keep your dotfiles clean you can save it to a different directory then\nupdate `$env.NU_LIB_DIRS`:\n\n```nushell\n\"\\n$env.NU_LIB_DIRS ++= ($mise_path | path dirname | to nuon)\" | save $nu.env-path --append\n```\n\n### Xonsh\n\nSince `.xsh` files are [not compiled](https://github.com/xonsh/xonsh/issues/3953) you may shave a\nbit off startup time by using a pure Python import: add the code below to, for\nexample, `~/.config/xonsh/mise.py` config file and `import mise` it in `~/.config/xonsh/rc.xsh`:\n\n```python\nfrom pathlib import Path\nfrom xonsh.built_ins import XSH\n\nctx = XSH.ctx\nmise_init = subprocess.run([Path('~/bin/mise').expanduser(),'activate','xonsh'],capture_output=True,encoding=\"UTF-8\").stdout\nXSH.builtins.execx(mise_init,'exec',ctx,filename='mise')\n```\n\nOr continue to use `rc.xsh`/`.xonshrc`:\n\n```sh\necho 'execx($(~/bin/mise activate xonsh))' >> ~/.config/xonsh/rc.xsh # or ~/.xonshrc\n```\n\nGiven that `mise` replaces both shell env `$PATH` and OS environ `PATH`, watch out that your configs\ndon't have these two set differently (might\nthrow `os.environ['PATH'] = xonsh.built_ins.XSH.env.get_detyped('PATH')` at the end of a config to\nmake sure they match)\n\n### Elvish\n\nAdd following to your `rc.elv`:\n\n```shell\nvar mise: = (ns [&])\neval (mise activate elvish | slurp) &ns=$mise: &on-end={|ns| set mise: = $ns }\nmise:activate\n```\n\nOptionally alias `mise` to `mise:mise` for seamless integration of `mise {activate,deactivate,shell}`:\n\n```shell\nedit:add-var mise~ {|@args| mise:mise $@args }\n```\n\n### Something else?\n\nAdding a new shell is not hard at all since very little shell code is\nin this project.\n[See here](https://github.com/jdx/mise/tree/main/src/shell) for how\nthe others are implemented. If your shell isn't currently supported\nI'd be happy to help you get yours integrated.\n\n## Autocompletion\n\n::: tip\nSome installation methods automatically install autocompletion scripts.\n:::\n\nThe [`mise completion`](/cli/completion.html) command can generate autocompletion scripts for your shell.\nThis requires `usage` to be installed. If you don't have it, install it with:\n\n```shell\nmise use -g usage\n```\n\nThen, run the following commands to install the completion script for your shell:\n\n::: code-group\n\n```sh [bash]\n# This requires bash-completion to be installed\nmkdir -p ~/.local/share/bash-completion/completions/\nmise completion bash --include-bash-completion-lib > ~/.local/share/bash-completion/completions/mise\n```\n\n```sh [zsh]\n# If you use oh-my-zsh, there is a `mise` plugin. Update your .zshrc file with:\n# plugins=(... mise)\n\n# Otherwise, look where zsh search for completions with\necho $fpath | tr ' ' '\\n'\n\n# if you installed zsh with `apt-get` for example, this will work:\nmkdir -p /usr/local/share/zsh/site-functions\nmise completion zsh  > /usr/local/share/zsh/site-functions/_mise\n```\n\n```sh [fish]\nmise completion fish > ~/.config/fish/completions/mise.fish\n```\n\n:::\n\nThen source your shell's rc file or restart your shell.\n\n## Troubleshooting\n\nIf you encounter issues after installation, run:\n\n```sh\nmise doctor\n```\n\nThis will diagnose common problems with your mise setup. See [mise doctor](/cli/doctor) for more information.\n\n## Uninstalling\n\nUse `mise implode` to uninstall mise. This will remove the mise binary and all of its data. Use\n`mise implode --help` for more information.\n\nAlternatively, manually remove the following directories to fully clean up:\n\n- `~/.local/share/mise` (can also be `MISE_DATA_DIR` or `XDG_DATA_HOME/mise`)\n- `~/.local/state/mise` (can also be `MISE_STATE_DIR` or `XDG_STATE_HOME/mise`)\n- `~/.config/mise` (can also be `MISE_CONFIG_DIR` or `XDG_CONFIG_HOME/mise`)\n- on Linux: `~/.cache/mise` (can also be `MISE_CACHE_DIR` or `XDG_CACHE_HOME/mise`)\n- on macOS: `~/Library/Caches/mise` (can also be `MISE_CACHE_DIR`)\n"
  },
  {
    "path": "docs/lang/bun.md",
    "content": "# Bun\n\n`mise` can be used to install and manage multiple versions of [bun](https://bun.sh/) on the same system.\n\n> The following are instructions for using the bun mise core plugin. This is used when there isn't a\n> git plugin installed named \"bun\".\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/bun.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/bun.rs).\n\n## Usage\n\nThe following installs bun and makes it the global default:\n\n```sh\nmise use -g bun@0.7     # install bun 0.7.x\nmise use -g bun@latest  # install latest bun\n```\n\nSee available versions with `mise ls-remote bun`.\n\n> [!NOTE]\n> Avoid using `bun upgrade` to upgrade bun as `mise` will not be aware of the change.\n"
  },
  {
    "path": "docs/lang/deno.md",
    "content": "# Deno\n\n`mise` can be used to install and manage multiple versions of [deno](https://deno.land/) on the same system.\n\n> The following are instructions for using the deno mise core plugin. This is used when there isn't a\n> git plugin installed named \"deno\". If you want to use [asdf-deno](https://github.com/asdf-community/asdf-deno)\n> then run `mise plugins install deno https://github.com/asdf-community/asdf-deno`.\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/deno.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/deno.rs).\n\n## Usage\n\nThe following installs deno and makes it the global default:\n\n```sh\nmise use -g deno@1       # install deno 1.x\nmise use -g deno@latest  # install latest deno\n```\n\nSee available versions with `mise ls-remote deno`.\n\n> [!NOTE]\n> Avoid using `deno upgrade` to upgrade `deno` as `mise` will not be aware of the change.\n"
  },
  {
    "path": "docs/lang/dotnet.md",
    "content": "# .NET\n\nThe core .NET plugin installs .NET SDKs using Microsoft's official install script. All SDK versions are\ninstalled side-by-side under a shared `DOTNET_ROOT` directory, matching .NET's native multi-version model.\nThis means `dotnet --list-sdks` will see every version you've installed through mise.\n\nUnlike most tools, the SDKs don't live inside `~/.local/share/mise/installs` because they share a\ncommon root. mise symlinks the install path to `DOTNET_ROOT` and sets environment variables so the\ncorrect SDK is picked up.\n\n::: info\nThis plugin manages the **.NET SDK** itself. To install .NET global tools (e.g., `dotnet-ef`),\nuse the [`dotnet` backend](/dev-tools/backends/dotnet.html) with `dotnet:ToolName` syntax.\n:::\n\n## Usage\n\nUse the latest .NET SDK:\n\n```sh\nmise use -g dotnet@latest\ndotnet --version\n```\n\nUse a specific version:\n\n```sh\nmise use -g dotnet@8.0.400\ndotnet --version\n```\n\nInstall multiple SDKs side-by-side for multi-targeting:\n\n```sh\nmise use dotnet@8\nmise use dotnet@9\ndotnet --list-sdks\n```\n\n## `global.json` support\n\nmise recognizes `global.json` as an idiomatic version file. If your project contains a `global.json`\nwith an SDK version, mise will automatically use it:\n\n```json\n{\n  \"sdk\": {\n    \"version\": \"8.0.100\"\n  }\n}\n```\n\nEnable idiomatic version file support:\n\n```sh\nmise settings set idiomatic_version_file_enable_tools dotnet\n```\n\n## Isolated Mode\n\nBy default, all SDK versions share a single `DOTNET_ROOT` directory. This matches .NET's native\nside-by-side model and means `dotnet --list-sdks` shows every installed version.\n\nIf you prefer the traditional mise approach where each version gets its own directory, enable\nisolated mode:\n\n```sh\nmise settings set dotnet.isolated true\n```\n\nIn isolated mode each SDK version is installed under `~/.local/share/mise/installs/dotnet/<version>/`,\njust like most other mise-managed tools. `dotnet --list-sdks` will only report the currently active\nversion.\n\n|                      | Shared (default)       | Isolated                     |\n| -------------------- | ---------------------- | ---------------------------- |\n| `dotnet --list-sdks` | All installed versions | Active version only          |\n| Install location     | `DOTNET_ROOT`          | `installs/dotnet/<version>/` |\n| Multi-targeting      | Works out of the box   | Requires switching versions  |\n\n## Environment Variables\n\nThe plugin sets the following environment variables:\n\n| Variable                      | Value                                                      |\n| ----------------------------- | ---------------------------------------------------------- |\n| `DOTNET_ROOT`                 | Shared SDK install directory (or install path if isolated) |\n| `DOTNET_MULTILEVEL_LOOKUP`    | `0`                                                        |\n| `DOTNET_CLI_TELEMETRY_OPTOUT` | Only set when `dotnet.cli_telemetry_optout` is configured  |\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"dotnet\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/elixir.md",
    "content": "# Elixir\n\n`mise` can be used to manage multiple [`elixir`](https://elixir-lang.org/) versions on the same system.\n\n> The following are instructions for using the elixir core plugin. This is used when there isn't a git plugin installed named \"elixir\".\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/elixir.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/elixir.rs).\n\n## Usage\n\nUse the latest stable version of elixir:\n\n```sh\nmise use -g erlang elixir\n```\n\nNote that [`erlang`](/lang/erlang.html) is required to install `elixir`.\n"
  },
  {
    "path": "docs/lang/erlang.md",
    "content": "# Erlang\n\n`mise` can be used to install and manage multiple versions of [erlang](https://www.erlang.org/) on the same system.\n\n> The following are instructions for using the erlang core plugin.\n> This is used when there isn't a git plugin installed named \"erlang\".\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/erlang.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/erlang.rs).\n\n## Usage\n\nThe following installs erlang and makes it the global default:\n\n```sh\nmise use -g erlang@26\n```\n\nSee available versions with `mise ls-remote erlang`.\n\n## kerl\n\nThe plugin uses [kerl](https://github.com/kerl/kerl) under the hood to build erlang.\nSee kerl's docs for information on configuring kerl.\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"erlang\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/go.md",
    "content": "# Go\n\n`mise` can be used to install and manage multiple versions of [go](https://golang.org/) on the same system.\n\n> The following are instructions for using the go mise core plugin. This is used when there isn't a\n> git plugin installed named \"go\". If you want to use [asdf-golang](https://github.com/kennyp/asdf-golang)\n> then use `mise plugins install go GIT_URL`.\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/go.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/go.rs).\n\n## Usage\n\nThe following installs the latest version of go-1.21.x (if some version of 1.21.x is not already\ninstalled) and makes it the global default:\n\n```sh\nmise use -g go@1.21\n```\n\nMinor go versions 1.20 and below require specifying `prefix` before the version number because the\nfirst version of each series was released without a `.0` suffix, making 1.20 an exact version match:\n\n```sh\nmise use -g go@prefix:1.20\n```\n\n## `.go-version` file support\n\nmise uses a `mise.toml` or `.tool-versions` file for auto-switching between software versions.\nHowever, it can also read go-specific version files named `.go-version`.\n\nSee [idiomatic version files](/configuration.html#idiomatic-version-files)\n\n## Default packages\n\nmise can automatically install a default set of packages right after installing a new go version.\nTo enable this feature, provide a `$HOME/.default-go-packages` file that lists one packages per\nline, for example:\n\n```text\ngithub.com/daixiang0/gci # allows comments\ngithub.com/jesseduffield/lazygit\n```\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"go\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/java.md",
    "content": "# Java\n\nLike `sdkman`, `mise` can manage multiple versions of Java on the same system.\n\n> The following are instructions for using the java mise core plugin. This is used when there isn't a\n> git plugin installed named \"java\". If you want to use [asdf-java](https://github.com/halcyon/asdf-java)\n> then use `mise plugins install java GIT_URL`.\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/java.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/java.rs).\n\n## Usage\n\nThe following installs the latest version of openjdk-21.x (if some version of openjdk-21.x is\nnot already installed) and makes it the global default:\n\n```sh\nmise use -g java@openjdk-21\nmise use -g java@21         # alternate shorthands for openjdk\n```\n\nYou can also install a jdk from a different vendor. To get the latest version from a vendor just use the\nvendor prefix.\n\n```sh\nmise use -g java@temurin        # latest version from Temurin\nmise use -g java@temurin-21\nmise use -g java@zulu-21\nmise use -g java@corretto-21\n```\n\nSee available versions with `mise ls-remote java`.\n\n::: warning\nNote that shorthand versions (like `21` in the example) use [`OpenJDK`](https://openjdk.org/) as the default vendor. The default vendor can be changed with the setting [`java.shorthand_vendor`](../configuration/settings.md#java.shorthand_vendor). The OpenJDK versions will only be updated for a 6-month period. Updates and security patches will not be available after this short period. This also applies for LTS versions.\n\nFor more information on which JDK to choose, see <https://whichjdk.com>.\n:::\n\n## macOS JAVA_HOME Integration\n\nSome applications in macOS rely on `/usr/libexec/java_home` to find installed Java runtimes.\n\nTo integrate an installed Java runtime with macOS run the following commands for the proper\nversion (e.g. openjdk-21).\n\n```sh\nsudo mkdir /Library/Java/JavaVirtualMachines/openjdk-21.jdk\nsudo ln -s ~/.local/share/mise/installs/java/openjdk-21/Contents /Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents\n```\n\n> Note: Not all distributions of the Java SDK support this integration (e.g liberica).\n\n## `.java-version` and `.sdkmanrc` files support\n\nThe Java core plugin supports the idiomatic version files `.java-version` and `.sdkmanrc`. See [idiomatic version files](/configuration.html#idiomatic-version-files).\n\nFor `.sdkmanrc` files, mise will try to map the vendor and version to the appropriate version\nstring. For example, the version `20.0.2-tem` will be mapped to `temurin-20.0.2`. Due to Azul's Zulu\nversioning, the version `11.0.12-zulu` will be mapped to the major version `zulu-11`.\n\nNot all vendors available in [sdkman](https://sdkman.io/jdks) are supported by mise.\nThe following vendors are NOT supported: `bsg` (Bisheng), `graal` (GraalVM), `nik` (Liberica NIK).\n\n### Using unsupported versions\n\nIn case an unsupported version of java is needed, some manual work is required:\n\n1. Download the unsupported version to a directory (e.g `~/.sdkman/candidates/java/21.0.1-open`)\n2. symlink the new version:\n\n```sh\nln -s ~/.sdkman/candidates/java/21.0.1-open ~/.local/share/mise/installs/java/21.0.1-open\n```\n\n3. If on Mac:\n\n```sh\nmkdir ~/.local/share/mise/installs/java/21.0.1-open/Contents\nmkdir ~/.local/share/mise/installs/java/21.0.1-open/Contents/MacOS\n\nln -s ~/.sdkman/candidates/java/21.0.1-open ~/.local/share/mise/installs/java/21.0.1-open/Contents/Home\ncp ~/.local/share/mise/installs/java/21.0.1-open/lib/libjli.dylib ~/.local/share/mise/installs/java/21.0.1-open/Contents/MacOS/libjli.dylib\n```\n\n4. Don't forget to make sure the cache is blocked and valid, by making sure an **empty** directory **exists** for your version in the [mise cache](https://mise.jdx.dev/directories.html#cache-mise):\n   e.g.\n\n```sh\n$ ls -R $MISE_CACHE_DIR/java\n21.0.1-open\n\nmise/java/21.0.1-open:\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `java` backend.\nThese options go in the `[tools]` section in `mise.toml`.\n\n### `release_type`\n\nThe `release_type` option allows you to specify the type of release to install. The following values\nare supported:\n\n- `ga` (default): General Availability release\n- `ea`: Early Access release\n\n```toml\n[tools]\n\"java\" = { version = \"openjdk-21\", release_type = \"ea\" }\n```\n\n## Gradle toolchains detection\n\nGradle can automatically detect toolchains installed by some tools (see [toolchain | auto-detection](https://docs.gradle.org/current/userguide/toolchains.html#sec:auto_detection)).\n\nAt the moment, `Gradle` does not support auto-detecting Java installations by `mise` (see [gradle/issues/29508](https://github.com/gradle/gradle/issues/29508) and [gradle/issues/29355](https://github.com/gradle/gradle/issues/29355)). A workaround is to leverage the fact that `mise` install layout is [similar to the one used by `asdf`](/ide-integration.html#sdk-selection-using-asdf-layout).\n\n```shell\nmkdir -p ~/.asdf/installs/ && ln -s ~/.local/share/mise/installs/java ~/.asdf/installs/\n```\n\nOtherwise, you can always use the [foojay-resolver-convention](https://plugins.gradle.org/plugin/org.gradle.toolchains.foojay-resolver-convention) plugin to let Gradle automatically install JDKs required by your project.\n"
  },
  {
    "path": "docs/lang/node.md",
    "content": "# Node\n\nLike `nvm`, (or `volta`, `fnm` or `asdf`...), `mise` can manage multiple versions of Node.js on the same system.\n\n> The following are instructions for using the node mise core plugin. This is used when there isn't a\n> git plugin installed named \"node\".\n> If you want to use [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs)\n> then run `mise plugins install node https://github.com/asdf-vm/asdf-nodejs`\n\nThe code for this is inside the mise repository at [`./src/plugins/core/node.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/node.rs).\n\n## Usage\n\nThe following installs the latest version of node-20.x and makes it the global\ndefault:\n\n```sh\nmise use -g node@20\n```\n\nSee the [Node.JS Cookbook](/mise-cookbook/nodejs.html) for common tasks and examples.\n\n## `.nvmrc` and `.node-version` support\n\nBy default, mise uses a `mise.toml` file for auto-switching between software versions.\n\nIt also supports `.tool-versions`, `.nvmrc` or `.node-version` file to find out what version of Node.js should be used. This will be used if `node` isn't defined in `mise.toml`.\n\nThis makes it a drop-in replacement for `nvm`. See [idiomatic version files](/configuration.html#idiomatic-version-files) for more information.\n\n## Default node packages\n\nmise-node can automatically install a default set of npm packages right after installing a node version. To enable this feature, provide a `$HOME/.default-npm-packages` file that lists one package per line, for example:\n\n```text\nlodash\nrequest\nexpress\n```\n\nYou can specify a non-default location of this file by setting a `MISE_NODE_DEFAULT_PACKAGES_FILE` variable.\n\n## \"nodejs\" -> \"node\" Alias\n\nYou cannot install/use a plugin named \"nodejs\". If you attempt this, mise will just rename it to\n\"node\". See the [FAQ](/faq.html#what-is-the-difference-between-nodejs-and-node-or-golang-and-go)\nfor an explanation.\n\n## Building from source\n\nIf compiling from source, see [BUILDING.md](https://github.com/nodejs/node/blob/main/BUILDING.md#building-nodejs-on-supported-platforms) in node's documentation for\nrequired system dependencies.\n\n```shell\nmise settings node.compile=1\nmise use node@latest\n```\n\n## Unofficial Builds\n\nNodejs.org offers a set of [unofficial builds](https://unofficial-builds.nodejs.org/) which are\ncompatible with some platforms that are not supported by the official binaries. These are a nice alternative to\ncompiling from source for these platforms.\n\nTo use, first set the mirror url to point to the unofficial builds:\n\n```sh\nmise settings node.mirror_url=https://unofficial-builds.nodejs.org/download/release/\n```\n\nIf your goal is to simply support an alternative arch/os like linux-loong64 or linux-armv6l, this is\nall that is required. Node also provides flavors such as musl or glibc-217 (an older glibc version\nthan what the official binaries are built with).\n\nTo use these, set `node.flavor`:\n\n```sh\nmise settings node.flavor=musl\nmise settings node.flavor=glibc-217\n```\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"node\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/python.md",
    "content": "# Python\n\nLike `pyenv`, `mise` can manage multiple versions of Python on the same system. Mise can also automatically create virtual environments for your projects and integrates with `uv`.\n\n> The following are instructions for using the python mise core plugin. The core plugin will be used\n> so long as no plugin is manually\n> installed named \"python\" using `mise plugins install python [GIT_URL]`.\n\nThe code for this is inside of the mise repository\nat [`./src/plugins/core/python.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/python.rs).\n\n## Usage\n\nThe following installs the latest version of python-3.11.x and makes it the global\ndefault:\n\n```sh\nmise use -g python@3.11\n```\n\nYou can also use multiple versions of python at the same time:\n\n```sh\n$ mise use -g python@3.10 python@3.11\n$ python -V\n3.10.0\n$ python3.11 -V\n3.11.0\n```\n\nYou can also install a specific python flavour. To get the latest version from a flavour just use the\nflavour prefix.\n\n```sh\nmise use -g python@anaconda         # latest version of anaconda\n```\n\nSee the [Python Cookbook](/mise-cookbook/python.html) for common tasks and examples.\n\n## `.python-version` support\n\n`.python-version`/`.python-versions` files are supported by mise. See [idiomatic version files](/configuration.html#idiomatic-version-files).\n\n## Automatic virtualenv activation\n\nPython comes with virtualenv support built in, use it with `mise.toml` configuration like\none of the following:\n\n```toml\n[tools]\npython = \"3.11\" # [optional] will be used for the venv\n\n[env]\n_.python.venv = \".venv\" # relative to this file's directory\n_.python.venv = \"/root/.venv\" # can be absolute\n_.python.venv = \"{{env.HOME}}/.cache/venv/myproj\" # can use templates\n_.python.venv = { path = \".venv\", create = true } # create the venv if it doesn't exist\n_.python.venv = { path = \".venv\", create = true, python = \"3.10\" } # use a specific python version\n_.python.venv = {\n  path = \".venv\", create = true,\n  python_create_args = [\"--without-pip\"], # pass args to python -m venv\n}\n_.python.venv = {\n  path = \".venv\", create = true,\n  uv_create_args = [\"--system-site-packages\"], # pass args to uv venv\n}\n# Install seed packages (pip, setuptools, and wheel) into the virtual environment.\n_.python.venv = { path = \".venv\", create = true, uv_create_args = ['--seed'] }\n```\n\nThe venv will need to be created manually with `python -m venv /path/to/venv` unless `create=true`.\nSee [env-directives](https://mise.jdx.dev/environments/#env-directives) for `_.python.venv`.\n\n## mise & uv\n\nIf you have installed `uv` (for example, with `mise use -g uv@latest`), `mise` will use it to create virtual environments. Otherwise, it will use the built-in `python -m venv` command.\n\nNote that `uv` does not include `pip` by default (as `uv` provides `uv pip` instead). If you need the `pip` package, add the `uv_create_args = ['--seed']` option.\n\n:::warning\nThe `true` value for `python.uv_venv_auto` is considered legacy and will be deprecated in a\nfuture release (planned for mise 2026.7). Prefer `\"source\"` or `\"create|source\"` instead.\nNote: the `python.uv_venv_auto` **setting** itself is not going away — only the `true` value is\nbeing phased out.\n:::\n\nOne difference between the legacy `true` value and the newer string values is that `true` also\nexports `UV_PYTHON` (set to just the Python version number). This tells `uv` which Python version\nto use, but does not guarantee that `uv` uses the specific interpreter managed by `mise` — `uv`\nmay fall back to a system or self-managed Python of the same version.\n\nTo strictly ensure `uv` uses `mise`'s managed Python interpreter, set `UV_PYTHON` to the actual\ninstall path instead:\n\n```toml\n[tools]\npython = \"3.12\"\n\n[env]\nUV_PYTHON = { value = \"{{ tools.python.path }}\", tools = true }\n```\n\nSee the [mise + uv Cookbook](/mise-cookbook/python.html#mise-uv) for more examples.\n\n## Default Python packages\n\nmise can automatically install a default set of Python packages with pip right after installing a\nPython version. To enable this feature, provide a `$HOME/.default-python-packages` file that lists\none package per line, for example:\n\n```text\nansible\npipenv\n```\n\nYou can specify a non-default location of this file by setting a `MISE_PYTHON_DEFAULT_PACKAGES_FILE`\nvariable.\n\n## Precompiled python binaries\n\nBy default, mise will\ndownload [precompiled binaries](https://github.com/astral-sh/python-build-standalone)\nfor python instead of compiling them with python-build. This makes installing python much faster.\n\nIn addition to being faster, it also means you don't have to install all of the system dependencies\neither.\n\nThat said, there are\nsome [quirks](https://github.com/astral-sh/python-build-standalone/blob/main/docs/quirks.rst)\nwith the precompiled binaries to be aware of.\n\nIf you'd like to disable these binaries, set `mise settings python.compile=1`.\n\nThese binaries may not work on older CPUs however you may opt into binaries which\nare more compatible with older CPUs by setting `MISE_PYTHON_PRECOMPILED_ARCH` with\na different version. See <https://gregoryszorc.com/docs/python-build-standalone/main/running.html> for\nmore information\non this option. Set it to \"x86_64\" for the most compatible binaries.\n\n## python-build\n\nOptionally, mise\nuses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv)\nto compile python runtimes,\nyou need to ensure\nits [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed\nbefore installing python with\npython-build.\n\n## Installing free-threaded python\n\nFree-threaded python can be installed via python-build by running the following:\n\n```bash\nMISE_PYTHON_COMPILE=0 MISE_PYTHON_PRECOMPILED_FLAVOR=freethreaded+pgo-full mise install python\n```\n\nOr to compile with python-build:\n\n```bash\nMISE_PYTHON_COMPILE=1 PYTHON_BUILD_FREE_THREADING=1 mise install python\n```\n\n## Troubleshooting errors with Homebrew\n\nIf you normally use Homebrew and you see errors regarding OpenSSL,\nyour best bet might be using the following command to install Python:\n\n```sh\nCFLAGS=\"-I$(brew --prefix openssl)/include\" \\\nLDFLAGS=\"-L$(brew --prefix openssl)/lib\" \\\nmise install python@latest;\n```\n\nHomebrew installs its own OpenSSL version, which may collide with system-expected ones.\nYou could even add that to your\n`.profile`,\n`.bashrc`,\n`.zshrc`...\nto avoid setting them every time\n\nAdditionally, if you encounter issues with python-build,\nyou may benefit from unlinking pkg-config prior to install\n([reason](https://github.com/pyenv/pyenv/issues/2823#issuecomment-1769081965)).\n\n```sh\nbrew unlink pkg-config\nmise install python@latest\nbrew link pkg-config\n```\n\nThus the entire script would look like:\n\n```sh\nbrew unlink pkg-config\nCFLAGS=\"-I$(brew --prefix openssl)/include\" \\\n  LDFLAGS=\"-L$(brew --prefix openssl)/lib\" \\\n  mise install python@latest\nbrew link pkg-config\n```\n\n## Settings\n\n`python-build` already has\na [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in\nadditional to that python in mise has a few extra configuration variables.\n\nSet these with `mise settings set [VARIABLE] [VALUE]` or by setting the environment variable.\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"python\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/ruby.md",
    "content": "# Ruby\n\nLike `rvm`, `rbenv`, or `asdf`, `mise` can manage multiple versions of [Ruby](https://www.ruby-lang.org/) on the same system.\n\n> The following are instructions for using the ruby mise core plugin. This is used when there isn't a\n> git plugin installed named \"ruby\". If you want to use [asdf-ruby](https://github.com/asdf-vm/asdf-ruby)\n> then use `mise plugins install ruby GIT_URL`.\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/ruby.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/ruby.rs).\n\n## Usage\n\nThe following installs the latest version of ruby-3.2.x (if some version of 3.2.x is not already\ninstalled) and makes it the global default:\n\n```sh\nmise use -g ruby@3.2\n```\n\nBehind the scenes, mise uses [`ruby-build`](https://github.com/rbenv/ruby-build) to compile ruby\nfrom source. Ensure that you have the necessary\n[dependencies](https://github.com/rbenv/ruby-build/wiki#suggested-build-environment) installed.\nYou can check its [README](https://github.com/rbenv/ruby-build/blob/master/README.md) for additional settings and some\ntroubleshooting.\n\n## Precompiled Binaries\n\nMise can download precompiled Ruby binaries instead of\ncompiling from source. This significantly reduces installation time.\n\nPrecompiled binaries will become the default in 2026.8.0. To opt in now:\n\n```sh\nmise settings ruby.compile=false\nmise use ruby@3.4.1\n```\n\nPrecompiled binaries are sourced from [jdx/ruby](https://github.com/jdx/ruby) and are available\nfor the following platforms:\n\n- macOS (arm64/Apple Silicon only)\n- Linux arm64\n- Linux x86_64\n\nIf a precompiled binary is not available for your platform or Ruby version, mise automatically\nfalls back to compiling from source using ruby-build.\n\nTo always compile from source even when precompiled binaries are available:\n\n```sh\nmise settings ruby.compile=true\n```\n\nYou can also use a custom source for precompiled binaries by setting `ruby.precompiled_url` to\neither a GitHub repo (e.g., `owner/repo`) or a full URL template.\n\nYou can also install a specific ruby flavour. To get the latest version from a flavour, just use the\nflavour prefix.\n\n```sh\nmise use -g ruby@truffleruby            # latest version of truffleruby\n```\n\n## Default gems\n\nmise can automatically install a default set of gems right after installing a new ruby version.\nTo enable this feature, provide a `$HOME/.default-gems` file that lists one gem per line, for\nexample:\n\n```text\n# supports comments\npry\nbcat ~> 0.6.0 # supports version constraints\nrubocop --pre # install prerelease version\n```\n\n## `.ruby-version` and `Gemfile` support\n\nmise uses a `mise.toml` or `.tool-versions` file for auto-switching between software versions.\nHowever, it can also read ruby-specific version files `.ruby-version` or `Gemfile`\n(if it specifies a ruby version).\n\nCreate a `.ruby-version` file for the current version of ruby:\n\n```sh\nruby -v > .ruby-version\n```\n\nEnable idiomatic version file reading for ruby:\n\n```sh\nmise settings add idiomatic_version_file_enable_tools ruby\n```\n\nSee [idiomatic version files](/configuration.html#idiomatic-version-files) for more information.\n\n## Manually updating ruby-build\n\nruby-build should update daily, however if you find versions do not yet exist you can force an\nupdate:\n\n```bash\nmise cache clean\nmise ls-remote ruby\n```\n\n## Settings\n\n`ruby-build` already has a\n[handful of settings](https://github.com/rbenv/ruby-build?tab=readme-ov-file#custom-build-configuration),\nin additional to that mise has a few extra settings:\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"ruby\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/rust.md",
    "content": "# Rust\n\nRust/cargo can be installed which uses rustup under the hood. mise will install rustup if it is not already\ninstalled and add the requested targets. By default, mise respects the `RUSTUP_HOME` and `CARGO_HOME` environment\nvariables for the home directories and falls back to their standard location (`~/.rustup` and `~/.cargo`) if they are\nnot set. You can change this by setting the `MISE_RUSTUP_HOME` and `MISE_CARGO_HOME` environment variables if you'd like\nto isolate mise's rustup/cargo from your other rustup/cargo installations.\n\nUnlike most tools, these won't exist inside of `~/.local/share/mise/installs` because they are managed by rustup.\nAll mise does is set the `RUSTUP_TOOLCHAIN` environment variable to the requested version and rustup will\nautomatically install it if it doesn't exist.\n\n## Usage\n\nUse the latest stable version of rust:\n\n```sh\nmise use -g rust\ncargo build\n```\n\nUse the latest beta version of rust:\n\n```sh\nmise use -g rust@beta\ncargo build\n```\n\nUse a specific version of rust:\n\n```sh\nmise use -g rust@1.82\ncargo build\n```\n\n## Tool Options\n\nThe following [tool-options](/dev-tools/#tool-options) are available for the `rust` backend—these\ngo in `[tools]` in `mise.toml`.\n\n### `components`\n\nThe `components` option allows you to specify which components to install. Multiple components can be\nspecified by separating them with a comma. The set of available components may vary with different releases and\ntoolchains. Please consult the Rust documentation for the most up-to-date list of components.\n\n```toml\n[tools]\n\"rust\" = { version = \"1.83.0\", components = \"rust-src,llvm-tools\" }\n```\n\n### `profile`\n\nThe `profile` option allows you to specify the type of release to install. The following values\nare supported:\n\n- `minimal`: Includes as few components as possible to get a working compiler (`rustc`, `rust-std`, and `cargo`)\n- `default`: Includes all of the components in the minimal profile, and adds `rust-docs`, `rustfmt`, and `clippy`\n- `complete`: Includes all the components available through `rustup`. This should never be used, as it includes every component ever included in the metadata and thus will almost always fail.\n\nIf not set, it defaults to the profile configured in `rustup`. You can check your current default by running `rustup show profile`.\n\n```toml\n[tools]\n\"rust\" = { version = \"1.83.0\", profile = \"minimal\" }\n```\n\n### `targets`\n\nThe `targets` option allows you to specify a list of platforms to install for cross-compilation. Multiple targets can\nbe specified by separating them with a comma.\n\n```toml\n[tools]\n\"rust\" = {\n  version = \"1.83.0\",\n  targets = \"wasm32-unknown-unknown,thumbv2-none-eabi\",\n}\n```\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"rust\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/swift.md",
    "content": "# Swift <Badge type=\"warning\" text=\"experimental\" />\n\n`mise` can be used to manage multiple versions of [`swift`](https://swift.org/) on the same system. Swift is supported for macos and linux.\n\n## Usage\n\nUse the latest stable version of swift:\n\n```sh\nmise use -g swift\nswift --version\n```\n\nSee [a mise guide for Swift developers](https://tuist.dev/blog/2025/02/04/mise) on how to use `mise` with `swift`.\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"swift\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lang/zig.md",
    "content": "# Zig\n\n`mise` can be used to install and manage multiple versions of [zig](https://ziglang.org/) on the same system.\n\n> The following are instructions for using the zig mise core plugin.\n\nThe code for this is inside the mise repository at\n[`./src/plugins/core/zig.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/zig.rs).\n\n## Usage\n\nThe following installs zig and makes it the global default:\n\n```sh\nmise use -g zig@0.14           # install zig 0.14.x\nmise use -g zig@latest         # install latest zig release\nmise use -g zig@master         # install latest nightly from master\nmise use -g zig@2024.11.0-mach # install Mach nominated zig\nmise use -g zig@mach-latest    # install latest Mach nominated zig\n```\n\nSee available stable versions with `mise ls-remote zig`.\n\nNote that [Mach](https://machengine.org/) versions\nwon't show in `mise ls-remote zig` due to workaround for\n[version ordering bug](https://github.com/jdx/mise/discussions/5232).\nDespite of that, you still can install Mach versions listed in\n[Mach version index](https://machengine.org/zig/index.json). The following\ncommand will list available Mach versions:\n\n```sh\ncurl https://machengine.org/zig/index.json | yq 'keys'\n```\n\n## zig Language Server\n\nThe `zig` language server ([zls](https://github.com/zigtools/zls)) needs to be installed separately.\nYou can install it with `mise`:\n\n```sh\nmise use -g zls@0.14   # install zls 0.14.x\nmise use -g zls@latest # install latest zls release\n```\n\nNote that a tagged release of `zig` should be used with\nthe same tagged release of `zls`. Currently there is no Mach version of `zls`.\n\n## Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n<Settings child=\"zig\" :level=\"3\" />\n"
  },
  {
    "path": "docs/lefthook.yml",
    "content": "pre-commit:\n  commands:\n    build:\n      glob: \"*\"\n      run: npm run docs:build\n      interactive: true\n"
  },
  {
    "path": "docs/mcp.md",
    "content": "# Model Context Protocol (MCP)\n\nThe Model Context Protocol (MCP) is a standard protocol that enables AI assistants to interact with development tools and access project context. Mise provides an MCP server that allows AI assistants to query information about your development environment.\n\n## Overview\n\nWhen you run `mise mcp`, it starts a server that AI assistants can connect to and query information about your mise-managed development environment. The server communicates over stdin/stdout using JSON-RPC protocol.\n\n::: warning\nThe MCP feature is experimental and requires enabling experimental features with `MISE_EXPERIMENTAL=1`.\n:::\n\n## Usage\n\nThe MCP server is typically launched by AI assistants automatically, but you can also run it manually for testing:\n\n```bash\n# Enable experimental features\nexport MISE_EXPERIMENTAL=1\n\n# Start the MCP server (it will wait for JSON-RPC input on stdin)\nmise mcp\n```\n\n## Available Resources\n\nThe MCP server exposes the following read-only resources that AI assistants can query:\n\n### `mise://tools`\n\nLists all tools managed by mise in your project, including:\n\n- Tool names and versions\n- Installation status\n- Configuration source\n\n### `mise://tasks`\n\nShows all available mise tasks with:\n\n- Task names and descriptions\n- Task dependencies\n- Command definitions\n\n### `mise://env`\n\nDisplays environment variables defined in your mise configuration:\n\n- Variable names and values\n- Environment-specific overrides\n\n### `mise://config`\n\nProvides information about mise configuration:\n\n- Active configuration files\n- Project root directory\n- Settings and preferences\n\n## Available Tools\n\nThe following tools are available for AI assistants to call:\n\n### `install_tool`\n\nInstall a specific tool version (not yet implemented)\n\n### `run_task`\n\nExecute a mise task with optional arguments.\n\n**Parameters:**\n\n- `task` (required, string): Name of the task to run\n- `args` (optional, array of strings): Arguments to pass to the task\n\n**Example:**\n\n```json\n{\n  \"task\": \"build\",\n  \"args\": [\"--verbose\"]\n}\n```\n\nWhen the AI assistant calls this tool, it will execute the specified task and return the output, including stdout, stderr, and the exit status.\n\n## Integration with AI Assistants\n\n### Claude Desktop\n\nTo use mise with Claude Desktop, add the following to your Claude configuration file:\n\n**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n**Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n**Linux**: `~/.config/claude/claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"mise\": {\n      \"command\": \"mise\",\n      \"args\": [\"mcp\"],\n      \"env\": {\n        \"MISE_EXPERIMENTAL\": \"1\"\n      }\n    }\n  }\n}\n```\n\nAfter adding this configuration and restarting Claude Desktop, the assistant will be able to:\n\n- Query your installed tools and versions\n- List available tasks in your project\n- Execute tasks directly (e.g., \"run the build task\")\n- Access environment variables from your mise configuration\n- View your mise configuration structure\n\n### Other AI Assistants\n\nThe MCP server uses standard JSON-RPC 2.0 over stdio, making it compatible with any AI assistant that supports the Model Context Protocol. Consult your AI assistant's documentation for specific integration instructions.\n\n## Examples\n\nWhen integrated with an AI assistant, you can ask questions like:\n\n- \"What version of Node.js is this project using?\"\n- \"List all the tasks available in this project\"\n- \"Run the build task\"\n- \"Execute the test task with verbose output\"\n- \"What environment variables are set by mise?\"\n- \"Show me the mise configuration for this project\"\n\nThe AI assistant will query the MCP server to provide accurate, up-to-date information about your development environment and can execute tasks on your behalf.\n\n## Technical Details\n\nThe MCP server implementation can be found in [`src/cli/mcp.rs`](https://github.com/jdx/mise/blob/main/src/cli/mcp.rs). It implements the ServerHandler trait from the rmcp crate to handle:\n\n- Resource listing and reading\n- Tool invocation (task execution)\n- JSON-RPC communication over stdio\n\nFor more information about the Model Context Protocol, visit the [official MCP documentation](https://modelcontextprotocol.io/).\n"
  },
  {
    "path": "docs/mise-cookbook/cpp.md",
    "content": "# Mise + C++ Cookbook\n\nHere are some tips on managing C++ projects with mise.\n\n## A C++ Project with CMake\n\n```toml [mise.toml]\nmin_version = \"2024.9.5\"\n\n[env]\n# Project information\nPROJECT_NAME = \"{{ config_root | basename }}\"\n\n# Build directory\nBUILD_DIR = \"{{ config_root }}/build\"\n\n[tools]\n# Install CMake and make\ncmake = \"latest\"\nmake = \"latest\"\n\n[tasks.configure]\ndescription = \"Configure the project\"\nrun = \"mkdir -p $BUILD_DIR && cd $BUILD_DIR && cmake ..\"\n\n[tasks.build]\ndescription = \"Build the project\"\nalias = \"b\"\nrun = \"cd $BUILD_DIR && make\"\n\n[tasks.clean]\ndescription = \"Clean the build directory\"\nalias = \"c\"\nrun = \"rm -rf $BUILD_DIR\"\n\n[tasks.run]\nalias = \"r\"\ndescription = \"Run the application\"\nrun = \"$BUILD_DIR/bin/$PROJECT_NAME\"\n\n[tasks.info]\ndescription = \"Print project information\"\nrun = '''\necho \"Project: $PROJECT_NAME\"\necho \"Build Directory: $BUILD_DIR\"\n'''\n```\n"
  },
  {
    "path": "docs/mise-cookbook/docker.md",
    "content": "# Mise + Docker Cookbook\n\nHere are some tips on using Docker with mise.\n\n## Docker image with mise\n\nHere is an example Dockerfile showing how to install mise in a Docker image.\n\n```Dockerfile [Dockerfile]\nFROM debian:13-slim\n\nRUN apt-get update  \\\n    && apt-get -y --no-install-recommends install  \\\n        # install any other dependencies you might need\n        sudo curl git ca-certificates build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\nSHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\nENV MISE_DATA_DIR=\"/mise\"\nENV MISE_CONFIG_DIR=\"/mise\"\nENV MISE_CACHE_DIR=\"/mise/cache\"\nENV MISE_INSTALL_PATH=\"/usr/local/bin/mise\"\nENV PATH=\"/mise/shims:$PATH\"\n# ENV MISE_VERSION=\"...\"\n\nRUN curl https://mise.run | sh\n```\n\nBuild and run the Docker image:\n\n```shell\ndocker build -t debian-mise .\ndocker run -it --rm debian-mise\n```\n\n## Shared tools in multi-user containers\n\nFor toolbox containers or bastion hosts where tools should be pre-installed for all users,\nuse `mise install --system` to install tools into `/usr/local/share/mise/installs`.\nEach user's mise will automatically find these system-level tools without any configuration.\n\n```Dockerfile [Dockerfile]\nFROM debian:13-slim\n\nRUN apt-get update  \\\n    && apt-get -y --no-install-recommends install  \\\n        sudo curl git ca-certificates build-essential \\\n    && rm -rf /var/lib/apt/lists/*\n\nSHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\nENV MISE_INSTALL_PATH=\"/usr/local/bin/mise\"\n\n# Install mise\nRUN curl https://mise.run | sh\n\n# Pre-install tools to the system-wide shared directory\nRUN mise install --system node@22 python@3.13\n```\n\nUsers in the container will see these tools automatically:\n\n```shell\n$ mise ls\nnode    22.0.0 (system)\npython  3.13.0 (system)\n```\n\nUsers can install additional versions in their own directory — those take priority over\nsystem versions. To customize the system directory, set `MISE_SYSTEM_DATA_DIR`.\n\nYou can also configure additional shared directories with `MISE_SHARED_INSTALL_DIRS`\n(colon-separated paths) or the `shared_install_dirs` setting.\n\n### Devcontainers with home directory mounts\n\nDevcontainers often mount the user's home directory, which means `~/.local/share/mise/installs`\ncomes from the mount rather than the Docker image. Tools pre-installed during `docker build`\ninto `~/.local/share/mise/installs` would be hidden by the mount.\n\nUse `mise install --system` to install tools to `/usr/local/share/mise/installs` instead —\nthis path is outside `~` and survives home directory mounts:\n\n```Dockerfile [Dockerfile]\nFROM debian:13-slim\n# ... install mise ...\nRUN mise install --system node@22 python@3.13\n```\n\nWhen the container starts with `~` mounted, users still see the system tools automatically.\nAny tools they install normally go to `~/.local/share/mise/installs` (on the mount) and\ntake priority over system versions.\n\n## Task to run mise in a Docker container\n\nThis can be useful if you need to reproduce an issue you're having with mise in a clean environment.\n\n```toml [mise.toml]\n[tasks.docker]\nrun = \"docker run -it --rm debian-mise\"\n```\n\nBuild the image first (see above), then:\n\n```shell\n❯ mise docker\n[docker] $ docker run -it --rm debian-mise\nroot@75f179a190a1:/# eval \"$(mise activate bash)\"\n# overwrite configuration and prune to give us a clean state\nroot@75f179a190a1:/# echo \"\" > /mise/config.toml\nroot@75f179a190a1:/# mise prune --yes\n# ...\n```\n"
  },
  {
    "path": "docs/mise-cookbook/index.md",
    "content": "# Cookbook\n\nHere we are sharing a few mise setups that other people have found useful.\n\n- [C++](cpp.md)\n- [Docker](docker.md)\n- [Node.JS](nodejs.md)\n- [Python](python.md)\n- [Ruby](ruby.md)\n- [Terraform](terraform.md)\n- [Neovim](neovim.md)\n\nFinally, here is how to create [presets](presets.md) and some [shell tricks](shell-tricks.md) you might find useful.\n\n## Contributing\n\nIf you would like to share your setup, please share it in this [cookbook thread](https://github.com/jdx/mise/discussions/3645).\n"
  },
  {
    "path": "docs/mise-cookbook/neovim.md",
    "content": "# Mise + Neovim Cookbook\n\nHere are some tips for an improved mise workflow with [Neovim](https://github.com/neovim/neovim).\n\n## Syntax highlighting\n\n### Run commands\n\nUse [Treesitter](https://github.com/nvim-treesitter/nvim-treesitter) to enable syntax highlighting for the code in the run commands of your mise files.\nSee the example here on the left side of the image:\n\n![run cmd syntax highlighting demo](./run-cmd-syntax-hl.png)\n\nIn your neovim config, create a `after/queries/toml/injections.scm` file with these queries:\n\n```query\n; extends\n\n(pair\n  (bare_key) @key (#eq? @key \"run\")\n  (string) @injection.content @injection.language\n\n  (#is-mise?)\n  (#match? @injection.language \"^['\\\"]{3}\\n*#!(/\\\\w+)+/env\\\\s+\\\\w+\") ; multiline shebang using env\n  (#gsub! @injection.language \"^.*#!/.*/env%s+([^%s]+).*\" \"%1\") ; extract lang\n  (#offset! @injection.content 0 3 0 -3) ; rm quotes\n)\n\n(pair\n  (bare_key) @key (#eq? @key \"run\")\n  (string) @injection.content @injection.language\n\n  (#is-mise?)\n  (#match? @injection.language \"^['\\\"]{3}\\n*#!(/\\\\w+)+\\s*\\n\") ; multiline shebang\n  (#gsub! @injection.language \"^.*#!/.*/([^/%s]+).*\" \"%1\") ; extract lang\n  (#offset! @injection.content 0 3 0 -3) ; rm quotes\n)\n\n(pair\n  (bare_key) @key (#eq? @key \"run\")\n  (string) @injection.content\n\n  (#is-mise?)\n  (#match? @injection.content \"^['\\\"]{3}\\n*.*\") ; multiline\n  (#not-match? @injection.content \"^['\\\"]{3}\\n*#!\") ; no shebang\n  (#offset! @injection.content 0 3 0 -3) ; rm quotes\n  (#set! injection.language \"bash\") ; default to bash\n)\n\n(pair\n  (bare_key) @key (#eq? @key \"run\")\n  (string) @injection.content\n\n  (#is-mise?)\n  (#not-match? @injection.content \"^['\\\"]{3}\") ; not multiline\n  (#offset! @injection.content 0 1 0 -1) ; rm quotes\n  (#set! injection.language \"bash\") ; default to bash\n)\n```\n\nTo only apply the highlighting on mise files instead of all toml files, the `is-mise?` predicate is used.\nIf you don't care for this distinction, the lines containing `(#is-mise?)` can be removed.\nOtherwise, make sure to also create the predicate somewhere in your neovim config.\n\nFor example, using [`lazy.nvim`](https://github.com/folke/lazy.nvim):\n\n```lua\n{\n  \"nvim-treesitter/nvim-treesitter\",\n  init = function()\n    require(\"vim.treesitter.query\").add_predicate(\"is-mise?\", function(_, _, bufnr, _)\n      local filepath = vim.api.nvim_buf_get_name(tonumber(bufnr) or 0)\n      local filename = vim.fn.fnamemodify(filepath, \":t\")\n      return string.match(filename, \".*mise.*%.toml$\") ~= nil\n    end, { force = true, all = false })\n  end,\n},\n```\n\nThis will consider any `toml` file containing `mise` in its name as a mise file.\n\n### MISE and USAGE comments in file tasks\n\nYou can also use Treesitter to enable syntax highlighting for `\"#MISE` and `#USAGE` comments in file based tasks.\nSee the example here on the left side of the image:\n\n![USAGE spec syntax highlighting demo](./usage-spec-syntax-hl.png)\n\nIn your neovim config, create a `after/queries/bash/injections.scm` file with these queries:\n\n```query\n; extends\n\n; ============================================================================\n; #MISE comments - TOML injection\n; ============================================================================\n; This injection captures comment lines starting with \"#MISE \" or \"#[MISE]\" or\n; \"# [MISE]\" and treats them as TOML code blocks for syntax highlighting.\n;\n; #MISE format\n; The (#offset!) directive skips the \"#MISE \" prefix (6 characters) from the source\n((comment) @injection.content\n  (#lua-match? @injection.content \"^#MISE \")\n  (#offset! @injection.content 0 6 0 1)\n  (#set! injection.language \"toml\"))\n\n; #[MISE] format\n((comment) @injection.content\n  (#lua-match? @injection.content \"^#%[MISE%] \")\n  (#offset! @injection.content 0 8 0 1)\n  (#set! injection.language \"toml\"))\n\n; # [MISE] format\n((comment) @injection.content\n  (#lua-match? @injection.content \"^# %[MISE%] \")\n  (#offset! @injection.content 0 9 0 1)\n  (#set! injection.language \"toml\"))\n\n; ============================================================================\n; #USAGE comments - KDL injection\n; ============================================================================\n; This injection captures consecutive comment lines starting with \"#USAGE \" or\n; \"#[USAGE]\" or \"# [USAGE]\" and treats them as a single KDL code block for\n; syntax highlighting.\n;\n; #USAGE format\n((comment) @injection.content\n  (#lua-match? @injection.content \"^#USAGE \")\n  ; Extend the range one byte to the right, to include the trailing newline.\n  ; see https://github.com/neovim/neovim/discussions/36669#discussioncomment-15054154\n  (#offset! @injection.content 0 7 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n\n; #[USAGE] format\n((comment) @injection.content\n  (#lua-match? @injection.content \"^#%[USAGE%] \")\n  (#offset! @injection.content 0 9 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n\n; # [USAGE] format\n((comment) @injection.content\n  (#lua-match? @injection.content \"^# %[USAGE%] \")\n  (#offset! @injection.content 0 10 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n\n; NOTE: on neovim >= 0.12, you can use the multi node pattern instead of\n; combining injections:\n;\n; ((comment)+ @injection.content\n;   (#lua-match? @injection.content \"^#USAGE \")\n;   (#offset! @injection.content 0 7 0 1)\n;   (#set! injection.language \"kdl\"))\n;\n; this is the preferred way as combined injections have multiple\n; limitations:\n; https://github.com/neovim/neovim/issues/32635\n\n```\n\nThe same queries work as is for all languages that use `#` as a comment delimiter.\nDue to TS injections being per language, you need to put the same queries to the language specific query files.\nFor example, put them to `after/queries/python/injections.scm` to enable them for `Python` in addition to `bash`.\n\nFor languages that use `//` as a comment delimiter, you need to modify the queries a bit:\n\n```query\n((comment) @injection.content\n  (#lua-match? @injection.content \"^//MISE \")\n  (#offset! @injection.content 0 7 0 1)\n  (#set! injection.language \"toml\"))\n((comment) @injection.content\n  (#lua-match? @injection.content \"^//%[MISE%] \")\n  (#offset! @injection.content 0 9 0 1)\n  (#set! injection.language \"toml\"))\n((comment) @injection.content\n  (#lua-match? @injection.content \"^// %[MISE%] \")\n  (#offset! @injection.content 0 10 0 1)\n  (#set! injection.language \"toml\"))\n((comment) @injection.content\n  (#lua-match? @injection.content \"^//USAGE \")\n  (#offset! @injection.content 0 8 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n((comment) @injection.content\n  (#lua-match? @injection.content \"^//%[USAGE%] \")\n  (#offset! @injection.content 0 10 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n((comment) @injection.content\n  (#lua-match? @injection.content \"^// %[USAGE%] \")\n  (#offset! @injection.content 0 11 0 1)\n  (#set! injection.combined)\n  (#set! injection.language \"kdl\"))\n```\n\n## Enable LSP for embedded lang in run commands\n\nUse [`otter.nvim`](https://github.com/jmbuhr/otter.nvim) to enable LSP features and code completion for code embedded in your mise files.\n\nAgain using [`lazy.nvim`](https://github.com/folke/lazy.nvim):\n\n```lua\n{\n  \"jmbuhr/otter.nvim\",\n  dependencies = {\n    \"nvim-treesitter/nvim-treesitter\",\n  },\n  config = function()\n    vim.api.nvim_create_autocmd({ \"FileType\" }, {\n      pattern = { \"toml\" },\n      group = vim.api.nvim_create_augroup(\"EmbedToml\", {}),\n      callback = function()\n        require(\"otter\").activate()\n      end,\n    })\n  end,\n},\n```\n\nThis will only work if the [TS injection queries](#run-commands) are also set up.\n"
  },
  {
    "path": "docs/mise-cookbook/nodejs.md",
    "content": "# Mise + Node.js Cookbook\n\nHere are some tips on managing [Node.js](/lang/node.html) projects with mise.\n\n## Getting started with Node.js\n\nTo install Node.JS, in a directory, you can use the following command:\n\n```shell\nmise use node\n```\n\nThis will install the latest version of Node.js and create a `mise.toml` file with the following content:\n\n```toml\nnode = \"latest\"\n```\n\nIf you want to install Node.JS globally instead (for example, node v24), you can use the following command:\n\n```shell\nmise use -g node@24\n```\n\n## Add node modules binaries to the PATH\n\nWhen installing Node.js packages specified in `package.json`, you typically need to use `npx` or the full path to the binary. For example:\n\n```shell\nnpm install --save eslint\neslint --version # doesn't work\nnpx eslint --version # works\n```\n\nThanks to `mise`, you can add the node modules binaries to the `PATH`. This will make CLIs installed with npm available without `npx`.\n\n```toml [mise.toml]\n[env]\n_.path = ['{{config_root}}/node_modules/.bin']\n```\n\nExample:\n\n```shell\nnpm install --save eslint\neslint --version # works\n```\n\n## Example Node.js Project\n\n```toml [mise.toml]\nmin_version = \"2024.9.5\"\n\n[env]\n_.path = ['{{config_root}}/node_modules/.bin']\n\n# Use the project name derived from the current directory\nPROJECT_NAME = \"{{ config_root | basename }}\"\n\n# Set up the path for node module binaries\nBIN_PATH = \"{{ config_root }}/node_modules/.bin\"\n\nNODE_ENV = \"{{ env.NODE_ENV | default(value='development') }}\"\n\n[tools]\n# Install Node.js using the specified version\nnode = \"{{ env['NODE_VERSION'] | default(value='lts') }}\"\n\n# Install some npm packages globally if needed\n\"npm:typescript\" = \"latest\"\n\"npm:eslint\" = \"latest\"\n\"npm:jest\" = \"latest\"\n\n[tasks.install]\nalias = \"i\"\ndescription = \"Install npm dependencies\"\nrun = \"npm install\"\n\n[tasks.start]\nalias = \"s\"\ndescription = \"Start the development server\"\nrun = \"npm run start\"\n\n[tasks.lint]\nalias = \"l\"\ndescription = \"Run ESLint\"\nrun = \"eslint src/\"\n\n[tasks.test]\ndescription = \"Run tests\"\nalias = \"t\"\nrun = \"jest\"\n\n[tasks.build]\ndescription = \"Build the project\"\nalias = \"b\"\nrun = \"npm run build\"\n\n[tasks.info]\ndescription = \"Print project information\"\nrun = '''\necho \"Project: $PROJECT_NAME\"\necho \"NODE_ENV: $NODE_ENV\"\n'''\n```\n\n## Example with `pnpm`\n\nThis example uses `pnpm` as the package manager. This will skip installing dependencies if the lock file hasn't changed.\n\n```toml [mise.toml]\n[tools]\nnode = '22'\n\n[hooks]\n# Enabling corepack will install the `pnpm` package manager specified in your package.json\n# alternatively, you can also install `pnpm` with mise\npostinstall = 'npx corepack enable'\n\n[settings]\n# This must be enabled to make the hooks work\nexperimental = true\n\n[env]\n_.path = ['{{config_root}}/node_modules/.bin']\n\n[tasks.pnpm-install]\ndescription = 'Installs dependencies with pnpm'\nrun = 'pnpm install'\nsources = ['package.json', 'pnpm-lock.yaml', 'mise.toml']\noutputs = ['node_modules/.pnpm/lock.yaml']\n\n[tasks.dev]\ndescription = 'Calls your dev script in `package.json`'\nrun = 'node --run dev'\ndepends = ['pnpm-install']\n```\n\nWith this setup, getting started in a NodeJS project is as simple as running `mise dev`:\n\n- `mise` will install the correct version of NodeJS\n- `mise` will enable `corepack`\n- `pnpm install` will be run before `node --run dev`\n"
  },
  {
    "path": "docs/mise-cookbook/presets.md",
    "content": "# Presets\n\nYou can create your own presets by leveraging [mise tasks](../tasks/index.md) to reduce boilerplate and make it easier to set up new projects.\n\n## Example python preset\n\nHere is an example of how to create your python preset that creates a `mise.toml` file to work with `python` and `pdm`\n\n```shell [~/.config/mise/tasks/preset/python]\n#!/usr/bin/env bash\n#MISE dir=\"{{cwd}}\"\n\nmise use pre-commit\nmise config set env._.python.venv.path .venv\nmise config set env._.python.venv.create true -t bool\nmise tasks add lint -- pre-commit run -a\n```\n\n```shell [~/.config/mise/tasks/preset/pdm]\n#!/usr/bin/env bash\n#MISE dir=\"{{cwd}}\"\n#MISE depends=[\"preset:python\"]\n#USAGE arg \"<version>\"\n\nmise use python@${usage_version?}\nmise use pdm@latest\nmise config set hooks.postinstall \"pdm sync\"\n```\n\nThen in any directory, you can run `mise preset:pdm 3.10` to scaffold a new project with `python` and `pdm`:\n\n```shell\ncd my-project\nmise preset:pdm 3.10\n# [preset:python] $ ~/.config/mise/tasks/preset/python\n# mise WARN  No untrusted config files found.\n# mise ~/my-project/mise.toml tools: pre-commit@4.0.1\n# [preset:pdm] $ ~/.config/mise/tasks/preset/pdm 3.10\n# mise WARN  No untrusted config files found.\n# mise ~/my-project/mise.toml tools: python@3.10.15\n# mise ~/my-project/mise.toml tools: pdm@2.21.0\n# mise creating venv with uv at: ~/my-project/.venv\n# Using CPython 3.10.15 interpreter at: /Users/simon/.local/share/mise/installs/python/3.10.15/bin/python\n# Creating virtual environment at: .venv\n# Activate with: source .venv/bin/activate.fish\n\n~/my-project via 🐍 v3.10.15 (.venv)\n# we are in the virtual environment ^\n```\n\nHere is the generated `mise.toml` file:\n\n```toml [mise.toml]\n[tools]\npdm = \"latest\"\npre-commit = \"latest\"\npython = \"3.10\"\n\n[hooks]\npostinstall = \"pdm sync\"\n\n[env]\n[env._]\n[env._.python]\n[env._.python.venv]\npath = \".venv\"\ncreate = true\n\n[tasks.lint]\nrun = \"pre-commit run -a\"\n```\n"
  },
  {
    "path": "docs/mise-cookbook/python.md",
    "content": "# Mise + Python Cookbook\n\nHere are some tips on managing [Python](/lang/python.html) projects with mise.\n\n## A Python Project with virtualenv\n\nHere is an example python project with a `requirements.txt` file.\n\n```toml [mise.toml]\nmin_version = \"2024.9.5\"\n\n[env]\n# Use the project name derived from the current directory\nPROJECT_NAME = \"{{ config_root | basename }}\"\n\n# Automatic virtualenv activation\n_.python.venv = { path = \".venv\", create = true }\n\n[tools]\npython = \"{{ get_env(name='PYTHON_VERSION', default='3.11') }}\"\nruff = \"latest\"\n\n[tasks.install]\ndescription = \"Install dependencies\"\nalias = \"i\"\nrun = \"uv pip install -r requirements.txt\"\n\n[tasks.run]\ndescription = \"Run the application\"\nrun = \"python app.py\"\n\n[tasks.test]\ndescription = \"Run tests\"\nrun = \"pytest tests/\"\n\n[tasks.lint]\ndescription = \"Lint the code\"\nrun = \"ruff src/\"\n\n[tasks.info]\ndescription = \"Print project information\"\nrun = '''\necho \"Project: $PROJECT_NAME\"\necho \"Virtual Environment: $VIRTUAL_ENV\"\n'''\n```\n\n## mise + uv\n\nIf you are using a `uv` project initialized with `uv init .`, here is how you can use it with mise.\n\nHere is how the `uv` project will look like:\n\n```shell [uv-project]\n.\n├── .gitignore\n├── .python-version\n├── main.py\n├── pyproject.toml\n└── README.md\n\ncat .python-version\n# 3.12\n```\n\nIf you run `uv run main.py` in the `uv` project, `uv` will automatically create a virtual environment for you using the python version specified in the `.python-version` file. This will also create a `uv.lock` file.\n\n`mise` will detect the python version in `.python-version`, however, it won't use the virtual env created by `uv` by default. So, using `which python` will show a global python installation from `mise`.\n\n```shell\nmise i\nwhich python\n# ~/.local/share/mise/installs/python/3.12.4/bin/python\n```\n\nIf you want `mise` to use the virtual environment created by `uv`, you can set the [`python.uv_venv_auto`](/lang/python.html#python.uv_venv_auto) setting in your `mise.toml` file.\nUse `\"source\"` to only source an existing `.venv`, or `\"create|source\"` to create it if missing and then source it.\nIf you prefer `mise prepare` to create the venv, keep it at `\"source\"`, enable `[prepare.uv]`, and run `mise prepare`.\n\n```toml [mise.toml]\n[settings]\npython.uv_venv_auto = \"source\"\n# or, to create if missing\n# python.uv_venv_auto = \"create|source\"\n```\n\nUsing `which python` will now show the python version from the virtual environment created by `uv`.\n\n```shell\nwhich python\n# ./uv-project/.venv/bin/python\n```\n\nAnother option is to use `_.python.venv` in your `mise.toml` file to specify the path to the virtual environment created by `uv`.\n\n```toml [mise.toml]\n[env]\n_.python.venv = { path = \".venv\" }\n```\n\n### Syncing python versions installed by mise and uv\n\nYou can use [mise sync python --uv](/cli/sync/python.html#uv) to sync the python version installed by `mise` with the python version specified in the `.python-version` file in the `uv` project.\n\n### uv scripts\n\nYou can take advantage of `uv run` in [`shebang`](/tasks/toml-tasks.html#shell-shebang) in toml or file tasks.\nNote that using `--script` is required if the filename does not end in `.py`.\n\nHere is an example toml task:\n\n```toml [mise.toml]\n[tools]\nuv = 'latest'\n\n[tasks.print_peps]\nrun = '''\n#!/usr/bin/env -S uv run --script\n# /// script\n# dependencies = [\"requests<3\", \"rich\"]\n# ///\n\nimport requests\nfrom rich.pretty import pprint\n\nresp = requests.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n'''\n```\n\nOr as a file task:\n\n```python [mise-tasks/print_peps.py]\n#!/usr/bin/env -S uv run --script\n# /// script\n# dependencies = [\"requests<3\", \"rich\"]\n# ///\n\nimport requests\nfrom rich.pretty import pprint\n\nresp = requests.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n```\n\nYou can then run it with `mise run print_peps`:\n\n```shell\n❯ mise run print_peps\n[print_peps] $ ~/uv-project/mise-tasks/print_peps.py\nInstalled 9 packages in 8ms\n[\n│   ('1', 'PEP Purpose and Guidelines'),\n│   ('2', 'Procedure for Adding New Modules'),\n    #...\n]\n```\n"
  },
  {
    "path": "docs/mise-cookbook/ruby.md",
    "content": "# Mise + Ruby Cookbook\n\nHere are some tips on managing Ruby projects with mise.\n\n## A Ruby on Rails Project\n\n```toml [mise.toml]\nmin_version = \"2024.9.5\"\n\n[env]\n# Project information\nPROJECT_NAME = \"{{ config_root | basename }}\"\n\n[tools]\n# Install Ruby with the specified version\nruby = \"{{ get_env(name='RUBY_VERSION', default='3.3.3') }}\"\n\n[tasks.\"bundle:install\"]\ndescription = \"Install gem dependencies\"\nrun = \"bundle install\"\n\n[tasks.server]\ndescription = \"Start the Rails server\"\nalias = \"s\"\nrun = \"rails server\"\n\n[tasks.test]\ndescription = \"Run tests\"\nalias = \"t\"\nrun = \"rails test\"\n\n[tasks.lint]\ndescription = \"Run lint using Rubocop\"\nalias = \"l\"\nrun = \"rubocop\"\n```\n"
  },
  {
    "path": "docs/mise-cookbook/shell-tricks.md",
    "content": "# Shell tricks\n\nA collection of shell utities leveraging mise.\n\n## Prompt colouring\n\nIn ZSH to set the prompt colour whenever mise updates the environment (e.g. on cd into a project, or due to modification of the .mise\\*.toml):\n\n```shell\n# activate mise like normal\nsource <(command mise activate zsh)\n\ntypeset -i _mise_updated\n\n# replace default mise hook\nfunction _mise_hook {\n  local diff=${__MISE_DIFF}\n  source <(command mise hook-env -s zsh)\n  [[ ${diff} == ${__MISE_DIFF} ]]\n  _mise_updated=$?\n}\n\n_PROMPT=\"❱ \"  # or _PROMPT=${PROMPT} to keep the default\n\nfunction _prompt {\n  if (( ${_mise_updated} )); then\n    PROMPT='%F{blue}${_PROMPT}%f'\n  else\n    PROMPT='%(?.%F{green}${_PROMPT}%f.%F{red}${_PROMPT}%f)'\n  fi\n}\n\nadd-zsh-hook precmd _prompt\n```\n\nNow, when mise makes any updates to the environment the prompt will go blue.\n\n## Current configuration environment in powerline-go prompt\n\n[powerline-go](https://github.com/justjanne/powerline-go)'s\n`shell-var` segment can be used to display the value of an environment\nvariable in the prompt.\nThe current mise [configuration environment](/configuration/environments),\n`MISE_ENV` is a good candidate for this.\n\nMostly, it is as one would expect: include `shell-var` in `-modules`,\nand `-shell-var MISE_ENV -shell-var-no-warn-empty` in arguments,\nand make sure `MISE_ENV` is exported so `powerline-go` can \"see\" it.\n\nA gotcha as of February 2025 is that the `shell-var` module does not\ntolerate _unset_ (as opposed to empty) environment variables.\nTo work around this, set `MISE_ENV` to an empty value early in the shell\nstartup scripts, and avoid manually `unset`ing it.\nFor example for bash, typically in `~/.bashrc`:\n\n```bash\nexport MISE_ENV=\n```\n\n## Inspect what changed after mise hook\n\nUsing record-query you can inspect the `__MISE_DIFF` and `__MISE_SESSION` variables to see what's changing in your environment due to the mise hook.\n\n```toml [~/.config/mise/config.toml]\n[tools]\n\"cargo:record-query\" = \"latest\"\n```\n\n```shell\nfunction mise_parse_env {\n  rq -m < <(\n    zcat -q < <(\n      printf '\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00'\n      base64 -d <<< \"$1\"\n    )\n  )\n}\n```\n\n```shell\n$ mise_parse_env \"${__MISE_DIFF}\"\n{\n  \"new\": {\n    ...\n  },\n  \"old\": {\n    ...\n  },\n  \"path\": [\n    ...\n  ]\n}\n```\n"
  },
  {
    "path": "docs/mise-cookbook/terraform.md",
    "content": "# Mise + Terraform/Opentofu Cookbook\n\nHere are some tips on managing Terraform projects with mise.\n\n## Managing `terraform`/`opentofu` Projects\n\nIt is often necessary to have your terraform configuration in a `terraform/` subdirectory.\nThis necessitates the use of syntax like `terraform -chdir=terraform plan` to use appropriate\nterraform command. The following config allows you to invoke all of them from `mise`, leveraging\n`mise` tasks.\n\n```toml [mise.toml]\n[tools]\nterraform = \"1\"\n\n[tasks.\"terraform:init\"]\ndescription = \"Initializes a Terraform working directory\"\nrun = \"terraform -chdir=terraform init\"\n\n[tasks.\"terraform:plan\"]\ndescription = \"Generates an execution plan for Terraform\"\nrun = \"terraform -chdir=terraform plan\"\n\n[tasks.\"terraform:apply\"]\ndescription = \"Applies the changes required to reach the desired state of the configuration\"\nrun = \"terraform -chdir=terraform apply\"\n\n[tasks.\"terraform:destroy\"]\ndescription = \"Destroy Terraform-managed infrastructure\"\nrun = \"terraform -chdir=terraform destroy\"\n\n[tasks.\"terraform:validate\"]\ndescription = \"Validates the Terraform files\"\nrun = \"terraform -chdir=terraform validate\"\n\n[tasks.\"terraform:format\"]\ndescription = \"Formats the Terraform files\"\nrun = \"terraform -chdir=terraform fmt\"\n\n[tasks.\"terraform:check\"]\ndescription = \"Checks the Terraform files\"\ndepends = [\"terraform:format\", \"terraform:validate\"]\n\n[env]\n_.file = \".env\"\n\n```\n"
  },
  {
    "path": "docs/mise.usage.kdl",
    "content": "name \"mise\"\nbin \"mise\"\nabout \"The front-end to your dev env\"\nlong_about r\"mise is a tool for managing runtime versions. https://github.com/jdx/mise\n\nIt's a replacement for tools like nvm, nodenv, rbenv, rvm, chruby, pyenv, etc.\nthat works for any language. It's also great for managing linters/tools like\njq and shellcheck.\n\nIt is inspired by asdf and uses asdf's plugin ecosystem under the hood:\nhttps://asdf-vm.com/\"\nusage \"Usage: mise [OPTIONS] <COMMAND>\"\nflag \"-C --cd\" help=\"Change directory before running command\" global=true {\n    arg \"<DIR>\"\n}\nflag \"--debug\" help=\"Sets log level to debug\" hide=true global=true\nflag \"--log-level\" help=\"Set the log output verbosity\" hide=true global=true {\n    arg \"<LEVEL>\"\n}\nflag \"-q --quiet\" help=\"Suppress non-error messages\" global=true\nflag \"--trace\" help=\"Sets log level to trace\" hide=true global=true\nflag \"-v --verbose\" help=\"Show extra output (use -vv for even more)\" var=true global=true count=true\nflag \"-y --yes\" help=\"Answer yes to all confirmation prompts\" global=true\ncmd \"activate\" help=\"Initializes mise in the current shell session\" {\n    long_help r#\"Initializes mise in the current shell session\n\nThis should go into your shell's rc file.\nOtherwise, it will only take effect in the current session.\n(e.g. ~/.zshrc, ~/.bashrc)\n\nThis is only intended to be used in interactive sessions, not scripts.\nmise is only capable of updating PATH when the prompt is displayed to the user.\nFor non-interactive use-cases, use shims instead.\n\nTypically this can be added with something like the following:\n\n    echo 'eval \"$(mise activate)\"' >> ~/.zshrc\n\nHowever, this requires that \"mise\" is in your PATH. If it is not, you need to\nspecify the full path like this:\n\n    echo 'eval \"$(/path/to/mise activate)\"' >> ~/.zshrc\n\nCustomize status output with `status` settings.\"#\n    after_long_help r#\"Examples:\n\n    $ eval \"$(mise activate bash)\"\n    $ eval \"$(mise activate zsh)\"\n    $ mise activate fish | source\n    $ execx($(mise activate xonsh))\n\"#\n    flag \"-s --shell\" help=\"Shell type to generate the script for\" hide=true {\n        arg \"<SHELL>\"\n    }\n    flag \"--status\" help=\"Show \\\"mise: <PLUGIN>@<VERSION>\\\" message when changing directories\" hide=true\n    flag \"--shims\" help=\"Use shims instead of modifying PATH\\nEffectively the same as:\\n    PATH=\\\"$HOME/.local/share/mise/shims:$PATH\\\"\"\n    flag \"-q --quiet\" help=\"Suppress non-error messages\"\n    arg \"[SHELL_TYPE]\" help=\"Shell type to generate the script for\"\n}\ncmd \"alias\" help=\"Manage aliases\" {\n    alias \"a\"\n    alias \"aliases\" hide=true\n    flag \"-p --plugin\" help=\"filter aliases by plugin\" {\n        arg \"<PLUGIN>\"\n    }\n    flag \"--no-header\" help=\"Don't show table header\"\n    cmd \"get\" help=\"Show an alias for a plugin\" {\n        long_help r\"Show an alias for a plugin\n\nThis is the contents of an alias.<PLUGIN> entry in ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n   $ mise alias get node lts-hydrogen\n   20.0.0\n\"\n        arg \"<PLUGIN>\" help=\"The plugin to show the alias for\"\n        arg \"<ALIAS>\" help=\"The alias to show\"\n    }\n    cmd \"ls\" help=\"List aliases\\nShows the aliases that can be specified.\\nThese can come from user config or from plugins in `bin/list-aliases`.\" {\n        alias \"list\"\n        long_help r#\"List aliases\nShows the aliases that can be specified.\nThese can come from user config or from plugins in `bin/list-aliases`.\n\nFor user config, aliases are defined like the following in `~/.config/mise/config.toml`:\n\n  [alias.node.versions]\n  lts = \"20.0.0\"\"#\n        after_long_help r\"Examples:\n\n    $ mise tool-alias\n    node    lts-hydrogen   20.0.0\n\"\n        flag \"--no-header\" help=\"Don't show table header\"\n        arg \"[PLUGIN]\" help=\"Show aliases for <PLUGIN>\"\n    }\n    cmd \"set\" help=\"Add/update an alias for a plugin\" {\n        alias \"add\" \"create\"\n        long_help r\"Add/update an alias for a plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n\n    $ mise alias set node lts-hydrogen 18.0.0\n\"\n        arg \"<PLUGIN>\" help=\"The plugin to set the alias for\"\n        arg \"<ALIAS>\" help=\"The alias to set\"\n        arg \"<VALUE>\" help=\"The value to set the alias to\"\n    }\n    cmd \"unset\" help=\"Clears an alias for a plugin\" {\n        alias \"rm\" \"remove\" \"delete\" \"del\"\n        long_help r\"Clears an alias for a plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n\n    $ mise alias unset node lts-hydrogen\n\"\n        arg \"<PLUGIN>\" help=\"The plugin to remove the alias from\"\n        arg \"<ALIAS>\" help=\"The alias to remove\"\n    }\n}\ncmd \"asdf\" hide=true help=\"[internal] simulates asdf for plugins that call \\\"asdf\\\" internally\" {\n    arg \"[ARGS]...\" help=\"all arguments\" var=true\n}\ncmd \"backends\" help=\"Manage backends\" {\n    alias \"b\"\n    alias \"backend\" \"backend-list\" hide=true\n    cmd \"ls\" help=\"List built-in backends\" {\n        alias \"list\"\n        after_long_help r\"Examples:\n\n  $ mise backends ls\n  cargo\n  go\n  npm\n  pipx\n  spm\n  ubi\n\"\n    }\n}\ncmd \"bin-paths\" help=\"List all the active runtime bin paths\"\ncmd \"cache\" help=\"Manage the mise cache\" {\n    long_help r\"Manage the mise cache\n\nRun `mise cache` with no args to view the current cache directory.\"\n    cmd \"clear\" help=\"Deletes all cache files in mise\" {\n        alias \"c\"\n        alias \"clean\" hide=true\n        arg \"[PLUGIN]...\" help=\"Plugin(s) to clear cache for e.g.: node, python\" var=true\n    }\n}\ncmd \"completion\" help=\"Generate shell completions\" {\n    alias \"complete\" \"completions\" hide=true\n    after_long_help r\"Examples:\n\n    $ mise completion bash > ~/.local/share/bash-completion/completions/mise\n    $ mise completion zsh  > /usr/local/share/zsh/site-functions/_mise\n    $ mise completion fish > ~/.config/fish/completions/mise.fish\n\"\n    flag \"-s --shell\" help=\"Shell type to generate completions for\" hide=true {\n        arg \"<SHELL_TYPE>\"\n    }\n    flag \"--usage\" help=\"Always use usage for completions.\\nCurrently, usage is the default for fish and bash but not zsh since it has a few quirks\\nto work out first.\" hide=true {\n        long_help \"Always use usage for completions.\\nCurrently, usage is the default for fish and bash but not zsh since it has a few quirks\\nto work out first.\\n\\nThis requires the `usage` CLI to be installed.\\nhttps://usage.jdx.dev\"\n    }\n    arg \"[SHELL]\" help=\"Shell type to generate completions for\"\n}\ncmd \"config\" help=\"[experimental] Manage config files\" {\n    alias \"cfg\"\n    flag \"--no-header\" help=\"Do not print table header\"\n    cmd \"ls\" help=\"[experimental] List config files currently in use\" {\n        after_long_help r\"Examples:\n\n    $ mise config ls\n\"\n        flag \"--no-header\" help=\"Do not print table header\"\n    }\n    cmd \"generate\" help=\"[experimental] Generate a .mise.toml file\" {\n        alias \"g\"\n        after_long_help r\"Examples:\n\n    $ mise cf generate > .mise.toml\n    $ mise cf generate --output=.mise.toml\n\"\n        flag \"-o --output\" help=\"Output to file instead of stdout\" {\n            arg \"<OUTPUT>\"\n        }\n    }\n}\ncmd \"current\" help=\"Shows current active and installed runtime versions\" {\n    long_help r\"Shows current active and installed runtime versions\n\nThis is similar to `mise ls --current`, but this only shows the runtime\nand/or version. It's designed to fit into scripts more easily.\"\n    after_long_help r\"Examples:\n    # outputs `.tool-versions` compatible format\n    $ mise current\n    python 3.11.0 3.10.0\n    shfmt 3.6.0\n    shellcheck 0.9.0\n    node 20.0.0\n\n    $ mise current node\n    20.0.0\n\n    # can output multiple versions\n    $ mise current python\n    3.11.0 3.10.0\n\"\n    arg \"[PLUGIN]\" help=\"Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc\"\n}\ncmd \"deactivate\" help=\"Disable mise for current shell session\" {\n    long_help r\"Disable mise for current shell session\n\nThis can be used to temporarily disable mise in a shell session.\"\n    after_long_help r\"Examples:\n\n    $ mise deactivate bash\n    $ mise deactivate zsh\n    $ mise deactivate fish\n    $ execx($(mise deactivate xonsh))\n\"\n}\ncmd \"direnv\" help=\"Output direnv function to use mise inside direnv\" {\n    long_help r\"Output direnv function to use mise inside direnv\n\nSee https://mise.jdx.dev/direnv.html for more information\n\nBecause this generates the idiomatic files based on currently installed plugins,\nyou should run this command after installing new plugins. Otherwise\ndirenv may not know to update environment variables when legacy file versions change.\"\n    cmd \"envrc\" hide=true help=\"[internal] This is an internal command that writes an envrc file\\nfor direnv to consume.\"\n    cmd \"exec\" hide=true help=\"[internal] This is an internal command that writes an envrc file\\nfor direnv to consume.\"\n    cmd \"activate\" help=\"Output direnv function to use mise inside direnv\" {\n        long_help r\"Output direnv function to use mise inside direnv\n\nSee https://mise.jdx.dev/direnv.html for more information\n\nBecause this generates the legacy files based on currently installed plugins,\nyou should run this command after installing new plugins. Otherwise\ndirenv may not know to update environment variables when legacy file versions change.\"\n        after_long_help r\"Examples:\n\n    $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh\n    $ echo 'use mise' > .envrc\n    $ direnv allow\n\"\n    }\n}\ncmd \"doctor\" help=\"Check mise installation for possible problems\" {\n    alias \"dr\"\n    after_long_help r\"Examples:\n\n    $ mise doctor\n    [WARN] plugin node is not installed\n\"\n}\ncmd \"env\" help=\"Exports env vars to activate mise a single time\" {\n    alias \"e\"\n    long_help r\"Exports env vars to activate mise a single time\n\nUse this if you don't want to permanently install mise. It's not necessary to\nuse this if you have `mise activate` in your shell rc file.\"\n    after_long_help r#\"Examples:\n\n    $ eval \"$(mise env -s bash)\"\n    $ eval \"$(mise env -s zsh)\"\n    $ mise env -s fish | source\n    $ execx($(mise env -s xonsh))\n\"#\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-s --shell\" help=\"Shell type to generate environment variables for\" {\n        arg \"<SHELL>\"\n    }\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to use\" var=true\n}\ncmd \"exec\" help=\"Execute a command with tool(s) set\" {\n    alias \"x\"\n    long_help r#\"Execute a command with tool(s) set\n\nuse this to avoid modifying the shell session or running ad-hoc commands with mise tools set.\n\nTools will be loaded from .mise.toml/.tool-versions, though they can be overridden with <RUNTIME> args\nNote that only the plugin specified will be overridden, so if a `.tool-versions` file\nincludes \"node 20\" but you run `mise exec python@3.11`; it will still load node@20.\n\nThe \"--\" separates runtimes from the commands to pass along to the subprocess.\"#\n    after_long_help r#\"Examples:\n\n    $ mise exec node@20 -- node ./app.js  # launch app.js using node-20.x\n    $ mise x node@20 -- node ./app.js     # shorter alias\n\n    # Specify command as a string:\n    $ mise exec node@20 python@3.11 --command \"node -v && python -V\"\n\n    # Run a command in a different directory:\n    $ mise x -C /path/to/project node@20 -- node ./app.js\n\"#\n    flag \"-c --command\" help=\"Command string to execute\" {\n        arg \"<C>\"\n    }\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg \"<JOBS>\"\n    }\n    flag \"--raw\" help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to start e.g.: node@20 python@3.10\" var=true\n    arg \"[COMMAND]...\" help=\"Command string to execute (same as --command)\" var=true\n}\ncmd \"generate\" subcommand_required=true help=\"[experimental] Generate files for various tools/services\" {\n    alias \"gen\"\n    cmd \"git-pre-commit\" help=\"[experimental] Generate a git pre-commit hook\" {\n        alias \"pre-commit\"\n        long_help r\"[experimental] Generate a git pre-commit hook\n\nThis command generates a git pre-commit hook that runs a mise task like `mise run pre-commit`\nwhen you commit changes to your repository.\"\n        after_long_help r#\"Examples:\n\n    $ mise generate git-pre-commit --write --task=pre-commit\n    $ git commit -m \"feat: add new feature\" # runs `mise run pre-commit`\n\"#\n        flag \"--hook\" help=\"Which hook to generate (saves to .git/hooks/$hook)\" {\n            arg \"<HOOK>\"\n        }\n        flag \"-t --task\" help=\"The task to run when the pre-commit hook is triggered\" {\n            arg \"<TASK>\"\n        }\n        flag \"-w --write\" help=\"write to .git/hooks/pre-commit and make it executable\"\n    }\n    cmd \"github-action\" help=\"[experimental] Generate a GitHub Action workflow file\" {\n        long_help r\"[experimental] Generate a GitHub Action workflow file\n\nThis command generates a GitHub Action workflow file that runs a mise task like `mise run ci`\nwhen you push changes to your repository.\"\n        after_long_help r#\"Examples:\n\n    $ mise generate github-action --write --task=ci\n    $ git commit -m \"feat: add new feature\"\n    $ git push # runs `mise run ci` on GitHub\n\"#\n        flag \"-n --name\" help=\"the name of the workflow to generate\" {\n            arg \"<NAME>\"\n        }\n        flag \"-t --task\" help=\"The task to run when the workflow is triggered\" {\n            arg \"<TASK>\"\n        }\n        flag \"-w --write\" help=\"write to .github/workflows/$name.yml\"\n    }\n}\ncmd \"global\" hide=true help=\"Sets/gets the global tool version(s)\" {\n    alias \"g\" hide=true\n    long_help r\"Sets/gets the global tool version(s)\n\nDisplays the contents of global config after writing.\nThe file is `$HOME/.config/mise/config.toml` by default. It can be changed with `$MISE_GLOBAL_CONFIG_FILE`.\nIf `$MISE_GLOBAL_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `.mise.toml`.\nOtherwise, it will be parsed as a `.tool-versions` file.\n\nUse MISE_ASDF_COMPAT=1 to default the global config to ~/.tool-versions\n\nUse `mise local` to set a tool version locally in the current directory.\"\n    after_long_help r\"Examples:\n    # set the current version of node to 20.x\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\n    $ mise global --fuzzy node@20\n\n    # set the current version of node to 20.x\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\n    $ mise global --pin node@20\n\n    # show the current version of node in ~/.tool-versions\n    $ mise global node\n    20.0.0\n\"\n    flag \"--pin\" help=\"Save exact version to `~/.tool-versions`\\ne.g.: `mise global --pin node@20` will save `node 20.0.0` to ~/.tool-versions\"\n    flag \"--fuzzy\" help=\"Save fuzzy version to `~/.tool-versions`\\ne.g.: `mise global --fuzzy node@20` will save `node 20` to ~/.tool-versions\\nthis is the default behavior unless MISE_ASDF_COMPAT=1\"\n    flag \"--remove\" help=\"Remove the plugin(s) from ~/.tool-versions\" var=true {\n        arg \"<PLUGIN>\"\n    }\n    flag \"--path\" help=\"Get the path of the global config file\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to add to .tool-versions\\ne.g.: node@20\\nIf this is a single tool with no version, the current value of the global\\n.tool-versions will be displayed\" var=true\n}\ncmd \"hook-env\" hide=true help=\"[internal] called by activate hook to update env vars directory change\" {\n    flag \"-s --shell\" help=\"Shell type to generate script for\" {\n        arg \"<SHELL>\"\n    }\n    flag \"--status\" help=\"Show \\\"mise: <PLUGIN>@<VERSION>\\\" message when changing directories\" hide=true\n    flag \"-q --quiet\" help=\"Hide warnings such as when a tool is not installed\"\n}\ncmd \"hook-not-found\" hide=true help=\"[internal] called by shell when a command is not found\" {\n    flag \"-s --shell\" help=\"Shell type to generate script for\" {\n        arg \"<SHELL>\"\n    }\n    arg \"<BIN>\" help=\"Attempted bin to run\"\n}\ncmd \"implode\" help=\"Removes mise CLI and all related data\" {\n    long_help r\"Removes mise CLI and all related data\n\nSkips config directory by default.\"\n    flag \"--config\" help=\"Also remove config directory\"\n    flag \"-n --dry-run\" help=\"List directories that would be removed without actually removing them\"\n}\ncmd \"install\" help=\"Install a tool version\" {\n    alias \"i\"\n    long_help r\"Install a tool version\n\nInstalls a tool version to `~/.local/share/mise/installs/<PLUGIN>/<VERSION>`\nInstalling alone will not activate the tools so they won't be in PATH.\nTo install and/or activate in one command, use `mise use` which will create a `.mise.toml` file\nin the current directory to activate this tool when inside the directory.\nAlternatively, run `mise exec <TOOL>@<VERSION> -- <COMMAND>` to execute a tool without creating config files.\n\nTools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1`\"\n    after_long_help r\"Examples:\n\n    $ mise install node@20.0.0  # install specific node version\n    $ mise install node@20      # install fuzzy node version\n    $ mise install node         # install version specified in .tool-versions or .mise.toml\n    $ mise install              # installs everything specified in .tool-versions or .mise.toml\n\"\n    flag \"-f --force\" help=\"Force reinstall even if already installed\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg \"<JOBS>\"\n    }\n    flag \"--raw\" help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    flag \"-v --verbose\" help=\"Show installation output\" var=true count=true {\n        long_help \"Show installation output\\n\\nThis argument will print plugin output such as download, configuration, and compilation output.\"\n    }\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to install e.g.: node@20\" var=true\n}\ncmd \"latest\" help=\"Gets the latest available version for a plugin\" {\n    after_long_help r\"Examples:\n\n    $ mise latest node@20  # get the latest version of node 20\n    20.0.0\n\n    $ mise latest node     # get the latest stable version of node\n    20.0.0\n\"\n    flag \"-i --installed\" help=\"Show latest installed instead of available version\"\n    arg \"<TOOL@VERSION>\" help=\"Tool to get the latest version of\"\n    arg \"[ASDF_VERSION]\" help=\"The version prefix to use when querying the latest version same as the first argument after the \\\"@\\\" used for asdf compatibility\" hide=true\n}\ncmd \"link\" help=\"Symlinks a tool version into mise\" {\n    alias \"ln\"\n    long_help r\"Symlinks a tool version into mise\n\nUse this for adding installs either custom compiled outside\nmise or built with a different tool.\"\n    after_long_help r\"Examples:\n    # build node-20.0.0 with node-build and link it into mise\n    $ node-build 20.0.0 ~/.nodes/20.0.0\n    $ mise link node@20.0.0 ~/.nodes/20.0.0\n\n    # have mise use the python version provided by Homebrew\n    $ brew install node\n    $ mise link node@brew $(brew --prefix node)\n    $ mise use node@brew\n\"\n    flag \"-f --force\" help=\"Overwrite an existing tool version if it exists\"\n    arg \"<TOOL@VERSION>\" help=\"Tool name and version to create a symlink for\"\n    arg \"<PATH>\" help=\"The local path to the tool version\\ne.g.: ~/.nvm/versions/node/v20.0.0\"\n}\ncmd \"local\" hide=true help=\"Sets/gets tool version in local .tool-versions or .mise.toml\" {\n    alias \"l\" hide=true\n    long_help r\"Sets/gets tool version in local .tool-versions or .mise.toml\n\nUse this to set a tool's version when within a directory\nUse `mise global` to set a tool version globally\nThis uses `.tool-version` by default unless there is a `.mise.toml` file or if `MISE_USE_TOML`\nis set. A future v2 release of mise will default to using `.mise.toml`.\"\n    after_long_help r\"Examples:\n    # set the current version of node to 20.x for the current directory\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\n    $ mise local node@20\n\n    # set node to 20.x for the current project (recurses up to find .tool-versions)\n    $ mise local -p node@20\n\n    # set the current version of node to 20.x for the current directory\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\n    $ mise local --fuzzy node@20\n\n    # removes node from .tool-versions\n    $ mise local --remove=node\n\n    # show the current version of node in .tool-versions\n    $ mise local node\n    20.0.0\n\"\n    flag \"-p --parent\" help=\"Recurse up to find a .tool-versions file rather than using the current directory only\\nby default this command will only set the tool in the current directory (\\\"$PWD/.tool-versions\\\")\"\n    flag \"--pin\" help=\"Save exact version to `.tool-versions`\\ne.g.: `mise local --pin node@20` will save `node 20.0.0` to .tool-versions\"\n    flag \"--fuzzy\" help=\"Save fuzzy version to `.tool-versions` e.g.: `mise local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless MISE_ASDF_COMPAT=1\"\n    flag \"--remove\" help=\"Remove the plugin(s) from .tool-versions\" var=true {\n        arg \"<PLUGIN>\"\n    }\n    flag \"--path\" help=\"Get the path of the config file\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to add to .tool-versions/.mise.toml\\ne.g.: node@20\\nif this is a single tool with no version,\\nthe current value of .tool-versions/.mise.toml will be displayed\" var=true\n}\ncmd \"ls\" help=\"List installed and active tool versions\" {\n    alias \"list\"\n    long_help r#\"List installed and active tool versions\n\nThis command lists tools that mise \"knows about\".\nThese may be tools that are currently installed, or those\nthat are in a config file (active) but may or may not be installed.\n\nIt's a useful command to get the current state of your tools.\"#\n    after_long_help r#\"Examples:\n\n    $ mise ls\n    node    20.0.0 ~/src/myapp/.tool-versions latest\n    python  3.11.0 ~/.tool-versions           3.10\n    python  3.10.0\n\n    $ mise ls --current\n    node    20.0.0 ~/src/myapp/.tool-versions 20\n    python  3.11.0 ~/.tool-versions           3.11.0\n\n    $ mise ls --json\n    {\n      \"node\": [\n        {\n          \"version\": \"20.0.0\",\n          \"install_path\": \"/Users/jdx/.mise/installs/node/20.0.0\",\n          \"source\": {\n            \"type\": \".mise.toml\",\n            \"path\": \"/Users/jdx/.mise.toml\"\n          }\n        }\n      ],\n      \"python\": [...]\n    }\n\"#\n    flag \"-p --plugin\" hide=true {\n        arg \"<PLUGIN_FLAG>\"\n    }\n    flag \"-c --current\" help=\"Only show tool versions currently specified in a .tool-versions/.mise.toml\"\n    flag \"-g --global\" help=\"Only show tool versions currently specified in a the global .tool-versions/.mise.toml\"\n    flag \"-i --installed\" help=\"Only show tool versions that are installed (Hides tools defined in .tool-versions/.mise.toml but not installed)\"\n    flag \"--parseable\" help=\"Output in an easily parseable format\" hide=true\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-m --missing\" help=\"Display missing tool versions\"\n    flag \"--prefix\" help=\"Display versions matching this prefix\" {\n        arg \"<PREFIX>\"\n    }\n    flag \"--no-header\" help=\"Don't display headers\"\n    arg \"[PLUGIN]...\" help=\"Only show tool versions from [PLUGIN]\" var=true\n}\ncmd \"ls-remote\" help=\"List runtime versions available for install\" {\n    alias \"list-all\" \"list-remote\" hide=true\n    long_help r\"List runtime versions available for install\n\nnote that the results are cached for 24 hours\nrun `mise cache clean` to clear the cache and get fresh results\"\n    after_long_help r\"Examples:\n\n    $ mise ls-remote node\n    18.0.0\n    20.0.0\n\n    $ mise ls-remote node@20\n    20.0.0\n    20.1.0\n\n    $ mise ls-remote node 20\n    20.0.0\n    20.1.0\n\"\n    flag \"--all\" help=\"Show all installed plugins and versions\"\n    arg \"[TOOL@VERSION]\" help=\"Plugin to get versions for\"\n    arg \"[PREFIX]\" help=\"The version prefix to use when querying the latest version\\nsame as the first argument after the \\\"@\\\"\"\n}\ncmd \"outdated\" help=\"Shows outdated tool versions\" {\n    after_long_help r#\"Examples:\n\n    $ mise outdated\n    Plugin  Requested  Current  Latest\n    python  3.11       3.11.0   3.11.1\n    node    20         20.0.0   20.1.0\n\n    $ mise outdated node\n    Plugin  Requested  Current  Latest\n    node    20         20.0.0   20.1.0\n\n    $ mise outdated --json\n    {\"python\": {\"requested\": \"3.11\", \"current\": \"3.11.0\", \"latest\": \"3.11.1\"}, ...}\n\"#\n    flag \"-J --json\" help=\"Output in JSON format\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to show outdated versions for\\ne.g.: node@20 python@3.10\\nIf not specified, all tools in global and local configs will be shown\" var=true\n}\ncmd \"plugins\" help=\"Manage plugins\" {\n    alias \"p\"\n    alias \"plugin\" \"plugin-list\" hide=true\n    flag \"-a --all\" help=\"list all available remote plugins\" hide=true {\n        long_help \"list all available remote plugins\\n\\nsame as `mise plugins ls-remote`\"\n    }\n    flag \"-c --core\" help=\"The built-in plugins only\\nNormally these are not shown\"\n    flag \"--user\" help=\"List installed plugins\" {\n        long_help \"List installed plugins\\n\\nThis is the default behavior but can be used with --core\\nto show core and user plugins\"\n    }\n    flag \"-u --urls\" help=\"Show the git url for each plugin\\ne.g.: https://github.com/asdf-vm/asdf-nodejs.git\"\n    flag \"--refs\" help=\"Show the git refs for each plugin\\ne.g.: main 1234abc\" hide=true\n    cmd \"install\" help=\"Install a plugin\" {\n        alias \"i\" \"a\" \"add\"\n        long_help r\"Install a plugin\n\nnote that mise automatically can install plugins when you install a tool\ne.g.: `mise install node@20` will autoinstall the node plugin\n\nThis behavior can be modified in ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n    # install the node via shorthand\n    $ mise plugins install node\n\n    # install the node plugin using a specific git url\n    $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git\n\n    # install the node plugin using the git url only\n    # (node is inferred from the url)\n    $ mise plugins install https://github.com/mise-plugins/rtx-nodejs.git\n\n    # install the node plugin using a specific ref\n    $ mise plugins install node https://github.com/mise-plugins/rtx-nodejs.git#v1.0.0\n\"\n        flag \"-f --force\" help=\"Reinstall even if plugin exists\"\n        flag \"-a --all\" help=\"Install all missing plugins\\nThis will only install plugins that have matching shorthands.\\ni.e.: they don't need the full git repo url\"\n        flag \"-v --verbose\" help=\"Show installation output\" var=true count=true\n        arg \"[NEW_PLUGIN]\" help=\"The name of the plugin to install\\ne.g.: node, ruby\\nCan specify multiple plugins: `mise plugins install node ruby python`\"\n        arg \"[GIT_URL]\" help=\"The git url of the plugin\"\n        arg \"[REST]...\" var=true hide=true\n    }\n    cmd \"link\" help=\"Symlinks a plugin into mise\" {\n        alias \"ln\"\n        long_help r\"Symlinks a plugin into mise\n\nThis is used for developing a plugin.\"\n        after_long_help r#\"Examples:\n    # essentially just `ln -s ./mise-node ~/.local/share/mise/plugins/node`\n    $ mise plugins link node ./mise-node\n\n    # infer plugin name as \"node\"\n    $ mise plugins link ./mise-node\n\"#\n        flag \"-f --force\" help=\"Overwrite existing plugin\"\n        arg \"<NAME>\" help=\"The name of the plugin\\ne.g.: node, ruby\"\n        arg \"[PATH]\" help=\"The local path to the plugin\\ne.g.: ./mise-node\"\n    }\n    cmd \"ls\" help=\"List installed plugins\" {\n        alias \"list\"\n        long_help r\"List installed plugins\n\nCan also show remotely available plugins to install.\"\n        after_long_help r\"Examples:\n\n    $ mise plugins ls\n    node\n    ruby\n\n    $ mise plugins ls --urls\n    node    https://github.com/asdf-vm/asdf-nodejs.git\n    ruby    https://github.com/asdf-vm/asdf-ruby.git\n\"\n        flag \"-a --all\" help=\"List all available remote plugins\\nSame as `mise plugins ls-remote`\" hide=true\n        flag \"-c --core\" help=\"The built-in plugins only\\nNormally these are not shown\"\n        flag \"--user\" help=\"List installed plugins\" {\n            long_help \"List installed plugins\\n\\nThis is the default behavior but can be used with --core\\nto show core and user plugins\"\n        }\n        flag \"-u --urls\" help=\"Show the git url for each plugin\\ne.g.: https://github.com/asdf-vm/asdf-nodejs.git\"\n        flag \"--refs\" help=\"Show the git refs for each plugin\\ne.g.: main 1234abc\" hide=true\n    }\n    cmd \"ls-remote\" help=\"List all available remote plugins\" {\n        alias \"list-remote\" \"list-all\"\n        long_help r\"\nList all available remote plugins\n\nThe full list is here: https://github.com/jdx/mise/blob/main/registry/\n\nExamples:\n  $ mise plugins ls-remote\n\"\n        flag \"-u --urls\" help=\"Show the git url for each plugin e.g.: https://github.com/mise-plugins/rtx-nodejs.git\"\n        flag \"--only-names\" help=\"Only show the name of each plugin by default it will show a \\\"*\\\" next to installed plugins\"\n    }\n    cmd \"uninstall\" help=\"Removes a plugin\" {\n        alias \"remove\" \"rm\"\n        after_long_help r\"Examples:\n\n    $ mise uninstall node\n\"\n        flag \"-p --purge\" help=\"Also remove the plugin's installs, downloads, and cache\"\n        flag \"-a --all\" help=\"Remove all plugins\"\n        arg \"[PLUGIN]...\" help=\"Plugin(s) to remove\" var=true\n    }\n    cmd \"update\" help=\"Updates a plugin to the latest version\" {\n        alias \"up\" \"upgrade\"\n        long_help r\"Updates a plugin to the latest version\n\nnote: this updates the plugin itself, not the runtime versions\"\n        after_long_help r\"Examples:\n\n    $ mise plugins update            # update all plugins\n    $ mise plugins update node       # update only node\n    $ mise plugins update node#beta  # specify a ref\n\"\n        flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\nDefault: 4\" {\n            arg \"<JOBS>\"\n        }\n        arg \"[PLUGIN]...\" help=\"Plugin(s) to update\" var=true\n    }\n}\ncmd \"prune\" help=\"Delete unused versions of tools\" {\n    long_help r\"Delete unused versions of tools\n\nmise tracks which config files have been used in ~/.local/state/mise/tracked-configs\nVersions which are no longer the latest specified in any of those configs are deleted.\nVersions installed only with environment variables (`MISE_<PLUGIN>_VERSION`) will be deleted,\nas will versions only referenced on the command line (`mise exec <PLUGIN>@<VERSION>`).\"\n    after_long_help r\"Examples:\n\n    $ mise prune --dry-run\n    rm -rf ~/.local/share/mise/versions/node/20.0.0\n    rm -rf ~/.local/share/mise/versions/node/20.0.1\n\"\n    flag \"-n --dry-run\" help=\"Do not actually delete anything\"\n    flag \"--configs\" help=\"Prune only tracked and trusted configuration links that point to non-existent configurations\"\n    flag \"--tools\" help=\"Prune only unused versions of tools\"\n    arg \"[PLUGIN]...\" help=\"Prune only versions from this plugin(s)\" var=true\n}\ncmd \"registry\" help=\"[experimental] List available tools\" {\n    after_long_help r\"Examples:\n\n    $ mise registry\n    node    core:node\n    poetry  asdf:mise-plugins/mise-poetry\n    ubi     cargo:ubi\n\"\n}\ncmd \"reshim\" help=\"rebuilds the shim farm\" {\n    long_help r#\"rebuilds the shim farm\n\nThis creates new shims in ~/.local/share/mise/shims for CLIs that have been added.\nmise will try to do this automatically for commands like `npm i -g` but there are\nother ways to install things (like using yarn or pnpm for node) that mise does\nnot know about and so it will be necessary to call this explicitly.\n\nIf you think mise should automatically call this for a particular command, please\nopen an issue on the mise repo. You can also setup a shell function to reshim\nautomatically (it's really fast so you don't need to worry about overhead):\n\nnpm() {\n  command npm \"$@\"\n  mise reshim\n}\"#\n    after_long_help r\"Examples:\n\n    $ mise reshim\n    $ ~/.local/share/mise/shims/node -v\n    v20.0.0\n\"\n    arg \"[PLUGIN]\" hide=true\n    arg \"[VERSION]\" hide=true\n}\ncmd \"run\" help=\"[experimental] Run a task\" {\n    alias \"r\"\n    long_help r#\"[experimental] Run a task\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in .mise.toml or as standalone scripts.\nIn .mise.toml, tasks take this form:\n\n    [tasks.build]\n    run = \"npm run build\"\n    sources = [\"src/**/*.ts\"]\n    outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in the `.mise/tasks`, `mise/tasks` or `.config/mise/tasks` directory.\nThe name of the script will be the name of the tasks.\n\n    $ cat .mise/tasks/build<<EOF\n    #!/usr/bin/env bash\n    npm run build\n    EOF\n    $ mise run build\"#\n    after_long_help r#\"Examples:\n\n    # Runs the \"lint\" tasks. This needs to either be defined in .mise.toml\n    # or as a standalone script. See the project README for more information.\n    $ mise run lint\n\n    # Forces the \"build\" tasks to run even if its sources are up-to-date.\n    $ mise run build --force\n\n    # Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n    # This forces `--jobs=1` to prevent interleaving of output.\n    $ mise run test --raw\n\n    # Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n    $ mise run lint ::: test ::: check\n\n    # Execute multiple tasks each with their own arguments.\n    $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n\"#\n    flag \"-C --cd\" help=\"Change to this directory before executing the command\" {\n        arg \"<CD>\"\n    }\n    flag \"-n --dry-run\" help=\"Don't actually run the task(s), just print them in order of execution\"\n    flag \"-f --force\" help=\"Force the tasks to run even if outputs are up to date\"\n    flag \"-p --prefix\" help=\"Print stdout/stderr by line, prefixed with the tasks's label\\nDefaults to true if --jobs > 1\\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var\"\n    flag \"-i --interleave\" help=\"Print directly to stdout/stderr instead of by line\\nDefaults to true if --jobs == 1\\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var\"\n    flag \"-t --tool\" help=\"Tool(s) to also add e.g.: node@20 python@3.10\" var=true {\n        arg \"<TOOL@VERSION>\"\n    }\n    flag \"-j --jobs\" help=\"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\" {\n        arg \"<JOBS>\"\n    }\n    flag \"-r --raw\" help=\"Read/write directly to stdin/stdout/stderr instead of by line\\nConfigure with `raw` config or `MISE_RAW` env var\"\n    flag \"--timings\" help=\"Shows elapsed time after each tasks\"\n    arg \"[TASK]\" help=\"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\" default=\"default\"\n    arg \"[ARGS]...\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks\" var=true\n}\ncmd \"self-update\" help=\"Updates mise itself\" {\n    long_help r\"Updates mise itself\n\nUses the GitHub Releases API to find the latest release and binary.\nBy default, this will also update any installed plugins.\nUses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits.\"\n    flag \"-f --force\" help=\"Update even if already up to date\"\n    flag \"--no-plugins\" help=\"Disable auto-updating plugins\"\n    flag \"-y --yes\" help=\"Skip confirmation prompt\"\n    arg \"[VERSION]\" help=\"Update to a specific version\"\n}\ncmd \"set\" help=\"Manage environment variables\" {\n    alias \"ev\" \"env-vars\" hide=true\n    long_help r#\"Manage environment variables\n\nBy default this command modifies \".mise.toml\" in the current directory.\"#\n    after_long_help r\"Examples:\n\n    $ mise set NODE_ENV=production\n\n    $ mise set NODE_ENV\n    production\n\n    $ mise set\n    key       value       source\n    NODE_ENV  production  ~/.config/mise/config.toml\n\"\n    flag \"--file\" help=\"The TOML file to update\" {\n        long_help \"The TOML file to update\\n\\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or \\\".mise.toml\\\".\"\n        arg \"<FILE>\"\n    }\n    flag \"-g --global\" help=\"Set the environment variable in the global config file\"\n    flag \"--remove\" help=\"Remove the environment variable from config file\" var=true hide=true {\n        long_help \"Remove the environment variable from config file\\n\\nCan be used multiple times.\"\n        arg \"<ENV_VAR>\"\n    }\n    arg \"[ENV_VARS]...\" help=\"Environment variable(s) to set\\ne.g.: NODE_ENV=production\" var=true\n}\ncmd \"settings\" help=\"Manage settings\" {\n    flag \"--keys\" help=\"Only display key names for each setting\"\n    cmd \"get\" help=\"Show a current setting\" {\n        long_help r\"Show a current setting\n\nThis is the contents of a single entry in ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool-alias get`\"\n        after_long_help r\"Examples:\n\n    $ mise settings get legacy_version_file\n    true\n\"\n        arg \"<SETTING>\" help=\"The setting to show\"\n    }\n    cmd \"ls\" help=\"Show current settings\" {\n        alias \"list\"\n        long_help r\"Show current settings\n\nThis is the contents of ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool-alias`\"\n        after_long_help r\"Examples:\n\n    $ mise settings\n    legacy_version_file = false\n\"\n        flag \"--keys\" help=\"Only display key names for each setting\"\n    }\n    cmd \"set\" help=\"Add/update a setting\" {\n        alias \"add\" \"create\"\n        long_help r\"Add/update a setting\n\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n\n    $ mise settings legacy_version_file=true\n\"\n        arg \"<SETTING>\" help=\"The setting to set\"\n        arg \"<VALUE>\" help=\"The value to set\"\n    }\n    cmd \"unset\" help=\"Clears a setting\" {\n        alias \"rm\" \"remove\" \"delete\" \"del\"\n        long_help r\"Clears a setting\n\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help r\"Examples:\n\n    $ mise settings unset legacy_version_file\n\"\n        arg \"<SETTING>\" help=\"The setting to remove\"\n    }\n}\ncmd \"shell\" help=\"Sets a tool version for the current session\" {\n    alias \"sh\"\n    long_help r#\"Sets a tool version for the current session\n\nOnly works in a session where mise is already activated.\n\nThis works by setting environment variables for the current shell session\nsuch as `MISE_NODE_VERSION=20` which is \"eval\"ed as a shell function created\nby `mise activate`.\"#\n    after_long_help r\"Examples:\n\n    $ mise shell node@20\n    $ node -v\n    v20.0.0\n\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg \"<JOBS>\"\n    }\n    flag \"--raw\" help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    flag \"-u --unset\" help=\"Removes a previously set version\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to use\" var=true\n}\ncmd \"sync\" subcommand_required=true help=\"Add tool versions from external tools to mise\" {\n    cmd \"node\" help=\"Symlinks all tool versions from an external tool into mise\" {\n        long_help r\"Symlinks all tool versions from an external tool into mise\n\nFor example, use this to import all Homebrew node installs into mise\"\n        after_long_help r\"Examples:\n\n    $ brew install node@18 node@20\n    $ mise sync node --brew\n    $ mise use -g node@18 - uses Homebrew-provided node\n\"\n        flag \"--brew\" help=\"Get tool versions from Homebrew\"\n        flag \"--nvm\" help=\"Get tool versions from nvm\"\n        flag \"--nodenv\" help=\"Get tool versions from nodenv\"\n    }\n    cmd \"python\" help=\"Symlinks all tool versions from an external tool into mise\" {\n        long_help r\"Symlinks all tool versions from an external tool into mise\n\nFor example, use this to import all pyenv installs into mise\"\n        after_long_help r\"Examples:\n\n    $ pyenv install 3.11.0\n    $ mise sync python --pyenv\n    $ mise use -g python@3.11.0 - uses pyenv-provided python\n\"\n        flag \"--pyenv\" help=\"Get tool versions from pyenv\" required=true\n    }\n}\ncmd \"tasks\" help=\"[experimental] Manage tasks\" {\n    alias \"t\"\n    alias \"task\" hide=true\n    after_long_help r\"Examples:\n\n    $ mise tasks ls\n\"\n    flag \"--no-header\" help=\"Do not print table header\"\n    flag \"-x --extended\" help=\"Show all columns\"\n    flag \"--hidden\" help=\"Show hidden tasks\"\n    flag \"--sort\" help=\"Sort by column. Default is name.\" {\n        arg \"<COLUMN>\"\n    }\n    flag \"--sort-order\" help=\"Sort order. Default is asc.\" {\n        arg \"<SORT_ORDER>\"\n    }\n    flag \"-J --json\" help=\"Output in JSON format\"\n    cmd \"deps\" help=\"[experimental] Display a tree visualization of a dependency graph\" {\n        after_long_help r#\"Examples:\n\n    # Show dependencies for all tasks\n    $ mise tasks deps\n\n    # Show dependencies for the \"lint\", \"test\" and \"check\" tasks\n    $ mise tasks deps lint test check\n\n    # Show dependencies in DOT format\n    $ mise tasks deps --dot\n\"#\n        flag \"--hidden\" help=\"Show hidden tasks\"\n        flag \"--dot\" help=\"Display dependencies in DOT format\"\n        arg \"[TASKS]...\" help=\"Tasks to show dependencies for\\nCan specify multiple tasks by separating with spaces\\ne.g.: mise tasks deps lint test check\" var=true\n    }\n    cmd \"edit\" help=\"[experimental] Edit a task with $EDITOR\" {\n        long_help r\"[experimental] Edit a task with $EDITOR\n\nThe task will be created as a standalone script if it does not already exist.\"\n        after_long_help r\"Examples:\n\n    $ mise tasks edit build\n    $ mise tasks edit test\n\"\n        flag \"-p --path\" help=\"Display the path to the task instead of editing it\"\n        arg \"<TASK>\" help=\"Task to edit\"\n    }\n    cmd \"ls\" help=\"[experimental] List available tasks to execute\\nThese may be included from the config file or from the project's .mise/tasks directory\\nmise will merge all tasks from all parent directories into this list.\" {\n        long_help r\"[experimental] List available tasks to execute\nThese may be included from the config file or from the project's .mise/tasks directory\nmise will merge all tasks from all parent directories into this list.\n\nSo if you have global tasks in ~/.config/mise/tasks/* and project-specific tasks in\n~/myproject/.mise/tasks/*, then they'll both be available but the project-specific\ntasks will override the global ones if they have the same name.\"\n        after_long_help r\"Examples:\n\n    $ mise tasks ls\n\"\n        flag \"--no-header\" help=\"Do not print table header\"\n        flag \"-x --extended\" help=\"Show all columns\"\n        flag \"--hidden\" help=\"Show hidden tasks\"\n        flag \"--sort\" help=\"Sort by column. Default is name.\" {\n            arg \"<COLUMN>\"\n        }\n        flag \"--sort-order\" help=\"Sort order. Default is asc.\" {\n            arg \"<SORT_ORDER>\"\n        }\n        flag \"-J --json\" help=\"Output in JSON format\"\n    }\n    cmd \"run\" help=\"[experimental] Run a task\" {\n        alias \"r\"\n        long_help r#\"[experimental] Run a task\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in .mise.toml or as standalone scripts.\nIn .mise.toml, tasks take this form:\n\n    [tasks.build]\n    run = \"npm run build\"\n    sources = [\"src/**/*.ts\"]\n    outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in the `.mise/tasks`, `mise/tasks` or `.config/mise/tasks` directory.\nThe name of the script will be the name of the tasks.\n\n    $ cat .mise/tasks/build<<EOF\n    #!/usr/bin/env bash\n    npm run build\n    EOF\n    $ mise run build\"#\n        after_long_help r#\"Examples:\n\n    # Runs the \"lint\" tasks. This needs to either be defined in .mise.toml\n    # or as a standalone script. See the project README for more information.\n    $ mise run lint\n\n    # Forces the \"build\" tasks to run even if its sources are up-to-date.\n    $ mise run build --force\n\n    # Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n    # This forces `--jobs=1` to prevent interleaving of output.\n    $ mise run test --raw\n\n    # Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n    $ mise run lint ::: test ::: check\n\n    # Execute multiple tasks each with their own arguments.\n    $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n\"#\n        flag \"-C --cd\" help=\"Change to this directory before executing the command\" {\n            arg \"<CD>\"\n        }\n        flag \"-n --dry-run\" help=\"Don't actually run the task(s), just print them in order of execution\"\n        flag \"-f --force\" help=\"Force the tasks to run even if outputs are up to date\"\n        flag \"-p --prefix\" help=\"Print stdout/stderr by line, prefixed with the tasks's label\\nDefaults to true if --jobs > 1\\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var\"\n        flag \"-i --interleave\" help=\"Print directly to stdout/stderr instead of by line\\nDefaults to true if --jobs == 1\\nConfigure with `task_output` config or `MISE_TASK_OUTPUT` env var\"\n        flag \"-t --tool\" help=\"Tool(s) to also add e.g.: node@20 python@3.10\" var=true {\n            arg \"<TOOL@VERSION>\"\n        }\n        flag \"-j --jobs\" help=\"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\" {\n            arg \"<JOBS>\"\n        }\n        flag \"-r --raw\" help=\"Read/write directly to stdin/stdout/stderr instead of by line\\nConfigure with `raw` config or `MISE_RAW` env var\"\n        flag \"--timings\" help=\"Shows elapsed time after each tasks\"\n        arg \"[TASK]\" help=\"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\" default=\"default\"\n        arg \"[ARGS]...\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks\" var=true\n    }\n}\ncmd \"trust\" help=\"Marks a config file as trusted\" {\n    long_help r\"Marks a config file as trusted\n\nThis means mise will parse the file with potentially dangerous\nfeatures enabled.\n\nThis includes:\n- environment variables\n- templates\n- `path:` plugin versions\"\n    after_long_help r\"Examples:\n    # trusts ~/some_dir/.mise.toml\n    $ mise trust ~/some_dir/.mise.toml\n\n    # trusts .mise.toml in the current or parent directory\n    $ mise trust\n\"\n    flag \"-a --all\" help=\"Trust all config files in the current directory and its parents\"\n    flag \"--untrust\" help=\"No longer trust this config\"\n    flag \"--show\" help=\"Show the trusted status of config files from the current directory and its parents.\\nDoes not trust or untrust any files.\"\n    arg \"[CONFIG_FILE]\" help=\"The config file to trust\"\n}\ncmd \"uninstall\" help=\"Removes runtime versions\" {\n    alias \"remove\" \"rm\"\n    after_long_help r\"Examples:\n\n    $ mise uninstall node@18.0.0 # will uninstall specific version\n    $ mise uninstall node        # will uninstall current node version\n    $ mise uninstall --all node@18.0.0 # will uninstall all node versions\n\"\n    flag \"-a --all\" help=\"Delete all installed versions\"\n    flag \"-n --dry-run\" help=\"Do not actually delete anything\"\n    arg \"[INSTALLED_TOOL@VERSION]...\" help=\"Tool(s) to remove\" var=true\n}\ncmd \"unset\" help=\"Remove environment variable(s) from the config file\" {\n    long_help r#\"Remove environment variable(s) from the config file\n\nBy default this command modifies \".mise.toml\" in the current directory.\"#\n    flag \"-f --file\" help=\"Specify a file to use instead of \\\".mise.toml\\\"\" {\n        arg \"<FILE>\"\n    }\n    flag \"-g --global\" help=\"Use the global config file\"\n    arg \"[KEYS]...\" help=\"Environment variable(s) to remove\\ne.g.: NODE_ENV\" var=true\n}\ncmd \"upgrade\" help=\"Upgrades outdated tool versions\" {\n    alias \"up\"\n    flag \"-n --dry-run\" help=\"Just print what would be done, don't actually do it\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg \"<JOBS>\"\n    }\n    flag \"-i --interactive\" help=\"Display multiselect menu to choose which tools to upgrade\"\n    flag \"--raw\" help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to upgrade\\ne.g.: node@20 python@3.10\\nIf not specified, all current tools will be upgraded\" var=true\n}\ncmd \"usage\" help=\"Generate a usage CLI spec\" {\n    long_help r\"Generate a usage CLI spec\n\nSee https://usage.jdx.dev for more information\"\n}\ncmd \"use\" help=\"Install tool version and add it to config\" {\n    alias \"u\"\n    long_help r\"Install tool version and add it to config\n\nThis will install the tool if it is not already installed.\nBy default, this will use a `.mise.toml` file in the current directory.\nUse the --global flag to use the global config file instead.\nThis replaces asdf's `local` and `global` commands, however those are still available in mise.\"\n    after_long_help r\"Examples:\n\n    # set the current version of node to 20.x in .mise.toml of current directory\n    # will write the fuzzy version (e.g.: 20)\n    $ mise use node@20\n\n    # set the current version of node to 20.x in ~/.config/mise/config.toml\n    # will write the precise version (e.g.: 20.0.0)\n    $ mise use -g --pin node@20\n\n    # sets .mise.local.toml (which is intended not to be committed to a project)\n    $ mise use --env local node@20\n\n    # sets .mise.staging.toml (which is used if MISE_ENV=staging)\n    $ mise use --env staging node@20\n\"\n    flag \"-f --force\" help=\"Force reinstall even if already installed\"\n    flag \"--fuzzy\" help=\"Save fuzzy version to config file\\ne.g.: `mise use --fuzzy node@20` will save 20 as the version\\nthis is the default behavior unless MISE_ASDF_COMPAT=1\"\n    flag \"-g --global\" help=\"Use the global config file (~/.config/mise/config.toml) instead of the local one\"\n    flag \"-e --env\" help=\"Modify an environment-specific config file like .mise.<env>.toml\" {\n        arg \"<ENV>\"\n    }\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg \"<JOBS>\"\n    }\n    flag \"--raw\" help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    flag \"--remove\" help=\"Remove the plugin(s) from config file\" var=true {\n        arg \"<PLUGIN>\"\n    }\n    flag \"-p --path\" help=\"Specify a path to a config file or directory If a directory is specified, it will look for .mise.toml (default) or .tool-versions\" {\n        arg \"<PATH>\"\n    }\n    flag \"--pin\" help=\"Save exact version to config file\\ne.g.: `mise use --pin node@20` will save 20.0.0 as the version\\nSet MISE_ASDF_COMPAT=1 to make this the default behavior\"\n    arg \"[TOOL@VERSION]...\" help=\"Tool(s) to add to config file\\ne.g.: node@20, cargo:ripgrep@latest npm:prettier@3\\nIf no version is specified, it will default to @latest\" var=true\n}\ncmd \"version\" help=\"Show mise version\" {\n    alias \"v\" hide=true\n}\ncmd \"watch\" help=\"[experimental] Run a task watching for changes\" {\n    alias \"w\"\n    after_long_help r#\"Examples:\n    $ mise watch -t build\n    Runs the \"build\" tasks. Will re-run the tasks when any of its sources change.\n    Uses \"sources\" from the tasks definition to determine which files to watch.\n\n    $ mise watch -t build --glob src/**/*.rs\n    Runs the \"build\" tasks but specify the files to watch with a glob pattern.\n    This overrides the \"sources\" from the tasks definition.\n\n    $ mise run -t build --clear\n    Extra arguments are passed to watchexec. See `watchexec --help` for details.\n\"#\n    flag \"-t --task\" help=\"Tasks to run\" var=true {\n        arg \"<TASK>\"\n    }\n    flag \"-g --glob\" help=\"Files to watch\\nDefaults to sources from the task(s)\" var=true {\n        arg \"<GLOB>\"\n    }\n    arg \"[ARGS]...\" help=\"Extra arguments\" var=true\n}\ncmd \"where\" help=\"Display the installation path for a runtime\" {\n    long_help r\"Display the installation path for a runtime\n\nMust be installed.\"\n    after_long_help r\"Examples:\n    # Show the latest installed version of node\n    # If it is is not installed, errors\n    $ mise where node@20\n    /home/jdx/.local/share/mise/installs/node/20.0.0\n\n    # Show the current, active install directory of node\n    # Errors if node is not referenced in any .tool-version file\n    $ mise where node\n    /home/jdx/.local/share/mise/installs/node/20.0.0\n\"\n    arg \"<TOOL@VERSION>\" help=\"Tool(s) to look up\\ne.g.: ruby@3\\nif \\\"@<PREFIX>\\\" is specified, it will show the latest installed version\\nthat matches the prefix\\notherwise, it will show the current, active installed version\"\n    arg \"[ASDF_VERSION]\" help=\"the version prefix to use when querying the latest version\\nsame as the first argument after the \\\"@\\\"\\nused for asdf compatibility\" hide=true\n}\ncmd \"which\" help=\"Shows the path that a bin name points to\" {\n    after_long_help r\"Examples:\n\n    $ mise which node\n    /home/username/.local/share/mise/installs/node/20.0.0/bin/node\n    $ mise which node --plugin\n    node\n    $ mise which node --version\n    20.0.0\n\"\n    flag \"--plugin\" help=\"Show the plugin name instead of the path\"\n    flag \"--version\" help=\"Show the version instead of the path\"\n    flag \"-t --tool\" help=\"Use a specific tool@version\\ne.g.: `mise which npm --tool=node@20`\" {\n        arg \"<TOOL@VERSION>\"\n    }\n    arg \"<BIN_NAME>\" help=\"The bin name to look up\"\n}\ncmd \"render-help\" hide=true help=\"internal command to generate markdown from help\"\ncmd \"render-mangen\" hide=true help=\"internal command to generate markdown from help\"\n\ncomplete \"alias\" run=\"mise alias ls {{words[PREV]}} | awk '{print $2}'\"\ncomplete \"config_file\" type=\"file\"\ncomplete \"new_plugin\" run=\"mise plugins --all\"\ncomplete \"plugin\" run=\"mise plugins --core --user\"\ncomplete \"prefix\" run=\"mise ls-remote {{words[PREV]}}\"\ncomplete \"setting\" run=\"mise settings --keys\"\ncomplete \"task\" run=\"mise tasks | awk '{print $1}'\"\n\ncomplete \"tool@version\" run=r#\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    versions=$(mise ls-remote $tool $prefix | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise plugins --all)\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"#\n\ncomplete \"installed_tool@version\" run=r#\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    if [ ! -z \"$prefix\" ]; then\n      prefix=\"--prefix $prefix\"\n    fi\n    versions=$(mise ls --installed $tool $prefix | awk '{print $2}' | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise plugins --core --user)\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"#\n"
  },
  {
    "path": "docs/paranoid.md",
    "content": "# Paranoid\n\nParanoid is an optional behavior that locks mise down more to make it harder\nfor a bad actor to compromise your system. These are settings that I\npersonally do not use on my own system because I find the behavior too\nrestrictive for the benefits.\n\nParanoid mode can be enabled with either `MISE_PARANOID=1` or a setting:\n\n```sh\nmise settings paranoid=1\n```\n\n## Config files\n\nNormally `mise` will make sure some config files are \"trusted\" before loading\nthem. This will prompt you to confirm that you want to load the file, e.g.:\n\n```sh\n$ mise install\nmise ~/src/mise/.tool-versions is not trusted. Trust it [y/n]?\n```\n\nGenerally only potentially dangerous config files are checked such as files\nthat use templates (which can execute arbitrary code) or that set env vars.\nUnder paranoid, however, all config files must be trusted first.\n\nAlso, in normal mode, a config file only needs to be trusted a single time.\nIn paranoid, the contents of the file are hashed to check if the file changes.\nIf you change your config file, you'll need to trust it again.\n\nNote that global and system config files (e.g., `~/.config/mise/config.toml`) are implicitly trusted and exempt from this check. This allows paranoid mode to be enabled in a global config without requiring a trust prompt for that file itself.\n\n## Community plugins\n\nCommunity plugins can not be directly installed via short-name under paranoid.\nYou can install plugins that are either core, maintained by the mise team,\nor plugins that mise has marked as \"first-party\"—meaning plugins developed by\nthe same team that builds the tool the plugin installs.\n\nOther than that, say for \"shfmt\", you'll need to specify the full git repo\nto install:\n\n```sh\nmise plugin install shfmt https://github.com/luizm/asdf-shfmt\n```\n\nUnlike in normal mode where `mise plugin install shfmt` would be sufficient.\n\n## Always uses HTTPS\n\nSome endpoints in mise are fetched over HTTP such as checking for the latest mise\nversion and pulling version lists of tools. These are not security risks and a\nmalicious actor injecting false data would not introduce a security risk.\nNormally mise uses HTTP because loading the TLS module takes about 10ms and this\naffects commonly used commands so it is a noticeably delay.\nIn paranoid mode, all endpoints will be fetched over HTTPS.\n\n## More?\n\nIf you have suggestions for more that could be added to paranoid, please let\nme know.\n"
  },
  {
    "path": "docs/plugin-lua-modules.md",
    "content": "# Plugin Lua Modules\n\nmise plugins have access to a comprehensive set of built-in Lua modules that provide common functionality. These modules are available in both backend plugins and tool plugins, making it easy to perform common operations like HTTP requests, JSON parsing, file operations, and more.\n\n## Available Modules\n\n### Core Modules\n\n- **`cmd`** - Execute shell commands\n- **`json`** - Parse and generate JSON\n- **`http`** - Make HTTP requests and downloads\n- **`file`** - File system operations\n- **`env`** - Environment variable operations\n- **`strings`** - String manipulation utilities\n- **`semver`** - Semantic version comparison and sorting\n- **`html`** - HTML parsing and manipulation\n- **`archiver`** - Archive extraction\n- **`log`** - Structured logging\n\n## HTTP Module\n\nThe HTTP module provides functionality for making web requests and downloading files.\n\n### Basic HTTP Requests\n\n```lua\nlocal http = require(\"http\")\n\n-- GET request\nlocal resp, err = http.get({\n    url = \"https://api.github.com/repos/owner/repo/releases\",\n    headers = {\n        ['User-Agent'] = \"mise-plugin\",\n        ['Accept'] = \"application/json\"\n    }\n})\n\nif err ~= nil then\n    error(\"Request failed: \" .. err)\nend\n\nif resp.status_code ~= 200 then\n    error(\"HTTP error: \" .. resp.status_code)\nend\n\nlocal body = resp.body\n```\n\n### HEAD Requests\n\n```lua\nlocal http = require(\"http\")\n\n-- HEAD request to check file info\nlocal resp, err = http.head({\n    url = \"https://example.com/file.tar.gz\"\n})\n\nif err ~= nil then\n    error(\"HEAD request failed: \" .. err)\nend\n\nlocal content_length = resp.headers['content-length']\nlocal content_type = resp.headers['content-type']\n```\n\n### File Downloads\n\n```lua\nlocal http = require(\"http\")\n\n-- Download file\nlocal err = http.download_file({\n    url = \"https://github.com/owner/repo/archive/v1.0.0.tar.gz\",\n    headers = {\n        ['User-Agent'] = \"mise-plugin\"\n    }\n}, \"/path/to/download.tar.gz\")\n\nif err ~= nil then\n    error(\"Download failed: \" .. err)\nend\n```\n\n### Response Object\n\nHTTP responses contain the following fields:\n\n```lua\n{\n    status_code = 200,\n    headers = {\n        ['content-type'] = \"application/json\",\n        ['content-length'] = \"1234\"\n    },\n    body = \"response content\"\n}\n```\n\n## JSON Module\n\nThe JSON module provides encoding and decoding functionality.\n\n### Basic Usage\n\n```lua\nlocal json = require(\"json\")\n\n-- Encode table to JSON string\nlocal obj = {\n    name = \"mise-plugin\",\n    version = \"1.0.0\",\n    tools = {\"prettier\", \"eslint\"}\n}\nlocal jsonStr = json.encode(obj)\n-- Result: '{\"name\":\"mise-plugin\",\"version\":\"1.0.0\",\"tools\":[\"prettier\",\"eslint\"]}'\n\n-- Decode JSON string to table\nlocal decoded = json.decode(jsonStr)\nprint(decoded.name)  -- \"mise-plugin\"\nprint(decoded.tools[1])  -- \"prettier\"\n```\n\n### Error Handling (Lua)\n\n```lua\nlocal json = require(\"json\")\n\n-- Safe JSON parsing\nlocal success, result = pcall(json.decode, response_body)\nif not success then\n    error(\"Failed to parse JSON: \" .. result)\nend\n\n-- Use the parsed data\nfor _, item in ipairs(result) do\n    print(item.version)\nend\n```\n\n## Strings Module\n\nThe strings module provides various string manipulation utilities.\n\n### String Operations\n\n```lua\nlocal strings = require(\"strings\")\n\n-- Split string into parts\nlocal parts = strings.split(\"hello,world,test\", \",\")\nprint(parts[1])  -- \"hello\"\nprint(parts[2])  -- \"world\"\nprint(parts[3])  -- \"test\"\n\n-- Join strings\nlocal joined = strings.join({\"hello\", \"world\", \"test\"}, \" - \")\nprint(joined)  -- \"hello - world - test\"\n\n-- Trim whitespace\nlocal trimmed = strings.trim_space(\"  hello world  \")\nprint(trimmed)  -- \"hello world\"\n```\n\n### String Checks\n\n```lua\nlocal strings = require(\"strings\")\n\n-- Check prefixes and suffixes\nlocal text = \"hello world\"\nprint(strings.has_prefix(text, \"hello\"))  -- true\nprint(strings.has_suffix(text, \"world\"))  -- true\nprint(strings.contains(text, \"lo wo\"))    -- true\n\n-- Trim specific characters\nlocal trimmed = strings.trim(\"hello world\", \"world\")\nprint(trimmed)  -- \"hello \"\n```\n\n### Version String Utilities\n\n```lua\nlocal strings = require(\"strings\")\n\n-- Common version string operations\nlocal function normalize_version(version)\n    -- Remove 'v' prefix if present\n    version = strings.trim_prefix(version, \"v\")\n\n    -- Remove pre-release suffixes\n    local parts = strings.split(version, \"-\")\n    return parts[1]\nend\n\nlocal version = normalize_version(\"v1.2.3-beta.1\")  -- \"1.2.3\"\n```\n\n## Semver Module\n\nThe semver module provides semantic version comparison and sorting functionality. This is useful for sorting version lists returned by `Available()` hooks.\n\n### Version Comparison\n\n```lua\nlocal semver = require(\"semver\")\n\n-- Compare two versions\n-- Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2\nlocal result = semver.compare(\"1.2.3\", \"1.2.4\")  -- -1\nlocal result = semver.compare(\"2.0.0\", \"1.9.9\")  -- 1\nlocal result = semver.compare(\"1.0.0\", \"1.0.0\")  -- 0\n\n-- Handles numeric comparison correctly\nlocal result = semver.compare(\"9.6.9\", \"9.6.24\")   -- -1 (not lexicographic!)\nlocal result = semver.compare(\"10.0.0\", \"9.6.24\") -- 1\n```\n\n### Parse Version\n\n```lua\nlocal semver = require(\"semver\")\n\n-- Parse version string into numeric parts\nlocal parts = semver.parse(\"1.2.3\")\nprint(parts[1])  -- 1\nprint(parts[2])  -- 2\nprint(parts[3])  -- 3\n\n-- Works with prefixes and suffixes\nlocal parts = semver.parse(\"v1.2.3-beta\")  -- {1, 2, 3}\n```\n\n### Sort Version Strings\n\n```lua\nlocal semver = require(\"semver\")\n\n-- Sort array of version strings (ascending order)\nlocal versions = {\"1.10.0\", \"1.2.0\", \"1.9.0\", \"2.0.0\"}\nlocal sorted = semver.sort(versions)\n-- Result: {\"1.2.0\", \"1.9.0\", \"1.10.0\", \"2.0.0\"}\n```\n\n### Sort Tables by Version Field\n\n```lua\nlocal semver = require(\"semver\")\n\n-- Sort array of tables by a version field (ascending order)\nlocal releases = {\n    {version = \"1.10.0\", url = \"...\"},\n    {version = \"1.2.0\", url = \"...\"},\n    {version = \"1.9.0\", url = \"...\"},\n}\nlocal sorted = semver.sort_by(releases, \"version\")\n-- Result: sorted by version ascending\n```\n\n### Real-World Example: Available Hook\n\n```lua\nlocal http = require(\"http\")\nlocal semver = require(\"semver\")\n\nfunction PLUGIN:Available(ctx)\n    local resp, err = http.get({\n        url = \"https://example.com/releases/\"\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    local result = {}\n    -- Parse versions from response...\n    for version in string.gmatch(resp.body, 'v([0-9]+%.[0-9]+%.[0-9]+)') do\n        table.insert(result, {version = version})\n    end\n\n    -- Sort versions semantically (ascending order - oldest first)\n    return semver.sort_by(result, \"version\")\nend\n```\n\n### Using Compare in Custom Sort\n\n```lua\nlocal semver = require(\"semver\")\n\n-- Sort with custom comparator (descending order - newest first)\ntable.sort(versions, function(a, b)\n    return semver.compare(a.version, b.version) > 0\nend)\n\n-- Sort ascending (oldest first) - default for Available()\ntable.sort(versions, function(a, b)\n    return semver.compare(a.version, b.version) < 0\nend)\n```\n\n## HTML Module\n\nThe HTML module provides HTML parsing capabilities.\n\n### Basic HTML Parsing\n\n```lua\nlocal html = require(\"html\")\n\n-- Parse HTML document\nlocal doc = html.parse([[\n    <html>\n        <body>\n            <div id=\"version\" class=\"info\">1.2.3</div>\n            <ul class=\"downloads\">\n                <li><a href=\"/download/v1.2.3.tar.gz\">Source</a></li>\n                <li><a href=\"/download/v1.2.3.zip\">Windows</a></li>\n            </ul>\n        </body>\n    </html>\n]])\n\n-- Extract text content\nlocal version = doc:find(\"#version\"):text()  -- \"1.2.3\"\n\n-- Extract attributes\nlocal links = doc:find(\"a\")\nfor _, link in ipairs(links) do\n    local href = link:attr(\"href\")\n    local text = link:text()\n    print(text .. \": \" .. href)\nend\n```\n\n### CSS Selectors\n\n```lua\nlocal html = require(\"html\")\n\nlocal doc = html.parse(html_content)\n\n-- Find by ID\nlocal element = doc:find(\"#version\")\n\n-- Find by class\nlocal elements = doc:find(\".download-link\")\n\n-- Find by tag\nlocal links = doc:find(\"a\")\n\n-- Complex selectors\nlocal specific_links = doc:find(\"ul.downloads a[href$='.tar.gz']\")\n```\n\n### Real-World Example: Scraping Releases\n\n```lua\nlocal html = require(\"html\")\nlocal http = require(\"http\")\n\nfunction get_github_releases(owner, repo)\n    local resp, err = http.get({\n        url = \"https://github.com/\" .. owner .. \"/\" .. repo .. \"/releases\"\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch releases: \" .. err)\n    end\n\n    local doc = html.parse(resp.body)\n    local releases = {}\n\n    -- Find all release tags\n    local release_elements = doc:find(\"a[href*='/releases/tag/']\")\n    for _, element in ipairs(release_elements) do\n        local href = element:attr(\"href\")\n        local version = href:match(\"/releases/tag/(.+)\")\n        if version then\n            table.insert(releases, {\n                version = version,\n                url = \"https://github.com\" .. href\n            })\n        end\n    end\n\n    return releases\nend\n```\n\n## Archiver Module\n\nThe archiver module provides functionality for extracting compressed archives.\n\n### Supported Formats\n\n- **tar.gz** - Gzipped tar archives\n- **tar.xz** - XZ compressed tar archives\n- **tar.bz2** - Bzip2 compressed tar archives\n- **zip** - ZIP archives\n\n### Basic Extraction\n\n```lua\nlocal archiver = require(\"archiver\")\n\n-- Extract archive to directory\nlocal err = archiver.decompress(\"archive.tar.gz\", \"extracted/\")\nif err ~= nil then\n    error(\"Extraction failed: \" .. err)\nend\n\n-- Extract ZIP file\nlocal err = archiver.decompress(\"package.zip\", \"destination/\")\nif err ~= nil then\n    error(\"ZIP extraction failed: \" .. err)\nend\n```\n\n### Real-World Example: Plugin Installation\n\n```lua\nlocal archiver = require(\"archiver\")\nlocal http = require(\"http\")\n\nfunction install_from_archive(download_url, install_path)\n    -- Download the archive\n    local archive_path = install_path .. \"/download.tar.gz\"\n    local err = http.download_file({\n        url = download_url\n    }, archive_path)\n\n    if err ~= nil then\n        error(\"Download failed: \" .. err)\n    end\n\n    -- Extract to installation directory\n    local err = archiver.decompress(archive_path, install_path)\n    if err ~= nil then\n        error(\"Extraction failed: \" .. err)\n    end\n\n    -- Clean up archive\n    os.remove(archive_path)\nend\n```\n\n## File Module\n\nThe file module provides file system operations.\n\n### Path Joining\n\n```lua\nlocal file = require(\"file\")\n\n-- Join path segments using the OS-specific separator\nlocal full_path = file.join_path(\"/foo\", \"bar\", \"baz.txt\")\nprint(full_path)  -- On Unix: /foo/bar/baz.txt, on Windows: \\foo\\bar\\baz.txt\n```\n\nThe `file.join_path(...)` function joins any number of path segments using the correct separator for the current operating system. This is the recommended way to construct file paths in cross-platform plugins.\n\n### Read File Contents\n\n```lua\nlocal file = require(\"file\")\nprint(file.read(\"/path/to/file\"))\n```\n\n### Create Symbolic Links\n\n```lua\nlocal file = require(\"file\")\nfile.symlink(\"/path/to/source\", \"/path/to/new-symlink\")\n```\n\n### Check if file exists\n\n```lua\nlocal file = require(\"file\")\nif file.exists(\"important_file.txt\") then\n    print(\"File exists\")\nelse\n    print(\"File does not exist\")\nend\n```\n\n## Environment Module\n\nThe env module provides environment variable operations.\n\n### Set Environment Variable\n\n```lua\nlocal env = require(\"env\")\n\n-- Set environment variable\nenv.setenv(\"MY_VAR\", \"my_value\")\n```\n\n### Get Environment Variable\n\n> To read variables in Lua, use `os.getenv(\"MY_VAR\")`.\n\n### Path Operations\n\n```lua\nlocal env = require(\"env\")\n\n-- Get current PATH\nlocal current_path = os.getenv(\"PATH\")\n\n-- Add to PATH\nlocal new_path = \"/usr/local/bin:\" .. current_path\nenv.setenv(\"PATH\", new_path)\n\n-- Platform-specific PATH separator\nlocal separator = package.config:sub(1,1) == '\\\\' and \";\" or \":\"\nlocal paths = {\"/usr/local/bin\", \"/opt/bin\", current_path}\nenv.setenv(\"PATH\", table.concat(paths, separator))\n```\n\n## Command Module\n\nThe cmd module provides shell command execution.\n\n### Basic Command Execution\n\n```lua\nlocal cmd = require(\"cmd\")\n\n-- Execute command and get output\nlocal output = cmd.exec(\"ls -la\")\nprint(\"Directory listing:\", output)\n\n-- Execute command with error handling\nlocal success, output = pcall(cmd.exec, \"some-command\")\nif not success then\n    error(\"Command failed: \" .. output)\nend\n```\n\n### Command Execution with Options\n\n```lua\nlocal cmd = require(\"cmd\")\n\n-- Execute command in a specific directory\nlocal output = cmd.exec(\"pwd\", {cwd = \"/tmp\"})\nprint(\"Current directory:\", output)\n\n-- Execute command with custom environment variables\nlocal result = cmd.exec(\"echo $TEST_VAR\", {\n    cwd = \"/path/to/project\",\n    env = {TEST_VAR = \"hello\", NODE_ENV = \"production\"}\n})\n\n-- Install package in specific directory\nlocal result = cmd.exec(\"npm install package-name\", {cwd = \"/path/to/project\"})\n```\n\n### Available Options\n\nThe options table supports the following keys:\n\n- **`cwd`** (string): Set the working directory for the command\n- **`env`** (table): Set environment variables for the command execution. These are merged on top of the inherited environment (see below).\n- **`timeout`** (number): Set a timeout for command execution (future feature)\n\n### Environment Inheritance in Env Module Hooks\n\nWhen `cmd.exec()` is called from environment module hooks (`MiseEnv`, `MisePath`), the command automatically inherits the mise-constructed environment instead of the process environment. This includes environment variables set by preceding directives and `_.path` entries accumulated so far.\n\nWhen the module directive has `tools = true`, the inherited environment also includes tool installation bin paths. This means mise-managed tools are directly callable:\n\n```toml\n[env]\n_.my-plugin = { tools = true }\n```\n\n```lua\nfunction PLUGIN:MiseEnv(ctx)\n    -- With tools=true, mise-managed tools are on PATH\n    local version = cmd.exec(\"node --version\")\n    return {\n        {key = \"NODE_VERSION\", value = version:gsub(\"%s+\", \"\")}\n    }\nend\n```\n\nWithout `tools = true`, only `_.path` directive entries and the original system PATH are available to `cmd.exec()`.\n\nAny explicit `env` options passed to `cmd.exec()` are merged on top of the inherited environment, allowing selective overrides.\n\n### Platform-Specific Commands\n\n```lua\nlocal cmd = require(\"cmd\")\n\n-- Cross-platform command execution\nlocal function is_windows()\n    return package.config:sub(1,1) == '\\\\'\nend\n\nlocal function get_os_info()\n    if is_windows() then\n        return cmd.exec(\"systeminfo\")\n    else\n        return cmd.exec(\"uname -a\")\n    end\nend\n\nlocal os_info = get_os_info()\nprint(\"OS Info:\", os_info)\n```\n\n## Practical Examples\n\n### Version Fetching from API\n\n```lua\nlocal http = require(\"http\")\nlocal json = require(\"json\")\n\nfunction fetch_npm_versions(package_name)\n    local resp, err = http.get({\n        url = \"https://registry.npmjs.org/\" .. package_name,\n        headers = {\n            ['User-Agent'] = \"mise-plugin\"\n        }\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch package info: \" .. err)\n    end\n\n    local package_info = json.decode(resp.body)\n    local versions = {}\n\n    for version, _ in pairs(package_info.versions) do\n        table.insert(versions, version)\n    end\n\n    -- Sort versions (simple string sort)\n    table.sort(versions)\n\n    return versions\nend\n```\n\n### File Download with Progress\n\n```lua\nlocal http = require(\"http\")\nlocal file = require(\"file\")\n\nfunction download_with_verification(url, dest_path, expected_sha256)\n    -- Download file\n    local err = http.download_file({\n        url = url,\n        headers = {\n            ['User-Agent'] = \"mise-plugin\"\n        }\n    }, dest_path)\n\n    if err ~= nil then\n        error(\"Download failed: \" .. err)\n    end\n\n    -- Verify file exists\n    if not file.exists(dest_path) then\n        error(\"Downloaded file not found\")\n    end\n\n    -- Note: SHA256 verification would need additional implementation\n    -- This is a simplified example\n    print(\"Downloaded successfully to: \" .. dest_path)\nend\n```\n\n### Configuration File Parsing\n\n```lua\nlocal file = require(\"file\")\nlocal json = require(\"json\")\nlocal strings = require(\"strings\")\n\nfunction parse_config_file(config_path)\n    if not file.exists(config_path) then\n        return {}  -- Return empty config\n    end\n\n    local content = file.read(config_path)\n    if not content then\n        error(\"Failed to read config file: \" .. config_path)\n    end\n\n    -- Trim whitespace\n    content = strings.trim_space(content)\n\n    -- Parse JSON\n    local success, config = pcall(json.decode, content)\n    if not success then\n        error(\"Invalid JSON in config file: \" .. config_path)\n    end\n\n    return config\nend\n```\n\n### Web Scraping for Versions\n\n```lua\nlocal http = require(\"http\")\nlocal html = require(\"html\")\nlocal strings = require(\"strings\")\n\nfunction scrape_versions_from_releases(base_url)\n    local resp, err = http.get({\n        url = base_url .. \"/releases\"\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch releases page: \" .. err)\n    end\n\n    local doc = html.parse(resp.body)\n    local versions = {}\n\n    -- Find version tags\n    local version_elements = doc:find(\"h2 a[href*='/releases/tag/']\")\n    for _, element in ipairs(version_elements) do\n        local version_text = element:text()\n        local version = strings.trim_space(version_text)\n\n        -- Remove 'v' prefix if present\n        version = strings.trim_prefix(version, \"v\")\n\n        if version and version ~= \"\" then\n            table.insert(versions, {\n                version = version,\n                url = base_url .. element:attr(\"href\")\n            })\n        end\n    end\n\n    return versions\nend\n```\n\n## Log Module\n\nThe log module provides structured logging that routes through Rust's `log` crate, respecting `MISE_DEBUG` and `MISE_TRACE` environment variables.\n\n### Log Levels\n\n```lua\nlocal log = require(\"log\")\n\nlog.trace(\"detailed tracing info\")   -- only visible with MISE_TRACE=1\nlog.debug(\"debugging info\")          -- visible with MISE_DEBUG=1\nlog.info(\"status message\")           -- visible by default\nlog.warn(\"warning message\")          -- visible by default\nlog.error(\"error message\")           -- visible by default\n```\n\n### Variadic Arguments\n\nAll log functions accept multiple arguments of any type. Arguments are converted to strings via `tostring()` and joined with tab characters (`\\t`), matching Lua's `print()` behavior:\n\n```lua\nlog.info(\"version\", version, \"installed to\", path)\n-- Output: [plugin-name] version<TAB>1.0.0<TAB>installed to<TAB>/path\n```\n\n### Plugin Name Prefix\n\nAll log messages are automatically prefixed with `[plugin_name]`:\n\n```\nmise [INFO] [my-plugin] Installing version 1.0.0\n```\n\n### Print Override\n\n`print()` is overridden to route through `info!()` level logging. This means:\n\n- `print()` output goes to stderr instead of stdout\n- Messages are prefixed with `[plugin_name]`\n- Output respects log level filtering\n\n```lua\n-- These are equivalent:\nprint(\"hello\", \"world\")\nlog.info(\"hello\", \"world\")\n```\n\n### Accessing via vfox Namespace\n\nThe log module is also available as `vfox.log`:\n\n```lua\nlocal log = require(\"vfox\").log\nlog.info(\"message\")\n```\n\n## Best Practices\n\n### Error Handling\n\nAlways handle errors gracefully:\n\n```lua\nlocal http = require(\"http\")\nlocal json = require(\"json\")\n\nfunction safe_api_call(url)\n    local resp, err = http.get({url = url})\n\n    if err ~= nil then\n        error(\"HTTP request failed: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"API returned error: \" .. resp.status_code .. \" \" .. resp.body)\n    end\n\n    local success, data = pcall(json.decode, resp.body)\n    if not success then\n        error(\"Failed to parse JSON response: \" .. data)\n    end\n\n    return data\nend\n```\n\n### Caching\n\nImplement caching for expensive operations:\n\n```lua\nlocal cache = {}\nlocal cache_ttl = 3600  -- 1 hour\n\nfunction cached_http_get(url)\n    local now = os.time()\n    local cache_key = url\n\n    -- Check cache\n    if cache[cache_key] and (now - cache[cache_key].timestamp) < cache_ttl then\n        return cache[cache_key].data\n    end\n\n    -- Fetch fresh data\n    local http = require(\"http\")\n    local resp, err = http.get({url = url})\n\n    if err ~= nil then\n        error(\"HTTP request failed: \" .. err)\n    end\n\n    -- Cache the result\n    cache[cache_key] = {\n        data = resp,\n        timestamp = now\n    }\n\n    return resp\nend\n```\n\n### Platform Detection\n\nHandle cross-platform differences:\n\n```lua\nlocal function get_platform_info()\n    local is_windows = package.config:sub(1,1) == '\\\\'\n    local cmd = require(\"cmd\")\n\n    if is_windows then\n        return {\n            os = \"windows\",\n            arch = os.getenv(\"PROCESSOR_ARCHITECTURE\") or \"x64\",\n            path_sep = \"\\\\\",\n            env_sep = \";\"\n        }\n    else\n        local uname = cmd.exec(\"uname -s\"):lower()\n        local arch = cmd.exec(\"uname -m\")\n\n        return {\n            os = uname,\n            arch = arch,\n            path_sep = \"/\",\n            env_sep = \":\"\n        }\n    end\nend\n```\n\n## Next Steps\n\n- [Backend Plugin Development](backend-plugin-development.md)\n- [Tool Plugin Development](tool-plugin-development.md)\n- [Publishing your plugin](plugin-publishing.md)\n"
  },
  {
    "path": "docs/plugin-publishing.md",
    "content": "# Plugin Publishing\n\nThis guide shows how to publish and distribute your plugins, whether they are backend plugins or tool plugins. Publishing makes your plugins available to other users and ensures they can be easily installed and maintained.\n\n## Publishing Checklist\n\nBefore publishing your plugin, ensure you have:\n\n### Essential Files\n\n- **`metadata.lua`** - Plugin metadata with name, version, description, and author\n- **Plugin implementation** - Either backend methods or hook functions\n- **Test coverage** - Automated tests to verify functionality\n\n### Optional but Recommended\n\n- **`README.md`** - Basic usage instructions and examples\n- **`test/`** directory - Test scripts for verification\n- **Version control** - Git repository with proper versioning\n\n## Repository Setup\n\n### 1. Initialize Repository\n\nThe easiest way to start is with the [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template):\n\n```bash\n# Clone the template\ngit clone https://github.com/jdx/mise-tool-plugin-template my-plugin\ncd my-plugin\n\n# Remove template history and set up your own repository\nrm -rf .git\ngit init\ngit remote add origin https://github.com/username/my-plugin.git\n\n# Customize for your plugin\n# Edit metadata.lua, hooks/*.lua, README.md, etc.\n```\n\nAlternatively, create a repository from scratch:\n\n```bash\n# Create plugin directory\nmkdir my-plugin\ncd my-plugin\n\n# Initialize git repository\ngit init\ngit remote add origin https://github.com/username/my-plugin.git\n\n# Create initial structure\ntouch metadata.lua\nmkdir -p test\necho \"# My Plugin\" > README.md\n```\n\n### 2. Basic Directory Structure\n\nOrganize your plugin with this structure:\n\n```\nmy-plugin/\n├── metadata.lua          # Plugin metadata\n├── README.md            # Basic documentation\n├── test/                # Test scripts\n│   └── test.sh\n├── .gitignore           # Git ignore rules\n└── [implementation files]\n```\n\nFor backend plugins:\n\n```\nbackend-plugin/\n├── metadata.lua          # Backend methods implementation\n├── README.md\n└── test/\n    └── test.sh\n```\n\nFor tool plugins:\n\n```\ntool-plugin/\n├── metadata.lua          # Plugin metadata\n├── hooks/               # Hook implementations\n│   ├── available.lua\n│   ├── pre_install.lua\n│   └── env_keys.lua\n├── lib/                 # Helper libraries\n│   └── helper.lua\n├── README.md\n└── test/\n    └── test.sh\n```\n\n### 3. Git Ignore Configuration\n\nCreate a `.gitignore` file:\n\n```gitignore\n# Temporary files\n*.tmp\n*.temp\n.DS_Store\nThumbs.db\n\n# Test artifacts\ntest/tmp/\ntest/output/\n\n# IDE files\n.vscode/\n.idea/\n*.swp\n*.swo\n\n# OS files\n*.log\n```\n\n## Versioning Strategy\n\n### Semantic Versioning\n\nUse semantic versioning (SemVer) for your plugin releases:\n\n- **Major version** (1.0.0 → 2.0.0): Breaking changes\n- **Minor version** (1.0.0 → 1.1.0): New features, backward compatible\n- **Patch version** (1.0.0 → 1.0.1): Bug fixes, backward compatible\n\n### Version Management\n\nUpdate version in `metadata.lua`:\n\n```lua\nPLUGIN = {\n    name = \"my-plugin\",\n    version = \"1.2.3\",  -- Update this for each release\n    description = \"My awesome plugin\",\n    author = \"Your Name\"\n}\n```\n\nCreate git tags for releases:\n\n```bash\n# Tag the current commit\ngit tag -a v1.2.3 -m \"Release version 1.2.3\"\n\n# Push tags to repository\ngit push origin --tags\n```\n\n## Testing Before Publication\n\n### Automated Testing\n\nCreate comprehensive test scripts:\n\n```bash\n#!/bin/bash\n# test/test.sh\nset -e\n\necho \"Testing plugin functionality...\"\n\n# Install plugin locally\nmise plugin install my-plugin .\n\n# Test basic functionality\nif [[ \"$(mise ls-remote my-plugin)\" == \"\" ]]; then\n    echo \"ERROR: No versions available\"\n    exit 1\nfi\n\n# Test installation\nmise install my-plugin@latest\n\n# Test execution\nmise exec my-plugin:tool -- --version\n\n# Clean up\nmise plugin remove my-plugin\n\necho \"All tests passed!\"\n```\n\n### Manual Testing\n\nTest your plugin manually:\n\n```bash\n# Link for development\nmise plugin link my-plugin /path/to/plugin\n\n# Test all functionality\nmise ls-remote my-plugin\nmise install my-plugin@latest\nmise use my-plugin@latest\n\n# Test in different environments\ndocker run --rm -it ubuntu:latest bash -c \"\n    curl -fsSL https://mise.jdx.dev/install.sh | sh\n    mise plugin install my-plugin https://github.com/username/my-plugin\n    mise install my-plugin@latest\n\"\n```\n\n## Publishing Process\n\n### 1. Prepare for Release\n\nBefore publishing, ensure everything is ready:\n\n```bash\n# Run tests\n./test/test.sh\n\n# Check git status\ngit status\n\n# Update version in metadata.lua\nvim metadata.lua\n\n# Commit changes\ngit add .\ngit commit -m \"Prepare release v1.2.3\"\n```\n\n### 2. Create Release\n\nCreate a tagged release:\n\n```bash\n# Create and push tag\ngit tag -a v1.2.3 -m \"Release version 1.2.3\"\ngit push origin v1.2.3\ngit push origin main\n```\n\n### 3. GitHub Releases (Recommended)\n\nCreate a GitHub release for better discoverability:\n\n1. Go to your repository on GitHub\n2. Click \"Releases\" → \"Create a new release\"\n3. Choose your tag (v1.2.3)\n4. Write release notes describing changes\n5. Publish the release\n\n### 4. Release Notes Template\n\n```markdown\n## Changes in v1.2.3\n\n### Added\n\n- New feature X\n- Support for Y\n\n### Changed\n\n- Improved performance of Z\n- Updated dependencies\n\n### Fixed\n\n- Fixed issue with A\n- Resolved bug in B\n\n### Installation\n\n```bash\nmise plugin install my-plugin https://github.com/username/my-plugin\n```\n```\n\n## Distribution Methods\n\n### 1. Direct Git Installation\n\nUsers can install directly from your repository:\n\n```bash\n# Install from GitHub\nmise plugin install my-plugin https://github.com/username/my-plugin\n\n# Install specific version\nmise plugin install my-plugin https://github.com/username/my-plugin@v1.2.3\n\n# Install from other Git providers\nmise plugin install my-plugin https://gitlab.com/username/my-plugin\n```\n\n### 2. Private Repository Access\n\nFor private repositories, users need access:\n\n```bash\n# SSH access (recommended)\nmise plugin install my-plugin git@github.com:username/private-plugin.git\n\n# HTTPS with token\nmise plugin install my-plugin https://username:token@github.com/username/private-plugin.git\n```\n\n### 3. Archive Distribution\n\nYou can also distribute as archives:\n\n```bash\n# Create release archive\ngit archive --format=zip --output=my-plugin-v1.2.3.zip v1.2.3\n\n# Users can install from archive\nmise plugin install my-plugin https://github.com/username/my-plugin/releases/download/v1.2.3/my-plugin-v1.2.3.zip\n```\n\n## Maintenance and Updates\n\n### 1. Update Workflow\n\nEstablish a regular update process:\n\n```bash\n# Development workflow\ngit checkout -b feature/new-feature\n# ... make changes ...\ngit commit -m \"Add new feature\"\ngit push origin feature/new-feature\n\n# After review and merge\ngit checkout main\ngit pull origin main\ngit tag -a v1.3.0 -m \"Release v1.3.0\"\ngit push origin v1.3.0\n```\n\n### 2. Backward Compatibility\n\nMaintain backward compatibility when possible:\n\n- Keep existing plugin interface unchanged\n- Add new features as optional\n- Deprecate old features gradually\n- Document breaking changes clearly\n\n### 3. User Communication\n\nKeep users informed about updates:\n\n- Use clear release notes\n- Announce major changes\n- Provide migration guides for breaking changes\n- Maintain documentation\n\n## Security Considerations\n\n### 1. Code Review\n\n- Review all code changes before publishing\n- Check for security vulnerabilities\n- Validate external dependencies\n- Test with untrusted inputs\n\n### 2. Dependency Management\n\n- Pin dependency versions where possible\n- Regularly update dependencies\n- Monitor for security advisories\n- Use trusted sources only\n\n### 3. Access Control\n\n- Limit repository access appropriately\n- Use strong authentication\n- Regularly audit access permissions\n- Consider signed releases for sensitive plugins\n\n## Best Practices\n\n### 1. Documentation\n\n- Keep README.md concise but complete\n- Include usage examples\n- Document configuration options\n- Provide troubleshooting guide\n\n### 2. Testing\n\n- Test on multiple platforms\n- Include edge cases\n- Test upgrade scenarios\n- Automate testing where possible\n\n### 3. Community\n\n- Respond to issues promptly\n- Accept contributions gracefully\n- Maintain consistent code style\n- Be helpful and respectful\n\n### 4. Release Management\n\n- Follow semantic versioning\n- Create clear release notes\n- Test releases thoroughly\n- Maintain stable branches\n\n## Troubleshooting\n\n### Common Issues\n\n**Plugin not installing:**\n\n```bash\n# Check repository URL\ngit clone https://github.com/username/my-plugin.git\n\n# Verify metadata.lua exists\nls -la my-plugin/metadata.lua\n\n# Test locally\nmise plugin link my-plugin ./my-plugin\n```\n\n**Version conflicts:**\n\n```bash\n# Check version in metadata.lua\ngrep version my-plugin/metadata.lua\n\n# Verify git tags\ngit tag -l\n```\n\n**Permission issues:**\n\n```bash\n# Check repository permissions\ngit ls-remote https://github.com/username/my-plugin.git\n\n# For private repos, verify access\nssh -T git@github.com\n```\n\n## Next Steps\n\n- [Backend Plugin Development](backend-plugin-development.md)\n- [Tool Plugin Development](tool-plugin-development.md)\n- [Plugin Lua Modules](plugin-lua-modules.md)\n\n## Examples\n\n### Simple Backend Plugin Release\n\n```bash\n# 1. Prepare plugin\ncd my-backend-plugin\necho \"Updated backend methods\" > metadata.lua\n\n# 2. Test locally\nmise plugin link my-plugin .\nmise ls-remote my-plugin:tool\n\n# 3. Release\ngit add .\ngit commit -m \"v1.0.0: Initial release\"\ngit tag -a v1.0.0 -m \"Initial release\"\ngit push origin v1.0.0\n```\n\n### Tool Plugin with Hooks\n\n```bash\n# 1. Prepare plugin\ncd my-tool-plugin\n./test/test.sh  # Run tests\n\n# 2. Update version\nsed -i 's/version = \"1.0.0\"/version = \"1.1.0\"/' metadata.lua\n\n# 3. Release\ngit add .\ngit commit -m \"v1.1.0: Add new hook functionality\"\ngit tag -a v1.1.0 -m \"Add new hook functionality\"\ngit push origin v1.1.0\n```\n"
  },
  {
    "path": "docs/plugin-usage.md",
    "content": "# Using Plugins\n\nmise supports plugins that extend its functionality, allowing you to install tools that aren't available in the standard registry. This is particularly useful for:\n\n- Installing tools from private repositories\n- Using experimental or niche tools\n- Creating custom tool installations for your team\n\n## What Are Plugins?\n\nPlugins are extensions that can install and manage tools not included in mise's built-in registry. They are written in Lua and come in two main types:\n\n### Backend Plugins\n\nBackend plugins use enhanced backend methods and support the `plugin:tool` format:\n\n- **Multiple Tools**: A single plugin can manage multiple tools\n- **Enhanced Methods**: Backend methods for listing, installing, and environment setup\n- **Format**: Use the `plugin:tool` format (e.g., `vfox-npm:prettier`)\n\n### Tool Plugins\n\nTool plugins use the traditional hook-based approach:\n\n- **Single Tool**: Each plugin manages one tool\n- **Hook-based**: Use hooks like `PreInstall`, `PostInstall`, `Available`, etc.\n- **Format**: Use the tool name directly (e.g., `my-tool`)\n\nBoth types:\n\n- Install tools from any source (npm packages, GitHub releases, custom builds)\n- Set up environment variables and PATH entries\n- Handle version management and listing\n- Work across all platforms (Windows, macOS, Linux)\n\n## Installing Plugins\n\n### From a Git Repository\n\n```bash\n# Install a plugin from a repository\nmise plugin install <plugin-name> <repository-url>\n\n# Example: Installing the vfox-npm plugin\nmise plugin install vfox-npm https://github.com/jdx/vfox-npm\n```\n\n### From Zip File\n\n```bash\n# Install a plugin from a zip file over HTTPS\nmise plugin install <plugin-name> <zip-url>\n\n# Example: Installing a plugin from a zip file\nmise plugin install tiny https://github.com/mise-plugins/mise-tiny.git\n```\n\n### From Local Directory\n\n```bash\n# Link a local plugin for development\nmise plugin link <plugin-name> /path/to/plugin/directory\n```\n\n## Using Plugins (Advanced)\n\nOnce a plugin is installed, you can use it with the `plugin:tool` format:\n\n```bash\n# Install a specific tool using the plugin\nmise install vfox-npm:prettier@latest\n\n# Use the tool\nmise use vfox-npm:prettier@3.0.0\n\n# Execute the tool\nmise exec vfox-npm:prettier -- --version\n\n# List available versions\nmise ls-remote vfox-npm:prettier\n```\n\n## Plugin:Tool Format\n\nThe `plugin:tool` format allows a single plugin to manage multiple tools. This is particularly useful for:\n\n- **Package managers**: Install different npm packages, Python packages, etc.\n- **Tool families**: Manage related tools from the same ecosystem\n- **Custom builds**: Install different variants of the same tool\n\n### Example: npm packages\n\n```bash\n# Install different npm packages using the same plugin\nmise install vfox-npm:prettier@latest\nmise install vfox-npm:eslint@8.0.0\nmise install vfox-npm:typescript@latest\n\n# Use them in your project\nmise use vfox-npm:prettier@latest vfox-npm:eslint@8.0.0\n```\n\n## Managing Plugins\n\n### List installed plugins\n\n```bash\n# Show all plugins\nmise plugins ls\n\n# Show plugin URLs\nmise plugins ls --urls\n```\n\n### Update plugins\n\n```bash\n# Update a specific plugin\nmise plugin update vfox-npm\n\n# Update all plugins\nmise plugin update --all\n```\n\n### Remove plugins\n\n```bash\n# Remove a plugin\nmise plugin remove vfox-npm\n\n# This will also remove all tools installed by the plugin\n```\n\n## Configuration\n\nPlugins can be configured in your `mise.toml` file:\n\n```toml\n[plugins]\nvfox-npm = \"https://github.com/jdx/vfox-npm\"\n\n[tools]\n\"vfox-npm:prettier\" = \"latest\"\n\"vfox-npm:eslint\" = \"8.0.0\"\n```\n\n## Finding Plugins\n\nWhile mise doesn't have a centralized registry for community plugins, you can find them:\n\n- **GitHub**: Search for repositories with \"vfox-\" prefix\n- **Community**: Check mise community discussions and Discord\n- **Company internal**: Your organization may have private plugins\n\n## Plugin Examples\n\n### vfox-npm (Example Plugin)\n\nThe `vfox-npm` plugin demonstrates how to create a plugin that installs npm packages:\n\n```bash\n# Install the plugin\nmise plugin install vfox-npm https://github.com/jdx/vfox-npm\n\n# Install tools\nmise install vfox-npm:prettier@latest\nmise install vfox-npm:eslint@latest\n\n# Use them\nmise use vfox-npm:prettier@latest\nmise exec vfox-npm:prettier -- --check .\n```\n\n::: info\nThis is just an example plugin for testing. mise already has built-in npm support that you should use instead: `mise install npm:prettier@latest`\n:::\n\n## Backend Plugins (Advanced)\n\nBackend plugins use enhanced backend methods that provide better performance and support for the `plugin:tool` format:\n\n- **BackendListVersions**: Lists available versions of a tool\n- **BackendInstall**: Installs a specific version\n- **BackendExecEnv**: Sets up environment variables\n\nThis architecture allows plugins to manage multiple tools efficiently while providing a consistent interface.\n\n## Tool Plugins (Advanced)\n\nTool plugins use the traditional hook-based approach:\n\n- **Available**: Lists available versions\n- **PreInstall/PostInstall**: Installation hooks\n- **EnvKeys**: Environment variable setup\n- **Parse**: Version parsing and validation\n\nBoth architectures provide a flexible plugin system that can handle diverse installation and management needs.\n\n## Security Considerations\n\n::: danger\nWhen using plugins, be aware that:\n\n- **Plugins execute arbitrary code** during installation and use\n- **Only install plugins from trusted sources**\n- **Review plugin code** before installation when possible\n- **Use version pinning** to avoid unexpected updates like [`mise.lock`](/dev-tools/mise-lock.md)\n:::\n\n## Troubleshooting\n\n### Plugin installation fails\n\n```bash\n# Check if the repository URL is correct\nmise plugin install vfox-npm https://github.com/jdx/vfox-npm\n\n# Check plugin directory\nls ~/.local/share/mise/plugins/\n```\n\n### Tool installation fails\n\n```bash\n# Check plugin logs\nmise install vfox-npm:prettier@latest --verbose\n\n# Verify plugin is installed\nmise plugins ls\n```\n\n### Environment issues\n\n```bash\n# Check if PATH is set correctly\nmise exec vfox-npm:prettier env | grep PATH\n\n# Verify tool is installed\nls ~/.local/share/mise/installs/vfox-npm/prettier/\n```\n\n## Next Steps\n\n- [Learn how to create backend plugins](backend-plugin-development.md)\n- [Learn how to create tool plugins](tool-plugin-development.md)\n- [Explore built-in backends](dev-tools/backends/)\n- [Check the community registry](registry.md)\n"
  },
  {
    "path": "docs/plugins.md",
    "content": "# Plugins\n\nPlugins in mise are a way to extend `mise` with new functionality like extra tools or environment variable management.\n\nHistorically it was the only way to add new tools (as the only backend was [asdf](/dev-tools/backends/asdf.html)).\n\nThe way that backend works is every tool has its own plugin which needs to be manually installed. However, now with [core tools](/core-tools.html)\nand backends like [aqua](/dev-tools/backends/aqua.html)/[github](/dev-tools/backends/github.html), plugins are no longer necessary to run most tools in mise.\n\nTool plugins should be avoided for security reasons. New tools will not be accepted into mise built with asdf/plugins unless they are very popular and\naqua/github is not an option for some reason.\n\nThe only exception is if the tool needs to set env vars or has a complex installation process, as plugins can provide functionality like [setting env vars globally](/environments/#plugin-provided-env-directives) without relying on a tool being installed. They can also provide [aliases for versions](/dev-tools/aliases.html#aliased-versions).\n\nIf you want to integrate a new tool into mise, you should either try to get it into the [aqua registry](https://mise.jdx.dev/dev-tools/backends/aqua.html)\nor see if it can be installed with [github](https://mise.jdx.dev/dev-tools/backends/github.html). Then add it to the [registry](https://github.com/jdx/mise/blob/main/registry/).\nAqua is definitely preferred to github as it has better UX and more features like slsa verification and the ability to use different logic for older versions.\n\nYou can manage all installed plugins in `mise` with [`mise plugins`](/cli/plugins.html).\n\n```shell\nmise plugins ls --urls\n# Plugin                          Url                                                     Ref  Sha\n# 1password                       https://github.com/mise-plugins/mise-1password-cli.git  HEAD f5d5aab\n# vfox-mise-plugins-vfox-dart     https://github.com/mise-plugins/vfox-dart               HEAD 1424253\n# ...\n```\n\n## Backend Plugins\n\nBackend plugins provide enhanced functionality with modern backend methods. These plugins use the `plugin:tool` format and offer advantages over traditional plugins:\n\n- **Multiple Tools**: A single plugin can manage multiple tools\n- **Enhanced Methods**: Backend methods for listing versions, installing, and setting environment variables\n- **Cross-platform**: Work on Windows, macOS, and Linux\n- **Performance**: Faster execution than shell-based plugins\n\nExample usage:\n\n```bash\n# Install a backend plugin\nmise plugin install my-plugin https://github.com/username/my-plugin\n\n# Use the plugin:tool format\nmise install my-plugin:some-tool@1.0.0\nmise use my-plugin:some-tool@latest\n```\n\nSee [Backend Plugin Development](backend-plugin-development.md) for creating backend plugins. You can start quickly with the [mise-backend-plugin-template](https://github.com/jdx/mise-backend-plugin-template).\n\n## Tool Plugins\n\nTool plugins use the traditional hook-based approach with Lua scripts. These plugins provide:\n\n- **Hook-based**: Use hooks like `PreInstall`, `PostInstall`, `Available`, etc.\n- **Single Tool**: Each plugin manages one tool\n- **Cross-platform**: Work on Windows, macOS, and Linux\n- **Flexible**: Full control over installation and environment setup\n\nExample usage:\n\n```bash\n# Install a tool plugin\nmise plugin install my-tool https://github.com/username/my-tool-plugin\n\n# Use the tool directly\nmise install my-tool@1.0.0\nmise use my-tool@latest\n```\n\nSee [Tool Plugin Development](tool-plugin-development.md) for creating tool plugins. The [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template) provides a ready-to-use starting point.\n\n## Environment Plugins\n\nEnvironment plugins provide environment variables and PATH modifications without managing tool versions. They're ideal for integrating with secret managers, setting dynamic configurations, and standardizing team environments.\n\nExample usage:\n\n```bash\n# Install an environment plugin\nmise plugin install my-env-plugin https://github.com/username/my-env-plugin\n```\n\n```toml\n# Configure in mise.toml\n[env]\n_.my-env-plugin = { api_url = \"https://api.example.com\", debug = true }\n```\n\nUnlike tool plugins, environment plugins:\n\n- Only implement environment hooks (`MiseEnv`, `MisePath`)\n- Are activated via `env._.<plugin-name>` syntax\n- Don't manage tool versions or installations\n\nSee [Environment Plugin Development](env-plugin-development.md) for creating environment plugins. The [mise-env-plugin-template](https://github.com/jdx/mise-env-plugin-template) repository provides a ready-to-use starting point.\n\n## General Plugin Usage\n\nFor end-user documentation on installing and using both backend and tool plugins, see [Using Plugins](plugin-usage.md).\n\n## asdf (Legacy) Plugins\n\nmise can use asdf's plugin ecosystem under the hood for backward compatibility. These plugins contain shell scripts like\n`bin/install` (for installing) and `bin/list-all` (for listing all of the available versions).\n\nasdf plugins have limitations compared to modern backends and should only be used when necessary. They only work on Linux/macOS and are slower than native backends.\n\nSee [asdf (Legacy) Plugins](asdf-legacy-plugins.md) for comprehensive documentation on using and creating these plugins.\n\n## Plugin Authors\n\n<https://github.com/mise-plugins> is a GitHub organization for community-developed plugins.\nSee [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md) for more details on how plugins here are treated differently.\n\nIf you'd like your plugin to be hosted here please let me know (GH discussion or discord is fine)\nand I'd be happy to host it for you.\n\n## Tool Options\n\nmise has support for \"tool options\" which is configuration specified in `mise.toml` to change behavior\nof tools. One example of this is virtualenv on python runtimes:\n\n```toml\n[tools]\npython = { version='3.11', virtualenv='.venv' }\n```\n\nThis will be passed to all plugin scripts as `MISE_TOOL_OPTS__VIRTUALENV=.venv`. The user can specify\nany option, and it will be passed to the plugin in that format.\n\nCurrently, this only supports simple strings, but we can make it compatible with more complex types\n(arrays, tables) fairly easily if there is a need for it.\n\n## Templates\n\nPlugin custom repository values can be templates, see [Templates](/templates) for details.\n\n```toml\n[plugins]\n\"vfox-backend:my-plugin\" = \"https://{{ get_env(name='GIT_USR', default='empty') }}:{{ get_env(name='GIT_PWD', default='empty') }}@github.com/foo/my-plugin.git\"\n```\n"
  },
  {
    "path": "docs/public/site.webmanifest",
    "content": "{\n  \"name\": \"mise-en-place\",\n  \"short_name\": \"mise\",\n  \"description\": \"The front-end to your dev env\",\n  \"icons\": [\n    {\n      \"src\": \"/logo.svg\",\n      \"sizes\": \"any\",\n      \"type\": \"image/svg+xml\",\n      \"purpose\": \"any maskable\"\n    },\n    {\n      \"src\": \"/android-chrome-192x192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"/android-chrome-512x512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    }\n  ],\n  \"theme_color\": \"#8B2252\",\n  \"background_color\": \"#FDF8F3\",\n  \"display\": \"standalone\"\n}\n"
  },
  {
    "path": "docs/registry.data.ts",
    "content": "import * as fs from \"node:fs\";\nimport { load } from \"js-toml\";\n\ntype Registry = {\n  tools: Record<\n    string,\n    {\n      aliases?: string[];\n      backends: (\n        | string\n        | {\n            full: string;\n            platforms?: string[];\n            options?: Record<string, string>;\n          }\n      )[];\n      os?: string[];\n    }\n  >;\n};\n\ntype Tool = {\n  short: string;\n  backends: { name: string; url: string }[];\n  aliases: string[];\n  os: string[];\n};\n\nexport default {\n  watch: [\"./registry\"],\n  load() {\n    const registryDir = \"./registry\";\n    const files = fs\n      .readdirSync(registryDir)\n      .filter((f) => f.endsWith(\".toml\"))\n      .sort();\n\n    const tools: Registry[\"tools\"] = {};\n    for (const file of files) {\n      const toolName = file.replace(/\\.toml$/, \"\");\n      const raw = fs.readFileSync(`${registryDir}/${file}`, \"utf-8\");\n      const toolInfo = load(raw) as Registry[\"tools\"][string];\n      tools[toolName] = toolInfo;\n    }\n\n    const registry: Record<string, Tool> = {};\n\n    const urlBuilders: Record<\n      string,\n      (slug: string, options: Record<string, string>) => string\n    > = {\n      aqua: (slug) => {\n        const repoName = slug.split(\"/\").slice(0, 2).join(\"/\");\n        return `https://github.com/${repoName}`;\n      },\n      asdf: (slug) =>\n        slug.startsWith(\"http\") ? slug : `https://github.com/${slug}`,\n      conda: (slug, options) =>\n        `https://anaconda.org/${options.channel ?? \"conda-forge\"}/${slug}`,\n      cargo: (slug) => `https://crates.io/crates/${slug}`,\n      core: (slug) => `https://mise.jdx.dev/lang/${slug}.html`,\n      dotnet: (slug) => `https://www.nuget.org/packages/${slug}`,\n      gem: (slug) => `https://rubygems.org/gems/${slug}`,\n      github: (slug) => `https://github.com/${slug}`,\n      gitlab: (slug) => `https://gitlab.com/${slug}`,\n      go: (slug) => `https://pkg.go.dev/${slug}`,\n      npm: (slug) => `https://www.npmjs.com/package/${slug}`,\n      pipx: (slug) => `https://pypi.org/project/${slug}`,\n      spm: (slug, options) =>\n        slug.startsWith(\"http\")\n          ? slug\n          : `https://${options.provider == \"gitlab\" ? \"gitlab.com\" : \"github.com\"}/${slug}`,\n      http: () => \"\",\n      ubi: (slug, options) => {\n        const repoName = slug.split(\"/\").slice(0, 2).join(\"/\");\n        return `https://${\n          options.provider === \"gitlab\" ? \"gitlab.com\" : \"github.com\"\n        }/${repoName}`;\n      },\n      vfox: (slug) => `https://github.com/${slug}`,\n    };\n\n    const nameRegex = /^(?<prefix>.+?):(?<slug>.+?)(?:\\[(?<options>.+)\\])?$/;\n\n    for (const key in tools) {\n      const tool = tools[key];\n\n      registry[key] = {\n        short: key,\n        backends: tool.backends.map((backend) => {\n          const name = typeof backend === \"string\" ? backend : backend.full;\n          const match = name.match(nameRegex);\n          const prefix = match?.groups?.prefix ?? \"\";\n          const slug = match?.groups?.slug ?? \"\";\n          const options = {\n            ...(typeof backend === \"object\" && backend.options\n              ? backend.options\n              : {}),\n            ...(match?.groups?.options\n              ? Object.fromEntries(\n                  match.groups.options.split(\",\").map((opt) => {\n                    const [k, v] = opt.split(\"=\");\n                    return [k, v];\n                  }),\n                )\n              : {}),\n          };\n          return {\n            name: `${prefix}:${slug}`,\n            url: urlBuilders[prefix] ? urlBuilders[prefix](slug, options) : \"\",\n          };\n        }),\n        aliases: tool.aliases ?? [],\n        os: tool.os ?? [],\n      };\n    }\n\n    return Object.values(registry).sort((a, b) =>\n      a.short.localeCompare(b.short, \"en\"),\n    );\n  },\n};\n"
  },
  {
    "path": "docs/registry.md",
    "content": "---\neditLink: false\n---\n\n# Registry\n\n<script setup>\nimport Registry from '/components/registry.vue';\n</script>\n\nList of all [tools](#tools) aliased by default in `mise`.\n\nYou can use these shorthands with `mise use`. This allows you to use a tool without needing to know the full name. For example, to use the `aws-cli` tool, you can do the following:\n\n```shell\nmise use aws-cli\n```\n\ninstead of\n\n```shell\nmise use aqua:aws/aws-cli\n```\n\nIf a tool is not available in the registry, you can install it by its full name. [github](./dev-tools/backends/github.html) and [aqua](./dev-tools/backends/aqua.html) give you for example access to almost all programs available on GitHub.\n\n## Backends\n\nIn addition to built-in [core tools](/core-tools.html), `mise` supports a variety of [backends](/dev-tools/backends/) to install tools.\n\nIn general, the preferred [backend](/dev-tools/backends/) to use for new tools is the following:\n\n- [aqua](./dev-tools/backends/aqua.html) - offers the most features and security while not requiring plugins\n- [github](./dev-tools/backends/github.html) - for tools that are not available in the aqua registry, but are available on GitHub\n- [gitlab](./dev-tools/backends/gitlab.html) - for tools that are not available in the aqua registry, but are available on GitLab\n- [pipx](./dev-tools/backends/pipx.html) - only for python tools, requires python to be installed but this generally would always be the case for python tools\n- [npm](./dev-tools/backends/npm.html) - only for node tools, requires node to be installed but this generally would always be the case for node tools\n- [go](./dev-tools/backends/go.html) - only for go tools, requires go to be installed to compile. Because go tools can be distributed as a single binary, aqua/github are definitely preferred.\n- [cargo](./dev-tools/backends/cargo.html) - only for rust tools, requires rust to be installed to compile. Because rust tools can be distributed as a single binary, aqua/github are definitely preferred.\n- [dotnet](./dev-tools/backends/dotnet.html) - only for dotnet tools, requires dotnet to be installed to compile. Because dotnet tools can be distributed as a single binary, aqua/github are definitely preferred.\n\nNew vfox and asdf tools are almost never accepted for supply-chain security reasons.\n\n### Backends Priority\n\nEach tool can define its own priority if it has more than one backend it supports. If you would like to disable a backend, you can do so with the following command:\n\n```shell\nmise settings disable_backends=asdf\n```\n\nThis will disable the [asdf](./dev-tools/backends/asdf.html) backend. See [Aliases](/dev-tools/aliases.html) for a way to set a default backend for a tool. Note that the `asdf` backend is disabled by default on Windows.\n\nYou can also specify the full name for a tool using `mise use aqua:1password/cli` if you want to use a specific backend.\n\n### Environment Variable Overrides\n\nYou can override the backend for any tool using environment variables with the pattern `MISE_BACKENDS_<TOOL>`. This takes the highest priority and overrides any registry or alias configuration:\n\n```shell\n# Use vfox backend for php\nexport MISE_BACKENDS_PHP='vfox:mise-plugins/vfox-php'\nmise install php@latest\n```\n\nThe tool name in the environment variable should be in SHOUTY_SNAKE_CASE (uppercase with underscores). For example, `my-tool` becomes `MISE_BACKENDS_MY_TOOL`.\n\nSource: <https://github.com/jdx/mise/blob/main/registry/>\n\n## Tools {#tools}\n\nNote that [`mise registry`](/cli/registry.html) can be used to list all tools in the registry. [`mise use`](/cli/use.html) without any arguments will show a `tui` to select a tool to install.\n\n<Registry />\n"
  },
  {
    "path": "docs/rtx.md",
    "content": "# Coming from rtx\n\n`mise` was formerly called `rtx`. The name was changed to avoid confusion with Nvidia's\nline of graphics cards. This wasn't a legal issue, but just general confusion. When\npeople first hear about the project or see it posted they wouldn't realize it was talking\nabout a CLI tool. It was a bit difficult to search for on Google but also places like\nTwitter and in Slack searches and things. This was the top complaint about `rtx` and\nmany people were fairly outspoken about disliking the name for this reason. `rtx` was\nsupposed to be a working title that I intended to change but never got around to doing.\nThis change should've happened earlier when there were fewer users and I apologize for\nnot having done that sooner knowing that this was likely going to be necessary at some point.\n\nTo upgrade from `rtx` to `mise`, simply install `mise` and it should automatically\nmigrate its internal directories, moving `~/.local/share/rtx/installs/*` to `~/.local/share/mise/installs/*`\n(skipping python & ruby which cannot be moved), `~/.local/share/rtx/plugins` to `~/.local/share/mise/plugins`,\nand `~/.config/rtx` to `~/.config/mise` (if the destination does not exist). Python and Ruby\ninstalls will need to be reinstalled with `mise install`.\n\n`mise` will continue reading `.rtx.toml` files for some time but that eventually will\nbe deprecated so please rename them to `mise.toml`. `mise` will not read from `RTX_*`\nenv vars so those will need to be changed to `MISE_*`. Anything using a local `.rtx` or\n`.config/rtx` directory will need to be moved to `.mise`/`.config/mise`.\n\nI apologize if this migration is not seamless however I think moving to a name that\nis easier to search for and avoids confusion is better for everyone. I also apologize\nfor it being abrupt—I simply couldn't think of a way to \"slow roll\" this change out\nwhile also keeping the GitHub repo.\n\nUsers of the `rtx-action` GitHub action will need to switch to `mise-action` (and also\nbump the major version to v2).\n\nIf you build infrastructure where users may still be calling `rtx activate` in their\nshell rc scripts, you can create a symlink `ln -s /path/to/mise /path/to/rtx` so\n`rtx activate` still functions.\n\nFor <https://mise.run>, we're using `~/.local/bin/mise`\nas the executable PATH instead of the old directory `~/.local/share/rtx/bin/mise`\nto keep things a bit cleaner. You can still use the old style if you like by setting\n`MISE_INSTALL_PATH`.\n\nIf you use shims, a `mise reshim` will be necessary to update the shims.\n\nThanks for trying out my little CLI tool by the way. I find this project incredibly\nfulfilling to work on and seeing people have success using. I have\ntremendous passion for building dev tools and the ideas in `mise` are the product of\nme thinking about building a tool like this for over a decade.\n\nIf you aren't happy with `mise` or the way I'm running this project, even in a tiny way,\nplease let me know. You can [contact me privately](/about#contact) if you like. I certainly\nwon't take offense and I would prefer you say something rather than nothing. Otherwise\nI'll never know.\n"
  },
  {
    "path": "docs/settings.data.ts",
    "content": "import * as fs from \"node:fs\";\nimport { load } from \"js-toml\";\nimport markdownit from \"markdown-it\";\n\nconst md = markdownit();\n\nexport default {\n  watch: [\"./settings.toml\"],\n  load() {\n    const settings = {};\n    const raw = fs.readFileSync(\"./settings.toml\", \"utf-8\");\n    const doc = load(raw);\n\n    function getParseEnv(parseEnv) {\n      if (parseEnv === \"list_by_comma\") {\n        return \"comma\";\n      }\n      if (parseEnv === \"list_by_colon\") {\n        return \"colon\";\n      }\n      return undefined;\n    }\n\n    const typeMap = {\n      String: \"string\",\n      Path: \"string\",\n      Url: \"string\",\n      Duration: \"string\",\n      Bool: \"boolean\",\n      Integer: \"integer\",\n      ListString: \"string[]\",\n      ListPath: \"string[]\",\n      SetString: \"string[]\",\n      \"IndexMap<String, String>\": \"object\",\n      BoolOrString: \"boolean | string\",\n    };\n\n    function buildElement(key, props) {\n      const type = typeMap[props.type] || props.type;\n      let default_ = props.default_docs ?? props.default;\n      if (default_ === undefined && type === \"boolean\" && !props.optional) {\n        default_ = false;\n      }\n      if (default_ === undefined && props.optional) {\n        default_ = \"None\";\n      }\n\n      const ele = {\n        key,\n        default: default_,\n        docs: md.render(props.docs ?? props.description),\n        deprecated: props.deprecated,\n        enum: props.enum,\n        env: props.env,\n        parseEnv: getParseEnv(props.parse_env),\n        optional: !props.default_docs && props.optional,\n        type,\n      };\n      return ele;\n    }\n\n    for (const key in doc) {\n      const props = doc[key];\n      if (props.hide) continue;\n      if (props.type) {\n        settings[key] = buildElement(key, props);\n      } else {\n        for (const subkey in props) {\n          if (props.hide) continue;\n          settings[key] = settings[key] || {\n            key,\n            additionalProperties: false,\n            description: props.description,\n            settings: [],\n          };\n          settings[key].settings.push(\n            buildElement(`${key}.${subkey}`, props[subkey]),\n          );\n        }\n      }\n    }\n    return Object.values(settings).sort((a, b) => a.key.localeCompare(b.key));\n  },\n};\n"
  },
  {
    "path": "docs/shell-aliases.md",
    "content": "# Shell Aliases\n\nmise can manage shell aliases that are set dynamically when you enter a directory and unset when you leave, similar to how environment variables work.\n\n## Configuration\n\nShell aliases are defined in `mise.toml` under the `[shell_alias]` section:\n\n```toml\n[shell_alias]\nll = \"ls -la\"\nla = \"ls -A\"\ngs = \"git status\"\ngc = \"git commit\"\n```\n\nWhen you enter a directory with this configuration, these aliases will be automatically set in your shell. When you leave the directory (and the new directory doesn't have the same aliases), they will be unset.\n\n## Supported Shells\n\nShell aliases are currently supported in:\n\n- **bash** - Uses `alias`/`unalias` commands\n- **zsh** - Uses `alias`/`unalias` commands\n- **fish** - Uses `alias`/`functions -e` commands\n\nOther shells (nushell, elvish, xonsh, powershell) do not currently support shell aliases.\n\n## Dynamic Behavior\n\nShell aliases work similarly to environment variables managed by mise:\n\n1. **Set on entry**: When you `cd` into a directory with `[shell_alias]` config, the aliases are set\n2. **Updated on change**: If an alias value changes in your config, it will be updated\n3. **Unset on exit**: When you leave the directory (or the alias is removed from config), it will be unset\n\n```bash\n$ cd ~/myproject\n# mise sets: alias ll='ls -la'\n\n$ ll\n# Runs: ls -la\n\n$ cd ~\n# mise runs: unalias ll\n```\n\n## Hierarchy\n\nLike other mise config, shell aliases from parent directories are available in child directories. A child directory can override a parent's alias:\n\n```toml\n# ~/projects/mise.toml\n[shell_alias]\nbuild = \"make build\"\n\n# ~/projects/myapp/mise.toml\n[shell_alias]\nbuild = \"npm run build\"  # Overrides parent\n```\n\n## Templates\n\nAlias values support [templates](/templates), allowing dynamic values:\n\n```toml\n[shell_alias]\nproj = \"cd {{config_root}}\"\nnode_version = \"echo {{exec(command='node --version')}}\"\n```\n\n## Use Cases\n\n### Project-Specific Shortcuts\n\nDefine shortcuts that only make sense within a specific project:\n\n```toml\n[shell_alias]\ndev = \"npm run dev\"\ntest = \"npm test\"\nbuild = \"npm run build\"\ndeploy = \"./scripts/deploy.sh\"\n```\n\n### Tool Wrappers\n\nCreate aliases that wrap tools with project-specific defaults:\n\n```toml\n[shell_alias]\ndocker-compose = \"docker compose -f docker-compose.dev.yml\"\nterraform = \"terraform -chdir=./infrastructure\"\n```\n\n### Quick Navigation\n\n```toml\n[shell_alias]\nsrc = \"cd {{config_root}}/src\"\ntests = \"cd {{config_root}}/tests\"\ndocs = \"cd {{config_root}}/docs\"\n```\n\n## Comparison to Tool Aliases\n\nmise has two different alias features that serve different purposes:\n\n| Feature           | Purpose                                                | Config Key      |\n| ----------------- | ------------------------------------------------------ | --------------- |\n| **Shell Aliases** | Define shell command shortcuts (`alias ll='ls -la'`)   | `[shell_alias]` |\n| **Tool Aliases**  | Define version aliases for tools (`node@lts` → `20.x`) | `[tool_alias]`  |\n\nSee [Tool Aliases](/dev-tools/aliases) for documentation on aliasing tool versions.\n"
  },
  {
    "path": "docs/tapes/demo.tape",
    "content": "# Use mise run docs:demo to record this tape\n\nOutput demo.gif\nOutput demo.mp4\n\n# vhs settings: https://github.com/charmbracelet/vhs#settings\nSet Shell \"bash\"\nSet FontSize 24\nSet Width 1200\nSet Height 600\nSet Padding 10\nSet WindowBar Colorful\nSet TypingSpeed 65ms\n\n#### SETUP\nHide\nType 'apt-get update && apt-get install -y curl gpg && curl https://mise.run | MISE_INSTALL_PATH=/usr/local/bin/mise sh' Enter Wait\nType 'mkdir myproj' Enter Wait\nType 'clear'\nEnter Wait\nShow\n\n#### DEMO START\n\nSleep 500ms\n\nType '# Short demo showing how mise helps manage multiple versions of tools like Node.js, Python, Ruby, Go, Terraform, ripgrep, jq, and more.' Enter\nSleep 2s\n\nEnter\n\nType '# \"mise exec <tool> -- <command>\" allows you to run any tools with mise'\nSleep 1s Enter Wait\n\nType \"mise exec node@24 -- node -v\"\nSleep 500ms Enter Wait Sleep 2s\n\nType '# node is only available in the mise environment, not globally' Sleep 500ms Enter Wait\n\nType 'node -v' Sleep 500ms Enter Wait\nSleep 2s\n\nType 'clear' Sleep 500ms Enter Wait\n\nType '# Here is another example where we run terraform with `mise exec`'\nSleep 1s Enter\n\nType \"mise exec terraform -- terraform -v\"\nSleep 500ms Enter Wait Sleep 3s\n\nType 'clear' Sleep 500ms Enter Wait\n\nType '# mise exec is great for running one-off commands, however it can be convenient to activate mise' Sleep 500ms Enter\n\nType '# When activated, mise will automatically update your PATH to include the tools you have installed, making them available directly' Enter\nSleep 2s Enter\n\nType 'clear' Sleep 500ms Enter Wait\n\nType \"# Let's activate mise. (this usually goes into your shell config file)\" Sleep 500ms Enter\n\nType 'eval \"$(mise activate bash)\"' Sleep 500ms Enter Wait\n\nType '# We will now make node@lts the global default.'\nSleep 2s Enter Wait\n\nType \"mise use --global node@lts\" Sleep 500ms Enter Wait\nSleep 2s\n\nType \"node -v\" Sleep 500ms Enter Wait\nSleep 1s\n\nType \"which node\" Sleep 500ms Enter Wait\nSleep 2s\n\nType '# Note that we get back the path to the real node here, not a shim'\nEnter\nSleep 3s\n\nType '# we can also install other tools with mise.' Enter\nType '# For example, we will set up terraform, jq, bat and go globally' Enter\nSleep 2s\n\nType 'clear' Sleep 500ms Enter Wait\n\nType \"mise use -g terraform jq go bat\" Sleep 500ms Enter Wait\nSleep 2s\n\nType \"terraform -v\" Sleep 500ms Enter Wait\nType \"jq --version\" Sleep 500ms Enter Wait\nType \"go version\" Sleep 500ms Enter Wait\nSleep 3s\n\nType 'mise ls' Sleep 500ms Enter Wait\nSleep 3s\n\nType 'clear' Sleep 500ms Enter Wait\nType '# Lets enter a project directory where we will set up node@23 and pnpm@10' Enter\nSleep 1s\n\nType \"cd myproj\" Sleep 500ms Enter Wait\nSleep 1s\n\nType \"mise use node@23 pnpm@10\" Sleep 500ms Enter Wait\nType \"node -v\" Enter Wait\nSleep 2s\n\nType \"pnpm -v\" Enter Wait\nSleep 2s\n\nType '# As expected, `node -v` is now v23.x' Enter Wait\nSleep 2s\n\nType 'bat mise.toml' Sleep 500ms Enter Wait\nSleep 2s\n\nType 'mise ls' Sleep 500ms Enter Wait\nSleep 3s\n\nType '# We will leave this directory. The node version will revert to the global LTS version' Enter\nSleep 2s\n\nType \"cd ..\" Sleep 500ms Enter Wait\nType \"node -v\" Sleep 500ms Enter Wait\n\nSleep 4s\n\n# cleanup\nHide\nType 'rm -rf myproj' Enter\nWait\n"
  },
  {
    "path": "docs/tasks/architecture.md",
    "content": "# Task System Architecture\n\nUnderstanding how mise's task system works helps you write more efficient tasks and troubleshoot dependency issues.\n\n## Task Dependency System\n\nmise uses a sophisticated dependency graph system to manage task execution order and parallelism. This ensures tasks run in the correct order while maximizing performance through parallel execution.\n\n### Dependency Graph Resolution\n\nWhen you run `mise run build`, mise creates a directed acyclic graph (DAG) of all tasks and their dependencies:\n\n```mermaid\ngraph TD\n    A[lint] --> D[test]\n    B[format] --> D[test]\n    C[build] --> D[test]\n    D[test] --> E[package]\n    F[docs] --> E[package]\n    E[package] --> G[deploy]\n```\n\nThis graph ensures that:\n\n- Dependencies run before dependents\n- Independent tasks run in parallel\n- No circular dependencies exist\n- Failed dependencies prevent dependents from running\n\n### Dependency Types\n\nmise supports three types of task dependencies:\n\n#### `depends` - Prerequisites\n\nTasks that must complete successfully before this task runs:\n\n```toml\n[tasks.test]\ndepends = [\"lint\", \"build\"]\nrun = \"npm test\"\n```\n\n#### `depends_post` - Cleanup Tasks\n\nTasks that run after this task completes (whether successful or failed):\n\n```toml\n[tasks.deploy]\ndepends = [\"build\", \"test\"]\ndepends_post = [\"cleanup\", \"notify\"]\nrun = \"kubectl apply -f deployment.yaml\"\n```\n\n#### `wait_for` - Soft Dependencies\n\nTasks that should run first if they're in the current execution, but don't fail if they're not available:\n\n```toml\n[tasks.integration-test]\nwait_for = [\"start-services\"]  # Only waits if start-services is also being run\nrun = \"npm run test:integration\"\n```\n\n## Parallel Execution Engine\n\n### Job Control\n\nmise executes tasks in parallel up to the configured job limit:\n\n```bash\nmise run --jobs 8 test        # Use 8 parallel jobs\nmise run -j 1 test            # Force sequential execution\n```\n\nThe default is 4 parallel jobs, but you can configure this globally:\n\n```toml\n# ~/.config/mise/config.toml\n[settings]\njobs = 8\n```\n\n### Example Execution Flow\n\nGiven these tasks:\n\n```toml\n[tasks.lint]\nrun = \"eslint src/\"\n\n[tasks.test-unit]\ndepends = [\"lint\"]\nrun = \"npm run test:unit\"\n\n[tasks.test-integration]\ndepends = [\"lint\"]\nrun = \"npm run test:integration\"\n\n[tasks.build]\ndepends = [\"test-unit\", \"test-integration\"]\nrun = \"npm run build\"\n```\n\nExecution with `--jobs 2`:\n\n```\nTime →\n0s:   [lint]\n5s:   [test-unit] [test-integration]  # Run in parallel after lint\n15s:  [build]                        # Waits for both tests\n```\n\n## Task Discovery and Resolution\n\n### Task Sources\n\nmise discovers tasks from multiple sources in this order:\n\n1. **File tasks**: Executable files in task directories\n2. **TOML tasks**: Defined in `mise.toml` files\n3. **Parent directory tasks**: Available from parent directories\n\n### Task Resolution Process\n\nWhen you run `mise run build`, mise:\n\n1. **Discovers all tasks** from all configuration sources\n2. **Resolves the task name** (handles aliases and partial matches)\n3. **Builds dependency graph** including all dependencies\n4. **Validates graph** (checks for circular dependencies)\n5. **Executes in dependency order** with parallelism\n\n### Task Resolution Across Directories\n\nTasks from parent directories are available in subdirectories and can be overridden:\n\n```\nproject/\n├── mise.toml              # defines: lint, test, build\n└── frontend/\n    └── mise.toml          # overrides: test, adds: bundle\n```\n\nIn `frontend/`, you have access to: `lint` (from parent), `test` (overridden), `build` (from parent), `bundle` (local).\n\n## Advanced Dependency Features\n\n### Conditional Dependencies\n\nUse task arguments for conditional behavior:\n\n```toml\n[tasks.test]\ndepends = [\"build\"]\nrun = '''\nif [ \"$1\" = \"--with-lint\" ]; then\n  mise run lint\nfi\nnpm test\n'''\n```\n\n### Dynamic Dependencies\n\nTasks can specify dependencies at runtime:\n\n```bash\n#!/usr/bin/env bash\n#MISE depends=[\"setup\"]\n\n# Additional conditional dependency\nif [ ! -f \".env\" ]; then\n  mise run generate-env\nfi\n\nnpm start\n```\n\n### Cross-Project Dependencies\n\nReference tasks from other directories:\n\n```toml\n[tasks.deploy-all]\ndepends = [\n  \"../api:build\",\n  \"../frontend:build\",\n  \"deploy-infrastructure\"\n]\nrun = \"echo 'All services deployed'\"\n```\n\n## Performance Optimizations\n\n### Source and Output Tracking\n\nTasks can skip execution if sources haven't changed:\n\n```toml\n[tasks.build]\nsources = [\"src/**/*.ts\", \"package.json\"]\noutputs = [\"dist/**/*\"]\nrun = \"npm run build\"\n```\n\nmise will only run the task if:\n\n- Source files are newer than output files\n- The task has never been run\n- Dependencies have changed\n\n### Incremental Execution\n\nUse `mise run --force` to ignore source/output checking:\n\n```bash\nmise run --force build     # Always run, ignore source changes\n```\n\n### Parallel File Watching\n\nUse `mise watch` for continuous development:\n\n```bash\nmise watch              # Watch all task sources\nmise watch build test   # Watch specific tasks\n```\n\nThis automatically reruns tasks when their source files change.\n\n## Debugging Task Dependencies\n\n### Visualize Dependencies\n\n```bash\nmise tasks deps build           # Show build's dependencies\nmise tasks deps --dot > deps.dot # Generate graphviz diagram\n```\n\n### Execution Tracing\n\n```bash\nmise run --verbose build       # Show task execution details\nmise run --dry-run build       # Show what would run without executing\n```\n\n### Common Issues\n\n**Circular Dependencies**:\n\n```\nError: Circular dependency detected: test → build → test\n```\n\nSolution: Remove the circular reference or use `wait_for` instead of `depends`.\n\n**Missing Dependencies**:\n\n```\nError: Task 'build' depends on 'lint' but 'lint' was not found\n```\n\nSolution: Define the missing task or remove the dependency.\n\n**Slow Parallel Execution**:\n\n- Check if tasks have unnecessary dependencies\n- Use `mise tasks deps` to verify dependency graph\n- Consider increasing `--jobs` if you have CPU cores available\n\nThe task architecture is designed to scale from simple single-task projects to complex multi-service applications with intricate build dependencies.\n"
  },
  {
    "path": "docs/tasks/file-tasks.md",
    "content": "# File Tasks\n\nIn addition to defining tasks through the configuration, they can also be defined as standalone script files in one of the following directories:\n\n- `mise-tasks/:task_name`\n- `.mise-tasks/:task_name`\n- `mise/tasks/:task_name`\n- `.mise/tasks/:task_name`\n- `.config/mise/tasks/:task_name`\n\nNote that you can configure directories using the [task_config](/tasks/task-configuration.html#task-config-options) section.\n\nHere is an example of a file task that builds a Rust CLI:\n\n```bash [mise-tasks/build]\n#!/usr/bin/env bash\n#MISE description=\"Build the CLI\"\ncargo build\n```\n\n::: tip Important\nEnsure that the file is executable, otherwise mise will not be able to detect it.\n\n```shell\nchmod +x mise-tasks/build\n```\n\n:::\n\nHaving the code in a bash file and not TOML helps make it work\nbetter in editors since they can do syntax highlighting and linting more easily.\n\nThey also still work great for non-mise users—though\nof course they'll need to find a different way to install their dev tools the tasks might use.\n\n## Task Configuration\n\nAll configuration options can be found here [task configuration](/tasks/task-configuration)\nYou can provide additional configuration for file tasks by adding `#MISE` comments at the top of the file.\n\n```bash\n#MISE description=\"Build the CLI\"\n#MISE alias=\"b\"\n#MISE sources=[\"Cargo.toml\", \"src/**/*.rs\"]\n#MISE outputs=[\"target/debug/mycli\"]\n#MISE env={RUST_BACKTRACE = \"1\"}\n#MISE depends=[\"lint\", \"test\"]\n#MISE tools={rust=\"1.50.0\"}\n```\n\nAssuming that file was located in `mise-tasks/build`, it can then be run with `mise run build` (or with its alias: `mise run b`).\n\n:::tip\nBeware of formatters changing `#MISE` to `# MISE`.\nIt's intentionally ignored by mise to avoid unintentional configuration.\nTo workaround this, use the alternative: `# [MISE]`.\n:::\n\n## Shebang\n\nThe shebang line is optional, but if it is present, it will be used to determine the shell to run the script with.\nYou can also use it to run the script with various programming languages.\n\n::: code-group\n\n```js [node]\n#!/usr/bin/env node\n//MISE description=\"Hello, World in Node.js\"\n\nconsole.log(\"Hello, World!\");\n```\n\n```python\n#!/usr/bin/env python\n#MISE description=\"Hello, World in Python\"\n\nprint('Hello, World!')\n```\n\n```ts [deno]\n#!/usr/bin/env -S deno run --allow-env\n//MISE description=\"Hello, World in Deno\"\n\nconsole.log(`PATH, ${Deno.env.get(\"PATH\")}`);\n```\n\n```powershell [powershell]\n#!/usr/bin/env pwsh\n#MISE description=\"Hello, World in PowerShell\"\n\n$current_directory = Get-Location\nWrite-Host \"Hello from PowerShell, current directory is $current_directory\"\n```\n\n:::\n\n## Editing tasks\n\nThis script can be edited by running `mise tasks edit build` (using `$EDITOR`). If it doesn't exist it will be created.\nThis is convenient for quickly editing or creating new scripts.\n\n## Task Grouping\n\nFile tasks in `mise-tasks`, `.mise/tasks`, `mise/tasks`, or `.config/mise/tasks` can be grouped into\nsub-directories which will automatically apply prefixes to their names\nwhen loaded.\n\n**Example**: With a folder structure like below:\n\n```text\nmise-tasks\n├── build\n└── test\n    ├── _default\n    ├── integration\n    └── units\n```\n\nRunning `mise tasks` will give the below output:\n\n```shellsession\n$ mise tasks\nName              Description Source\nbuild                         ./mise-tasks/build\ntest                          ./mise-tasks/test/_default\ntest:integration              ./mise-tasks/test/integration\ntest:units                    ./mise-tasks/test/units\n```\n\n## Arguments\n\n::: tip\nFor comprehensive information about task arguments, see the dedicated [Task Arguments](/tasks/task-arguments) page.\n:::\n\n[usage](https://usage.jdx.dev) spec can be used within these files to provide argument parsing, autocompletion,\ndocumentation when running mise and can be exported to markdown. Essentially this turns tasks into\nfully-fledged CLIs.\n\n:::tip\nThe `usage` CLI is not required to execute mise tasks with the usage spec.\nHowever, for completions to work, the `usage` CLI must be installed and available in the PATH.\n:::\n\n### Example file task with arguments\n\nHere is an example of a file task that builds a Rust CLI using some of the features of usage:\n\n```bash [mise-tasks/build]\n#!/usr/bin/env bash\nset -e\n\n#USAGE flag \"-c --clean\" help=\"Clean the build directory before building\"\n#USAGE flag \"-p --profile <profile>\" help=\"Build with the specified profile\" default=\"debug\" {\n#USAGE   choices \"debug\" \"release\"\n#USAGE }\n#USAGE flag \"-u --user <user>\" help=\"The user to build for\"\n#USAGE complete \"user\" run=\"mycli users\"\n#USAGE arg \"<target>\" help=\"The target to build\"\n\nif [ \"${usage_clean:-false}\" = \"true\" ]; then\n  cargo clean\nfi\n\ncargo build --profile \"${usage_profile?}\" --target \"${usage_target?}\"\n```\n\n::: tip\nFor details on bash parameter expansion patterns like `${var?}`, `${var:-default}`, and `${var:+value}`, see [Bash Variable Expansion for Usage Variables](/tasks/task-arguments#bash-variable-expansion).\n:::\n\nIf you have installed `usage`, completions will be enabled for your task. In this example,\n\n- `mise run -- build --profile <tab><tab>`\n  will show `debug` and `release` as options.\n- The `--user` flag will also show completions generated by the output of `mycli users`.\n- Note: Use `--` to separate mise flags from task arguments: `mise run -- build --profile release <target>`\n\n(Note that cli and markdown help for tasks is not yet implemented in mise as of this writing but that is planned.)\n\n:::tip\nIf you don't get any autocomplete suggestions, use the `-v` (verbose) flag to see what's going on.\nFor example, if you use `mise run build -v` and have an invalid `usage` spec, you will see an error message such as `DEBUG failed to parse task file with usage`\n:::\n\n### Example of a NodeJS file task with arguments\n\nHere is how you can use [usage](https://usage.jdx.dev/cli/scripts#usage-scripts) to parse arguments in a Node.js script:\n\n```js [mise-tasks/greet]\n#!/usr/bin/env -S node\n//MISE description=\"Write a greeting to a file\"\n//USAGE flag \"-f --force\" help=\"Overwrite existing <file>\"\n//USAGE flag \"-u --user <user>\" help=\"User to run as\"\n//USAGE arg \"<output_file>\" help=\"The file to write\" default=\"file.txt\" {\n//USAGE   choices \"greeting.txt\" \"file.txt\"\n//USAGE }\n\nconst fs = require(\"fs\");\n\nconst { usage_user, usage_force, usage_output_file } = process.env;\n\nif (usage_force === \"true\") {\n  fs.rmSync(usage_output_file, { force: true });\n}\n\nconst user = usage_user ?? \"world\";\nfs.appendFileSync(usage_output_file, `Hello, ${user}\\n`);\nconsole.log(`Greeting written to ${usage_output_file}`);\n```\n\nRun it with:\n\n```shell\nmise run greet greeting.txt --user Alice\n# Greeting written to greeting.txt\n```\n\nIf you pass an invalid argument, you will get an error message:\n\n```shell\nmise run greet invalid.txt --user Alice\n# [greet] ERROR\n#   0: Invalid choice for arg output_file: invalid.txt, expected one of greeting.txt, file.txt\n```\n\nAutocomplete will show the available choices for the `output_file` argument if `usage` is installed.\n\n```shell\nmise run greet <TAB>\n# > greeting.txt\n#   file.txt\n```\n\n## CWD\n\nmise sets the current working directory to the directory of `mise.toml` before running tasks.\nThis can be overridden by setting <span v-pre>`dir=\"{{cwd}}\"`</span> in the task header:\n\n```bash\n#!/usr/bin/env bash\n#MISE dir=\"{{cwd}}\"\n```\n\nAlso, the original working directory is available in the `MISE_ORIGINAL_CWD` environment variable:\n\n```bash\n#!/usr/bin/env bash\ncd \"$MISE_ORIGINAL_CWD\"\n```\n\n## Running tasks directly\n\nTasks don't need to be configured as part of a config, you can just run them directly by passing the path to the script:\n\n```bash\nmise run ./path/to/script.sh\n```\n\nNote that the path must start with `/` or `./` to be considered a file path. (On Windows it can be `C:\\` or `.\\`)\n"
  },
  {
    "path": "docs/tasks/index.md",
    "content": "# Tasks\n\n> Like [make](https://www.gnu.org/software/make/manual/make.html) it manages _tasks_ used\n> to build and test projects.\n\nYou can define tasks in `mise.toml` files or as standalone shell scripts. These are useful for\nthings like running linters, tests, builders, servers, and other tasks that are specific to a\nproject. Of\ncourse, tasks launched with mise will include the mise environment—your tools and env vars defined\nin `mise.toml`.\n\nHere's my favorite features about mise's task runner:\n\n- building dependencies in parallel—by default with no configuration required\n- last-modified checking to avoid rebuilding when there are no changes—requires minimal config\n- [mise watch](./running-tasks.html#watching-files) to automatically rebuild on changes—no configuration required, but it helps\n- ability to write tasks as actual bash script files and not inside yml/json/toml strings that lack\n  syntax highlighting and linting/checking support\n\nThere are 2 ways to define tasks: [inside of `mise.toml` files](./toml-tasks.html) or as [standalone shell scripts](./file-tasks.html). You can also use [task templates](./templates.html) to create reusable task definitions.\n\n## Tasks in `mise.toml` files\n\nTasks are defined in the `[tasks]` section of the `mise.toml` file.\n\n```toml [mise.toml]\n[tasks.build]\ndescription = \"Build the CLI\"\nrun = \"cargo build\"\n```\n\nYou can then run the task with `mise run build` (or `mise build` if it doesn't conflict with an existing command).\n\n- See [TOML tasks](./toml-tasks.html) for more information.\n- See [Running Tasks](./running-tasks.html) to learn how to run tasks.\n\n## File Tasks\n\nYou can also define tasks as standalone shell scripts. All you have to do is to create an `executable` file in a specific directory like `mise-tasks`.\n\n```sh [mise-tasks/build]\n#!/usr/bin/env bash\n#MISE description=\"Build the CLI\"\ncargo build\n```\n\nYou can then run the task with `mise run build` like for TOML tasks.\nSee the [file tasks reference](./file-tasks.html) for more information.\n\n## Environment variables passed to tasks\n\nThe following environment variables are passed to the task:\n\n- `MISE_ORIGINAL_CWD`: The original working directory from where the task was run.\n- `MISE_CONFIG_ROOT`: The directory containing the `mise.toml` file where the task was defined or if the config path is something like `~/src/myproj/.config/mise.toml`, it will be `~/src/myproj`.\n- `MISE_PROJECT_ROOT`: The root of the project.\n- `MISE_TASK_NAME`: The name of the task being run.\n- `MISE_TASK_DIR`: The directory containing the task script.\n- `MISE_TASK_FILE`: The full path to the task script.\n"
  },
  {
    "path": "docs/tasks/monorepo.md",
    "content": "# Monorepo Tasks <Badge type=\"warning\" text=\"experimental\" />\n\nmise supports monorepo-style task organization with target path syntax. This feature allows you to manage tasks across multiple projects in a single repository, where each project can have its own `mise.toml` configuration with tools, environment variables, and tasks that may be different from where the task is called from.\n\n## Overview\n\nWhen `experimental_monorepo_root` is enabled in your root `mise.toml`, mise will automatically discover tasks in subdirectories and prefix them with their relative path from the monorepo root. This creates a unified task namespace across your entire repository.\n\n::: tip\nThe directory containing a `mise.toml` file is called the **config_root**. In monorepo mode, each project can have its own config_root with its own configuration, separate from the monorepo root. Note that if you use one of the alternate paths in a subdirectory like `./projects/frontend/.mise/config.toml`, the config_root will be `./projects/frontend`–not `./projects/frontend/.mise`.\n:::\n\n### Benefits\n\n- **Consistent execution**: Run tasks from any location in the monorepo using the mise config that would be set if called from the task's directory\n- **Clear task namespacing**: Tasks are prefixed with their location from the monorepo root\n- **Pattern-based execution**: Use wildcards to run tasks across multiple projects\n- **Tool and environment layering**: Subdirectory tasks use tools and environment variables from parent configs, but can also define their own in their config_root\n- **Automatic trust propagation**: When the monorepo root is trusted, all descendant configs are automatically trusted\n\n## Configuration\n\n### Enabling Monorepo Mode\n\nAdd `experimental_monorepo_root = true` to your root `mise.toml`:\n\n```toml\n# /myproject/mise.toml\nexperimental_monorepo_root = true\n\n[tools]\n# Tools defined here apply to all subdirectories\nnode = \"20\"\n```\n\n::: warning\nThis feature requires `MISE_EXPERIMENTAL=1` environment variable.\n:::\n\n### Example Structure\n\n```\nmyproject/\n├── mise.toml (with experimental_monorepo_root = true)\n├── projects/\n│   ├── frontend/\n│   │   └── mise.toml (with tasks: build, test)\n│   └── backend/\n│       └── mise.toml (with tasks: build, test)\n```\n\nWith this structure, tasks will be automatically namespaced:\n\n- `//projects/frontend:build`\n- `//projects/frontend:test`\n- `//projects/backend:build`\n- `//projects/backend:test`\n\n## Task Path Syntax\n\nMonorepo tasks use special path syntax with `//` and `:` prefixes. You can run these tasks directly with `mise` or with `mise run`. With non-monorepo tasks, the guidance is to avoid using the direct syntax for scripts because it could conflict with future core mise commands. However, mise will never define commands with a `//` or `:` prefix, so this guidance does not apply to monorepo tasks.\n\n```bash\n# Direct syntax (preferred for monorepo tasks)\nmise //projects/frontend:build\n\n# Also works with 'run'\nmise run //projects/frontend:build\n\n# Need quotes for wildcards\nmise '//projects/frontend:*'\n```\n\n### Absolute Paths\n\nUse `//` prefix to specify the absolute path from the monorepo root:\n\n```bash\n# Run build task in frontend project\nmise //projects/frontend:build\n\n# Run test task in backend project\nmise //projects/backend:test\n```\n\n### Current config_root Tasks\n\nUse `:` prefix to run tasks in the current config_root:\n\n```bash\ncd projects/frontend\nmise :build  # Runs the build task from frontend's config_root\n```\n\n::: tip Optional Colon Syntax\nThe leading `:` is optional when running tasks from subdirectories or defining task dependencies. While both syntaxes work, **we encourage using the `:` prefix to be explicit** about monorepo task references.\n\n**Running from subdirectory:**\n\n```bash\ncd projects/frontend\nmise :build      # Recommended: Explicit monorepo task reference\nmise build       # Also works (for migration compatibility)\n```\n\n**Task dependencies:**\n\n```toml\n# projects/frontend/mise.toml\n[tasks.lint]\nrun = \"eslint .\"\n\n[tasks.build]\ndepends = [\":lint\"]  # Recommended: Explicit and clear\n# OR\ndepends = [\"lint\"]   # Also works (for migration compatibility)\nrun = \"webpack build\"\n```\n\nThe bare name syntax (without `:`) is supported primarily to ease migration from non-monorepo to monorepo configurations. When migrating, you won't need to update all your task dependencies immediately - they'll continue to work. However, using the `:` prefix makes it clear you're referencing a task in the current config_root.\n:::\n\n### Wildcard Patterns\n\nmise supports two types of wildcards for flexible task execution:\n\n#### Path Wildcards (`...`)\n\nUse ellipsis (`...`) to match any directory depth:\n\n```bash\n# Run 'test' task in ALL projects (any depth)\nmise //...:test\n\n# Run 'build' in all subdirs under projects/\nmise //projects/...:build\n\n# Match paths with wildcards in the middle\nmise //projects/.../api:build  # Matches projects/*/api and projects/*/*/api\n```\n\n::: info\nAdditional glob patterns may be added in a future version so `mise //projects/*:build`\nand `mise '//projects/**:build'` will likely be supported. We're using `...` because it matches\nhow bazel and buck2 do it.\n:::\n\n#### Task Name Wildcards (`*`)\n\nUse asterisk (`*`) to match task names:\n\n```bash\n# Run ALL tasks in frontend project\nmise '//projects/frontend:*'\n\n# Run all tasks starting with 'test:'\nmise '//projects/frontend:test:*'\n\n# Run 'lint' task across all projects\nmise //...:lint\n```\n\n### Combining Wildcards\n\nYou can combine both types of wildcards for powerful patterns:\n\n```bash\n# Run all tasks in all projects (idk why you'd ever want to do this, but you can)\nmise '//...:*'\n\n# Run all test tasks in all projects\nmise '//...:test*'\n\n# Run build tasks in all frontend-related projects\nmise //.../frontend:build\n```\n\n## Tool, Environment, and Vars Layering\n\nSubdirectory tasks automatically use tools and environment variables from parent config files in the hierarchy. However, each subdirectory can also define its own tools and environment variables in its config_root. This allows you to:\n\n1. Define common tools and environment at the monorepo root\n2. Override tools or environment in specific subdirectories\n3. Add additional tools or environment in subdirectories\n\n`vars` follow the same hierarchy for task templating, so child config vars are available when\nrunning subdirectory tasks from the monorepo root.\n\n### Layering Example\n\n```toml\n# /myproject/mise.toml\nexperimental_monorepo_root = true\n\n[tools]\nnode = \"20\"      # Available to all subdirectories\npython = \"3.12\"  # Available to all subdirectories\n\n[env]\nLOG_LEVEL = \"info\"  # Available to all subdirectories\n```\n\n```toml\n# /myproject/projects/frontend/mise.toml\n[tools]\nnode = \"18\"  # Overrides the root's node 20\n\n[env]\nLOG_LEVEL = \"debug\"  # Overrides the root's LOG_LEVEL\nPORT = \"3000\"        # Adds new environment variable\n\n[tasks.build]\nrun = \"npm run build\"  # Uses node 18 and LOG_LEVEL=debug\n```\n\n```toml\n# /myproject/projects/backend/mise.toml\n# No tools or env section - uses node 20, python 3.12, and LOG_LEVEL=info from root\n\n[tasks.build]\nrun = \"npm run build\"  # Uses node 20 and LOG_LEVEL=info from root\n```\n\n### Layering Rules\n\n1. **Base toolset and environment**: Tasks start with tools and environment from all global config files (including parent configs in the hierarchy)\n2. **Subdirectory override**: Tools and environment defined in the subdirectory's config file are merged on top, allowing overrides\n3. **Task-specific tools and environment**: Values defined in the task's `tools` and `env` properties take highest precedence\n\n## Config Roots\n\nYou must explicitly list your config roots using the `[monorepo]` section:\n\n```toml\n# /myproject/mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\n    \"packages/frontend\",\n    \"packages/backend\",\n    \"services/*\",          # Single-level glob pattern\n]\n```\n\nThis tells mise exactly which directories contain project configurations. Benefits:\n\n- **Fast discovery**: No filesystem walking needed\n- **Explicit control**: Only the projects you list are included\n- **Glob support**: Use `*` for single-level patterns (e.g., `services/*` matches `services/api`, `services/worker`)\n\n::: tip\nSingle-level globs (`*`) are supported, but recursive globs (`**`) are not. This ensures predictable performance while still allowing flexible patterns.\n:::\n\n::: warning Automatic Discovery Deprecated\nAutomatic filesystem walking to discover monorepo subdirectories is deprecated. If you don't define `[monorepo].config_roots`, mise will still walk the filesystem but will emit a deprecation warning. Please migrate to explicit config roots.\n:::\n\n## Listing Tasks\n\nThe difference between `mise tasks` and `mise tasks --all`:\n\n- **`mise tasks`**: Lists tasks from the current config_root hierarchy (current config_root and its parents)\n- **`mise tasks --all`**: Lists tasks from the entire monorepo, including sibling and descendant directories\n\n### Listing Example\n\nGiven this structure:\n\n```\nmyproject/\n├── mise.toml (task: deploy)\n├── projects/\n│   ├── frontend/\n│   │   └── mise.toml (tasks: build, test)\n│   └── backend/\n│       └── mise.toml (tasks: build, serve)\n```\n\nWhen in `projects/frontend/`:\n\n```bash\n# Lists: //:deploy, //projects/frontend:build, //projects/frontend:test\nmise tasks\n\n# Lists: //:deploy, //projects/frontend:build, //projects/frontend:test,\n#        //projects/backend:build, //projects/backend:serve\nmise tasks --all\n```\n\n### View Specific Project Tasks\n\n```bash\n# List all tasks in frontend project\nmise tasks '//projects/frontend:*'\n```\n\n## Best Practices\n\n### 1. Define Shared Tools and Environment at Root\n\nPlace commonly-used tools and environment in the root `mise.toml` to avoid repetition:\n\n```toml\n# /myproject/mise.toml\nexperimental_monorepo_root = true\n\n[tools]\nnode = \"20\"\npython = \"3.12\"\ngo = \"1.21\"\n\n[env]\nNODE_ENV = \"development\"\n```\n\n### 2. Override Only When Necessary\n\nOnly override tools in subdirectories when they genuinely need different versions:\n\n```toml\n# /myproject/legacy-app/mise.toml\n[tools]\nnode = \"14\"  # Override only for legacy app\n# python and go from root\n```\n\n### 3. Use Descriptive Task Names\n\nPrefix related tasks with common names to enable pattern matching:\n\n```toml\n[tasks.test]\nrun = \"npm test\"\n\n[tasks.\"test:unit\"]\nrun = \"npm run test:unit\"\n\n[tasks.\"test:e2e\"]\nrun = \"npm run test:e2e\"\n```\n\nThen run all test tasks: `mise '//...:test*'`\n\n### 4. Group Related Projects\n\nOrganize projects in subdirectories to enable targeted execution:\n\n```\nmyproject/\n├── services/\n│   ├── api/\n│   ├── worker/\n│   └── scheduler/\n└── apps/\n    ├── web/\n    └── mobile/\n```\n\nThen run tasks by group:\n\n```bash\nmise //services/...:build  # Build all services\nmise //apps/...:test       # Test all apps\n```\n\n## Comparison to Other Tools\n\nThe monorepo ecosystem offers many excellent tools, each with different strengths. Here's how mise's Monorepo Tasks compares:\n\n### Simple Task Runners\n\n**Taskfile** and **Just** are fantastic for single-project task automation. They're lightweight and easy to set up, but they weren't designed with monorepos in mind. While you can have multiple Taskfiles/Justfiles in a repo, they don't provide unified task discovery, cross-project wildcards, or automatic tool/environment layering across projects.\n\n**mise's advantage:** Automatic task discovery across the entire monorepo with a unified namespace and powerful wildcard patterns.\n\n### JavaScript-Focused Tools\n\n**Nx**, **Turborepo**, and **Lerna** are powerful tools specifically designed for JavaScript/TypeScript monorepos.\n\n- **Nx** offers incredible features like dependency graph visualization, affected project detection, code generation, and computation caching. It has a massive plugin ecosystem and excels at frontend monorepos.\n- **Turborepo** focuses on blazing-fast task caching and parallel execution with minimal configuration.\n- **Lerna** pioneered JavaScript monorepo management with package versioning and publishing workflows.\n\n**mise's advantage:** Language-agnostic support. While these tools excel in JS/TS ecosystems, mise works equally well with Rust, Go, Python, Ruby, or any mix of languages. You also get unified tool version management (not just tasks) and environment variables across your entire stack.\n\n### Large-Scale Build Systems\n\n**Bazel** (Google) and **Buck2** (Meta) are industrial-strength build systems designed for massive, multi-language monorepos at companies with thousands of engineers.\n\n- **Bazel** offers incredible features like distributed caching, remote execution, and hermetic builds with fine-grained dependency tracking.\n- **Buck2** is a modern rewrite with a clean architecture and impressive performance optimizations.\n\nBoth are extremely powerful but come with significant complexity:\n\n- Hermetic builds require strict isolation and complete dependency control\n- Steep learning curve with specialized DSLs (Starlark, etc.)\n- Complex configuration requiring dedicated build engineers\n- Heavy investment in infrastructure for remote caching\n- Stricter constraints on how you structure your code\n\n**mise's advantage:** Simplicity through non-hermetic builds. mise doesn't try to control your entire build environment in isolation - instead, it manages tools and tasks in a flexible, practical way. This \"non-hermetic\" approach means you can use mise without restructuring your entire codebase or learning a new language. You get powerful monorepo task management with simple TOML configuration - enough power for most teams without the enterprise-level complexity that hermetic builds require.\n\n### Other Notable Tools\n\n**Rush** (Microsoft) offers strict dependency management and build orchestration for JavaScript monorepos, with a focus on safety and convention adherence.\n\n**Moon** is a newer Rust-based build system that aims to be developer-friendly while supporting multiple languages.\n\n### The mise Sweet Spot\n\nmise's Monorepo Tasks aims to hit the sweet spot between simplicity and power:\n\n| Feature                 | Simple Runners | JS-Focused | Build Systems | mise |\n| ----------------------- | -------------- | ---------- | ------------- | ---- |\n| Multi-language support  | ✅             | ❌         | ✅            | ✅   |\n| Easy to learn           | ✅             | ⚠️         | ❌            | ✅   |\n| Unified task discovery  | ❌             | ✅         | ✅            | ✅   |\n| Wildcard patterns       | ❌             | ⚠️         | ✅            | ✅   |\n| Tool version management | ❌             | ❌         | ⚠️            | ✅   |\n| Environment layering    | ❌             | ⚠️         | ❌            | ✅   |\n| Minimal setup           | ✅             | ⚠️         | ❌            | ✅   |\n| Task caching            | ❌             | ✅         | ✅            | ❌   |\n\n**When to choose mise:**\n\n- ✅ Polyglot monorepos (multiple languages)\n- ✅ You want unified tool + task management\n- ✅ You prefer simplicity over maximum performance\n- ✅ You're already using mise for tool management\n\n**When to consider alternatives:**\n\n- You're exclusively JavaScript/TypeScript → Nx or Turborepo might offer more JS-specific features\n- You're at Google/Meta scale with thousands of engineers → Bazel or Buck2 offer distributed build infrastructure\n- You need advanced task caching → Nx, Turborepo, or Bazel offer sophisticated caching systems\n\nThe best tool is the one that fits your team's needs. mise's Monorepo Tasks is designed for teams who want powerful monorepo management without the complexity overhead, especially when working across multiple languages.\n\n## Task Templates\n\nFor monorepos with similar task patterns across projects, [task templates](/tasks/templates) allow you to define reusable task definitions at the monorepo root:\n\n```toml\n# Root mise.toml\n[settings]\nexperimental = true\nexperimental_monorepo_root = true\n\n[task_templates.\"python:build\"]\nrun = \"uv build\"\ntools = { python = \"3.12\", uv = \"latest\" }\n\n[task_templates.\"python:test\"]\nrun = \"pytest\"\ntools = { python = \"3.12\" }\ndepends = [\"build\"]\n```\n\nProjects can then extend these templates:\n\n```toml\n# packages/api/mise.toml\n[tasks.build]\nextends = \"python:build\"\n\n[tasks.test]\nextends = \"python:test\"\nrun = \"pytest --cov\"  # Override with coverage\n```\n\nSee [Task Templates](/tasks/templates) for complete documentation.\n\n## Related\n\n- [Task Templates](/tasks/templates) - Reusable task definitions\n- [Task Configuration](/tasks/task-configuration) - All task configuration options\n- [Running Tasks](/tasks/running-tasks) - How to execute tasks\n- [Configuration](/configuration) - General mise configuration\n"
  },
  {
    "path": "docs/tasks/running-tasks.md",
    "content": "# Running Tasks\n\nSee available tasks with `mise tasks`. To show tasks hidden with property `hide=true`, use the option `--hidden`.\n\nList dependencies of tasks with `mise tasks deps [tasks]...`.\n\nRun a task with `mise tasks run <task>`, `mise run <task>`, `mise r <task>`, or just `mise <task>`—however\nthat last one you should never put into scripts or documentation because if mise ever adds a command with that name in a\nfuture mise version, the task will be shadowed and must be run with one of the other forms.\n\nMost mise users will have an alias for `mise run` like `alias mr='mise run'`.\n\nBy default, tasks will execute with a maximum of 4 parallel jobs. Customize this with the `--jobs` option,\n`jobs` setting or `MISE_JOBS` environment variable. The output normally will be by line, prefixed with the task\nlabel. By printing line-by-line we avoid interleaving output from parallel executions. However, if\n--jobs == 1, the output will be set to `interleave`.\n\nTo just print stdout/stderr directly, use `--interleave`, the `task.output` setting, or `MISE_TASK_OUTPUT=interleave`.\n\nStdin is not read by default. To enable this, set `raw = true` on the task that needs it. This will prevent\nit running in parallel with any other task—a RWMutex will get a write lock in this case. This also prevents redactions applied to the output.\n\nExtra arguments will be passed to the task, for example, if we want to run in release mode:\n\n```bash\nmise run build --release\n```\n\nIf there are multiple commands, the args are only passed to the last command.\n\n:::tip\nYou can define arguments/flags for tasks which will provide validation, parsing, autocomplete, and documentation.\n\n- [Arguments in File Tasks](/tasks/file-tasks#arguments)\n- [Arguments in TOML Tasks](/tasks/toml-tasks#arguments)\n\nAutocomplete will work automatically for tasks if the `usage` CLI is installed and mise completions are working.\n\nMarkdown documentation can be generated with [`mise generate task-docs`](/cli/generate/task-docs).\n:::\n\nMultiple tasks/arguments can be separated with this `:::` delimiter:\n\n```bash\nmise run build arg1 arg2 ::: test arg3 arg4\n```\n\nmise will run the task named \"default\" if no task is specified—and you've created one named \"default\". You can also alias a different task to \"default\".\n\n```bash\nmise run\n```\n\n## Task Grouping\n\nTasks can be grouped semantically by using name prefixes separated with `:`s.\nFor example all testing related tasks may begin with `test:`. Nested grouping\ncan also be used to further refine groups and simplify pattern matching.\nFor example running `mise run test:**:local` will match`test:units:local`,\n`test:integration:local` and `test:e2e:happy:local`\n(See [Wildcards](#wildcards) for more information).\n\n## Wildcards\n\nGlob style wildcards are supported when running tasks or specifying tasks\ndependencies.\n\nAvailable Wildcard Patterns:\n\n- `?` matches any single character\n- `*` matches 0 or more characters\n- `**` matches 0 or more groups\n- `{glob1,glob2,...}` matches any of the comma-separated glob patterns\n- `[ab,...]` matches any of the characters or ranges `[a-z]`\n- `[!ab,...]` matches any character not in the character set\n\n### Examples\n\n`mise run generate:{completions,docs:*}`\n\nAnd with dependencies:\n\n```toml\n[tasks.\"lint:eslint\"] # using a \":\" means we need to add quotes\nrun = \"eslint .\"\n[tasks.\"lint:prettier\"]\nrun = \"prettier --check .\"\n[tasks.lint]\ndepends = [\"lint:*\"]\nwait_for = [\"render\"] # does not add as a dependency, but if it is already running, wait for it to finish\n```\n\n## Running on file changes\n\nIt's often handy to only execute a task if the files it uses changes. For example, we might only want\nto run `cargo build` if an \".rs\" file changes. This can be done with the following config:\n\n```toml\n[tasks.build]\ndescription = 'Build the CLI'\nrun = \"cargo build\"\nsources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed\noutputs = ['target/debug/mycli']\n```\n\nNow if `target/debug/mycli` is newer than `Cargo.toml` or any \".rs\" file, the task will be skipped. This uses last modified timestamps.\nIt wouldn't be hard to add checksum support.\n\n## Watching files\n\nRun a task when the source changes with [`mise watch`](/cli/watch.html)\n\n```bash\nmise watch build\n```\n\nCurrently, this just shells out to `watchexec` (which you can install however you want including with mise: `mise use -g watchexec@latest`.\nThis may change in the future.)\n\n## `mise run` shorthand\n\nTasks can be run with `mise run <TASK>` or `mise <TASK>`—if the name doesn't conflict with a mise command.\nBecause mise may later add a command with a conflicting name, it's recommended to use `mise run <TASK>` in\nscripts and documentation.\n\n## Execution order\n\nYou can use [depends](/tasks/task-configuration.html#depends), [wait_for](/tasks/task-configuration.html#wait-for) and [depends_post](/tasks/task-configuration.html#depends-post) to control the order of execution.\n\n```toml\n[tasks.build]\nrun = \"echo 'build'\"\n\n[tasks.test]\nrun = \"echo 'test'\"\ndepends = [\"build\"]\n```\n\nThis will ensure that the `build` task is run before the `test` task.\n\nYou can also define a mise task to run other tasks in parallel or in series:\n\n```toml\n[tasks.example1]\nrun = \"echo 'example1'\"\n\n[tasks.example2]\nrun = \"mise example2\"\n\n[tasks.example3]\nrun = \"echo 'example3'\"\n\n[tasks.one_by_one]\nrun = [\n    { task = \"example1\" }, # will wait for example1 to finish before running the next step\n    { tasks = [\"example2\", \"example3\"] }, # these 2 are run in parallel\n]\n```\n"
  },
  {
    "path": "docs/tasks/task-arguments.md",
    "content": "# Task Arguments\n\nTask arguments allow you to pass parameters to tasks, making them more flexible and reusable. There are three ways to define task arguments in mise, but only two are recommended for current use.\n\n## Recommended Methods\n\n### 1. Usage Field (Preferred) {#usage-field}\n\nThe **usage field** is the recommended approach for defining task arguments. It provides a clean, declarative syntax that works with both TOML tasks and file tasks.\n\nSee [Complete Usage Specification Reference](#complete-usage-specification-reference) for more details.\n\n#### Quick Example\n\n```mise-toml [mise.toml]\n[tasks.deploy]\ndescription = \"Deploy application\"\nusage = '''\narg \"<environment>\" help=\"Target environment\" {\n  choices \"dev\" \"staging\" \"prod\"\n}\nflag \"-v --verbose\" help=\"Enable verbose output\"\nflag \"--region <region>\" help=\"AWS region\" default=\"us-east-1\" env=\"AWS_REGION\"\n'''\n\nrun = '''\necho \"Deploying to ${usage_environment?} in ${usage_region?}\"\n[[ \"${usage_verbose?}\" == \"true\" ]] && set -x\n./deploy.sh \"${usage_environment?}\" \"${usage_region?}\"\n'''\n```\n\nArguments defined in the usage field are automatically available as environment variables prefixed with `usage_`:\n\n```shell\n# Execute with arguments\n$ mise run deploy staging --verbose --region us-west-2\n\n# Inside the task, these are available as:\n# $usage_environment = \"staging\"\n# $usage_verbose = \"true\"\n# $usage_region = \"us-west-2\"\n```\n\nIn addition to environment variables, **usage values are available inside Tera\ntemplates in task run scripts** via a `usage` map:\n\n```mise-toml [mise.toml]\n[tasks.deploy]\ndescription = \"Deploy application\"\nusage = '''\narg \"<environment>\" help=\"Target environment\"\nflag \"-v --verbose\" help=\"Enable verbose output\"\nflag \"--region <region>\" help=\"AWS region\" default=\"us-east-1\"\n'''\nrun = '''\necho \"Deploying to {{ usage.environment }} in {{ usage.region }}\"\n{% if usage.verbose %}\n  echo \"Verbose mode enabled\"\n{% endif %}\n'''\n```\n\nThe `usage` map uses **snake_case argument/flag names as keys** (just like the\n`usage_` environment variables). Names with `-` are converted to `_`, so a flag\nlike `--dry-run` becomes available as <span v-pre>`{{ usage.dry_run }}`</span>\nand `$usage_dry_run`. Variadic arguments/flags are exposed as arrays and can be\nused with Tera's `for` loops and filters like `length`. The `usage` map is\n**separate from** the deprecated Tera template functions (`arg()`, `option()`,\n`flag()`) described later on this page—you should not mix the two approaches in\nthe same task.\n\n**Help output example:**\n\n```shellsession\n$ mise run deploy --help\nDeploy application\n\nUsage: deploy <environment> [OPTIONS]\n\nArguments:\n  <environment>  Target environment [possible values: dev, staging, prod]\n\nOptions:\n  -v, --verbose          Enable verbose output\n      --region <region>  AWS region [env: AWS_REGION] [default: us-east-1]\n  -h, --help            Print help\n```\n\n### 2. File Task Headers {#file-task-headers}\n\nFor file tasks, you can define arguments directly in the file using special `#MISE` or `#USAGE` comment syntax:\n\n```bash [.mise/tasks/deploy]\n#!/usr/bin/env bash\n#MISE description \"Deploy application\"\n#USAGE arg \"<environment>\" help=\"Deployment environment\" {\n#USAGE   choices \"dev\" \"staging\" \"prod\"\n#USAGE }\n#USAGE flag \"--dry-run\" help=\"Preview changes without deploying\"\n#USAGE flag \"--region <region>\" help=\"AWS region\" default=\"us-east-1\" env=\"AWS_REGION\"\n\nENVIRONMENT=\"${usage_environment?}\"\nREGION=\"${usage_region?}\"\nDRY_RUN=\"${usage_dry_run:-false}\"\n\nif [[ \"$DRY_RUN\" == \"true\" ]]; then\n  echo \"DRY RUN: Would deploy to $ENVIRONMENT in $REGION\"\nelse\n  echo \"Deploying to $ENVIRONMENT in $REGION...\"\n  ./scripts/deploy.sh \"$ENVIRONMENT\" \"$REGION\"\nfi\n```\n\n::: tip Syntax Options\nUse `#MISE` (uppercase, recommended) or `#USAGE` for defining arguments in file tasks. `# [MISE]` or `# [USAGE]` are also accepted as workarounds for formatters.\n:::\n\n## Complete Usage Specification Reference\n\n### Positional Arguments (`arg`)\n\nPositional arguments are defined with `arg` and must be provided in order.\n\n#### Basic Syntax\n\n```kdl\narg \"<name>\" help=\"Description\"               // Required positional arg\narg \"[name]\" help=\"Description\"               // Optional positional arg\narg \"<file>\"                                  // Completed as filename\narg \"<dir>\"                                   // Completed as directory\n```\n\n#### With Defaults\n\n```kdl\narg \"<file>\" default=\"config.toml\"            // Default value if not provided\narg \"[output]\" default=\"out.txt\"              // Optional with default\n```\n\n#### Variadic Arguments\n\n```kdl\narg \"[files]\" var=#true                        // 0 or more files\narg \"<files>\" var=#true                        // 1 or more files (required)\narg \"<files>\" var=#true var_min=2              // At least 2 files required\narg \"<files>\" var=#true var_max=5              // Maximum 5 files allowed\narg \"<files>\" var=#true var_min=1 var_max=3    // Between 1 and 3 files\n```\n\n::: tip Handling Variadic Args with Spaces in Bash\nVariadic arguments are passed as a shell-escaped string. To properly handle arguments containing spaces as a bash array, wrap the variable in parentheses:\n\n```bash\n# Convert to bash array:\neval \"files=($usage_files)\"\n\n# Use as array:\nfor f in \"${files[@]}\"; do\n  echo \"Processing: $f\"\ndone\n\n# Or pass to commands:\ntouch \"${files[@]}\"\n```\n\n:::\n\n#### Environment Variable Backing\n\n```kdl\narg \"<token>\" env=\"API_TOKEN\"                 // Can be set via $API_TOKEN\narg \"<host>\" env=\"API_HOST\" default=\"localhost\"\n```\n\nPriority order: CLI argument > Environment variable > Default value\n\n#### Choices (Enum Values)\n\n```kdl\narg \"<level>\" {\n  choices \"debug\" \"info\" \"warn\" \"error\"\n}\narg \"<shell>\" {\n  choices \"bash\" \"zsh\" \"fish\"\n  help \"Shell type\"\n}\n```\n\n#### Advanced Features\n\n```kdl\narg \"<file>\" long_help=\"Extended help text shown with --help\"\n\n// Hidden from help output\narg \"<file>\" hide=#true\n```\n\n#### Double-Dash Behavior\n\n```kdl\n// Must use: mycli -- file.txt\narg \"<file>\" double_dash=\"required\"\n\n// Both work: mycli file.txt or mycli -- file.txt\narg \"<file>\" double_dash=\"optional\"\n\n// After first arg, behaves as if -- was used\narg \"<files>\" double_dash=\"automatic\"\n```\n\n### Flags (`flag`)\n\nFlags can be defined as booleans or as accepting values.\n\n#### Boolean Flags\n\n```kdl\nflag \"-f --force\"\nflag \"-v --verbose\" help=\"Enable verbose mode\"\nflag \"--dry-run\" help=\"Preview without executing\"\n```\n\n#### Short-Only or Long-Only\n\n```kdl\nflag \"-f\"                                     // Short flag only\nflag \"--force\"                                // Long flag only\n```\n\n#### Flag With Values\n\n```kdl\nflag \"-o --output <file>\" help=\"Output file\"\nflag \"--port <port>\" help=\"Server port\"\nflag \"--color <when>\" {\n  choices \"auto\" \"always\" \"never\"\n}\n```\n\n#### Flag With Defaults\n\n```kdl\nflag \"--force\" default=#true\nflag \"--format <format>\" help=\"Output format\" default=\"json\"\nflag \"--port <port>\" help=\"Server port\" default=\"8080\"\nflag \"--color <when>\" {\n  choices \"auto\" \"always\" \"never\"\n  default \"auto\"\n}\n```\n\n#### Count Flags\n\n```kdl\n// Can be repeated: -vvv\n// $usage_verbose = number of times used (e.g., 3)\nflag \"-v --verbose\" count=#true\n```\n\n#### Negation\n\n```kdl\nflag \"--color\" negate=\"--no-color\" default=#true\n// Default: $usage_color = \"true\"\n// With --no-color: $usage_color = \"false\"\n```\n\n#### Global Flags\n\n```kdl\n// Available on all subcommands (if using cmd structure)\nflag \"-v --verbose\" global=#true\n```\n\n#### Flag Advanced Features\n\n```kdl\nflag \"--verbose\" long_help=\"Extended help text\"\nflag \"--debug\" hide=#true                      // Hidden from help\n```\n\n### Completion (`complete`)\n\nCustom completion can be defined for any argument or flag by name:\n\n```kdl\narg \"<plugin>\"\ncomplete \"plugin\" run=\"mise plugins ls\"       // Complete with command output\n```\n\n#### With Descriptions\n\n```kdl\ncomplete \"plugin\" run=\"mycli plugins list\" descriptions=#true\n```\n\nOutput format (split on `:` for value and description):\n\n```\nnodejs:JavaScript runtime\npython:Python language\nruby:Ruby language\n```\n\n### Long Help Text\n\nFor detailed help text, use multi-line format:\n\n```mise-toml\n[tasks.complex]\nusage = '''\narg \"<input>\" {\n  help \"Input file to process\"\n  long_help \"\"\"\n  The input file should be in JSON or YAML format.\n\n  Supported schemas:\n  - schema-v1: Legacy format\n  - schema-v2: Current format (recommended)\n  - schema-v3: Experimental format\n\n  Example:\n    mise run complex data.json\n  \"\"\"\n}\nflag \"--format <fmt>\" {\n  help \"Output format\"\n  long_help \"\"\"\n  Supported output formats:\n  - json: JSON output (default)\n  - yaml: YAML output\n  - toml: TOML output\n  \"\"\"\n  choices \"json\" \"yaml\" \"toml\"\n  default \"json\"\n}\n'''\nrun = 'process-data \"${usage_input?}\" --format \"${usage_format?}\"'\n```\n\n### Hide Arguments\n\nHide arguments from help output (useful for deprecated or internal options):\n\n```kdl\narg \"<legacy_arg>\" hide=#true\nflag \"--internal-debug\" hide=#true\n```\n\n### Combining Features Example\n\n```mise-toml [mise.toml]\n[tasks.deploy]\ndescription = \"Deploy application to cloud\"\nusage = '''\n// Positional arguments\narg \"<environment>\" {\n  help \"Deployment environment\"\n  choices \"dev\" \"staging\" \"prod\"\n}\n\narg \"[services]\" {\n  help \"Services to deploy (default: all)\"\n  var #true\n  var_min 0\n}\n\n// Flags\nflag \"-v --verbose\" {\n  help \"Enable verbose logging\"\n  count #true\n  default 0\n}\n\nflag \"--dry-run\" help=\"Show what would be deployed without doing it\"\n\nflag \"--region <region>\" {\n  help \"Cloud region\"\n  env \"AWS_REGION\"\n  default \"us-east-1\"\n  choices \"us-east-1\" \"us-west-2\" \"eu-west-1\"\n}\n\nflag \"--skip-tests\" help=\"Skip running tests before deploy\"\n\nflag \"--force\" help=\"Force deployment even with warnings\"\n\n// Custom completions\ncomplete \"services\" run=\"mycli list-services\"\n'''\n\nrun = '''\n#!/usr/bin/env bash\nset -euo pipefail\n\n# Handle verbosity\nif [[ \"${usage_verbose?}\" -ge 2 ]]; then\n  set -x\nelif [[ \"${usage_verbose?}\" -ge 1 ]]; then\n  export VERBOSE=1\nfi\n\n# Validate environment\nENVIRONMENT=\"${usage_environment?}\"\nREGION=\"${usage_region?}\"\nDRY_RUN=\"${usage_dry_run:-false}\"\nSKIP_TESTS=\"${usage_skip_tests:-false}\"\nFORCE=\"${usage_force:-false}\"\n\necho \"Deploying to $ENVIRONMENT in $REGION\"\n\n# Run tests unless skipped\nif [[ \"$SKIP_TESTS\" != \"true\" ]]; then\n  echo \"Running tests...\"\n  npm test\nfi\n\n# Deploy services\nif [[ -n \"${usage_services?}\" ]]; then\n  echo \"Deploying services: ${usage_services?}\"\n  for service in ${usage_services?}; do\n    deploy_service \"$service\" \"$ENVIRONMENT\" \"$REGION\" \"$DRY_RUN\"\n  done\nelse\n  echo \"Deploying all services\"\n  deploy_all \"$ENVIRONMENT\" \"$REGION\" \"$DRY_RUN\"\nfi\n'''\n```\n\n## Bash Variable Expansion for Usage Variables {#bash-variable-expansion}\n\nWhen accessing usage-defined variables in bash scripts, use parameter expansion syntax to help [shellcheck](https://www.shellcheck.net/) understand these variables and provide default values for boolean flags.\n\n### Common Patterns\n\n| Syntax            | Behavior                     | Use Case                                           | Example                       |\n| ----------------- | ---------------------------- | -------------------------------------------------- | ----------------------------- |\n| `${var?}`         | Error if unset               | Required args or flags with defaults in usage spec | `${usage_profile?}`           |\n| `${var:?}`        | Error if unset or empty      | When you need to ensure non-empty values           | `${usage_target:?}`           |\n| `${var:-default}` | Use default if unset         | Boolean flags without `default=` in usage spec     | `${usage_clean:-false}`       |\n| `${var:=default}` | Set and use default if unset | When you want to set the variable for later use    | `${usage_dir:=.}`             |\n| `${var:+value}`   | Use value if set             | Conditional flag passing                           | `${usage_verbose:+--verbose}` |\n\n### Guidelines for Usage Variables\n\n#### Args and Flags with Defaults\n\nUse `${usage_var?}` since usage guarantees they'll be set:\n\n```bash\n# --profile has default=\"debug\" in usage spec\ncargo build --profile \"${usage_profile?}\"\n```\n\n#### Boolean Flags without Defaults\n\nUse `${usage_var:-false}` to provide a default value:\n\n```bash\n# --clean flag has no default in usage spec\nif [ \"${usage_clean:-false}\" = \"true\" ]; then\n  cargo clean\nfi\n```\n\n#### Required Arguments\n\nUse `${usage_var:?}` to ensure non-empty values:\n\n```bash\n# <target> is a required positional argument\ncargo build --target \"${usage_target:?}\"\n```\n\n#### Conditional Flags\n\nUse `${usage_var:+value}` to pass flags only when set:\n\n```bash\n# Only add --verbose if the flag was provided\nmycli deploy ${usage_verbose:+--verbose}\n```\n\nThese expansions help [shellcheck](https://www.shellcheck.net/) understand your script and prevent warnings about potentially unset variables while maintaining proper error handling.\n\n## Deprecated Method\n\n### Tera Template Functions <Badge type=\"danger\" text=\"deprecated\" /> {#tera-templates}\n\n::: danger Deprecated - Removal in 2026.11.0\nThe Tera template method for defining task arguments is **deprecated** and will be **removed in mise 2026.11.0**.\n\n**Why it's being removed:**\n\n- **Two-pass parsing issues**: Template functions return empty strings during spec collection, causing unexpected behavior when trying to use them as normal template values\n- **Complex escaping rules**: Shell escaping rules are confusing and error-prone\n- **Inconsistent behavior**: Doesn't work the same way between TOML and file tasks\n- **Poor user experience**: Mixes argument definitions with script logic\n\n**Migration required:** Please migrate to the [usage field](#usage-field) method before 2026.11.0.\n\n**Opt-out setting:** If you want to disable the two-pass parsing behavior immediately (before removal), you can set:\n\n```toml\n# ~/.config/mise/config.toml\n[settings]\ntask.disable_spec_from_run_scripts = true\n```\n\nOr via environment variable: `MISE_TASK_DISABLE_SPEC_FROM_RUN_SCRIPTS=1`\n\nWhen enabled, mise will only use the `usage` field for spec generation, ignoring any `arg()`, `option()`, or `flag()` functions in run scripts. See [Settings](/configuration/settings) for more details.\n:::\n\n<details>\n<summary>Click to see deprecated Tera template syntax (not recommended)</summary>\n\nPreviously, you could define arguments inline in run scripts using Tera template functions:\n\n```mise-toml [mise.toml]\n# ❌ DEPRECATED - Do not use\n[tasks.test]\nrun = 'cargo test {{arg(name=\"file\", default=\"all\")}}'\n```\n\n```mise-toml [mise.toml]\n# ❌ DEPRECATED - Do not use\n[tasks.build]\nrun = [\n    'cargo build {{option(name=\"profile\", default=\"dev\")}}',\n    './scripts/package.sh {{flag(name=\"verbose\")}}'\n]\n```\n\n**Problems with this approach:**\n\n1. **Empty strings during parsing**: During spec collection (first pass), template functions return empty strings, so you can't use them in templates like:\n\n   ```toml\n   # This doesn't work as expected!\n   run = 'echo \"File: {{arg(name=\"file\")}}\" > {{arg(name=\"file\")}}.log'\n   # First pass: 'echo \"File: \" > .log' (invalid!)\n   ```\n\n2. **Escaping complexity**: Different shell types require different escaping:\n\n   ```toml\n   # Escaping behavior varies by shell\n   run = 'cmd {{arg(name=\"file\")}}' # May or may not be properly escaped\n   ```\n\n3. **No help generation**: Doesn't generate proper `--help` output\n\n</details>\n\n### Migration Guide\n\nHere's how to migrate from Tera templates to the usage field:\n\n#### Example 1: Simple Arguments\n\n<div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;\">\n\n<div>\n\n**Old (Deprecated):**\n\n```mise-toml\n[tasks.test]\nrun = '''\ncargo test {{arg(\n  name=\"file\",\n  default=\"all\",\n  help=\"Test file\"\n)}}\n'''\n```\n\n</div>\n\n<div>\n\n**New (Preferred):**\n\n```mise-toml\n[tasks.test]\nusage = 'arg \"<file>\" help=\"Test file\" default=\"all\"'\nrun = 'cargo test ${usage_file?}'\n```\n\n</div>\n\n</div>\n\n#### Example 2: Multiple Arguments with Flags\n\n<div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;\">\n\n<div>\n\n**Old (Deprecated):**\n\n```mise-toml\n[tasks.build]\nrun = [\n  'cargo build {{arg(name=\"target\", default=\"debug\")}}',\n  './package.sh {{flag(name=\"verbose\")}}'\n]\n```\n\n</div>\n\n<div>\n\n**New (Preferred):**\n\n```mise-toml\n[tasks.build]\nusage = '''\narg \"<target>\" default=\"debug\"\nflag \"-v --verbose\"\n'''\nrun = [\n  'cargo build ${usage_target?}',\n  './package.sh ${usage_verbose?}'\n]\n```\n\n</div>\n\n</div>\n\n#### Example 3: Options with Choices\n\n<div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;\">\n\n<div>\n\n**Old (Deprecated):**\n\n```mise-toml\n[tasks.deploy]\nrun = '''\ndeploy {{option(\n  name=\"env\",\n  choices=[\"dev\", \"prod\"]\n)}} {{flag(name=\"force\")}}\n'''\n```\n\n</div>\n\n<div>\n\n**New (Preferred):**\n\n```mise-toml\n[tasks.deploy]\nusage = '''\nflag \"--env <env>\" {\n  choices \"dev\" \"prod\"\n}\nflag \"--force\"\n'''\nrun = 'deploy --env ${usage_env?} ${usage_force?}'\n```\n\n</div>\n\n</div>\n\n#### Example 4: Variadic Arguments\n\n<div style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;\">\n\n<div>\n\n**Old (Deprecated):**\n\n```mise-toml\n[tasks.lint]\nrun = 'eslint {{arg(name=\"files\", var=true)}}'\n```\n\n</div>\n\n<div>\n\n**New (Preferred):**\n\n```mise-toml\n[tasks.lint]\nusage = 'arg \"<files>\" var=#true'\nrun = 'eslint ${usage_files?}'\n```\n\n</div>\n\n</div>\n\n::: tip Handling Arguments with Spaces\nIf your variadic arguments may contain spaces, convert the variable to a bash array:\n\n```mise-toml\n[tasks.process]\nusage = 'arg \"<files>\" var=#true'\nrun = '''\neval \"files=($usage_files)\"\nfor f in \"${files[@]}\"; do\n  process \"$f\"\ndone\n'''\n```\n\n:::\n\n## See Also\n\n- [Task Configuration](/tasks/task-configuration) - Complete task configuration reference\n- [TOML Tasks](/tasks/toml-tasks) - TOML task syntax\n- [File Tasks](/tasks/file-tasks) - File-based task syntax\n- [Running Tasks](/tasks/running-tasks) - How to execute tasks\n- [Usage Spec Documentation](https://usage.jdx.dev/spec/) - Complete usage specification reference\n"
  },
  {
    "path": "docs/tasks/task-configuration.md",
    "content": "# Task Configuration\n\nThis is an exhaustive list of all the configuration options available for tasks in `mise.toml` or\nas file tasks.\n\n## Task properties\n\nAll examples are in toml-task format instead of file, however they apply in both except where otherwise noted.\n\n### `run`\n\n- **Type**: `string | (string | { task: string } | { tasks: string[] })[]`\n\nThe command(s) to run. This is the only required property for a task.\n\nYou can now mix scripts with task references:\n\n```mise-toml\n[tasks.grouped]\nrun = [\n  { task = \"t1\" },          # run t1 (with its dependencies)\n  { tasks = [\"t2\", \"t3\"] }, # run t2 and t3 in parallel (with their dependencies)\n  \"echo end\",               # then run a script\n]\n```\n\nSimple forms still work and are equivalent:\n\n```mise-toml\ntasks.a = \"echo hello\"\ntasks.b = [\"echo hello\"]\ntasks.c.run = \"echo hello\"\n[tasks.d]\nrun = \"echo hello\"\n[tasks.e]\nrun = [\"echo hello\"]\n```\n\n### `run_windows`\n\n- **Type**: `string | (string | { task: string } | { tasks: string[] })[]`\n\nWindows-specific variant of `run` supporting the same structured syntax:\n\n```mise-toml\n[tasks.build]\nrun = \"cargo build\"\nrun_windows = \"cargo build --features windows\"\n```\n\n### `description`\n\n- **Type**: `string`\n\nA description of the task. This is used in (among other places)\nthe help output, completions, `mise run` (without arguments), and `mise tasks`.\n\n```mise-toml\n[tasks.build]\ndescription = \"Build the CLI\"\nrun = \"cargo build\"\n```\n\n### `alias`\n\n- **Type**: `string | string[]`\n\nAn alias for the task so you can run it with `mise run <alias>` instead of the full task name.\n\n```mise-toml\n[tasks.build]\nalias = \"b\" # run with `mise run b`\nrun = \"cargo build\"\n```\n\n### `depends`\n\n- **Type**: `string | string[] | { task: string, args?: string[], env?: { [key]: string } }[]`\n\nTasks that must be run before this task. This is a list of task names or aliases. Arguments can be\npassed to the task, e.g.: `depends = [\"build --release\"]`. If multiple tasks have the same dependency,\nthat dependency will only be run once. mise will run whatever it can in parallel (up to [`--jobs`](/cli/run))\nthrough the use of `depends` and related properties.\n\n```mise-toml\n[tasks.build]\nrun = \"cargo build\"\n[tasks.test]\ndepends = [\"build\"]\nrun = \"cargo test\"\n```\n\n#### Passing environment variables to dependencies\n\nYou can pass environment variables to specific dependencies using two syntaxes:\n\n**Shell-style inline:**\n\n```mise-toml\n[tasks.test]\ndepends = [\"NODE_ENV=test setup\"]\nrun = \"npm test\"\n\n[tasks.setup]\nrun = 'echo \"Setting up for $NODE_ENV\"'\n```\n\n**Structured object format:**\n\n```mise-toml\n[tasks.test]\ndepends = [\n  { task = \"setup\", env = { NODE_ENV = \"test\", DEBUG = \"true\" } }\n]\nrun = \"npm test\"\n```\n\nThe structured format also supports combining env vars with arguments:\n\n```mise-toml\n[tasks.deploy]\ndepends = [\n  { task = \"build\", args = [\"--release\"],\n    env = { RUSTFLAGS = \"-C opt-level=3\" } }\n]\nrun = \"./deploy.sh\"\n```\n\nNote: These environment variables are passed only to the specified dependency, not to the current task or other dependencies.\n\n### `depends_post`\n\n- **Type**: `string | string[] | { task: string, args?: string[], env?: { [key]: string } }[]`\n\nLike `depends` but these tasks run _after_ this task and its dependencies complete. For example, you\nmay want a `postlint` task that you can run individually without also running `lint`:\n\n```mise-toml\n[tasks.lint]\nrun = \"eslint .\"\ndepends_post = [\"postlint\"]\n[tasks.postlint]\nrun = \"echo 'linting complete'\"\n```\n\nSupports the same argument and environment variable syntax as `depends`.\n\n### `wait_for`\n\n- **Type**: `string | string[] | { task: string, args?: string[], env?: { [key]: string } }[]`\n\nSimilar to `depends`, it will wait for these tasks to complete before running however they won't be\nadded to the list of tasks to run. This is essentially optional dependencies.\n\n```mise-toml\n[tasks.lint]\nwait_for = [\"render\"] # creates some js files, so if it's running, wait for it to finish\nrun = \"eslint .\"\n```\n\nSupports the same argument and environment variable syntax as `depends`.\n\n`wait_for` matches tasks differently depending on whether args or env vars are specified:\n\n- `wait_for = [\"setup\"]` — matches by name, regardless of args or env overrides. If another task runs `depends = [\"DEBUG=1 setup\"]`, this will still match and wait for it.\n- `wait_for = [\"setup arg1\"]` or `wait_for = [\"DEBUG=1 setup\"]` — matches only tasks running with that exact args/env configuration.\n\n### `env`\n\n- **Type**: `{ [key]: string | int | bool }`\n\nEnvironment variables specific to this task. These will not be passed to `depends` tasks.\n\n```mise-toml\n[tasks.test]\nenv.TEST_ENV_VAR = \"ABC\"\nrun = [\n    \"echo $TEST_ENV_VAR\",\n    \"mise run some-other-task\", # running tasks like this _will_ have TEST_ENV_VAR set of course\n]\n```\n\n### `tools`\n\n- **Type**: `{ [key]: string }`\n\nTools to install and activate before running the task. This is useful for tasks that require a specific tool to be\ninstalled or a tool with a different version. It will only be used for that task, not dependencies.\n\n```mise-toml\n[tasks.build]\ntools.rust = \"1.50.0\"\nrun = \"cargo build\"\n```\n\n### `dir`\n\n- **Type**: `string`\n- **Default**: <code v-pre>\"{{ config_root }}\"</code> - the directory containing `mise.toml`, or in the case of something like `~/src/myproj/.config/mise.toml`, it will be `~/src/myproj`.\n\nThe directory to run the task from. The most common way this is used is when you want the task to execute\nin the user's current directory:\n\n```mise-toml\n[tasks.test]\ndir = \"{{cwd}}\"\nrun = \"cargo test\"\n```\n\n### `hide`\n\n- **Type**: `bool`\n- **Default**: `false`\n\nHide the task from help, completion, and other output like `mise tasks`. Useful for deprecated or internal\ntasks you don't want others to easily see.\n\n```mise-toml\n[tasks.internal]\nhide = true\nrun = \"echo my internal task\"\n```\n\n### `confirm`\n\n- **Type**: `string`\n\nA message to show before running the task. This is useful for tasks that are destructive or take a long\ntime to run. The user will be prompted to confirm before the task is run.\n\n```mise-toml\n[tasks.release]\nconfirm = \"Are you sure you want to cut a release?\"\ndescription = 'Cut a new release'\nfile = 'scripts/release.sh'\n```\n\nThe confirm message supports Tera templates and can reference usage arguments:\n\n```mise-toml\n[tasks.deploy]\nusage = '''\narg \"<environment>\" help=\"Environment to deploy to\"\nflag \"--force\" help=\"Force deployment\"\n'''\nconfirm = \"Deploy to {{ usage.environment }}?{% if usage.force %} (forced){% endif %}\"\nrun = \"deploy.sh ${usage_environment}\"\n```\n\n### `raw`\n\n- **Type**: `bool`\n- **Default**: `false`\n\nConnects the task directly to the shell's stdin/stdout/stderr. This is useful for tasks that need to\naccept input or output in a way that mise's normal task handling doesn't support. This is not recommended\nto use because it really screws up the output whenever mise runs tasks in parallel. Ensure when using\nthis that no other tasks are running at the same time.\n\nIn the future we could have a property like `single = true` or something that prevents multiple tasks\nfrom running at the same time. If that sounds useful, search/file a ticket.\n\n### `interactive`\n\n- **Type**: `bool`\n- **Default**: `false`\n\nConnects the task directly to the shell's stdin/stdout/stderr. Instead of the broad `raw` setting that forces\nsingle-threaded execution (by setting `jobs = 1`), `interactive` tasks acquire an exclusive global write lock,\nensuring sole access to standard I/O. Concurrently, non-interactive tasks can proceed in parallel, significantly\nenhancing task concurrency and user experience for interactive processes without sacrificing system stability.\n\n### `sources`\n\n- **Type**: `string | string[]`\n\nFiles or directories that this task uses as input, if this and `outputs` is defined, mise will skip\nexecuting tasks where the modification time of the oldest output file is newer than the modification\ntime of the newest source file. This is useful for tasks that are expensive to run and only need to\nbe run when their inputs change.\n\nThe task itself will be automatically added as a source, so if you edit the definition that will also\ncause the task to be run.\n\nThis is also used in `mise watch` to know which files/directories to watch.\n\nThis can be specified with relative paths to the config file and/or with glob patterns, e.g.: `src/**/*.rs`.\nEnsure you don't go crazy with adding a ton of files in a glob though—mise has to scan each and every one to check\nthe timestamp.\n\n```mise-toml\n[tasks.build]\nrun = \"cargo build\"\nsources = [\"Cargo.toml\", \"src/**/*.rs\"]\noutputs = [\"target/debug/mycli\"]\n```\n\nRunning the above will only execute `cargo build` if `mise.toml`, `Cargo.toml`, or any \".rs\" file in the `src` directory\nhas changed since the last build.\n\nThe [`task_source_files`](../templates.md#task-source-files) function can be used to iterate over a task's\n`sources` within its template context.\n\n### `outputs`\n\n- **Type**: `string | string[] | { auto = true }`\n- **Default**: `{ auto = true }`\n\nThe counterpart to `sources`, these are the files or directories that the task will create/modify after\nit executes.\n\n`auto = true` is an alternative to specifying output files manually. In that case, mise will touch\nan internally tracked file based on the hash of the task definition (stored in `~/.local/state/mise/task-outputs/<hash>` if you're curious).\nThis is useful if you want `mise run` to execute when sources change but don't want to have to manually `touch`\na file for `sources` to work.\n\n```mise-toml\n[tasks.build]\nrun = \"cargo build\"\nsources = [\"Cargo.toml\", \"src/**/*.rs\"]\noutputs = { auto = true } # this is the default when sources is defined\n```\n\n### `shell`\n\n- **Type**: `string`\n- **Default**: [`unix_default_inline_shell_args`](/configuration/settings.html#unix_default_inline_shell_args) or [`windows_default_inline_shell_args`](/configuration/settings.html#windows_default_inline_shell_args)\n- **Note**: Only applies to toml-tasks.\n\nThe shell to use to run the task. This is useful if you want to run a task with a different shell than\nthe default such as `fish`, `zsh`, or `pwsh`. Generally though, it's recommended to use a [shebang](./toml-tasks#shell-shebang) instead\nbecause that will allow IDEs with mise support to show syntax highlighting and linting for the script.\n\n```mise-toml\n[tasks.hello]\nrun = '''\n#!/usr/bin/env node\nconsole.log('hello world')\n'''\n```\n\n### `quiet`\n\n- **Type**: `bool`\n- **Default**: `false`\n\nSuppress mise's output for the task such as showing the command that is run, e.g.: `[build] $ cargo build`.\nWhen this is set, mise won't show any output other than what the script itself outputs. If you'd also\nlike to hide even the output that the task emits, use [`silent`](#silent).\n\n### `silent`\n\n- **Type**: `bool | \"stdout\" | \"stderr\"`\n- **Default**: `false`\n\nSuppress all output from the task. If set to `\"stdout\"` or `\"stderr\"`, only that stream will be suppressed.\n\n### `usage`\n\n- **Type**: `string`\n\n::: tip\nFor comprehensive information about task arguments and the usage field, see the dedicated [Task Arguments](/tasks/task-arguments) page.\n:::\n\nMore advanced usage specs can be added to the task's `usage` field. This only applies to toml-tasks.\n\n```mise-toml\n[tasks.test]\nusage = '''\narg \"<file>\" help=\"The file to test\" default=\"src/main.rs\"\n'''\nrun = 'cargo test ${usage_file?}'\n```\n\n#### Environment Variable Support for Args and Flags\n\nBoth args and flags in usage specs can specify an environment variable as an alternative source for their value. This allows task arguments to be provided through environment variables when not specified on the command line.\n\nThe precedence order is:\n\n1. CLI arguments/flags (highest priority)\n2. Environment variables (middle priority)\n3. Default values (lowest priority)\n\n**For positional arguments:**\n\n```mise-toml\n[tasks.deploy]\nusage = '''\narg \"<environment>\" env=\"DEPLOY_ENV\" help=\"Target environment\" default=\"staging\"\narg \"<region>\" env=\"AWS_REGION\" help=\"AWS region\" default=\"us-east-1\"\n'''\n\nrun = '''\necho \"Deploying to ${usage_environment?} in ${usage_region?}\"\n'''\n```\n\nUsage examples:\n\n```bash\n# Using CLI args (highest priority)\nmise run deploy production us-west-2\n\n# Using environment variables\nexport DEPLOY_ENV=production\nexport AWS_REGION=us-west-2\nmise run deploy\n\n# Using defaults (lowest priority)\nmise run deploy  # deploys to staging in us-east-1\n\n# CLI overrides environment variable\nexport DEPLOY_ENV=staging\nmise run deploy production  # deploys to production\n```\n\n**For flags:**\n\n```mise-toml\n[tasks.build]\nusage = '''\nflag \"-p --profile <profile>\" env=\"BUILD_PROFILE\" help=\"Build profile\" default=\"dev\"\nflag \"-v --verbose\" env=\"VERBOSE\" help=\"Verbose output\"\n'''\n\nrun = '''\necho \"Building with profile: ${usage_profile?}\"\necho \"Verbose: ${usage_verbose:-false}\"\n'''\n```\n\nUsage examples:\n\n```bash\n# Using CLI flags\nmise run build --profile release --verbose\n\n# Using environment variables\nexport BUILD_PROFILE=release\nexport VERBOSE=true\nmise run build\n\n# Mixed usage - env var provides one, CLI provides another\nexport BUILD_PROFILE=release\nmise run build --verbose\n```\n\n**File tasks** (tasks defined as executable files in `mise-tasks/` or `.mise/tasks/`) also support the `env` attribute:\n\n```bash\n#!/usr/bin/env bash\n#USAGE arg \"<input>\" env=\"INPUT_FILE\" help=\"Input file to process\"\n#USAGE flag \"-o --output <file>\" env=\"OUTPUT_FILE\" help=\"Output file\" default=\"out.txt\"\n\necho \"Processing ${usage_input?} -> ${usage_output?}\"\n```\n\n**Required arguments:**\n\nEnvironment variables can satisfy required argument checks. If an argument is marked as required (using angle brackets `<arg>`), providing its value through the environment variable specified in the `env` attribute fulfills that requirement:\n\n```mise-toml\n[tasks.deploy]\nusage = '''\narg \"<api-key>\" env=\"API_KEY\" help=\"API key for deployment\"\n'''\nrun = 'deploy --api-key ${usage_api_key?}'\n```\n\n```bash\n# This will fail - no API_KEY provided\nmise run deploy\n\n# This succeeds - API_KEY provided via environment\nexport API_KEY=secret123\nmise run deploy\n\n# This also succeeds - provided via CLI\nmise run deploy secret123\n```\n\n## Vars\n\nVars are variables that can be shared between tasks like environment variables but they are not\npassed as environment variables to the scripts. They are defined in the `vars` section of the\n`mise.toml` file.\n\n```mise-toml\n[vars]\ne2e_args = '--headless'\n\n[tasks.test]\nrun = './scripts/test-e2e.sh {{vars.e2e_args}}'\n```\n\nTasks can also define task-local vars that override config vars for that task:\n\n```mise-toml\n[tasks.test]\nvars = { e2e_args = \"--headed\" }\nrun = './scripts/test-e2e.sh {{vars.e2e_args}}'\n```\n\nLike most configuration in mise, vars can be defined across several files. So for example, you could\nput some vars in your global mise config `~/.config/mise/config.toml`, use them in a task at\n`~/src/work/myproject/mise.toml`. You can also override those vars in \"later\" config files such\nas `~/src/work/myproject/mise.local.toml` and they will be used inside tasks of any config file.\n\nAs of this writing vars are only supported in TOML tasks. I want to add support for file tasks, but\nI don't want to turn all file tasks into tera templates just for this feature.\n\n## `[task_config]` options\n\nOptions available in the top-level `mise.toml` `[task_config]` section. These apply to all tasks which\nare included by that config file or use the same root directory, e.g.: `~/src/myprojec/mise.toml`'s `[task_config]`\napplies to file tasks like `~/src/myproject/mise-tasks/mytask` but not to tasks in `~/src/myproject/subproj/mise.toml`.\n\n### `task_config.dir`\n\nChange the default directory tasks are run from.\n\n```toml\n[task_config]\ndir = \"{{cwd}}\"\n```\n\n### `task_config.includes`\n\nAdd toml files containing toml tasks, or file tasks to include when looking for tasks.\n\n```toml\n[task_config]\nincludes = [\n    \"tasks.toml\", # a task toml file\n    \"mytasks\"     # a directory containing file tasks (in addition to the default file tasks directories)\n]\n```\n\nIf using included task toml files, note that they have a different format than the `mise.toml` file. They are just a list of tasks.\nThe file should be the same format as the `[tasks]` section of `mise.toml` but without the `[task]` prefix:\n\n::: code-group\n\n```mise-toml [tasks.toml]\ntask1 = \"echo task1\"\ntask2 = \"echo task2\"\ntask3 = \"echo task3\"\n\n[task4]\nrun = \"echo task4\"\nvars = { target = \"linux\" }\n```\n\n:::\n\nIf you want auto-completion/validation in included toml tasks files, you can use the following JSON schema: <https://mise.jdx.dev/schema/mise-task.json>\n\n#### Remote Git Includes <Badge type=\"warning\" text=\"experimental\" />\n\nYou can include directories of tasks from git repositories using the `git::` URL syntax:\n\n::: code-group\n\n```mise-toml [ssh]\n[task_config]\nincludes = [\n    \"git::ssh://git@github.com/myorg/shared-tasks.git//tasks?ref=v1.0.0\"\n]\n```\n\n```mise-toml [https]\n[task_config]\nincludes = [\n    \"git::https://github.com/myorg/shared-tasks.git//tasks?ref=main\"\n]\n```\n\n:::\n\nURL format: `git::<protocol>://<url>//<path>?<ref>`\n\nRequired fields:\n\n- `protocol`: The git protocol (ssh or https).\n- `url`: The git repository URL.\n- `path`: The path to the directory in the repository.\n\nOptional fields:\n\n- `ref`: The git reference (branch, tag, commit). Defaults to the repository's default branch.\n\nThe repository will be cloned and cached in `MISE_CACHE_DIR/remote-git-tasks-cache`. Tasks from the included directory will be loaded as if they were local file tasks. You can disable caching with `MISE_TASK_REMOTE_NO_CACHE=true` or the `--no-cache` flag.\n\n## Monorepo Support <Badge type=\"warning\" text=\"experimental\" />\n\nmise supports monorepo-style task organization with target path syntax. Enable it by setting `experimental_monorepo_root = true` in your root `mise.toml`.\n\nFor complete documentation on monorepo tasks including:\n\n- Task path syntax and wildcards\n- Tool layering from parent configs\n- Performance tuning\n- Best practices and troubleshooting\n\nSee the dedicated [Monorepo Tasks](/tasks/monorepo) documentation.\n\n## `redactions` <Badge type=\"warning\" text=\"experimental\" />\n\n- **Type**: `string[]`\n\nRedactions are a way to hide sensitive information from the output of tasks. This is useful for things like\nAPI keys, passwords, or other sensitive information that you don't want to accidentally leak in logs or\nother output.\n\nA list of environment variables to redact from the output.\n\n```toml\nredactions = [\"API_KEY\", \"PASSWORD\"]\n```\n\nRunning the above task will output `echo [redacted]` instead.\n\nYou can also specify these as a glob pattern, e.g.: `redactions.env = [\"SECRETS_*\"]`.\n\n## `[vars]` options\n\nVars are variables that can be shared between tasks like environment variables but they are not\npassed as environment variables to the scripts. They are defined in the `vars` section of the\n`mise.toml` file.\n\n```mise-toml\n[vars]\ne2e_args = '--headless'\n[tasks.test]\nrun = './scripts/test-e2e.sh {{vars.e2e_args}}'\nvars = { e2e_args = '--headed' }\n```\n\nThe task-level `vars` override any config-level vars with the same name. In the example above, `e2e_args` resolves to `'--headed'` instead of the config-level `'--headless'`.\n\nLike `[env]`, vars can also be read in as a file:\n\n```toml\n[vars]\n_.file = \".env\"\n```\n\n[Secrets](/environments/secrets/) are also supported as vars.\n\n## Task Configuration Settings\n\n<script setup>\nimport Settings from '/components/settings.vue';\n</script>\n\nThe following settings control task behavior. These can be set globally in `~/.config/mise/config.toml` or per-project in `mise.toml`:\n\n<Settings :level=\"3\" prefix=\"task\" />\n"
  },
  {
    "path": "docs/tasks/templates.md",
    "content": "# Task Templates\n\n::: warning\nThis feature is experimental and requires `experimental = true` in your settings.\n:::\n\nTask templates allow you to define reusable task definitions that can be extended by multiple tasks. This is particularly useful in monorepos or projects with similar task patterns across different components.\n\n## Defining Templates\n\nTemplates are defined in the `[task_templates.*]` section of your `mise.toml`:\n\n```toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\ndescription = \"Build a Python project\"\nrun = \"uv build\"\ntools = { python = \"3.12\", uv = \"latest\" }\nenv = { PYTHONPATH = \"src\" }\n\n[task_templates.\"python:test\"]\ndescription = \"Run Python tests\"\nrun = \"pytest\"\ntools = { python = \"3.12\" }\ndepends = [\"build\"]\n```\n\n## Extending Templates\n\nTasks can extend templates using the `extends` field:\n\n```toml\n[tasks.build]\nextends = \"python:build\"\n\n[tasks.test]\nextends = \"python:test\"\nrun = \"pytest --cov\"  # Override run while keeping tools, depends\n```\n\n## Template Naming\n\nTemplates use colon (`:`) separators for namespacing, similar to task naming conventions in monorepos:\n\n- `python:build`\n- `python:test`\n- `rust:cargo:build`\n- `node:npm:test`\n\n## Merge Semantics\n\nWhen a task extends a template, fields are merged according to these rules:\n\n| Field                                   | Behavior                                                    |\n| --------------------------------------- | ----------------------------------------------------------- |\n| `run`, `run_windows`                    | Local overrides completely                                  |\n| `tools`                                 | Deep merge (local tools added/override template)            |\n| `env`                                   | Deep merge (local env added/override template)              |\n| `depends`, `depends_post`, `wait_for`   | Local overrides completely (not merged)                     |\n| `dir`                                   | Local overrides; defaults to config_root if not in template |\n| `sources`, `outputs`                    | Local overrides completely                                  |\n| `description`, `shell`, `timeout`, etc. | Local overrides template (if set)                           |\n| `quiet`, `hide`, `raw`                  | Not carried over (must be set explicitly in task)           |\n\n### Example: Deep Merge for Tools\n\n```toml\n[task_templates.\"fullstack:build\"]\ntools = { python = \"3.12\", node = \"18\" }\n\n[tasks.build]\nextends = \"fullstack:build\"\ntools = { node = \"20\" }  # Override node, keep python from template\n# Result: tools = { python = \"3.12\", node = \"20\" }\n```\n\n### Example: Deep Merge for Env\n\n```toml\n[task_templates.\"python:build\"]\nenv = { PYTHONPATH = \"src\", DEBUG = \"0\" }\n\n[tasks.build]\nextends = \"python:build\"\nenv = { DEBUG = \"1\" }  # Override DEBUG, keep PYTHONPATH from template\n# Result: env = { PYTHONPATH = \"src\", DEBUG = \"1\" }\n```\n\n### Example: Complete Override for Depends\n\n```toml\n[task_templates.\"python:test\"]\ndepends = [\"lint\", \"typecheck\"]\n\n[tasks.test]\nextends = \"python:test\"\ndepends = [\"build\"]  # Completely replaces template depends\n# Result: depends = [\"build\"] (lint and typecheck NOT included)\n```\n\n## Tera Templating\n\nTemplates support Tera templating, rendered with the **using project's context**:\n\n```toml\n[task_templates.\"python:build\"]\ndescription = \"Build Python project\"\ndir = \"{{ config_root }}\"  # Resolves to the PROJECT's directory\nrun = \"uv build\"\nenv = { PROJECT = \"{{ config_root | basename }}\" }\n```\n\nAvailable variables (same as regular tasks):\n\n- <code v-pre>{{ config_root }}</code> - The project using the template (NOT where template is defined)\n- <code v-pre>{{ env.VAR }}</code> - Environment variables\n- <code v-pre>{{ cwd }}</code> - Current working directory\n- <code v-pre>{{ vars.* }}</code> - User-defined variables from config\n\n## Monorepo Usage\n\nTask templates are especially useful in monorepos where multiple packages share similar build patterns:\n\n```toml\n# Root mise.toml\n[settings]\nexperimental = true\nexperimental_monorepo_root = true\n\n[task_templates.\"python:build\"]\nrun = \"uv build\"\ntools = { python = \"3.12\", uv = \"latest\" }\n\n[task_templates.\"python:test\"]\nrun = \"pytest\"\ntools = { python = \"3.12\" }\ndepends = [\"build\"]\n\n[task_templates.\"python:lint\"]\nrun = \"ruff check .\"\ntools = { python = \"3.12\", ruff = \"latest\" }\n```\n\n```toml\n# packages/api/mise.toml\n[tasks.build]\nextends = \"python:build\"\n\n[tasks.test]\nextends = \"python:test\"\nrun = \"pytest --cov\"  # Add coverage\n\n[tasks.lint]\nextends = \"python:lint\"\n```\n\n```toml\n# packages/worker/mise.toml\n[tasks.build]\nextends = \"python:build\"\n\n[tasks.test]\nextends = \"python:test\"\n\n[tasks.lint]\nextends = \"python:lint\"\n```\n\n## Future Enhancements\n\nThe following features are planned for future releases:\n\n- **Global templates**: Define templates in `~/.config/mise/config.toml` for use across all projects\n- **Template packages**: Import templates from external sources\n- **Pattern-matching rules**: Auto-apply templates based on file detection (e.g., auto-apply `python:*` templates when `pyproject.toml` exists)\n- **File task templates**: Define templates as standalone script files, similar to [file tasks](/tasks/file-tasks)\n"
  },
  {
    "path": "docs/tasks/toml-tasks.md",
    "content": "# TOML-based Tasks\n\nTasks can be defined in `mise.toml` files in different ways. Trivial tasks can be written into a `[tasks]` section, while more detailed tasks each get their own section.\n\n## Trivial task examples\n\n```mise-toml [mise.toml]\nbuild = \"cargo build\"\ntest = \"cargo test\"\nlint = \"cargo clippy\"\n```\n\n## Detailed task examples\n\n```mise-toml [mise.toml]\n[tasks.cleancache]\nrun = \"rm -rf .cache\"\nhide = true # hide this task from the list\n\n[tasks.clean]\ndepends = ['cleancache']\nrun = \"cargo clean\" # runs as a shell command\n\n[tasks.build]\ndescription = 'Build the CLI'\nrun = \"cargo build\"\nalias = 'b' # `mise run b`\n\n[tasks.test]\ndescription = 'Run automated tests'\n# multiple commands are run in series\nrun = [\n    'cargo test',\n    './scripts/test-e2e.sh',\n]\ndir = \"{{cwd}}\" # run in user's cwd, default is the project's base directory\n\n[tasks.lint]\ndescription = 'Lint with clippy'\nenv = { RUST_BACKTRACE = '1' } # env vars for the script\n# you can specify a multiline script instead of individual commands\nrun = '''\n#!/usr/bin/env bash\ncargo clippy\n'''\n\n[tasks.ci] # only dependencies to be run\ndescription = 'Run CI tasks'\ndepends = ['build', 'lint', 'test']\n\n[tasks.release]\nconfirm = 'Are you sure you want to cut a new release?'\ndescription = 'Cut a new release'\nfile = 'scripts/release.sh' # execute an external script\n```\n\nYou can use [environment variables](/environments/) or [`vars`](/tasks/task-configuration.html#vars-options) to define common arguments:\n\n```mise-toml [mise.toml]\n[env]\nVERBOSE_ARGS = '--verbose'\n\n# Vars can be shared between tasks like environment variables,\n# but they are not passed as environment variables to the scripts\n[vars]\ne2e_args = '--headless'\n\n[tasks.test]\nrun = './scripts/test-e2e.sh {{vars.e2e_args}} $VERBOSE_ARGS'\n```\n\n## Adding tasks\n\nYou can edit the `mise.toml` file directly or using [`mise tasks add`](/cli/tasks/add)\n\n```shell\nmise tasks add pre-commit --depends \"test\" --depends \"render\" -- echo pre-commit\n```\n\nwill add the following to `mise.toml`:\n\n```shell\n[tasks.pre-commit]\ndepends = [\"test\", \"render\"]\nrun = \"echo pre-commit\"\n```\n\n## Common options\n\nFor an exhaustive list, see [task configuration](/tasks/task-configuration).\n\n### Run command\n\nProvide the script to run. Can be a single command or an array of commands:\n\n```mise-toml\n[tasks.test]\nrun = 'cargo test'\n```\n\nCommands are run in series. If a command fails, the task will stop and the remaining commands will not run.\n\n```mise-toml\n[tasks.test]\nrun = [\n    'cargo test',\n    './scripts/test-e2e.sh',\n]\n```\n\nYou can specify an alternate command to run on Windows by using the `run_windows` key:\n\n```mise-toml\n[tasks.test]\nrun = 'cargo test'\nrun_windows = 'cargo test --features windows'\n```\n\n### Specifying which directory to use\n\nThe [`dir`](/tasks/task-configuration.html#dir) property determines the `cwd` in which the task is executed. You can use the directory\nfrom where the task was run with <span v-pre>`dir = \"{{cwd}}\"`</span>:\n\n```mise-toml\n[tasks.test]\nrun = 'cargo test'\ndir = \"{{cwd}}\"\n```\n\nAlso, `MISE_ORIGINAL_CWD` is set to the original working directory and will be passed to the task.\n\n### Adding a description and alias\n\nYou can add a description to a task and alias for a task.\n\n```mise-toml\n[tasks.build]\ndescription = 'Build the CLI'\nrun = \"cargo build\"\nalias = 'b' # `mise run b`\n```\n\n- This alias can be used to run the task\n- The description will be displayed when running [`mise tasks ls`](/cli/tasks/ls.html) or [`mise run`](/cli/run.html) with no arguments.\n\n```shell\n❯ mise run\nTasks\n# Select a task to run\n# > build  Build the CLI\n#   test   Run the tests\n```\n\n### Dependencies\n\nYou can specify dependencies for a task. Dependencies are run before the task itself. If a dependency fails, the task will not run.\n\n```mise-toml\n[tasks.build]\nrun = 'cargo build'\n\n[tasks.test]\ndepends = ['build']\n```\n\nThere are other ways to specify dependencies, see [wait_for](/tasks/task-configuration.html#wait-for) and [depends_post](/tasks/task-configuration.html#depends-post)\n\n### Environment variables\n\nYou can specify environment variables for a task:\n\n```mise-toml\n[tasks.lint]\ndescription = 'Lint with clippy'\nenv = { RUST_BACKTRACE = '1' } # env vars for the script\n# you can specify a multiline script instead of individual commands\nrun = '''\n#!/usr/bin/env bash\ncargo clippy\n'''\n```\n\n### Sources / Outputs\n\nIf you want to skip executing a task if certain files haven't changed (up-to-date), you should specify `sources` and `outputs`:\n\n```mise-toml\n[tasks.build]\ndescription = 'Build the CLI'\nrun = \"cargo build\"\nsources = ['Cargo.toml', 'src/**/*.rs'] # skip running if these files haven't changed\noutputs = ['target/debug/mycli']\n```\n\nYou can use `sources` alone if with [`mise watch`](/cli/watch.html) to run the task when the sources change.\nYou can use the [`task_source_files()`](../templates.md#task-source-files) function to get the resolved paths of a task's `sources` from within\nits [template](../templates.md).\n\n### Confirmation\n\nA message to show before running the task. The user will be prompted to confirm before the task is run.\n\n```mise-toml\n[tasks.release]\nconfirm = 'Are you sure you want to cut a new release?'\ndescription = 'Cut a new release'\nfile = 'scripts/release.sh'\n```\n\n## Specifying a shell or an interpreter {#shell-shebang}\n\nTasks are executed with `set -e` (`set -o erropt`) if the shell is `sh`, `bash`, or `zsh`. This means that the script\nwill exit if any command fails. You can disable this by running `set +e` in the script.\n\n```mise-toml\n[tasks.echo]\nrun = '''\nset +e\ncd /nonexistent\necho \"This will not fail the task\"\n'''\n```\n\nYou can specify a `shell` command to run the script with (default is [`sh -c`](/configuration/settings.html#unix_default_inline_shell_args) or [`cmd /c`](/configuration/settings.html#windows_default_inline_shell_args)):\n\n```mise-toml\n[tasks.lint]\nshell = 'bash -c'\nrun = \"cargo clippy\"\n```\n\nor use a shebang:\n\n```mise-toml\n[tasks.lint]\nrun = '''\n#!/usr/bin/env bash\ncargo clippy\n'''\n```\n\nBy using a `shebang` (or `shell`), you can run tasks in different languages (e.g., Python, Node.js, Ruby, etc.):\n\n::: code-group\n\n```mise-toml [python]\n[tools]\npython = 'latest'\n\n[tasks.python_task]\nrun = '''\n#!/usr/bin/env python\nfor i in range(10):\n    print(i)\n'''\n```\n\n```mise-toml [python + uv]\n[tools]\nuv = 'latest'\n\n[tasks.python_uv_task]\nrun = '''\n#!/usr/bin/env -S uv run --script\n# /// script\n# dependencies = [\"requests<3\", \"rich\"]\n# ///\n\nimport requests\nfrom rich.pretty import pprint\n\nresp = requests.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n'''\n```\n\n```mise-toml [node]\n[tools]\nnode = 'lts'\n\n[tasks.node_task]\nshell = 'node -e'\nrun = [\n  \"console.log('First line')\",\n  \"console.log('Second line')\",\n]\n```\n\n```mise-toml [bun]\n[tools]\nbun = 'latest'\n\n[tasks.bun_shell]\ndescription = \"https://bun.sh/docs/runtime/shell\"\nrun = '''\n#!/usr/bin/env bun\n\nimport { $ } from \"bun\";\nconst response = await fetch(\"https://example.com\");\nawait $`cat < ${response} | wc -c`; // 1256\n'''\n```\n\n```mise-toml [deno]\n[tools]\ndeno = 'latest'\n\n[tasks.deno_task]\ndescription = \"A more complex task using Deno imports\"\nrun = '''\n#!/usr/bin/env -S deno run\nimport ProgressBar from \"jsr:@deno-library/progress\";\nimport { delay } from \"jsr:@std/async\";\n\nif (!confirm('Start download?')) {\n    Deno.exit(1);\n}\n\nconst progress = new ProgressBar({ title:  \"downloading:\", total: 100 });\nlet completed = 0;\nasync function download() {\n  while (completed <= 100) {\n    await progress.render(completed++);\n    await delay(10);\n  }\n}\nawait download();\n'''\n# ❯ mise run deno_task\n# [download_task] $ import ProgressBar from \"jsr:@deno-library/progress\";\n# Start download? [y/N] y\n# downloading: ...\n```\n\n```mise-toml [ruby]\n[tools]\nruby = 'latest'\n\n[tasks.ruby_task]\nrun = '''\n#!/usr/bin/env ruby\nputs 'Hello, ruby!'\n'''\n```\n\n:::\n\n::: details What's a shebang? What's the difference between `#!/usr/bin/env` and `#!/usr/bin/env -S`\n\nA shebang is the character sequence `#!` at the beginning of a script file that tells the system which program should be used to interpret/execute the script.\nThe [env command](https://manpages.ubuntu.com/manpages/jammy/man1/env.1.html) comes from GNU Coreutils. `mise` does not use `env` but will behave similarly.\n\nFor example, `#!/usr/bin/env python` will run the script with the Python interpreter found in the `PATH`.\n\nThe `-S` flag allows passing multiple arguments to the interpreter.\nIt treats the rest of the line as a single argument string to be split.\n\nThis is useful when you need to specify interpreter flags or options.\nExample: `#!/usr/bin/env -S python -u` will run Python with unbuffered output.\n\n:::\n\n## Using a file or remote script\n\nYou can specify a file to run as a task:\n\n```mise-toml\n[tasks.release]\ndescription = 'Cut a new release'\nfile = 'scripts/release.sh' # execute an external script\n```\n\n### Remote tasks\n\nTask files can be fetched remotely with multiple protocols:\n\n#### HTTP\n\n```mise-toml\n[tasks.build]\nfile = \"https://example.com/build.sh\"\n```\n\nPlease note that the file will be downloaded and executed. Make sure you trust the source.\n\n#### Git <Badge type=\"warning\" text=\"experimental\" />\n\n::: code-group\n\n```mise-toml [ssh]\n[tasks.build]\nfile = \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\"\n```\n\n```mise-toml [https]\n[tasks.build]\nfile = \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\"\n```\n\n:::\n\nUrl format must follow these patterns `git::<protocol>://<url>//<path>?<ref>`\n\nRequired fields:\n\n- `protocol`: The git repository URL.\n- `url`: The git repository URL.\n- `path`: The path to the file in the repository.\n\nOptional fields:\n\n- `ref`: The git reference (branch, tag, commit).\n\n#### Cache\n\nEach task file is cached in the `MISE_CACHE_DIR` directory. If the file is updated, it will not be re-downloaded unless the cache is cleared.\n\n:::tip\nYou can reset the cache by running `mise cache clear`.\n:::\n\nYou can use the `MISE_TASK_REMOTE_NO_CACHE` environment variable to disable caching of remote tasks.\n\n## Arguments\n\n::: tip\nFor comprehensive information about task arguments, see the dedicated [Task Arguments](/tasks/task-arguments) page.\n:::\n\nBy default, arguments are passed to the last script in the `run` array. So if a task was defined as:\n\n```mise-toml\n[tasks.test]\nrun = ['cargo test', './scripts/test-e2e.sh']\n```\n\nThen running `mise run test foo bar` will pass `foo bar` to `./scripts/test-e2e.sh` but not to\n`cargo test`.\n\n### Recommended: Using the Usage Field\n\nThe recommended way to define arguments is using the `usage` field:\n\n```mise-toml\n[tasks.test]\nusage = '''\narg \"<file>\" help=\"Test file to run\" default=\"all\"\nflag \"--format <format>\" help=\"Output format\" default=\"text\"\nflag \"-v --verbose\" help=\"Enable verbose output\"\n'''\nrun = 'cargo test ${usage_file?} --format ${usage_format?}'\n```\n\nArguments defined in the usage field are available as environment variables prefixed with `usage_`.\n\nSee the [Task Arguments](/tasks/task-arguments#usage-field) page for complete documentation.\n\n### Tera Template Functions <Badge type=\"danger\" text=\"deprecated\" />\n\n::: danger Deprecated - Removal in 2026.11.0\nUsing Tera template functions (`arg()`, `option()`, `flag()`) in run scripts is **deprecated** and will be **removed in mise 2026.11.0**. Versions >= 2026.5.0 will show a deprecation warning.\n\n**Why it's being removed:**\n\n- Template functions return empty strings during spec collection (two-pass parsing issue)\n- Complex and unpredictable shell escaping rules\n- Doesn't work consistently between TOML/file tasks\n\n**Please migrate to using the `usage` field instead.** See the [migration guide](/tasks/task-arguments#tera-templates).\n:::\n\n<details>\n<summary>Click to see deprecated Tera template syntax (not recommended)</summary>\n\nYou can define arguments using Tera template functions (deprecated):\n\n```mise-toml\n[tasks.test]\nrun = [\n    'cargo test {{arg(name=\"cargo_test_args\", var=true)}}',\n    './scripts/test-e2e.sh {{option(name=\"e2e_args\")}}',\n]\n```\n\nThen running `mise run test foo bar` will pass `foo bar` to `cargo test`.\n`mise run test --e2e-args baz` will pass `baz` to `./scripts/test-e2e.sh`.\n\n#### Positional Arguments\n\nThese are defined in scripts with <span v-pre>`{{arg()}}`</span>. They are used for positional\narguments where the order matters.\n\nExample:\n\n```mise-toml\n[tasks.test]\nrun = 'cargo test {{arg(name=\"file\")}}'\n# execute: mise run test my-test-file\n# runs: cargo test my-test-file\n```\n\n- `i`: The index of the argument. This can be used to specify the order of arguments. Defaults to\n  the order they're defined in the scripts.\n- `name`: The name of the argument. This is used for help/error messages.\n- `var`: If `true`, multiple arguments can be passed.\n- `default`: The default value if the argument is not provided.\n\n#### Options\n\nThese are defined in scripts with <span v-pre>`{{option()}}`</span>. They are used for named\narguments where the order doesn't matter.\n\nExample:\n\n```mise-toml\n[tasks.test]\nrun = 'cargo test {{option(name=\"file\")}}'\n# execute: mise run test --file my-test-file\n# runs: cargo test my-test-file\n```\n\n- `name`: The name of the argument. This is used for help/error messages.\n- `var`: If `true`, multiple values can be passed.\n- `default`: The default value if the option is not provided.\n\n#### Flags\n\nFlags are like options except they don't take values. They are defined in scripts with <span v-pre>\n`{{flag()}}`</span>.\n\nExamples:\n\n```mise-toml\n[tasks.echo]\nrun = 'echo {{flag(name=\"myflag\")}}'\n# execute: mise run echo --myflag\n# runs: echo true\n```\n\n```mise-toml\n[tasks.maybeClean]\nrun = '''\nif [ '{{flag(name='clean')}}' = 'true' ]; then\n  echo 'cleaning'\nfi\n'''\n# execute: mise run maybeClean --clean\n# runs: echo cleaning\n```\n\n- `name`: The name of the flag. This is used for help/error messages.\n\nThe value will be `true` if the flag is passed, and `false` otherwise.\n\n</details>\n"
  },
  {
    "path": "docs/team.md",
    "content": "<script setup>\nimport { VPTeamPage, VPTeamPageTitle, VPTeamPageSection, VPTeamMembers } from 'vitepress/theme'\n\nconst members = [\n  {\n    avatar: 'https://www.github.com/jdx.png',\n    name: 'Jeff Dickey',\n    title: 'BDFL',\n    links: [\n      { icon: 'github', link: 'https://github.com/jdx' },\n      { icon: 'twitter', link: 'https://twitter.com/jdxcode' },\n      { icon: 'mastodon', link: 'https://fosstodon.org/@jdx' }\n    ]\n  }\n]\nconst board = [\n  {\n    avatar: 'https://www.github.com/booniepepper.png',\n    name: 'Justin \"J.R.\" Hill',\n    links: [\n      { icon: 'github', link: 'https://github.com/booniepepper' },\n    ]\n  },\n  {\n    avatar: 'https://www.github.com/pepicrft.png',\n    name: 'Pedro Piñera Buendía',\n    links: [\n      { icon: 'github', link: 'https://github.com/pepicrft' },\n    ]\n  },\n  {\n    avatar: 'https://www.github.com/chadac.png',\n    name: 'Chad Crawford',\n    links: [\n      { icon: 'github', link: 'https://github.com/chadac' },\n    ]\n  }\n]\n</script>\n\n# Team\n\nJeff Dickey is the primary developer behind mise. He does the bulk\nof development for the project.\n\n<VPTeamMembers :members=\"members\" />\n\n## Advisory Board\n\nThe advisory board helps make important decisions about the project such as:\n\n- What features should be on the roadmap\n- When should functionality move from experimental to stable\n- If/when/how features should be deprecated\n\n<VPTeamMembers :members=\"board\" />\n\n## Contributors\n\nmise is an open source project which welcomes [contributions](https://github.com/jdx/mise/graphs/contributors).\nWe're grateful for those that have volunteered their work for the project.\n"
  },
  {
    "path": "docs/templates.md",
    "content": "# Templates\n\nTemplates in mise provide a powerful way to configure different aspects of\nyour environment and project settings.\n\nA template is a string that contains variables, expressions, and control structures.\nWhen rendered, the template engine (`tera`) replaces the variables with their values.\n\nYou can define and use templates in the following locations:\n\n- Most `mise.toml` configuration values\n  - The `mise.toml` file itself is not templated and must be valid toml\n- `.tool-versions` files\n- _(Submit a ticket if you want to see it used elsewhere!)_\n\n## Example\n\nHere is an example of a `mise.toml` file that uses templates:\n\n```toml\n[env]\nPROJECT_NAME = \"{{ cwd | basename }}\"\nTERRAFORM_VERSION = \"1.0.0\"\n\n[tools]\n# refers to env variable defined in this file\nterraform = \"{{ env.TERRAFORM_VERSION }}\"\n# refers to external env variable\nnode = \"{{ get_env(name='NODE_VERSION', default='20') }}\"\n```\n\nYou will find more examples in the [cookbook](./mise-cookbook/index.md).\n\n## Template Rendering\n\nMise uses [tera](https://keats.github.io/tera/docs/) to provide the template feature.\nIn the template, there are 3 kinds of delimiters:\n\n- <span v-pre>`{{`</span> and <span v-pre>`}}`</span> for expressions\n- <span v-pre>`{%`</span> and <span v-pre>`%}`</span> for statements\n- <span v-pre>`{#`</span> and <span v-pre>`#}`</span> for comments\n\nAdditionally, use `raw` block to skip rendering tera delimiters:\n\n<div v-pre>\n\n```\n{% raw %}\n  Hello {{ name }}\n{% endraw %}\n```\n\n</div>\n\nThis will become <span v-pre>`Hello {{name}}`</span>.\n\nTera supports [literals](https://keats.github.io/tera/docs/#literals), including:\n\n- booleans: `true` (or `True`) and `false` (or `False`)\n- integers\n- floats\n- strings: text delimited by `\"\"`, `''` or <code>\\`\\`</code>\n- arrays: a comma-separated list of literals and/or ident surrounded by\n  `[` and `]` (trailing comma allowed)\n\nYou can render a variable by using the <span v-pre>`{{ name }}`</span>.\nFor complex attributes, use:\n\n- dot `.`, e.g. <span v-pre>`{{ product.name }}`</span>\n- square brackets `[]`, e.g. <span v-pre>`{{ product[\"name\"] }}`</span>\n\nTera also supports powerful [expressions](https://keats.github.io/tera/docs/#expressions):\n\n- mathematical expressions\n  - `+`\n  - `-`\n  - `/`\n  - `*`\n  - `%`\n- comparisons\n  - `==`\n  - `!=`\n  - `>=`\n  - `<=`\n  - `<`\n  - `>`\n- logic\n  - `and`\n  - `or`\n  - `not`\n- concatenation `~`, e.g. <code v-pre>{{ \"hello \" ~ 'world' ~ \\`!\\` }</code>\n- in checking, e.g. <span v-pre>`{{ some_var in [1, 2, 3] }}`</span>\n\nTera also supports control structures such as <span v-pre>`if`</span> and\n<span v-pre>`for`</span>. [Read more](https://keats.github.io/tera/docs/#control-structures).\n\n### Tera Filters\n\nYou can modify variables using [filters](https://keats.github.io/tera/docs/#filters).\nYou can filter a variable by a pipe symbol (`|`) and may have named arguments\nin parentheses. You can also chain multiple filters.\ne.g. <span v-pre>`{{ \"Doctor Who\" | lower | replace(from=\"doctor\", to=\"Dr.\") }}`</span>\nwill output `Dr. who`.\n\n### Tera Functions\n\n[Functions](https://keats.github.io/tera/docs/#functions) provide\nadditional features to templates.\n\n### Tera Tests\n\nYou can also uses [tests](https://keats.github.io/tera/docs/#tests) to examine variables.\n\n```\n{% if my_number is not odd %}\n  Even\n{% endif %}\n```\n\n## Mise Template Features\n\nMise provides additional variables, functions, filters, and tests on top of tera features.\n\n### Variables\n\nMise exposes several [variables](https://keats.github.io/tera/docs/#variables).\nThese variables offer key information about the current environment:\n\n- `env: HashMap<String, String>` – Accesses current environment variables as\n  a key-value map.\n- `cwd: PathBuf` – Points to the current working directory.\n- `config_root: PathBuf` – Locates the directory containing your `mise.toml` file, or in the case of something like `~/src/myproj/.config/mise.toml`, it will point to `~/src/myproj`.\n- `mise_bin: String` - Points to the path to the current mise executable\n- `mise_pid: String` - Points to the pid of the current mise process\n- `mise_env: Vec<String>` - The configuration environment as specified by `MISE_ENV`, `-E`, or `--env`. Will be undefined if the configuration environment is not set.\n- `xdg_cache_home: PathBuf` - Points to the directory of XDG cache home\n- `xdg_config_home: PathBuf` - Points to the directory of XDG config home\n- `xdg_data_home: PathBuf` - Points to the directory of XDG data home\n- `xdg_state_home: PathBuf` - Points to the directory of XDG state home\n- `tools: HashMap<String, ToolInfo | ToolInfo[]>` – Maps installed tool names to their info.\n  Available in task templates and env directives with `tools = true`.\n  - When a single version is installed:\n    - `tools.<name>.version: String` – The resolved version (e.g., `\"22.1.0\"`)\n    - `tools.<name>.path: String` – The install path\n  - When multiple versions are installed, it becomes an array:\n    - `tools.<name>[0].version: String` – The first version\n    - `tools.<name>[0].path: String` – The first install path\n    - `tools.<name>[1].version: String` – The second version, etc.\n\nIn **task run scripts**, mise also exposes a `usage` map when the task has a usage\nspecification (see [Task Arguments](/tasks/task-arguments#usage-field)):\n\n- `usage: HashMap<String, Value>` – Parsed task arguments and flags, keyed by their\n  names. Values are **not shell-escaped or quoted** and may be:\n  - booleans (for flags and boolean args)\n  - strings\n  - arrays of booleans/strings for variadic args/flags\n\nThe keys are the argument/flag names as written in the usage spec. If the name\ncontains `-`, use bracket access, e.g. <span v-pre>`{{ usage[\"dry-run\"] }}`</span>.\nExamples:\n\n```mise-toml\n[tasks.deploy]\nusage = '''\narg \"<environment>\" help=\"Target environment\"\nflag \"-v --verbose\" help=\"Enable verbose output\"\narg \"[tags]\" var=#true\n'''\nrun = '''\necho \"env={{ usage.environment }}\"\necho \"verbose={{ usage.verbose }}\"\necho \"tag count={{ usage.tags | length }}\"\n{% for tag in usage.tags %}\n  echo \"tag={{ tag }}\"\n{% endfor %}\n'''\n```\n\n### Functions\n\n#### Tera Built-In Functions\n\nTera offers many [built-in functions](https://keats.github.io/tera/docs/#built-in-functions).\n`[]` indicates an optional function argument.\nSome functions:\n\n- `range(end, [start], [step_by])` - Returns an array of integers created\n  using the arguments given.\n  - `end: usize`: stop before `end`, mandatory\n  - `start: usize`: where to start from, defaults to `0`\n  - `step_by: usize`: with what number do we increment, defaults to `1`\n- `now([timestamp], [utc])` - Returns the local datetime as string or\n  the timestamp as integer.\n  - `timestamp: bool`: whether to return the timestamp instead of the datetime\n  - `utc: bool`: whether to return the UTC datetime instead of\n    the local one\n  - Tip: use date filter to format date string.\n    e.g. <span v-pre>`{{ now() | date(format=\"%Y\") }}`</span> gets the current year.\n- `throw(message)` - Throws with the message.\n- `get_random(end, [start])` - Returns a random integer in a range.\n  - `end: usize`: upper end of the range\n  - `start: usize`: defaults to 0\n- `get_env(name, [default])`: Returns the environment variable value by name.\n  Prefer `env` variable than this function.\n  - `name: String`: the name of the environment variable\n  - `default: String`: a default value in case the environment variable is not found.\n    Throws when can't find the environment variable and `default` is not set.\n\nTera offers more functions. Read more on [tera documentation](https://keats.github.io/tera/docs/#functions).\n\n#### Additional Mise Functions\n\nMise offers a slew of useful functions in addition to tera's built-ins.\n\n##### General Functions\n\nThese functions are available in all tasks, and will always behave the same way regardless\nof the task definition they are used in. In other words, their return values are consistent\nacross task definition(s).\n\n- `exec(command) -> String` – Runs a shell command and returns its output as a string.\n- `arch() -> String` – Retrieves the system architecture, such as `x64` or `arm64`.\n- `os() -> String` – Returns the name of the operating system,\n  e.g. linux, macos, windows.\n- `os_family() -> String` – Returns the operating system family, e.g. `unix`, `windows`.\n- `num_cpus() -> usize` – Gets the number of CPUs available on the system.\n- `choice(n, alphabet)` - Generate a string of `n` with random sample with replacement\n  of `alphabet`. For example, `choice(64, HEX)` will generate a random\n  64-character lowercase hex string.\n- `read_file(path) -> String` – Reads the contents of a file at the given path and returns\n  it as a string.\n\n##### Task-Specific Functions\n\nThese functions are task-specific and behave differently depending on the task they are used\nin. In other words, their return values **_may_** (but are not guaranteed to) be consistent\nacross executions of any given _task_, and should be expected to be inconsisent across\ndifferent task definition(s).\n\nFor example, `task_source_files()` returns a different set of filepaths depending on the [`sources`](https://mise.jdx.dev/tasks/task-configuration.html#sources) of the task it's called from.\n\n- <span id=\"task-source-files\">`task_source_files() -> Vec<String>`</span> – Returns the task's [`sources`](https://mise.jdx.dev/tasks/task-configuration.html#sources)\n  as an array of resolved file paths. This function processes glob patterns and Tera template strings\n  defined in the task's sources, expanding them into actual file paths. If a pattern doesn't match any\n  files, it will be omitted from the result. Returns an empty array if no sources are configured or if\n  no files match the patterns.\n\n#### Examples\n\n```toml\n# Using exec to get command output\n[alias.node.versions]\ncurrent = \"{{ exec(command='node --version') }}\"\n\n# Using read_file to include content from a file\n[env]\nVERSION = \"{{ read_file(path='VERSION') | trim }}\"\n\n# Access resolved source files in task scripts\n[tasks.example]\nsources = [\"src/**/*.ts\", \"package.json\"]\nrun = '''\n{% for file in task_source_files() %}\n  echo \"Processing: {{ file }}\"\n{% endfor %}\n'''\n```\n\n### Exec Options\n\nThe `exec` function supports the following options:\n\n- `command: String` – [required] The command to run.\n- `cache_key: String` – The cache key to store the result.\n  If the cache key is provided, the result will be cached and reused\n  for subsequent calls.\n- `cache_duration: String` – The duration to cache the result.\n  The duration is in seconds, minutes, hours, days, or weeks.\n  e.g. `cache_duration=\"1d\"` will cache the result for 1 day.\n\n### Filters\n\nTera offers many [built-in filters](https://keats.github.io/tera/docs/#built-in-filters).\n`[]` indicates an optional filter argument.\nSome filters:\n\n- `str | lower -> String` – Converts a string to lowercase.\n- `str | upper -> String` – Converts a string to uppercase.\n- `str | capitalize -> String` – Converts a string with all its characters lowercased\n  apart from the first char which is uppercased.\n- `str | replace(from, to) -> String` – Replaces a string with all instances of\n  `from` to `to`. e.g., <span v-pre>`{{ name | replace(from=\"Robert\", to=\"Bob\")}}`</span>\n- `str | title -> String` – Capitalizes each word inside a sentence.\n  e.g., <span v-pre>`{{ \"foo bar\" | title }}`</span> becomes `Foo Bar`.\n- `str | trim -> String` – Removes leading and trailing whitespace.\n- `str | trim_start -> String` – Removes leading whitespace.\n- `str | trim_end -> String` – Removes trailing whitespace.\n- `str | truncate -> String` – Truncates a string to the indicated length.\n- `str | first -> String` – Returns the first element in an array or string.\n- `str | last -> String` – Returns the last element in an array or string.\n- `str | join(sep) -> String` – Joins an array of strings with a separator,\n  such as <span v-pre>`{{ [\"a\", \"b\", \"c\"] | join(sep=\", \") }}`</span>\n  to produce `a, b, c`.\n- `str | length -> usize` – Returns the length of a string or array.\n- `str | reverse -> String` – Reverses the order of characters in a string or\n  elements in an array.\n- `str | urlencode -> String` – Encodes a string to be safely used in URLs,\n  converting special characters to percent-encoded values.\n- `arr | map(attribute) -> Array` – Extracts an attribute from each object\n  in an array.\n- `arr | concat(with) -> Array` – Appends values to an array.\n- `num | abs -> Number` – Returns the absolute value of a number.\n- `num | filesizeformat -> String` – Converts an integer into\n  a human-readable file size (e.g., 110 MB).\n- `str | date(format) -> String` – Converts a timestamp to\n  a formatted date string using the provided format,\n  such as <span v-pre>`{{ ts | date(format=\"%Y-%m-%d\") }}`</span>.\n  Find a list of time format on [`chrono` documentation](https://docs.rs/chrono/latest/chrono/format/strftime/index.html).\n- `str | split(pat) -> Array` – Splits a string by the given pattern and\n  returns an array of substrings.\n- `str | default(value) -> String` – Returns the default value\n  if the variable is not defined or is empty.\n\nTera offers more filters. Read more on [tera documentation](https://keats.github.io/tera/docs/#built-in-filters).\n\n#### Hash\n\n- `str | hash([algorithm], [len]) -> String` – Generates a hash for the input string.\n  - `algorithm: \"sha256\" | \"blake3\"`: hash algorithm to use (default: `\"sha256\"`)\n  - `len: usize`: truncates the hash string to the given size\n  - Examples:\n    - <span v-pre>`{{ \"foo\" | hash }}`</span> – SHA256 hash (default)\n    - <span v-pre>`{{ \"foo\" | hash(algorithm=\"blake3\") }}`</span> – BLAKE3 hash\n    - <span v-pre>`{{ \"foo\" | hash(len=8) }}`</span> – SHA256 hash truncated to 8 characters\n- `path | hash_file([len]) -> String` – Returns the BLAKE3 hash of the file\n  at the given path.\n  - `len: usize`: truncates the hash string to the given size\n\n#### Path Manipulation\n\n- `path | absolute -> String` – Converts the input path into\n  an absolute path. Does not require the path to exist.\n- `path | canonicalize -> String` – Converts the input path into\n  absolute input path version. Throws if path doesn't exist.\n- `path | basename -> String` – Extracts the file name from a path,\n  e.g. `/foo/bar/baz.txt` becomes `baz.txt`.\n- `path | file_size -> String` – Returns the size of a file in bytes.\n- `path | dirname -> String` – Returns the directory path for a file,\n  e.g. `/foo/bar/baz.txt` becomes `/foo/bar`.\n- `path | basename -> String` – Returns the base name of a file,\n  e.g. `/foo/bar/baz.txt` becomes `baz.txt`.\n- `path | extname -> String` – Returns the extension of a file,\n  e.g. `/foo/bar/baz.txt` becomes `.txt`.\n- `path | file_stem -> String` – Returns the file name without the extension,\n  e.g. `/foo/bar/baz.txt` becomes `baz`.\n- `path | file_size -> String` – Returns the size of a file in bytes.\n- `path | last_modified -> String` – Returns the last modified time of a file.\n- `path[] | join_path -> String` – Joins an array of paths into a single path.\n\nFor example, you can use `split()`, `concat()`, and `join_path` filters to\nconstruct a file path:\n\n```toml\n[env]\nPROJECT_CONFIG = \"{{ [config_root] | concat(with='bar.txt') | join_path }}\"\n```\n\n#### String Manipulation\n\n- `str | quote -> String` – Quotes a string. Converts `'` to `\\'` and\n  then quotes str, e.g `'it\\'s str'`.\n- `str | kebabcase -> String` – Converts a string to kebab-case\n- `str | lowercamelcase -> String` – Converts a string to lowerCamelCase\n- `str | uppercamelcase -> String` – Converts a string to UpperCamelCase\n- `str | snakecase -> String` – Converts a string to snake_case\n- `str | shoutysnakecase -> String` – Converts a string to SHOUTY_SNAKE_CASE\n\n### Tests\n\nTera offers many [built-in tests](https://keats.github.io/tera/docs/#built-in-tests).\nSome tests:\n\n- `defined` - Returns `true` if the given variable is defined.\n- `string` - Returns `true` if the given variable is a string.\n- `number` - Returns `true` if the given variable is a number.\n- `starting_with` - Returns `true` if the given variable is a string and starts with\n  the arg given.\n- `ending_with` - Returns `true` if the given variable is a string and ends with\n  the arg given.\n- `containing` - Returns `true` if the given variable contains the arg given.\n- `matching` - Returns `true` if the given variable is a string and matches the regex\n  in the argument.\n\nTera offers more tests. Read more on [tera documentation](https://keats.github.io/tera/docs/#built-in-tests).\n\nMise offers additional tests:\n\n- `if path is dir` – Checks if the provided path is a directory.\n- `if path is file` – Checks if the path points to a file.\n- `if path is exists` – Checks if the path exists.\n"
  },
  {
    "path": "docs/test-grammar.test.mjs",
    "content": "import { createHighlighter } from \"shiki\";\nimport { strict as assert } from \"assert\";\nimport miseTomlGrammar from \"./.vitepress/grammars/mise-toml.tmLanguage.json\" with { type: \"json\" };\nimport kdlGrammar from \"./.vitepress/grammars/kdl.tmLanguage.json\" with { type: \"json\" };\n\nconst code = `[tasks.deploy]\nusage = '''\narg \"<environment>\" help=\"Target environment\"\nflag \"-v --verbose\"\n'''\nrun = '''\necho \"Deploying\"\n./deploy.sh\n'''`;\n\nconsole.log(\"Testing mise-toml grammar...\");\n\ntry {\n  const highlighter = await createHighlighter({\n    themes: [\"github-dark\"],\n    langs: [\n      \"shell\",\n      \"bash\",\n      \"toml\",\n      {\n        ...kdlGrammar,\n        name: \"kdl\",\n        scopeName: \"source.kdl\",\n      },\n      {\n        ...miseTomlGrammar,\n        name: \"mise-toml\",\n        aliases: [\"mise.toml\"],\n        scopeName: \"source.mise-toml\",\n      },\n    ],\n  });\n\n  const html = highlighter.codeToHtml(code, {\n    lang: \"mise-toml\",\n    theme: \"github-dark\",\n  });\n\n  // Test that KDL keywords are highlighted (green color)\n  assert.ok(\n    html.includes(\"color:#85E89D\"),\n    \"KDL keywords (arg/flag) should be highlighted green\",\n  );\n\n  // Test that shell commands are highlighted (blue color)\n  assert.ok(\n    html.includes(\"color:#79B8FF\"),\n    \"Shell commands (echo) should be highlighted blue\",\n  );\n\n  // Test that strings are highlighted (blue color)\n  assert.ok(html.includes(\"color:#9ECBFF\"), \"Strings should be highlighted\");\n\n  // Test that TOML structure is present (may be HTML escaped)\n  assert.ok(\n    html.includes(\"tasks\") && html.includes(\"deploy\"),\n    \"TOML structure should be preserved\",\n  );\n\n  console.log(\"✓ All tests passed!\");\n  console.log(\"✓ KDL syntax highlighting working in usage fields\");\n  console.log(\"✓ Bash syntax highlighting working in run fields\");\n  console.log(\"✓ TOML structure properly parsed\");\n\n  process.exit(0);\n} catch (error) {\n  console.error(\"✗ Test failed:\", error.message);\n  process.exit(1);\n}\n"
  },
  {
    "path": "docs/tips-and-tricks.md",
    "content": "# Tips & Tricks\n\nAn assortment of helpful tips for using `mise`.\n\n## macOS Rosetta\n\nIf you have a need to run tools as x86_64 on Apple Silicon, this can be done with mise however you'll currently\nneed to use the x86_64 version of mise itself. A common reason for doing this is to support compiling node <=14.\n\nYou can do this either with the [`MISE_ARCH`](https://mise.jdx.dev/configuration/settings.html#arch)\nsetting or by using a dedicated rosetta mise bin as described below:\n\nFirst, you'll need a copy of mise that's built for x86_64:\n\n```sh\n$ curl https://mise.run | MISE_INSTALL_PATH=~/.local/bin/mise-x64 MISE_INSTALL_ARCH=x64 sh\n$ ~/.local/bin/mise-x64 --version\nmise 2024.x.x\n```\n\n::: warning\nIf `~/.local/bin` is not in PATH, you'll need to prefix all commands with `~/.local/bin/mise-x64`.\n:::\n\nNow you can use `mise-x64` to install tools:\n\n```sh\nmise-x64 use -g node@20\n```\n\n## Shebang\n\nYou can specify a tool and its version in a shebang without needing to first\nset up a `mise.toml`/`.tool-versions` config:\n\n```typescript\n#!/usr/bin/env -S mise x node@20 -- node\n// \"env -S\" allows multiple arguments in a shebang\nconsole.log(`Running node: ${process.version}`);\n```\n\nThis can also be useful in environments where mise isn't activated\n(such as a non-interactive session).\n\n## Bootstrap script\n\nYou can download the <https://mise.run> script to use in a project bootstrap script:\n\n```sh\ncurl https://mise.run > setup-mise.sh\nchmod +x setup-mise.sh\n./setup-mise.sh\n```\n\n::: tip\nThis file contains checksums so it's more secure to commit it into your project rather than\ncalling `curl https://mise.run` dynamically—though of course this means it will only fetch\nthe version of mise that was current when the script was created.\n:::\n\n## Installation via zsh zinit\n\n[Zinit](https://github.com/zdharma-continuum/zinit) is a plugin manager for ZSH, which this snippet you will get mise (and usage for shell completion):\n\n```sh\nzinit as=\"command\" lucid from=\"gh-r\" for \\\n    id-as=\"usage\" \\\n    atpull=\"%atclone\" \\\n    jdx/usage\n    #atload='eval \"$(mise activate zsh)\"' \\\n\nzinit as=\"command\" lucid from=\"gh-r\" for \\\n    id-as=\"mise\" mv=\"mise* -> mise\" \\\n    atclone=\"./mise* completion zsh > _mise\" \\\n    atpull=\"%atclone\" \\\n    atload='eval \"$(mise activate zsh)\"' \\\n    jdx/mise\n```\n\n## CI/CD\n\nUsing mise in CI/CD is a great way to synchronize tool versions for dev/build.\n\n### GitHub Actions\n\nmise is pretty easy to use without an action:\n\n```yaml\njobs:\n  build:\n    steps:\n      - run: |\n          curl https://mise.run | sh\n          echo \"$HOME/.local/bin\" >> $GITHUB_PATH\n          echo \"$HOME/.local/share/mise/shims\" >> $GITHUB_PATH\n```\n\nOr you can use the custom action [`jdx/mise-action`](https://github.com/jdx/mise-action):\n\n```yaml\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: jdx/mise-action@v3\n      - run: node -v # will be the node version from `mise.toml`/`.tool-versions`\n```\n\n## `mise set`\n\nInstead of manually editing `mise.toml` to add env vars, you can use [`mise set`](/cli/set.html) instead:\n\n```sh\nmise set NODE_ENV=production\n```\n\n## [`mise run`](/cli/run.html) shorthand\n\nAs long as the task name doesn't conflict with a mise-provided command you can skip the `run` part:\n\n```sh\nmise test\n```\n\n::: warning\nDon't do this inside of scripts because mise may add a command in a future version and could conflict with your task.\n:::\n\n## Software verification\n\nmise provides **native software verification** for aqua tools without requiring external dependencies. For aqua tools, Cosign/Minisign signatures, SLSA provenance, and GitHub artifact attestations are verified automatically using mise's built-in implementation.\n\nFor other verification needs (like GPG), you can install additional tools:\n\n```sh\nbrew install gpg\n# Note: cosign and slsa-verifier are no longer needed for aqua tools\n# mise now handles verification natively\n```\n\nTo configure aqua verification (all enabled by default):\n\n```sh\n# Disable specific verification methods if needed\nexport MISE_AQUA_COSIGN=false\nexport MISE_AQUA_SLSA=false\nexport MISE_AQUA_GITHUB_ATTESTATIONS=false\nexport MISE_AQUA_MINISIGN=false\n```\n\n## [`mise up --bump`](/cli/upgrade.html)\n\nUse `mise up --bump` to upgrade all software to the latest version and update `mise.toml` files. This keeps the same semver range as before,\nso if you had `node = \"22\"` and node 24 is the latest, `mise up --bump node` will change `mise.toml` to `node = \"24\"`.\n\n## cargo-binstall\n\ncargo-binstall is sort of like ubi but specific to rust tools. It fetches binaries for cargo releases. mise will use this automatically for `cargo:` tools if it is installed\nso if you use `cargo:` you should add this to make `mise i` go much faster.\n\n```sh\nmise use -g cargo-binstall\n```\n\n## [`mise cache clear`](/cli/cache.html)\n\nmise caches things for obvious reasons but sometimes you want it to use fresh data (maybe it's not noticing a new release). Run `mise cache clear` to remove the cache which\nbasically just run `rm -rf ~/.cache/mise/*`.\n\n## [`mise en`](/cli/en.html)\n\n`mise en` is a great alternative to `mise activate` if you don't want to always be using mise for some reason. It sets up the mise environment in your current directory\nbut doesn't keep running and updating the env vars after that.\n\n## Auto-install when entering a project\n\nAuto-install tools when entering a project by adding the following to `mise.toml`:\n\n```toml\n[hooks]\nenter = \"mise i -q\"\n```\n\n## [`mise tool [TOOL]`](/cli/tool.html)\n\nGet information about what backend a tool is using and other information with `mise tool [TOOL]`:\n\n```sh\n❯ mise tool ripgrep\nBackend:            aqua:BurntSushi/ripgrep\nInstalled Versions: 14.1.1\nActive Version:     14.1.1\nRequested Version:  latest\nConfig Source:      ~/src/mise/mise.toml\nTool Options:       [none]\n```\n\n## [`mise cfg`](/cli/config.html)\n\nList the config files mise is reading in a particular directory with `mise cfg`:\n\n```sh\n❯ mise cfg\nPath                                    Tools\n~/.config/mise/config.toml              (none)\n~/.mise/config.toml                     (none)\n~/src/mise.toml                         (none)\n~/src/mise/.config/mise/conf.d/foo.toml (none)\n~/src/mise/mise.toml                    actionlint, bun, cargo-binstall, cargo:…\n~/src/mise/mise.local.toml              (none)\n```\n\nThis is helpful figuring out which order the config files are loaded in to figure out which one is overriding.\n\n## `mise.lock`\n\nWhen lockfiles are enabled, mise will update `mise.lock` with full versions and tarball checksums (if supported by the backend).\nThese can be updated with [`mise up`](/cli/upgrade.html). You need to manually create the lockfile, then mise will add the tools to it:\n\n```sh\ntouch mise.lock\nmise i\n```\n\nThe lockfile uses a consolidated format with `[tools.name.assets]` sections to organize asset information under each tool. Asset information includes checksums, file sizes, and optional download URLs. Legacy lockfiles with separate `[tools.name.checksums]` and `[tools.name.sizes]` sections are automatically migrated to the new format.\n\nNote that at least currently mise needs to actually install the tool to get the tarball checksum (otherwise it would need to download the tarball just\nto get the checksum of it since normally that gets deleted). So you may need to run something like `mise uninstall --all` first in order to have it\nreinstall everything. It will store the full versions even if it doesn't know the checksum though so it'll still lock the version just not have a checksum\nto go with it.\n\n## Lockfile URL Tracking (Avoiding Rate Limits)\n\nWhen you use a lockfile (`mise.lock`), mise stores the exact download URLs for each tool asset. This means that after the initial install, future `mise install` runs will use the URLs from the lockfile instead of making API calls to GitHub (or other providers). This has several benefits:\n\n- **Avoids GitHub API rate limits**: No need to make repeated API calls for every install, which can quickly exhaust your rate limit, especially in CI or large teams.\n- **No need for GITHUB_TOKEN**: Since the URLs are already known, you don’t need to set up a `GITHUB_TOKEN` for simple installs.\n- **Faster installs**: Skipping API lookups speeds up repeated installs.\n\nThis is especially useful in CI/CD or when working in environments with strict network or authentication requirements.\n"
  },
  {
    "path": "docs/tool-plugin-development.md",
    "content": "# Tool Plugin Development\n\n::: tip\nThe [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template) provides a ready-to-use starting point with LuaCATS type definitions, stylua formatting, and hk linting pre-configured.\n:::\n\nTool plugins use a hook-based architecture to manage individual tools. They are compatible with the standard vfox ecosystem and are perfect for tools that need complex installation logic, environment configuration, or legacy file parsing.\n\n## What are Tool Plugins?\n\nTool plugins use traditional hook functions to manage a single tool. They provide:\n\n- **Standard vfox Compatibility**: Works with both mise and vfox\n- **Complex Installation Logic**: Handle source compilation, custom builds, and complex setups\n- **Environment Configuration**: Set up complex environment variables beyond just PATH\n- **Legacy File Support**: Parse version files from other tools (`.nvmrc`, `.tool-version`, etc.)\n- **Cross-Platform Support**: Works on Windows, macOS, and Linux\n\n## Plugin Architecture\n\nTool plugins are implemented in Lua (version 5.1 at the moment). They use a hook-based architecture with specific functions for different lifecycle events:\n\n```mermaid\ngraph TD\n    A[User Request] --> B[mise CLI]\n    B --> C[Tool Plugin]\n\n    C --> D[Available Hook<br/>List Versions]\n    C --> E[PreInstall Hook<br/>Download]\n    C --> F[PostInstall Hook<br/>Setup]\n    C --> G[EnvKeys Hook<br/>Configure]\n\n    subgraph \"Plugin Files\"\n        H[metadata.lua]\n        I[hooks/available.lua]\n        J[hooks/pre_install.lua]\n        K[hooks/env_keys.lua]\n        L[hooks/post_install.lua]\n    end\n\n    style C fill:#e1f5fe\n    style D fill:#e8f5e8\n    style E fill:#e8f5e8\n    style F fill:#e8f5e8\n    style G fill:#e8f5e8\n```\n\n## Hook Functions\n\n### Required Hooks\n\nThese hooks must be implemented for a functional plugin:\n\n#### Available Hook\n\nLists all available versions of the tool:\n\n```lua\n-- hooks/available.lua\nfunction PLUGIN:Available(ctx)\n    local args = ctx.args  -- User arguments\n\n    -- Return array of available versions\n    return {\n        {\n            version = \"20.0.0\",\n            note = \"Latest\"\n        },\n        {\n            version = \"18.18.0\",\n            note = \"LTS\",\n            addition = {\n                {\n                    name = \"npm\",\n                    version = \"9.8.1\"\n                }\n            }\n        }\n    }\nend\n```\n\n##### Rolling Releases\n\nFor tools that have rolling releases like \"nightly\" or \"stable\" where the version string stays the same but the content changes, you can mark versions as rolling and provide a checksum for update detection:\n\n```lua\nfunction PLUGIN:Available(ctx)\n    return {\n        {\n            version = \"nightly\",\n            note = \"Latest development build\",\n            rolling = true,  -- Mark as rolling release\n            checksum = \"abc123...\"  -- SHA256 of the release asset\n        },\n        {\n            version = \"stable\",\n            note = \"Latest stable release\",\n            rolling = true,\n            checksum = \"def456...\"\n        },\n        {\n            version = \"1.0.0\",\n            note = \"Fixed release\"\n            -- No rolling or checksum needed for fixed versions\n        }\n    }\nend\n```\n\nWhen `rolling = true` is set:\n\n- `mise upgrade` will check if the checksum has changed to detect updates\n- `mise upgrade --bump` will preserve the version name (e.g., \"nightly\") instead of converting it to a semver\n\nThe checksum should be the SHA256 hash of the release asset for the user's platform. See the [vfox-neovim plugin](https://github.com/mise-plugins/vfox-neovim) for a complete example.\n\n#### PreInstall Hook\n\nHandles pre-installation logic and returns download information:\n\n```lua\n-- hooks/pre_install.lua\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n    local runtimeVersion = ctx.runtimeVersion\n\n    -- Determine download URL and checksums\n    local url = \"https://nodejs.org/dist/v\" .. version .. \"/node-v\" .. version .. \"-linux-x64.tar.gz\"\n\n    return {\n        version = version,\n        url = url,\n        sha256 = \"abc123...\",  -- Optional checksum\n        note = \"Installing Node.js \" .. version,\n        -- Optional attestation metadata, choose a verification type\n        attestation = {\n            -- GitHub\n            github_owner = \"ownername\"\n            github_repo = \"reponame\"\n            -- Cosign\n            cosign_sig_or_bundle_path = \"/path/to/sig/or/bundle/file\"\n            -- SLSA\n            slsa_provenance_path = \"/path/to/provenance/file\"\n        },\n        -- Additional files can be specified\n        addition = {\n            {\n                name = \"npm\",\n                url = \"https://registry.npmjs.org/npm/-/npm-\" .. npm_version .. \".tgz\"\n            }\n        }\n    }\nend\n```\n\n#### EnvKeys Hook\n\nConfigures environment variables for the installed tool:\n\n```lua\n-- hooks/env_keys.lua\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n    local runtimeVersion = ctx.runtimeVersion\n    local sdkInfo = ctx.sdkInfo['nodejs']\n    local path = sdkInfo.path\n    local version = sdkInfo.version\n    local name = sdkInfo.name\n\n    return {\n        {\n            key = \"NODE_HOME\",\n            value = mainPath\n        },\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\"\n        },\n        -- Multiple PATH entries are automatically merged\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/lib/node_modules/.bin\"\n        }\n    }\nend\n```\n\n### Optional Hooks\n\nThese hooks provide additional functionality:\n\n#### PostInstall Hook\n\nPerforms additional setup after installation:\n\n```lua\n-- hooks/post_install.lua\nfunction PLUGIN:PostInstall(ctx)\n    local rootPath = ctx.rootPath\n    local runtimeVersion = ctx.runtimeVersion\n    local sdkInfo = ctx.sdkInfo['nodejs']\n    local path = sdkInfo.path\n    local version = sdkInfo.version\n\n    -- Compile native modules, set permissions, etc.\n    local result = os.execute(\"chmod +x \" .. path .. \"/bin/*\")\n    if result ~= 0 then\n        error(\"Failed to set permissions\")\n    end\n\n    -- No return value needed\nend\n```\n\n#### PreUse Hook\n\nModifies version before use:\n\n```lua\n-- hooks/pre_use.lua\nfunction PLUGIN:PreUse(ctx)\n    local version = ctx.version\n    local previousVersion = ctx.previousVersion\n    local installedSdks = ctx.installedSdks\n    local cwd = ctx.cwd\n    local scope = ctx.scope  -- global/project/session\n\n    -- Optionally modify the version\n    if version == \"latest\" then\n        version = \"20.0.0\"  -- Resolve to specific version\n    end\n\n    return {\n        version = version\n    }\nend\n```\n\n#### ParseLegacyFile Hook\n\nParses version files from other tools:\n\n```lua\n-- hooks/parse_legacy_file.lua\nfunction PLUGIN:ParseLegacyFile(ctx)\n    local filename = ctx.filename\n    local filepath = ctx.filepath\n    local versions = ctx:getInstalledVersions()\n\n    -- Read and parse the file\n    local file = require(\"file\")\n    local content = file.read(filepath)\n    local version = content:match(\"v?([%d%.]+)\")\n\n    return {\n        version = version\n    }\nend\n```\n\n## Creating a Tool Plugin\n\n### Using the Template Repository\n\nThe easiest way to create a new tool plugin is to use the [mise-tool-plugin-template](https://github.com/jdx/mise-tool-plugin-template) repository as a starting point:\n\n```bash\n# Clone the template\ngit clone https://github.com/jdx/mise-tool-plugin-template my-tool-plugin\ncd my-tool-plugin\n\n# Remove the template's git history and start fresh\nrm -rf .git\ngit init\n\n# Customize the plugin for your tool\n# Edit metadata.lua, hooks/*.lua files, etc.\n```\n\nThe template includes:\n\n- Pre-configured plugin structure with all required hooks\n- Example implementations with comments\n- Linting configuration (`.luacheckrc`, `stylua.toml`)\n- Testing setup with mise tasks\n- GitHub Actions workflow for CI\n\n### 1. Plugin Structure\n\nCreate a directory with this structure (or use the template above):\n\n```\nmy-tool-plugin/\n├── metadata.lua          # Plugin metadata and configuration\n├── hooks/               # Hook functions directory\n│   ├── available.lua    # List available versions [required]\n│   ├── pre_install.lua  # Pre-installation hook [required]\n│   ├── env_keys.lua     # Environment configuration [required]\n│   ├── post_install.lua # Post-installation hook [optional]\n│   ├── pre_use.lua      # Pre-use hook [optional]\n│   └── parse_legacy_file.lua # Legacy file parser [optional]\n├── lib/                 # Shared library code [optional]\n│   └── helper.lua       # Helper functions\n└── test/               # Test scripts [optional]\n    └── test.sh\n```\n\n### 2. metadata.lua\n\nConfigure plugin metadata and legacy file support:\n\n```lua\n-- metadata.lua\nPLUGIN = {\n    name = \"nodejs\",\n    version = \"1.0.0\",\n    description = \"Node.js runtime environment\",\n    author = \"Plugin Author\",\n\n    -- Legacy version files this plugin can parse\n    legacyFilenames = {\n        '.nvmrc',\n        '.node-version'\n    }\n}\n```\n\n### 3. Helper Libraries\n\nCreate shared functions in the `lib/` directory:\n\n```lua\n-- lib/helper.lua\nlocal M = {}\n\nfunction M.get_arch()\n    -- Use the RUNTIME object provided by vfox/mise\n    local arch = RUNTIME.archType\n    if arch == \"amd64\" then\n        return \"x64\"\n    elseif arch == \"386\" then\n        return \"x86\"\n    elseif arch == \"arm64\" then\n        return \"arm64\"\n    else\n        return arch  -- return as-is for other architectures\n    end\nend\n\nfunction M.get_os()\n    -- Use the RUNTIME object provided by vfox/mise\n    local os = RUNTIME.osType\n    if os == \"Windows\" then\n        return \"win\"\n    elseif os == \"Darwin\" then\n        return \"darwin\"\n    else\n        return \"linux\"\n    end\nend\n\nfunction M.get_platform()\n    return M.get_os() .. \"-\" .. M.get_arch()\nend\n\nreturn M\n```\n\n## Real-World Example: vfox-nodejs\n\nHere's a complete example based on the vfox-nodejs plugin that demonstrates all the concepts:\n\n### Available Hook Example\n\n```lua\n-- hooks/available.lua\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local json = require(\"json\")\n\n    -- Fetch versions from Node.js API\n    local resp, err = http.get({\n        url = \"https://nodejs.org/dist/index.json\"\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions: \" .. err)\n    end\n\n    local versions = json.decode(resp.body)\n    local result = {}\n\n    for i, v in ipairs(versions) do\n        local version = v.version:gsub(\"^v\", \"\")  -- Remove 'v' prefix\n        local note = nil\n\n        if v.lts then\n            note = \"LTS\"\n        end\n\n        table.insert(result, {\n            version = version,\n            note = note,\n            addition = {\n                {\n                    name = \"npm\",\n                    version = v.npm\n                }\n            }\n        })\n    end\n\n    return result\nend\n```\n\n### PreInstall Hook Example\n\n```lua\n-- hooks/pre_install.lua\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Determine platform using RUNTIME object\n    local arch_token\n    if RUNTIME.archType == \"amd64\" then\n        arch_token = \"x64\"\n    elseif RUNTIME.archType == \"386\" then\n        arch_token = \"x86\"\n    elseif RUNTIME.archType == \"arm64\" then\n        arch_token = \"arm64\"\n    else\n        arch_token = RUNTIME.archType\n    end\n    local os_token\n    if RUNTIME.osType == \"Windows\" then\n        os_token = \"win\"\n    elseif RUNTIME.osType == \"Darwin\" then\n        os_token = \"darwin\"\n    else\n        os_token = \"linux\"\n    end\n    local platform = os_token .. \"-\" .. arch_token\n    local extension = (RUNTIME.osType == \"Windows\") and \"zip\" or \"tar.gz\"\n\n    -- Build download URL\n    local filename = \"node-v\" .. version .. \"-\" .. platform .. \".\" .. extension\n    local url = \"https://nodejs.org/dist/v\" .. version .. \"/\" .. filename\n\n    -- Fetch checksum\n    local http = require(\"http\")\n    local shasums_url = \"https://nodejs.org/dist/v\" .. version .. \"/SHASUMS256.txt\"\n    local resp, err = http.get({ url = shasums_url })\n\n    local sha256 = nil\n    if err == nil then\n        -- Extract SHA256 for our file\n        for line in resp.body:gmatch(\"[^\\n]+\") do\n            if line:match(filename) then\n                sha256 = line:match(\"^(%w+)\")\n                break\n            end\n        end\n    end\n\n    return {\n        version = version,\n        url = url,\n        sha256 = sha256,\n        note = \"Installing Node.js \" .. version .. \" (\" .. platform .. \")\"\n    }\nend\n```\n\n### EnvKeys Hook Example\n\n```lua\n-- hooks/env_keys.lua\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n    local os_type = RUNTIME.osType\n\n    local env_vars = {\n        {\n            key = \"NODE_HOME\",\n            value = mainPath\n        },\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\"\n        }\n    }\n\n    -- Add npm global modules to PATH\n    local npm_global_path = mainPath .. \"/lib/node_modules/.bin\"\n    if os_type == \"Windows\" then\n        npm_global_path = mainPath .. \"/node_modules/.bin\"\n    end\n\n    table.insert(env_vars, {\n        key = \"PATH\",\n        value = npm_global_path\n    })\n\n    return env_vars\nend\n```\n\n### PostInstall Hook Example\n\n```lua\n-- hooks/post_install.lua\nfunction PLUGIN:PostInstall(ctx)\n    local sdkInfo = ctx.sdkInfo['nodejs']\n    local path = sdkInfo.path\n    -- Set executable permissions on Unix systems\n    if RUNTIME.osType ~= \"Windows\" then\n        os.execute(\"chmod +x \" .. path .. \"/bin/*\")\n    end\n\n    -- Create npm cache directory\n    local npm_cache_dir = path .. \"/.npm\"\n    os.execute(\"mkdir -p \" .. npm_cache_dir)\n\n    -- Configure npm to use local cache\n    local npm_cmd = path .. \"/bin/npm\"\n    if RUNTIME.osType == \"Windows\" then\n        npm_cmd = path .. \"/npm.cmd\"\n    end\n\n    os.execute(npm_cmd .. \" config set cache \" .. npm_cache_dir)\n    os.execute(npm_cmd .. \" config set prefix \" .. path)\nend\n```\n\n### Legacy File Support\n\n```lua\n-- hooks/parse_legacy_file.lua\nfunction PLUGIN:ParseLegacyFile(ctx)\n    local filename = ctx.filename\n    local filepath = ctx.filepath\n    local file = require(\"file\")\n\n    -- Read file content\n    local content = file.read(filepath)\n    if not content then\n        error(\"Failed to read \" .. filepath)\n    end\n\n    -- Parse version from different file formats\n    local version = nil\n\n    if filename == \".nvmrc\" then\n        -- .nvmrc can contain version with or without 'v' prefix\n        version = content:match(\"v?([%d%.]+)\")\n    elseif filename == \".node-version\" then\n        -- .node-version typically contains just the version number\n        version = content:match(\"([%d%.]+)\")\n    end\n\n    -- Remove any whitespace\n    if version then\n        version = version:gsub(\"%s+\", \"\")\n    end\n\n    return {\n        version = version\n    }\nend\n```\n\n## Testing Your Plugin\n\n### Local Development\n\n```bash\n# Link your plugin for development\nmise plugin link my-tool /path/to/my-tool-plugin\n\n# Test listing versions\nmise ls-remote my-tool\n\n# Test installation\nmise install my-tool@1.0.0\n\n# Test environment setup\nmise use my-tool@1.0.0\nmy-tool --version\n\n# Test legacy file parsing (if applicable)\necho \"2.0.0\" > .my-tool-version\nmise use my-tool\n```\n\nIf you're using the template repository, you can run the included tests:\n\n```bash\n# Run linting\nmise run lint\n\n# Run tests\nmise run test\n```\n\n### Debug Mode\n\nUse debug mode to see detailed plugin execution:\n\n```bash\nmise --debug install nodejs@20.0.0\n```\n\n### Plugin Test Script\n\nCreate a comprehensive test script:\n\n```bash\n#!/bin/bash\n# test/test.sh\nset -e\n\necho \"Testing nodejs plugin...\"\n\n# Install the plugin\nmise plugin install nodejs .\n\n# Test basic functionality\nmise install nodejs@18.18.0\nmise use nodejs@18.18.0\n\n# Verify installation\nnode --version | grep \"18.18.0\"\nnpm --version\n\n# Test legacy file support\necho \"20.0.0\" > .nvmrc\nmise use nodejs\nnode --version | grep \"20.0.0\"\n\n# Clean up\nrm -f .nvmrc\nmise plugin remove nodejs\n\necho \"All tests passed!\"\n```\n\n## Best Practices\n\n### Error Handling\n\nAlways provide meaningful error messages:\n\n```lua\nfunction PLUGIN:Available(ctx)\n    local http = require(\"http\")\n    local resp, err = http.get({\n        url = \"https://api.example.com/versions\"\n    })\n\n    if err ~= nil then\n        error(\"Failed to fetch versions from API: \" .. err)\n    end\n\n    if resp.status_code ~= 200 then\n        error(\"API returned status \" .. resp.status_code .. \": \" .. resp.body)\n    end\n\n    -- Process response...\nend\n```\n\n### Platform Detection\n\nHandle different operating systems properly using the RUNTIME object:\n\n```lua\n-- lib/platform.lua\nlocal M = {}\n\nfunction M.is_windows()\n    return RUNTIME.osType == \"Windows\"\nend\n\nfunction M.get_exe_extension()\n    return M.is_windows() and \".exe\" or \"\"\nend\n\nfunction M.get_path_separator()\n    return M.is_windows() and \"\\\\\" or \"/\"\nend\n\nreturn M\n```\n\n**Note:** The `RUNTIME` object is automatically available in all plugin hooks and provides:\n\n- `RUNTIME.osType`: Operating system type (\"Windows\", \"Linux\", \"Darwin\")\n- `RUNTIME.archType`: Architecture (\"amd64\", \"arm64\", \"386\", etc.)\n- `RUNTIME.envType`: libc environment type (`\"gnu\"` on glibc Linux, `\"musl\"` on musl Linux, `nil` on Windows/macOS and undetected systems)\n- `RUNTIME.version`: vfox runtime version\n- `RUNTIME.pluginDirPath`: Plugin directory path\n\n### Version Normalization\n\nNormalize versions consistently:\n\n```lua\nlocal function normalize_version(version)\n    -- Remove 'v' prefix if present\n    version = version:gsub(\"^v\", \"\")\n\n    -- Remove pre-release suffixes\n    version = version:gsub(\"%-.*\", \"\")\n\n    return version\nend\n```\n\n### Caching\n\nCache expensive operations:\n\n```lua\n-- Cache versions for 12 hours\nlocal cache = {}\nlocal cache_ttl = 12 * 60 * 60  -- 12 hours in seconds\n\nfunction PLUGIN:Available(ctx)\n    local now = os.time()\n\n    -- Check cache first\n    if cache.versions and cache.timestamp and (now - cache.timestamp) < cache_ttl then\n        return cache.versions\n    end\n\n    -- Fetch fresh data\n    local versions = fetch_versions_from_api()\n\n    -- Update cache\n    cache.versions = versions\n    cache.timestamp = now\n\n    return versions\nend\n```\n\n## Advanced Features\n\n### Conditional Installation\n\nDifferent installation logic based on platform or version:\n\n```lua\nfunction PLUGIN:PreInstall(ctx)\n    local version = ctx.version\n\n    -- Different logic for different platforms using RUNTIME object\n    if RUNTIME.osType == \"Windows\" then\n        -- Windows-specific installation\n        return install_windows(version)\n    elseif RUNTIME.osType == \"Darwin\" then\n        -- macOS-specific installation\n        return install_macos(version)\n    else\n        -- Linux installation\n        return install_linux(version)\n    end\nend\n```\n\n### Source Compilation\n\nFor plugins that need to compile from source:\n\n```lua\n-- hooks/post_install.lua\nfunction PLUGIN:PostInstall(ctx)\n    local sdkInfo = ctx.sdkInfo['tool-name']\n    local path = sdkInfo.path\n    local version = sdkInfo.version\n\n    -- Change to source directory\n    local build_dir = path .. \"/src\"\n\n    -- Configure build\n    local configure_result = os.execute(\"cd \" .. build_dir .. \" && ./configure --prefix=\" .. path)\n    if configure_result ~= 0 then\n        error(\"Configure failed\")\n    end\n\n    -- Compile\n    local make_result = os.execute(\"cd \" .. build_dir .. \" && make -j$(nproc)\")\n    if make_result ~= 0 then\n        error(\"Compilation failed\")\n    end\n\n    -- Install\n    local install_result = os.execute(\"cd \" .. build_dir .. \" && make install\")\n    if install_result ~= 0 then\n        error(\"Installation failed\")\n    end\nend\n```\n\n### Environment Configuration\n\nComplex environment variable setup:\n\n```lua\nfunction PLUGIN:EnvKeys(ctx)\n    local mainPath = ctx.path\n    local version = ctx.sdkInfo['tool-name'].version\n\n    local env_vars = {\n        -- Standard environment variables\n        {\n            key = \"TOOL_HOME\",\n            value = mainPath\n        },\n        {\n            key = \"TOOL_VERSION\",\n            value = version\n        },\n\n        -- PATH entries\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/bin\"\n        },\n        {\n            key = \"PATH\",\n            value = mainPath .. \"/scripts\"\n        },\n\n        -- Library paths\n        {\n            key = \"LD_LIBRARY_PATH\",\n            value = mainPath .. \"/lib\"\n        },\n        {\n            key = \"PKG_CONFIG_PATH\",\n            value = mainPath .. \"/lib/pkgconfig\"\n        }\n    }\n\n    -- Platform-specific additions\n    if RUNTIME.osType == \"Darwin\" then\n        table.insert(env_vars, {\n            key = \"DYLD_LIBRARY_PATH\",\n            value = mainPath .. \"/lib\"\n        })\n    end\n\n    return env_vars\nend\n```\n\n## Next Steps\n\n- [Start with the plugin template](https://github.com/jdx/mise-tool-plugin-template)\n- [Learn about Backend Plugin Development](backend-plugin-development.md)\n- [Explore available Lua modules](plugin-lua-modules.md)\n- [Publishing your plugin](plugin-publishing.md)\n- [View the vfox-nodejs plugin source](https://github.com/version-fox/vfox-nodejs)\n"
  },
  {
    "path": "docs/troubleshooting.md",
    "content": "# Troubleshooting\n\n## `mise activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile`\n\n`mise activate` should only be used in `rc` files. These are the interactive ones used when\na real user is using the terminal. (As opposed to being executed by an IDE or something). The prompt\nisn't displayed in non-interactive environments so PATH won't be modified.\n\nFor non-interactive setups, consider using shims instead which will route calls to the correct\ndirectory by looking at `PWD` every time they're executed. You can also call `mise exec` instead of\nexpecting things to be directly on PATH. You can also run `mise env` in a non-interactive shell,\nhowever that\nwill only setup the global tools. It won't modify the environment variables when entering into a\ndifferent project.\n\n::: warning\n`mise activate --shims` does not support all the features of `mise activate`.<br>\nSee [shims vs path](/dev-tools/shims.html#shims-vs-path) for more info.\n:::\n\nAlso see the [shebang](/tips-and-tricks#shebang) example for a way to make scripts call mise to get\nthe runtime.\nThat is another way to use mise without activation.\n\n## mise is failing or not working right\n\nFirst try setting `MISE_DEBUG=1` or `MISE_TRACE=1` and see if that gives you more information.\nYou can also set `MISE_LOG_FILE_LEVEL=debug MISE_LOG_FILE=/path/to/logfile` to write logs to a file.\n\nIf something is happening with the activate hook, you can try disabling it and\ncalling `eval \"$(mise hook-env)\"` manually.\nIt can also be helpful to use `mise env` which will just output environment variables that would be\nset.\nAlso consider using [shims](/dev-tools/shims.md) which can be more compatible.\n\nIf runtime installation isn't working right, try using the `--raw` flag which will install things in\nseries and connect stdin/stdout/stderr directly to the terminal. If a plugin is trying to interact\nwith you for some reason this will make it work.\n\nOf course check the version of mise with `mise --version` and make sure it is the latest.\nUse `mise self-update`\nto update it. `mise cache clean` can be used to wipe the internal cache and `mise implode` can be\nused\nto remove everything except config.\n\nLastly, there is `mise doctor` which will show diagnostic information and any warnings about issues\ndetected with your setup. If you submit a bug report, please include the output of `mise doctor`.\n\n## The wrong version of a tool is being used\n\nLikely this means that mise isn't first in PATH—using shims or `mise activate`. You can verify if\nthis is the case by calling `which -a`, for example, if node@20.0.0 is being used but mise specifies\nnode@24.0.0, first make sure that mise has this version installed and active by running `mise ls node`.\nIt should not say missing and have the correct \"Requested\" version:\n\n```bash\n$ mise ls node\nPlugin  Version  Config Source       Requested\nnode    24.0.0  ~/.mise/config.toml  24.0.0\n```\n\nIf `node -v` isn't showing the right version, make sure mise is activated by running `mise doctor`.\nIt should not have a \"problem\" listed about mise not being activated. Lastly, run `which -a node`.\nIf the directory listed is not a mise directory, then mise is not first in PATH. Whichever node is\nbeing run first needs to have its directory set before mise is. Typically this means setting PATH for\nmise shims at the end of bashrc/zshrc.\n\nIf using `mise activate`, you have another option of enabling `MISE_ACTIVATE_AGGRESSIVE=1` which will\nhave mise always prepend its tools to be first in PATH. If you're using something that also modifies\npaths dynamically like `mise activate` does, this may not work because the other tool may be modifying\nPATH after mise does.\n\nIf nothing else, you can run things with [`mise x --`](/cli/exec) to ensure that the correct version is being used.\n\n## New version of a tool is not available\n\nThere are 2 places that versions are cached so a brand new release might not appear right away.\n\nThe first is that the mise CLI caches versions for. The cache can be cleared with `mise cache clear`.\n\nThe second uses the <https://mise-versions.jdx.dev> host as a centralized\nplace to list all of the versions of most plugins. This is intended to speed up mise and also\nget around GitHub rate limits when querying for new versions. Check that repo for your plugin to\nsee if it has an updated version. This service can be disabled by\nsetting `MISE_USE_VERSIONS_HOST=0`.\n\nmise-versions itself also struggles with rate limits but you can help it to fetch more frequently by authenticating\nwith its [GitHub app](https://github.com/apps/mise-versions). It does not require any permissions since it simply\nfetches public repository information. The more people do this, the quicker\nmise will be able to fetch new versions of tools.\n\n## Windows problems\n\n::: warning\nVery basic support for windows is currently available, however because Windows can't support asdf\nplugins, they must use core and vfox only—which means only a handful of tools are available on\nWindows.\n:::\n\n### Path limits\n\nIf you have many tools defined in your `mise.toml` hierarchy, then it is possible that `mise x` will produce a `Path` environment variable that is too long for certain tools to handle, most notably, `cmd.exe`. This will affect `mise` tools that invoke `cmd.exe` (like `npm install`).\n\nYou have a few options:\n\n1. Set the `MISE_INSTALLS_DIR` environment variable to a shorter location, e.g. `C:\\.mise-installs`.\n1. Use `powershell.exe` or `pwsh.exe` instead of `cmd.exe`, since they can handle a longer `Path`.\n1. Re-organise the `mise.toml` files in your monorepo, to specify only the tools they need.\n\nYou can run the following command to test whether you have hit the `cmd.exe` `Path` limitation:\n\n```powershell\n# Path is within limits\n❯ mise x -- cmd.exe /d /s /c \"where.exe where\"\nC:\\Windows\\System32\\where.exe\n# Path exceeds cmd.exe limits\n❯ mise x -- cmd.exe /d /s /c \"where.exe where\"\n'where.exe' is not recognized as an internal or external command,\noperable program or batch file.\nmise ERROR command failed: exit code 1\nmise ERROR Run with --verbose or MISE_VERBOSE=1 for more information\n```\n\n## mise isn't working when calling from tmux or another shell initialization script\n\n`mise activate` will not update PATH until the shell prompt is displayed. So if you need to access a\ntool provided by mise before the prompt is displayed you can either\n[add the shims to your PATH](/dev-tools/shims.html#how-to-add-mise-shims-to-path) e.g.\n\n```bash\nexport PATH=\"$HOME/.local/share/mise/shims:$PATH\"\npython --version # will work after adding shims to PATH\n```\n\nOr you can manually call `hook-env`:\n\n```bash\neval \"$(mise activate bash)\"\neval \"$(mise hook-env)\"\npython --version # will work only after calling hook-env explicitly\n```\n\nFor more information, see [What does `mise activate` do?](/faq#what-does-mise-activate-do)\n\n## Is mise secure?\n\nProviding a secure supply chain is incredibly important. mise already provides a more secure\nexperience when compared to asdf. Security-oriented evaluations and contributions are welcome.\nWe also urge users to look after the plugins they use, and urge plugin authors to look after\nthe users they serve.\n\nFor more details see [SECURITY.md](https://github.com/jdx/mise/blob/main/SECURITY.md).\n\n## 403 Forbidden when installing a tool\n\nYou may get an error like one of the following:\n\n```text\nHTTP status client error (403 Forbidden) for url\n403 API rate limit exceeded for\n```\n\nThis can happen if the tool is hosted on GitHub, and you've hit the API rate limit. This is especially\ncommon running mise in a CI environment like GitHub Actions. If you don't have a `GITHUB_TOKEN`\nset, the rate limit is quite low. You can fix this by creating a GitHub token (which needs no scopes)\nby going to [https://github.com/settings/tokens/new](https://github.com/settings/tokens/new?description=MISE_GITHUB_TOKEN) and setting it as an environment variable. You can\nuse any of the following (in order of preference):\n\n- `MISE_GITHUB_TOKEN`\n- `GITHUB_TOKEN`\n- `GITHUB_API_TOKEN`\n\n## Auto-install on command not found handler does not work for new tools\n\nIf you are expecting mise to automatically install a tool when you run a command that is not found (using the [`not_found_auto_install`](/configuration/settings.html#not_found_auto_install) feature), be aware of an important limitation:\n\n**mise can only auto-install missing versions of tools that already have at least one version installed.**\n\nThis is because mise does not have a way of knowing which binaries a tool provides unless there is already an installed (even inactive) version of that tool. If you have never installed any version of a tool, mise cannot determine which tool is responsible for a given binary name, and so it cannot auto-install it on demand.\n\n**Workarounds:**\n\n- Manually install at least one version of the tool you want to be auto-installed in the future. After that, the auto-install feature will work for missing versions of that tool.\n- Use [`mise x|exec`](/cli/exec) or [`mise r|run`](/cli/run) to trigger auto-install for missing tools, even if no version is currently installed. These commands will attempt to install the required tool versions automatically.\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"esnext\",\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"noUnusedLocals\": true,\n    \"resolveJsonModule\": true,\n    \"verbatimModuleSyntax\": true,\n    \"jsx\": \"preserve\",\n    \"lib\": [\"esnext\", \"dom\", \"dom.iterable\"]\n  },\n  \"exclude\": [\n    \"**/node_modules/**\",\n    \"**/dist/**\",\n    \"template\",\n    \"bin\",\n    \"docs/snippets\",\n    \"scripts\"\n  ]\n}\n"
  },
  {
    "path": "docs/url-replacements.md",
    "content": "# URL Replacements\n\nmise does not include a built-in registry for downloading artifacts.\nInstead, it retrieves remote registry manifests, which specify the URLs for downloading tools.\n\nIn some environments — such as enterprises or DMZs — these URLs may not be directly accessible and must be accessed through a proxy or internal mirror.\n\nURL replacements allow you to modify or redirect any URL that mise attempts to access, making it possible to use internal proxies, mirrors, or alternative sources as needed.\n\n## Configuration Examples\n\nIn mise.toml (single line):\n\n```toml\n[settings]\nurl_replacements = { \"example.com\" = \"mirror.example.com\" }\n```\n\nIn mise.toml (multiline):\n\n```toml\n[settings.url_replacements]\n\"example.com\" = \"mirror.example.com\"\n\"releases.hashicorp.com\" = \"hashicorp.example.com\"\n```\n\nRegEx example:\n\n```toml\n[settings.url_replacements]\n\"regex:^http://(.+)\" = \"https://$1\"\n\"regex:^https://github\\\\.com/([^/]+)/([^/]+)/releases/download/(.+)\" = \"https://hub.example.com/artifactory/github/$1/$2/$3\"\n```\n\n## Simple Hostname Replacement\n\nFor simple hostname-based mirroring, the key is the original hostname/domain to replace,\nand the value is the replacement string. The replacement happens by searching and replacing\nthe pattern anywhere in the full URL string (including protocol, hostname, path, and query parameters).\n\nExamples:\n\n- `github.com` -> `mirror.example.com` replaces GitHub hostnames\n- `https://github.com` -> `https://mirror.example.com` with protocol excludes e.g. 'api.github.com'\n- `https://github.com` -> `https://proxy.example.com/github-mirror` replaces GitHub with corporate proxy\n- `http://example.net` -> `https://example.net` replaces protocol from HTTP to HTTPS\n\nSee [Security Considerations](#security-considerations) for important warnings about credential handling.\n\n## Advanced Regex Replacement\n\nFor more complex URL transformations, you can use regex patterns. When a key starts with `regex:`,\nit is treated as a regular expression pattern that can match and transform any part of the URL.\nThe value can use capture groups from the regex pattern.\n\n### Regex Examples\n\n#### 1. Protocol Conversion (HTTP to HTTPS)\n\n```toml\n[settings]\nurl_replacements = {\n  \"regex:^http://(.+)\" = \"https://$1\"\n}\n```\n\nThis converts any HTTP URL to HTTPS by capturing everything after \"http://\" and replacing it with \"https://\".\n\n#### 2. GitHub Release Mirroring with Path Restructuring\n\n```toml\n[settings]\nurl_replacements = {\n  \"regex:^https://github\\\\.com/([^/]+)/([^/]+)/releases/download/(.+)\" =\n    \"https://hub.example.com/artifactory/github/$1/$2/$3\"\n}\n```\n\nTransforms `https://github.com/owner/repo/releases/download/v1.0.0/file.tar.gz`\nto `https://hub.example.com/artifactory/github/owner/repo/v1.0.0/file.tar.gz`\n\n#### 3. Subdomain to Path Conversion\n\n```toml\n[settings]\nurl_replacements = {\n  \"regex:^https://([^.]+)\\\\.cdn\\\\.example\\\\.com/(.+)\" =\n    \"https://unified-cdn.example.com/$1/$2\"\n}\n```\n\nConverts subdomain-based URLs to path-based URLs on a unified CDN.\n\n#### 4. Multiple Replacement Patterns (processed in order)\n\n```toml\n[settings]\nurl_replacements = {\n  \"regex:^https://github\\\\.com/microsoft/(.+)\" =\n    \"https://internal.example.org/microsoft/$1\",\n  \"regex:^https://github\\\\.com/(.+)\" =\n    \"https://public.example.org/github/$1\",\n  \"releases.hashicorp.com\" = \"hashicorp.example.net\"\n}\n```\n\nFirst regex catches Microsoft repositories specifically, second catches all other GitHub URLs,\nand the simple replacement handles HashiCorp.\n\n## Use Cases\n\n1. **Corporate Mirrors**: Replace public download URLs with internal corporate mirrors\n2. **Custom Registries**: Redirect package downloads to custom or private registries\n3. **Geographic Optimization**: Route downloads to geographically closer mirrors\n4. **Protocol Changes**: Convert HTTP URLs to HTTPS or vice versa\n\n## Regex Syntax\n\nmise uses Rust regex engine which supports:\n\n- `^` and `$` for anchors (start/end of string)\n- `(.+)` for capture groups (use `$1`, `$2`, etc. in replacement)\n- `[^/]+` for character classes (matches any character except `/`)\n- `\\\\.` for escaping special characters (note: double backslash required in TOML)\n- `*`, `+`, `?` for quantifiers\n- `|` for alternation\n\nYou can check on regex101.com if your regex works (see [example](https://regex101.com/r/rmcIE1/1)).\nFull regex syntax documentation: <https://docs.rs/regex/latest/regex/#syntax>\n\n## Precedence and Matching\n\n- URL replacements are processed in the order they appear in the configuration (IndexMap insertion order)\n- Both regex patterns (keys starting with `regex:`) and simple string replacements are processed in this same order\n- The first matching pattern is used; subsequent patterns are ignored for that URL\n- If no patterns match, the original URL is used unchanged\n\n## Security Considerations\n\nWhen using regex patterns, ensure your replacement URLs point to trusted sources,\nas this feature can redirect tool downloads to arbitrary locations.\n\n> [!WARNING]\n> **Credential Leaking**: When using `url_replacements`, any authentication headers (like `Authorization: Bearer <TOKEN>`) generated for the original URL (e.g., `api.github.com`) are **preserved** and sent to the replaced URL.\n>\n> This is by design to allow authentication with internal proxies that forward requests to upstream services (GitHub, GitLab, Forgejo, etc.). However, it means you must **only** replace URLs with trusted servers. Redirecting to an untrusted server will leak your credentials to that server.\n>\n> **Best Practice**: Use the `^` anchor in your regex patterns to ensure you are matching the start of the URL.\n>\n> **Bad**: `\"regex:github\\\\.com\"` (matches `evil-github.com`)\n> **Good**: `\"regex:^https://github\\\\.com\"` (only matches actual GitHub URLs)\n\n## Authentication\n\nURL replacements can be used with `~/.netrc` (or `~/_netrc` on Windows) to authenticate with the replaced URL.\nReplacements are applied _before_ the netrc lookup, so you should use the hostname of the _replaced_ URL in your netrc file.\n\nFor example, if you have this in `mise.toml`:\n\n```toml\n[settings]\nurl_replacements = { \"regex:^https://github\\\\.com\" = \"https://nexus.example.com\" }\n```\n\n> [!NOTE]\n> Credentials from `.netrc` take precedence over and will **overwrite** any default authentication headers (such as those from `MISE_GITHUB_TOKEN` or other environment variables).\n\nYou should have this in `~/.netrc`:\n\n```netrc\nmachine nexus.example.com\n  login myusername\n  password mypassword\n```\n"
  },
  {
    "path": "docs/walkthrough.md",
    "content": "# Walkthrough\n\nOnce you've completed the [Getting Started](/getting-started) guide, you're ready to start using mise.\nThis document offers a quick overview on some initial things you may want to try out.\n\n## Installing Dev Tools\n\nThe main command for working with tools in mise is [`mise u|use`](/cli/use). This does 2 main things:\n\n- Installs tools (if not already installed)\n- Adds the tool to the `mise.toml` configuration file—in mise I say the tool is \"active\" if it's in `mise.toml`\n\n:::warning\nBoth of these are required to use a tool. If you simply install a tool via `mise install`, it won't be available in your shell.\nIt must also be added to `mise.toml`—which is why I promote using `mise use` since it does both.\n:::\n\nYou use it like so (note that `mise` must be [activated](/getting-started.html#activate-mise) for this example to work):\n\n```bash\nmkdir example-project && cd example-project\nmise use node@24\nnode -v\n# v24.x.x\n```\n\nAnd you'll also note that you now have a `mise.toml` file with the following content:\n\n```mise-toml [mise.toml]\n[tools]\nnode = \"24\"\n```\n\n- If this file is in the root of a project, `node` will be installed whenever someone runs [`mise install|i`](/cli/install).\n- This is the command you want to run when you first clone a project or when you want to update installed tools.\n\n## `mise.toml` Configuration\n\nYou can create a `mise.toml` file manually or with the CLI.\n\n> [!TIP]\n> Use `mise edit` to open an interactive editor for your configuration. It provides a TUI where you can navigate sections, add tools from the registry with fuzzy search, and configure settings with schema-aware autocompletion.\n\nUse [`mise.toml`](/configuration#mise-toml) to share your tool configurations with others. This file should be committed to version control and contains the common toolset needed for your project.\n\nFor tools or settings you want to keep private, use [`mise.local.toml`](/configuration#mise-toml). This file should be added to `.gitignore` and is perfect for personal preferences or configurations.\n\n`mise` supports nested configuration files that cascade from broad to specific settings:\n\n1. `~/.config/mise/config.toml` - Global settings for all projects\n2. `~/work/mise.toml` - Work-specific settings\n3. `~/work/project/mise.toml` - Project-specific settings\n4. `~/work/project/mise.local.toml` - Project-specific settings that should not be shared\n\n`mise` will use all the parent directories together to determine the set of tools—overriding configuration as it goes lower in the hierarchy.\n\n:::tip\nUse [`mise config ls`](/cli/config/ls) to see the configuration files currently used by `mise`.\n:::\n\nIn general, it's preferred to use loose versions like this in `mise` so that other people working\non a project don't have to worry about the exact version of a tool you're using. If you'd like to\npin the version to enforce a specific version, use `mise use --pin` or the [`lockfile`](/configuration/settings#lockfile) setting.\n\nIf you leave out the version, then mise will default to `node@latest`.\n\n## Dev Tool Backends\n\nTools are installed with a variety of backends like `asdf`, `github`, or `vfox`. See [registry](/registry.html) for\nthe full list of shorthands like `node` you can use.\n\nYou can also use other backends like `npm` or `cargo`\nwhich can install any package from their respective registries:\n\n```bash\nmise use npm:@antfu/ni\nmise use cargo:starship\n```\n\n## Upgrading Dev Tools\n\nUpgrading tool versions can be done with [`mise up|upgrade`](/cli/upgrade). By default, it will respect\nthe version prefix in `mise.toml`. If a [lockfile](/configuration/settings#lockfile) exists,\nmise will update `mise.lock` to the latest version of the tool with the prefix from `mise.toml`.\n\nSo if you have `node = \"24\"` in `mise.toml`, then `mise upgrade node` will upgrade to the latest version of `node 24`.\n\nIf you'd like to upgrade to the latest version of node, you can use `mise upgrade --bump node`. It will set the version\nat the same specificity as the current version, so if you have `node = \"24\"`, but use `mise upgrade --bump node` to update to\n`node@26`, then it will set `node = \"26\"` in `mise.toml`.\n\n_See [Dev Tools](/dev-tools/) for more information on working with tools._\n\n## Setting Environment Variables\n\nmise can also be used to set environment variables for your project. You can set environment variables\nwith the CLI:\n\n```bash\nmise set MY_VAR=123\necho $MY_VAR\n# 123\n```\n\nOr by directly modifying `mise.toml`:\n\n```toml\n[env]\nMY_VAR = \"123\"\n```\n\nSome examples on where this can be used:\n\n- Setting `NODE_ENV` for a Node.js project\n- Setting `DATABASE_URL` for a database connection\n- Setting `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` for AWS\n- Setting `RUST_TEST_THREADS=1` to run cargo tests in series\n\nYou can also modify `PATH` with `mise.toml`.\nThis example makes CLIs installed with `npm` available:\n\n```toml\n[env]\n_.path = \"./node_modules/.bin\"\n```\n\nThis will add `./node_modules/.bin` to the PATH for the project—with \".\" here referring to the directory\nthe `mise.toml` file is in so if you enter a subdirectory, it will still work.\n\n_See [Environments](/environments/) for more information on working with environment variables._\n\n## Tasks\n\nTasks are defined in a project to execute commands.\n\nYou can define tasks in a `mise.toml`:\n\n```mise-toml [mise.toml]\n[tasks]\nbuild = \"npm run build\"\ntest = \"npm test\"\n```\n\nOr in a `mise-tasks` directory as a standalone file, such as `mise-tasks/build`:\n\n```bash [mise-tasks/build]\n#!/bin/bash\nnpm run build\n```\n\nTasks are executed with [`mise r|run`](/cli/run):\n\n```bash\nmise run build\nmise run test\n```\n\n:::tip\n`mise run` sets up the \"mise environment\" before running the task (tools and environment variables).\nSo if you'd rather not activate mise in your shell, you can use `mise run` to run tasks, and it will\nhave the tools in PATH and the environment variables from `mise.toml` set.\n:::\n\n`mise` is paired with [usage](https://usage.jdx.dev) which provides lots of features for documenting and running tasks.\n\nHere is an example of a task with usage spec:\n\n```bash [mise-tasks/greet]\n#!/usr/bin/env bash\nset -e\n\n#MISE description=\"Greet a user with a message\"\n#USAGE flag \"-g --greeting <greeting>\" help=\"The greeting word to use\" {\n#USAGE   choices \"hi\" \"hello\" \"hey\"\n#USAGE }\n#USAGE flag \"-u --user <user>\" help=\"The user to greet\"\n#USAGE flag \"--dir <dir>\" help=\"The directory to greet from\" default=\".\"\n#USAGE complete \"dir\" run=\"find . -maxdepth 1 -type d\"\n#USAGE arg \"<message>\" help=\"Greeting message\"\n\necho \"all available options are in the env with the prefix 'usage_'\"\nenv | grep usage_\n\necho \"${usage_greeting?}, ${usage_user?}! Your message is: ${usage_message?}\"\n```\n\nThis task can be run like so:\n\n```shell\nmise run greet --user jdx -g \"hey\" \"How are you?\"\n```\n\n- The options will all be passed as environment variables prefixed with `usage_` like `usage_user`.\n- Help is available with `mise run greet --help` and will show the options defined in the task.\n- Completions are available like you'd expect, so typing `mise run greet --greeting <tag>` will show `hi`, `hello`, and `hey`\n  as options.\n- [Custom completion](https://usage.jdx.dev/spec/reference/complete) can be provided by a CLI. `mise run greet --dir <tab>` will execute `find . -maxdepth 1 -type d` to provide completions.\n\nTo get the autocompletion working, set up [mise autocompletions](/installing-mise.html#autocompletion).\n\n_See [Tasks](/tasks/) for more information on working with tasks._\n\n## Common Commands\n\nSince there are a lot of commands available in mise, here are what I consider the most important:\n\n- [`mise completion`](/cli/completion) – Set up completions for your shell.\n- [`mise cfg|config`](/cli/config) – A bunch of commands for working with `mise.toml` files via the CLI.\n- [`mise x|exec`](/cli/exec) – Execute a command in the mise environment without activating mise.\n- [`mise g|generate`](/cli/generate) – Generates things like git hooks, task documentation, GitHub actions, and more for your project.\n- [`mise i|install`](/cli/install) – Install tools.\n- [`mise link`](/cli/link) – Symlink a tool installed by some other means into the mise.\n- [`mise ls-remote`](/cli/ls-remote) – List all available versions of a tool.\n- [`mise ls`](/cli/ls) – Lists information about installed/active tools.\n- [`mise outdated`](/cli/outdated) – Informs you of any tools with newer versions available.\n- [`mise plugin`](/cli/plugins) – Plugins can extend mise with new functionality like extra tools or environment variable management. Commonly, these are simply asdf plugins or modern plugins.\n- [`mise r|run`](/cli/run) – Run a task defined in `mise.toml` or `mise-tasks`.\n- [`mise self-update`](/cli/self-update) – Update mise to the latest version. Don't use this if you installed mise via a package manager.\n- [`mise settings`](/cli/settings) – CLI access to get/set configuration settings.\n- [`mise rm|uninstall`](/cli/uninstall) – Uninstall a tool.\n- [`mise up|upgrade`](/cli/upgrade) – Upgrade tool versions.\n- [`mise u|use`](/cli/use) – Install and activate tools.\n- [`mise w|watch`](/cli/watch) – Watch for changes in a project and run tasks when they occur.\n\n## Final Thoughts\n\nDev tools, env vars, and tasks work together to make managing your development environment easier—especially\nwhen working with others. The goal is to have a consistent UX to interface with projects regardless of the\nprogramming languages or tools used on it.\n\nFor further reading:\n\n- [Dev Tools](/dev-tools/) – A deeper overview of working with dev tools\n- [Environments](/environments/) – A deeper overview of working with environment variables\n- [Tasks](/tasks/) – A deeper overview of working with tasks\n- [Configuration](/configuration) – More information on `mise.toml` files\n- [Settings](/configuration/settings) – All the configuration settings available in mise\n- [Backends](/dev-tools/backends/) – An index of all the backends available in mise\n- [Registry](/registry) – Every \"shorthand\" available for tools in mise like `node`, `terraform`, or `watchexec` which point to `core:node`, `asdf:asdf-community/asdf-hashicorp`, and `aqua:watchexec/watchexec` respectively\n- [CLI](/cli/) – The full list of commands available in mise\n"
  },
  {
    "path": "e2e/.gitignore",
    "content": ".e2e.mise.toml\n.local\n.cache\n.config\n.asdf\n.default-go-packages\n.venv\nruby/Gemfile\nruby/.ruby-version\nLibrary\n/pyproject.toml\n/poetry.lock\n/test-e2e/\nenv.d\nsource.d\n"
  },
  {
    "path": "e2e/assert.sh",
    "content": "#!/usr/bin/env bash\n\n# shellcheck source-path=SCRIPTDIR\nsource \"$TEST_ROOT/style.sh\"\n\n# shellcheck disable=SC2034,SC2016\nLOCKFILE_HEADER='# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html'\n\nfail() {\n\ttitle=\"E2E assertion failed\" err \"$*\"\n\texit 1\n}\n\n# Portable timeout helper for e2e tests.\n# Uses system timeout/gtimeout when available, otherwise falls back to a\n# shell implementation that returns 124 on timeout.\nrun_with_timeout() {\n\tlocal seconds=\"$1\"\n\tshift\n\n\tlocal output_file\n\toutput_file=\"$(mktemp)\"\n\n\t(\"$@\" >\"$output_file\" 2>&1) &\n\tlocal cmd_pid=$!\n\tlocal elapsed=0\n\tlocal timed_out=0\n\n\twhile kill -0 \"$cmd_pid\" 2>/dev/null; do\n\t\tif ((elapsed >= seconds * 10)); then\n\t\t\ttimed_out=1\n\t\t\tkill -TERM \"$cmd_pid\" 2>/dev/null || true\n\t\t\tsleep 0.2\n\t\t\tkill -KILL \"$cmd_pid\" 2>/dev/null || true\n\t\t\twait \"$cmd_pid\" 2>/dev/null || true\n\t\t\tbreak\n\t\tfi\n\t\tsleep 0.1\n\t\telapsed=$((elapsed + 1))\n\tdone\n\n\tlocal status=0\n\tif ((timed_out == 1)); then\n\t\tstatus=124\n\telse\n\t\twait \"$cmd_pid\" || status=$?\n\tfi\n\n\tcat \"$output_file\"\n\trm -f \"$output_file\"\n\treturn \"$status\"\n}\n\nparse_timeout_seconds() {\n\tlocal duration=\"$1\"\n\tif [[ ! $duration =~ ^[0-9]+[smh]?$ ]]; then\n\t\treturn 1\n\tfi\n\tcase \"$duration\" in\n\t*s)\n\t\techo \"${duration%s}\"\n\t\t;;\n\t*m)\n\t\techo $((10#${duration%m} * 60))\n\t\t;;\n\t*h)\n\t\techo $((10#${duration%h} * 3600))\n\t\t;;\n\t*)\n\t\techo $((10#$duration))\n\t\t;;\n\tesac\n}\n\ntimeout() {\n\tif type -P timeout >/dev/null 2>&1; then\n\t\tcommand timeout \"$@\"\n\t\treturn $?\n\tfi\n\tif type -P gtimeout >/dev/null 2>&1; then\n\t\tcommand gtimeout \"$@\"\n\t\treturn $?\n\tfi\n\tif [[ $# -lt 2 ]]; then\n\t\techo \"timeout fallback requires DURATION and COMMAND\" >&2\n\t\treturn 125\n\tfi\n\tlocal seconds\n\tseconds=\"$(parse_timeout_seconds \"$1\")\" || {\n\t\techo \"unsupported timeout duration: $1\" >&2\n\t\treturn 125\n\t}\n\tshift\n\trun_with_timeout \"$seconds\" \"$@\"\n}\n\n# Safeguard against running the test directly, which would execute in the actual user home\n[[ -n ${TEST_NAME:-} ]] || fail \"tests should be called using run_test\"\n\nquiet_assert_succeed() {\n\tlocal status=0\n\tdebug \"$ $1\"\n\tbash -c \"$1\" || status=$?\n\tif [[ $status -ne 0 ]]; then\n\t\tfail \"[$1] command failed with status $status\"\n\tfi\n}\nquiet_assert_fail() {\n\tlocal status=0\n\tdebug \"$ $1\"\n\tMISE_FRIENDLY_ERROR=1 RUST_BACKTRACE=0 bash -c \"$1 2>&1\" || status=$?\n\tif [[ $status -eq 0 ]]; then\n\t\tfail \"[$1] command succeeded but was expected to fail\"\n\tfi\n}\n\nassert_succeed() {\n\tif quiet_assert_succeed \"$1\"; then\n\t\tok \"[$1] expected success\"\n\tfi\n}\n\nassert_fail() {\n\tlocal actual\n\tactual=\"$(quiet_assert_fail \"$1\")\"\n\tif [[ -z ${2:-} ]]; then\n\t\tok \"[$1] expected failure\"\n\telif [[ $actual == *\"$2\"* ]]; then\n\t\tok \"[$1] output is equal to '$2'\"\n\telse\n\t\tfail \"[$1] expected '$2' but got '$actual'\"\n\tfi\n}\n\nassert() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ -z ${2:-} ]]; then\n\t\tok \"[$1]\"\n\telif [[ $actual == \"$2\" ]]; then\n\t\tok \"[$1] output is equal to '$2'\"\n\telse\n\t\tfail \"[$1] expected '$2' but got '$actual'\"\n\tfi\n}\n\nassert_json() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif jq -e . >/dev/null <<<\"$actual\"; then\n\t\tok \"[$1] output is valid JSON\"\n\telse\n\t\tfail \"[$1] output is not valid JSON\"\n\tfi\n\n\tactual_json=\"$(jq . <<<\"$actual\")\"\n\texpected_json=\"$(jq . <<<\"$2\")\"\n\tif [[ $actual_json == \"$expected_json\" ]]; then\n\t\tok \"[$1] output is equal to '$2'\"\n\telse\n\t\tdiff --side-by-side <(jq . <<<\"$expected_json\") <(jq . <<<\"$actual_json\") || true\n\t\tfail \"JSON output from [$1] is different from expected\"\n\tfi\n}\n\nassert_json_partial_array() {\n\tlocal command=\"$1\" fields=\"$2\" expected=\"$3\"\n\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$command\")\"\n\n\tlocal filter=\"map({$fields})\"\n\tlocal actual_filtered expected_filtered\n\n\tactual_filtered=\"$(jq -S \"$filter\" <<<\"$actual\")\"\n\texpected_filtered=\"$(jq -S \"$filter\" <<<\"$expected\")\"\n\n\tif [[ $actual_filtered == \"$expected_filtered\" ]]; then\n\t\tok \"[$command] partial array match successful\"\n\telse\n\t\techo \"Expected:\"\n\t\techo \"$expected_filtered\"\n\t\techo \"Got:\"\n\t\techo \"$actual_filtered\"\n\t\tfail \"[$command] partial array match failed\"\n\tfi\n}\n\nassert_json_partial_object() {\n\tlocal command=\"$1\" fields=\"$2\" expected=\"$3\"\n\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$command\")\"\n\n\t# shellcheck disable=SC2016\n\tlocal filter='with_entries(select(.key as $k | ($fields | split(\",\")) | contains([$k])))'\n\tlocal actual_filtered expected_filtered\n\n\tactual_filtered=\"$(jq -S --arg fields \"$fields\" \"$filter\" <<<\"$actual\")\"\n\texpected_filtered=\"$(jq -S --arg fields \"$fields\" \"$filter\" <<<\"$expected\")\"\n\n\tif [[ $actual_filtered == \"$expected_filtered\" ]]; then\n\t\tok \"[$command] partial object match successful\"\n\telse\n\t\techo \"Expected:\"\n\t\techo \"$expected_filtered\"\n\t\techo \"Got:\"\n\t\techo \"$actual_filtered\"\n\t\tfail \"[$command] partial object match failed\"\n\tfi\n}\n\nassert_not() {\n\tlocal actual\n\tdebug \"$ $1\"\n\tactual=\"$(bash -c \"$1\" || true)\"\n\tif [[ $actual != \"$2\" ]]; then\n\t\tok \"[$1] output is different from '$2'\"\n\telse\n\t\tfail \"[$1] expected '$2' not to be in '$actual'\"\n\tfi\n}\n\nassert_contains() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ $actual == *\"$2\"* ]]; then\n\t\tok \"[$1] '$2' is in output\"\n\telse\n\t\tfail \"[$1] expected '$2' to be in '$actual'\"\n\tfi\n}\n\nassert_not_contains() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ $actual != *\"$2\"* ]]; then\n\t\tok \"[$1] '$2' is not in output\"\n\telse\n\t\tfail \"[$1] expected '$2' not to be in '$actual'\"\n\tfi\n}\n\nassert_matches() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ $actual =~ $2 ]]; then\n\t\tok \"[$1] '$2' matches output\"\n\telse\n\t\tfail \"[$1] expected '$2' to match '$actual'\"\n\tfi\n}\n\nassert_fail_contains() {\n\tlocal actual\n\tactual=\"$(quiet_assert_fail \"$1\")\"\n\tif [[ $actual == *\"$2\"* ]]; then\n\t\tok \"[$1] '$2' is in failure output\"\n\telse\n\t\tfail \"[$1] expected '$2' to be in '$actual'\"\n\tfi\n}\n\nassert_fail_matches() {\n\tlocal actual\n\tactual=\"$(quiet_assert_fail \"$1\")\"\n\tif [[ $actual =~ $2 ]]; then\n\t\tok \"[$1] failure matches '$2'\"\n\telse\n\t\tfail \"[$1] expected failure to match '$2' but got '$actual'\"\n\tfi\n}\n\nassert_empty() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ -z $actual ]]; then\n\t\tok \"[$1] output is empty\"\n\telse\n\t\tfail \"[$1] expected empty output but got '$actual'\"\n\tfi\n}\n\nassert_not_empty() {\n\tlocal actual\n\tactual=\"$(quiet_assert_succeed \"$1\")\"\n\tif [[ -n $actual ]]; then\n\t\tok \"[$1] output is not empty\"\n\telse\n\t\tfail \"[$1] expected non-empty output but got empty\"\n\tfi\n}\n\nassert_directory_exists() {\n\tif [[ -d $1 ]]; then\n\t\tok \"[$1] directory exists\"\n\telse\n\t\tfail \"[$1] directory does not exist\"\n\tfi\n}\n\nassert_directory_not_exists() {\n\tif [[ ! -d $1 ]]; then\n\t\tok \"[$1] directory does not exist\"\n\telse\n\t\tfail \"[$1] directory exists\"\n\tfi\n}\n\nassert_directory_empty() {\n\tif [[ -z \"$(ls -A \"$1\")\" ]]; then\n\t\tok \"[$1] directory is empty\"\n\telse\n\t\tfail \"[$1] directory is not empty\"\n\tfi\n}\n\nassert_directory_not_empty() {\n\tif [[ -n \"$(ls -A \"$1\")\" ]]; then\n\t\tok \"[$1] directory is not empty\"\n\telse\n\t\tfail \"[$1] directory is empty\"\n\tfi\n}\n\nrequire_cmd() {\n\tif ! type -p \"$1\" >/dev/null; then\n\t\ttitle=\"E2E test $TEST_NAME aborted\" err \"'$1' is required but was not found in PATH\"\n\t\texit 2\n\tfi\n}\n\n# Detect platform key for lockfile tests\n# Sets: MISE_PLATFORM, MISE_PLATFORM_OS, MISE_PLATFORM_ARCH\ndetect_platform() {\n\tlocal os arch\n\tos=$(uname -s)\n\tarch=$(uname -m)\n\tcase \"$os\" in\n\tDarwin)\n\t\tMISE_PLATFORM_OS=\"macos\"\n\t\t;;\n\tLinux)\n\t\tMISE_PLATFORM_OS=\"linux\"\n\t\t;;\n\t*)\n\t\tMISE_PLATFORM_OS=\"unknown\"\n\t\t;;\n\tesac\n\tcase \"$arch\" in\n\tarm64 | aarch64)\n\t\tMISE_PLATFORM_ARCH=\"arm64\"\n\t\t;;\n\t*)\n\t\tMISE_PLATFORM_ARCH=\"x64\"\n\t\t;;\n\tesac\n\tMISE_PLATFORM=\"${MISE_PLATFORM_OS}-${MISE_PLATFORM_ARCH}\"\n\texport MISE_PLATFORM MISE_PLATFORM_OS MISE_PLATFORM_ARCH\n}\n"
  },
  {
    "path": "e2e/backend/test_aqua",
    "content": "#!/usr/bin/env bash\n\nexport MISE_EXPERIMENTAL=1\n\ntest() {\n\tassert_contains \"mise x $1 -- $2\" \"$3\"\n}\n\ntest aqua:BurntSushi/ripgrep@14.0.0 \"rg --version\" \"ripgrep 14.0.0\"\ntest age@1.2.0 \"age --version\" \"v1.2.0\"\ntest aqua:helm/helm@3.16.3 \"helm version\" \"v3.16.3\"\ntest aqua:crate-ci/typos@1.27.3 \"typos --version\" \"typos-cli 1.27.3\"\ntest aqua:gruntwork-io/terragrunt@0.77.22 \"terragrunt --version\" \"terragrunt version v0.77.22\"\n# Test gradle to verify pipe expression parsing works (fixes #7068)\n# Use 'mise which' instead of running gradle since it requires Java\nassert_contains \"mise x gradle@8.14.3 -- which gradle\" \"gradle-8.14.3/bin/gradle\"\n\nassert_contains \"MISE_USE_VERSIONS_HOST=0 mise ls-remote aqua:sharkdp/hyperfine\" \"1.8.0\n1.9.0\n1.10.0\n1.11.0\"\n"
  },
  {
    "path": "e2e/backend/test_aqua_cosign",
    "content": "#!/usr/bin/env bash\n# Test native Cosign verification for aqua packages\n\nset -euo pipefail\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_AQUA_COSIGN=true\nexport MISE_AQUA_SLSA=false\n\necho \"=== Testing Native Cosign Verification ===\"\n\n# Test: Install sops which has cosign signatures configured (v3.8.0+)\necho \"Installing sops with native Cosign verification...\"\n\n# Capture the installation output to verify the native verification is being used\noutput=$(mise install aqua:getsops/sops@3.9.0 2>&1)\necho \"$output\"\n\n# Verify the native Cosign verification was used\nif echo \"$output\" | grep -q \"verify checksums with cosign\"; then\n\techo \"✅ Native Cosign verification was used\"\nelse\n\techo \"❌ ERROR: Cosign verification message not found in output\"\n\techo \"Output was:\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Verify the tool works\nassert_contains \"mise x aqua:getsops/sops@3.9.0 -- sops --version\" \"3.9.0\"\necho \"✓ sops installed and working correctly\"\n\n# Cleanup\nmise uninstall aqua:getsops/sops@3.9.0 || true\n\necho \"\"\necho \"=== Native Cosign Verification Test Passed ✓ ===\"\n"
  },
  {
    "path": "e2e/backend/test_aqua_failed_install_cleanup",
    "content": "#!/usr/bin/env bash\n# Regression test: failed installs should not leave empty parent directories.\n#\n# Before the fix, cleanup_install_dirs_on_error only removed the version-specific\n# subdirectory (e.g. installs/tilt/9999.9999.9999) but left the parent\n# (installs/tilt/) as an empty directory behind.\n\n# Trigger a failed install using a non-existent version number.\n# This causes the GitHub API to return 404 after create_install_dirs() has\n# already created installs/tilt/9999.9999.9999.\nassert_fail \"mise x tilt@9999.9999.9999 -- tilt version\"\n\n# The parent installs directory should be fully cleaned up, not left empty.\nassert_directory_not_exists \"$MISE_DATA_DIR/installs/tilt\"\n\n# A subsequent successful install should work correctly.\nassert_contains \"mise x tilt@0.36.3 -- tilt version\" \"v0.36.3\"\n"
  },
  {
    "path": "e2e/backend/test_aqua_github_attestations",
    "content": "#!/usr/bin/env bash\n# Test native GitHub artifact attestations verification for aqua packages\n\nset -euo pipefail\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_AQUA_GITHUB_ATTESTATIONS=true\n\necho \"=== Testing Native GitHub Artifact Attestations Verification ===\"\n\n# Test: Install goreleaser which has GitHub artifact attestations configured (v2.7.0+)\n# Pin to a specific version with known-good attestations to avoid failures when\n# a new release hasn't published attestations yet (e.g. goreleaser v2.14.2).\necho \"Installing goreleaser with native GitHub artifact attestations verification...\"\n\n# Capture the installation output to verify the native verification is being used\noutput=$(mise install aqua:goreleaser/goreleaser@2.14.1 2>&1)\necho \"$output\"\n\n# Verify the native GitHub artifact attestations verification was used\nif echo \"$output\" | grep -q \"verify GitHub artifact attestations\"; then\n\techo \"✅ Native GitHub artifact attestations verification was used\"\nelse\n\techo \"❌ ERROR: GitHub artifact attestations verification message not found in output\"\n\techo \"Output was:\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Check if installation succeeded (it may fail due to async runtime issues but we still want to verify the verification step was called)\nif echo \"$output\" | grep -q \"✓ installed\"; then\n\techo \"✓ goreleaser installed successfully\"\n\t# Cleanup\n\tmise uninstall aqua:goreleaser/goreleaser@2.14.1 || true\nelse\n\techo \"⚠️ Installation failed (expected due to async runtime issue) but verification step was called\"\nfi\n\necho \"\"\necho \"=== Native GitHub Artifact Attestations Verification Test Passed ✓ ===\"\n"
  },
  {
    "path": "e2e/backend/test_aqua_slsa",
    "content": "#!/usr/bin/env bash\n# Test native SLSA verification for aqua packages\n\nset -euo pipefail\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_AQUA_SLSA=true\nexport MISE_AQUA_COSIGN=false\n\necho \"=== Testing Native SLSA Verification ===\"\n\n# Test: Install sops which has SLSA provenance configured\necho \"Installing sops with native SLSA verification...\"\n\n# Capture the installation output to verify the native verification is being used\noutput=$(mise install aqua:getsops/sops@3.9.0 2>&1)\necho \"$output\"\n\n# Verify the native SLSA verification was used\nif echo \"$output\" | grep -q \"verify slsa\"; then\n\techo \"✅ Native SLSA verification was used\"\nelse\n\techo \"❌ ERROR: SLSA verification message not found in output\"\n\techo \"Output was:\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Verify the tool works\nassert_contains \"mise x aqua:getsops/sops@3.9.0 -- sops --version\" \"3.9.0\"\necho \"✓ sops installed and working correctly\"\n\n# Cleanup\nmise uninstall aqua:getsops/sops@3.9.0 || true\n\necho \"\"\necho \"=== Native SLSA Verification Test Passed ✓ ===\"\n"
  },
  {
    "path": "e2e/backend/test_aqua_symlink_bins",
    "content": "#!/usr/bin/env bash\n\n# Test that symlink_bins option prevents bundled dependencies from being exposed on PATH.\n# aws-cli bundles Python which should NOT be exposed when symlink_bins=true.\n#\n# Note: On macOS, aws-cli uses .pkg format which requires special extraction tools\n# not available in isolated test environments, so we skip the full test there.\n\nexport MISE_EXPERIMENTAL=1\n\n# Verify aws-cli registry entry exists with aqua backend\nassert_contains \"mise registry aws-cli\" \"aqua:aws/aws-cli\"\n\n# Full installation test only on Linux (aws-cli uses zip format there)\nif [[ \"$(uname -s)\" == \"Linux\" ]]; then\n\t# Install aws-cli (uses symlink_bins=true by default from registry)\n\tmise install aws-cli@2.32.6\n\n\t# Verify aws-cli is installed and working\n\tassert_contains \"mise x aws-cli@2.32.6 -- aws --version\" \"aws-cli/2.32.6\"\n\n\t# Get the bin path for aws-cli - should be .mise-bins directory\n\tbin_path=\"$(mise where aws-cli@2.32.6)/.mise-bins\"\n\tassert_directory_exists \"$bin_path\"\n\n\t# List binaries in the .mise-bins directory - should only have aws and aws_completer\n\tbins=$(find \"$bin_path\" -maxdepth 1 \\( -type l -o -type f \\) -print0 | xargs -0 -n1 basename | sort | tr '\\n' ' ')\n\tassert_contains \"echo '$bins'\" \"aws\"\n\tassert_contains \"echo '$bins'\" \"aws_completer\"\n\n\t# Verify Python is NOT in the .mise-bins directory\n\tassert_not_contains \"echo '$bins'\" \"Python\"\n\tassert_not_contains \"echo '$bins'\" \"python\"\nfi\n\n# Test that symlink_bins=true still exposes the main binary when the aqua registry entry has an empty `files` field.\ncat <<EOF >mise.toml\n[tools]\n\"aqua:casey/just\" = { version = \"1.46.0\", symlink_bins = true }\nEOF\n\nassert \"mise install\"\n\njust_root=\"$(mise where aqua:casey/just@1.46.0)\"\nassert_directory_exists \"$just_root/.mise-bins\"\nassert \"mise which just\" \"$just_root/.mise-bins/just\"\nassert_contains \"mise x -- just --version\" \"just 1.46.0\"\n"
  },
  {
    "path": "e2e/backend/test_asdf",
    "content": "#!/usr/bin/env bash\n\nassert \"mise x asdf:jdx/mise-tiny -- mise-tiny\" \"mise-tiny: v3.1.0\"\nassert \"mise x asdf:https://github.com/jdx/mise-tiny -- mise-tiny\" \"mise-tiny: v3.1.0\"\n"
  },
  {
    "path": "e2e/backend/test_asdf_fake_list",
    "content": "#!/usr/bin/env bash\n\nmise uninstall --all tiny\nmise install tiny@1 tiny@2\nmise asdf install tiny\nassert \"mise asdf list tiny\" \"1.1.0\n2.1.0\n3.1.0\"\n"
  },
  {
    "path": "e2e/backend/test_backend_env_override",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test MISE_BACKENDS_* environment variable override for non-registry tools\n\n# Test 1: Non-registry tool with custom backend via env var\necho \"Testing non-registry tool with env override...\"\nexport MISE_BACKENDS_JUST_TEST='github:casey/just[bin=just]'\n\nassert \"mise exec just-test@1.43.0 -- just --version\" \"just 1.43.0\"\n"
  },
  {
    "path": "e2e/backend/test_backend_missing_deps",
    "content": "#!/usr/bin/env bash\n\n# Test that package manager backends show helpful warnings when their dependencies are missing\n\n# Create a PATH that has mise but not package managers\n# ROOT is set by run_test script\n# Resolve the mise binary from PATH (release e2e ensures it's installed)\nMISE_BIN=\"$(command -v mise)\"\nMISE_DIR=\"$(dirname \"$MISE_BIN\")\"\nexport PATH=\"$MISE_DIR:/usr/bin:/bin:/usr/sbin:/sbin\"\n\n# Track overall test status\nTEST_FAILED=0\n\n# Helper function to check if a command exists in PATH\ncheck_command_missing() {\n\tlocal cmd=$1\n\tif command -v \"$cmd\" >/dev/null 2>&1; then\n\t\techo \"ERROR: $cmd is found in PATH, test cannot verify missing dependency behavior\"\n\t\texit 1\n\tfi\n}\n\n# Helper function to test an expected error message\ntest_error_message() {\n\tlocal test_name=$1\n\tlocal output=$2\n\tlocal expected=$3\n\n\tif [[ $output == *\"$expected\"* ]]; then\n\t\techo \"✓ $test_name\"\n\telse\n\t\techo \"ERROR: $test_name failed\"\n\t\techo \"Expected: $expected\"\n\t\techo \"Got: $output\"\n\t\tTEST_FAILED=1\n\t\treturn 1\n\tfi\n}\n\n# Helper function to test a command that should show a warning\ntest_backend_warning() {\n\tlocal backend_name=$1\n\tlocal command=$2\n\tlocal expected_warning=$3\n\n\tlocal output\n\t# Commands will succeed but show warnings, capture stderr\n\toutput=$(MISE_LOG_LEVEL=warn eval \"$command\" 2>&1 || true)\n\ttest_error_message \"$backend_name shows correct warning\" \"$output\" \"$expected_warning\"\n}\n\n# Test npm backend\ntest_npm() {\n\techo \"Testing npm backend with missing npm...\"\n\tcheck_command_missing \"npm\"\n\n\t# Test ls-remote - should show warning but continue\n\ttest_backend_warning \"npm\" \"mise ls-remote npm:test-package\" \"npm may be required but was not found\"\n\n\t# Check for helpful install instructions\n\tlocal output\n\toutput=$(MISE_LOG_LEVEL=warn mise ls-remote npm:test-package 2>&1 || true)\n\ttest_error_message \"npm suggests installing node\" \"$output\" \"mise use node@latest\"\n\ttest_error_message \"npm mentions npm is needed for queries\" \"$output\" \"npm is required for querying package information\"\n\n\t# Test install - should show warning but continue\n\ttest_backend_warning \"npm\" \"mise install npm:test-package@latest\" \"npm may be required but was not found\"\n\n\t# Test with bun mode enabled but npm still missing\n\techo \"Testing npm backend with bun mode enabled but npm missing...\"\n\texport MISE_NPM_BUN=true\n\ttest_backend_warning \"npm (bun mode)\" \"mise ls-remote npm:test-package\" \"npm may be required but was not found\"\n\toutput=$(mise ls-remote npm:test-package 2>&1 || true)\n\ttest_error_message \"npm (bun mode) shows npm is required for queries\" \"$output\" \"npm is required for querying package information\"\n\tunset MISE_NPM_BUN\n}\n\n# Test cargo backend\ntest_cargo() {\n\techo \"Testing cargo backend with missing cargo...\"\n\n\t# Remove cargo from PATH if it exists\n\tlocal new_path=\"\"\n\tlocal IFS=':'\n\tread -ra PATHS <<<\"$PATH\"\n\tfor p in \"${PATHS[@]}\"; do\n\t\tif [[ ! -x \"$p/cargo\" ]]; then\n\t\t\t[[ -z $new_path ]] && new_path=\"$p\" || new_path=\"$new_path:$p\"\n\t\tfi\n\tdone\n\texport PATH=\"$new_path\"\n\n\tcheck_command_missing \"cargo\"\n\ttest_backend_warning \"cargo\" \"mise install cargo:tiny@latest\" \"cargo may be required but was not found\"\n}\n\n# Test go backend\ntest_go() {\n\techo \"Testing go backend with missing go...\"\n\n\t# Remove go from PATH if it exists\n\tlocal new_path=\"\"\n\tlocal IFS=':'\n\tread -ra PATHS <<<\"$PATH\"\n\tfor p in \"${PATHS[@]}\"; do\n\t\tif [[ ! -x \"$p/go\" ]]; then\n\t\t\t[[ -z $new_path ]] && new_path=\"$p\" || new_path=\"$new_path:$p\"\n\t\tfi\n\tdone\n\texport PATH=\"$new_path\"\n\n\tcheck_command_missing \"go\"\n\ttest_backend_warning \"go\" \"mise ls-remote go:github.com/test/test\" \"go may be required but was not found\"\n}\n\n# Run all tests\ntest_npm\ntest_cargo\ntest_go\n\nif [ $TEST_FAILED -eq 0 ]; then\n\techo \"✓ backend dependency warning test passed\"\nelse\n\techo \"✗ Some tests failed\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/backend/test_cargo_binstall_slow",
    "content": "#!/usr/bin/env bash\nrequire_cmd cargo\n\nexport MISE_CARGO_BINSTALL=1\necho \"tools.cargo-binstall = 'latest'\" >mise.toml\nmise i\nassert \"mise x cargo:eza@0.18.24 -- eza -v\" \"eza - A modern, maintained replacement for ls\nv0.18.24 [+git]\nhttps://github.com/eza-community/eza\"\n\nexport MISE_CARGO_BINSTALL_ONLY=1\ncat >mise.toml <<EOF\ntools.cargo-binstall = \"latest\"\ntools.\"cargo:cargo-show\" = \"latest\"\nEOF\n\nmise i\nmise uninstall cargo:cargo-show cargo-binstall\n\n###### TEST CUSTOM REGISTRY ######\nexport CARGO_REGISTRIES_OFFICIAL_GIT_INDEX=https://github.com/rust-lang/crates.io-index\nexport MISE_CARGO_REGISTRY_NAME=official_git\nmise i\n"
  },
  {
    "path": "e2e/backend/test_cargo_binstall_token",
    "content": "#!/usr/bin/env bash\n\nunset GITHUB_TOKEN GITHUB_API_TOKEN\n\n# Create a cargo-binstall stub that just outputs the value of GITHUB_TOKEN\ncat >~/bin/cargo-binstall <<'EOF'\n#!/usr/bin/env bash\necho \"token=$GITHUB_TOKEN\"\nEOF\nchmod u+x ~/bin/cargo-binstall\nexport PATH=\"$HOME/bin:$PATH\"\n\n# This should reuse the existing GITHUB_TOKEN variable\nassert_contains \"GITHUB_TOKEN=foobar mise install -f cargo:eza@0.18.24 2>&1\" \"token=foobar\"\n\n# This should use the GITHUB_API_TOKEN variable\nassert_contains \"GITHUB_API_TOKEN=foobar mise install -f cargo:eza@0.18.24 2>&1\" \"token=foobar\"\n\n# This should prefer GITHUB_API_TOKEN\nassert_contains \"GITHUB_API_TOKEN=foobar GITHUB_TOKEN=barquz mise install -f cargo:eza@0.18.24 2>&1\" \"token=foobar\"\n"
  },
  {
    "path": "e2e/backend/test_cargo_compile_git_slow",
    "content": "#!/usr/bin/env bash\nrequire_cmd cargo\n\nassert \"mise x cargo:eza-community/eza@tag:v0.18.24 -- eza --version\" \"eza - A modern, maintained replacement for ls\nv0.18.24 [+git]\nhttps://github.com/eza-community/eza\"\n"
  },
  {
    "path": "e2e/backend/test_cargo_compile_slow",
    "content": "#!/usr/bin/env bash\nrequire_cmd cargo\n\nexport MISE_CARGO_BINSTALL=0\nassert \"mise x cargo:eza@0.18.24 -- eza -v\" \"eza - A modern, maintained replacement for ls\nv0.18.24 [+git]\nhttps://github.com/eza-community/eza\"\n"
  },
  {
    "path": "e2e/backend/test_cargo_features_slow",
    "content": "#!/usr/bin/env bash\nrequire_cmd cargo\n\ncat <<EOF >mise.toml\n[tools]\n\"cargo:cargo-edit\" = {version = \"0.12.3\", default-features = \"false\", features = \"add\"}\nEOF\n\nmise i cargo:cargo-edit\n# TODO: assert feature is working\n# assert \"mise x cargo:cargo-edit -- cargo-add\" \"XXXXXX\"\n"
  },
  {
    "path": "e2e/backend/test_conda",
    "content": "#!/usr/bin/env bash\n\n# Test basic version listing\nassert_succeed \"mise ls-remote conda:ruff | head -5\"\n\n# Test installation and execution (no dependencies)\nassert_contains \"mise x conda:ruff@0.8.0 -- ruff --version\" \"0.8.0\"\n\n# Test installing another tool (no dependencies)\nassert_contains \"mise x conda:bat@0.24.0 -- bat --version\" \"0.24.0\"\n\n# Test installing a tool with dependencies (jq depends on oniguruma)\nassert_contains \"mise x conda:jq@1.7.1 -- jq --version\" \"jq-1.7.1\"\n\n# Test installing a tool with many dependencies and library path fixes\n# postgresql has ~23 dependencies including ncurses, readline, openssl, etc.\n# This tests that hardcoded library paths are correctly patched\nassert_contains \"mise x conda:postgresql@17.2 -- psql --version\" \"17.2\"\n"
  },
  {
    "path": "e2e/backend/test_disable_backends",
    "content": "#!/usr/bin/env bash\nexport MISE_EXPERIMENTAL=1\n\nassert \"mise registry age\" \"aqua:FiloSottile/age asdf:threkk/asdf-age\"\n\nmise install age\nassert_fail \"ls $MISE_DATA_DIR/plugins/age\"\nmise uninstall age\n\nMISE_DISABLE_BACKENDS=aqua mise install age\nls \"$MISE_DATA_DIR/plugins/age\"\n"
  },
  {
    "path": "e2e/backend/test_dotnet",
    "content": "#!/usr/bin/env bash\n\nif ! command -v dotnet >/dev/null 2>&1; then\n\techo \"dotnet is not installed\"\n\texit 0\nfi\n\nexport MISE_EXPERIMENTAL=1\n\ntest() {\n\tassert_contains \"mise x $1 -- $2\" \"$3\"\n}\n\nassert_not_contains \"mise ls-remote dotnet:GitVersion.Tool\" \"-beta\"\ntest dotnet:GitVersion.Tool@5.12.0 \"dotnet-gitversion /version\" \"5.12.0+Branch.support-5.x.Sha.3f75764963eb3d7956dcd5a40488c074dd9faf9e\"\ntest dotnet:Husky@0.7.2 \"husky --version\" \"v0.7.2\"\n\n# This command is needed if you want to reexcute the ls-remote command\nmise cache clear\n\nexport MISE_DOTNET_PACKAGE_FLAGS=\"prerelease\"\n\nassert_contains \"mise ls-remote dotnet:GitVersion.Tool\" \"-beta\"\n"
  },
  {
    "path": "e2e/backend/test_forgejo",
    "content": "#!/usr/bin/env bash\n\n# Disabled: Forgejo tests are flaky due to intermittent API issues\nexit 0\n\n# Test basic Forgejo backend functionality with real tools\ncat <<EOF >mise.toml\n[tools]\n\"forgejo:roele/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\nmise uninstall forgejo:roele/mise-test-fixtures\n\n# Test Forgejo backend with platform-specific URLs\ncat <<EOF >mise.toml\n[tools.\"forgejo:roele/mise-test-fixtures\"]\nplatform_darwin_arm64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_darwin_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_linux_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nversion = \"1.0.0\"\nbin_path = \"bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/bin/hello-world\"\nstrip_components = 1\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\nmise uninstall forgejo:roele/mise-test-fixtures\n\n# Test Forgejo backend with mise.lock checksum generation\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\ntouch mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"forgejo:roele/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\n# Verify mise.lock is written correctly with checksums\nassert_contains \"cat mise.lock\" '[[tools.\"forgejo:roele/mise-test-fixtures\"]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\nassert_contains \"cat mise.lock\" 'backend = \"forgejo:roele/mise-test-fixtures\"'\nassert_contains \"cat mise.lock\" 'asset_pattern = \"hello-world-1.0.0.tar.gz\"'\n# Get the current platform key\nPLATFORM_KEY=$(mise x --cd . -- bash -c \"echo \\\"\\$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/macos/')-\\$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')\\\"\")\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM_KEY\\\"\"\nassert_contains \"cat mise.lock\" 'checksum = \"blake3:71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"'\nassert_contains \"cat mise.lock\" 'url = \"https://codeberg.org/roele/mise-test-fixtures/releases/download/v1.0.0/hello-world-1.0.0.tar.gz\"'\n"
  },
  {
    "path": "e2e/backend/test_gem_shebang_slow",
    "content": "#!/usr/bin/env bash\n\n# Test that gem shebangs are rewritten correctly for mise-managed Ruby\n\nmise use ruby@3.3\nmise use gem:ruby-lsp@0.23.0\n\n# Get the Ruby shebang from the gem executable\n# RubyGems creates polyglot scripts: #!/bin/sh on line 1, Ruby shebang after =end\ngem_exec=\"$MISE_DATA_DIR/installs/gem-ruby-lsp/0.23.0/libexec/bin/ruby-lsp\"\n\n# Find the Ruby shebang line (after =end for polyglot scripts)\nshebang=$(awk '/^=end$/{found=1; next} found && /^#!/{print; exit}' \"$gem_exec\")\n\n# If no polyglot format found, check first line\nif [[ -z $shebang ]]; then\n\tshebang=$(head -n1 \"$gem_exec\")\nfi\n\n# Should use minor version symlink (3.3) not full version (3.3.x)\n# Pattern: /ruby/3.3/bin/ruby (minor version), NOT /ruby/3.3.x/bin/ruby (patch version)\nassert_matches \"echo '$shebang'\" '/ruby/[0-9]+\\.[0-9]+/bin/ruby'\n\n# Verify the gem actually works\nassert_contains \"mise x gem:ruby-lsp -- ruby-lsp --version\" \"0.23.0\"\n"
  },
  {
    "path": "e2e/backend/test_gem_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_RUBY_COMPILE=true\nmise use ruby\nassert \"mise x gem:rubocop@1.69.0 -- rubocop --version\" \"1.69.0\"\n"
  },
  {
    "path": "e2e/backend/test_github",
    "content": "#!/usr/bin/env bash\n\n# Test use of release/latest endpoint for GitHub backend\nassert_not_empty \"mise latest github:unikraft/kraftkit\"\n\n# Test basic GitHub backend functionality with real tools\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test GitHub backend with platform-specific URLs\ncat <<EOF >mise.toml\n[tools.\"github:jdx/mise-test-fixtures\"]\nplatform_darwin_arm64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_darwin_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_linux_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nversion = \"1.0.0\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"\nstrip_components = 1\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test GitHub backend with a raw file asset\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world\" }\nEOF\n\nmise uninstall github:jdx/mise-test-fixtures\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test GitHub backend with mise.lock checksum generation\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\ntouch mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise uninstall github:jdx/mise-test-fixtures\nassert \"mise install\"\n# Verify mise.lock is written correctly with checksums\nassert_contains \"cat mise.lock\" '[[tools.\"github:jdx/mise-test-fixtures\"]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\nassert_contains \"cat mise.lock\" 'backend = \"github:jdx/mise-test-fixtures\"'\n# Get the current platform key\nPLATFORM_KEY=$(mise x --cd . -- bash -c \"echo \\\"\\$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/macos/')-\\$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')\\\"\")\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM_KEY\\\"\"\n# GitHub API provides sha256 digests for release assets\n# This checksum is the same across all platforms (macos-arm64, linux-x64, linux-arm64)\n# because hello-world-1.0.0.tar.gz is a generic tarball, not platform-specific\nassert_contains \"cat mise.lock\" 'checksum = \"sha256:dbca4f08377d70dc0828f5822fc47ecec3895cd9a6dacbc54cc984d346a571af\"'\nassert_contains \"cat mise.lock\" 'url = \"https://github.com/jdx/mise-test-fixtures/releases/download/v1.0.0/hello-world-1.0.0.tar.gz\"'\nassert_contains \"cat mise.lock\" 'url_api = \"https://api.github.com/repos/jdx/mise-test-fixtures/releases/assets/272317030\"'\n"
  },
  {
    "path": "e2e/backend/test_github_alias_versions",
    "content": "#!/usr/bin/env bash\n\n# Test that when a registry tool is aliased to a different github backend,\n# version resolution uses the actual GitHub releases, not the versions host.\n# This is a regression test for https://github.com/jdx/mise/discussions/8215\n\n# \"tiny\" is in the registry (asdf:mise-plugins/mise-tiny) but we alias it\n# to a different github backend. The versions host would return versions for\n# the default \"tiny\" backend, which won't match github:jdx/mise-test-fixtures.\ncat <<EOF >mise.toml\n[tool_alias]\ntiny = \"github:jdx/mise-test-fixtures\"\n\n[tools]\n\"tiny\" = { version = \"latest\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\n# ls-remote should return versions from the github backend (1.0.0), not the versions host\nassert_contains \"mise ls-remote tiny\" \"1.0.0\"\n\n# Installing with @latest should resolve to 1.0.0 from the github releases\nmise install\nassert \"mise where tiny\" \"$MISE_DATA_DIR/installs/tiny/1.0.0\"\nassert_contains \"mise x -- hello-world\" \"hello world\"\n"
  },
  {
    "path": "e2e/backend/test_github_auto_detect",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise x github:cli/cli@2.75.0 -- gh --version\" \"gh version 2.75.0\"\n"
  },
  {
    "path": "e2e/backend/test_github_docker_compose",
    "content": "#!/usr/bin/env bash\n# Test GitHub backend with docker-compose\n\nset -euo pipefail\n\n# Test: Install docker-compose via GitHub backend\ncat >mise.toml <<EOF\n[tools]\n\"github:docker/compose\" = \"2.29.1\"\nEOF\n\nassert_succeed \"mise install -f github:docker/compose\"\n\n# Verify it's executable\nassert_succeed \"mise exec github:docker/compose -- docker-compose version\"\nassert \"mise x github:docker/compose -- which docker-compose\" \"$MISE_DATA_DIR/installs/github-docker-compose/2.29.1/docker-compose\"\n"
  },
  {
    "path": "e2e/backend/test_github_filter_bins",
    "content": "#!/usr/bin/env bash\n\n# Test filter_bins option for github backend using pandoc.\n# We use pandoc because it is a compiled binary and comes with multiple binaries to filter.\n\nif [[ \"$(uname -s)\" != \"Linux\" ]]; then\n\techo \"Skipping Linux-specific test on non-Linux OS\"\n\texit 0\nfi\n\nexport MISE_EXPERIMENTAL=1\n\nmise install \"github:jgm/pandoc[filter_bins=pandoc]@3.8.2\"\n\nbin_path=\"$(mise where github:jgm/pandoc@3.8.2)/.mise-bins\"\nassert_directory_exists \"$bin_path\"\n\nbins=$(find \"$bin_path\" -maxdepth 1 \\( -type l -o -type f \\) -print0 | xargs -0 -n1 basename | sort | tr '\\n' ' ')\nassert_contains \"echo '$bins'\" \"pandoc\"\nassert_not_contains \"echo '$bins'\" \"pandoc-lua\"\nassert_not_contains \"echo '$bins'\" \"pandoc-server\"\n"
  },
  {
    "path": "e2e/backend/test_github_latest",
    "content": "#!/usr/bin/env bash\n\n# Test that github backend handles \"latest\" version correctly\n# Regression test for https://github.com/jdx/mise/discussions/8530\n# The GitHub API endpoint for latest release is /releases/latest, not /releases/tags/latest\n\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/mise-test-fixtures\" = { version = \"latest\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Verify that \"latest\" resolved to a concrete version, not the literal string \"latest\".\n# The version column should contain a semver-like string (e.g. \"1.0.0\"), not \"latest\".\nmise_ls_output=$(mise ls github:jdx/mise-test-fixtures)\nif echo \"$mise_ls_output\" | awk '{print $2}' | grep -qx \"latest\"; then\n\techo \"FAIL: 'latest' was not resolved to a concrete version\"\n\techo \"Output: $mise_ls_output\"\n\texit 1\nfi\nif ! echo \"$mise_ls_output\" | awk '{print $2}' | grep -qE '[0-9]+\\.[0-9]+'; then\n\techo \"FAIL: version column does not contain a semver-like version\"\n\techo \"Output: $mise_ls_output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/backend/test_github_rename_exe",
    "content": "#!/usr/bin/env bash\n# Test rename_exe with archives that have a bin/ subdirectory structure\n# Regression test: rename_exe should auto-detect bin/ when bin_path is not set\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_GPG_VERIFY=false\n\n# The tiny archive (e.g., tiny-2.0.0-linux-x64.tar.gz) contains:\n#   tiny-2.0.0/bin/tiny\n# With auto-strip (strip_components=1), it extracts to:\n#   install_path/bin/tiny\n# rename_exe should find the binary inside bin/ automatically\n\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/tiny\" = { version = \"2.0.0\", rename_exe = \"my-tiny\" }\nEOF\n\nmise install\nassert_contains \"mise x -- my-tiny\" \"tiny v2.\"\n"
  },
  {
    "path": "e2e/backend/test_github_tools",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use github:BurntSushi/ripgrep@14.1.0\"\nassert \"mise which rg\"\nassert_contains \"mise x -- rg --version\" \"ripgrep 14.1.0\"\n\n# zip file with strip_components=1\nassert \"mise use github:nats-io/natscli@0.2.3\"\nassert \"mise which nats\"\nassert_contains \"mise x -- nats --version\" \"0.2.3\"\n"
  },
  {
    "path": "e2e/backend/test_github_url_tracking",
    "content": "#!/usr/bin/env bash\n\n# Test GitHub backend URL tracking functionality\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\n# Clean up any existing installations\nmise uninstall github:jdx/mise-test-fixtures 2>/dev/null || true\n\n# Create initial configuration\ncat <<EOF >mise.toml\n[tools]\n\"github:jdx/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\n# Create lockfile\ntouch mise.lock\n\n# First install - should fetch URL from GitHub API\necho \"=== First install - fetching URL from GitHub API ===\"\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Verify URL is stored in lockfile\necho \"=== Verifying URL is stored in lockfile ===\"\nassert_contains \"cat mise.lock\" '[[tools.\"github:jdx/mise-test-fixtures\"]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\nassert_contains \"cat mise.lock\" 'backend = \"github:jdx/mise-test-fixtures\"'\nassert_contains \"cat mise.lock\" 'asset_pattern = \"hello-world-1.0.0.tar.gz\"'\n# Get the current platform key\nPLATFORM_KEY=$(mise x --cd . -- bash -c \"echo \\\"\\$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/macos/')-\\$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')\\\"\")\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM_KEY\\\"\"\nassert_contains \"cat mise.lock\" 'url = \"https://github.com/jdx/mise-test-fixtures/releases/download/v1.0.0/hello-world-1.0.0.tar.gz\"'\nassert_contains \"cat mise.lock\" 'url_api = \"https://api.github.com/repos/jdx/mise-test-fixtures/releases/assets/272317030\"'\n\necho \"Lockfile after installation:\"\ncat mise.lock\n\n# Uninstall and reinstall - should reuse URL from lockfile\necho \"=== Uninstall and reinstall - should reuse cached URL ===\"\nmise uninstall \"github:jdx/mise-test-fixtures@1.0.0\"\nmise install\n\n# Should still work with cached URL\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\necho \"Test completed successfully!\"\n"
  },
  {
    "path": "e2e/backend/test_gitlab",
    "content": "#!/usr/bin/env bash\n\n# Test basic GitLab backend functionality with real tools\ncat <<EOF >mise.toml\n[tools]\n\"gitlab:jdxcode/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\nmise uninstall gitlab:jdxcode/mise-test-fixtures\n\n# Test GitLab backend with platform-specific URLs\ncat <<EOF >mise.toml\n[tools.\"gitlab:jdxcode/mise-test-fixtures\"]\nplatform_darwin_arm64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_darwin_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nplatform_linux_amd64_url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nversion = \"1.0.0\"\nbin_path = \"bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/bin/hello-world\"\nstrip_components = 1\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\nmise uninstall gitlab:jdxcode/mise-test-fixtures\n\n# Test GitLab backend with mise.lock checksum generation\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\ntouch mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"gitlab:jdxcode/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\n# Verify mise.lock is written correctly with checksums\nassert_contains \"cat mise.lock\" '[[tools.\"gitlab:jdxcode/mise-test-fixtures\"]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\nassert_contains \"cat mise.lock\" 'backend = \"gitlab:jdxcode/mise-test-fixtures\"'\nassert_contains \"cat mise.lock\" 'asset_pattern = \"hello-world-1.0.0.tar.gz\"'\n# Get the current platform key\nPLATFORM_KEY=$(mise x --cd . -- bash -c \"echo \\\"\\$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/macos/')-\\$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')\\\"\")\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM_KEY\\\"\"\nassert_contains \"cat mise.lock\" 'checksum = \"blake3:71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"'\nassert_contains \"cat mise.lock\" 'url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"'\n\nmise uninstall gitlab:jdxcode/mise-test-fixtures\n\n# Test GitLab backend with tool alias propagates options correctly\n# Regression test for https://github.com/jdx/mise/discussions/8079\ncat <<EOF >mise.toml\n[tools]\n\"gitlab:jdxcode/mise-test-fixtures\" = { version = \"1.0.0\", asset_pattern = \"hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\n\n[tool_alias]\nmy-test-tool = 'gitlab:jdxcode/mise-test-fixtures'\nEOF\n\n# Verify ls-remote works via alias (exercises _list_remote_versions with get_tool_opts)\nassert_contains \"mise ls-remote my-test-tool\" \"1.0.0\"\n\nmise install\nassert_contains \"mise x my-test-tool -- hello-world\" \"hello world\"\n"
  },
  {
    "path": "e2e/backend/test_go_install_slow",
    "content": "#!/usr/bin/env bash\n\n# Create system \"tools\" that always fail and push them to the front of PATH\ncat >\"$HOME/bin/fail\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM $(basename $0)! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/fail\nln -s fail \"$HOME/bin/go\"\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail go\n\ncat >>.mise.toml <<EOF\n[tools]\ngo = \"prefix:1.22\"\n\"go:github.com/golangci/golangci-lint/cmd/golangci-lint\" = \"latest\"\n[settings]\nexperimental = true\nEOF\n\nmise install go\nmise install\n\neval \"$(mise activate bash --shims)\"\n\nassert \"mise x go:github.com/DarthSim/hivemind@1.1.0 -- hivemind --version\" \"Hivemind version 1.1.0\"\nassert \"mise x go:github.com/go-task/task/v3/cmd/task@3.34.1 -- task --version\" \"Task version: v3.34.1 (h1:yAAxUM54zoaHv+OtDnGgkWSVeiRuaOCn1lPUXPQQA0o=)\"\n# See https://github.com/jdx/mise/discussions/6737\nassert \"mise x go:github.com/jdx/go-example@e16a340 -- go-example\" \"hello world\"\n\nassert_contains \"mise x go:github.com/golang-migrate/migrate/v4/cmd/migrate[tags=postgres]@4.18.2 -- bash -c 'migrate --help 2>&1'\" \"postgres\"\n\n# Required to properly cleanup as go installs read-only sources\nchmod -R +w ~/go\n"
  },
  {
    "path": "e2e/backend/test_go_shim_recursion",
    "content": "#!/usr/bin/env bash\n# Test that go: backend tools don't cause infinite process spawning when:\n# - the cache is cleared (forcing _list_remote_versions to call `go list`)\n# - go is available only as a mise shim in PATH (simulating `mise activate --shims` mode)\n# - the configured go version is not installed\n#\n# Without the fix in dependency_env, the go shim would call `mise exec`, which\n# would resolve the go: backend tool again, calling `go list` via shim, etc. → fork bomb.\n# With the fix, shims are stripped from dependency_env PATH so go list fails cleanly.\n\n# Create a fake go shim that mimics real mise shim behavior:\n# it calls `mise exec -- go \"$@\"`, triggering recursive mise resolution\nmkdir -p \"$MISE_DATA_DIR/shims\"\ncat >\"$MISE_DATA_DIR/shims/go\" <<'SHIM'\n#!/usr/bin/env bash\nexec mise exec -- go \"$@\"\nSHIM\nchmod +x \"$MISE_DATA_DIR/shims/go\"\n\n# Add the shims directory to PATH, simulating the effect of `mise activate bash --shims`.\n# In --shims mode the shims dir is added to the shell's PATH without setting __MISE_DIFF,\n# so PRISTINE_ENV ends up containing the shims dir and dependency_env inherits it.\nexport PATH=\"$MISE_DATA_DIR/shims:$PATH\"\n\n# Configure a go: backend tool plus a go version that is NOT installed.\n# The go: backend's _list_remote_versions calls `go list` using dependency_env;\n# since go@1.23.3 is not installed, the only `go` available is the shim above.\ncat >>mise.toml <<'EOF'\n[tools]\n\"go:github.com/pulumi/upgrade-provider\" = \"main\"\ngo = \"1.23.3\"\nEOF\nmise trust --yes\n\n# Clear the remote version cache so _list_remote_versions must actually call `go list`\n# (without this, the cached versions would be returned and the shim would not be called)\nmise cache clear\n\n# This must complete within the timeout without spawning infinite child processes.\n# Without the fix: fork bomb (OOM / timeout).\n# With the fix: go list fails cleanly (go not in dependency PATH), command completes.\noutput=\"$(run_with_timeout 15 mise ls --json -c)\" || {\n\techo \"ERROR: mise ls timed out or failed (likely infinite recursion fork bomb)\"\n\texit 1\n}\nassert_contains \"echo '$output'\" '\"go\"'\n"
  },
  {
    "path": "e2e/backend/test_http",
    "content": "#!/usr/bin/env bash\n\n# Test basic HTTP backend functionality with real tools\ncat <<EOF >mise.toml\n[tools]\n\"http:hello\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-verified\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", checksum = \"sha256:dbca4f08377d70dc0828f5822fc47ecec3895cd9a6dacbc54cc984d346a571af\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nmise env\n\ncat <<EOF >mise.toml\n[tools]\n\"http:version-test\" = { version = \"2.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-2.0.0.tar.gz\", bin_path = \"hello-world-2.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-2.0.0/bin/hello-world\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world 2.0.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"http:fd\" = { version = \"8.7.0\", url = \"https://mise.jdx.dev/test-fixtures/fd-8.7.0.tar.gz\", bin_path = \"fd-8.7.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/fd-8.7.0/bin/fd\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- fd --version\" \"8.7.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"http:fd-explicit\" = { version = \"8.7.0\", url = \"https://mise.jdx.dev/test-fixtures/fd-8.7.0.tar.gz\", bin_path = \"fd-8.7.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/fd-8.7.0/bin/fd\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- fd --version\" \"8.7.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"http:fd-multi\" = { version = \"8.7.0\", url = \"https://mise.jdx.dev/test-fixtures/fd-8.7.0.tar.gz\", bin_path = \"fd-8.7.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/fd-8.7.0/bin/fd\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- fd --version\" \"8.7.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-strip\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", strip_components = 1, bin_path = \"bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/bin/hello-world\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test HTTP backend with platform-specific URLs\ncat <<EOF >mise.toml\n[tools.\"http:hello-platform\"]\nversion = \"1.0.0\"\nbin_path = \"bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/bin/hello-world\"\nstrip_components = 1\n\n[tools.\"http:hello-platform\".platforms]\ndarwin-arm64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\ndarwin-amd64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\nlinux-amd64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test HTTP backend with a raw file asset\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-raw\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Clear cache to avoid conflicts with different bin_path configurations\nmise cache clear\n\n# Test HTTP backend with a raw file asset and bin_path\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-raw-bin-path\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world\", bin_path = \"custom/path\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/custom/path/hello-world\" }\nEOF\n\nmise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test HTTP backend with mise.lock checksum generation\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\ntouch mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-lock\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"cat mise.lock\" '[[tools.\"http:hello-lock\"]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\nassert_contains \"cat mise.lock\" 'backend = \"http:hello-lock\"'\nassert_contains \"cat mise.lock\" 'url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"'\nassert_contains \"cat mise.lock\" 'platforms'\nassert_contains \"cat mise.lock\" 'checksum = \"blake3:71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"'\n\n# Test HTTP backend with URL templating\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-world\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-{{version}}.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise uninstall --all && mise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test HTTP backend with templated bin_path\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-world\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-{{version}}/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise uninstall --all && mise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test HTTP backend with Tera {{ version }} templating syntax (with spaces)\n# This tests the fix for https://github.com/jdx/mise/discussions/7748\n# Note: postinstall uses literal version since it's a shell command executed directly\ncat <<'EOF' >mise.toml\n[tools]\n\"http:hello-tera\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-{{ version }}.tar.gz\", bin_path = \"hello-world-{{ version }}/bin\", postinstall = \"chmod +x $MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise uninstall --all && mise install\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n"
  },
  {
    "path": "e2e/backend/test_http_binary_clean",
    "content": "#!/usr/bin/env bash\n# Test HTTP backend binary name cleaning with docker-compose\n\nset -euo pipefail\nexport MISE_EXPERIMENTAL=1\n\n# Test: Install docker-compose via HTTP backend\n# The binary name should be automatically cleaned from docker-compose-linux-x86_64 to docker-compose\ncat >mise.toml <<EOF\n[tools]\n\"http:docker-compose\" = { version = \"2.29.1\", url = \"https://github.com/docker/compose/releases/download/v{version}/docker-compose-linux-x86_64\" }\nEOF\n\nassert_succeed \"mise install -f http:docker-compose\"\n\n# Verify it's executable\nassert_succeed \"mise exec http:docker-compose -- docker-compose version\"\n\n# The binary should be cleaned to just \"docker-compose\" in the data dir\nassert_succeed \"test -f $HOME/.local/share/mise/http-tarballs/*/docker-compose\"\n"
  },
  {
    "path": "e2e/backend/test_http_caching",
    "content": "#!/usr/bin/env bash\n\n# Test HTTP backend caching functionality\n# This test verifies that the same tarball is reused when multiple tools use it\n\n# First, let's check if the cache directory exists and is empty\n# Note: http-tarballs is stored in DATA dir (not CACHE) to survive `mise cache clear`\nCACHE_DIR=\"$HOME/.local/share/mise/http-tarballs\"\nif [ -d \"$CACHE_DIR\" ]; then\n\techo \"Clearing existing HTTP cache...\"\n\trm -rf \"$CACHE_DIR\"\nfi\n\n# Test 1: Install a tool and verify cache is created\necho \"Test 1: Installing first tool and checking cache creation\"\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-cache1\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Check that cache directory was created\nif [ ! -d \"$CACHE_DIR\" ]; then\n\techo \"ERROR: Cache directory was not created\"\n\texit 1\nfi\n\n# Count cache entries (should be 1)\nCACHE_COUNT=$(find \"$CACHE_DIR\" -maxdepth 1 -type d | wc -l)\nCACHE_COUNT=$((CACHE_COUNT - 1)) # Subtract 1 for the cache directory itself\necho \"Cache entries after first install: $CACHE_COUNT\"\nif [ \"$CACHE_COUNT\" -ne 1 ]; then\n\techo \"ERROR: Expected 1 cache entry, found $CACHE_COUNT\"\n\texit 1\nfi\n\n# Test 2: Install another tool with the same tarball and verify cache is reused\necho \"Test 2: Installing second tool with same tarball and checking cache reuse\"\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-cache2\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Count cache entries (should still be 1)\nCACHE_COUNT=$(find \"$CACHE_DIR\" -maxdepth 1 -type d | wc -l)\nCACHE_COUNT=$((CACHE_COUNT - 1)) # Subtract 1 for the cache directory itself\necho \"Cache entries after second install: $CACHE_COUNT\"\nif [ \"$CACHE_COUNT\" -ne 1 ]; then\n\techo \"ERROR: Expected 1 cache entry, found $CACHE_COUNT\"\n\texit 1\nfi\n\n# Test 3: Install a tool with a different tarball and verify new cache entry\necho \"Test 3: Installing tool with different tarball and checking new cache entry\"\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-cache3\" = { version = \"2.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-2.0.0.tar.gz\", bin_path = \"hello-world-2.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-2.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world 2.0.0\"\n\n# Count cache entries (should be 2)\nCACHE_COUNT=$(find \"$CACHE_DIR\" -maxdepth 1 -type d | wc -l)\nCACHE_COUNT=$((CACHE_COUNT - 1)) # Subtract 1 for the cache directory itself\necho \"Cache entries after third install: $CACHE_COUNT\"\nif [ \"$CACHE_COUNT\" -ne 2 ]; then\n\techo \"ERROR: Expected 2 cache entries, found $CACHE_COUNT\"\n\texit 1\nfi\n\n# Test 4: Install a tool with checksum and verify cache key uses checksum\necho \"Test 4: Installing tool with checksum and checking cache key\"\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-cache4\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", checksum = \"sha256:dbca4f08377d70dc0828f5822fc47ecec3895cd9a6dacbc54cc984d346a571af\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Count cache entries (should still be 2, as it should reuse the existing cache)\nCACHE_COUNT=$(find \"$CACHE_DIR\" -maxdepth 1 -type d | wc -l)\nCACHE_COUNT=$((CACHE_COUNT - 1)) # Subtract 1 for the cache directory itself\necho \"Cache entries after fourth install: $CACHE_COUNT\"\nif [ \"$CACHE_COUNT\" -ne 2 ]; then\n\techo \"ERROR: Expected 2 cache entries, found $CACHE_COUNT\"\n\texit 1\nfi\n\n# Test 5: Verify that install directories are symlinks to cache\necho \"Test 5: Verifying install directories are symlinks to cache\"\nINSTALL_DIR=\"$HOME/.local/share/mise/installs/http-hello-cache1/1.0.0\"\nif [ ! -L \"$INSTALL_DIR\" ]; then\n\techo \"ERROR: Install directory is not a symlink: $INSTALL_DIR\"\n\texit 1\nfi\n\n# Check that the symlink points to the cache\nLINK_TARGET=$(readlink \"$INSTALL_DIR\")\nif [[ ! $LINK_TARGET =~ /http-tarballs/ ]]; then\n\techo \"ERROR: Symlink does not point to cache directory: $LINK_TARGET\"\n\texit 1\nfi\n\necho \"SUCCESS: All HTTP backend caching tests passed!\"\n"
  },
  {
    "path": "e2e/backend/test_http_compressed_binaries",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test HTTP backend with compressed binaries\n\n# Create a temporary directory for test artifacts\nTEST_DIR=\"$(mktemp -d)\"\nHTTP_PORT=8765\nSERVER_PID=\"\"\n\n# Cleanup function\ncleanup() {\n\tif [ -n \"$SERVER_PID\" ]; then\n\t\tkill \"$SERVER_PID\" 2>/dev/null || true\n\tfi\n\trm -rf \"$TEST_DIR\"\n\trm -f mise.toml\n}\ntrap cleanup EXIT\n\n# Create a simple test binary\ncat >\"$TEST_DIR/test-tool\" <<'EOF'\n#!/usr/bin/env bash\necho \"test-tool version 1.0.0\"\nEOF\nchmod +x \"$TEST_DIR/test-tool\"\n\n# Create compressed versions of the binary\necho \"Creating compressed binaries...\"\ngzip -c \"$TEST_DIR/test-tool\" >\"$TEST_DIR/test-tool-linux-x64.gz\"\nxz -c \"$TEST_DIR/test-tool\" >\"$TEST_DIR/test-tool-linux-x64.xz\"\nbzip2 -c \"$TEST_DIR/test-tool\" >\"$TEST_DIR/test-tool-linux-x64.bz2\"\n\n# Also test with zst if available\nif command -v zstd >/dev/null 2>&1; then\n\tzstd -c \"$TEST_DIR/test-tool\" >\"$TEST_DIR/test-tool-linux-x64.zst\"\nfi\n\n# Start a simple HTTP server\necho \"Starting HTTP server on port $HTTP_PORT...\"\ncd \"$TEST_DIR\"\npython3 -m http.server $HTTP_PORT --bind 127.0.0.1 >/dev/null 2>&1 &\nSERVER_PID=$!\n\n# Go back to original directory\ncd -\n\n# Wait for server to start\nsleep 2\n\n# Test with different compressed formats\necho \"Testing .gz compressed binary...\"\ncat <<EOF >mise.toml\n[tools]\n\"http:test-tool-gz\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$HTTP_PORT/test-tool-linux-x64.gz\", bin = \"test-tool\" }\nEOF\nmise install\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\nmise uninstall --all\n\necho \"Testing .xz compressed binary...\"\ncat <<EOF >mise.toml\n[tools]\n\"http:test-tool-xz\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$HTTP_PORT/test-tool-linux-x64.xz\", bin = \"test-tool\" }\nEOF\nmise install\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\nmise uninstall --all\n\necho \"Testing .bz2 compressed binary...\"\ncat <<EOF >mise.toml\n[tools]\n\"http:test-tool-bz2\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$HTTP_PORT/test-tool-linux-x64.bz2\", bin = \"test-tool\" }\nEOF\nmise install\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\nmise uninstall --all\n\nif [ -f \"$TEST_DIR/test-tool-linux-x64.zst\" ]; then\n\techo \"Testing .zst compressed binary...\"\n\tcat <<EOF >mise.toml\n[tools]\n\"http:test-tool-zst\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$HTTP_PORT/test-tool-linux-x64.zst\", bin = \"test-tool\" }\nEOF\n\tmise install\n\tassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\n\tmise uninstall --all\nfi\n\n# Test with a tar.gz archive for comparison\necho \"Creating tar.gz archive...\"\nmkdir -p \"$TEST_DIR/archive\"\ncp \"$TEST_DIR/test-tool\" \"$TEST_DIR/archive/\"\ntar czf \"$TEST_DIR/test-tool-archive.tar.gz\" -C \"$TEST_DIR\" archive\n\necho \"Testing .tar.gz archive...\"\ncat <<EOF >mise.toml\n[tools]\n\"http:test-tool-archive\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$HTTP_PORT/test-tool-archive.tar.gz\", bin_path = \"archive\", bin = \"test-tool\" }\nEOF\nmise install\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/backend/test_http_flutter_url",
    "content": "#!/usr/bin/env bash\n\n# Test that Flutter URL is correctly constructed without duplicate -stable suffix\n# See: https://github.com/jdx/mise/discussions/7863\n\n# Test that flutter versions can be listed (verifies registry parsing)\nassert_contains \"mise ls-remote flutter\" \"3.22.1\"\n\n# Test that the URL template handles versions correctly\n# The fix uses replace filter to strip -stable suffix before adding it back\n# This prevents URLs like flutter_linux_3.22.1-stable-stable.tar.xz\n\n# Quick verification that flutter@3.22.1 resolves without error\n# Using --dry-run to avoid actual download\nassert_succeed \"mise install flutter@3.22.1 --dry-run\"\n"
  },
  {
    "path": "e2e/backend/test_http_format",
    "content": "#!/usr/bin/env bash\n\n# Test HTTP backend with explicit format parameter\n# This simulates tools without proper file extensions\n\n# Test 1: Explicit format with tar.gz\ncat <<EOF >mise.toml\n[tools.\"http:hello-format\"]\nversion = \"1.0.0\"\nurl = \"https://mise.jdx.dev/test-fixtures/test-fixtures_hello-world-1.0.0-tarball\"\nformat = \"tar.gz\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"\nEOF\n\nmise install -v\nmise env\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Test 2: Platform-specific format\ncat <<EOF >mise.toml\n[tools.\"http:hello-format-platform\"]\nversion = \"1.0.0\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"\n\n[tools.\"http:hello-format-platform\".platforms]\ndarwin-arm64 = { url = \"https://mise.jdx.dev/test-fixtures/test-fixtures_hello-world-1.0.0-tarball\", format = \"tar.gz\" }\ndarwin-amd64 = { url = \"https://mise.jdx.dev/test-fixtures/test-fixtures_hello-world-1.0.0-tarball\", format = \"tar.gz\" }\nlinux-amd64 = { url = \"https://mise.jdx.dev/test-fixtures/test-fixtures_hello-world-1.0.0-tarball\", format = \"tar.gz\" }\nlinux-arm64 = { url = \"https://mise.jdx.dev/test-fixtures/test-fixtures_hello-world-1.0.0-tarball\", format = \"tar.gz\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n"
  },
  {
    "path": "e2e/backend/test_http_platform_switch",
    "content": "#!/usr/bin/env bash\n\n# Test switching from single url to platform-specific urls\n# Regression test for https://github.com/jdx/mise/discussions/7034\n#\n# When a tool is first installed with a single `url`, the install state stores\n# the options (including url) in the manifest. If the user then changes the\n# config to use platform-specific urls via [tools.\"http:X\".platforms], the\n# stale cached options could shadow the new config, causing\n# \"Http backend requires 'url' option\" error.\n\n# Step 1: Install with a single url\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-plat-switch\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", bin_path = \"hello-world-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\" }\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Step 2: Switch to platform-specific urls (same tool name, same version)\n# This previously failed with \"Http backend requires 'url' option\" because\n# the stale cached platforms data from parse_tool_options was mangled and\n# shadowed the correct config values during merge.\ncat <<EOF >mise.toml\n[tools.\"http:hello-plat-switch\"]\nversion = \"1.0.0\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"\n\n[tools.\"http:hello-plat-switch\".platforms]\nlinux-x64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\nlinux-arm64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\ndarwin-arm64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\ndarwin-x64 = { url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\" }\nEOF\n\n# This should succeed, not fail with \"Http backend requires 'url' option\"\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n"
  },
  {
    "path": "e2e/backend/test_http_rename_exe",
    "content": "#!/usr/bin/env bash\n# Test HTTP backend rename_exe option for renaming executables in archives\n\nset -euo pipefail\nexport MISE_EXPERIMENTAL=1\n\n# Test: rename_exe renames the executable inside the archive\n# The hello-world archive contains hello-world-1.0.0/bin/hello-world\n# We use strip_components=1 and bin_path=bin to get to the binary,\n# then rename_exe to rename it to \"my-hello\"\ncat <<EOF >mise.toml\n[tools]\n\"http:hello-rename\" = { version = \"1.0.0\", url = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\", strip_components = 1, bin_path = \"bin\", rename_exe = \"my-hello\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/bin/my-hello\" }\nEOF\n\nmise install\nmise env\n\n# Verify the renamed binary works\nassert_contains \"mise x -- my-hello\" \"hello world\"\n\n# Test: rename_exe with bin_path - binary should be renamed in the bin_path directory\ncat <<EOF >mise.toml\n[tools]\n\"http:fd-rename\" = { version = \"8.7.0\", url = \"https://mise.jdx.dev/test-fixtures/fd-8.7.0.tar.gz\", bin_path = \"fd-8.7.0/bin\", rename_exe = \"my-fd\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/fd-8.7.0/bin/my-fd\" }\nEOF\n\nmise install\nmise env\n\n# Verify the renamed binary works\nassert_contains \"mise x -- my-fd --version\" \"8.7.0\"\n"
  },
  {
    "path": "e2e/backend/test_http_upgrade",
    "content": "#!/usr/bin/env bash\n\n# Test that HTTP backend tools (which use symlinks to cache) can be upgraded\n# This validates the fix for https://github.com/jdx/mise/pull/7012\n#\n# The HTTP backend creates symlinks from installs/ to http-tarballs/ cache.\n# Before the fix, these symlinks caused tools to be incorrectly skipped\n# in the outdated check, preventing upgrades from working.\n\n# Start a simple HTTP server to serve version list\nVERSION_LIST_DIR=\"$TMPDIR/version-list-server\"\nmkdir -p \"$VERSION_LIST_DIR\"\n\n# Create version list file with two versions\necho -e \"1.0.0\\n2.0.0\" >\"$VERSION_LIST_DIR/versions.txt\"\n\n# Start Python HTTP server on a random available port\nHTTP_PORT_FILE=\"$TMPDIR/http_server_port\"\npython3 -c \"\nimport http.server, socketserver, threading, os\ns = socketserver.TCPServer(('', 0), lambda *a: http.server.SimpleHTTPRequestHandler(*a, directory='$VERSION_LIST_DIR'))\nwith open('$HTTP_PORT_FILE', 'w') as f:\n    f.write(str(s.server_address[1]))\ns.serve_forever()\n\" &\nHTTP_SERVER_PID=$!\n\n# Wait for server to start and write port file\nfor _i in {1..20}; do\n\tif [[ -f $HTTP_PORT_FILE ]]; then break; fi\n\tsleep 0.1\ndone\nHTTP_PORT=$(cat \"$HTTP_PORT_FILE\")\n\n# Cleanup function\ncleanup() {\n\tkill $HTTP_SERVER_PID 2>/dev/null || true\n}\ntrap cleanup EXIT\n\n# Verify server is running\nif ! curl -s \"http://localhost:$HTTP_PORT/versions.txt\" | grep -q \"1.0.0\"; then\n\tfail \"HTTP server failed to start\"\nfi\n\n# Test 1: Install HTTP tool and verify it's a symlink to cache\necho \"Test 1: Install HTTP tool with version_list_url\"\ncat <<EOF >mise.toml\n[tools.\"http:hello-upgrade\"]\nversion = \"1.0.0\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-{{version}}.tar.gz\"\nversion_list_url = \"http://localhost:$HTTP_PORT/versions.txt\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"\nEOF\n\nmise install\nassert_contains \"mise x -- hello-world\" \"hello world\"\n\n# Verify install is a symlink (HTTP backend caching behavior)\nINSTALL_PATH=\"$MISE_DATA_DIR/installs/http-hello-upgrade/1.0.0\"\nif [[ ! -L $INSTALL_PATH ]]; then\n\tfail \"Expected install path to be a symlink: $INSTALL_PATH\"\nfi\necho \"Verified: Install path is a symlink (HTTP backend caching)\"\n\n# Test 2: Verify mise latest sees the newer version\necho \"Test 2: Check that mise latest sees version 2.0.0\"\nassert \"mise latest http:hello-upgrade\" \"2.0.0\"\n\n# Test 3: Verify mise outdated --bump shows the tool as outdated\n# This is the key test - before the fix, HTTP backend tools were skipped\necho \"Test 3: Check that mise outdated --bump detects outdated version\"\nOUTDATED_OUTPUT=$(mise outdated --bump 2>&1)\nif [[ $OUTDATED_OUTPUT != *\"hello-upgrade\"* ]] || [[ $OUTDATED_OUTPUT != *\"2.0.0\"* ]]; then\n\techo \"outdated output: $OUTDATED_OUTPUT\"\n\tfail \"mise outdated --bump should show http:hello-upgrade as outdated to 2.0.0\"\nfi\necho \"Verified: mise outdated --bump correctly detects HTTP backend tool as outdated\"\n\n# Test 4: Verify mise upgrade --bump --dry-run shows the upgrade\necho \"Test 4: Check that mise upgrade --bump --dry-run shows the upgrade\"\nUPGRADE_OUTPUT=$(mise upgrade --bump --dry-run 2>&1)\nif [[ $UPGRADE_OUTPUT != *\"Would install\"* ]] || [[ $UPGRADE_OUTPUT != *\"hello-upgrade\"* ]]; then\n\techo \"upgrade output: $UPGRADE_OUTPUT\"\n\tfail \"mise upgrade --bump --dry-run should show install for http:hello-upgrade\"\nfi\necho \"Verified: mise upgrade --bump --dry-run correctly shows upgrade for HTTP backend tool\"\n\necho \"SUCCESS: HTTP backend upgrade test passed!\"\n"
  },
  {
    "path": "e2e/backend/test_install_manifest",
    "content": "#!/usr/bin/env bash\n# Test the consolidated install manifest (.mise-installs.toml)\n\nset -euo pipefail\n\nMANIFEST=\"$MISE_DATA_DIR/installs/.mise-installs.toml\"\n\n# Install a tool — manifest should be created\nmise install tiny@3.1.0\nassert_contains \"cat $MANIFEST\" \"tiny\"\nassert_contains \"cat $MANIFEST\" \"full\"\n\n# Verify the tool is installed\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Install a second version — manifest entry should persist\nmise install tiny@2.1.0\nassert_contains \"cat $MANIFEST\" \"tiny\"\nassert_contains \"mise ls tiny\" \"2.1.0\"\n\n# Remove the tool dir (rm -rf workflow) — mise should handle it cleanly\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"\n# The manifest still references tiny, but the dir is gone — mise should not error\nassert_succeed \"mise ls\"\n# tiny should no longer appear as installed\nassert_not_contains \"mise ls tiny 2>&1\" \"3.1.0\"\n\n# Re-install — manifest should be updated and tool should work\nmise install tiny@3.1.0\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Test migration from legacy .mise.backend files\n# Create a fake tool with a legacy .mise.backend file and no manifest entry\nmkdir -p \"$MISE_DATA_DIR/installs/legacy-test/1.0.0\"\necho -e \"legacy-test\\nasdf:legacy-test\\n0\" >\"$MISE_DATA_DIR/installs/legacy-test/.mise.backend\"\n\n# Remove manifest so migration is triggered on next init\nrm -f \"$MANIFEST\"\n\n# Running mise should migrate the legacy entry into the manifest\nassert_succeed \"mise ls\"\nassert_contains \"cat $MANIFEST\" \"legacy-test\"\nassert_contains \"cat $MANIFEST\" \"asdf:legacy-test\"\n"
  },
  {
    "path": "e2e/backend/test_install_with_tools_env",
    "content": "#!/usr/bin/env bash\nrequire_cmd npm\n\n# Regression test: installing npm/cargo/pipx tools should not fail when\n# env vars use `tools = true` lazy evaluation referencing other tools.\n# Previously, the install process tried to resolve `tools = true` env\n# directives during installation, but the referenced tools might not be\n# installed yet, causing template rendering errors.\n# See: https://github.com/jdx/mise/discussions/8346\n\nexport NPM_CONFIG_FUND=false\n\ncat >mise.toml <<'EOF'\n[tools]\nnode = \"latest\"\n\"npm:prettier\" = \"3.1.0\"\n\n[env]\nNODE_VERSION = { value = \"{{ tools.node.version }}\", tools = true }\nEOF\n\nassert_succeed \"mise install\"\n"
  },
  {
    "path": "e2e/backend/test_npm",
    "content": "#!/usr/bin/env bash\nrequire_cmd npm\n\nexport NPM_CONFIG_FUND=false\n\nmise use node\nassert \"mise x npm:prettier@3.1.0 -- prettier -v\" \"3.1.0\"\nassert \"FORCE_COLOR=0 mise x npm:@antfu/ni@0.21.12 -- ni -v 2>/dev/null | head -n1\" \"@antfu/ni  v0.21.12\"\nassert_succeed \"mise install npm:tldr@3.4.0\"\n"
  },
  {
    "path": "e2e/backend/test_npm_package_manager",
    "content": "#!/usr/bin/env bash\n\n# Test that npm backend properly uses npm.package_manager and legacy npm.bun settings\n\n# Ensure npm is available by installing node if needed\nif ! command -v npm >/dev/null 2>&1; then\n\techo \"npm not available in test environment, installing node...\"\n\t# Disable GPG verification for faster test\n\texport MISE_GPG_VERIFY=false\n\tassert_succeed \"mise use node@20\"\nfi\n\n# Ensure bun is available\nif ! command -v bun >/dev/null 2>&1; then\n\techo \"bun not available in test environment, installing...\"\n\tassert_succeed \"mise use bun@latest\"\nfi\n\n# Ensure pnpm is available\nif ! command -v pnpm >/dev/null 2>&1; then\n\techo \"pnpm not available in test environment, installing...\"\n\t# Install pnpm using corepack or npm if needed, or just use mise\n\tassert_succeed \"mise use pnpm@latest\"\nfi\n\n# Test 1: Default behavior (npm) - checks npm.package_manager=\"npm\" implicitly\necho \"Testing npm backend with default settings (npm)...\"\nunset MISE_NPM_BUN\nunset MISE_NPM_PACKAGE_MANAGER\n\n# Test listing versions - should succeed\nassert_succeed \"mise ls-remote npm:tiny >/dev/null\"\necho \"✓ npm backend lists versions using npm\"\n\n# Test installation using npm (default)\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\nassert_succeed \"mise install npm:tiny@latest >/dev/null 2>&1\"\necho \"✓ npm backend successfully installs package using npm (default)\"\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\n\n# Test 2: npm.package_manager = \"bun\"\necho \"Testing npm.package_manager=bun...\"\nexport MISE_NPM_PACKAGE_MANAGER=bun\n\nassert_succeed \"mise install npm:tiny@latest >/dev/null 2>&1\"\necho \"✓ npm backend successfully installs package using bun (package_manager=bun)\"\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\n\n# Test 3: npm.package_manager = \"pnpm\"\necho \"Testing npm.package_manager=pnpm...\"\nexport MISE_NPM_PACKAGE_MANAGER=pnpm\n\nif ! mise install npm:tiny@latest >/tmp/pnpm_debug.log 2>&1; then\n\techo \"Command failed. Output:\"\n\tcat /tmp/pnpm_debug.log\n\texit 1\nfi\necho \"✓ npm backend successfully installs package using pnpm (package_manager=pnpm)\"\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\n\n# Test 4: Legacy npm.bun = true (should override package_manager=npm default)\necho \"Testing legacy npm.bun=true...\"\nunset MISE_NPM_PACKAGE_MANAGER\nexport MISE_NPM_BUN=true\n\nassert_succeed \"mise install npm:tiny@latest >/dev/null 2>&1\"\necho \"✓ npm backend successfully installs package using bun (legacy npm.bun=true)\"\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\n\nunset MISE_NPM_BUN\n\n# Test 5: npm.bun = true overrides package_manager=\"npm\"\necho \"Testing npm.bun=true overrides npm.package_manager=npm...\"\nexport MISE_NPM_BUN=true\nexport MISE_NPM_PACKAGE_MANAGER=npm\n\nassert_succeed \"mise install npm:tiny@latest >/dev/null 2>&1\"\n# Verify it actually used bun? The output might show it, or we rely on logic.\n# Since installation succeeds, at least it works.\necho \"✓ npm backend successfully installs package (priority check)\"\nmise uninstall npm:tiny@latest >/dev/null 2>&1 || true\n\nunset MISE_NPM_BUN\nunset MISE_NPM_PACKAGE_MANAGER\n\necho \"✓ npm package manager behavior test completed\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_custom_registry",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# Create a system pipx that always fail and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python\nexport MISE_PYTHON_COMPILE=0\nexport MISE_PIPX_REGISTRY_URL=\"https://pypi.org/simple/{}\"\n\n# Set up a 2-step installation: pipx@1.5.0 > pipx:mkdocs@1.6.0\ncat >.mise.toml <<EOF\n[tools]\npipx = \"1.5.0\"\n\"pipx:mkdocs\" = \"1.6.0\"\nEOF\n\nmise install\n\n# Assert that mkdocs 1.6.0 has been installed with pipx\n# (mkdocs conveniently returns its installation path in with --version)\nassert_contains \"mise x -- mkdocs --version\" \"/mise/installs/pipx-mkdocs/1.6.0/\"\n\n# Test invalid MISE_PIPX_REGISTRY_URL format (missing {} placeholder)\nmise uninstall pipx:mkdocs\nmise cache clear\nexport MISE_PIPX_REGISTRY_URL=\"https://invalid-registry.example/simple\"\n\n# This should fail with an error about the registry URL format\nassert_fail \"mise install\" \"Registry URL must be a valid URL and contain a {} placeholder\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_deep_dependencies_slow",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016,SC2034\nexport MISE_PIPX_UVX=0\n\n# Create system \"tools\" that always fail and push them to the front of PATH\ncat >\"$HOME/bin/fail\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM $(basename $0)! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/fail\nfor TOOL in python python3 pipx; do\n\tln -s fail \"$HOME/bin/$TOOL\"\ndone\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"python\"\nassert_fail \"python3\"\nassert_fail \"pipx\"\n\n# Use only precompiled python\nexport MISE_PYTHON_COMPILE=0\n\n# Set up a 3-step installation: python@3.12.3 > pipx@1.5.0 > pipx:mkdocs@1.6.0\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\npipx = \"1.5.0\"\n\"pipx:mkdocs\" = \"1.6.0\"\nEOF\n\n# Install the tools\nmise install\n\n# Assert that mkdocs 1.6.0 has been installed with pipx and uses python 3.12\n# (mkdocs conveniently returns its installation path in with --version)\nassert_contains \"mise x -- mkdocs --version\" \"/mise/installs/pipx-mkdocs/1.6.0/venvs/mkdocs/lib/python3.12/\"\n\nassert \"mise up --bump python\"\nassert_contains \"mise x -- mkdocs --version\" \"mkdocs, version 1.6.0\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_direct_dependencies",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# Create a system pipx that always fail and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python\nexport MISE_PYTHON_COMPILE=0\n\n# Set up a 2-step installation: pipx@1.5.0 > pipx:mkdocs@1.6.0\ncat >.mise.toml <<EOF\n[tools]\npipx = \"1.5.0\"\n\"pipx:mkdocs\" = \"1.6.0\"\nEOF\n\n# Install the tools\nmise install\n\n# Assert that mkdocs 1.6.0 has been installed with pipx\n# (mkdocs conveniently returns its installation path in with --version)\nassert_contains \"mise x -- mkdocs --version\" \"/mise/installs/pipx-mkdocs/1.6.0/\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_extras",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# use python3.12 if available for consistency\nif command -v python3.12 &>/dev/null; then\n\tln -s \"$(which python3.12)\" \"$HOME/bin/python3\"\nfi\n\n# Create a system pipx that always fail and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python\nexport MISE_PYTHON_COMPILE=0\n\n# Set up a 2-step installation: pipx@1.5.0 > pipx:mkdocs@1.6.0\ncat >.mise.toml <<EOF\n[tools]\npipx = \"1.5.0\"\n\"pipx:harlequin\" = {version = \"2.5.1\", extras = \"s3\"}\nEOF\n\n# Install the tools\nmise install\n\nassert_contains \"mise x -- harlequin --version\" \"2.5.1\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_postinstall_hook",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# Test that pipx postinstall hooks can invoke the installed tool when using uvx.\n# This validates the fix for https://github.com/jdx/mise/discussions/7864\n# The bug was that uvx creates venv symlinks pointing to minor version paths\n# (e.g., python/3.12/) but the symlink didn't exist yet when postinstall ran.\n\n# Create a system pipx that always fails and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python and uvx (the default)\nexport MISE_PYTHON_COMPILE=0\nexport MISE_PIPX_UVX=1\n\n# Set up mise-managed Python with a pipx package that has a postinstall hook\n# The hook invokes the installed tool, which requires the Python symlink to work\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.5\"\n\n[tools.\"pipx:mkdocs\"]\nversion = \"1.6.0\"\npostinstall = \"mkdocs --version\"\nEOF\n\n# Install the tools - this should succeed with the postinstall hook\nmise install\n\n# Verify mkdocs is installed and works\nassert_contains \"mise x -- mkdocs --version\" \"1.6.0\"\n\n# Verify the minor version symlink was created early (before runtime_symlinks::rebuild)\nMINOR_VERSION_DIR=\"$MISE_DATA_DIR/installs/python/3.12\"\nif [[ -L $MINOR_VERSION_DIR ]]; then\n\tok \"Minor version symlink 3.12 was created\"\nelif [[ -d $MINOR_VERSION_DIR ]]; then\n\tok \"Minor version directory 3.12 exists\"\nelse\n\tfail \"Minor version symlink/directory 3.12 does not exist\"\nfi\n"
  },
  {
    "path": "e2e/backend/test_pipx_slow",
    "content": "#!/usr/bin/env bash\nrequire_cmd pipx\n\nassert_contains \"mise x pipx:black@22.6.0 -- black --version\" \"22.6.0\"\nassert_contains \"mise x pipx:psf/black@24.3.0 -- black --version\" \"24.3.0\"\nassert_contains \"mise x pipx:git+https://github.com/psf/black.git@24.2.0 -- black --version\" \"24.2.0\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_uvx",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# Create a system pipx that always fail and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python\nexport MISE_PYTHON_COMPILE=0\nexport MISE_PIPX_UVX=1\n\n# Set up a 2-step installation: pipx@1.5.0 > pipx:mkdocs@1.6.0\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\npipx = \"1.5.0\"\nuv = \"0.5.5\"\n\"pipx:mkdocs\" = \"1.6.0\"\nEOF\n\n# Install the tools\nmise install\n\n# Assert that mkdocs 1.6.0 has been installed with pipx\n# (mkdocs conveniently returns its installation path in with --version)\nassert_contains \"mise x -- mkdocs --version\" \"/mise/installs/pipx-mkdocs/1.6.0/\"\n\nassert \"mise up --bump python\"\nassert_contains \"mise x -- mkdocs --version\" \"mkdocs, version 1.6.0\"\n"
  },
  {
    "path": "e2e/backend/test_pipx_venv_symlink",
    "content": "#!/usr/bin/env bash\nrequire_cmd python3\n\n# Create a system pipx that always fail and push it to the front of PATH\ncat >\"$HOME/bin/pipx\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM pipx! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME\"/bin/pipx\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Just to be sure...\nassert_fail \"pipx\"\n\n# Use precompiled python and disable uvx to use pipx (which uses mise's Python)\nexport MISE_PYTHON_COMPILE=0\nexport MISE_PIPX_UVX=0\n\n# Set up mise-managed Python and pipx\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12\"\npipx = \"1.5.0\"\n\"pipx:cowsay\" = \"6.1\"\nEOF\n\n# Install the tools\nmise install\n\n# Verify cowsay is installed\nassert_contains \"mise x -- cowsay --version\" \"6.1\"\n\n# Find the venv directory - could be cowsay/ or venvs/cowsay/\nINSTALL_DIR=\"$MISE_DATA_DIR/installs/pipx-cowsay/6.1\"\nif [[ -d \"$INSTALL_DIR/cowsay\" ]]; then\n\tVENV_DIR=\"$INSTALL_DIR/cowsay\"\nelif [[ -d \"$INSTALL_DIR/venvs/cowsay\" ]]; then\n\tVENV_DIR=\"$INSTALL_DIR/venvs/cowsay\"\nelse\n\techo \"Venv directory structure:\"\n\tls -la \"$INSTALL_DIR\"\n\tfail \"Could not find venv directory\"\nfi\n\n# Check the venv Python symlink target (not fully resolved, just immediate target)\n# We want to verify the symlink points to the minor version path (e.g., python/3.12/)\n# not the full version path (e.g., python/3.12.12/)\n\n# Find the symlink with the absolute path (python3, not python which points to python3)\nPYTHON3_SYMLINK=\"$VENV_DIR/bin/python3\"\nif [[ -L $PYTHON3_SYMLINK ]]; then\n\t# Get immediate symlink target (not fully resolved)\n\tSYMLINK_TARGET=$(readlink \"$PYTHON3_SYMLINK\")\n\n\t# Check if the symlink target contains mise's installs directory\n\tif [[ $SYMLINK_TARGET == *\"/installs/python/\"* ]]; then\n\t\t# If it's mise-managed Python, verify the symlink uses minor version (e.g., 3.12 not 3.12.x)\n\t\t# The regex matches /python/X.Y/ but not /python/X.Y.Z/\n\t\tif [[ $SYMLINK_TARGET =~ /python/[0-9]+\\.[0-9]+/bin/python ]]; then\n\t\t\tok \"Venv python3 symlink uses minor version path\"\n\t\telif [[ $SYMLINK_TARGET =~ /python/[0-9]+\\.[0-9]+\\.[0-9]+/bin/python ]]; then\n\t\t\tfail \"Venv python3 symlink uses full version path instead of minor version: $SYMLINK_TARGET\"\n\t\telse\n\t\t\tok \"Venv python3 symlink path format is unexpected but accepted: $SYMLINK_TARGET\"\n\t\tfi\n\telse\n\t\t# Not mise-managed Python (could be homebrew, uv, etc.) - that's fine\n\t\tok \"Venv python3 symlink points to non-mise Python (expected in some environments)\"\n\tfi\nelse\n\tok \"Venv python3 is not a symlink (expected on some platforms)\"\nfi\n"
  },
  {
    "path": "e2e/backend/test_s3",
    "content": "#!/usr/bin/env bash\n\n# Test S3 backend configuration and error handling\n# Note: This test validates configuration parsing and error messages\n# since we don't have a test S3 bucket available in CI\n\n# Test 1: S3 backend requires 'url' option\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\" }\nEOF\n\nassert_fail_matches \"mise install 2>&1\" \"S3 backend requires 'url' option\"\n\n# Test 2: S3 URL must use s3:// scheme\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\", url = \"https://bucket/path/tool.tar.gz\" }\nEOF\n\nassert_fail_matches \"mise install 2>&1\" \"URL must use s3:// scheme\"\n\n# Test 3: S3 URL must include bucket name\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\", url = \"s3:///path/tool.tar.gz\" }\nEOF\n\nassert_fail_matches \"mise install 2>&1\" \"S3 URL must include bucket name\"\n\n# Test 4: Valid S3 URL shows access denied (expected without credentials)\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\", url = \"s3://nonexistent-bucket-12345/tools/test-{version}.tar.gz\" }\nEOF\n\n# This should fail with an S3 error (access denied or bucket not found)\n# The exact error depends on AWS SDK behavior, but it should be an S3-related error\nassert_fail_matches \"mise install 2>&1\" \"S3\"\n\n# Test 5: Verify S3 backend is recognized (ls-remote returns empty when no version discovery)\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\", url = \"s3://bucket/tools/test-{version}.tar.gz\" }\nEOF\n\n# ls-remote should succeed but return empty (no version discovery configured)\nassert_empty \"mise ls-remote s3:test-tool\"\n\n# Test 6: S3 backend with custom endpoint (for MinIO, etc.)\ncat <<EOF >mise.toml\n[tools.\"s3:custom-endpoint\"]\nversion = \"1.0.0\"\nurl = \"s3://bucket/tools/tool-{version}.tar.gz\"\nendpoint = \"http://localhost:9000\"\nregion = \"us-east-1\"\nEOF\n\n# Should fail trying to connect to the endpoint\nassert_fail_matches \"mise install 2>&1\" \"S3\"\n\n# Test 7: S3 backend with platform-specific URLs\ncat <<EOF >mise.toml\n[tools.\"s3:platform-tool\"]\nversion = \"1.0.0\"\n\n[tools.\"s3:platform-tool\".platforms]\ndarwin-arm64 = { url = \"s3://bucket/tools/tool-{version}-darwin-arm64.tar.gz\" }\ndarwin-x64 = { url = \"s3://bucket/tools/tool-{version}-darwin-x64.tar.gz\" }\nlinux-x64 = { url = \"s3://bucket/tools/tool-{version}-linux-x64.tar.gz\" }\nEOF\n\n# Should fail with S3 error (validates platform URL selection works)\nassert_fail_matches \"mise install 2>&1\" \"S3\"\n\necho \"S3 backend E2E tests completed successfully\"\n"
  },
  {
    "path": "e2e/backend/test_s3_minio_slow",
    "content": "#!/usr/bin/env bash\n\n# Test S3 backend with a real MinIO server\n# This test installs MinIO, starts a local server, and tests actual S3 operations\n\n# Install MinIO server and client\nmise install minio@latest mc@latest\n\n# MinIO configuration\nMINIO_PORT=19000\nMINIO_CONSOLE_PORT=19001\nMINIO_ROOT_USER=\"minioadmin\"\nMINIO_ROOT_PASSWORD=\"minioadmin\"\nMINIO_ENDPOINT=\"http://127.0.0.1:$MINIO_PORT\"\n# Use /tmp directly to avoid disk space issues in isolated test tmp dir\nMINIO_DATA_DIR=\"/tmp/mise-minio-test-$$\"\n\n# Create data directory\nmkdir -p \"$MINIO_DATA_DIR\"\n\n# Start MinIO server in the background using mise x\n# MINIO_CI_CD=1 relaxes storage constraints for CI/CD environments\nMINIO_ROOT_USER=\"$MINIO_ROOT_USER\" \\\n\tMINIO_ROOT_PASSWORD=\"$MINIO_ROOT_PASSWORD\" \\\n\tMINIO_CI_CD=1 \\\n\tmise x minio@latest -- minio server \"$MINIO_DATA_DIR\" \\\n\t--address \":$MINIO_PORT\" \\\n\t--console-address \":$MINIO_CONSOLE_PORT\" \\\n\t>/dev/null 2>&1 &\nMINIO_PID=$!\n\n# Cleanup function\ncleanup() {\n\tif [[ -n ${MINIO_PID:-} ]]; then\n\t\tkill \"$MINIO_PID\" 2>/dev/null || true\n\t\twait \"$MINIO_PID\" 2>/dev/null || true\n\tfi\n\trm -rf \"$MINIO_DATA_DIR\"\n}\ntrap cleanup EXIT\n\n# Wait for MinIO to be ready\necho \"Waiting for MinIO to start...\"\nfor i in {1..30}; do\n\tif curl -s \"$MINIO_ENDPOINT/minio/health/ready\" >/dev/null 2>&1; then\n\t\techo \"MinIO is ready\"\n\t\tbreak\n\tfi\n\tif [[ $i -eq 30 ]]; then\n\t\techo \"MinIO failed to start\"\n\t\texit 1\n\tfi\n\tsleep 1\ndone\n\n# Configure mc (MinIO client) using mise x\nmise x mc@latest -- mc alias set testminio \"$MINIO_ENDPOINT\" \"$MINIO_ROOT_USER\" \"$MINIO_ROOT_PASSWORD\" --api S3v4\n\n# Create test bucket\nmise x mc@latest -- mc mb testminio/test-bucket\n\n# Create a simple test tarball with a hello-world script\n# Use --no-xattrs and --no-mac-metadata to avoid macOS extended attribute issues\nTEST_DIR=\"$HOME/test-tool-1.0.0\"\nmkdir -p \"$TEST_DIR/bin\"\nprintf '#!/bin/sh\\necho \"test-tool version 1.0.0\"\\n' >\"$TEST_DIR/bin/test-tool\"\nchmod +x \"$TEST_DIR/bin/test-tool\"\n\n# Create tarball without macOS metadata\nif tar --help 2>&1 | grep -q \"no-mac-metadata\"; then\n\t(cd \"$HOME\" && tar --no-mac-metadata -czf test-tool-1.0.0.tar.gz test-tool-1.0.0)\nelse\n\t(cd \"$HOME\" && COPYFILE_DISABLE=1 tar -czf test-tool-1.0.0.tar.gz test-tool-1.0.0)\nfi\n\n# Upload to MinIO\nmise x mc@latest -- mc cp \"$HOME/test-tool-1.0.0.tar.gz\" testminio/test-bucket/tools/\n\n# Create a versions.json manifest\necho '[\"1.0.0\", \"0.9.0\", \"0.8.0\"]' >\"$HOME/versions.json\"\nmise x mc@latest -- mc cp \"$HOME/versions.json\" testminio/test-bucket/tools/\n\n# Set AWS credentials for mise to use\nexport AWS_ACCESS_KEY_ID=\"$MINIO_ROOT_USER\"\nexport AWS_SECRET_ACCESS_KEY=\"$MINIO_ROOT_PASSWORD\"\nexport AWS_DEFAULT_REGION=\"us-east-1\"\n\n# Test 1: Basic S3 download and install\necho \"Test 1: Basic S3 download and install\"\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool\" = { version = \"1.0.0\", url = \"s3://test-bucket/tools/test-tool-{version}.tar.gz\", endpoint = \"$MINIO_ENDPOINT\", region = \"us-east-1\", bin_path = \"test-tool-1.0.0/bin\", postinstall = \"chmod +x \\$MISE_TOOL_INSTALL_PATH/test-tool-1.0.0/bin/test-tool\" }\nEOF\n\nmise install\n\n# Debug: show what was installed\nls -la \"$HOME/.local/share/mise/installs/s3-test-tool/1.0.0/\" || true\nls -la \"$HOME/.local/share/mise/installs/s3-test-tool/1.0.0/test-tool-1.0.0/bin/\" || true\n\n# Debug: check if the binary runs directly\ncat \"$HOME/.local/share/mise/installs/s3-test-tool/1.0.0/test-tool-1.0.0/bin/test-tool\"\n\"$HOME/.local/share/mise/installs/s3-test-tool/1.0.0/test-tool-1.0.0/bin/test-tool\" || echo \"Direct exec failed with: $?\"\n\n# Debug: check mise bin paths\nmise where s3:test-tool@1.0.0 || true\nmise bin-paths s3:test-tool@1.0.0 || true\n\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\n\n# Test 2: Version listing from manifest file\necho \"Test 2: Version listing from manifest file\"\ncat <<EOF >mise.toml\n[tools.\"s3:test-tool-manifest\"]\nversion = \"latest\"\nurl = \"s3://test-bucket/tools/test-tool-{version}.tar.gz\"\nversion_list_url = \"s3://test-bucket/tools/versions.json\"\nendpoint = \"$MINIO_ENDPOINT\"\nregion = \"us-east-1\"\nbin_path = \"test-tool-1.0.0/bin\"\nEOF\n\n# List versions - should show 1.0.0, 0.9.0, 0.8.0\nVERSIONS=$(mise ls-remote s3:test-tool-manifest)\nassert_contains \"echo '$VERSIONS'\" \"1.0.0\"\nassert_contains \"echo '$VERSIONS'\" \"0.9.0\"\nassert_contains \"echo '$VERSIONS'\" \"0.8.0\"\n\n# Test 3: Version listing from S3 object listing\necho \"Test 3: Version listing from S3 object listing\"\n\n# Upload additional versions for listing test\ncp \"$HOME/test-tool-1.0.0.tar.gz\" \"$HOME/test-tool-0.9.0.tar.gz\"\ncp \"$HOME/test-tool-1.0.0.tar.gz\" \"$HOME/test-tool-0.8.0.tar.gz\"\nmise x mc@latest -- mc cp \"$HOME/test-tool-0.9.0.tar.gz\" testminio/test-bucket/tools/\nmise x mc@latest -- mc cp \"$HOME/test-tool-0.8.0.tar.gz\" testminio/test-bucket/tools/\n\ncat <<EOF >mise.toml\n[tools.\"s3:test-tool-listing\"]\nversion = \"latest\"\nurl = \"s3://test-bucket/tools/test-tool-{version}.tar.gz\"\nversion_prefix = \"tools/test-tool-\"\nversion_regex = \"test-tool-([0-9.]+)\"\nendpoint = \"$MINIO_ENDPOINT\"\nregion = \"us-east-1\"\nbin_path = \"test-tool-1.0.0/bin\"\nEOF\n\n# List versions - should find versions from S3 listing\nVERSIONS=$(mise ls-remote s3:test-tool-listing)\nassert_contains \"echo '$VERSIONS'\" \"1.0.0\"\nassert_contains \"echo '$VERSIONS'\" \"0.9.0\"\nassert_contains \"echo '$VERSIONS'\" \"0.8.0\"\n\n# Test 4: Checksum verification\necho \"Test 4: Checksum verification\"\n\n# Calculate checksum of the uploaded file (use shasum on macOS, sha256sum on Linux)\nif command -v sha256sum >/dev/null 2>&1; then\n\tCHECKSUM=$(sha256sum \"$HOME/test-tool-1.0.0.tar.gz\" | cut -d' ' -f1)\nelse\n\tCHECKSUM=$(shasum -a 256 \"$HOME/test-tool-1.0.0.tar.gz\" | cut -d' ' -f1)\nfi\n\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool-checksum\" = { version = \"1.0.0\", url = \"s3://test-bucket/tools/test-tool-{version}.tar.gz\", endpoint = \"$MINIO_ENDPOINT\", region = \"us-east-1\", bin_path = \"test-tool-1.0.0/bin\", checksum = \"sha256:$CHECKSUM\" }\nEOF\n\nmise install\nassert_contains \"mise x -- test-tool\" \"test-tool version 1.0.0\"\n\n# Test 5: Invalid checksum should fail\necho \"Test 5: Invalid checksum should fail\"\ncat <<EOF >mise.toml\n[tools]\n\"s3:test-tool-bad-checksum\" = { version = \"1.0.0\", url = \"s3://test-bucket/tools/test-tool-{version}.tar.gz\", endpoint = \"$MINIO_ENDPOINT\", region = \"us-east-1\", bin_path = \"test-tool-1.0.0/bin\", checksum = \"sha256:0000000000000000000000000000000000000000000000000000000000000000\" }\nEOF\n\nassert_fail \"mise install 2>&1\"\n\necho \"All S3 MinIO tests passed!\"\n"
  },
  {
    "path": "e2e/backend/test_terraform",
    "content": "#!/usr/bin/env bash\n\n# Enable idiomatic version files for terraform\nmise settings set idiomatic_version_file_enable_tools terraform\n\necho \"1.10.0\" >.terraform-version\nassert_contains \"mise tool terraform\" \"1.10.0\"\n"
  },
  {
    "path": "e2e/backend/test_ubi",
    "content": "#!/usr/bin/env bash\n\nassert \"mise x ubi:goreleaser/goreleaser@v1.25.0 -- goreleaser -v | grep -o 1.25.0\" \"1.25.0\"\n\nmise use ubi:kellyjonbrazil/jc@1.25.3\nassert_contains \"$MISE_DATA_DIR/shims/jc --version\" \"jc version:  1.25.3\"\n\n# only run on linux/amd64\nif [ \"$(uname -m)\" = \"x86_64\" ] && [ \"$(uname -s)\" = \"Linux\" ]; then\n\tmise use 'ubi:https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz[exe=ffmpeg]'\n\tassert_contains \"$MISE_DATA_DIR/shims/ffmpeg -version\" \"ffmpeg version\"\nfi\n\ncat <<EOF >mise.toml\n[tools]\n\"ubi:cilium/cilium-cli\" = { version = \"latest\", exe = \"cilium\" }\nEOF\n# re-uses tool options\nmise use ubi:cilium/cilium-cli\nassert \"cat mise.toml\" '[tools]\n\"ubi:cilium/cilium-cli\" = { version = \"latest\", exe = \"cilium\" }'\n\nassert \"mise x ubi:gitlab-org/cli[exe=glab,provider=gitlab]@1.54.0 -- glab --version | grep -o 1.54.0\" \"1.54.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"ubi:gitlab-org/cli\" = { version = \"1.55.0\", exe = \"glab\", provider = \"gitlab\" }\nEOF\nmise use ubi:gitlab-org/cli@1.55.0\nassert \"mise x ubi:gitlab-org/cli@1.55.0 -- glab --version | grep -o 1.55.0\" \"1.55.0\"\n\ncat <<EOF >mise.toml\n[tools]\n\"ubi:kscripting/kscript\" = { version = \"4.2.3\", bin_path = \"bin\", extract_all = \"true\" }\nEOF\nmise use ubi:kscripting/kscript@4.2.3\nassert_contains \"mise x ubi:kscripting/kscript@4.2.3 -- which kscript\" \"/4.2.3/bin/kscript\"\n\nMISE_USE_VERSIONS_HOST=0 assert_not_contains \"mise ls-remote cargo-binstall\" \"binstalk\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_backend_npm",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test vfox backend with npm plugin (plugin:tool format) using vfox-npm submodule\n\n# Link the vfox-npm plugin from the submodule\nmise plugins link vfox-npm \"$ROOT/test/plugins/vfox-npm\"\n\n# Test plugin:tool format with assertions\nlatest_version=$(mise latest vfox-npm:prettier)\npartial_version=$(echo \"$latest_version\" | cut -d. -f1-2)\nassert_contains \"mise ls-remote vfox-npm:prettier\" \"$partial_version.\"\nmise install \"vfox-npm:prettier@$latest_version\"\nassert \"mise use vfox-npm:prettier@$latest_version\"\nassert_contains \"mise exec -- prettier --version\" \"$latest_version\"\n\n# Test uninstall functionality\nassert \"mise uninstall vfox-npm:prettier@$latest_version\"\nassert_directory_not_exists \"$MISE_DATA_DIR/installs/vfox-npm/prettier/$latest_version\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_cmake",
    "content": "#!/usr/bin/env bash\n\nassert \"mise x vfox:cmake@3.30.2 -- cmake --version\" \"cmake version 3.30.2\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_embedded_override",
    "content": "#!/usr/bin/env bash\n\n# Test that embedded vfox plugins can be overridden by installing a filesystem plugin\n\n# Verify embedded plugin works without installation - use the short \"bfs\" name\n# which goes through the versions host cache (doesn't require network to the plugin)\nassert_contains \"mise ls-remote bfs\" \"4.0\"\n\n# Embedded plugins don't show git info in plugins list\nassert_not_contains \"mise plugins --urls\" \"vfox-bfs\"\n\n# Install the same vfox plugin as a filesystem override\nmise plugin install vfox-bfs https://github.com/mise-plugins/vfox-bfs\n\n# Verify the filesystem plugin is now shown with git URL (overrides embedded)\nassert_contains \"mise plugins --urls\" \"vfox-bfs\"\nassert_contains \"mise plugins --urls\" \"github.com/mise-plugins/vfox-bfs\"\n\n# Verify it still works (now using filesystem version)\nassert_contains \"mise ls-remote bfs\" \"4.0\"\n\n# Uninstall the override\nmise plugin uninstall vfox-bfs\n\n# Verify it falls back to embedded (no longer in plugins list with URL)\nassert_not_contains \"mise plugins --urls\" \"vfox-bfs\"\n\n# Verify embedded still works after uninstall\nassert_contains \"mise ls-remote bfs\" \"4.0\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_file_url",
    "content": "#!/usr/bin/env bash\n\n# Test installing vfox plugins using file:// URLs\n# This verifies that file:// URLs don't panic (they have no host)\n\n# Clone the plugin to a temp directory\nPLUGIN_DIR=\"$MISE_DATA_DIR/test-vfox-aapt2\"\ngit clone --depth 1 https://github.com/mise-plugins/vfox-aapt2.git \"$PLUGIN_DIR\"\n\n# List remote versions using file:// URL\nassert_contains \"mise ls-remote vfox:file://$PLUGIN_DIR\" \"9.0.0\"\n\n# Install a specific version\nmise install \"vfox:file://$PLUGIN_DIR@9.0.0-14304508\"\n\n# Verify installation\nassert_contains \"mise ls vfox:file://$PLUGIN_DIR\" \"9.0.0-14304508\"\n\n# Verify the tool runs via mise x\nassert_succeed \"mise x vfox:file://$PLUGIN_DIR@9.0.0-14304508 -- aapt2 version\"\n\n# Clean up\nmise uninstall \"vfox:file://$PLUGIN_DIR@9.0.0-14304508\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_go_slow",
    "content": "#!/usr/bin/env bash\n\nversion=\"$(mise latest vfox:version-fox/vfox-golang)\"\nassert \"mise i vfox:version-fox/vfox-golang\"\nassert_contains \"mise x vfox:version-fox/vfox-golang -- go version\" \"go version go$version\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_kotlin_slow",
    "content": "#!/usr/bin/env bash\n\nmise use java\nassert_contains \"mise x vfox:version-fox/vfox-kotlin@2.0.20 -- kotlin -version\" \"Kotlin version 2.0.20\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_log",
    "content": "#!/usr/bin/env bash\n\n# Install the dummy vfox plugin from GitHub\nmise plugin install vfox-dummy https://github.com/jdx/vfox-dummy\n\n# Test with MISE_DEBUG=1 to capture debug+ level output\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] log.debug msg\"\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] log.info msg\"\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] log.warn msg\"\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] log.error msg\"\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] print msg\"\nassert_contains \"TEST_VFOX_LOG=1 MISE_DEBUG=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] multi\targ\t123\"\n\n# Test with MISE_TRACE=1 to capture trace level\nassert_contains \"TEST_VFOX_LOG=1 MISE_TRACE=1 mise ls-remote vfox-dummy 2>&1\" \"[vfox-dummy] log.trace msg\"\n\n# Verify direct stderr write passes through\nassert_contains \"TEST_VFOX_LOG=1 mise ls-remote vfox-dummy 2>&1\" \"stderr msg\"\n\n# Verify log.debug is NOT shown at default log level\nassert_not_contains \"TEST_VFOX_LOG=1 mise ls-remote vfox-dummy 2>&1\" \"log.debug msg\"\nassert_not_contains \"TEST_VFOX_LOG=1 mise ls-remote vfox-dummy 2>&1\" \"log.trace msg\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_maven_slow",
    "content": "#!/usr/bin/env bash\n\n# this is flaky\n# mise use java\n# assert_contains \"mise x vfox:version-fox/vfox-maven@3.9.8 -- mvn --version\" \"Apache Maven 3.9.8\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_node_slow",
    "content": "#!/usr/bin/env bash\n\nmise i vfox:version-fox/vfox-nodejs@23.2.0\nassert \"mise x vfox:version-fox/vfox-nodejs@23.2.0 -- node -v\" \"v23.2.0\"\n"
  },
  {
    "path": "e2e/backend/test_vfox_python_slow",
    "content": "#!/usr/bin/env bash\n\nmise i vfox:version-fox/vfox-python@3.12.0\nassert \"mise x vfox:version-fox/vfox-python@3.12.0 -- python3 -V\" \"Python 3.12.0\"\n"
  },
  {
    "path": "e2e/cli/activate_multiple_xonsh.xsh",
    "content": "# shellcheck disable=all\n$XONSH_SHOW_TRACEBACK = True\n\n# Test that calling mise activate multiple times preserves user-added paths at the front\n# while properly handling mise paths (env._.path and tool installs)\n#\n# Expected behavior:\n# - Start: A\n# - mise activate: env_path:mise_tools:A\n# - add B: B:env_path:mise_tools:A\n# - mise activate + hook-env: B:env_path:mise_tools:A (user path B preserved at front)\n# - add C: C:B:env_path:mise_tools:A\n# - mise activate + hook-env: C:B:env_path:mise_tools:A (user paths C,B preserved at front)\n# - deactivate: C:B:A (mise_tools and env_path removed, user paths preserved)\n\nfrom xonsh.built_ins import XSH\nimport os\n\n# Create a mise config with a tool, env._.path, and env.FOO\nmkdir -p custom_bin\nconfig = \"\"\"\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\"]\nFOO = \"bar\"\nBAZ = \"qux\"\n\"\"\"\necho @(config) > .mise.toml\n\nmise install\n\n# Save the original PATH for verification\nORIGINAL_PATH = list(XSH.env['PATH'])\n\n# First activation\n# shellcheck disable=SC1073,SC1065,SC1064,SC1072\nexecx($(mise activate -s xonsh))\n\n# Fire the hook to apply environment\nevents.on_pre_prompt.fire()\n\n# Verify env variables were set\nassert XSH.env.get('FOO') == 'bar', f\"FOO should be bar, got: {XSH.env.get('FOO')}\"\nassert XSH.env.get('BAZ') == 'qux', f\"BAZ should be qux, got: {XSH.env.get('BAZ')}\"\n\n# Check that mise was activated at all\nassert 'mise' in aliases\n\n# custom_bin from env._.path should be in PATH\ncurrent_path = ':'.join(XSH.env['PATH'])\nassert 'custom_bin' in current_path, \"custom_bin not in PATH\"\n\n# Get the mise tool path - it should be somewhere in PATH\nmise_tool_path = None\nfor p in XSH.env['PATH']:\n    if '/mise/installs/tiny' in p:\n        mise_tool_path = p\n        break\nassert mise_tool_path is not None, \"MISE_TOOL_PATH not found\"\n\n# Verify no duplicate paths\npath_list = XSH.env['PATH']\nassert len(path_list) == len(set(path_list)), \"Duplicate paths found\"\n\n# User adds path B\nXSH.env['PATH'].add('/path_b', front=True)\n\n# User modifies FOO\nXSH.env['FOO'] = 'user_modified'\n\n# Second activation - user path preserved at front, mise paths follow\n# This tests that activation is idempotent when __MISE_DIFF exists but mise isn't in aliases\n# (simulating nested shells like tmux)\ndel aliases['mise']\n# shellcheck disable=SC1073,SC1065,SC1064,SC1072\nexecx($(mise activate -s xonsh))\nevents.on_pre_prompt.fire()\n\n# FOO should be reset to \"bar\" by mise\nassert XSH.env.get('FOO') == 'bar', f\"FOO should be bar after reactivation, got: {XSH.env.get('FOO')}\"\n\n# BAZ should still be qux\nassert XSH.env.get('BAZ') == 'qux', f\"BAZ should be qux, got: {XSH.env.get('BAZ')}\"\n\n# Verify mise paths are in PATH\ncurrent_path = ':'.join(XSH.env['PATH'])\nassert '/path_b' in current_path, \"/path_b not in PATH after second activation\"\nassert 'custom_bin' in current_path, \"custom_bin not in PATH after second activation\"\nassert '/mise/installs/tiny' in current_path, \"Tool path not in PATH after second activation\"\n\n# Check no duplicates\npath_list = XSH.env['PATH']\nassert len(path_list) == len(set(path_list)), \"Duplicate paths found after second activation\"\n\n# User adds path C\nXSH.env['PATH'].add('/path_c', front=True)\n\n# Third activation - user paths preserved at front, mise paths follow\n# shellcheck disable=SC1073,SC1065,SC1064,SC1072\nexecx($(mise activate -s xonsh))\nevents.on_pre_prompt.fire()\n\n# Verify all paths are present\ncurrent_path = ':'.join(XSH.env['PATH'])\nassert '/path_c' in current_path, \"/path_c not in PATH\"\nassert '/path_b' in current_path, \"/path_b not in PATH\"\nassert 'custom_bin' in current_path, \"custom_bin not in PATH\"\nassert '/mise/installs/tiny' in current_path, \"Tool path not in PATH\"\n\n# Check no duplicates\npath_list = XSH.env['PATH']\nassert len(path_list) == len(set(path_list)), \"Duplicate paths found after third activation\"\n\n# Test deactivation - unsets mise shell functions and variables\n# (Comprehensive deactivation tests are in test_deactivate)\nmise deactivate\n\nprint(\"All tests passed!\")\n"
  },
  {
    "path": "e2e/cli/deactivate_xonsh.xsh",
    "content": "# shellcheck disable=all\n$XONSH_SHOW_TRACEBACK = True\n\n# Test that mise deactivate properly works and can be called multiple times safely\n# This tests the fix for https://github.com/jdx/mise/issues/6855\n\nfrom xonsh.built_ins import XSH\n\n# Create a simple mise config\nconfig = \"\"\"\n[tools]\ntiny = \"latest\"\n\n[env]\nFOO = \"mise_foo\"\n\"\"\"\necho @(config) > .mise.toml\n\nmise install\n\n# Activate mise\n# shellcheck disable=SC1073,SC1065,SC1064,SC1072\nexecx($(mise activate -s xonsh))\nevents.on_pre_prompt.fire()\n\n# Verify mise is activated\nassert 'mise' in aliases, \"mise alias should exist after activation\"\nassert XSH.env.get('FOO') == 'mise_foo', \"FOO should be set\"\n\n# Deactivate mise\nmise deactivate\n\n# Verify mise is deactivated\nassert 'mise' not in aliases, \"mise alias should be removed after deactivate\"\n\n# Test edge case: deactivating when not activated should be safe\n# This is the KEY TEST for the fix - using .pop() instead of del\n# means this won't raise KeyError\nmise deactivate\nprint(\"deactivate_twice works - fix verified!\")\n\nprint(\"All tests passed!\")\n"
  },
  {
    "path": "e2e/cli/test_activate_aggressive",
    "content": "#!/usr/bin/env bash\n\neval \"$(mise activate bash)\"\nexport PATH=\"/added:$PATH\"\n\nassert \"mise hook-env -s bash --trace\" \"\" # checking early exit functions\nmkdir -p \"$MISE_DATA_DIR/installs/dummy/1.0.0/bin\"\necho \"#!/usr/bin/env bash\" >\"$MISE_DATA_DIR/installs/dummy/1.0.0/bin/dummy\"\nchmod +x \"$MISE_DATA_DIR/installs/dummy/1.0.0/bin/dummy\"\necho \"tools.dummy = '1'\" >mise.toml\nassert_contains \"mise hook-env -s bash --trace\" \"export PATH='/added:$MISE_DATA_DIR/installs/dummy/1.0.0/bin:\"\nexport MISE_ACTIVATE_AGGRESSIVE=1\nassert_contains \"mise hook-env -s bash --trace\" \"export PATH='$MISE_DATA_DIR/installs/dummy/1.0.0/bin:/added:\"\n"
  },
  {
    "path": "e2e/cli/test_activate_multiple",
    "content": "#!/usr/bin/env bash\n\n# Test that calling mise activate multiple times preserves user-added paths at the front\n# while properly handling mise paths (env._.path and tool installs)\n#\n# Expected behavior:\n# - Start: A\n# - mise activate: env_path:mise_tools:A\n# - add B: B:env_path:mise_tools:A\n# - mise activate + hook-env: B:env_path:mise_tools:A (user path B preserved at front)\n# - add C: C:B:env_path:mise_tools:A\n# - mise activate + hook-env: C:B:env_path:mise_tools:A (user paths C,B preserved at front)\n# - deactivate: C:B:A (mise_tools and env_path removed, user paths preserved)\n\n# Create a mise config with a tool, env._.path, and env.FOO\nmkdir -p custom_bin\ncat >.mise.toml <<EOF\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\"]\nFOO = \"bar\"\nBAZ = \"qux\"\nEOF\n\nmise install\n\n# Save the original PATH for verification\nORIGINAL_PATH=\"$PATH\"\n\n# First activation\neval \"$(mise activate bash)\"\neval \"$(mise hook-env -s bash)\"\n\n# Verify env variables were set\nassert \"echo $FOO\" \"bar\"\nassert \"echo $BAZ\" \"qux\"\n\n# Get the mise tool path - it should be somewhere in PATH\nMISE_TOOL_PATH=$(echo \"$PATH\" | tr ':' '\\n' | grep \"/mise/installs/tiny\" | head -1)\nassert_contains \"echo $MISE_TOOL_PATH\" \"/mise/installs/tiny\"\n\n# custom_bin from env._.path should be in PATH\nassert_contains \"echo $PATH\" \"custom_bin\"\n\n# env._.path (custom_bin) should come BEFORE tool paths\n# (both are part of mise installs, so custom_bin is first in installs)\nPATH_BEFORE_ORIGINAL=\"${PATH%%:\"${ORIGINAL_PATH}\"*}\"\nassert_contains \"echo $PATH_BEFORE_ORIGINAL\" \"custom_bin\"\n\n# Tool path should come after custom_bin\nPATH_AFTER_CUSTOM=\"${PATH#*custom_bin:}\"\nassert_contains \"echo $PATH_AFTER_CUSTOM\" \"/mise/installs/tiny\"\n\n# Verify no duplicate paths\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l)\nassert \"echo $PATH_COUNT\" \"0\"\n\n# User adds path B\nexport PATH=\"/path_b:$PATH\"\n\n# User modifies FOO\nexport FOO=\"user_modified\"\n\n# Second activation - user path preserved at front, mise paths follow\neval \"$(mise activate bash)\"\neval \"$(mise hook-env -s bash)\"\n\n# FOO should be reset to \"bar\" by mise\nassert \"echo $FOO\" \"bar\"\n\n# BAZ should still be qux\nassert \"echo $BAZ\" \"qux\"\n\n# Verify PATH structure: /path_b (user addition) should be first, then mise paths, then original\nFIRST_PATH=$(echo \"$PATH\" | cut -d: -f1)\nassert_contains \"echo $FIRST_PATH\" \"/path_b\"\nassert_contains \"echo $PATH\" \"custom_bin\"\nassert_contains \"echo $PATH\" \"/mise/installs/tiny\"\n\n# /path_b should come BEFORE custom_bin (it's a user addition)\n# Extract everything before custom_bin appears in PATH\nPATH_PREFIX=\"${PATH%%custom_bin*}\"\nassert_contains \"echo $PATH_PREFIX\" \"/path_b\"\n\n# Check no duplicates\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l)\nassert \"echo $PATH_COUNT\" \"0\"\n\n# User adds path C\nexport PATH=\"/path_c:$PATH\"\n\n# Third activation - user paths preserved at front, mise paths follow\neval \"$(mise activate bash)\"\neval \"$(mise hook-env -s bash)\"\n\n# Verify user paths are first (C, B), then mise paths, then original\nFIRST_PATH=$(echo \"$PATH\" | cut -d: -f1)\nassert_contains \"echo $FIRST_PATH\" \"/path_c\"\nassert_contains \"echo $PATH\" \"/path_b\"\nassert_contains \"echo $PATH\" \"custom_bin\"\nassert_contains \"echo $PATH\" \"/mise/installs/tiny\"\n\n# /path_c and /path_b should come BEFORE custom_bin\n# Extract everything before custom_bin appears in PATH\nPATH_PREFIX=\"${PATH%%custom_bin*}\"\nassert_contains \"echo $PATH_PREFIX\" \"/path_c\"\nassert_contains \"echo $PATH_PREFIX\" \"/path_b\"\n\n# Check no duplicates\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l)\nassert \"echo $PATH_COUNT\" \"0\"\n\n# Test deactivation - unsets mise shell functions and variables\n# (Comprehensive deactivation tests are in test_deactivate)\neval \"$(command mise deactivate)\"\n"
  },
  {
    "path": "e2e/cli/test_activate_multiple_fish.fish",
    "content": "#!/usr/bin/env fish\n# shellcheck disable=SC1072,SC1065,SC1064,SC1073,SC2103\n\n# Test that calling mise activate multiple times preserves user-added paths at the front\n# while properly handling mise paths (env._.path and tool installs)\n#\n# Expected behavior:\n# - Start: A\n# - mise activate: env_path:mise_tools:A\n# - add B: B:env_path:mise_tools:A\n# - mise activate + hook-env: B:env_path:mise_tools:A (user path B preserved at front)\n# - add C: C:B:env_path:mise_tools:A\n# - mise activate + hook-env: C:B:env_path:mise_tools:A (user paths C,B preserved at front)\n# - deactivate: C:B:A (mise_tools and env_path removed, user paths preserved)\n\n# Create a mise config with a tool, env._.path, and env.FOO\nmkdir -p custom_bin\necho >.mise.toml '\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\"]\nFOO = \"bar\"\nBAZ = \"qux\"\n'\n\nmise install\nor exit 1\n\n# Save the original PATH for verification\nset -l ORIGINAL_PATH $PATH\n\n# First activation\nmise activate --status fish | source\n__mise_env_eval\n\n# Verify env variables were set\ntest \"$FOO\" = \"bar\"\nor begin; echo \"FOO should be bar, got: $FOO\"; exit 1; end\n\ntest \"$BAZ\" = \"qux\"\nor begin; echo \"BAZ should be qux, got: $BAZ\"; exit 1; end\n\n# Get the mise tool path - it should be somewhere in PATH\nset -l MISE_TOOL_PATH (string join \\n $PATH | grep \"/mise/installs/tiny\" | head -1)\nstring match -q \"*/mise/installs/tiny*\" $MISE_TOOL_PATH\nor begin; echo \"MISE_TOOL_PATH not found\"; exit 1; end\n\n# custom_bin from env._.path should be in PATH\nstring match -q \"*custom_bin*\" (string join : $PATH)\nor begin; echo \"custom_bin not in PATH\"; exit 1; end\n\n# Verify no duplicate paths\nset -l PATH_COUNT (string join \\n $PATH | sort | uniq -d | count)\ntest $PATH_COUNT -eq 0\nor begin; echo \"Duplicate paths found: $PATH_COUNT\"; exit 1; end\n\n# User adds path B\nset -x PATH /path_b $PATH\n\n# User modifies FOO\nset -x FOO \"user_modified\"\n\n# Second activation - user path preserved at front, mise paths follow\nmise activate --status fish | source\n__mise_env_eval\n\n# FOO should be reset to \"bar\" by mise\ntest \"$FOO\" = \"bar\"\nor begin; echo \"FOO should be bar after reactivation, got: $FOO\"; exit 1; end\n\n# BAZ should still be qux\ntest \"$BAZ\" = \"qux\"\nor begin; echo \"BAZ should be qux, got: $BAZ\"; exit 1; end\n\n# Verify PATH structure: /path_b (user addition) should be first\ntest \"$PATH[1]\" = \"/path_b\"\nor begin; echo \"First path should be /path_b, got: $PATH[1]\"; exit 1; end\n\nstring match -q \"*custom_bin*\" (string join : $PATH)\nor begin; echo \"custom_bin not in PATH\"; exit 1; end\n\nstring match -q \"*/mise/installs/tiny*\" (string join : $PATH)\nor begin; echo \"Tool path not in PATH\"; exit 1; end\n\n# Check no duplicates\nset -l PATH_COUNT (string join \\n $PATH | sort | uniq -d | count)\ntest $PATH_COUNT -eq 0\nor begin; echo \"Duplicate paths found: $PATH_COUNT\"; exit 1; end\n\n# User adds path C\nset -x PATH /path_c $PATH\n\n# Third activation - user paths preserved at front, mise paths follow\nmise activate --status fish | source\n__mise_env_eval\n\n# Verify user paths are first (C, B), then mise paths, then original\ntest \"$PATH[1]\" = \"/path_c\"\nor begin; echo \"First path should be /path_c, got: $PATH[1]\"; exit 1; end\n\nstring match -q \"*/path_b*\" (string join : $PATH)\nor begin; echo \"/path_b not in PATH\"; exit 1; end\n\nstring match -q \"*custom_bin*\" (string join : $PATH)\nor begin; echo \"custom_bin not in PATH\"; exit 1; end\n\nstring match -q \"*/mise/installs/tiny*\" (string join : $PATH)\nor begin; echo \"Tool path not in PATH\"; exit 1; end\n\n# Check no duplicates\nset -l PATH_COUNT (string join \\n $PATH | sort | uniq -d | count)\ntest $PATH_COUNT -eq 0\nor begin; echo \"Duplicate paths found: $PATH_COUNT\"; exit 1; end\n\n# Test deactivation - unsets mise shell functions and variables\n# (Comprehensive deactivation tests are in test_deactivate)\nmise deactivate\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_activate_multiple_xonsh",
    "content": "#!/usr/bin/env bash\nexec mise x uv -- uv tool run --with 'xonsh[full]' xonsh --no-rc \"$TEST_DIR/activate_multiple_xonsh.xsh\"\n"
  },
  {
    "path": "e2e/cli/test_activate_multiple_zsh",
    "content": "#!/usr/bin/env zsh\n# shellcheck disable=SC1071\nset -euo pipefail\n\n# Test that calling mise activate multiple times preserves user-added paths at the front\n# while properly handling mise paths (env._.path and tool installs)\n#\n# Expected behavior:\n# - Start: A\n# - mise activate: env_path:mise_tools:A\n# - add B: B:env_path:mise_tools:A\n# - mise activate + hook-env: B:env_path:mise_tools:A (user path B preserved at front)\n# - add C: C:B:env_path:mise_tools:A\n# - mise activate + hook-env: C:B:env_path:mise_tools:A (user paths C,B preserved at front)\n# - deactivate: C:B:A (mise_tools and env_path removed, user paths preserved)\n\n# Create a mise config with a tool, env._.path, and env.FOO\nmkdir -p custom_bin\ncat >.mise.toml <<EOF\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\"]\nFOO = \"bar\"\nBAZ = \"qux\"\nEOF\n\nmise install\n\n# Save the original PATH for verification\nORIGINAL_PATH=\"$PATH\"\n\n# First activation\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n# Verify env variables were set\n[[ $FOO == \"bar\" ]] || {\n\techo \"FOO should be bar, got: $FOO\"\n\texit 1\n}\n[[ $BAZ == \"qux\" ]] || {\n\techo \"BAZ should be qux, got: $BAZ\"\n\texit 1\n}\n\n# Get the mise tool path - it should be somewhere in PATH\nMISE_TOOL_PATH=$(echo \"$PATH\" | tr ':' '\\n' | grep \"/mise/installs/tiny\" | head -1)\n[[ $MISE_TOOL_PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"MISE_TOOL_PATH not found\"\n\texit 1\n}\n\n# custom_bin from env._.path should be in PATH\n[[ $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not in PATH\"\n\texit 1\n}\n\n# env._.path (custom_bin) should come BEFORE tool paths\n# (both are part of mise installs, so custom_bin is first in installs)\nPATH_BEFORE_ORIGINAL=\"${PATH%%:\"${ORIGINAL_PATH}\"*}\"\n[[ $PATH_BEFORE_ORIGINAL =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not before original PATH\"\n\texit 1\n}\n\n# Tool path should come after custom_bin\nPATH_AFTER_CUSTOM=\"${PATH#*custom_bin:}\"\n[[ $PATH_AFTER_CUSTOM =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path not after custom_bin\"\n\texit 1\n}\n\n# Verify no duplicate paths\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l | tr -d ' ')\n[[ $PATH_COUNT == \"0\" ]] || {\n\techo \"Duplicate paths found: $PATH_COUNT\"\n\texit 1\n}\n\n# User adds path B\nexport PATH=\"/path_b:$PATH\"\n\n# User modifies FOO\nexport FOO=\"user_modified\"\n\n# Second activation - user path preserved at front, mise paths follow\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n# FOO should be reset to \"bar\" by mise\n[[ $FOO == \"bar\" ]] || {\n\techo \"FOO should be bar after reactivation, got: $FOO\"\n\texit 1\n}\n\n# BAZ should still be qux\n[[ $BAZ == \"qux\" ]] || {\n\techo \"BAZ should be qux, got: $BAZ\"\n\texit 1\n}\n\n# Verify PATH structure: /path_b (user addition) should be first, then mise paths, then original\nFIRST_PATH=$(echo \"$PATH\" | cut -d: -f1)\n[[ $FIRST_PATH =~ \"/path_b\" ]] || {\n\techo \"First path should be /path_b, got: $FIRST_PATH\"\n\texit 1\n}\n[[ $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path not in PATH\"\n\texit 1\n}\n\n# /path_b should come BEFORE custom_bin (it's a user addition)\n# Extract everything before custom_bin appears in PATH\nPATH_PREFIX=\"${PATH%%custom_bin*}\"\n[[ $PATH_PREFIX =~ \"/path_b\" ]] || {\n\techo \"/path_b not before custom_bin\"\n\texit 1\n}\n\n# Check no duplicates\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l | tr -d ' ')\n[[ $PATH_COUNT == \"0\" ]] || {\n\techo \"Duplicate paths found: $PATH_COUNT\"\n\texit 1\n}\n\n# User adds path C\nexport PATH=\"/path_c:$PATH\"\n\n# Third activation - user paths preserved at front, mise paths follow\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n# Verify user paths are first (C, B), then mise paths, then original\nFIRST_PATH=$(echo \"$PATH\" | cut -d: -f1)\n[[ $FIRST_PATH =~ \"/path_c\" ]] || {\n\techo \"First path should be /path_c, got: $FIRST_PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/path_b\" ]] || {\n\techo \"/path_b not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path not in PATH\"\n\texit 1\n}\n\n# /path_c and /path_b should come BEFORE custom_bin\n# Extract everything before custom_bin appears in PATH\nPATH_PREFIX=\"${PATH%%custom_bin*}\"\n[[ $PATH_PREFIX =~ \"/path_c\" ]] || {\n\techo \"/path_c not before custom_bin\"\n\texit 1\n}\n[[ $PATH_PREFIX =~ \"/path_b\" ]] || {\n\techo \"/path_b not before custom_bin\"\n\texit 1\n}\n\n# Check no duplicates\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | sort | uniq -d | wc -l | tr -d ' ')\n[[ $PATH_COUNT == \"0\" ]] || {\n\techo \"Duplicate paths found: $PATH_COUNT\"\n\texit 1\n}\n\n# Test deactivation - unsets mise shell functions and variables\n# (Comprehensive deactivation tests are in test_deactivate)\nmise deactivate\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_activate_path_safety",
    "content": "#!/usr/bin/env bash\n\neval \"$(mise activate bash)\" && eval \"$(mise hook-env)\"\ninstall -m 0755 /dev/null \"$TMPDIR/MISE_PATH_SAFETY_CHECK\"\nassert_fail \"cd '$TMPDIR' && command -v MISE_PATH_SAFETY_CHECK\"\n"
  },
  {
    "path": "e2e/cli/test_alias",
    "content": "#!/usr/bin/env bash\n\nassert \"mise alias set tiny xxx 2\"\nassert_contains \"mise alias ls tiny\" \"tiny  xxx 2\"\nassert \"mise alias unset tiny xxx\"\nassert_not_contains \"mise alias ls\" \"tiny  xxx\"\n\nassert \"mise alias set nushell aqua:nushell/nushell\"\nassert \"mise x nushell -- nu --version\"\n"
  },
  {
    "path": "e2e/cli/test_backends",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise backends\" \"cargo\"\n"
  },
  {
    "path": "e2e/cli/test_bin_paths",
    "content": "#!/usr/bin/env bash\n\nmise use dummy@latest tiny@latest\nassert \"mise bin-paths dummy\" \"$MISE_DATA_DIR/installs/dummy/2.0.0/bin\"\nassert \"mise bin-paths tiny\" \"$MISE_DATA_DIR/installs/tiny/3.1.0/bin\"\nassert \"mise bin-paths\" \"$MISE_DATA_DIR/installs/dummy/2.0.0/bin\n$MISE_DATA_DIR/installs/tiny/3.1.0/bin\"\n"
  },
  {
    "path": "e2e/cli/test_cache_clear",
    "content": "#!/usr/bin/env bash\n\n# Test cache clear with simple plugin name\nmkdir -p \"$MISE_CACHE_DIR/tiny\"\necho \"test\" >\"$MISE_CACHE_DIR/tiny/data\"\nassert_directory_exists \"$MISE_CACHE_DIR/tiny\"\nassert \"mise cache clear tiny\"\nassert_directory_not_exists \"$MISE_CACHE_DIR/tiny\"\n\n# Test cache clear with github:owner/repo style name\n# The cache dir uses kebab-case: github:owner/repo -> github-owner-repo\nmkdir -p \"$MISE_CACHE_DIR/github-test-repo\"\necho \"test\" >\"$MISE_CACHE_DIR/github-test-repo/data\"\nassert_directory_exists \"$MISE_CACHE_DIR/github-test-repo\"\nassert \"mise cache clear github:test/repo\"\nassert_directory_not_exists \"$MISE_CACHE_DIR/github-test-repo\"\n\n# Test cache clear all\nmkdir -p \"$MISE_CACHE_DIR/foo\"\necho \"test\" >\"$MISE_CACHE_DIR/foo/data\"\nassert_directory_exists \"$MISE_CACHE_DIR/foo\"\nassert \"mise cache clear\"\nassert_directory_not_exists \"$MISE_CACHE_DIR/foo\"\n"
  },
  {
    "path": "e2e/cli/test_cache_path",
    "content": "#!/usr/bin/env bash\n\n# Test cache path command and its alias\n\n# Test `mise cache` shows cache directory\nassert_contains \"mise cache\" \"$MISE_CACHE_DIR\"\n\n# Test `mise cache path` shows cache directory\nassert_contains \"mise cache path\" \"$MISE_CACHE_DIR\"\n\n# Test `mise cache dir` alias shows cache directory\nassert_contains \"mise cache dir\" \"$MISE_CACHE_DIR\"\n\n# Test with custom cache directory\nexport MISE_CACHE_DIR=/tmp/test-mise-cache\nassert_contains \"mise cache path\" \"/tmp/test-mise-cache\"\nassert_contains \"mise cache dir\" \"/tmp/test-mise-cache\"\n"
  },
  {
    "path": "e2e/cli/test_cd_nonexistent",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Test that mise shows a friendly error when --cd is set to a non-existent path\n# This validates that the error message is clear and helpful to users\n\necho \"Testing --cd with non-existent directory...\"\n\n# Test 1: --cd with non-existent absolute path\necho \"Test 1: --cd with non-existent absolute path\"\nassert_fail \"mise --cd /nonexistent/path/that/does/not/exist config ls\" \\\n\t\"Directory specified with --cd does not exist\"\n\n# Test 2: --cd with non-existent relative path\necho \"Test 2: --cd with non-existent relative path\"\nassert_fail \"mise --cd ./nonexistent config ls\" \\\n\t\"Directory specified with --cd does not exist\"\n\n# Test 3: --cd with a file instead of a directory\necho \"Test 3: --cd with a file (not a directory)\"\ntouch test_file\nassert_fail \"mise --cd test_file config ls\" \\\n\t\"Path specified with --cd is not a directory\"\nrm -f test_file\n\n# Test 4: --cd with existing directory should work\necho \"Test 4: --cd with existing directory (should succeed)\"\nmkdir -p test_dir\ncat <<EOF >test_dir/mise.toml\n[env]\nTEST_VAR = \"hello\"\nEOF\nassert_contains \"mise --cd $PWD/test_dir config ls\" \"test_dir/mise.toml\"\nrm -rf test_dir\n\n# Test 5: Verify error message format and helpfulness\necho \"Test 5: Verify error message contains helpful guidance\"\noutput=$(mise --cd /does/not/exist config ls 2>&1) || true\nif [[ $output == *\"Please check the path and try again\"* ]]; then\n\tok \"Error message includes helpful guidance\"\nelif [[ $output == *\"Directory specified with --cd does not exist\"* ]]; then\n\tok \"Error message shows the required info\"\nelse\n\tfail \"Error message missing expected text: ${output:0:200}...\"\nfi\n\n# Test 6: Test with run command and non-existent --cd path\necho \"Test 6: --cd with run command and non-existent path\"\nassert_fail \"mise run --cd /nonexistent/path hello\" \\\n\t\"Directory specified with --cd does not exist\"\n\n# Test 7: Test with other commands and non-existent --cd path\necho \"Test 7: --cd with various commands and non-existent path\"\nassert_fail \"mise --cd /nonexistent ls\" \\\n\t\"Directory specified with --cd does not exist\"\n\necho \"\"\necho \"All --cd non-existent directory tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_chdir",
    "content": "#!/usr/bin/env bash\n\nmkdir -p ./test\ncat <<EOF >./test/mise.toml\n[tasks.hello]\nrun = 'echo \"Hello, World!\"'\nEOF\n\nassert_contains \"mise config --cd $PWD/test ls\" \"test/mise.toml\"\n\nassert_contains \"mise run --cd $PWD/test hello\" \"Hello, World!\"\nassert_contains \"mise run --cd ./test hello\" \"Hello, World!\"\nassert_contains \"mise run --cd test hello\" \"Hello, World!\"\n"
  },
  {
    "path": "e2e/cli/test_config_dir_override",
    "content": "#!/usr/bin/env bash\n# Test that MISE_CONFIG_DIR properly overrides the default config location\n# When MISE_CONFIG_DIR is set to a custom location, configs from the default\n# location (~/.config/mise) should NOT be loaded during directory traversal.\n# See: https://github.com/jdx/mise/discussions/7015\n\n# Create a custom config directory\nCUSTOM_CONFIG_DIR=\"$HOME/.mise-custom\"\nmkdir -p \"$CUSTOM_CONFIG_DIR\"\n\n# Create config in the custom location\ncat >\"$CUSTOM_CONFIG_DIR/config.toml\" <<'EOF'\n[tools]\ndummy = \"1.0.0\"\nEOF\n\n# Create config in the DEFAULT location (~/.config/mise) which should be ignored\n# when MISE_CONFIG_DIR is overridden\nmkdir -p \"$HOME/.config/mise\"\ncat >\"$HOME/.config/mise/config.toml\" <<'EOF'\n[tools]\ndummy = \"2.0.0\"\nEOF\n\n# Set MISE_CONFIG_DIR to custom location and verify only custom config is loaded\nexport MISE_CONFIG_DIR=\"$CUSTOM_CONFIG_DIR\"\n\n# The config list should show ONLY the custom config, not the default location\n# Note: mise uses ~ shorthand in output, so check for that\nassert_contains \"mise config ls\" \".mise-custom/config.toml\"\n\n# Should NOT contain the default config location\nassert_not_contains \"mise config ls\" \".config/mise/config.toml\"\n\n# Verify the correct tool version is used (1.0.0 from custom, not 2.0.0 from default)\nmise install\nassert_contains \"mise x -- dummy\" \"1.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_config_ls",
    "content": "#!/usr/bin/env bash\n\nassert \"mise set FOO=bar\"\nassert \"mise env\"\nassert \"mise cfg --tracked-configs\" \"$PWD/mise.toml\"\n"
  },
  {
    "path": "e2e/cli/test_config_set",
    "content": "#!/usr/bin/env bash\n\necho '[tools.node]\nversion = \"latest\"' >mise.toml\n\nassert \"cat mise.toml\" '[tools.node]\nversion = \"latest\"'\n\nmise config set tools.node.postinstall 'corepack enable'\nassert \"mise config get tools.node.postinstall\" \"corepack enable\"\nassert \"mise config get tools.node.version\" \"latest\"\nmise config set env._.python.venv.path '.venv'\nassert \"mise config get env._.python.venv.path\" \".venv\"\nmise config set env._.python.venv.create true\nassert \"mise config get env._.python.venv.create\" \"true\"\n\n# test \"config set key=value\" format\nmise config set env._.python.venv.path=.venv2\nassert \"mise config get env._.python.venv.path\" \".venv2\"\n\n# test \"config set\" with no value and no = fails\nassert_fail \"mise config set tools.node\"\n"
  },
  {
    "path": "e2e/cli/test_current",
    "content": "#!/usr/bin/env bash\n\nmise i dummy@3 tiny@2\nmise use dummy@3\n\nassert \"mise current\" \"dummy 3\"\nassert \"mise current dummy\" \"3\"\nassert \"mise current tiny\" \"\"\n"
  },
  {
    "path": "e2e/cli/test_deactivate",
    "content": "#!/usr/bin/env bash\n\n# Test that mise deactivate properly removes mise-managed environment\n# while preserving user-added paths and variables\n\n# Create a mise config with tools, env._.path, and env vars\nmkdir -p custom_bin shared_entry user_bin\nSHARED_PATH=\"$PWD/shared_entry\"\ncat >.mise.toml <<EOF\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\", \"./shared_entry\"]\nFOO = \"mise_foo\"\nBAR = \"mise_bar\"\nEOF\n\nmise install\n\n# Save the original PATH and environment\nORIGINAL_PATH=\"$PATH\"\n\n# Activate mise and run hook-env\neval \"$(mise activate bash)\"\neval \"$(mise hook-env -s bash)\"\n\n# Verify mise environment is set up\nassert \"echo $FOO\" \"mise_foo\"\nassert \"echo $BAR\" \"mise_bar\"\nassert_contains \"echo $PATH\" \"custom_bin\"\nassert_contains \"echo $PATH\" \"/mise/installs/tiny\"\nassert_contains \"echo $PATH\" \"$SHARED_PATH\"\n\n# User manually adds paths after activation\nexport PATH=\"$SHARED_PATH:$PATH\"\nexport PATH=\"/user_path_1:$PATH\"\nexport PATH=\"/user_path_2:$PATH\"\n# Add SHARED_PATH again after mise so PATH now has it before, within, and after\nexport PATH=\"$PATH:$SHARED_PATH\"\n\n# User sets their own environment variables\nexport USER_VAR=\"user_value\"\nexport USER_PATH=\"/usr/local/myapp\"\n\n# Verify everything is in place before deactivation\nassert \"echo $FOO\" \"mise_foo\"\nassert \"echo $USER_VAR\" \"user_value\"\nassert_contains \"echo $PATH\" \"/user_path_1\"\nassert_contains \"echo $PATH\" \"/user_path_2\"\nassert_contains \"echo $PATH\" \"custom_bin\"\nassert_contains \"echo $PATH\" \"/mise/installs/tiny\"\nassert_contains \"echo $PATH\" \"$SHARED_PATH\"\n\n# SHARED_PATH should appear three times (before, inside, and after mise entries)\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\nassert \"echo $SHARED_COUNT\" \"3\"\n\n# Deactivate mise\n# Note: Use 'command' to bypass the shell function and call the binary directly\neval \"$(command mise deactivate)\"\n\n# After deactivation:\n\n# 1. Mise-managed environment variables should be removed\nassert \"echo ${FOO:-unset}\" \"unset\"\nassert \"echo ${BAR:-unset}\" \"unset\"\n\n# 2. User's own environment variables should be preserved\nassert \"echo $USER_VAR\" \"user_value\"\nassert \"echo $USER_PATH\" \"/usr/local/myapp\"\n\n# 3. Mise-managed paths should be removed from PATH\nassert_not_contains \"echo $PATH\" \"/mise/installs/tiny\"\nassert_not_contains \"echo $PATH\" \"custom_bin\"\n\n# Shared path should now appear exactly twice (before and after mise)\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\nassert \"echo $SHARED_COUNT\" \"2\"\n\n# 4. User-added paths should be preserved\nassert_contains \"echo $PATH\" \"/user_path_1\"\nassert_contains \"echo $PATH\" \"/user_path_2\"\n\n# 5. Original PATH components should still be present\nassert_contains \"echo $PATH\" \"${ORIGINAL_PATH%%:*}\"\n\n# 6. No duplicate paths other than SHARED_PATH\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fvx \"$SHARED_PATH\" | sort | uniq -d | wc -l)\nassert \"echo $PATH_COUNT\" \"0\"\n\n# 7. Mise shell integration should be removed\n# The mise function should no longer exist\nif type mise 2>/dev/null | grep -q \"function\"; then\n\techo \"ERROR: mise function still exists after deactivate\"\n\texit 1\nfi\n\n# 8. Test edge case: deactivating when not activated should be safe\neval \"$(command mise deactivate)\"\nassert \"echo deactivate_twice\" \"deactivate_twice\"\n\n# 9. Test reactivation after deactivation\neval \"$(mise activate bash)\"\neval \"$(mise hook-env -s bash)\"\n\n# After reactivation, mise env vars should be back\nassert \"echo $FOO\" \"mise_foo\"\nassert \"echo $BAR\" \"mise_bar\"\n\n# User additions should still be preserved\nassert_contains \"echo $PATH\" \"/user_path_1\"\nassert_contains \"echo $PATH\" \"/user_path_2\"\nassert_contains \"echo $PATH\" \"$SHARED_PATH\"\n\n# After reactivation, shared_entry appears 3 times:\n# - Once from env._.path config (mise adds it to maintain user's intended ordering)\n# - Twice from user manual additions (lines 36 and 40, preserved in PATH)\n# This is correct behavior: user-configured paths are always added even if they\n# exist elsewhere in PATH, to ensure the user's intended precedence is maintained.\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\nassert \"echo $SHARED_COUNT\" \"3\"\n\n# And user vars should still be there\nassert \"echo $USER_VAR\" \"user_value\"\n\n# 10. Test deactivation with modified env vars\n# If user modifies a mise-managed variable, deactivation should still remove it\nexport FOO=\"user_modified_foo\"\neval \"$(command mise deactivate)\"\n\n# FOO should be removed entirely by deactivation (mise doesn't track user modifications)\nassert \"echo ${FOO:-unset}\" \"unset\"\n"
  },
  {
    "path": "e2e/cli/test_deactivate_fish.fish",
    "content": "#!/usr/bin/env fish\n# shellcheck disable=SC1072,SC1065,SC1064,SC1073,SC2103\n\n# Test that mise deactivate properly removes mise-managed environment\n# while preserving user-added paths and variables\n\n# Create a mise config with tools, env._.path, and env vars\nmkdir -p custom_bin shared_entry user_bin\nset -l SHARED_PATH \"$PWD/shared_entry\"\necho >.mise.toml '\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\", \"./shared_entry\"]\nFOO = \"mise_foo\"\nBAR = \"mise_bar\"\n'\n\nmise install\nor exit 1\n\n# Save the original PATH and environment\nset -l ORIGINAL_PATH $PATH\n\n# Activate mise and run hook-env\nmise activate --status fish | source\n__mise_env_eval\n\n# Verify mise environment is set up\ntest \"$FOO\" = \"mise_foo\"\nor begin; echo \"FOO should be mise_foo, got: $FOO\"; exit 1; end\n\ntest \"$BAR\" = \"mise_bar\"\nor begin; echo \"BAR should be mise_bar, got: $BAR\"; exit 1; end\n\nstring match -q \"*custom_bin*\" (string join : $PATH)\nor begin; echo \"custom_bin not in PATH\"; exit 1; end\n\nstring match -q \"*/mise/installs/tiny*\" (string join : $PATH)\nor begin; echo \"Tool path not in PATH\"; exit 1; end\n\nstring match -q \"*$SHARED_PATH*\" (string join : $PATH)\nor begin; echo \"SHARED_PATH not in PATH\"; exit 1; end\n\n# User manually adds paths after activation\nset -x PATH $SHARED_PATH $PATH\nset -x PATH /user_path_1 $PATH\nset -x PATH /user_path_2 $PATH\n# Add SHARED_PATH again after mise so PATH now has it before, within, and after\nset -x PATH $PATH $SHARED_PATH\n\n# User sets their own environment variables\nset -x USER_VAR \"user_value\"\nset -x USER_PATH \"/usr/local/myapp\"\n\n# Verify everything is in place before deactivation\ntest \"$FOO\" = \"mise_foo\"\nor begin; echo \"FOO should be mise_foo, got: $FOO\"; exit 1; end\n\ntest \"$USER_VAR\" = \"user_value\"\nor begin; echo \"USER_VAR should be user_value, got: $USER_VAR\"; exit 1; end\n\nstring match -q \"*/user_path_1*\" (string join : $PATH)\nor begin; echo \"/user_path_1 not in PATH\"; exit 1; end\n\nstring match -q \"*/user_path_2*\" (string join : $PATH)\nor begin; echo \"/user_path_2 not in PATH\"; exit 1; end\n\nstring match -q \"*custom_bin*\" (string join : $PATH)\nor begin; echo \"custom_bin not in PATH\"; exit 1; end\n\nstring match -q \"*/mise/installs/tiny*\" (string join : $PATH)\nor begin; echo \"Tool path not in PATH\"; exit 1; end\n\nstring match -q \"*$SHARED_PATH*\" (string join : $PATH)\nor begin; echo \"SHARED_PATH not in PATH\"; exit 1; end\n\n# SHARED_PATH should appear three times (before, inside, and after mise entries)\nset -l SHARED_COUNT (string join \\n $PATH | grep -Fxc \"$SHARED_PATH\")\ntest $SHARED_COUNT -eq 3\nor begin; echo \"SHARED_PATH should appear 3 times, got: $SHARED_COUNT\"; exit 1; end\n\n# Deactivate mise\nmise deactivate\n\n# After deactivation:\n\n# 1. Mise-managed environment variables should be removed\nset -q FOO\nand begin; echo \"FOO should be unset, got: $FOO\"; exit 1; end\n\nset -q BAR\nand begin; echo \"BAR should be unset, got: $BAR\"; exit 1; end\n\n# 2. User's own environment variables should be preserved\ntest \"$USER_VAR\" = \"user_value\"\nor begin; echo \"USER_VAR should be user_value, got: $USER_VAR\"; exit 1; end\n\ntest \"$USER_PATH\" = \"/usr/local/myapp\"\nor begin; echo \"USER_PATH should be /usr/local/myapp, got: $USER_PATH\"; exit 1; end\n\n# 3. Mise-managed paths should be removed from PATH\nif string match -q \"*/mise/installs/tiny*\" (string join : $PATH)\n    echo \"Tool path should not be in PATH after deactivation\"\n    exit 1\nend\n\nif string match -q \"*custom_bin*\" (string join : $PATH)\n    echo \"custom_bin should not be in PATH after deactivation\"\n    exit 1\nend\n\n# Shared path should now appear exactly twice (before and after mise)\nset -l SHARED_COUNT (string join \\n $PATH | grep -Fxc \"$SHARED_PATH\")\ntest $SHARED_COUNT -eq 2\nor begin; echo \"SHARED_PATH should appear 2 times after deactivation, got: $SHARED_COUNT\"; exit 1; end\n\n# 4. User-added paths should be preserved\nstring match -q \"*/user_path_1*\" (string join : $PATH)\nor begin; echo \"/user_path_1 should be preserved\"; exit 1; end\n\nstring match -q \"*/user_path_2*\" (string join : $PATH)\nor begin; echo \"/user_path_2 should be preserved\"; exit 1; end\n\n# 5. Original PATH components should still be present\nstring match -q \"*$ORIGINAL_PATH[1]*\" (string join : $PATH)\nor begin; echo \"Original PATH components should be preserved\"; exit 1; end\n\n# 6. No duplicate paths other than SHARED_PATH\nset -l PATH_COUNT (string join \\n $PATH | grep -Fvx \"$SHARED_PATH\" | sort | uniq -d | count)\ntest $PATH_COUNT -eq 0\nor begin; echo \"No duplicate paths expected other than SHARED_PATH, got: $PATH_COUNT\"; exit 1; end\n\n# 7. Mise shell integration should be removed\n# The mise function should no longer exist\nif type -q __mise_env_eval\n    echo \"ERROR: __mise_env_eval function still exists after deactivate\"\n    exit 1\nend\n\n# 8. Test edge case: deactivating when not activated should be safe\nmise deactivate\necho \"deactivate_twice works\"\n\n# 9. Test reactivation after deactivation\nmise activate --status fish | source\n__mise_env_eval\n\n# After reactivation, mise env vars should be back\ntest \"$FOO\" = \"mise_foo\"\nor begin; echo \"FOO should be mise_foo after reactivation, got: $FOO\"; exit 1; end\n\ntest \"$BAR\" = \"mise_bar\"\nor begin; echo \"BAR should be mise_bar after reactivation, got: $BAR\"; exit 1; end\n\n# User additions should still be preserved\nstring match -q \"*/user_path_1*\" (string join : $PATH)\nor begin; echo \"/user_path_1 should be preserved\"; exit 1; end\n\nstring match -q \"*/user_path_2*\" (string join : $PATH)\nor begin; echo \"/user_path_2 should be preserved\"; exit 1; end\n\nstring match -q \"*$SHARED_PATH*\" (string join : $PATH)\nor begin; echo \"SHARED_PATH should be preserved\"; exit 1; end\n\n# After reactivation, shared_entry appears 3 times:\n# - Once from env._.path config (mise adds it to maintain user's intended ordering)\n# - Twice from user manual additions (preserved in PATH)\n# This is correct behavior: user-configured paths are always added even if they\n# exist elsewhere in PATH, to ensure the user's intended precedence is maintained.\nset -l SHARED_COUNT (string join \\n $PATH | grep -Fxc \"$SHARED_PATH\")\ntest $SHARED_COUNT -eq 3\nor begin; echo \"SHARED_PATH should appear 3 times after reactivation, got: $SHARED_COUNT\"; exit 1; end\n\n# And user vars should still be there\ntest \"$USER_VAR\" = \"user_value\"\nor begin; echo \"USER_VAR should be user_value, got: $USER_VAR\"; exit 1; end\n\n# 10. Test deactivation with modified env vars\n# If user modifies a mise-managed variable, deactivation should still remove it\nset -x FOO \"user_modified_foo\"\nmise deactivate\n\n# FOO should be removed entirely by deactivation (mise doesn't track user modifications)\nset -q FOO\nand begin; echo \"FOO should be unset after deactivation, got: $FOO\"; exit 1; end\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_deactivate_xonsh",
    "content": "#!/usr/bin/env bash\nexec mise x uv -- uv tool run --with 'xonsh[full]' xonsh --no-rc \"$TEST_DIR/deactivate_xonsh.xsh\"\n"
  },
  {
    "path": "e2e/cli/test_deactivate_zsh",
    "content": "#!/usr/bin/env zsh\n# shellcheck disable=SC1071\nset -euo pipefail\n\n# Test that mise deactivate properly removes mise-managed environment\n# while preserving user-added paths and variables\n\n# Create a mise config with tools, env._.path, and env vars\nmkdir -p custom_bin shared_entry user_bin\nSHARED_PATH=\"$PWD/shared_entry\"\ncat >.mise.toml <<EOF\n[tools]\ntiny = \"latest\"\n\n[env]\n_.path = [\"./custom_bin\", \"./shared_entry\"]\nFOO = \"mise_foo\"\nBAR = \"mise_bar\"\nEOF\n\nmise install\n\n# Save the original PATH and environment\nORIGINAL_PATH=\"$PATH\"\n\n# Activate mise and run hook-env\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n# Verify mise environment is set up\n[[ $FOO == \"mise_foo\" ]] || {\n\techo \"FOO should be mise_foo, got: $FOO\"\n\texit 1\n}\n[[ $BAR == \"mise_bar\" ]] || {\n\techo \"BAR should be mise_bar, got: $BAR\"\n\texit 1\n}\n[[ $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path not in PATH\"\n\texit 1\n}\n[[ $PATH =~ $SHARED_PATH ]] || {\n\techo \"SHARED_PATH not in PATH\"\n\texit 1\n}\n\n# User manually adds paths after activation\nexport PATH=\"$SHARED_PATH:$PATH\"\nexport PATH=\"/user_path_1:$PATH\"\nexport PATH=\"/user_path_2:$PATH\"\n# Add SHARED_PATH again after mise so PATH now has it before, within, and after\nexport PATH=\"$PATH:$SHARED_PATH\"\n\n# User sets their own environment variables\nexport USER_VAR=\"user_value\"\nexport USER_PATH=\"/usr/local/myapp\"\n\n# Verify everything is in place before deactivation\n[[ $FOO == \"mise_foo\" ]] || {\n\techo \"FOO should be mise_foo, got: $FOO\"\n\texit 1\n}\n[[ $USER_VAR == \"user_value\" ]] || {\n\techo \"USER_VAR should be user_value, got: $USER_VAR\"\n\texit 1\n}\n[[ $PATH =~ \"/user_path_1\" ]] || {\n\techo \"/user_path_1 not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/user_path_2\" ]] || {\n\techo \"/user_path_2 not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin not in PATH\"\n\texit 1\n}\n[[ $PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path not in PATH\"\n\texit 1\n}\n[[ $PATH =~ $SHARED_PATH ]] || {\n\techo \"SHARED_PATH not in PATH\"\n\texit 1\n}\n\n# SHARED_PATH should appear three times (before, inside, and after mise entries)\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\n[[ $SHARED_COUNT == \"3\" ]] || {\n\techo \"SHARED_PATH should appear 3 times, got: $SHARED_COUNT\"\n\texit 1\n}\n\n# Deactivate mise\neval \"$(command mise deactivate)\"\n\n# After deactivation:\n\n# 1. Mise-managed environment variables should be removed\n[[ ${FOO:-unset} == \"unset\" ]] || {\n\techo \"FOO should be unset, got: $FOO\"\n\texit 1\n}\n[[ ${BAR:-unset} == \"unset\" ]] || {\n\techo \"BAR should be unset, got: $BAR\"\n\texit 1\n}\n\n# 2. User's own environment variables should be preserved\n[[ $USER_VAR == \"user_value\" ]] || {\n\techo \"USER_VAR should be user_value, got: $USER_VAR\"\n\texit 1\n}\n[[ $USER_PATH == \"/usr/local/myapp\" ]] || {\n\techo \"USER_PATH should be /usr/local/myapp, got: $USER_PATH\"\n\texit 1\n}\n\n# 3. Mise-managed paths should be removed from PATH\n[[ ! $PATH =~ \"/mise/installs/tiny\" ]] || {\n\techo \"Tool path should not be in PATH after deactivation\"\n\texit 1\n}\n[[ ! $PATH =~ \"custom_bin\" ]] || {\n\techo \"custom_bin should not be in PATH after deactivation\"\n\texit 1\n}\n\n# Shared path should now appear exactly twice (before and after mise)\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\n[[ $SHARED_COUNT == \"2\" ]] || {\n\techo \"SHARED_PATH should appear 2 times after deactivation, got: $SHARED_COUNT\"\n\texit 1\n}\n\n# 4. User-added paths should be preserved\n[[ $PATH =~ \"/user_path_1\" ]] || {\n\techo \"/user_path_1 should be preserved\"\n\texit 1\n}\n[[ $PATH =~ \"/user_path_2\" ]] || {\n\techo \"/user_path_2 should be preserved\"\n\texit 1\n}\n\n# 5. Original PATH components should still be present\n[[ $PATH =~ ${ORIGINAL_PATH%%:*} ]] || {\n\techo \"Original PATH components should be preserved\"\n\texit 1\n}\n\n# 6. No duplicate paths other than SHARED_PATH\nPATH_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fvx \"$SHARED_PATH\" | sort | uniq -d | wc -l | tr -d ' ')\n[[ $PATH_COUNT == \"0\" ]] || {\n\techo \"No duplicate paths expected other than SHARED_PATH, got: $PATH_COUNT\"\n\texit 1\n}\n\n# 7. Mise shell integration should be removed\n# The mise function should no longer exist\nif type mise 2>/dev/null | grep -q \"function\"; then\n\techo \"ERROR: mise function still exists after deactivate\"\n\texit 1\nfi\n\n# 8. Test edge case: deactivating when not activated should be safe\neval \"$(command mise deactivate)\"\necho \"deactivate_twice works\"\n\n# 9. Test reactivation after deactivation\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n# After reactivation, mise env vars should be back\n[[ $FOO == \"mise_foo\" ]] || {\n\techo \"FOO should be mise_foo after reactivation, got: $FOO\"\n\texit 1\n}\n[[ $BAR == \"mise_bar\" ]] || {\n\techo \"BAR should be mise_bar after reactivation, got: $BAR\"\n\texit 1\n}\n\n# User additions should still be preserved\n[[ $PATH =~ \"/user_path_1\" ]] || {\n\techo \"/user_path_1 should be preserved\"\n\texit 1\n}\n[[ $PATH =~ \"/user_path_2\" ]] || {\n\techo \"/user_path_2 should be preserved\"\n\texit 1\n}\n[[ $PATH =~ $SHARED_PATH ]] || {\n\techo \"SHARED_PATH should be preserved\"\n\texit 1\n}\n\n# After reactivation, shared_entry appears 3 times:\n# - Once from env._.path config (mise adds it to maintain user's intended ordering)\n# - Twice from user manual additions (preserved in PATH)\n# This is correct behavior: user-configured paths are always added even if they\n# exist elsewhere in PATH, to ensure the user's intended precedence is maintained.\nSHARED_COUNT=$(echo \"$PATH\" | tr ':' '\\n' | grep -Fxc \"$SHARED_PATH\")\n[[ $SHARED_COUNT == \"3\" ]] || {\n\techo \"SHARED_PATH should appear 3 times after reactivation, got: $SHARED_COUNT\"\n\texit 1\n}\n\n# And user vars should still be there\n[[ $USER_VAR == \"user_value\" ]] || {\n\techo \"USER_VAR should be user_value, got: $USER_VAR\"\n\texit 1\n}\n\n# 10. Test deactivation with modified env vars\n# If user modifies a mise-managed variable, deactivation should still remove it\nexport FOO=\"user_modified_foo\"\neval \"$(command mise deactivate)\"\n\n# FOO should be removed entirely by deactivation (mise doesn't track user modifications)\n[[ ${FOO:-unset} == \"unset\" ]] || {\n\techo \"FOO should be unset after deactivation, got: $FOO\"\n\texit 1\n}\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_did_you_mean",
    "content": "#!/usr/bin/env bash\n# Test \"Did you mean?\" suggestions for unknown tools\n\nset -euo pipefail\nexport RUST_BACKTRACE=0\nexport MISE_FRIENDLY_ERROR=1\n\n# Test: Typo of a known mise registry tool should suggest the correct name\nassert_fail \"mise use nod\" \"Did you mean?\"\nassert_fail \"mise use nod\" \"node\"\n\n# Test: Typo of python should suggest python\nassert_fail \"mise use pythn\" \"python\"\n\n# Test: Completely unrelated name should not show suggestions\nassert_fail \"mise use somethingnonexistent\" \"not found in mise tool registry\"\n"
  },
  {
    "path": "e2e/cli/test_doctor",
    "content": "#!/usr/bin/env bash\n\nmise use dummy@latest\n\neval \"$(mise activate bash)\" && _mise_hook\nassert \"PATH=\"\" $(which mise) doctor --json\"\n\n# Test PATH ordering warning when non-mise paths precede mise tool paths\nassert_not_contains \"mise doctor\" \"mise tool paths are not first in PATH\"\nexport PATH=\"/tmp/fake-system-bin:$PATH\"\nassert_contains \"mise doctor\" \"mise tool paths are not first in PATH\"\nassert_contains \"mise doctor\" \"/tmp/fake-system-bin\"\n# Restore PATH for remaining tests\nexport PATH=\"${PATH#/tmp/fake-system-bin:}\"\n\nmise p add uv\nmise use uv\nassert_contains \"mise doctor\" \"asdf:uv@\"\nassert_contains \"mise doctor\" \"self_update_available\"\nassert_contains \"mise doctor -J\" \"dummy\"\nassert_contains \"mise doctor -J\" \"self_update_available\"\nassert_contains \"mise doctor -J\" \"aqua\"\nassert_contains \"mise doctor\" \"aqua\"\n"
  },
  {
    "path": "e2e/cli/test_en_mise_env",
    "content": "#!/usr/bin/env bash\n\n# Test that MISE_ENV is properly propagated when using 'mise -E <env> en'\n# This tests the fix for: https://github.com/jdx/mise/discussions/6928\n\n# Create base config\ncat >mise.toml <<EOF\n[env]\nTTT_BASE_VAR = \"base_value\"\nEOF\n\n# Create dev-specific config\ncat >mise.dev.toml <<EOF\n[env]\nTTT_ENV_NAME = \"dev\"\nTTT_BASE_VAR = \"dev_value\"\nEOF\n\n# Create staging-specific config\ncat >mise.staging.toml <<EOF\n[env]\nTTT_ENV_NAME = \"staging\"\nTTT_BASE_VAR = \"staging_value\"\nEOF\n\n# Test 1: Verify MISE_ENV is set in spawned shell\nassert_contains \"mise -E dev en -s 'bash -c \\\"echo \\$MISE_ENV\\\"'\" \"dev\"\n\n# Test 2: Verify mise config can find dev-specific config files in spawned shell\nassert_contains \"mise -E dev en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.dev.toml\"\n\n# Test 3: Verify environment variables from dev config are available\nassert_contains \"mise -E dev en -s 'bash -c \\\"mise env | grep TTT_ENV_NAME\\\"'\" \"TTT_ENV_NAME=dev\"\n\n# Test 4: Verify base variable is overridden by dev config\nassert_contains \"mise -E dev en -s 'bash -c \\\"mise env | grep TTT_BASE_VAR\\\"'\" \"TTT_BASE_VAR=dev_value\"\n\n# Test 5: Test with staging environment\nassert_contains \"mise -E staging en -s 'bash -c \\\"echo \\$MISE_ENV\\\"'\" \"staging\"\n\n# Test 6: Verify staging-specific config files are found\nassert_contains \"mise -E staging en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.staging.toml\"\n\n# Test 7: Verify staging-specific variables are loaded\nassert_contains \"mise -E staging en -s 'bash -c \\\"mise env | grep TTT_ENV_NAME\\\"'\" \"TTT_ENV_NAME=staging\"\n\n# Test 8: Verify staging overrides base variable\nassert_contains \"mise -E staging en -s 'bash -c \\\"mise env | grep TTT_BASE_VAR\\\"'\" \"TTT_BASE_VAR=staging_value\"\n\n# Test 9: Test multiple environments (comma-separated)\nassert_contains \"mise -E dev,staging en -s 'bash -c \\\"echo \\$MISE_ENV\\\"'\" \"dev,staging\"\n\n# Test 10: Verify last environment wins for conflicting variables (staging should override dev)\nassert_contains \"mise -E dev,staging en -s 'bash -c \\\"mise env | grep TTT_ENV_NAME\\\"'\" \"TTT_ENV_NAME=staging\"\n\n# Test 11: Verify both config files are loaded\nassert_contains \"mise -E dev,staging en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.dev.toml\"\nassert_contains \"mise -E dev,staging en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.staging.toml\"\n\n# Test 12: Test reverse order (dev should win over staging)\nassert_contains \"mise -E staging,dev en -s 'bash -c \\\"mise env | grep TTT_ENV_NAME\\\"'\" \"TTT_ENV_NAME=dev\"\n\n# Test 13: Without -E flag, MISE_ENV should be empty\nassert_contains \"mise en -s 'bash -c \\\"echo MISE_ENV_IS:\\$MISE_ENV:END\\\"'\" \"MISE_ENV_IS::END\"\n\n# Test 14: Without -E flag, only base config is loaded (no env-specific configs)\nassert_not_contains \"mise en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.dev.toml\"\nassert_not_contains \"mise en -s 'bash -c \\\"mise config ls\\\"'\" \"mise.staging.toml\"\n\n# Test 15: Without -E flag, base variable has base value\nassert_contains \"mise en -s 'bash -c \\\"mise env | grep TTT_BASE_VAR\\\"'\" \"TTT_BASE_VAR=base_value\"\n\n# Test 16: Without -E flag, env-specific variable is not set\nassert_not_contains \"mise en -s 'bash -c \\\"mise env\\\"'\" \"TTT_ENV_NAME\"\n"
  },
  {
    "path": "e2e/cli/test_env_redacted_flags",
    "content": "#!/usr/bin/env bash\n\n# Test --redacted flag to filter only redacted env vars\ncat <<EOF >mise.toml\n[env]\nSECRET_VAR = {value = \"my_secret_value\", redact = true}\nNORMAL_VAR = \"normal_value\"\nAPI_KEY = {value = \"api_key_123\", redact = true}\nEOF\n\n# Test that all vars are shown by default\nassert_contains \"mise env\" \"SECRET_VAR=my_secret_value\"\nassert_contains \"mise env\" \"NORMAL_VAR=normal_value\"\nassert_contains \"mise env\" \"API_KEY=api_key_123\"\n\n# Test --redacted flag filters to only redacted vars\nassert_contains \"mise env --redacted\" \"SECRET_VAR=my_secret_value\"\nassert_not_contains \"mise env --redacted\" \"NORMAL_VAR=normal_value\"\nassert_contains \"mise env --redacted\" \"API_KEY=api_key_123\"\n\n# Test --values flag shows only values\nassert_contains \"mise env --values\" \"my_secret_value\"\nassert_contains \"mise env --values\" \"normal_value\"\nassert_contains \"mise env --values\" \"api_key_123\"\nassert_not_contains \"mise env --values\" \"SECRET_VAR=\"\nassert_not_contains \"mise env --values\" \"NORMAL_VAR=\"\n\n# Test --redacted --values together shows only values of redacted vars\noutput=$(mise env --redacted --values)\necho \"$output\" | grep -q \"my_secret_value\" || fail \"Expected 'my_secret_value' in output\"\necho \"$output\" | grep -qv \"normal_value\" || fail \"Expected 'normal_value' not in output\"\necho \"$output\" | grep -q \"api_key_123\" || fail \"Expected 'api_key_123' in output\"\n\n# Test with redactions array (these are exact matches, not patterns)\ncat <<EOF >mise.toml\nredactions = [\"DB_PASSWORD\", \"AUTH_TOKEN\"]\n[env]\nDB_PASSWORD = \"super_secret\"\nAUTH_TOKEN = \"token_123\"\nUSERNAME = \"john_doe\"\nEOF\n\n# All vars shown by default\nassert_contains \"mise env\" \"DB_PASSWORD=super_secret\"\nassert_contains \"mise env\" \"AUTH_TOKEN=token_123\"\nassert_contains \"mise env\" \"USERNAME=john_doe\"\n\n# Only redacted vars with --redacted\nassert_contains \"mise env --redacted\" \"DB_PASSWORD=super_secret\"\nassert_contains \"mise env --redacted\" \"AUTH_TOKEN=token_123\"\nassert_not_contains \"mise env --redacted\" \"USERNAME=john_doe\"\n\n# Test wildcard redactions\ncat <<EOF >mise.toml\nredactions = [\"SECRET_*\", \"*_KEY\"]\n[env]\nSECRET_ONE = \"secret1\"\nSECRET_TWO = \"secret2\"\nAPI_KEY = \"key123\"\nAUTH_KEY = \"key456\"\nPUBLIC_VAR = \"public\"\nEOF\n\n# Test --redacted with wildcards\nassert_contains \"mise env --redacted\" \"SECRET_ONE=secret1\"\nassert_contains \"mise env --redacted\" \"SECRET_TWO=secret2\"\nassert_contains \"mise env --redacted\" \"API_KEY=key123\"\nassert_contains \"mise env --redacted\" \"AUTH_KEY=key456\"\nassert_not_contains \"mise env --redacted\" \"PUBLIC_VAR=public\"\n\n# Test JSON output with --redacted\ncat <<EOF >mise.toml\n[env]\nSECRET_VAR = {value = \"my_secret\", redact = true}\nPUBLIC_VAR = \"public\"\nEOF\n\nassert_contains \"mise env -J --redacted\" '\"SECRET_VAR\": \"my_secret\"'\nassert_not_contains \"mise env -J --redacted\" '\"PUBLIC_VAR\"'\n\n# Test dotenv format with --redacted\nassert_contains \"mise env -D --redacted\" \"SECRET_VAR=my_secret\"\nassert_not_contains \"mise env -D --redacted\" \"PUBLIC_VAR=public\"\n\n# Test file-based redaction\necho '{\"FILE_SECRET\": \"file_secret_value\", \"FILE_PUBLIC\": \"public_value\"}' >.env.json\ncat <<EOF >mise.toml\n[env]\n_.file = {path = \".env.json\", redact = true}\nEOF\n\n# With file redaction, all vars from file are redacted\nassert_contains \"mise env --redacted\" \"FILE_SECRET=file_secret_value\"\nassert_contains \"mise env --redacted\" \"FILE_PUBLIC=public_value\"\n"
  },
  {
    "path": "e2e/cli/test_error_display",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Test comprehensive error display\n# This test validates that error messages are properly formatted and structured\n\n# Try to disable colors\nexport NO_COLOR=1\n\n# Local assert_fail function that doesn't force MISE_FRIENDLY_ERROR\nlocal_assert_fail() {\n\tlocal cmd=\"$1\"\n\tlocal expected=\"${2:-}\"\n\tlocal status=0\n\tlocal actual\n\n\tdebug \"$ $cmd\"\n\tactual=$(RUST_BACKTRACE=0 bash -c \"$cmd 2>&1\") || status=$?\n\n\tif [[ $status -eq 0 ]]; then\n\t\tfail \"[$cmd] command succeeded but was expected to fail\"\n\tfi\n\n\tif [[ -z $expected ]]; then\n\t\tok \"[$cmd] expected failure\"\n\telif [[ $actual == *\"$expected\"* ]]; then\n\t\tok \"[$cmd] output contains expected text\"\n\telse\n\t\tfail \"[$cmd] expected '$expected' but got '$actual'\"\n\tfi\n}\n\necho \"Testing error message formatting...\"\n\n# =============================================================================\n# PART 1: Testing with FRIENDLY errors (simplified output)\n# =============================================================================\necho \"\"\necho \"PART 1: Testing FRIENDLY error format (MISE_FRIENDLY_ERROR=1)\"\necho \"============================================================\"\nexport MISE_FRIENDLY_ERROR=1\n\n# Test 1: Invalid tool version error\necho \"Test 1: Invalid tool version\"\nlocal_assert_fail \"mise install core:node@invalid-version\" \\\n\t\"mise ERROR Failed to install core:node@invalid-version: HTTP status client error (404 Not Found) for url (https://nodejs.org/dist/vinvalid-version/node-vinvalid-version.tar.gz)\"\n\n# Test 2: Backend error (cargo)\necho \"Test 2: Cargo backend error\"\nlocal_assert_fail \"mise install cargo:nonexistent-crate-12345@1.0.0\" \\\n\t\"mise ERROR Failed to install cargo:nonexistent-crate-12345@1.0.0: HTTP status client error (404 Not Found) for url (https://crates.io/api/v1/crates/nonexistent-crate-12345/versions)\"\n\n# Test 3: GitHub repository not found\necho \"Test 3: GitHub repository not found\"\nlocal_assert_fail \"mise install github:nonexistent-org/nonexistent-repo@latest\" \\\n\t\"mise ERROR Failed to install github:nonexistent-org/nonexistent-repo@latest: HTTP status client error (404 Not Found) for url (https://api.github.com/repos/nonexistent-org/nonexistent-repo/releases)\"\n\n# Test 4: Plugin not found\necho \"Test 4: Plugin not found\"\nlocal_assert_fail \"mise install nonexistent-tool@1.0.0\" \\\n\t\"mise ERROR Failed to install nonexistent-tool@1.0.0: nonexistent-tool not found in mise tool registry\"\n\n# Test 5: Multiple tool failures (could be single or multiple depending on timing)\necho \"Test 5: Multiple tool failures\"\nlocal_assert_fail \"mise install tiny@999.999.999 jq@999.999.999\" \\\n\t\"mise ERROR Failed to install aqua:jqlang/jq@999.999.999: HTTP status client error (404 Not Found) for url (https://api.github.com/repos/jqlang/jq/releases/tags/jq-999.999.999)\"\n\n# =============================================================================\n# PART 2: Testing with DETAILED errors (full error chains)\n# =============================================================================\necho \"\"\necho \"PART 2: Testing DETAILED error format (MISE_FRIENDLY_ERROR=0)\"\necho \"============================================================\"\nexport MISE_FRIENDLY_ERROR=0\n\n# Test 1: Invalid tool version error - check for the error format with full chain\necho \"Test 1: Invalid tool version\"\nlocal_assert_fail \"mise install core:node@invalid-version\" \\\n\t\"0: Failed to install core:node@invalid-version: HTTP status client error (404 Not Found) for url (https://nodejs.org/dist/vinvalid-version/node-vinvalid-version.tar.gz)\"\n\n# Test 2: Backend error (cargo) - check for error format with full chain\necho \"Test 2: Cargo backend error\"\nlocal_assert_fail \"mise install cargo:nonexistent-crate-12345@1.0.0\" \\\n\t\"0: Failed to install cargo:nonexistent-crate-12345@1.0.0: HTTP status client error (404 Not Found) for url (https://crates.io/api/v1/crates/nonexistent-crate-12345/versions)\"\n\n# Test 3: GitHub repository not found - check for error format with full chain\necho \"Test 3: GitHub repository not found\"\nlocal_assert_fail \"mise install github:nonexistent-org/nonexistent-repo@latest\" \\\n\t\"0: Failed to install github:nonexistent-org/nonexistent-repo@latest: HTTP status client error (404 Not Found) for url (https://api.github.com/repos/nonexistent-org/nonexistent-repo/releases)\"\n\n# Test 4: Multiple tool failures - check for error format\necho \"Test 4: Multiple tool failures\"\nlocal_assert_fail \"mise install tiny@999.999.999 jq@999.999.999\" \\\n\t\"0: Failed to install aqua:jqlang/jq@999.999.999: HTTP status client error (404 Not Found) for url (https://api.github.com/repos/jqlang/jq/releases/tags/jq-999.999.999)\"\n\n# Test 5: Error with backtrace enabled - check for proper backtrace format\necho \"Test 5: Error with backtrace\"\nlocal_assert_fail \"RUST_BACKTRACE=1 mise install core:node@invalid-version\" \\\n\t\"0: Failed to install core:node@invalid-version: HTTP status client error (404 Not Found) for url (https://nodejs.org/dist/vinvalid-version/node-vinvalid-version.tar.gz)\"\n\n# Test 6: Invalid configuration (treated as version strings)\necho \"Test 6: Invalid configuration\"\ncat >test_invalid_config.toml <<EOF\n[tools]\nnode = \"this is not valid\"\npython = [\"also\", \"not\", \"valid\"]\nEOF\n\nlocal_assert_fail \"MISE_CONFIG_FILE=test_invalid_config.toml mise install\" \\\n\t\"0: Failed to install tools: core:node@this is not valid, core:python@also, core:python@not, core:python@valid\"\nrm -f test_invalid_config.toml\n\necho \"\"\necho \"All error display tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_exec_chdir",
    "content": "#!/usr/bin/env bash\n\nmkdir direnv\n\nassert \"mise x -C $PWD/direnv -- pwd\" \"$(pwd)/direnv\"\nassert \"mise x -C ./direnv -- pwd\" \"$(pwd)/direnv\"\nassert \"mise x -C direnv -- pwd\" \"$(pwd)/direnv\"\n"
  },
  {
    "path": "e2e/cli/test_exec_latest",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise x tool@latest` installs the actual latest version from registry\n# even if an older version is already installed\n\n# Install an older version\nmise install dummy@1.0.0\n\n# Verify only 1.0.0 is installed\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"2.0.0\"\n\n# Running `mise x dummy@latest` should install and use the actual latest (2.0.0)\n# not just use the latest installed (1.0.0)\nassert_contains \"mise x dummy@latest -- dummy\" \"2.0.0\"\n\n# Verify 2.0.0 is now installed\nassert_contains \"mise ls --installed dummy\" \"2.0.0\"\n\n# Contrast with `mise x dummy` (no explicit @latest) which should use config or latest installed\n# First, ensure no config file requests dummy\nrm -f mise.toml .tool-versions\n\n# `mise x dummy` without explicit version should still work with what's installed\n# (this tests that we didn't break the default behavior)\n# Should output 2.0.0 (latest installed after the above test)\nassert_contains \"mise x dummy -- dummy\" \"2.0.0\"\n\n# Test that consecutive `mise x tool@latest` calls use the cache\n# The second call should not trigger a version list fetch (no bin/list-all or latest-stable call)\n# Run with debug to capture backend calls\nMISE_DEBUG=1 mise x dummy@latest -- dummy 2>&1 | tee /tmp/exec_latest_output.txt\n# Verify it ran successfully with 2.0.0\ngrep -q \"2.0.0\" /tmp/exec_latest_output.txt\n# Should NOT call list-all or latest-stable again since versions are cached\nif grep -q \"bin/list-all\" /tmp/exec_latest_output.txt; then\n\techo \"ERROR: Expected cache hit but got bin/list-all call\"\n\texit 1\nfi\nif grep -q \"latest-stable\" /tmp/exec_latest_output.txt; then\n\techo \"ERROR: Expected cache hit but got latest-stable call\"\n\texit 1\nfi\n\n# Now clear cache and verify that latest-stable IS called (to re-resolve @latest)\nmise cache clear dummy\nMISE_DEBUG=1 mise x dummy@latest -- dummy 2>&1 | tee /tmp/exec_latest_output2.txt\ngrep -q \"2.0.0\" /tmp/exec_latest_output2.txt\n# After cache clear, latest-stable SHOULD be called to resolve @latest\nif ! grep -q \"latest-stable\" /tmp/exec_latest_output2.txt; then\n\techo \"ERROR: Expected cache miss but latest-stable was not called\"\n\texit 1\nfi\n\n# Test that @latest only affects the tool it's specified for, not other tools\n# When running `mise x dummy@1.0.0 dummy@latest`, the 1.0.0 should use installed version\n# First clear cache to ensure a clean test\nmise cache clear dummy\n# Run with both a specific version and @latest - should NOT fetch for 1.0.0\n# (We can't easily test this with dummy since it's the same tool, but we verify\n# the resolve logic works correctly by ensuring both versions work together)\nassert_contains \"mise x dummy@1.0.0 -- dummy\" \"1.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_exec_shim_recursion",
    "content": "#!/usr/bin/env bash\n\n# Regression test: when not_found_auto_install preserves shims in PATH,\n# `mise x -- tool` should resolve the real tool binary, not a shim,\n# preventing infinite recursion.\n\n# Create a real tool binary\ntooldir=\"$HOME/toolbin\"\nmkdir -p \"$tooldir\"\ncat >\"$tooldir/mytool\" <<'TOOL'\n#!/bin/sh\necho REAL_TOOL_OUTPUT\nTOOL\nchmod +x \"$tooldir/mytool\"\n\n# Create a fake shim that would be found first if shims aren't stripped\nshimdir=\"$MISE_DATA_DIR/shims\"\nmkdir -p \"$shimdir\"\ncat >\"$shimdir/mytool\" <<'SHIM'\n#!/bin/sh\necho SHIM_NOT_REAL\nSHIM\nchmod +x \"$shimdir/mytool\"\n\n# Put shims BEFORE tooldir in PATH (the problematic ordering)\nexport PATH=\"$shimdir:$tooldir:$PATH\"\n\n# mise x should strip shims from lookup path and find the real tool\nassert_contains \"mise x -- mytool\" \"REAL_TOOL_OUTPUT\"\nassert_not_contains \"mise x -- mytool\" \"SHIM_NOT_REAL\"\n"
  },
  {
    "path": "e2e/cli/test_exec_venv_path_order",
    "content": "#!/usr/bin/env bash\n\n# Regression test: `mise x -- tool` should respect PATH order when a\n# virtualenv (or similar) directory is prepended to PATH by mise config.\n# Previously, `which_bin` pre-resolution bypassed PATH entirely for\n# mise-managed tools, so a venv binary would be ignored even though\n# mise itself added it to PATH.\n# See: https://github.com/jdx/mise/discussions/8340\n\n# Create a fake \"venv\" with a dummy override that prints a distinct marker\nvenvdir=\"$HOME/fake_venv/bin\"\nmkdir -p \"$venvdir\"\ncat >\"$venvdir/dummy\" <<'SCRIPT'\n#!/bin/sh\necho VENV_DUMMY\nSCRIPT\nchmod +x \"$venvdir/dummy\"\n\n# Configure mise with the dummy tool and prepend the venv dir to PATH\n# (this simulates what _.python.venv does)\ncat >mise.toml <<EOF\n[tools]\ndummy = \"latest\"\n\n[env]\n_.path = [\"$venvdir\"]\nEOF\n\nmise i\n\n# mise x -- which dummy should find the venv binary first\nassert \"mise x -- which dummy\" \"$venvdir/dummy\"\n\n# mise x -- dummy should actually execute the venv binary, not the mise-managed one\nassert \"mise x -- dummy\" \"VENV_DUMMY\"\n"
  },
  {
    "path": "e2e/cli/test_exec_wrapper_recursion",
    "content": "#!/usr/bin/env bash\n\n# Regression test: a wrapper script that calls `mise x -- tool` should not\n# cause infinite recursion, even when the wrapper directory precedes mise\n# tool paths in the system PATH.\n#\n# This tests the scenario from PR #8276 where e.g. .devcontainer/bin/tool\n# calls `mise x -- tool` and the wrapper sits before the mise install path\n# in the original PATH.\n\n# 1. Install a mise-managed tool\ncat >mise.toml <<'EOF'\n[tools]\ndummy = \"latest\"\nEOF\nmise i\n\n# 2. Create a wrapper script that calls `mise x -- dummy` (simulating\n#    .devcontainer/bin/dummy or similar)\nwrapperdir=\"$HOME/wrapper_bin\"\nmkdir -p \"$wrapperdir\"\ncat >\"$wrapperdir/dummy\" <<WRAPPER\n#!/bin/sh\nexec mise x -- dummy\nWRAPPER\nchmod +x \"$wrapperdir/dummy\"\n\n# 3. Put the wrapper directory BEFORE everything else in PATH so it would\n#    be found first if mise didn't prepend its tool paths\nexport PATH=\"$wrapperdir:$PATH\"\n\noutput=\"$(run_with_timeout 10 mise x -- dummy)\" || {\n\techo \"ERROR: mise x -- dummy timed out or failed (likely infinite recursion)\"\n\texit 1\n}\n\n# 5. Should get real dummy output, not hang\nassert_contains \"echo '$output'\" \"This is Dummy\"\n"
  },
  {
    "path": "e2e/cli/test_exec_wrapper_recursion_with_shims",
    "content": "#!/usr/bin/env bash\n\n# Regression test: a wrapper script that calls `mise x -- tool` should not\n# cause infinite recursion when BOTH the wrapper directory AND the shims\n# directory are in PATH, with the wrapper directory appearing first.\n#\n# This is the scenario that occurs in devcontainers where .devcontainer/bin\n# contains wrapper scripts and mise shims are also in PATH. The PathEnv\n# ordering puts \"pre-shims\" paths (including the wrapper dir) before\n# mise-managed tool paths, so `which` finds the wrapper instead of the\n# real binary, causing infinite recursion until E2BIG.\n\n# 1. Install a mise-managed tool\ncat >mise.toml <<'EOF'\n[tools]\ndummy = \"latest\"\nEOF\nmise i\n\n# 2. Create a wrapper script that calls `mise x -- dummy` (simulating\n#    .devcontainer/bin/dummy or similar)\nwrapperdir=\"$HOME/wrapper_bin\"\nmkdir -p \"$wrapperdir\"\ncat >\"$wrapperdir/dummy\" <<WRAPPER\n#!/bin/sh\nexec mise x -- dummy\nWRAPPER\nchmod +x \"$wrapperdir/dummy\"\n\n# 3. Put the wrapper directory BEFORE shims in PATH. This is the key\n#    difference from test_exec_wrapper_recursion: with shims in PATH,\n#    PathEnv classifies the wrapper dir as \"pre\" (before shims), and\n#    tool bins go into \"mise\" which comes after \"pre\". So the wrapper\n#    is found before the real binary.\nshimdir=\"$MISE_DATA_DIR/shims\"\nmkdir -p \"$shimdir\"\nexport PATH=\"$wrapperdir:$shimdir:$PATH\"\n\noutput=\"$(run_with_timeout 10 mise x -- dummy)\" || {\n\techo \"ERROR: mise x -- dummy timed out or failed (likely infinite recursion)\"\n\texit 1\n}\n\n# Should get real dummy output, not hang\nassert_contains \"echo '$output'\" \"This is Dummy\"\n"
  },
  {
    "path": "e2e/cli/test_fmt",
    "content": "#!/usr/bin/env bash\n\necho '[settings]\nidiomatic_version_file_enable_tools = [\n\"go\", \"ruby\"\n]\n\n\n\n[env]\nTEST = \"Hello World!\"\n' >mise.toml\nassert_fail \"mise fmt --check\" \"mise ERROR Following config files are not properly formatted\"\n\nmise fmt\nassert \"mise fmt --check\"\nassert \"cat mise.toml\" '[settings]\nidiomatic_version_file_enable_tools = [\"go\", \"ruby\"]\n\n\n[env]\nTEST = \"Hello World!\"'\n"
  },
  {
    "path": "e2e/cli/test_generate_tool_stub",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test that tool-stub generation works for git-branchless\n\necho \"Testing tool-stub generation for git-branchless...\"\n\n# Generate a tool stub for git-branchless\nmise generate tool-stub git-branchless \\\n\t--platform-url 'https://github.com/arxanas/git-branchless/releases/download/v0.10.0/git-branchless-v0.10.0-x86_64-unknown-linux-musl.tar.gz'\n\n# Check that the file was created\nif [[ ! -f git-branchless ]]; then\n\techo \"FAIL: Tool stub file was not created\"\n\texit 1\nfi\n\n# Check that it's executable\nif [[ ! -x git-branchless ]]; then\n\techo \"FAIL: Tool stub is not executable\"\n\texit 1\nfi\n\necho \"Tool stub created successfully\"\n\n# Show the stub content for debugging\necho \"Stub content:\"\ncat git-branchless\n\n# Try to execute it to see the version\n# This will install the tool if we're on Linux x64, otherwise will show an error about platform\necho \"Attempting to execute git-branchless --version...\"\nOUTPUT=$(./git-branchless --version 2>&1 || true)\necho \"Output: $OUTPUT\"\n\nif echo \"$OUTPUT\" | grep -q \"git-branchless\"; then\n\techo \"SUCCESS: git-branchless executed successfully\"\nelif echo \"$OUTPUT\" | grep -q \"No URL configured for platform\"; then\n\techo \"Expected platform error (not on linux-x64), but tool stub works\"\nelse\n\techo \"FAIL: Unexpected output when executing git-branchless\"\n\texit 1\nfi\n\necho \"Test passed!\"\n"
  },
  {
    "path": "e2e/cli/test_global",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise global dummy@2.0.0\" \"~/.config/mise/config.toml\"\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ndummy = \"2.0.0\"'\n\nmise i\nassert_contains \"mise x -- dummy\" \"2.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_global_alt",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"MISE_GLOBAL_CONFIG_FILE=~/.mise.global.toml mise global dummy@latest\" \"~/.mise.global.toml\"\nassert \"cat ~/.mise.global.toml\" '[tools]\ndummy = \"latest\"'\n\nassert_contains \"MISE_GLOBAL_CONFIG_FILE=~/.config/mise/.tool-versions mise global dummy@latest\" \"~/.config/mise/.tool-versions\"\nassert \"cat ~/.config/mise/.tool-versions\" 'dummy latest'\n\nassert_contains \"MISE_ASDF_COMPAT=1 mise global dummy@3\" \"~/.tool-versions\"\nassert \"cat ~/.tool-versions\" 'dummy 3'\n"
  },
  {
    "path": "e2e/cli/test_help_without_tasks",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Test that `mise help` works even when no tasks are defined\n# This validates the fix for https://github.com/jdx/mise/discussions/6947\n\necho \"Testing 'mise help' command without tasks defined...\"\n\n# Test in a temporary directory without any mise config\nTEMP_DIR=$(mktemp -d)\ncd \"$TEMP_DIR\"\n\n# Test 1: `mise help` should work without tasks\necho \"Test 1: mise help (without tasks)\"\nassert_contains \"mise help\" \"Usage: mise\"\n\n# Test 2: `mise --help` should work (baseline)\necho \"Test 2: mise --help\"\nassert_contains \"mise --help\" \"Usage: mise\"\n\n# Test 3: `mise -h` should work (baseline)\necho \"Test 3: mise -h\"\nassert_contains \"mise -h\" \"Usage: mise\"\n\n# Test 4: All three should produce similar output\necho \"Test 4: Verify all help variants work consistently\"\nif mise help >/dev/null 2>&1; then\n\tok \"mise help succeeded\"\nelse\n\tfail \"mise help failed\"\nfi\nif mise --help >/dev/null 2>&1; then\n\tok \"mise --help succeeded\"\nelse\n\tfail \"mise --help failed\"\nfi\nif mise -h >/dev/null 2>&1; then\n\tok \"mise -h succeeded\"\nelse\n\tfail \"mise -h failed\"\nfi\n\n# Cleanup\ncd - >/dev/null\nrm -rf \"$TEMP_DIR\"\n\necho \"\"\necho \"All help command tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_hook_env",
    "content": "#!/usr/bin/env bash\n\nmise i dummy@{1.0.0,1.1.0,2.0.0}\n\neval \"$(mise activate bash --status)\"\n\nmise use dummy@2.0.0\npushd .. && popd\nassert_contains \"dummy\" \"2.0.0\"\n\nmise shell dummy@1.0.0\npushd .. && popd\nassert_contains \"dummy\" \"1.0.0\"\n\n# TODO: make \"v\" prefixes optional\nexport MISE_DUMMY_VERSION=1.1.0\npushd .. && popd\nassert_contains \"dummy\" \"1.1.0\"\n"
  },
  {
    "path": "e2e/cli/test_hook_env_fast_path",
    "content": "#!/usr/bin/env bash\n\n# Test that hook-env fast-path correctly detects when nothing has changed\n# and skips expensive initialization\n#\n# Key insight: When fast-path triggers, hook-env returns immediately with NO output.\n# When fast-path is bypassed, hook-env outputs shell commands including __MISE_SESSION.\n#\n# Note: eval \"$(mise activate bash)\" already runs hook-env and sets __MISE_SESSION,\n# so subsequent calls should take the fast-path if nothing changed.\n\n# Activate mise - this runs hook-env internally and establishes a session\neval \"$(mise activate bash)\"\n\n# Verify session was established by activate\nif [[ -n $__MISE_SESSION ]]; then\n\tok \"activate established __MISE_SESSION\"\nelse\n\tfail \"activate should establish __MISE_SESSION\"\nfi\n\n# Fast-path should work - nothing has changed since activate\noutput=$(mise hook-env -s bash)\nif [[ -z $output ]]; then\n\tok \"fast-path works when nothing changed (no output)\"\nelse\n\tfail \"fast-path should produce no output but got: '$output'\"\nfi\n\n# Test 1: Creating a new config file should bypass fast-path\nsleep 0.1 # ensure mtime difference\necho '[tools]' >mise.toml\noutput=$(mise hook-env -s bash)\nif [[ $output == *\"__MISE_SESSION\"* ]]; then\n\tok \"new config file bypasses fast-path\"\nelse\n\tfail \"new config file should bypass fast-path but got: '$output'\"\nfi\nrm mise.toml\neval \"$output\"\n\n# Removing the config file also changes directory mtime, so the first\n# hook-env after removal will bypass fast-path. Run it to re-establish session.\noutput=$(mise hook-env -s bash)\neval \"$output\"\n\n# Now fast-path should work\noutput=$(mise hook-env -s bash)\nif [[ -z $output ]]; then\n\tok \"fast-path works after session re-established\"\nelse\n\tfail \"fast-path should work after session re-established but got: '$output'\"\nfi\n\n# Test 2: Changing directories should bypass fast-path\n# First ensure we have a clean session in the current directory\neval \"$(mise activate bash)\"\n# Verify fast-path works here\noutput=$(mise hook-env -s bash)\nif [[ -n $output ]]; then\n\tfail \"expected fast-path before dir change but got output\"\nfi\n\n# Now change directory and verify fast-path is bypassed\n# Use builtin cd to avoid the _mise_hook wrapper that activate installs\nmkdir -p subdir\nbuiltin cd subdir\noutput=$(mise hook-env -s bash)\nif [[ $output == *\"__MISE_SESSION\"* ]]; then\n\tok \"directory change bypasses fast-path\"\nelse\n\tfail \"directory change should bypass fast-path but got: '$output'\"\nfi\nbuiltin cd ..\nrmdir subdir\n\n# Test 3: Creating config in parent's .config/mise should be detected\n# Re-establish session first\neval \"$(mise activate bash)\"\n\nmkdir -p ../.config/mise\nsleep 0.1 # ensure mtime difference\necho '[tools]' >../.config/mise/config.toml\noutput=$(mise hook-env -s bash)\nif [[ $output == *\"__MISE_SESSION\"* ]]; then\n\tok \"parent .config/mise config file bypasses fast-path\"\nelse\n\tfail \"parent .config/mise should bypass fast-path but got: '$output'\"\nfi\n"
  },
  {
    "path": "e2e/cli/test_hook_not_found_auto_install",
    "content": "#!/usr/bin/env bash\n\n# Test that not_found_auto_install works when a tool is already configured but not installed\n# Reproduces https://github.com/jdx/mise/discussions/6482#discussioncomment-14552091\n\n# Test 1: hook-not-found auto-install\n# Set up: Install tiny@3.1.0 globally\nmise use -g tiny@3.1.0\nassert \"mise current tiny\" \"3.1.0\"\n\n# Create a project that requires a different version (tiny@3.0.0)\ncat >mise.toml <<EOF\n[tools]\ntiny = \"3.0.0\"\nEOF\n\n# Uninstall the required version to simulate it being missing\nmise uninstall tiny@3.0.0 || true\n\n# Verify it's not installed\nassert_fail \"mise ls tiny --installed | grep 3.0.0\"\n\n# Simulate the hook-not-found behavior: rtx-tiny is requested but not installed\n# This should auto-install tiny@3.0.0 (note: tiny plugin provides rtx-tiny binary)\nmise hook-not-found rtx-tiny && mise current tiny | grep -q \"3.0.0\"\nassert_contains \"mise ls tiny --installed\" \"3.0.0\"\n\n# Clean up for next test\nrm -f mise.toml\nmise uninstall tiny@3.0.0\n\n# Test 2: shim auto-install\n# Set up: Install tiny@3.1.0 globally, configure tiny@3.0.0 locally (not installed)\ncat >mise.toml <<EOF\n[tools]\ntiny = \"3.0.0\"\nEOF\n\n# Verify it's not installed\nassert_fail \"mise ls tiny --installed | grep 3.0.0\"\n\n# Add shims to PATH and run the shimmed binary\n# This should auto-install tiny@3.0.0 via the shim\nexport PATH=\"$MISE_DATA_DIR/shims:$PATH\"\nrtx-tiny && mise current tiny | grep -q \"3.0.0\"\nassert_contains \"mise ls tiny --installed\" \"3.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_install_before",
    "content": "#!/usr/bin/env bash\n# Test --before flag for date-based version filtering\n\nset -euo pipefail\n\n# Clean up any existing installations\nmise uninstall tiny --all 2>/dev/null || true\nrm -f mise.toml .tool-versions\n\n# Test: install --before with dry-run should show the tool\noutput=$(mise install tiny@latest --before 2020-01-01 --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\n\n# Test: install --before should install a version\nmise install tiny@latest --before 2025-01-01\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\n\n# Test: use --before with dry-run\nmise uninstall tiny --all 2>/dev/null || true\noutput=$(mise use tiny@latest --before 2025-01-01 --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\nrm -f mise.toml\n\n# Test: MISE_INSTALL_BEFORE environment variable works\nmise uninstall tiny --all 2>/dev/null || true\nexport MISE_INSTALL_BEFORE=\"2025-01-01\"\nmise install tiny@latest\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\nunset MISE_INSTALL_BEFORE\n\n# Test: upgrade --before with dry-run\ncat <<EOF >mise.toml\n[tools]\ntiny = \"1\"\nEOF\nmise uninstall tiny --all 2>/dev/null || true\nmise install tiny@1.0.0\noutput=$(mise upgrade --before 2025-01-01 --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\n\n# Test: install --before with relative duration \"90d\"\nmise uninstall tiny --all 2>/dev/null || true\noutput=$(mise install tiny@latest --before 90d --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\n\n# Test: install --before with relative duration \"1y\"\noutput=$(mise install tiny@latest --before 1y --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\n\n# Test: install --before with relative duration \"6m\"\noutput=$(mise install tiny@latest --before 6m --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\n\n# Test: MISE_INSTALL_BEFORE with relative duration\nmise uninstall tiny --all 2>/dev/null || true\nexport MISE_INSTALL_BEFORE=\"90d\"\nmise install tiny@latest\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\nunset MISE_INSTALL_BEFORE\n"
  },
  {
    "path": "e2e/cli/test_install_concurrent_via_exec",
    "content": "#!/usr/bin/env bash\n\n# Test that concurrent processes installing the same tool doesn't corrupt\n# the other ongoing `exec`s.\n# This tests the race condition fix where Process B would wipe Process A's install\n\nset -euo pipefail\n\nmise use dummy@2.0.0\n\n# Clean up any existing installation\nmise uninstall dummy --all 2>/dev/null || true\n\n# Launch multiple processes trying to install the same tool concurrently\nfor _ in {1..4}; do\n\tmise x -- dummy --version &\ndone\n\n# Wait for all background processes to complete\nwait\n\n# Verify the tool is installed and works\nassert_contains \"mise ls --installed dummy\" \"2.0.0\"\n\n# Verify the binary actually exists and is executable\nassert_contains \"mise x -- dummy --version\" \"2.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_install_dry_run",
    "content": "#!/usr/bin/env bash\n# Test install --dry-run functionality\n\nset -euo pipefail\n\n# Test: Dry-run should show what would be installed without actually installing\nassert_contains \"mise install tiny@3.1.0 --dry-run 2>&1\" \"would install\"\n\n# Verify tiny is NOT actually installed\nassert_fail \"mise which tiny\"\n\n# Test: Dry-run should show already installed for existing tools\nmise install jq@latest --force\nassert_contains \"mise install jq@latest --dry-run 2>&1\" \"already installed\"\n\n# Test: Dry-run should work with multiple tools\nassert_contains \"mise install tiny@3.1.0 shfmt@3.10.0 --dry-run 2>&1\" \"would install\"\n\n# Verify neither tool was actually installed\nassert_fail \"mise which tiny\"\n\n# Test: --dry-run-code should exit non-zero when there are tools to install\nassert_fail_contains \"mise install tiny@3.1.0 --dry-run-code 2>&1\" \"would install\"\n\n# Test: --dry-run-code should exit 0 when all tools are already installed\nassert_contains \"mise install jq@latest --dry-run-code 2>&1\" \"already installed\"\n\n# Test: --dry-run-code with no args should exit non-zero when config has missing tools\nTEST_DIR=$(mktemp -d)\ncd \"$TEST_DIR\"\necho 'tools.tiny = \"3.1.0\"' >mise.toml\nmise uninstall tiny@3.1.0 2>/dev/null || true\nassert_fail_contains \"mise install --dry-run-code 2>&1\" \"would install\"\n\n# Test: --dry-run-code with no args should exit 0 when all config tools are installed\nmise install\nassert_contains \"mise install --dry-run-code 2>&1\" \"all tools are installed\"\n"
  },
  {
    "path": "e2e/cli/test_install_inactive_hint",
    "content": "#!/usr/bin/env bash\n# Test that `mise install` warns when installing tools not in any config file\n\nset -euo pipefail\nexport RUST_BACKTRACE=0\nexport MISE_FRIENDLY_ERROR=1\n\n# Test: Installing a tool not in config should show a \"mise use\" hint\nassert_contains \"mise install tiny@3.1.0 2>&1\" \"not activated\"\nassert_contains \"mise install tiny@3.1.0 2>&1\" \"mise use tiny\"\n\n# Test: Installing a tool that IS in config should NOT show the hint\nmise use dummy@1.0.0\nassert_not_contains \"mise install dummy 2>&1\" \"not activated\"\n\n# Clean up\nmise use --rm dummy\n"
  },
  {
    "path": "e2e/cli/test_install_into",
    "content": "#!/usr/bin/env bash\n\nassert \"mise install-into node@22.0.0 ./mynode\"\nassert \"./mynode/bin/node -v\" \"v22.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_install_parallel_failure",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise install` with parallel installation handles failures correctly:\n# - Command exits with non-zero status when some tools fail\n# - Successful tools are still installed\n# - Failed tools don't get installed\n# - All tools are attempted (no early returns)\n\n# Clean up any existing installations\nmise uninstall dummy --all 2>/dev/null || true\nmise uninstall tiny --all 2>/dev/null || true\n\n# Test 1: Install multiple tools where one will fail\n# This tests the parallel installation logic\n\n# Set up config with multiple tools\ncat <<EOF >mise.toml\n[tools]\ndummy = \"other-dummy\"  # This version will fail to install  \ntiny = \"latest\"        # This should install successfully\nEOF\n\n# Try to install both tools in parallel\n# The dummy tool should fail, but tiny should succeed\nassert_fail \"mise install\" \"Failed to install asdf:dummy@other-dummy\"\n\n# Verify tiny was installed successfully despite dummy failure\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\n\n# Verify dummy failed to install the bad version\nassert_not_contains \"mise ls --installed dummy\" \"other-dummy\"\n\n# Test 2: Install with missing plugin that would cause early return\n# This tests the plugin installation error handling\n\n# Try to install a non-existent plugin\nassert_fail \"mise install nonexistent@latest\" \"nonexistent not found in mise tool registry\"\n\n# Test 3: Install multiple tools with mixed success/failure\n# This tests that all tools are attempted even when some fail\n\n# Clean up\nrm -f mise.toml\nmise uninstall jq --all 2>/dev/null || true\nmise uninstall tiny --all 2>/dev/null || true\n\n# Create a scenario with one valid and one invalid tool\nassert_fail \"mise install tiny@latest jq@999.999.999\" \"Failed to install aqua:jqlang/jq@999.999.999\"\n\n# Verify the valid tool was installed\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\n\n# Verify the invalid tool was not installed\nassert_not_contains \"mise ls --installed jq\" \"999.999.999\"\n"
  },
  {
    "path": "e2e/cli/test_install_postinstall_bin_path",
    "content": "#!/usr/bin/env bash\n\n# Test that the per-tool postinstall hook has the tool's actual bin paths on PATH.\n# This uses the backend's list_bin_paths() to set PATH, ensuring tools like helm\n# (where the binary is not in $install_path/bin/) are found during postinstall.\n# Regression test for https://github.com/jdx/mise/discussions/6323\n\ncat <<EOF >mise.toml\n[tools]\ndummy = { version = \"latest\", postinstall = \"dummy\" }\nEOF\n\n# Remove any existing dummy installation to force reinstall\nrm -rf \"$MISE_DATA_DIR/installs/dummy\"\n\n# Install the tool — the postinstall hook should be able to run the dummy command\noutput=$(mise install dummy 2>&1)\n\nif [[ $output == *\"2.0.0\"* ]]; then\n\techo \"✓ postinstall hook found tool binary on PATH\"\nelse\n\techo \"✗ postinstall hook could not find tool binary\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/cli/test_install_postinstall_cli_version",
    "content": "#!/usr/bin/env bash\n\n# Test that tool-level postinstall hooks fire when installing with an explicit\n# version on the CLI (e.g. `mise install dummy@latest`).\n# Regression test for https://github.com/jdx/mise/discussions/7979\n\ncat <<EOF >mise.toml\n[tools]\ndummy = { version = \"latest\", postinstall = \"echo POSTINSTALL_RAN=yes\" }\nEOF\n\n# Remove any existing dummy installation to force reinstall\nrm -rf \"$MISE_DATA_DIR/installs/dummy\"\n\n# Test 1: Install with explicit CLI version — postinstall should still fire\noutput=$(mise install dummy@latest 2>&1)\n\nif [[ $output == *\"POSTINSTALL_RAN=yes\"* ]]; then\n\techo \"✓ postinstall ran with explicit CLI version\"\nelse\n\techo \"✗ postinstall did NOT run with explicit CLI version\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Clean up and test again without explicit version to confirm it still works\nrm -rf \"$MISE_DATA_DIR/installs/dummy\"\n\noutput=$(mise install dummy 2>&1)\n\nif [[ $output == *\"POSTINSTALL_RAN=yes\"* ]]; then\n\techo \"✓ postinstall ran without explicit CLI version\"\nelse\n\techo \"✗ postinstall did NOT run without explicit CLI version\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/cli/test_install_raw",
    "content": "#!/usr/bin/env bash\n\nassert_contains 'mise i --raw -f dummy@1 2>&1' \"~/.local/share/mise/plugins/dummy/bin/install\"\nassert_contains 'MISE_RAW=1 mise i -f dummy@1 2>&1' \"~/.local/share/mise/plugins/dummy/bin/install\"\n"
  },
  {
    "path": "e2e/cli/test_latest",
    "content": "#!/usr/bin/env bash\n\n# Java\n# assert shorthand is a N.N.N version\nassert \"mise latest java | grep -E '^[0-9]+(\\\\.[0-9]+)*$'\"\n# assert vendor version ends with -N.N.N(-SUFFIX)?\nassert \"mise latest java@temurin | grep -E '\\\\-[0-9]+(\\\\.[0-9]+)*(\\..*)?$'\"\n# assert vendor 21 version ends with -21.N.N(-SUFFIX)?\nassert \"mise latest java@temurin-21 | grep -E '\\\\-21(\\\\.[0-9]+)*(\\..*)?$'\"\n\n# Python\n# assert shorthand is a N.N.N version\nassert \"mise latest python | grep -E '^[0-9]+(\\\\.[0-9]+)*$'\"\n# assert vendor version ends with -N.N.N\nassert \"mise latest python@anaconda | grep -E '\\\\-[0-9]+(\\\\.[0-9]+)*$'\"\n# assert vendor 2 version ends with -2.N.N\nassert \"mise latest python@anaconda-2 | grep -E '\\\\-2(\\\\.[0-9]+)*$'\"\n\n# Ruby\n# assert shorthand is a N.N.N version\nassert \"mise latest ruby | grep -E '^[0-9]+(\\\\.[0-9]+)*$'\"\n# assert vendor version ends with -N.N.N\nassert \"mise latest ruby@truffleruby | grep -E '\\\\-[0-9]+(\\\\.[0-9]+)*$'\"\n# assert vendor 22 version ends with -22.N.N\nassert \"mise latest ruby@truffleruby-22 | grep -E '\\\\-22(\\\\.[0-9]+)*$'\"\n"
  },
  {
    "path": "e2e/cli/test_link",
    "content": "#!/usr/bin/env bash\n\nmise install tiny@1.0.1 tiny@3.1.0\nmkdir -p tmp/tiny\nmise link tiny@9.8.7 tmp/tiny\n\nassert_contains \"mise ls tiny\" \"tiny  9.8.7 (symlink)\"\n"
  },
  {
    "path": "e2e/cli/test_link_lockfile",
    "content": "#!/usr/bin/env bash\n\n# Test that linked tools are not reported as missing when a lockfile exists\n# Regression test for https://github.com/jdx/mise/discussions/8049\n\nexport MISE_LOCKFILE=1\n\necho \"=== Setup: install tiny and create a linked version ===\"\nrm -f mise.toml mise.lock\nmise install tiny@3.1.0\n\n# Create a directory to link as a fake \"brew\" version\nmkdir -p \"$PWD/tmp/tiny-brew\"\n\n# Link it as tiny@brew (absolute symlink, like `mise link hk@brew $(brew --prefix hk)`)\nmise link tiny@brew \"$PWD/tmp/tiny-brew\"\nassert_contains \"mise ls tiny\" \"brew (symlink)\"\n\necho \"=== Create mise.toml requesting latest and a lockfile pinning 3.1.0 ===\"\ncat <<EOF >mise.toml\n[tools]\ntiny = \"latest\"\nEOF\n\n# Create a lockfile that pins tiny to 3.1.0\ncat <<EOF >mise.lock\n[tools.tiny]\nversion = \"3.1.0\"\nEOF\n\necho \"=== Verify linked version is used instead of lockfile version ===\"\n# The linked version should take priority over the lockfile entry\n# Previously this would show tiny@3.1.0 as (missing) alongside the linked version\nassert_contains \"mise ls tiny\" \"brew (symlink)\"\nassert_not_contains \"mise ls tiny\" \"missing\"\n\necho \"=== Cleanup ===\"\nrm -rf mise.toml mise.lock tmp/tiny-brew\nmise uninstall tiny@brew 2>/dev/null || true\n\necho \"mise link + lockfile tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_local",
    "content": "#!/usr/bin/env bash\n\nexport MISE_USE_TOML=0\n\nassert \"mise i dummy@{1,2} tiny@3\"\n\nassert \"mise local dummy@2 -vv\"\nassert \"mise local\" \"dummy 2\"\nassert \"mise local --path\" \"$PWD/.tool-versions\"\n\nassert_contains \"mise x -- dummy\" \"2.0.0\"\n\nmise local --pin dummy@1\nassert \"mise local\" \"dummy 1.1.0\"\n\nassert_contains \"mise x -- dummy\" \"1.1.0\"\n\nmkdir subdir\n(\n\tcd subdir || exit\n\tmise local --parent dummy@2\n\tassert \"mise local --parent --path\" \"$HOME/workdir/.tool-versions\"\n\tassert \"mise local --parent\" \"dummy 2\"\n\n\tassert_contains \"mise x -- dummy\" \"2.0.0\"\n)\n\n(\n\tcd subdir || exit\n\tmise local tiny@3\n\tassert \"mise local --path\" \"$PWD/.tool-versions\"\n\tassert \"mise local\" \"tiny 3\"\n\n\tassert_contains \"mise x -- dummy\" \"2.0.0\"\n\tassert_contains \"mise x -- rtx-tiny\" \"3.1.0\"\n)\nassert_fail \"rtx-tiny\"\n\nMISE_ASDF_COMPAT=1 mise local dummy@2\nassert \"mise local\" \"dummy 2.0.0\"\n\nMISE_ASDF_COMPAT=1 mise local --fuzzy dummy@2\nassert \"mise local\" \"dummy 2\"\n"
  },
  {
    "path": "e2e/cli/test_local_toml",
    "content": "#!/usr/bin/env bash\n\nexport MISE_USE_TOML=1\n\nmise i dummy@{1,2} tiny@3\n\nmise local dummy@2\nassert \"mise local --path\" \"$PWD/mise.toml\"\nassert \"mise local\" '[tools]\ndummy = \"2\"'\nassert_contains \"mise x -- dummy\" \"2.0.0\"\n\nmise local --pin dummy@1\nassert \"mise local\" '[tools]\ndummy = \"1.1.0\"'\nassert_contains \"mise x -- dummy\" \"1.1.0\"\n\nmkdir subdir\n(\n\tcd subdir || exit\n\tmise local --parent dummy@2\n\tassert \"mise local --parent --path\" \"$HOME/workdir/mise.toml\"\n\tassert \"mise local --parent\" '[tools]\ndummy = \"2\"'\n\n\tassert_contains \"mise x -- dummy\" \"2.0.0\"\n)\n\n(\n\tcd subdir || exit\n\tmise local tiny@3\n\tassert \"mise local --path\" \"$PWD/mise.toml\"\n\tassert \"mise local\" '[tools]\ntiny = \"3\"'\n\n\tassert_contains \"mise x -- dummy\" \"2.0.0\"\n\tassert_contains \"mise x -- rtx-tiny\" \"3.1.0\"\n)\nassert_fail \"rtx-tiny\"\n"
  },
  {
    "path": "e2e/cli/test_lock",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\necho \"=== Testing basic lock command with no tools ===\"\n# Test basic lock command with no tools configured - should show no tools message\nrm -f mise.toml mise.lock\nassert_contains \"mise lock\" \"No tools configured to lock\"\n\necho \"=== Testing lock command generates cross-platform lockfile ===\"\n# Create a mise.toml with an aqua tool (which supports cross-platform resolution)\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\nrm -f mise.lock\n\n# Test that lock command generates lockfile for all 7 default platforms (including musl variants)\noutput=$(mise lock 2>&1)\nassert_contains \"echo '$output'\" \"Targeting 7 platform(s)\"\nassert_contains \"echo '$output'\" \"Processing 1 tool(s)\"\nassert_contains \"echo '$output'\" \"Updated\"\nassert_contains \"echo '$output'\" \"Lockfile written to\"\n\n# Verify lockfile was created with platform data\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.linux-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.windows-x64\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_contains \"cat mise.lock\" \"1.7.1\"\n# URLs should be github release URLs for jq\nassert_contains \"cat mise.lock\" \"github.com/jqlang/jq/releases\"\n\necho \"=== Testing dry-run mode ===\"\nrm -f mise.lock\noutput=$(mise lock --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"Dry run - would update\"\nassert_contains \"echo '$output'\" \"aqua:jqlang/jq@1.7.1 for linux-x64\"\n# Lockfile should NOT be created in dry-run mode\nassert \"test ! -f mise.lock\"\n\necho \"=== Testing platform filtering ===\"\nrm -f mise.lock\n# Test filtering to specific platforms\noutput=$(mise lock --platform linux-x64,macos-arm64 2>&1)\nassert_contains \"echo '$output'\" \"Targeting 2 platform(s)\"\nassert_contains \"echo '$output'\" \"linux-x64\"\nassert_contains \"echo '$output'\" \"macos-arm64\"\n\n# Verify lockfile only has the requested platforms\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\nassert_not_contains \"cat mise.lock\" \"platforms.windows-x64\"\n\necho \"=== Testing multiple tools ===\"\nrm -f mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\n\"aqua:mikefarah/yq\" = \"4.44.6\"\nEOF\n\noutput=$(mise lock --platform linux-x64 2>&1)\nassert_contains \"echo '$output'\" \"Processing 2 tool(s)\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_contains \"cat mise.lock\" \"mikefarah/yq\"\n\necho \"=== Testing tool filtering ===\"\nrm -f mise.lock\n# Filter to only jq\noutput=$(mise lock \"aqua:jqlang/jq\" --platform linux-x64 2>&1)\nassert_contains \"echo '$output'\" \"Processing 1 tool(s)\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_not_contains \"cat mise.lock\" \"mikefarah/yq\"\n\necho \"=== Testing filtered dry-run skips prune lockfile read ===\"\ncat <<'EOF' >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.linux-x64\" = { checksum = \"sha256:jq\" }\n\n[[tools.dummy]]\nversion = \"1.0.0\"\nbackend = \"asdf:dummy\"\n\"platforms.linux-x64\" = { checksum = \"sha256:dummy\" }\nEOF\n\n# With an explicit tool filter, dry-run should not show prune preview.\noutput=$(mise lock \"aqua:jqlang/jq\" --platform linux-x64 --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"Dry run - would update\"\nassert_not_contains \"echo '$output'\" \"Dry run - would prune\"\n\necho \"=== Testing help output ===\"\nassert_contains \"mise lock --help\" \"Update lockfile checksums and URLs\"\nassert_contains \"mise lock --help\" \"--platform\"\nassert_contains \"mise lock --help\" \"--dry-run\"\nassert_contains \"mise lock --help\" \"--jobs\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\n\necho \"mise lock tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_creation",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\necho \"=== Testing lockfile creation with aqua tool ===\"\n# Create a mise.toml with an aqua tool (which supports cross-platform resolution)\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\nrm -f mise.lock\n\n# Test that lock command creates lockfile\noutput=$(mise lock --platform linux-x64 2>&1)\nassert_contains \"echo '$output'\" \"Processing 1 tool(s)\"\nassert_contains \"echo '$output'\" \"Updated\"\nassert_contains \"echo '$output'\" \"Lockfile written\"\n\n# Verify lockfile was created\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_contains \"cat mise.lock\" \"1.7.1\"\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\n\necho \"=== Testing lockfile update (adding platforms) ===\"\n# Now add another platform - it should update the existing lockfile\noutput=$(mise lock --platform macos-arm64 2>&1)\nassert_contains \"echo '$output'\" \"Updated\"\n\n# Should now have both platforms\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\n\necho \"=== Testing lockfile with multiple tools ===\"\nrm -f mise.lock\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\n\"aqua:sharkdp/fd\" = \"10.2.0\"\nEOF\n\noutput=$(mise lock --platform linux-x64 2>&1)\nassert_contains \"echo '$output'\" \"Processing 2 tool(s)\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_contains \"cat mise.lock\" \"sharkdp/fd\"\n\necho \"=== Testing lockfile retains existing data ===\"\n# Create a lockfile with existing data\nrm -f mise.lock\nmise lock --platform linux-x64\n\n# Now add more platforms\nmise lock --platform macos-arm64\n\n# Original platform data should still exist\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\n\necho \"=== Cleanup ===\"\nrm -f mise.toml mise.lock\n\necho \"mise lock creation tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_env",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise lock` creates separate lockfiles for env-specific configs\n\nexport MISE_LOCKFILE=1\n\necho \"=== Testing mise lock creates separate env lockfile ===\"\n\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\ncat >mise.test.toml <<'EOF'\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\nrm -f mise.lock mise.test.lock\n\n# Install tiny so it's available\nassert \"mise install tiny@1.0.1\"\n\n# Run mise lock with MISE_ENV=test so mise.test.toml is loaded\nassert \"MISE_ENV=test mise lock --platform linux-x64\"\n\n# The base tool should be in mise.lock\nassert_contains \"cat mise.lock\" '[[tools.tiny]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.1\"'\n# mise.lock should NOT contain the env-specific tool\nassert_not_contains \"cat mise.lock\" 'jqlang/jq'\n# mise.lock should NOT have any env field\nassert_not_contains \"cat mise.lock\" 'env = '\n\n# The env-specific tool should be in mise.test.lock\nassert_contains \"cat mise.test.lock\" 'jqlang/jq'\n# mise.test.lock should NOT have env field (env is encoded in filename now)\nassert_not_contains \"cat mise.test.lock\" 'env = '\n\necho \"=== Testing mise lock without MISE_ENV creates only mise.lock ===\"\n\nrm -f mise.lock mise.test.lock mise.test.toml\n\n# With only mise.toml and no MISE_ENV, there should be only mise.lock\nassert \"mise lock --platform linux-x64\"\nassert_contains \"cat mise.lock\" 'version = \"1.0.1\"'\nassert_not_contains \"cat mise.lock\" 'env = '\n# No env-specific lockfile should be created\nassert_fail \"test -f mise.test.lock\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.test.lock mise.toml mise.test.toml\n\necho \"mise lock env tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_env_ci",
    "content": "#!/usr/bin/env bash\n\n# Test that env-specific tools are NOT installed when MISE_ENV is unset.\n# Demonstrates that CI running `mise install --locked` without MISE_ENV\n# will not pick up dev tools from mise.dev.toml.\n\nexport MISE_LOCKFILE=1\n\necho \"=== Setup: create base + dev configs ===\"\n\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\ncat >mise.dev.toml <<'EOF'\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\nrm -f mise.lock mise.dev.lock\n\n# Generate lockfile with dev env active\nassert \"MISE_ENV=dev mise lock --platform linux-x64\"\n\n# Verify base tool is in mise.lock, NOT in mise.dev.lock\nassert_contains \"cat mise.lock\" '[[tools.tiny]]'\nassert_not_contains \"cat mise.lock\" 'jqlang/jq'\n\n# Verify dev tool is in mise.dev.lock, NOT in mise.lock\nassert_contains \"cat mise.dev.lock\" 'jqlang/jq'\nassert_not_contains \"cat mise.dev.lock\" '[[tools.tiny]]'\n\n# Neither lockfile should have env fields\nassert_not_contains \"cat mise.lock\" 'env = '\nassert_not_contains \"cat mise.dev.lock\" 'env = '\n\necho \"=== CI scenario: mise install --locked without MISE_ENV ===\"\n\n# Simulate CI: no MISE_ENV set, only mise.toml is loaded\n# mise ls should only show tiny, not jq\noutput=$(mise ls 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\nassert_not_contains \"echo '$output'\" \"jq\"\n\necho \"=== Verify: with MISE_ENV=dev, both tools are visible ===\"\n\noutput=$(MISE_ENV=dev mise ls 2>&1)\nassert_contains \"echo '$output'\" \"tiny\"\nassert_contains \"echo '$output'\" \"jq\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.dev.lock mise.toml mise.dev.toml\n\necho \"mise lock env CI isolation test passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_future",
    "content": "#!/usr/bin/env bash\n\n# Test for cross-platform lockfile generation\n# This tests that mise lock can generate platform-specific URLs for all platforms\n# even when running on a different platform (e.g., generating linux URLs from macOS)\n\nexport MISE_LOCKFILE=1\n\necho \"=== Testing cross-platform URL generation ===\"\n\n# Create a mise.toml with an aqua tool\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\nrm -f mise.lock\n\n# Generate lockfile for all default platforms\nmise lock\n\necho \"Generated lockfile:\"\ncat mise.lock\n\n# Verify each platform has correct URLs\n# jq uses different filenames for each platform\nassert_contains \"cat mise.lock\" \"jq-linux-amd64\"\nassert_contains \"cat mise.lock\" \"jq-linux-arm64\"\nassert_contains \"cat mise.lock\" \"jq-macos-amd64\"\nassert_contains \"cat mise.lock\" \"jq-macos-arm64\"\nassert_contains \"cat mise.lock\" \"jq-windows-amd64.exe\"\n\n# Verify all 5 default platforms are present\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.linux-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.windows-x64\"\n\necho \"=== Testing selective platform generation ===\"\nrm -f mise.lock\n\n# Generate only for specific platforms\nmise lock --platform linux-x64,windows-x64\n\n# Should only have the requested platforms\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.windows-x64\"\nassert_not_contains \"cat mise.lock\" \"platforms.macos-arm64\"\nassert_not_contains \"cat mise.lock\" \"platforms.macos-x64\"\n\necho \"=== Testing URL validity ===\"\nrm -f mise.lock\nmise lock --platform linux-x64\n\n# URLs should be proper GitHub release URLs\nassert_contains \"cat mise.lock\" \"https://github.com/jqlang/jq/releases/download\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\n\necho \"Cross-platform lockfile tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_local_config",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise lock` writes tools to the correct lockfile based on their source config.\n# Tools from mise.toml should go to mise.lock, tools from mise.local.toml to mise.local.lock.\n\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\necho \"=== Test: tools only in mise.toml, mise.local.toml has only env ===\"\nrm -f mise.toml mise.local.toml mise.lock mise.local.lock\n\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\ncat <<EOF >mise.local.toml\n[env]\nFOO = \"bar\"\nEOF\n\nmise lock --platform linux-x64\n# Tools should go to mise.lock, not mise.local.lock\nassert \"test -f mise.lock\"\nassert \"test ! -f mise.local.lock\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_contains \"cat mise.lock\" \"1.7.1\"\n\necho \"=== Test: tools in both configs go to separate lockfiles ===\"\nrm -f mise.toml mise.local.toml mise.lock mise.local.lock\n\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\ncat <<EOF >mise.local.toml\n[tools]\n\"aqua:mikefarah/yq\" = \"4.44.6\"\nEOF\n\nmise lock --platform linux-x64\n# jq (from mise.toml) should be in mise.lock\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\nassert_not_contains \"cat mise.lock\" \"mikefarah/yq\"\n\n# yq (from mise.local.toml) should be in mise.local.lock\nassert \"test -f mise.local.lock\"\nassert_contains \"cat mise.local.lock\" \"mikefarah/yq\"\nassert_not_contains \"cat mise.local.lock\" \"jqlang/jq\"\n\necho \"=== Test: --local flag only writes mise.local.lock ===\"\nrm -f mise.lock mise.local.lock\n\nmise lock --local --platform linux-x64\n# Only mise.local.lock should be created\nassert \"test -f mise.local.lock\"\nassert \"test ! -f mise.lock\"\nassert_contains \"cat mise.local.lock\" \"mikefarah/yq\"\n\necho \"=== Cleanup ===\"\nrm -f mise.toml mise.local.toml mise.lock mise.local.lock\n\necho \"mise lock local config tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_lock_platform_merge",
    "content": "#!/usr/bin/env bash\n\n# Test that lockfile platform info merging preserves URLs and prefers sha256 over blake3\n\nexport MISE_LOCKFILE=1\n\necho \"=== Testing lockfile platform merge preserves URL and sha256 checksum ===\"\nrm -f mise.toml mise.lock\n\n# Create a mise.toml with a tool\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\n# Create an existing lockfile with sha256 checksum and URL for current platform\n# This simulates what the lockfile looks like after `mise lock` generates it\ncat <<'EOF' >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.linux-x64\" = { checksum = \"sha256:5942c9b0934e510ee61eb3e30273f1b3fe2590df93933a93d7c58b81d19c8ff5\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64\" }\n\"platforms.linux-arm64\" = { checksum = \"sha256:4dd2d8a0661df0b22f1bb9a1f9830f06b6f3b8f7d91211a1ef5d7c4f06a8b4c5\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-arm64\" }\n\"platforms.macos-x64\" = { checksum = \"sha256:0bbe619e663e0de2c550be2fe7e7e4b0a3f6e9a5e6c8d0d8ddf88ba6d0c3c2d6\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-amd64\" }\n\"platforms.macos-arm64\" = { checksum = \"sha256:0bbe619e663e0de2c550be2fe7e7e4b0a3f6e9a5e6c8d0d8ddf88ba6d0c3c2d7\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-arm64\" }\n\"platforms.windows-x64\" = { checksum = \"sha256:3f8a60f8c9c4e6d0f3b0e8d0c9f0a0b0c0d0e0f0a0b0c0d0e0f0a0b0c0d0e0f0\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-windows-amd64.exe\" }\nEOF\n\n# Run mise lock to re-resolve the current platform\n# This should merge the new platform info with existing, preserving URLs\nmise lock --platform linux-x64 2>&1\n\n# Verify the URL is still present for linux-x64 (should not be lost during merge)\nassert_contains \"cat mise.lock\" 'url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64\"'\n\n# Verify sha256 checksum is preserved (not replaced with blake3)\nassert_contains \"cat mise.lock\" 'sha256:'\n\n# Verify other platforms' entries are also preserved\nassert_contains \"cat mise.lock\" 'platforms.macos-arm64'\nassert_contains \"cat mise.lock\" 'platforms.windows-x64'\n\necho \"=== Testing merge with blake3 checksum prefers sha256 ===\"\nrm -f mise.lock\n\n# Create a lockfile where one platform has blake3 (simulating local install)\n# and existing has sha256 (from mise lock)\ncat <<'EOF' >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.linux-x64\" = { checksum = \"sha256:5942c9b0934e510ee61eb3e30273f1b3fe2590df93933a93d7c58b81d19c8ff5\", url = \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64\" }\nEOF\n\n# Run mise lock which may try to update with new checksums\nmise lock --platform linux-x64 2>&1\n\n# Verify sha256 is still present (not replaced)\nassert_contains \"cat mise.lock\" 'sha256:'\n\n# Verify URL is preserved\nassert_contains \"cat mise.lock\" 'url = \"https://github.com/jqlang/jq/releases'\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\n\necho \"mise lock platform merge tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_log_level",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise x dummy@latest --log-level debug -- dummy 2>&1\" \"DEBUG\"\nassert_contains \"mise x dummy@latest --log-level=debug -- dummy 2>&1\" \"DEBUG\"\nassert_contains \"mise x dummy@latest --debug -- dummy 2>&1\" \"DEBUG\"\nassert_contains \"mise x dummy@latest --trace -- dummy 2>&1\" \"TRACE\"\n"
  },
  {
    "path": "e2e/cli/test_ls",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use -g dummy@ref:master\"\nassert \"mise use tiny@3\"\nassert_contains \"mise ls\" \"dummy  ref:master  ~/.config/mise/config.toml  ref:master\"\nassert_contains \"mise ls tiny\" \"tiny  3.1.0  ~/workdir/mise.toml  3\"\nassert \"mise i tiny@2.0.0\"\nassert_contains \"mise ls\" \"tiny   2.0.0\"\nassert_not_contains \"mise ls -c\" \"tiny   2.0.0\"\nassert_contains \"mise ls --prefix=3 tiny\" \"3.1.0\"\nassert_not_contains \"mise ls --prefix=2 tiny\" \"3.1.0\"\nassert_contains \"mise ls --global\" \"dummy\"\nassert_not_contains \"mise ls --global\" \"tiny\"\nassert_contains \"mise ls --local\" \"tiny\"\nassert_not_contains \"mise ls --local\" \"dummy\"\n\nmise ls tiny --json >json\nassert \"cat json | jq -r '.[0].installed'\" \"true\"\nassert \"cat json | jq -r '.[0].active'\" \"false\"\nassert \"cat json | jq -r '.[0].version'\" \"2.0.0\"\nassert \"cat json | jq -r '.[0].install_path'\" \"$MISE_DATA_DIR/installs/tiny/2.0.0\"\nmise ls --json >json\nassert \"cat json | jq -r '.tiny[1].installed'\" \"true\"\nassert \"cat json | jq -r '.tiny[1].active'\" \"true\"\nassert \"cat json | jq -r '.tiny[1].version'\" \"3.1.0\"\nassert \"cat json | jq -r '.tiny[1].install_path'\" \"$MISE_DATA_DIR/installs/tiny/3.1.0\"\n\nassert \"mise uninstall tiny@3.1.0\"\nassert_contains \"mise ls tiny\" \"tiny  3.1.0 (missing)  ~/workdir/mise.toml  3\"\nassert_contains \"mise ls --missing tiny\" \"tiny  3.1.0 (missing)  ~/workdir/mise.toml  3\"\nassert_not_contains \"mise ls --missing tiny\" \"2.0.0\"\n\nassert_fail \"mise ls missing-tool\" \"missing-tool not found in mise tool registry\"\n\nmise use cargo-binstall\nmise i cargo:usage-cli\nassert_contains \"mise ls\" \"cargo:usage-cli\"\nassert_not_contains \"mise ls\" \"cargo-usage-cli\" # if the backend meta file isn't working right these will be displayed\n\nassert_contains \"mise ls --prunable\" \"cargo:usage-cli\"\n"
  },
  {
    "path": "e2e/cli/test_ls_all_sources",
    "content": "#!/usr/bin/env bash\n\nmkdir -p project-a project-b\n\necho \"tools.dummy = '1'\" >project-a/mise.toml\necho \"tools.dummy = '1'\" >project-b/mise.toml\n\nassert_succeed \"cd project-a && mise ls dummy\"\nassert_succeed \"cd project-b && mise ls dummy\"\n\nassert_contains \"mise ls dummy --all-sources\" \"dummy  1.1.0 (missing)  ~/workdir/project-a/mise.toml  1\"\nassert_contains \"mise ls dummy --all-sources\" \"~/workdir/project-b/mise.toml  1\"\n\nassert \"mise ls dummy --all-sources --json | jq -r '.[0].sources | length'\" \"2\"\nassert_contains \"mise ls dummy --all-sources --json\" \"project-a/mise.toml\"\nassert_contains \"mise ls dummy --all-sources --json\" \"project-b/mise.toml\"\n"
  },
  {
    "path": "e2e/cli/test_ls_cache",
    "content": "#!/usr/bin/env bash\nexport MISE_USE_VERSIONS_HOST=1\n\n# verify that cache is reused for `mise ls`\n# see https://github.com/jdx/mise/discussions/6736\n\nassert_contains \"mise -v use bat 2>&1\" \"GET https://mise-versions.jdx.dev/tools/bat.toml 200 OK\"\ntouch -t 202001010000 \"$MISE_CACHE_DIR/bat/\"*\nassert_not_contains \"mise -v ls bat 2>&1\" \"GET https://mise-versions.jdx.dev/tools/bat.toml 200 OK\"\n"
  },
  {
    "path": "e2e/cli/test_ls_remote",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise ls-remote dummy\" '1.0.0\n1.1.0\n2.0.0'\n\nassert_contains \"mise p list-remote\" \"elixir\"\n\nassert \"mise ls-remote dummy 1\" \"1.0.0\n1.1.0\"\nassert \"mise ls-remote dummy@2\" \"2.0.0\"\nassert \"mise ls-remote dummy@sub-1:2\" \"1.0.0\n1.1.0\"\n\n# Test --json flag outputs valid JSON with version field\njson_output=$(mise ls-remote dummy --json)\nassert_contains \"echo '$json_output'\" '\"version\"'\n\n# Test -J short flag works the same as --json\njson_output_short=$(mise ls-remote dummy -J)\nassert_contains \"echo '$json_output_short'\" '\"version\"'\n\n# Test JSON output for GitHub backend includes created_at\n# Using a real GitHub tool to verify created_at timestamps are included\nif github_json=$(mise ls-remote github:jdx/mise --json 2>/dev/null | head -1); then\n\tassert_contains \"echo '$github_json'\" '\"created_at\"'\nfi\n\n# Test JSON output for NPM backend includes created_at\nif npm_json=$(mise ls-remote npm:prettier --json 2>/dev/null | head -1); then\n\tassert_contains \"echo '$npm_json'\" '\"created_at\"'\nfi\n\n# Test JSON output for Cargo backend includes created_at\nif cargo_json=$(mise ls-remote cargo:eza --json 2>/dev/null | head -1); then\n\tassert_contains \"echo '$cargo_json'\" '\"created_at\"'\nfi\n\n# Test JSON output for Pipx backend includes created_at\nif pipx_json=$(mise ls-remote pipx:black --json 2>/dev/null | head -1); then\n\tassert_contains \"echo '$pipx_json'\" '\"created_at\"'\nfi\n"
  },
  {
    "path": "e2e/cli/test_mcp",
    "content": "#!/usr/bin/env bash\n\n# Test mise mcp command\nexport MISE_EXPERIMENTAL=1\n\n# Test that mcp command exists and shows help\nassert_contains \"mise mcp --help\" \"[experimental] Run Model Context Protocol (MCP) server\"\nassert_contains \"mise mcp --help\" \"This command starts an MCP server that exposes mise functionality\"\nassert_contains \"mise mcp --help\" \"to AI assistants over stdin/stdout using JSON-RPC protocol.\"\n\n# Test that mcp server can be invoked (even if it errors without proper initialization)\n# The server requires proper initialization sequence, so we just test that the command exists\n# and returns a recognizable error when given invalid input\necho \"invalid json\" | mise mcp 2>&1 | grep -q \"Failed to create service\" || echo \"MCP server invocation test passed\"\n"
  },
  {
    "path": "e2e/cli/test_mcp_protocol",
    "content": "#!/usr/bin/env bash\n\n# Test MCP protocol interactions in more detail\nexport MISE_EXPERIMENTAL=1\n\n# Create a test environment with tools, tasks and env vars\ncat >mise.toml <<EOF\n[tools]\nnode = \"20.11.0\"\npython = \"3.12\"\n\n[env]\nTEST_MCP_VAR = \"test_value\"\nPROJECT_ENV = \"development\"\nAPI_KEY = \"secret123\"\n\n[tasks.test-task]\nrun = \"echo 'Running test task'\"\ndescription = \"A test task for MCP\"\n\n[tasks.echo-args]\nrun = 'echo \"args: $@\"'\ndescription = \"Echo arguments back\"\n\n[tasks.build]\nrun = \"echo 'Building...'\"\ndescription = \"Build the project\"\ndepends = [\"test-task\"]\nalias = [\"b\"]\ndir = \".\"\nquiet = true\n\n[tasks.lint]\nrun = \"echo 'Linting code'\"\ndescription = \"Run linters\"\nusage = \"lint [files...]\"\nEOF\n\necho \"Testing MCP server startup and error handling...\"\n\n# Test that MCP server rejects invalid JSON\noutput=$(echo \"not json\" | mise mcp 2>&1 || true)\nif [[ $output == *\"Failed to create service\"* ]]; then\n\techo \"SUCCESS: MCP server correctly rejected invalid JSON\"\nelse\n\techo \"ERROR: Expected 'Failed to create service' in output, got: $output\"\n\texit 1\nfi\n\necho -e \"\\nTesting MCP protocol with actual requests...\"\n\n# Create a simplified test that works around the rmcp 0.3 connection issue\ncat >test_mcp.py <<'EOF'\n#!/usr/bin/env python3\nimport json\nimport os\nimport select\nimport subprocess\nimport sys\n\n\ndef find_mise():\n    paths = [\n        os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"target\", \"debug\", \"mise\"),\n        \"mise\",\n    ]\n    for path in paths:\n        if os.path.exists(path) or path == \"mise\":\n            return path\n    return None\n\n\ndef send(proc, msg):\n    proc.stdin.write((json.dumps(msg) + \"\\n\").encode())\n    proc.stdin.flush()\n\n\ndef recv(proc, timeout=5.0):\n    ready, _, _ = select.select([proc.stdout], [], [], timeout)\n    if not ready:\n        return None\n    line = proc.stdout.readline().decode().strip()\n    if not line:\n        return None\n    return json.loads(line)\n\n\ndef handshake(proc):\n    \"\"\"Perform initialize + initialized handshake, return initialize result.\"\"\"\n    send(proc, {\n        \"jsonrpc\": \"2.0\", \"id\": 1,\n        \"method\": \"initialize\",\n        \"params\": {\n            \"protocolVersion\": \"2025-03-26\",\n            \"capabilities\": {},\n            \"clientInfo\": {\"name\": \"test-client\", \"version\": \"1.0.0\"},\n        },\n    })\n    resp = recv(proc)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad initialize response: {resp}\")\n        return None\n    # Send initialized notification (no id = notification)\n    send(proc, {\"jsonrpc\": \"2.0\", \"method\": \"notifications/initialized\"})\n    return resp[\"result\"]\n\n\ndef test_initialize(proc):\n    result = handshake(proc)\n    if not result:\n        return 1\n\n    assert result[\"protocolVersion\"] == \"2025-03-26\", \"wrong protocol version\"\n    print(\"✓ Protocol version correct\")\n\n    caps = result[\"capabilities\"]\n    assert \"resources\" in caps, \"resources capability missing\"\n    print(\"✓ Resources capability present\")\n    assert \"tools\" in caps, \"tools capability missing\"\n    print(\"✓ Tools capability present\")\n\n    assert result[\"serverInfo\"][\"name\"] == \"rmcp\", \"wrong server name\"\n    print(\"✓ Server info correct\")\n    return 0\n\n\ndef test_tools_list(proc):\n    send(proc, {\"jsonrpc\": \"2.0\", \"id\": 2, \"method\": \"tools/list\", \"params\": {}})\n    resp = recv(proc)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad tools/list response: {resp}\")\n        return 1\n\n    tools = resp[\"result\"][\"tools\"]\n    tool_names = {t[\"name\"] for t in tools}\n    assert \"run_task\" in tool_names, f\"run_task not in tools: {tool_names}\"\n    assert \"install_tool\" in tool_names, f\"install_tool not in tools: {tool_names}\"\n    print(f\"✓ tools/list returned {len(tools)} tools: {tool_names}\")\n\n    # Verify run_task has proper input schema\n    run_task = next(t for t in tools if t[\"name\"] == \"run_task\")\n    schema_props = run_task[\"inputSchema\"][\"properties\"]\n    assert \"task\" in schema_props, \"run_task missing 'task' param\"\n    assert \"args\" in schema_props, \"run_task missing 'args' param\"\n    print(\"✓ run_task schema has task and args parameters\")\n    return 0\n\n\ndef test_run_task_success(proc):\n    send(proc, {\n        \"jsonrpc\": \"2.0\", \"id\": 3,\n        \"method\": \"tools/call\",\n        \"params\": {\n            \"name\": \"run_task\",\n            \"arguments\": {\"task\": \"test-task\"},\n        },\n    })\n    resp = recv(proc, timeout=30.0)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad run_task response: {resp}\")\n        return 1\n\n    result = resp[\"result\"]\n    assert not result.get(\"isError\", False), f\"run_task returned error: {result}\"\n    text = result[\"content\"][0][\"text\"]\n    assert \"Running test task\" in text, f\"unexpected output: {text}\"\n    print(f\"✓ run_task success: {text.strip()}\")\n    return 0\n\n\ndef test_run_task_with_args(proc):\n    send(proc, {\n        \"jsonrpc\": \"2.0\", \"id\": 4,\n        \"method\": \"tools/call\",\n        \"params\": {\n            \"name\": \"run_task\",\n            \"arguments\": {\"task\": \"echo-args\", \"args\": [\"hello\", \"world\"]},\n        },\n    })\n    resp = recv(proc, timeout=30.0)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad run_task response: {resp}\")\n        return 1\n\n    result = resp[\"result\"]\n    assert not result.get(\"isError\", False), f\"run_task returned error: {result}\"\n    text = result[\"content\"][0][\"text\"]\n    assert \"hello\" in text and \"world\" in text, f\"args not forwarded: {text}\"\n    print(f\"✓ run_task with args forwarded correctly: {text.strip()}\")\n    return 0\n\n\ndef test_run_task_unknown(proc):\n    send(proc, {\n        \"jsonrpc\": \"2.0\", \"id\": 5,\n        \"method\": \"tools/call\",\n        \"params\": {\n            \"name\": \"run_task\",\n            \"arguments\": {\"task\": \"nonexistent-task-xyz\"},\n        },\n    })\n    resp = recv(proc, timeout=30.0)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad run_task response: {resp}\")\n        return 1\n\n    result = resp[\"result\"]\n    assert result.get(\"isError\", False), \"expected error for unknown task\"\n    print(\"✓ run_task with unknown task returns error\")\n    return 0\n\n\ndef test_install_tool_stub(proc):\n    send(proc, {\n        \"jsonrpc\": \"2.0\", \"id\": 6,\n        \"method\": \"tools/call\",\n        \"params\": {\n            \"name\": \"install_tool\",\n            \"arguments\": {\"tool\": \"node\"},\n        },\n    })\n    resp = recv(proc, timeout=30.0)\n    if not resp or \"result\" not in resp:\n        print(f\"ERROR: Bad install_tool response: {resp}\")\n        return 1\n\n    result = resp[\"result\"]\n    assert result.get(\"isError\", False), \"expected error from stub\"\n    text = result[\"content\"][0][\"text\"]\n    assert \"not yet implemented\" in text, f\"unexpected stub message: {text}\"\n    print(\"✓ install_tool stub returns not-yet-implemented error\")\n    return 0\n\n\ndef main():\n    mise_path = find_mise()\n    if not mise_path:\n        print(\"ERROR: Could not find mise binary\")\n        return 1\n    print(f\"Using mise binary: {mise_path}\")\n\n    proc = subprocess.Popen(\n        [mise_path, \"mcp\"],\n        stdin=subprocess.PIPE,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        env={**dict(os.environ), \"MISE_EXPERIMENTAL\": \"1\"},\n    )\n\n    try:\n        tests = [\n            (\"initialize\", test_initialize),\n            (\"tools/list\", test_tools_list),\n            (\"run_task success\", test_run_task_success),\n            (\"run_task with args\", test_run_task_with_args),\n            (\"run_task unknown task\", test_run_task_unknown),\n            (\"install_tool stub\", test_install_tool_stub),\n        ]\n        for name, test_fn in tests:\n            print(f\"\\n--- {name} ---\")\n            rc = test_fn(proc)\n            if rc != 0:\n                print(f\"FAIL: {name}\")\n                return 1\n        print(\"\\n✓ All MCP protocol tests passed!\")\n        return 0\n    except Exception as e:\n        print(f\"ERROR: {e}\")\n        return 1\n    finally:\n        proc.terminate()\n        proc.wait()\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\nEOF\n\n# Run the Python test script\npython3 test_mcp.py || exit 1\n\n# Clean up\nrm -f test_mcp.py\n\necho \"All tests completed successfully!\"\n"
  },
  {
    "path": "e2e/cli/test_multiple_version_constraints_lockfile",
    "content": "#!/usr/bin/env bash\n\n# Test for https://github.com/jdx/mise/discussions/5906\n# Issue: Multiple version constraints with lockfile cause incorrect version selection\n# and lockfile inconsistency\n\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\n# Clean start\nrm -f mise.toml mise.lock\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"*\n\n# Create a config with multiple version constraints\ncat <<EOF >mise.toml\n[tools]\ntiny = ['latest', 'prefix:1.0', 'prefix:1.1']\nEOF\n\n# Create lockfile to enable lockfile mode\ntouch mise.lock\n\n# Initial install should fetch all versions\necho \"=== Initial install with multiple version constraints ===\"\nmise install\nassert \"mise ls tiny --json | jq -r 'length'\" \"3\"\n\n# Check that all versions are installed (prefix:1.0 installs 1.0.1, prefix:1.1 installs 1.1.0)\nassert_contains \"mise ls tiny\" \"1.0.1\"\nassert_contains \"mise ls tiny\" \"1.1.0\"\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Verify initial lockfile format uses array of tables\necho \"=== Checking initial lockfile format ===\"\ncat mise.lock\nassert_contains \"cat mise.lock\" '[[tools.tiny]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.1\"'\nassert_contains \"cat mise.lock\" 'version = \"1.1.0\"'\nassert_contains \"cat mise.lock\" 'version = \"3.1.0\"'\n\n# Check which version is considered \"latest\"\necho \"=== Checking 'latest' version ===\"\nlatest_version=$(mise ls tiny --json | jq -r '.[] | select(.requested_version == \"latest\") | .version')\nassert \"echo $latest_version\" \"3.1.0\"\n\n# Test that after removing and reinstalling a version,\n# the lockfile maintains all versions\necho \"=== Testing reinstall after removing a version ===\"\nrm -rf \"$MISE_DATA_DIR/installs/tiny/1.1.0\"\nmise install\n\n# Check that lockfile maintains format and all versions\necho \"=== Checking lockfile after reinstall ===\"\ncat mise.lock\nassert_contains \"cat mise.lock\" '[[tools.tiny]]'\nassert_contains \"cat mise.lock\" 'version = \"1.0.1\"'\nassert_contains \"cat mise.lock\" 'version = \"1.1.0\"'\nassert_contains \"cat mise.lock\" 'version = \"3.1.0\"'\n\n# Count how many versions are in the lockfile\nlockfile_versions=$(grep -c \"version =\" mise.lock || echo 0)\necho \"Number of versions in lockfile: $lockfile_versions\"\nassert \"echo $lockfile_versions\" \"3\"\n\n# Show that all versions are still installed despite lockfile issues\necho \"=== All versions still installed despite lockfile issues ===\"\nassert_contains \"mise ls tiny\" \"1.0.1\"\nassert_contains \"mise ls tiny\" \"1.1.0\"\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Clean all versions and test install from broken lockfile\necho \"=== Testing install from incomplete lockfile ===\"\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"*\nmise install\n\n# Check what actually got installed\necho \"=== Checking what was installed from incomplete lockfile ===\"\nmise ls tiny\n\n# This should install all 3 versions from the lockfile\ninstalled_count=$(mise ls tiny --json | jq -r 'length')\necho \"Number of versions installed from lockfile: $installed_count\"\n\n# The test should fail if not all versions are installed\nassert \"echo $installed_count\" \"3\"\n"
  },
  {
    "path": "e2e/cli/test_no_env",
    "content": "#!/usr/bin/env bash\n\n# Test that --no-env flag prevents loading environment variables from config files\n\n# Create a config file with environment variables\ncat <<EOF >mise.toml\n[env]\nTEST_FOO_VAR = \"FOO\"\nEOF\n\n# Test if it works with env\nassert_contains \"mise env\" \"TEST_FOO_VAR\"\nassert_not_contains \"mise --no-env env\" \"TEST_FOO_VAR\"\n\n# Test with exec as well\nassert_contains \"mise exec -- env | grep TEST_FOO_VAR\" \"TEST_FOO_VAR=FOO\"\nassert_not_contains \"mise --no-env exec -- env\" \"TEST_FOO_VAR\"\n\n# Test that MISE_NO_ENV=1 environment variable works the same way\nassert_not_contains \"MISE_NO_ENV=1 mise env\" \"TEST_FOO_VAR\"\nassert_not_contains \"MISE_NO_ENV=1 mise exec -- env\" \"TEST_FOO_VAR\"\n\ncat <<EOF >mise.toml\n[settings]\nno_env = true\n\n[env]\nTEST_FOO_VAR = \"FOO\"\nEOF\n\nassert_not_contains \"mise env\" \"TEST_FOO_VAR\"\n"
  },
  {
    "path": "e2e/cli/test_no_hooks",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[settings]\nexperimental = true\n[tools]\ndummy = 'latest'\n[hooks]\npreinstall = 'echo PREINSTALL'\nEOF\n\nassert_contains \"mise i dummy 2>&1\" \"PREINSTALL\"\nassert_not_contains \"mise --no-hooks i dummy 2>&1\" \"PREINSTALL\"\n\nassert_not_contains \"MISE_NO_HOOKS=1 mise --no-hooks i dummy 2>&1\" \"PREINSTALL\"\n\ncat <<EOF >mise.toml\n[settings]\nexperimental = true\nno_hooks = true\n[tools]\ndummy = 'latest'\n[hooks]\npreinstall = 'echo PREINSTALL'\nEOF\n\nassert_not_contains \"mise i dummy 2>&1\" \"PREINSTALL\"\n"
  },
  {
    "path": "e2e/cli/test_nonexistent_cwd",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# Test that mise handles commands from non-existent directories gracefully\n# This test validates that when a directory is deleted while mise is running from it,\n# mise shows a warning but continues execution\n\n# Test helper function to run commands from a non-existent directory\nrun_from_nonexistent() {\n\tlocal cmd=\"$1\"\n\tlocal should_succeed=\"${2:-true}\" # Whether the command should succeed despite the warning\n\n\t# Create a temporary directory\n\tlocal temp_dir\n\ttemp_dir=$(mktemp -d)\n\n\t# Change to the temporary directory\n\tcd \"$temp_dir\"\n\n\t# Remove the directory while we're still in it\n\trmdir \"$temp_dir\"\n\n\t# Now we're in a non-existent directory - run the mise command\n\tlocal status=0\n\tlocal output\n\toutput=$(MISE_FRIENDLY_ERROR=1 RUST_BACKTRACE=0 bash -c \"$cmd 2>&1\") || status=$?\n\n\t# Check for the warning about non-existent directory\n\tif [[ $output == *\"Current directory does not exist\"* ]] || [[ $output == *\"WARNING\"* ]]; then\n\t\tok \"[$cmd] showed warning about non-existent directory\"\n\telse\n\t\t# Some commands might not trigger the warning if they exit early\n\t\tdebug \"[$cmd] may not have shown warning, output: ${output:0:100}...\"\n\tfi\n\n\tif [[ $should_succeed == \"true\" ]]; then\n\t\tif [[ $status -eq 0 ]]; then\n\t\t\tok \"[$cmd] succeeded despite non-existent directory\"\n\t\telse\n\t\t\t# Command might fail for other reasons (e.g., missing tools)\n\t\t\tdebug \"[$cmd] failed (status $status), which might be expected\"\n\t\tfi\n\telse\n\t\tif [[ $status -ne 0 ]]; then\n\t\t\tok \"[$cmd] failed as expected\"\n\t\telse\n\t\t\tfail \"[$cmd] succeeded but was expected to fail\"\n\t\tfi\n\tfi\n\n\t# Return to a valid directory\n\tcd \"$HOME\" || cd / || true\n}\n\necho \"Testing mise commands from non-existent directories...\"\n\n# Test various commands - they should all show a warning but may still work\necho \"Test 1: mise --version from non-existent directory\"\nrun_from_nonexistent \"mise --version\" \"true\"\n\necho \"Test 2: mise ls from non-existent directory\"\nrun_from_nonexistent \"mise ls\" \"true\"\n\necho \"Test 3: mise current from non-existent directory\"\nrun_from_nonexistent \"mise current\" \"true\"\n\necho \"Test 4: mise env from non-existent directory\"\nrun_from_nonexistent \"mise env\" \"true\"\n\necho \"Test 5: mise doctor from non-existent directory\"\nrun_from_nonexistent \"mise doctor\" \"true\"\n\necho \"Test 6: mise plugins from non-existent directory\"\nrun_from_nonexistent \"mise plugins\" \"true\"\n\n# Commands that need to write to cwd might fail\necho \"Test 7: mise use from non-existent directory\"\nrun_from_nonexistent \"mise use node@20\" \"false\"\n\necho \"Test 8: mise install from non-existent directory\"\nrun_from_nonexistent \"mise install\" \"true\" # Should work for global tools\n\n# Test that the warning appears consistently\necho \"Test 9: Verify warning message format\"\ntemp_dir=$(mktemp -d)\ncd \"$temp_dir\"\nrmdir \"$temp_dir\"\n\noutput=$(mise --version 2>&1) || true\nif [[ $output == *\"WARNING\"* ]] && [[ $output == *\"Current directory does not exist\"* ]]; then\n\tok \"Warning message has proper format\"\nelif [[ $output == *\"current directory\"* ]]; then\n\tok \"Warning message mentions directory issue\"\nelse\n\tdebug \"Warning might not be shown for --version: ${output:0:100}...\"\nfi\n\ncd \"$HOME\" || cd / || true\n\necho \"\"\necho \"All non-existent directory tests passed!\"\n"
  },
  {
    "path": "e2e/cli/test_nonexistent_tool",
    "content": "#!/usr/bin/env bash\n# Test behavior with non-existent tools in config\n\nset -euo pipefail\n\n# Disable backtraces for cleaner error messages\nexport RUST_BACKTRACE=0\nexport MISE_FRIENDLY_ERROR=1\n\n# Create mise.toml with a non-existent tool\ncat >mise.toml <<EOF\n[tools]\nnonexistent-tool-xyz = \"1.0.0\"\nEOF\n\necho \"Test 1: mise install should error for non-existent tool in mise.toml\"\nstatus=0\noutput=$(mise install 2>&1) || status=$?\nif [[ $status -ne 0 ]] && [[ $output == *\"nonexistent-tool-xyz not found in mise tool registry\"* ]]; then\n\techo \"✓ Test 1 passed: mise install errors for non-existent tool\"\nelse\n\techo \"✗ Test 1 failed: Expected error for non-existent tool\"\n\techo \"  Status: $status\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\necho \"Test 2: mise use should error for non-existent tool\"\nstatus=0\noutput=$(mise use nonexistent-tool-abc@1.0.0 2>&1) || status=$?\nif [[ $status -ne 0 ]] && [[ $output == *\"nonexistent-tool-abc not found in mise tool registry\"* ]]; then\n\techo \"✓ Test 2 passed: mise use errors for non-existent tool\"\nelse\n\techo \"✗ Test 2 failed: Expected error for non-existent tool\"\n\techo \"  Status: $status\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\necho \"Test 3: mise env should warn but not error for non-existent tool\"\nstatus=0\noutput=$(mise env 2>&1) || status=$?\n# mise env should warn about the non-existent tool but still exit successfully\nif [[ $status -eq 0 ]]; then\n\tif [[ $output == *\"WARN\"* ]] && [[ $output == *\"nonexistent-tool-xyz\"* ]]; then\n\t\techo \"✓ Test 3 passed: mise env warns but does not error\"\n\telse\n\t\techo \"✗ Test 3 failed: Expected warning about nonexistent-tool-xyz\"\n\t\techo \"  Output: $output\"\n\t\texit 1\n\tfi\nelse\n\techo \"✗ Test 3 failed: mise env should not exit with error\"\n\techo \"  Status: $status\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\necho \"Test 4: mise hook-env should not error for non-existent tool\"\nstatus=0\noutput=$(mise hook-env 2>&1) || status=$?\n# mise hook-env is designed for shell integration, so it should silently skip non-existent tools\nif [[ $status -eq 0 ]]; then\n\techo \"✓ Test 4 passed: mise hook-env does not error\"\nelse\n\techo \"✗ Test 4 failed: mise hook-env should not exit with error\"\n\techo \"  Status: $status\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\necho \"Test 5: mise install with explicit non-existent tool should error\"\nstatus=0\noutput=$(mise install nonexistent-explicit-tool@1.0.0 2>&1) || status=$?\nif [[ $status -ne 0 ]] && [[ $output == *\"nonexistent-explicit-tool not found in mise tool registry\"* ]]; then\n\techo \"✓ Test 5 passed: explicit mise install errors for non-existent tool\"\nelse\n\techo \"✗ Test 5 failed: Expected error for non-existent tool\"\n\techo \"  Status: $status\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\necho \"Test 6: mise ls should not list non-existent tool\"\nstatus=0\noutput=$(mise ls nonexistent-tool-xyz 2>&1) || status=$?\n# mise ls should either error or show nothing for a non-existent tool\nif [[ $output != *\"nonexistent-tool-xyz\"*\"1.0.0\"* ]]; then\n\techo \"✓ Test 6 passed: mise ls does not list non-existent tool as installed\"\nelse\n\techo \"✗ Test 6 failed: mise ls should not show non-existent tool\"\n\techo \"  Output: $output\"\n\texit 1\nfi\n\n# Clean up\nrm -f mise.toml\n\necho \"\"\necho \"Non-existent tool tests completed!\"\necho \"\"\necho \"Summary:\"\necho \"  - mise install with config file: ✓ errors as expected\"\necho \"  - mise use: ✓ errors as expected\"\necho \"  - mise env: ✓ warns but succeeds\"\necho \"  - mise hook-env: ✓ silently succeeds\"\necho \"  - mise install explicit: ✓ errors as expected\"\n"
  },
  {
    "path": "e2e/cli/test_outdated",
    "content": "#!/usr/bin/env bash\n\nassert \"mise outdated --json\" \"{}\"\nassert \"mise outdated\" \"\"\n\necho 'dummy 1' >.tool-versions\nmise install dummy@1.0.0\n\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.1.0\"\n\n#mise outdated dummy\n#assert_contains \"mise ls --installed dummy\" \"1.1.0\"\n#assert_not_contains \"mise ls --installed dummy\" \"1.0.0\"\n\nassert \"mise outdated dummy\" \"dummy  1  1.0.0  1.1.0 ~/workdir/.tool-versions\"\nassert \"mise outdated dummy --bump\" \"dummy  1  1.0.0  2  2.0.0 ~/workdir/.tool-versions\"\n\n# Test: --local should only show outdated tools from local config, not global\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1\"\nEOF\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[tools]\ntiny = \"1\"\nEOF\nmise uninstall dummy tiny --all\nmise install dummy@1.0.0 tiny@1.0.0\n# --local should only show dummy (local), not tiny (global)\nassert_contains \"mise outdated --local\" \"dummy\"\nassert_not_contains \"mise outdated --local\" \"tiny\"\n# without --local, both should appear\nassert_contains \"mise outdated\" \"dummy\"\nassert_contains \"mise outdated\" \"tiny\"\nrm -f .tool-versions\nrm -f \"$MISE_CONFIG_DIR/config.toml\"\n\necho 'dummy 1' >.tool-versions\nmise uninstall dummy --all\nmise install dummy@1.0.0\n\nassert \"mise outdated dummy --json | jq -r '.dummy.latest'\" \"1.1.0\"\nassert \"mise outdated dummy --bump --json | jq -r '.dummy.latest'\" \"2.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_prepare",
    "content": "#!/usr/bin/env bash\n\n# Test mise prepare (mise prep) command\n\n# Test --list with no providers configured\nassert_contains \"mise prepare --list\" \"No prepare providers found\"\n\n# Create a package-lock.json (npm provider needs to be configured to detect it)\ncat >package-lock.json <<'EOF'\n{\n  \"name\": \"test-project\",\n  \"lockfileVersion\": 3,\n  \"packages\": {}\n}\nEOF\n\n# Still no providers without explicit config\nassert_contains \"mise prepare --list\" \"No prepare providers found\"\n\n# Configure npm provider explicitly\ncat >mise.toml <<'EOF'\n[prepare.npm]\nEOF\n\n# Now npm provider should be detected\nassert_contains \"mise prepare --list\" \"npm\"\nassert_contains \"mise prepare --list\" \"package-lock.json\"\nassert_contains \"mise prepare --list\" \"node_modules\"\n\n# Test --dry-run shows what would run\nassert_contains \"mise prepare --dry-run\" \"npm\"\n\n# Test alias works\nassert_contains \"mise prep --list\" \"npm\"\n\n# Test with custom prepare provider (no .rules. prefix)\ncat >mise.toml <<'EOF'\n[prepare.npm]\n\n[prepare.codegen]\nsources = [\"schema.graphql\"]\noutputs = [\"generated/\"]\nrun = \"echo codegen\"\nEOF\n\n# Create source file\ntouch schema.graphql\n\nassert_contains \"mise prepare --list\" \"codegen\"\nassert_contains \"mise prepare --list\" \"schema.graphql\"\n\n# Test --only flag\nassert_contains \"mise prepare --dry-run --only codegen\" \"codegen\"\nassert_not_contains \"mise prepare --dry-run --only codegen\" \"npm\"\n\n# Test --skip flag\nassert_not_contains \"mise prepare --dry-run --skip npm\" \"npm install\"\n\n# Test disable in config\ncat >mise.toml <<'EOF'\n[prepare]\ndisable = [\"npm\"]\n\n[prepare.npm]\n\n[prepare.codegen]\nsources = [\"schema.graphql\"]\noutputs = [\"generated/\"]\nrun = \"echo codegen\"\nEOF\n\nassert_not_contains \"mise prepare --list\" \"npm\"\nassert_contains \"mise prepare --list\" \"codegen\"\n\n# Test per-provider auto flag\ncat >mise.toml <<'EOF'\n[prepare.npm]\nauto = true\n\n[prepare.codegen]\nauto = false\nsources = [\"schema.graphql\"]\noutputs = [\"generated/\"]\nrun = \"echo codegen\"\nEOF\n\n# Both should show in list\nassert_contains \"mise prepare --list\" \"npm\"\nassert_contains \"mise prepare --list\" \"codegen\"\n\n# Test yarn provider\nrm -f package-lock.json\ncat >yarn.lock <<'EOF'\n# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.yarn]\nEOF\n\nassert_contains \"mise prepare --list\" \"yarn\"\nassert_contains \"mise prepare --list\" \"yarn.lock\"\nassert_contains \"mise prepare --dry-run\" \"yarn\"\n\n# Test pnpm provider\nrm -f yarn.lock\ncat >pnpm-lock.yaml <<'EOF'\nlockfileVersion: '9.0'\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.pnpm]\nEOF\n\nassert_contains \"mise prepare --list\" \"pnpm\"\nassert_contains \"mise prepare --list\" \"pnpm-lock.yaml\"\nassert_contains \"mise prepare --dry-run\" \"pnpm\"\n\n# Test bun provider (binary lockfile)\nrm -f pnpm-lock.yaml\ntouch bun.lockb\n\ncat >mise.toml <<'EOF'\n[prepare.bun]\nEOF\n\nassert_contains \"mise prepare --list\" \"bun\"\nassert_contains \"mise prepare --list\" \"bun.lockb\"\nassert_contains \"mise prepare --dry-run\" \"bun\"\n\n# Test bun provider (text lockfile)\nrm -f bun.lockb\ncat >bun.lock <<'EOF'\n# bun lockfile\nEOF\n\nassert_contains \"mise prepare --list\" \"bun\"\nassert_contains \"mise prepare --list\" \"bun.lock\"\n\n# Test go provider\nrm -f bun.lock\ncat >go.sum <<'EOF'\ngithub.com/foo/bar v1.0.0 h1:abc\nEOF\ncat >go.mod <<'EOF'\nmodule test\ngo 1.21\nEOF\n# Ensure go.sum (output) is older than go.mod (source) to trigger staleness\ntouch -t 202301010000 go.sum\n\ncat >mise.toml <<'EOF'\n[prepare.go]\nEOF\n\nassert_contains \"mise prepare --list\" \"go\"\nassert_contains \"mise prepare --list\" \"go.sum\"\nassert_contains \"mise prepare --dry-run\" \"go\"\n\n# Test pip provider\nrm -f go.sum go.mod\ncat >requirements.txt <<'EOF'\nrequests==2.31.0\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.pip]\nEOF\n\nassert_contains \"mise prepare --list\" \"pip\"\nassert_contains \"mise prepare --list\" \"requirements.txt\"\nassert_contains \"mise prepare --dry-run\" \"pip\"\n\n# Test poetry provider\nrm -f requirements.txt\ncat >poetry.lock <<'EOF'\n[[package]]\nname = \"requests\"\nversion = \"2.31.0\"\nEOF\ncat >pyproject.toml <<'EOF'\n[tool.poetry]\nname = \"test\"\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.poetry]\nEOF\n\nassert_contains \"mise prepare --list\" \"poetry\"\nassert_contains \"mise prepare --list\" \"poetry.lock\"\nassert_contains \"mise prepare --dry-run\" \"poetry\"\n\n# Test uv provider\nrm -f poetry.lock\ncat >uv.lock <<'EOF'\nversion = 1\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.uv]\nEOF\n\nassert_contains \"mise prepare --list\" \"uv\"\nassert_contains \"mise prepare --list\" \"uv.lock\"\nassert_contains \"mise prepare --dry-run\" \"uv\"\n\n# Test bundler provider\nrm -f uv.lock pyproject.toml\ncat >Gemfile.lock <<'EOF'\nGEM\n  specs:\nEOF\ncat >Gemfile <<'EOF'\nsource 'https://rubygems.org'\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.bundler]\nEOF\n\nassert_contains \"mise prepare --list\" \"bundler\"\nassert_contains \"mise prepare --list\" \"Gemfile.lock\"\nassert_contains \"mise prepare --dry-run\" \"bundler\"\n\n# Test composer provider\nrm -f Gemfile.lock Gemfile\ncat >composer.lock <<'EOF'\n{\n    \"_readme\": [\"This file locks the dependencies\"]\n}\nEOF\ncat >composer.json <<'EOF'\n{}\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.composer]\nEOF\n\nassert_contains \"mise prepare --list\" \"composer\"\nassert_contains \"mise prepare --list\" \"composer.lock\"\nassert_contains \"mise prepare --dry-run\" \"composer\"\n\n# Test freshness detection with content hashing\nrm -f composer.lock composer.json\n\ncat >mise.toml <<'EOF'\n[prepare.custom_venv]\nsources = [\"requirements.txt\"]\noutputs = [\".venv\"]\nrun = \"echo PREPARE_RAN\"\nEOF\n\ncat >requirements.txt <<'EOF'\nrequests==2.31.0\nEOF\n\n# Test 1: No output directory exists → should be stale (outputs missing)\nrm -rf .venv .mise\nassert_contains \"mise prepare --dry-run\" \"custom_venv\"\nassert_contains \"mise prepare --dry-run\" \"outputs missing\"\n\n# Test 2: Run prepare to establish state, then check freshness\nmkdir -p .venv\nassert_contains \"mise prepare --only custom_venv\" \"Prepared: custom_venv\"\n\n# Second run: sources unchanged, should be fresh (content hashes match)\nassert_not_contains \"mise prepare --dry-run\" \"custom_venv\"\n\n# Test 3: Change source content → should be stale\necho \"flask==3.0.0\" >>requirements.txt\nassert_contains \"mise prepare --dry-run\" \"custom_venv\"\nassert_contains \"mise prepare --dry-run\" \"requirements.txt changed\"\n\n# Clean up\nrm -rf .venv requirements.txt .mise\nrm -f composer.lock composer.json package.json mise.toml schema.graphql\n\n# Test --explain flag\ncat >mise.toml <<'EOF'\n[prepare.explain_test]\nauto = true\nsources = [\"src_input.txt\"]\noutputs = [\"out_dir\"]\nrun = \"echo explain_ran\"\nEOF\n\ntouch src_input.txt\n\n# Test --explain with missing output (stale)\nrm -rf out_dir\nmise prepare explain_test --explain >.explain_out 2>&1 || true\nassert_contains \"cat .explain_out\" \"Provider: explain_test\"\nassert_contains \"cat .explain_out\" \"Auto: yes\"\nassert_contains \"cat .explain_out\" \"Sources:\"\nassert_contains \"cat .explain_out\" \"Outputs:\"\nassert_contains \"cat .explain_out\" \"Command: echo explain_ran\"\nassert_contains \"cat .explain_out\" \"stale\"\n\n# Test --explain with fresh output (run prepare first to establish state)\nmkdir -p out_dir\nmise prepare --only explain_test >/dev/null 2>&1 || true\nmise prepare explain_test --explain >.explain_out 2>&1\nassert_contains \"cat .explain_out\" \"Provider: explain_test\"\nassert_contains \"cat .explain_out\" \"fresh\"\n\n# Test --explain with unknown provider\nmise prepare nonexistent --explain >.explain_out 2>&1 || true\nassert_contains \"cat .explain_out\" \"not found\"\n\nrm -rf src_input.txt out_dir mise.toml .explain_out\n\n# Test content-hash freshness: after a successful run, state is saved and provider is fresh\ncat >mise.toml <<'EOF'\n[prepare.hash_test]\nsources = [\"src_file.txt\"]\noutputs = [\"out_dir\"]\nrun = \"echo HASH_RAN\"\nEOF\n\necho \"original content\" >src_file.txt\nmkdir -p out_dir\n\n# First run: should execute (no previous state)\nassert_contains \"mise prepare --only hash_test\" \"Prepared: hash_test\"\n\n# Second run: sources unchanged, should be fresh (hashes saved in state)\nassert_contains \"mise prepare --only hash_test\" \"up to date\"\n\n# Modify source content → should be stale again\necho \"modified content\" >src_file.txt\nassert_contains \"mise prepare --only hash_test\" \"Prepared: hash_test\"\n\n# Third run after re-prepare: fresh again\nassert_contains \"mise prepare --only hash_test\" \"up to date\"\n\nrm -rf src_file.txt out_dir .mise\n\n# Test timeout: a command that exceeds its timeout should fail\ncat >mise.toml <<'EOF'\n[prepare.timeout_test]\nsources = [\"src_file.txt\"]\noutputs = [\"out_dir\"]\nrun = \"sleep 30\"\ntimeout = \"2s\"\nEOF\n\ntouch src_file.txt\nmkdir -p out_dir\n# Make source newer than output so provider is stale\ntouch -t 202501010000 out_dir\ntouch -t 202601010000 src_file.txt\n\n# Should fail because sleep 30 exceeds the 2-second timeout\nassert_fail \"mise prepare --only timeout_test\"\n\nrm -rf src_file.txt out_dir mise.toml\n\n# Test that prepare providers are NOT inherited from parent config files\n# (monorepo scenario: root defines [prepare.pnpm], subdirectory should not inherit it)\nmkdir -p subproject\n\ncat >mise.toml <<'EOF'\n[prepare.custom_root]\nsources = [\"root_input.txt\"]\noutputs = [\"root_output.txt\"]\nrun = \"echo root_ran\"\nEOF\ntouch root_input.txt\n\ncat >subproject/mise.toml <<'EOF'\n[prepare.custom_sub]\nsources = [\"sub_input.txt\"]\noutputs = [\"sub_output.txt\"]\nrun = \"echo sub_ran\"\nEOF\ntouch subproject/sub_input.txt\n\n# From root: only root provider should be visible\nassert_contains \"mise prepare --list\" \"custom_root\"\nassert_not_contains \"mise prepare --list\" \"custom_sub\"\n\n# From subdirectory: only subdirectory provider should be visible, not inherited root\n(\n\tcd subproject\n\tassert_contains \"mise prepare --list\" \"custom_sub\"\n\tassert_not_contains \"mise prepare --list\" \"custom_root\"\n)\n\n# Clean up previous test\nrm -rf subproject root_input.txt root_output.txt mise.toml .mise\n\n# Test that monorepo subdirectory prepare steps run when using //subdir:task from root\nexport MISE_EXPERIMENTAL=1\nmkdir -p subapp\n\ncat >mise.toml <<'EOF'\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"subapp\"]\nEOF\n\ncat >subapp/mise.toml <<'EOF'\n[prepare.subapp_deps]\nauto = true\nsources = [\"input.txt\"]\noutputs = [\"deps_marker\"]\nrun = \"touch deps_marker\"\n\n[tasks.check]\nrun = \"test -f deps_marker && echo SUBAPP_PREPARE_OK || echo SUBAPP_PREPARE_MISSING\"\nEOF\n\ntouch subapp/input.txt\n\n# Run the task from root using monorepo syntax\nassert_contains \"mise run //subapp:check\" \"SUBAPP_PREPARE_OK\"\n\n# Test that prepare steps also run when subtasks are reached via dependencies\ncat >mise.toml <<'EOF'\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"subapp\"]\n\n[tasks.check]\ndepends = \"//...:check\"\nEOF\n\ntouch subapp/input.txt\nrm -f subapp/deps_marker\nassert_contains \"mise run //:check\" \"SUBAPP_PREPARE_OK\"\n\n# Clean up\nrm -rf subapp mise.toml .mise\n\n# Test git-submodule provider\ncat >.gitmodules <<'EOF'\n[submodule \"libs/foo\"]\n\tpath = libs/foo\n\turl = https://example.com/foo.git\n[submodule \"libs/bar\"]\n\tpath = libs/bar\n\turl = https://example.com/bar.git\nEOF\n\ncat >mise.toml <<'EOF'\n[prepare.git-submodule]\nEOF\n\nassert_contains \"mise prepare --list\" \"git-submodule\"\nassert_contains \"mise prepare --list\" \".gitmodules\"\nassert_contains \"mise prepare --list\" \"libs/foo\"\nassert_contains \"mise prepare --list\" \"libs/bar\"\n\n# Test that empty .gitmodules is not applicable\necho -n \"\" >.gitmodules\ncat >mise.toml <<'EOF'\n[prepare.git-submodule]\nEOF\nassert_not_contains \"mise prepare --list\" \"git-submodule\"\n\n# Clean up\nrm -f .gitmodules mise.toml .mise\n\n# Test tera template rendering in prepare.env\ncat >mise.toml <<'EOF'\n[env]\nMY_TEMPLATE_VAR = \"hello_from_env\"\n\n[prepare.env_tera]\nsources = [\"tera_input.txt\"]\noutputs = [\"tera_output.txt\"]\nrun = \"bash -c 'echo $RENDERED_VAR > tera_output.txt'\"\n\n[prepare.env_tera.env]\nRENDERED_VAR = \"{{env.MY_TEMPLATE_VAR}}\"\nPLAIN_VAR = \"no_template\"\nEOF\n\ntouch tera_input.txt\n\n# Prepare should run successfully\nassert_contains \"mise prepare --only env_tera\" \"env_tera\"\n\n# The output file should contain the rendered value, not the raw template\nassert_contains \"cat tera_output.txt\" \"hello_from_env\"\nassert_not_contains \"cat tera_output.txt\" \"{{env.MY_TEMPLATE_VAR}}\"\n\n# Clean up\nrm -f tera_input.txt tera_output.txt mise.toml\nrm -rf .mise\n\n# Test dir option affects source/output resolution for custom providers\nmkdir -p subdir\necho '{\"name\": \"test\"}' >subdir/package.json\necho '{\"lockfileVersion\": 3}' >subdir/package-lock.json\n\ncat >mise.toml <<'EOF'\n[prepare.subdir_custom]\ndir = \"subdir\"\nsources = [\"package.json\", \"package-lock.json\"]\noutputs = [\"build_output\"]\nrun = \"echo SUBDIR_RAN\"\nEOF\n\n# Sources should resolve against subdir, not project root\nassert_contains \"mise prepare --list\" \"subdir_custom\"\nassert_contains \"mise prepare --list\" \"subdir/package.json\"\nassert_contains \"mise prepare --list\" \"subdir/package-lock.json\"\n\n# Run prepare and verify source hashes are tracked (provider becomes fresh)\nmkdir -p subdir/build_output\nassert_contains \"mise prepare --only subdir_custom\" \"Prepared: subdir_custom\"\n\n# Second run should be fresh (sources hashed correctly via subdir)\nassert_contains \"mise prepare --only subdir_custom\" \"up to date\"\n\n# Modify source in subdir → should be stale\necho '{\"name\": \"modified\"}' >subdir/package.json\nassert_contains \"mise prepare --only subdir_custom\" \"Prepared: subdir_custom\"\n\n# Clean up\nrm -rf subdir mise.toml .mise\n"
  },
  {
    "path": "e2e/cli/test_prepare_depends",
    "content": "#!/usr/bin/env bash\n\n# Test prepare dependency ordering\n# Verifies that prepare providers with `depends` run in the correct order\n\n# Create source files so providers are stale\ntouch schema.graphql\ntouch requirements.txt\n\ncat >mise.toml <<'EOF'\n[prepare.step-a]\nrun = \"bash -c 'echo STEP-A >> prepare.log'\"\nsources = [\"schema.graphql\"]\noutputs = [\"gen-a\"]\ndescription = \"step-a\"\n\n[prepare.step-b]\nrun = \"bash -c 'echo STEP-B >> prepare.log'\"\nsources = [\"requirements.txt\"]\noutputs = [\"gen-b\"]\ndepends = [\"step-a\"]\ndescription = \"step-b\"\n\n[prepare.step-c]\nrun = \"bash -c 'echo STEP-C >> prepare.log'\"\nsources = [\"requirements.txt\"]\noutputs = [\"gen-c\"]\ndepends = [\"step-b\"]\ndescription = \"step-c\"\nEOF\n\n# Force run to ensure all steps execute\nmise prepare --force 2>&1\n\n# Verify all steps ran and in dependency order (a before b before c)\nassert \"cat prepare.log\" \"STEP-A\nSTEP-B\nSTEP-C\"\n\n# Clean up for next test\nrm -f prepare.log\n\n# Test that independent steps can still run in parallel alongside deps\ncat >mise.toml <<'EOF'\n[prepare.dep-first]\nrun = \"bash -c 'echo DEP-FIRST >> prepare2.log'\"\nsources = [\"schema.graphql\"]\noutputs = [\"gen-dep-first\"]\ndescription = \"dep-first\"\n\n[prepare.dep-second]\nrun = \"bash -c 'echo DEP-SECOND >> prepare2.log'\"\nsources = [\"requirements.txt\"]\noutputs = [\"gen-dep-second\"]\ndepends = [\"dep-first\"]\ndescription = \"dep-second\"\n\n[prepare.independent]\nrun = \"bash -c 'echo INDEPENDENT >> prepare2.log'\"\nsources = [\"schema.graphql\"]\noutputs = [\"gen-independent\"]\ndescription = \"independent\"\nEOF\n\nmise prepare --force 2>&1\n\n# dep-first must appear before dep-second\noutput=$(cat prepare2.log)\nassert_contains \"echo '$output'\" \"DEP-FIRST\"\nassert_contains \"echo '$output'\" \"DEP-SECOND\"\nassert_contains \"echo '$output'\" \"INDEPENDENT\"\n\n# Verify dep-first is before dep-second in the log\ndep_first_line=$(grep -n \"DEP-FIRST\" prepare2.log | head -1 | cut -d: -f1)\ndep_second_line=$(grep -n \"DEP-SECOND\" prepare2.log | head -1 | cut -d: -f1)\nif [[ $dep_first_line -ge $dep_second_line ]]; then\n\techo \"ERROR: DEP-FIRST (line $dep_first_line) should appear before DEP-SECOND (line $dep_second_line)\"\n\texit 1\nfi\n\nrm -f prepare2.log\n\n# Test dry-run with depends shows what would run\nassert_contains \"mise prepare --dry-run\" \"dep-first\"\n"
  },
  {
    "path": "e2e/cli/test_prepare_tool_install",
    "content": "#!/usr/bin/env bash\n\n# Test that tools from [tools] are installed BEFORE prepare steps run\n# Regression test: prepare steps that depend on mise-managed tools\n# should not fail because the tool hasn't been installed yet.\n\ncat <<'EOF' >mise.toml\n[tools]\ntiny = \"1\"\n\n[prepare.needs_tool]\nauto = true\nsources = [\"input.txt\"]\noutputs = [\"output.txt\"]\nrun = \"rtx-tiny > output.txt\"\nEOF\n\ntouch input.txt\n\n# Remove tiny if installed so we test the install-before-prepare path\nrm -rf \"${MISE_DATA_DIR}/installs/tiny/1\"* 2>/dev/null || true\n\n# mise prepare should install tiny THEN run the prepare step (which uses tiny)\nassert_contains \"mise prepare --only needs_tool\" \"Prepared: needs_tool\"\nassert_contains \"cat output.txt\" \"rtx-tiny\"\n\n# Clean up\nrm -f mise.toml input.txt output.txt\n"
  },
  {
    "path": "e2e/cli/test_prune",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use dummy@2.0.0 tiny@2.0.0\"\nassert \"mise use dummy@3.0.0 tiny@3.0.0\"\ncd \"$(mktemp -d)\" || exit 1 # mise should not prune these files even though they're from some other directory\n\nassert_contains \"mise prune --dry-run 2>&1\" \"mise dummy@2.0.0 [dryrun]\"\nassert_contains \"mise prune --dry-run 2>&1\" \"mise tiny@2.0.0 [dryrun]\"\n\n# Test: --dry-run-code should exit non-zero when there are tools to prune\nassert_fail_contains \"mise prune --dry-run-code 2>&1\" \"[dryrun]\"\n# Verify nothing was actually pruned\nassert \"ls $MISE_DATA_DIR/installs/dummy/2.0.0\"\nassert \"ls $MISE_DATA_DIR/installs/tiny/2.0.0\"\nassert \"mise prune tiny\"\nassert \"ls $MISE_DATA_DIR/installs/dummy/2.0.0\"\nassert_fail \"ls $MISE_DATA_DIR/installs/tiny/2.0.0\"\nassert \"mise prune\"\nassert_fail \"ls $MISE_DATA_DIR/installs/dummy/2.0.0\"\nassert \"ls $MISE_DATA_DIR/installs/dummy/3.0.0\"\nassert \"ls $MISE_DATA_DIR/installs/tiny/3.0.0\"\n\n# Test: --dry-run-code should exit 0 when there is nothing to prune\nassert_succeed \"mise prune --dry-run-code 2>&1\"\n"
  },
  {
    "path": "e2e/cli/test_registry",
    "content": "#!/usr/bin/env bash\n\nassert \"mise registry gh\" \"aqua:cli/cli asdf:bartlomiejdanek/asdf-github-cli\"\nassert_contains \"mise registry\" \"gh                            aqua:cli/cli asdf:bartlomiejdanek/asdf-github-cli\"\n\n# --json flag tests\nassert \"mise registry gh --json | jq -r '.short'\" \"gh\"\nassert \"mise registry gh --json | jq -r '.backends[0]'\" \"aqua:cli/cli\"\nassert_contains \"mise registry --json | jq -r '.[].short'\" \"gh\"\nassert \"mise registry --json | jq -r '.[] | select(.short == \\\"gh\\\") | .backends[0]'\" \"aqua:cli/cli\"\n"
  },
  {
    "path": "e2e/cli/test_search",
    "content": "#!/usr/bin/env bash\n\nassert \"mise search jq\" \"jq    Command-line JSON processor. https://github.com/jqlang/jq\njqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\njaq   A jq clone focussed on correctness, speed, and simplicity. https://github.com/01mf02/jaq\njiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\ngojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\"\n\nassert \"mise search --match-type contains jq\" \"gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\njq    Command-line JSON processor. https://github.com/jqlang/jq\njqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\"\n\nassert \"mise search --match-type equal jq\" \"jq  Command-line JSON processor. https://github.com/jqlang/jq\"\n"
  },
  {
    "path": "e2e/cli/test_set",
    "content": "#!/usr/bin/env bash\n\nassert \"mise set FOO=bar\" \"\"\nassert \"mise set FOO\" \"bar\"\nassert \"mise set\" \"FOO  bar ~/workdir/mise.toml\"\nassert \"mise set --rm FOO\" \"\"\nassert_fail \"mise set FOO\" \"Environment variable FOO not found\"\n\nassert \"mise set --file .test.mise.toml FOO=bar\" \"\"\nassert \"mise set --file .test.mise.toml FOO\" \"bar\"\n\n# Test -E flag for environment-specific config files\nassert \"mise set -E staging STAGING_VAR=staging_value\" \"\"\nassert \"mise set -E staging STAGING_VAR\" \"staging_value\"\nassert \"mise set -E staging\" \"STAGING_VAR  staging_value ~/workdir/mise.staging.toml\"\n\n# Test that -E flag only shows vars from that environment file\nassert \"mise set -E production PROD_VAR=prod_value\" \"\"\nassert \"mise set -E production\" \"PROD_VAR  prod_value ~/workdir/mise.production.toml\"\n# STAGING_VAR should not appear when reading production env\nassert_not_contains \"mise set -E production\" \"STAGING_VAR\"\n\n# Test that regular set doesn't show env-specific vars\nassert_not_contains \"mise set\" \"STAGING_VAR\"\nassert_not_contains \"mise set\" \"PROD_VAR\"\n\n# Test that mise set writes to mise.toml (lowest precedence) instead of mise.local.toml\n# when both exist. See: https://github.com/jdx/mise/discussions/6475\nrm -f mise.toml mise.local.toml\necho '[env]' >mise.toml\necho 'BASE_VAR = \"base\"' >>mise.toml\necho '[env]' >mise.local.toml\necho 'LOCAL_VAR = \"local\"' >>mise.local.toml\nassert \"mise set NEW_VAR=new_value\" \"\"\nassert_contains \"cat mise.toml\" \"NEW_VAR\"\nassert_not_contains \"cat mise.local.toml\" \"NEW_VAR\"\n\n# Test --stdin reads multiline value\nassert \"printf 'line1\\nline2' | mise set --stdin MULTI_LINE\" \"\"\nassert \"mise set MULTI_LINE\" \"line1\nline2\"\nassert \"mise set --rm MULTI_LINE\" \"\"\n\n# Test --stdin strips trailing newline\nassert \"printf 'hello\\n' | mise set --stdin TRAILING_NL\" \"\"\nassert \"mise set TRAILING_NL\" \"hello\"\nassert \"mise set --rm TRAILING_NL\" \"\"\n\n# Test --stdin fails with multiple keys\nassert_fail \"printf 'val' | mise set --stdin KEY1 KEY2\"\n\n# Test --stdin fails with KEY=VALUE syntax\nassert_fail \"printf 'val' | mise set --stdin KEY1=value\"\n\n# Test that `mise set` redacts values marked with redact=true\nrm -f mise.toml\ncat <<EOF >mise.toml\n[env]\nSECRET = {value = \"my_secret_value\", redact = true}\nNORMAL = \"normal_value\"\nEOF\nassert_contains \"mise set\" \"[redacted]\"\nassert_not_contains \"mise set\" \"my_secret_value\"\nassert_contains \"mise set\" \"normal_value\"\n\n# Test --no-redact shows raw values\nassert_contains \"mise set --no-redact\" \"my_secret_value\"\nassert_not_contains \"mise set --no-redact\" \"[redacted]\"\n\n# Test redactions array with mise set\nrm -f mise.toml\ncat <<EOF >mise.toml\nredactions = [\"DB_*\"]\n[env]\nDB_PASSWORD = \"super_secret\"\nUSERNAME = \"john\"\nEOF\nassert_contains \"mise set\" \"[redacted]\"\nassert_not_contains \"mise set\" \"super_secret\"\nassert_contains \"mise set\" \"john\"\nassert_contains \"mise set --no-redact\" \"super_secret\"\n\n# Test redaction with --file flag\nrm -f mise.toml\ncat <<EOF >mise.toml\n[env]\nFILE_SECRET = {value = \"file_secret_val\", redact = true}\nEOF\nassert_contains \"mise set --file mise.toml\" \"[redacted]\"\nassert_not_contains \"mise set --file mise.toml\" \"file_secret_val\"\nassert_contains \"mise set --file mise.toml --no-redact\" \"file_secret_val\"\n\n# Test redaction with --file pointing outside config hierarchy\ntmpfile=\"$(mktemp)\"\ncat <<EOF >\"$tmpfile\"\n[env]\nOUT_SECRET = {value = \"out_of_hierarchy_secret\", redact = true}\nOUT_NORMAL = \"out_normal\"\nEOF\nassert_contains \"mise set --file $tmpfile\" \"[redacted]\"\nassert_not_contains \"mise set --file $tmpfile\" \"out_of_hierarchy_secret\"\nassert_contains \"mise set --file $tmpfile\" \"out_normal\"\nassert_contains \"mise set --file $tmpfile --no-redact\" \"out_of_hierarchy_secret\"\nrm -f \"$tmpfile\"\n"
  },
  {
    "path": "e2e/cli/test_set_env",
    "content": "#!/usr/bin/env bash\n\n# Create an initial mise.toml file to reproduce the issue\necho '[tools]\nnode = \"20\"' >mise.toml\n\n# This should create mise.pp.toml (environment-specific) instead of modifying mise.toml\n# Currently this fails because the -E flag doesn't exist\nif mise set -E pp NODE_ENV=production 2>/dev/null; then\n\t# If the command succeeded, check if it created the environment-specific file\n\tif [[ -f \"mise.pp.toml\" ]]; then\n\t\tassert \"cat mise.pp.toml\" '[env]\nNODE_ENV = \"production\"'\n\t\t# Ensure original mise.toml wasn't modified\n\t\tassert \"cat mise.toml\" '[tools]\nnode = \"20\"'\n\telse\n\t\techo \"ERROR: mise set -E pp should create mise.pp.toml but it doesn't exist\"\n\t\texit 1\n\tfi\nelse\n\techo \"Expected: mise set -E flag should exist and work\"\n\techo \"Actual: mise set command doesn't support -E flag\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/cli/test_set_use_consistency",
    "content": "#!/usr/bin/env bash\n\n# Test to verify inconsistent behavior between `mise set` and `mise use`\n# This test documents the current broken behavior that needs to be fixed\n\nset -euo pipefail\n\n# Track test failures\ntest_failures=0\n\n# Disable trust checking for this test\nexport MISE_TRUSTED_CONFIG_PATHS=\"/\"\n\noriginal_home=\"$HOME\"\ntest_home=\"/tmp/test_home_$$\"\ntest_project=\"/tmp/test_project_$$\"\n\n# Set up test environment\nmkdir -p \"$test_home/.config/mise\"\nmkdir -p \"$test_project\"\nexport HOME=\"$test_home\"\n\ncleanup() {\n\texport HOME=\"$original_home\"\n\trm -rf \"$test_home\" \"$test_project\"\n\tif [ $test_failures -gt 0 ]; then\n\t\techo \"❌ Test failed with $test_failures failures\"\n\t\texit 1\n\tfi\n}\ntrap cleanup EXIT\n\necho \"=== Testing consistent behavior between commands ===\"\ncd \"$test_home\"\n\n# Test 1: Both commands should handle global config consistently when explicitly requested\necho \"Test 1: Both commands should handle --global flag consistently\"\nmise use --global dummy@1.0.0 >/dev/null 2>&1\nmise set --global TEST_VAR=test_value >/dev/null 2>&1\necho \"✓ Both commands accept --global flag without errors\"\n# Note: The actual global config functionality is tested elsewhere\n# This test focuses on config resolution consistency, which is the main PR goal\n\necho \"=== Testing behavior in project directory ===\"\ncd \"$test_project\"\n\n# Test 3: In project dir, both should create local config\necho \"Test 3: Both commands should create local config in project\"\nmise set PROJECT_VAR=project_value\nif [ -f \"$test_project/mise.toml\" ]; then\n\techo \"✓ mise set created local config\"\n\trm \"$test_project/mise.toml\"\nelse\n\techo \"✗ mise set did not create local config\"\n\ttest_failures=$((test_failures + 1))\nfi\n\nmise use dummy@1.0.0 || echo \"mise use failed (expected if dummy not installed)\"\nif [ -f \"$test_project/mise.toml\" ]; then\n\techo \"✓ mise use created local config\"\n\trm \"$test_project/mise.toml\"\nelse\n\techo \"✗ mise use did not create local config\"\n\ttest_failures=$((test_failures + 1))\nfi\n\necho \"=== Testing --path/--file directory handling ===\"\n\n# Test 4: mise use supports --path with directory\necho \"Test 4: mise use --path with directory\"\nmkdir -p \"$test_project/subdir\"\nmise use --path \"$test_project/subdir\" dummy@1.0.0 || echo \"mise use failed (expected if dummy not installed)\"\nif [ -f \"$test_project/subdir/mise.toml\" ]; then\n\techo \"✓ mise use --path with directory worked\"\n\trm \"$test_project/subdir/mise.toml\"\nelse\n\techo \"✗ mise use --path with directory failed\"\n\ttest_failures=$((test_failures + 1))\nfi\n\n# Test 5: mise set --file should support directory (like mise use --path)\necho \"Test 5: mise set --file with directory should work like mise use --path\"\nif mise set --file \"$test_project/subdir\" TEST_VAR=test; then\n\techo \"✓ mise set --file with directory worked\"\n\tif [ -f \"$test_project/subdir/mise.toml\" ]; then\n\t\techo \"✓ mise set created config file in directory\"\n\t\trm \"$test_project/subdir/mise.toml\"\n\telse\n\t\techo \"✗ mise set did not create config file in directory\"\n\t\ttest_failures=$((test_failures + 1))\n\tfi\nelse\n\techo \"✗ mise set --file with directory failed\"\n\ttest_failures=$((test_failures + 1))\nfi\n\necho \"=== Testing environment-specific configs ===\"\n\n# Test 6: Both should handle --env consistently\necho \"Test 6: Environment-specific config handling\"\ncd \"$test_project\"\n\nmise use --env staging dummy@1.0.0 || echo \"mise use failed (expected if dummy not installed)\"\nstaging_file_use=\"\"\nif [ -f \"mise.staging.toml\" ]; then\n\tstaging_file_use=\"mise.staging.toml\"\nelif [ -f \".mise.staging.toml\" ]; then\n\tstaging_file_use=\".mise.staging.toml\"\nfi\n\nmise set --env staging STAGING_VAR=staging_value\nstaging_file_set=\"\"\nif [ -f \"mise.staging.toml\" ]; then\n\tstaging_file_set=\"mise.staging.toml\"\nelif [ -f \".mise.staging.toml\" ]; then\n\tstaging_file_set=\".mise.staging.toml\"\nfi\n\nif [ \"$staging_file_use\" = \"$staging_file_set\" ] && [ -n \"$staging_file_use\" ]; then\n\techo \"✓ Both commands use same staging config file: $staging_file_use\"\n\trm \"$staging_file_use\"\nelse\n\techo \"✗ Commands use different staging config files:\"\n\techo \"  mise use: $staging_file_use\"\n\techo \"  mise set: $staging_file_set\"\n\ttest_failures=$((test_failures + 1))\n\t[ -n \"$staging_file_use\" ] && rm \"$staging_file_use\"\n\t[ -n \"$staging_file_set\" ] && rm \"$staging_file_set\"\nfi\n\necho \"=== Testing config file precedence ===\"\n\n# Test 7: Create hierarchy and see where each command writes\necho \"Test 7: Config file precedence handling\"\ncd \"$test_project\"\n\n# Create parent directory with config\nmkdir -p parent\necho '[env]' >parent/mise.toml\necho 'PARENT_VAR = \"parent\"' >>parent/mise.toml\n\n# Create subdirectory\nmkdir -p parent/child\ncd parent/child\n\necho \"Current directory: $(pwd)\"\necho \"Parent config exists: $([ -f ../mise.toml ] && echo yes || echo no)\"\n\n# Test where each command writes when parent has config\nmise use --pin dummy@1.0.0 || echo \"mise use failed (expected if dummy not installed)\"\nuse_created_local=$([ -f mise.toml ] && echo yes || echo no)\n\nmise set CHILD_VAR=child_value\nset_created_local=$([ -f mise.toml ] && echo yes || echo no)\n\necho \"mise use created local config: $use_created_local\"\necho \"mise set created local config: $set_created_local\"\n\nif [ \"$use_created_local\" = \"$set_created_local\" ]; then\n\techo \"✓ Both commands handle precedence consistently\"\nelse\n\techo \"✗ Commands handle precedence differently (INCONSISTENT)\"\n\ttest_failures=$((test_failures + 1))\nfi\n"
  },
  {
    "path": "e2e/cli/test_settings_add",
    "content": "#!/usr/bin/env bash\n\n# mise should ignore identical values which have been passed using `add`\nassert \"mise settings add disable_hints a\" \"\"\nassert \"mise settings add disable_hints b\" \"\"\nassert \"mise settings get disable_hints\" '[\"a\", \"b\"]'\nassert \"mise settings add disable_hints a\" \"\"\nassert \"grep disable_hints ~/.config/mise/config.toml\" 'disable_hints = [\"a\", \"b\"]'\n\nassert \"mise settings add idiomatic_version_file_enable_tools python\" \"\"\nassert \"mise settings add idiomatic_version_file_enable_tools rust\" \"\"\nassert \"mise settings get idiomatic_version_file_enable_tools\" '[\"python\", \"rust\"]'\nassert \"mise settings add idiomatic_version_file_enable_tools python,rust,zig\" \"\"\nassert \"grep idiomatic_version_file_enable_tools ~/.config/mise/config.toml\" 'idiomatic_version_file_enable_tools = [\"python\", \"rust\", \"zig\"]'\n\n# test \"settings add key=value\" format\nassert \"mise settings add disable_hints=c\" \"\"\nassert \"mise settings get disable_hints\" '[\"a\", \"b\", \"c\"]'\n\n# test \"settings add\" with no value and no = fails\nassert_fail \"mise settings add disable_hints\"\n"
  },
  {
    "path": "e2e/cli/test_settings_ls",
    "content": "#!/usr/bin/env bash\n\necho \"settings.all_compile = false\" >mise.toml\necho 'settings.disable_backends = [\"rust\", \"java\"]' >>mise.toml\n\nassert_contains \"mise settings\" 'all_compile       false            ~/workdir/mise.toml\ndisable_backends  [\"rust\", \"java\"] ~/workdir/mise.toml'\n\nassert_contains \"mise settings --json\" '{\n  \"all_compile\": false,\n  \"disable_backends\": [\n    \"rust\",\n    \"java\"\n  ]\n}'\n\nassert_contains \"mise settings --toml\" 'all_compile = false\ndisable_backends = [\"rust\", \"java\"]'\n\nassert_contains \"mise settings --json-extended\" \"{\n  \\\"all_compile\\\": {\n    \\\"value\\\": false,\n    \\\"type\\\": \\\"boolean\\\",\n    \\\"description\\\": \\\"do not use precompiled binaries for any tool\\\",\n    \\\"source\\\": \\\"$HOME/workdir/mise.toml\\\"\n  },\n  \\\"disable_backends\\\": {\n    \\\"value\\\": [\n      \\\"rust\\\",\n      \\\"java\\\"\n    ],\n    \\\"type\\\": \\\"array\\\",\n    \\\"description\\\": \\\"Backends to disable such as \\`asdf\\` or \\`pipx\\`\\\",\n    \\\"source\\\": \\\"$HOME/workdir/mise.toml\\\"\n  }\n}\"\n\nassert_contains \"mise settings ls -T\" \"all_compile = false\"\n"
  },
  {
    "path": "e2e/cli/test_settings_set",
    "content": "#!/usr/bin/env bash\n\nmise settings set legacy_version_file 0\nassert \"mise settings get legacy_version_file\" \"false\"\nmise settings set always_keep_download y\nassert \"mise settings get always_keep_download\" \"true\"\nmise settings set status.missing_tools never\nassert \"mise settings get status.missing_tools\" 'never'\nmise settings set plugin_autoupdate_last_check_duration 1\nassert \"mise settings get plugin_autoupdate_last_check_duration\" '1'\nmise settings set all_compile 1\nassert_contains \"mise settings -T\" \"all_compile = true\"\nmise settings unset all_compile\nassert \"mise settings get all_compile\" \"false\"\nassert_fail \"mise settings get abcdefg\" \"mise ERROR Unknown setting: abcdefg\"\nassert \"mise settings all_compile\" \"false\"\nassert \"mise settings all_compile=1\"\nassert \"mise settings all_compile\" \"true\"\nassert \"mise settings all_compile=0\"\nassert \"mise settings all_compile\" \"false\"\nassert \"mise settings -l\" \"\"\nassert \"mise settings -l all_compile=1\"\nassert \"mise settings -l\" \"all_compile  true ~/workdir/mise.toml\"\nassert \"mise settings all_compile\" \"true\"\nassert \"mise settings all_compile=0\"\nassert \"mise settings all_compile\" \"true\"\nassert \"mise settings -l set all_compile 0\"\nassert \"mise settings all_compile\" \"false\"\n\n# test \"settings set key=value\" format\nmise settings -l unset all_compile\nassert \"mise settings set all_compile=1\"\nassert \"mise settings all_compile\" \"true\"\nassert \"mise settings set all_compile=0\"\nassert \"mise settings all_compile\" \"false\"\n\n# test \"settings set key=value\" with dotted keys\nmise settings set status.missing_tools=always\nassert \"mise settings get status.missing_tools\" \"always\"\nmise settings set status.missing_tools=never\nassert \"mise settings get status.missing_tools\" \"never\"\n\n# test \"settings set\" with no value and no = fails\nassert_fail \"mise settings set all_compile\"\n"
  },
  {
    "path": "e2e/cli/test_settings_unset",
    "content": "#!/usr/bin/env bash\n\nmise settings set python.compile true\nassert \"mise settings get python.compile\" \"true\"\nmise settings unset python.compile\nassert_fail \"mise settings get python.compile\" \"mise ERROR Unknown setting: python.compile\"\n"
  },
  {
    "path": "e2e/cli/test_shared_install_dirs",
    "content": "#!/usr/bin/env bash\n\n# Test that MISE_SHARED_INSTALL_DIRS allows fallback to shared directories\n\n# Install tiny into the primary directory\nmise install tiny@1.0.1\n\n# Verify it's installed\nassert_contains \"mise ls tiny\" \"1.0.1\"\n\n# Create a shared install directory with a different version\nshared_dir=\"$PWD/tmp/shared-installs\"\nmkdir -p \"$shared_dir/tiny/2.0.0/bin\"\necho \"2.0.0\" >\"$shared_dir/tiny/2.0.0/VERSION\"\ncat >\"$shared_dir/tiny/2.0.0/bin/tiny\" <<'SCRIPT'\n#!/usr/bin/env bash\necho \"2.0.0\"\nSCRIPT\nchmod +x \"$shared_dir/tiny/2.0.0/bin/tiny\"\n\n# Write a manifest for the shared directory\ncat >\"$shared_dir/.mise-installs.toml\" <<'TOML'\n[tiny]\nshort = \"tiny\"\nfull = \"asdf:tiny\"\nexplicit_backend = true\nTOML\n\n# Set shared install dirs and verify the version from the shared dir is visible\nexport MISE_SHARED_INSTALL_DIRS=\"$shared_dir\"\nassert_contains \"mise ls tiny --installed\" \"2.0.0\"\nassert_contains \"mise ls tiny --installed\" \"1.0.1\"\n\n# Use the shared version by setting it in config\necho -e \"[tools]\\ntiny = \\\"2.0.0\\\"\" >mise.toml\nassert \"mise x -- tiny\" \"2.0.0\"\n\n# Verify shared version is treated as already installed (no re-install to primary)\nprimary_install=\"$MISE_DATA_DIR/installs/tiny/2.0.0\"\nmise install tiny@2.0.0\nassert_fail \"ls $primary_install\"\n\n# --force installs into primary dir, not the shared dir\nmise install --force tiny@2.0.0\nassert_contains \"ls $primary_install\" \"VERSION\"\n# Shared dir should be untouched\nassert_contains \"ls $shared_dir/tiny/2.0.0\" \"VERSION\"\n# Clean up the primary copy for the next test\nrm -rf \"$primary_install\"\n\n# Primary version (1.0.1) can be uninstalled without affecting shared version (2.0.0)\nmise uninstall tiny@1.0.1\nassert_fail \"ls $MISE_DATA_DIR/installs/tiny/1.0.1\"\nassert \"mise x -- tiny\" \"2.0.0\"\n\n# Clean up\nrm -rf \"$shared_dir\" mise.toml\n"
  },
  {
    "path": "e2e/cli/test_shell_alias",
    "content": "#!/usr/bin/env bash\n\n# Test 1: Shell alias is set when entering directory with [shell_alias]\ncat >mise.toml <<'EOF'\n[shell_alias]\nll = \"ls -la\"\nmytest = \"echo hello from alias\"\nEOF\n\n# First hook-env call should output alias commands (no session yet)\n# We don't call activate first to test fresh session behavior\nunset __MISE_SESSION\nunset __MISE_DIFF\nassert_contains \"mise hook-env -s bash --force\" \"alias ll='ls -la'\"\nassert_contains \"mise hook-env -s bash --force\" \"alias mytest='echo hello from alias'\"\n\n# Now eval to establish session\neval \"$(mise hook-env -s bash --force)\"\n\n# Test 2: Alias change triggers new alias command\ncat >mise.toml <<'EOF'\n[shell_alias]\nll = \"ls -lah\"\nmytest = \"echo hello from alias\"\nEOF\n\n# Changed alias should be re-emitted\nassert_contains \"mise hook-env -s bash --force\" \"alias ll='ls -lah'\"\n\n# Update session\neval \"$(mise hook-env -s bash --force)\"\n\n# Test 3: Alias is unset when removed from config\ncat >mise.toml <<'EOF'\n[shell_alias]\nmytest = \"echo hello from alias\"\nEOF\n\n# ll was removed, should be unaliased\nassert_contains \"mise hook-env -s bash --force\" \"unalias ll\"\n\n# Update session\neval \"$(mise hook-env -s bash --force)\"\n\n# Test 4: Alias with special characters in command\ncat >mise.toml <<'EOF'\n[shell_alias]\ngreet = \"echo 'Hello, World!'\"\nEOF\n\n# New alias should be set, mytest should be unaliased\nassert_contains \"mise hook-env -s bash --force\" \"alias greet=\"\nassert_contains \"mise hook-env -s bash --force\" \"unalias mytest\"\n\n# Update session\neval \"$(mise hook-env -s bash --force)\"\n\n# Test 5: All aliases removed when config is empty\ncat >mise.toml <<'EOF'\n# empty config - no shell_alias section\nEOF\n\n# greet was removed, should be unaliased\nassert_contains \"mise hook-env -s bash --force\" \"unalias greet\"\n\n# Test 6: shell-alias set key=value format\nmise shell-alias set myalias=\"echo test\"\nassert \"mise shell-alias get myalias\" \"echo test\"\n\n# shell-alias set with separate args still works\nmise shell-alias set myalias2 \"echo test2\"\nassert \"mise shell-alias get myalias2\" \"echo test2\"\n\n# shell-alias set with no value and no = fails\nassert_fail \"mise shell-alias set myalias3\"\n"
  },
  {
    "path": "e2e/cli/test_shell_alias_fish.fish",
    "content": "#!/usr/bin/env fish\n\n# Test fish shell alias completions are properly managed\n\n# Test 1: Shell alias set includes complete -e to clear stale completions\nprintf '[shell_alias]\\nll = \"ls -la\"\\n' >mise.toml\n\nset -e __MISE_SESSION\nset -e __MISE_DIFF\nset output (mise hook-env -s fish --force)\nstring match -q '*complete -e ll*' -- $output; or begin; echo \"FAIL: expected 'complete -e ll' in set_alias output\"; exit 1; end\nstring match -q '*alias ll*' -- $output; or begin; echo \"FAIL: expected 'alias ll' in set_alias output\"; exit 1; end\n\n# Establish session\nmise hook-env -s fish --force | source\n\n# Test 2: Alias removal includes complete -e to clean up leaked completions\nprintf '# empty config\\n' >mise.toml\n\nset output (mise hook-env -s fish --force)\nstring match -q '*complete -e ll*' -- $output; or begin; echo \"FAIL: expected 'complete -e ll' in unset_alias output\"; exit 1; end\nstring match -q '*functions -e ll*' -- $output; or begin; echo \"FAIL: expected 'functions -e ll' in unset_alias output\"; exit 1; end\n"
  },
  {
    "path": "e2e/cli/test_shell_alias_template_watch",
    "content": "#!/usr/bin/env bash\n\n# Test that shell aliases using template functions like read_file()\n# update when the referenced file changes, without needing to cd away and back.\n# See: https://github.com/jdx/mise/discussions/8121\n\n# Create a file that will be read by the template\necho \"initial value\" >dynamic.txt\n\ncat >mise.toml <<'EOF'\n[shell_alias]\ndebug = \"echo '{{ read_file(path='dynamic.txt') | trim }}'\"\nEOF\n\n# Establish initial session\nunset __MISE_SESSION\nunset __MISE_DIFF\nassert_contains \"mise hook-env -s bash --force\" \"initial value\"\neval \"$(mise hook-env -s bash --force)\"\n\n# Change the referenced file (NOT the config file)\nsleep 1 # ensure mtime difference even on filesystems with 1-second resolution\necho \"updated value\" >dynamic.txt\n\n# hook-env should detect the file change and re-evaluate the template\n# Without the fix, this will produce no output (fast-path exit) because\n# only mise.toml mtime is checked, not dynamic.txt\noutput=$(mise hook-env -s bash)\nif [[ $output == *\"updated value\"* ]]; then\n\tok \"alias updated after referenced file changed\"\nelse\n\tfail \"expected alias with 'updated value' but got: '$output'\"\nfi\n"
  },
  {
    "path": "e2e/cli/test_shims",
    "content": "#!/usr/bin/env bash\n\nexport PATH=\"$MISE_DATA_DIR/shims:$PATH\"\n\nassert_fail \"which dummy\"\n\nmise i dummy@latest\nassert_contains \"which dummy\" \"/mise/shims/dummy\"\n\nmise uninstall -a dummy\nassert_fail \"which dummy\"\n"
  },
  {
    "path": "e2e/cli/test_shims_fallback",
    "content": "#!/usr/bin/env bash\n\neval \"$(mise activate bash --shims)\"\nmise i dummy@1.0.0 tiny@1.0.0\n\ncat >mise.toml <<'EOF'\n[tools]\ndummy = \"1.0.0\"\ntiny = \"1.0.1\"\nEOF\n\nassert_contains \"dummy-exec-tiny\" \"1.0.1\"\n"
  },
  {
    "path": "e2e/cli/test_status",
    "content": "#!/usr/bin/env bash\n\neval \"$(mise activate bash)\"\nmise use dummy@1.0.0\n\nmise settings status.show_env=1\nassert \"mise set FOO=1\"\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise +FOO\" && _mise_hook\nassert \"mise set FOO=2\"\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise ~FOO\" && _mise_hook\nassert \"mise set --rm FOO\"\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise -FOO\" && _mise_hook\necho \"FOO=3\" >.env\nassert \"mise set _.file=.env\"\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise +FOO\" && _mise_hook\nassert \"mise set _.path=./node_modules/.bin\"\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise +./node_modules/.bin\" && _mise_hook\n\nmise settings status.show_tools=1\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise +dummy@1.0.0\" && _mise_hook\nmise use --rm dummy\nassert \"mise hook-env 2>&1 >/dev/null\" \"mise -dummy@1.0.0\" && _mise_hook\n"
  },
  {
    "path": "e2e/cli/test_test_tool_clean",
    "content": "#!/usr/bin/env bash\n\nset -euxo pipefail\n\n# Test 1: Verify test-tool cleans existing installations before running\necho \"=== Test 1: Clean existing installations ===\"\n\n# Install multiple versions first\nmise install shellcheck@0.9.0\nmise install shellcheck@0.10.0\n\n# Verify both versions are installed\nmise ls shellcheck | grep \"0.9.0\"\nmise ls shellcheck | grep \"0.10.0\"\n[ -d \"$MISE_DATA_DIR/installs/shellcheck/0.9.0\" ]\n[ -d \"$MISE_DATA_DIR/installs/shellcheck/0.10.0\" ]\n\n# Create a marker file to verify directories are cleaned\ntouch \"$MISE_DATA_DIR/installs/shellcheck/marker.txt\"\ntouch \"$MISE_CACHE_DIR/shellcheck/marker.txt\" 2>/dev/null || true\n\n# Run test-tool which should clean everything first and succeed\nmise test-tool shellcheck\n\n# Verify the marker files are gone (directories were cleaned)\nif [ -f \"$MISE_DATA_DIR/installs/shellcheck/marker.txt\" ]; then\n\techo \"ERROR: installs directory was not cleaned\"\n\texit 1\nfi\n\n# Verify test-tool installed the latest version\nmise ls shellcheck | grep -E \"0\\.[0-9]+\\.[0-9]+\"\n[ -d \"$MISE_DATA_DIR/installs/shellcheck\" ]\n\n# Test 2: Verify cache directory is cleaned\necho \"=== Test 2: Cache directory cleaning ===\"\n\n# Create cache content\nmkdir -p \"$MISE_CACHE_DIR/shellcheck\"\necho \"cached data\" >\"$MISE_CACHE_DIR/shellcheck/test.cache\"\n\n# Run test-tool again\nmise test-tool shellcheck\n\n# Verify cache was cleaned and recreated\n[ -d \"$MISE_CACHE_DIR/shellcheck\" ]\nif [ -f \"$MISE_CACHE_DIR/shellcheck/test.cache\" ]; then\n\techo \"ERROR: cache directory was not cleaned\"\n\texit 1\nfi\n\necho \"Test passed: test-tool correctly cleans all directories before installing\"\n"
  },
  {
    "path": "e2e/cli/test_tool",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test valid tool information\nmise tool node | grep -q \"Backend:\" || fail \"Backend field not found\"\n\n# Test JSON output\nmise tool node --json | grep -q '\"backend\"' || fail \"JSON backend field not found\"\n\n# Test specific field filters\nbackend_output=$(mise tool node --backend)\n[[ -n $backend_output ]] || fail \"Backend output is empty\"\n\n# Test that invalid tool names should error\nassert_fail \"mise tool INVALID_TOOL_NAME\"\n\n# Test duplicate version bug - install multiple versions of a tool\nmise use tiny@1.0.0\nmise use tiny@1.1.0\nassert \"mise tool tiny --installed\" \"1.0.0 1.1.0\"\n\n# Test security field exists in JSON output for aqua tool\nmise tool aqua:cli/cli --json | jq -e '.security' || fail \"security field not found in JSON\"\n\n# Test security field is an array\nmise tool aqua:cli/cli --json | jq -e '.security | type == \"array\"' || fail \"security is not an array\"\n\n# Test that security features have type field when present\nmise tool aqua:cli/cli --json | jq -e '.security | if length > 0 then .[0].type else true end' || fail \"security feature missing type field\"\n\n# Test core plugin security features\n# Node has checksum + gpg\nmise tool node --json | jq -e '.security | length >= 1' || fail \"node should have security features\"\nmise tool node --json | jq -e '.security[] | select(.type == \"checksum\")' || fail \"node should have checksum\"\n\n# Go has checksum\nmise tool go --json | jq -e '.security[] | select(.type == \"checksum\")' || fail \"go should have checksum\"\n\n# Zig has checksum + minisign\nmise tool zig --json | jq -e '.security[] | select(.type == \"checksum\")' || fail \"zig should have checksum\"\nmise tool zig --json | jq -e '.security[] | select(.type == \"minisign\")' || fail \"zig should have minisign\"\nmise tool zig --json | jq -e '.security[] | select(.type == \"minisign\") | .public_key' || fail \"zig minisign should have public_key\"\n"
  },
  {
    "path": "e2e/cli/test_tool_alias",
    "content": "#!/usr/bin/env bash\n\n# Test 1: tool_alias works as replacement for alias\ncat >mise.toml <<'EOF'\n[tool_alias.tiny.versions]\nlts = \"1.0.0\"\nEOF\n\nmise i tiny@lts\nassert_contains \"mise ls tiny\" \"1.0.0\"\n\n# Test 2: Deprecated [alias] still works but shows warning\ncat >mise.toml <<'EOF'\n[alias.tiny.versions]\nold = \"1.1.0\"\nEOF\n\nmise i tiny@old\noutput=$(mise ls tiny 2>&1)\n# Should have installed 1.1.0\nassert_contains \"echo '$output'\" \"1.1.0\"\n\n# Test 3: Both alias and tool_alias can coexist, tool_alias takes precedence\ncat >mise.toml <<'EOF'\n[alias.tiny.versions]\nboth = \"1.0.0\"\n\n[tool_alias.tiny.versions]\nboth = \"1.1.0\"\nEOF\n\nmise i tiny@both\n# tool_alias should take precedence - should install 1.1.0\nassert_contains \"mise ls tiny\" \"1.1.0\"\n"
  },
  {
    "path": "e2e/cli/test_tool_stub_basic",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test basic tool stub functionality with stable tools\n\n# Disable GPG verification to avoid test failures\nexport MISE_GPG_VERIFY=false\n\n# Create a test project directory\nmkdir -p tool_stub_basic/bin\ncd tool_stub_basic\n\n# Test 1: Basic tool stub with Node.js\ncat >bin/node <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n# Basic Node.js tool stub\n\nversion = \"20.0.0\"\nEOF\nchmod +x bin/node\n\n# Test the tool stub via CLI command\nassert_contains \"mise tool-stub bin/node --version\" \"v20.0.0\"\n\n# Test 2: Tool stub with explicit tool specification\ncat >bin/python <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n# Python tool stub with explicit tool\n\ntool = \"python\"\nversion = \"3.11\"\nEOF\nchmod +x bin/python\n\nassert_contains \"mise tool-stub bin/python --version\" \"Python 3.11\"\n\n# Test 3: Tool stub with different bin name\ncat >bin/py <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n# Python tool stub with custom bin name\n\ntool = \"python\"\nversion = \"3.11\"\nbin = \"python\"\nEOF\nchmod +x bin/py\n\nassert_contains \"mise tool-stub bin/py --version\" \"Python 3.11\"\n\n# Test 4: Error handling - missing version\ncat >bin/no_version <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n# Missing version field\n\ntool = \"python\"\nEOF\nchmod +x bin/no_version\n\nassert_fail \"mise tool-stub bin/no_version --version\"\n\n# Test 5: Error handling - malformed TOML\ncat >bin/malformed <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n# Malformed TOML\n\nversion = \"1.0.0\ntool = invalid syntax\nEOF\nchmod +x bin/malformed\n\nassert_fail \"mise tool-stub bin/malformed --version\"\n\n# Test 7: Verify we can see the tool-stub command in help (it's there but minimal)\nassert_contains \"mise --help\" \"tool-stub\"\n\n# Test 11: GitHub backend\ncat >bin/gh <<'EOF'\n#!/usr/bin/env -S mise tool-stub\ntool = \"github:cli/cli\"\nEOF\nchmod +x bin/gh\n\nassert_contains \"bin/gh --version\" \"gh version\"\nassert_contains \"bin/gh --version\" \"gh version\" # short-circuit works\nmise uninstall --all\nassert_contains \"bin/gh --version\" \"gh version\" # refetches even if it's cached\n\n# Test 12: Aqua backend\ncat >bin/flyctl <<'EOF'\n#!/usr/bin/env -S mise tool-stub\ntool = \"flyctl\"\nversion = \"0.3.206\"\nbin = \"flyctl\"\nEOF\n\nchmod +x bin/flyctl\n\nassert_contains \"bin/flyctl version\" \"flyctl v0.3.206\"\nmise uninstall --all\nassert_contains \"bin/flyctl version\" \"flyctl v0.3.206\"\n\n# Test 13: Tool using non-built-in backend (e.g. npm/pipx)\ncat >bin/stylelint <<'EOF'\n#!/usr/bin/env -S mise tool-stub\ntool = \"npm:stylelint\"\nversion = \"17.0.0\"\nEOF\n\nchmod +x bin/stylelint\nmise use node@20\nassert_contains \"bin/stylelint --version\" \"17.0.0\"\nmise uninstall --all\nmise unuse node@20\nassert_contains \"bin/stylelint --version\" \"17.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_tool_stub_errors",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test proper error messages for tool-stub http backend tools\n\n# Disable backtraces for cleaner error messages\nexport RUST_BACKTRACE=0\nexport MISE_QUIET=1\n\n# Test 1: Default bin name (stub filename) not found shows available executables\ncat >test_http_default_bin <<'EOF'\n#!/usr/bin/env -S mise tool-stub\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nblake3 = \"71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"\nsize = 518\n# bin defaults to filename: test_http_default_bin\nEOF\nchmod +x test_http_default_bin\n\n# Test error message content\noutput=$(mise tool-stub ./test_http_default_bin 2>&1 || true)\n# Simple check that the key parts of the error message are present\nif [[ $output == *\"does not have an executable named 'test_http_default_bin'\"* ]] &&\n\t[[ $output == *\"Available executables: hello-world-1.0.0/bin/hello-world\"* ]]; then\n\techo \"✓ Test 1 passed: Error message contains expected content\"\nelse\n\techo \"✗ Test 1 failed: Expected error message not found\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Clean up (skip uninstall for speed in testing)\nrm test_http_default_bin\n\n# Test 2: Binary not found should not show hidden files\ncat >test_hidden_files <<'EOF'\n#!/usr/bin/env -S mise tool-stub\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nblake3 = \"71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"\nsize = 518\nbin = \"nonexistent\"\nEOF\nchmod +x test_hidden_files\n\noutput=$(mise tool-stub ./test_hidden_files 2>&1 || true)\nif [[ $output == *\"does not have an executable named 'nonexistent'\"* ]] &&\n\t[[ $output == *\"Available executables: hello-world-1.0.0/bin/hello-world\"* ]]; then\n\techo \"✓ Test 2 passed: Error message contains expected content\"\nelse\n\techo \"✗ Test 2 failed: Expected error message not found\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Clean up\nrm test_hidden_files\n\n# Test 3: Binary with path not found shows correct error\ncat >test_bin_path <<'EOF'\n#!/usr/bin/env -S mise tool-stub\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nblake3 = \"71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f\"\nsize = 518\nbin = \"bin/nonexistent\"\nEOF\nchmod +x test_bin_path\n\noutput=$(mise tool-stub ./test_bin_path 2>&1 || true)\nif [[ $output == *\"does not have an executable named 'bin/nonexistent'\"* ]] &&\n\t[[ $output == *\"Available executables: hello-world-1.0.0/bin/hello-world\"* ]]; then\n\techo \"✓ Test 3 passed: Error message contains expected content\"\nelse\n\techo \"✗ Test 3 failed: Expected error message not found\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Clean up\nrm test_bin_path\n\n# Test 4: Actual tool not found (non-existent tool)\ncat >test_tool_notfound <<'EOF'\n#!/usr/bin/env -S mise tool-stub\ntool = \"nonexistent-tool-that-doesnt-exist\"\nEOF\nchmod +x test_tool_notfound\n\noutput=$(mise tool-stub ./test_tool_notfound 2>&1 || true)\n# The error for non-existent tools shows up as a toolset resolution error\nif [[ $output == *\"No current versions found after resolving toolset\"* ]]; then\n\techo \"✓ Test 4 passed: Non-existent tool error handled correctly\"\nelse\n\techo \"✗ Test 4 failed: Expected toolset resolution error\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/cli/test_tool_stub_http",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103,SC2016\n\nexport MISE_EXPERIMENTAL=1\n# Disable GPG verification to avoid test failures\nexport MISE_GPG_VERIFY=false\n\n# Test tool stub with HTTP backend nested options\n# This test verifies that the tool stub correctly passes backend options to the HTTP backend\n\n# Create a test project directory\nmkdir -p tool_stub_http_test/bin\ncd tool_stub_http_test\n\n# Function to create and test a tool stub\n# Usage: test_tool_stub <stub_name> <toml_content>\ntest_tool_stub() {\n\tlocal stub_name=\"$1\"\n\tlocal toml_content=\"$2\"\n\n\t# Create the tool stub file\n\tcat >\"bin/$stub_name\" <<EOF\n#!/usr/bin/env -S mise tool-stub\n$toml_content\nEOF\n\tchmod +x \"bin/$stub_name\"\n\n\t# Test the tool stub\n\tassert_succeed \"mise tool-stub bin/$stub_name\"\n\n\t# Clean up for next test\n\tmise uninstall --all && mise cache clear\n}\n\n# Test 1: Basic HTTP backend with bin_path\ntest_tool_stub \"hello-world\" '\ntool = \"http:hello-tool-stub\"\nversion = \"1.0.0\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nbin_path = \"hello-world-1.0.0/bin\"\npostinstall = \"chmod +x $MISE_TOOL_INSTALL_PATH/hello-world-1.0.0/bin/hello-world\"'\n\n# Test 2: HTTP backend with platform-specific URLs and strip_components\ntest_tool_stub \"hello-platform\" '\ntool = \"http:hello-platform-stub\"\nversion = \"1.0.0\"\nbin = \"hello-world\"\nbin_path = \"bin\"\npostinstall = \"chmod +x $MISE_TOOL_INSTALL_PATH/bin/hello-world\"\nstrip_components = 1\n\n[platforms.linux-amd64]\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\n\n[platforms.darwin-arm64]\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"'\n\n# Test 3: HTTP backend with simple configuration\ntest_tool_stub \"hello-simple\" '\ntool = \"http:hello-simple-stub\"\nversion = \"1.0.0\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nstrip_components = 1\nbin = \"hello-world\"\nbin_path = \"bin\"\npostinstall = \"chmod +x $MISE_TOOL_INSTALL_PATH/bin/hello-world\"'\n\n# Test 4: HTTP backend with simple configuration\ntest_tool_stub \"hello-world\" '\ntool = \"http:hello-world\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nbin = \"hello-world\"'\n\n# Test 5: HTTP backend with simple configuration\ntest_tool_stub \"hello-world\" '\ntool = \"http:hello-world\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nbin = \"hello-world-1.0.0/bin/hello-world\"'\n\n# Test 6: HTTP backend with simple configuration\ntest_tool_stub \"hello-world\" '\ntool = \"http:hello-world\"\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nbin = \"bin/hello-world\"'\n\n# Test 7: HTTP backend with simple configuration\ntest_tool_stub \"hello-world\" '\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\nbin = \"bin/hello-world\"'\n\n# Test 8: HTTP backend with simple configuration\ntest_tool_stub \"hello-world\" '\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"'\n\ntest_tool_stub \"hello-world\" '\n[platforms.linux-amd64]\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"\n[platforms.darwin-arm64]\nurl = \"https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz\"'\n"
  },
  {
    "path": "e2e/cli/test_uninstall",
    "content": "#!/usr/bin/env bash\n\nexport CLICOLOR=0\n\necho \"dummy latest\" >.tool-versions\n\nassert_contains \"mise ls dummy\" \"2.0.0 (missing)\"\n\nmise i dummy@{1.0.0,1.1.0,2.0.0}\nassert_contains \"mise ls dummy\" \"1.0.0\"\nassert_contains \"mise ls dummy\" \"1.1.0\"\nassert_contains \"mise ls dummy\" \"2.0.0\"\n\nmise uninstall -a dummy@1\nassert_not_contains \"mise ls dummy\" \"1.0.0\"\nassert_not_contains \"mise ls dummy\" \"1.1.0\"\nassert_contains \"mise ls dummy\" \"2.0.0\"\n\nmise uninstall -a dummy\nassert_not_contains \"mise ls dummy\" \"1.1.0\"\nassert_not_contains \"mise ls dummy\" \"2.0.1\"\nassert_not_contains \"mise ls dummy\" \"2.1.0\"\n\n# Test: --dry-run-code should exit non-zero when there are tools to uninstall\nmise i dummy@1.0.0\nassert_fail_contains \"mise uninstall dummy@1.0.0 --dry-run-code 2>&1\" \"uninstalled (dry-run)\"\n# Verify the tool was NOT actually uninstalled\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\n\n# Test: --dry-run-code should exit 0 when the tool is not installed\nmise uninstall dummy@1.0.0\nassert_succeed \"mise uninstall dummy@1.0.0 --dry-run-code 2>&1\"\n"
  },
  {
    "path": "e2e/cli/test_unknown_command_suggestion",
    "content": "#!/usr/bin/env bash\n# Test that mistyped CLI commands suggest the correct command instead of\n# showing a confusing \"no tasks defined\" error.\n# See: https://github.com/jdx/mise/discussions/8278\n\nset -euo pipefail\nexport RUST_BACKTRACE=0\nexport MISE_FRIENDLY_ERROR=1\n\n# Test: Typo of a known command should suggest the correct command\nassert_fail \"mise bin-path\" \"Did you mean\"\nassert_fail \"mise bin-path\" \"bin-paths\"\n\n# Test: Another typo should suggest the correct command\nassert_fail \"mise instal\" \"install\"\n\n# Test: Should say \"unknown command\" not \"no tasks defined\" for command typos\nassert_fail \"mise bin-path\" \"unknown command\"\n"
  },
  {
    "path": "e2e/cli/test_unuse",
    "content": "#!/usr/bin/env bash\n\nassert \"mise install dummy@1.0.0\"\nassert \"ls $MISE_DATA_DIR/installs/dummy\" \"1\n1.0\n1.0.0\nlatest\"\nassert \"mise rm dummy\"\nassert_empty \"mise ls\"\nassert_fail \"ls $MISE_DATA_DIR/installs/dummy\"\n\nassert \"mise use dummy@1.0.0\"\nassert_contains \"mise ls dummy\" \"1.0.0\"\nassert \"mise unuse dummy@1.0.0\"\nassert_empty \"mise ls dummy\"\n\nassert \"mise use dummy@1.0.0\"\nmkdir subdir\ncd subdir || exit 1\nassert \"mise use -p mise.toml dummy@1.0.0\"\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/workdir/subdir/mise.toml  1.0.0\"\nassert \"mise unuse dummy@1.0.0\"\n# version is not pruned because it's in ~/workdir/mise.toml\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/workdir/mise.toml  1.0.0\"\nassert \"mise unuse dummy@1.0.0\"\nassert_empty \"mise ls dummy\"\ncd - || exit 1\n\nassert \"mise use -g dummy@1.0.0\"\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/.config/mise/config.toml  1.0.0\"\nassert \"mise use dummy@1.0.0\"\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/workdir/mise.toml  1.0.0\"\nassert \"mise unuse dummy@1.0.0\"\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/.config/mise/config.toml  1.0.0\"\nassert \"mise unuse -g dummy@1.0.0\"\nassert_empty \"mise ls dummy\"\n\nassert \"mise use -e test dummy@1.0.0\"\nassert \"mise ls -E test dummy\" \"dummy  1.0.0  ~/workdir/mise.test.toml  1.0.0\"\nassert \"mise unuse -e test dummy@1.0.0\"\nassert_empty \"mise ls -E test dummy\"\nrm ~/workdir/mise.test.toml\n\nassert \"mise use dummy@2.0.0\"\nassert \"mise ls dummy\" \"dummy  2.0.0  ~/workdir/mise.toml  2.0.0\"\n# tool is not removed because version does not match\nassert \"mise unuse dummy@1.0.0\"\nassert \"mise ls dummy\" \"dummy  2.0.0  ~/workdir/mise.toml  2.0.0\"\n\n# not specifying version means it will remove any version\nassert \"mise use dummy@2\"\nassert \"mise ls dummy\" \"dummy  2.0.0  ~/workdir/mise.toml  2\"\nassert \"mise unuse dummy\"\nassert_empty \"mise ls dummy\"\n"
  },
  {
    "path": "e2e/cli/test_upgrade",
    "content": "#!/usr/bin/env bash\n\necho 'dummy 1' >.tool-versions\nmise install dummy@1.0.0\n\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.1.0\"\n\nmise upgrade dummy\n\nassert_contains \"mise ls --installed dummy\" \"1.1.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.0.0\"\n\nmise upgrade dummy --bump\nassert_contains \"mise ls --installed dummy\" \"2.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.1.0\"\nrm .tool-versions\n\n# Test: --local should only upgrade tools in local config, not global config\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1\"\nEOF\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[tools]\ntiny = \"1\"\nEOF\nmise uninstall dummy tiny --all\nmise install dummy@1.0.0 tiny@1.0.0\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_contains \"mise ls --installed tiny\" \"1.0.0\"\n# Dry-run should only show the local tool (dummy)\nassert_contains \"mise upgrade --local -n\" \"Would install dummy@1.1.0\"\nassert_not_contains \"mise upgrade --local -n\" \"tiny\"\n# Actual upgrade should only upgrade dummy\nmise upgrade --local\nassert_contains \"mise ls --installed dummy\" \"1.1.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.0.0\"\n# tiny should remain at 1.0.0 since it's in global config\nassert_contains \"mise ls --installed tiny\" \"1.0.0\"\nassert_not_contains \"mise ls --installed tiny\" \"1.1.0\"\nrm -f \"$MISE_CONFIG_DIR/config.toml\"\nrm -f mise.toml\n\n# ensure options are retained\nmise use \"ubi:bazelbuild/buildtools[exe=buildifier,matching=buildifier]@7.1.2\"\nassert \"cat mise.toml\" '[tools]\n\"ubi:bazelbuild/buildtools\" = { version = \"7.1.2\", exe = \"buildifier\", matching = \"buildifier\" }'\nbazelbuild_latest=$(mise latest ubi:bazelbuild/buildtools)\nmise up --bump ubi:bazelbuild/buildtools\nassert \"cat mise.toml\" \"[tools]\n\\\"ubi:bazelbuild/buildtools\\\" = { version = \\\"$bazelbuild_latest\\\", exe = \\\"buildifier\\\", matching = \\\"buildifier\\\" }\"\n\nrm -f .tool-versions\necho \"tools.dummy = 'prefix:1'\" >mise.toml\nmise uninstall dummy --all\nmkdir -p \"$MISE_DATA_DIR/installs/dummy/1.0.0\"\nassert \"mise ls dummy --outdated\" \"dummy  1.0.0 (outdated)  ~/workdir/mise.toml  prefix:1\"\nassert \"mise up -n\" \"Would uninstall dummy@1.0.0\nWould install dummy@1.1.0\"\nmise up\nassert \"mise ls dummy\" \"dummy  1.1.0  ~/workdir/mise.toml  prefix:1\"\nassert \"mise up dummy -n --bump\" \"Would uninstall dummy@1.1.0\nWould install dummy@2.0.0\nWould bump dummy@prefix:2 in ~/workdir/mise.toml\"\nmise up dummy --bump\nassert \"mise ls dummy\" \"dummy  2.0.0  ~/workdir/mise.toml  prefix:2\"\necho \"tools.dummy = 'prefix:1'\" >mise.toml\nmise uninstall dummy --all\nmise i dummy@1.0.0\nassert \"mise up dummy -n --bump\" \"Would uninstall dummy@1.0.0\nWould install dummy@2.0.0\nWould bump dummy@prefix:2 in ~/workdir/mise.toml\"\nmise up dummy --bump\nassert \"mise ls dummy\" \"dummy  2.0.0  ~/workdir/mise.toml  prefix:2\"\n\ncat <<EOF >mise.toml\n[tools]\ndummy = \"latest\"\nEOF\nassert \"mise uninstall dummy --all\"\nassert \"mise i dummy@1.0.0\"\nassert \"mise up --bump\"\nassert \"cat mise.toml\" '[tools]\ndummy = \"latest\"'\n\n# Test: --dry-run-code should exit non-zero when there are outdated tools\necho \"tools.dummy = 'prefix:1'\" >mise.toml\nmise uninstall dummy --all\nmkdir -p \"$MISE_DATA_DIR/installs/dummy/1.0.0\"\nassert_fail_contains \"mise up --dry-run-code 2>&1\" \"Would install\"\n# Verify nothing was actually upgraded\nassert \"ls $MISE_DATA_DIR/installs/dummy/1.0.0\"\n\n# Test: --dry-run-code should exit 0 when everything is up to date\nmise up\nassert_contains \"mise up --dry-run-code 2>&1\" \"All tools are up to date\"\n\n# Test: upgrade should not re-download a version that is already installed\n# This verifies the fix for https://github.com/jdx/mise/discussions/8260\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1\"\nEOF\nmise uninstall dummy --all\n# Install 1.0.0 first (old version), then also install 1.1.0 (the latest 1.x)\nmise install dummy@1.0.0\nmise install dummy@1.1.0\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_contains \"mise ls --installed dummy\" \"1.1.0\"\n# upgrade should report \"All tools are up to date\" since 1.1.0 is already installed\nassert_contains \"mise up 2>&1\" \"All tools are up to date\"\n\n# Test: upgrade with lockfile should update the lockfile to the new version\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1\"\nEOF\nmise uninstall dummy --all\nmise install dummy@1.0.0\n# Write a lockfile pinning to 1.0.0\ncat <<EOF >mise.lock\n[[tools.dummy]]\nversion = \"1.0.0\"\nbackend = \"asdf:dummy\"\nEOF\n# Verify the lockfile pins to 1.0.0\nassert \"mise ls dummy\" \"dummy  1.0.0  ~/workdir/mise.toml  1\"\n# Upgrade should install 1.1.0 and update the lockfile\nmise up\nassert \"mise ls dummy\" \"dummy  1.1.0  ~/workdir/mise.toml  1\"\n# Verify the lockfile was updated to 1.1.0\nassert_contains \"cat mise.lock\" \"1.1.0\"\nassert_not_contains \"cat mise.lock\" \"1.0.0\"\nrm -f mise.lock\n\n# Test that upgrading a specific tool doesn't check other tools\n# This verifies the fix for https://github.com/jdx/mise/discussions/7328\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1\"\ntiny = \"1\"\nEOF\nmise uninstall dummy tiny --all\nmise install dummy@1.0.0 tiny@1.0.0\n\n# Upgrade only dummy, should not see any warnings about tiny\noutput=$(mise upgrade dummy --bump 2>&1)\nassert_not_contains \"echo '$output'\" \"Error getting latest version for tiny\"\nassert_not_contains \"echo '$output'\" \"WARN.*tiny\"\nassert_contains \"mise ls --installed dummy\" \"2.0.0\"\n# dummy 1.0.0 should have been uninstalled since we upgraded it\nassert_not_contains \"mise ls --installed dummy\" \"1.0.0\"\n# tiny should still be at 1.0.0 since we didn't upgrade it\nassert_contains \"mise ls --installed tiny\" \"1.0.0\"\nassert_not_contains \"mise ls --installed tiny\" \"1.1.0\"\n"
  },
  {
    "path": "e2e/cli/test_upgrade_parallel_failure",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise up` with parallel installation handles failures correctly:\n# - Command exits with non-zero status when some tools fail\n# - Successful tools are still installed\n# - Failed tools don't get installed\n\n# Clean up any existing installations\nmise uninstall dummy --all 2>/dev/null || true\nmise uninstall tiny --all 2>/dev/null || true\n\n# Test 1: Create a scenario with mixed success/failure during parallel upgrade\n# Follow the pattern from the existing upgrade test\n\n# Set up config with multiple tools\ncat <<EOF >mise.toml\n[tools]\ndummy = \"other-dummy\"  # This version will fail to install  \ntiny = \"latest\"        # This should upgrade successfully\nEOF\n\n# Manually create outdated installations to trigger upgrades\n# Create dummy@1.0.0 installation (this will be \"outdated\" vs other-dummy)\nmkdir -p \"$MISE_DATA_DIR/installs/dummy/1.0.0\"\necho \"1.0.0\" >\"$MISE_DATA_DIR/installs/dummy/1.0.0/version\"\n\n# Create tiny@1.0.0 installation (this will be outdated vs latest 3.1.0)\nmkdir -p \"$MISE_DATA_DIR/installs/tiny/1.0.0\"\necho \"1.0.0\" >\"$MISE_DATA_DIR/installs/tiny/1.0.0/version\"\n\n# Now `mise up` should try to install/upgrade both:\n# - dummy: install other-dummy (will fail)\n# - tiny: upgrade to latest 3.1.0 (will succeed)\nassert_fail \"mise up\" \"Failed to install asdf:dummy@other-dummy\"\n\n# Verify tiny was upgraded successfully despite dummy failure\nassert_contains \"mise ls --installed tiny\" \"3.1.0\"\n\n# Verify dummy failed to install the bad version (should still show 1.0.0)\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"other-dummy\"\n"
  },
  {
    "path": "e2e/cli/test_use",
    "content": "#!/usr/bin/env bash\n\nmise i dummy@1.0.0\n\nassert_contains \"mise use dummy\" \"dummy@1.0.0\"\nassert \"mise current dummy\" \"1.0.0\"\n\nassert_contains \"mise use dummy@2\" \"dummy@2.\"\nassert \"mise current dummy\" \"2.0.0\"\n\nassert_contains \"mise use --rm dummy\" \"removed: dummy\"\nassert \"mise current dummy\" \"\"\n\nassert_contains \"mise use --env local dummy@2\" \"dummy@2.\"\nassert \"cat mise.local.toml\" '[tools]\ndummy = \"2\"'\nassert \"mise current dummy\" \"2.0.0\"\nrm mise.local.toml\n\nassert_contains \"mise use --env local dummy@1\" \"dummy@1.\"\nassert \"cat mise.local.toml\" '[tools]\ndummy = \"1\"'\nmv mise.local.toml .mise.local.toml\nassert_contains \"mise use --env local dummy@2\" \"dummy@2.\"\nassert_fail \"test -f mise.local.toml\"\nassert \"cat .mise.local.toml\" '[tools]\ndummy = \"2\"'\nrm .mise.local.toml\n\nmise use dummy@1 dummy@2\nassert \"mise current dummy\" \"1.0.0 2.0.0\"\n\nmise use --pin dummy@1\nassert \"cat mise.toml\" '[tools]\ndummy = \"1.0.0\"'\n\nMISE_PIN=1 mise use --fuzzy dummy@1\nassert \"cat mise.toml\" '[tools]\ndummy = \"1\"'\n\nMISE_PIN=1 mise use dummy@1 --path mise.local.toml\nassert \"cat mise.local.toml\" '[tools]\ndummy = \"1.0.0\"'\n\nmise use --rm dummy --path mise.local.toml\nassert \"cat mise.local.toml\" \"\"\n\nmise use dummy@1 --path .\nassert \"cat mise.toml\" '[tools]\ndummy = \"1\"'\n\n# mise use should write to mise.toml (lowest precedence) instead of mise.local.toml\n# See: https://github.com/jdx/mise/discussions/6475\nmise use dummy@2\nassert \"cat mise.toml\" '[tools]\ndummy = \"2\"'\n\n# When both mise.toml and mise.local.toml exist, mise use should still write to mise.toml\necho '[tools]' >mise.local.toml\necho 'dummy = \"1\"' >>mise.local.toml\nmise use dummy@3\nassert \"cat mise.toml\" '[tools]\ndummy = \"3\"'\nassert \"cat mise.local.toml\" '[tools]\ndummy = \"1\"'\n\nrm -f mise.local.toml mise.toml\n\n# mise use should write to .config/mise/config.toml instead of .config/mise/config.local.toml\nmkdir -p .config/mise\necho '[tools]' >.config/mise/config.toml\necho 'dummy = \"1\"' >>.config/mise/config.toml\ntouch .config/mise/config.local.toml\nmise use dummy@2\nassert \"cat .config/mise/config.toml\" '[tools]\ndummy = \"2\"'\nassert \"cat .config/mise/config.local.toml\" \"\"\nrm -rf .config\n\necho \"dummy 1.0.0\" >.tool-versions\nmise use dummy@2\nassert \"cat .tool-versions\" \"dummy 2\"\n\n# When both .tool-versions and mise.toml exist, mise use should prefer mise.toml\necho '[tools]' >mise.toml\necho 'dummy = \"1\"' >>mise.toml\nmise use dummy@3\nassert \"cat mise.toml\" '[tools]\ndummy = \"3\"'\nassert \"cat .tool-versions\" \"dummy 2\"\n\nrm -f .tool-versions mise.toml\n\nmise use -g dummy@1\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ndummy = \"1\"'\nrm -f ~/.config/mise/config.toml\n\nmise use -g \"ubi:cli/cli[exe=gh]\"\nassert \"cat ~/.config/mise/config.toml\" '[tools]\n\"ubi:cli/cli\" = { version = \"latest\", exe = \"gh\" }'\nrm -f ~/.config/mise/config.toml\n\nmise use -g gh@2\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ngh = \"2\"'\nrm -f ~/.config/mise/config.toml\n\n# mise use -g should write to config.toml instead of config.local.toml\n# See: https://github.com/jdx/mise/discussions/8236\ntouch ~/.config/mise/config.toml ~/.config/mise/config.local.toml\nmise use -g dummy@1\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ndummy = \"1\"'\nassert \"cat ~/.config/mise/config.local.toml\" \"\"\nrm -f ~/.config/mise/config.toml ~/.config/mise/config.local.toml\n\nexport MISE_ENV=test\nmise use -g dummy@1\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ndummy = \"1\"'\nrm -f ~/.config/mise/config.toml\nunset MISE_ENV\n\nmise uninstall dummy --all\nmise use dummy@system\nassert \"mise ls dummy\" \"dummy  system  ~/workdir/mise.toml  system\"\n\nmkdir -p ~/workdir/mydummy\nmise use \"dummy@path:~/workdir/mydummy\"\nassert_contains \"mise ls dummy\" \"dummy  path:~/workdir/mydummy  ~/workdir/mise.toml  path:~/workdir/mydummy\"\n\ncd \"$HOME\" || exit 1\nassert_contains \"mise use dummy@system\" \"mise ~/.config/mise/config.toml tools: dummy@system\"\n\nassert_contains \"mise use --path mise.path.toml dummy@1\" \"dummy@1.\"\nassert \"cat mise.path.toml\" '[tools]\ndummy = \"1\"'\n"
  },
  {
    "path": "e2e/cli/test_use_dry_run",
    "content": "#!/usr/bin/env bash\n# Test use --dry-run functionality\n\nset -euo pipefail\n\n# Create a temporary directory for testing\nTEST_DIR=$(mktemp -d)\ncd \"$TEST_DIR\"\n\n# Test: Dry-run should show what would be added without actually modifying the file\nassert_contains \"mise use tiny@3.1.0 --dry-run 2>&1\" \"would update\"\nassert_contains \"mise use tiny@3.1.0 --dry-run 2>&1\" \"add: tiny@3.1.0\"\n# Config file should not exist after dry-run\nassert_fail \"test -f mise.toml\"\n\n# Test: Tool should not be installed after dry-run\nassert_fail \"mise which tiny\"\n\n# Test: Regular use should actually add the tool\nmise use tiny@3.1.0\nassert_contains \"cat mise.toml\" \"tiny\"\n\n# Test: Dry-run for removing a tool\nassert_contains \"mise use --remove tiny --dry-run 2>&1\" \"would update\"\nassert_contains \"mise use --remove tiny --dry-run 2>&1\" \"remove: tiny\"\nassert_contains \"cat mise.toml\" \"tiny\" # Should still be there\n\n# Test: Actually remove the tool\nmise use --remove tiny\nassert_not_contains \"cat mise.toml\" \"tiny\"\n\n# Test: Dry-run with multiple tools\nrm -f mise.toml # Start fresh\noutput=$(mise use jq@latest shfmt@3.10.0 --dry-run 2>&1)\nassert_contains \"echo '$output'\" \"would update\"\nassert_contains \"echo '$output'\" \"jq@\"\nassert_contains \"echo '$output'\" \"shfmt@\"\nassert_fail \"test -f mise.toml\" # File should not be created\n\n# Test: --dry-run-code should exit non-zero when there are changes to make\nrm -f mise.toml\nassert_fail_contains \"mise use tiny@3.1.0 --dry-run-code 2>&1\" \"would update\"\nassert_fail \"test -f mise.toml\" # File should not be created\n\n# Test: --dry-run-code for removing a tool should exit non-zero\nmise use tiny@3.1.0\nassert_fail_contains \"mise use --remove tiny --dry-run-code 2>&1\" \"would update\"\nassert_contains \"cat mise.toml\" \"tiny\" # Should still be there\n"
  },
  {
    "path": "e2e/cli/test_use_env",
    "content": "#!/usr/bin/env bash\n\nmise use -e local dummy@1\nassert \"cat mise.local.toml\" '[tools]\ndummy = \"1\"'\nassert \"rm mise.local.toml\"\n\nMISE_ENV=local mise use dummy@1 # doesn't imply `-e local` for writing\nassert \"cat mise.toml\" '[tools]\ndummy = \"1\"'\n"
  },
  {
    "path": "e2e/cli/test_use_latest",
    "content": "#!/usr/bin/env bash\n\nassert \"mise i tiny@1.0.0\"\nassert \"mise i dummy@1.0.0\"\n\nassert \"mise use dummy tiny\"\nassert \"mise tool dummy --requested\" \"latest\"\nassert \"mise tool dummy --active\" \"1.0.0\"\nassert \"mise tool tiny --active\" \"1.0.0\"\n\nassert \"mise use dummy@latest\"\nassert \"mise tool dummy --active\" \"2.0.0\"\nassert \"mise tool tiny --active\" \"1.0.0\"\nassert \"mise tool dummy --requested\" \"latest\"\nassert \"mise tool tiny --requested\" \"latest\"\n\ntouch mise.lock\nassert \"mise use dummy@1 tiny@1\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.dummy]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:dummy\\\"\n\n[[tools.tiny]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise tool dummy --requested\" \"1\"\nassert \"mise tool tiny --requested\" \"1\"\nassert \"mise tool dummy --active\" \"1.0.0\"\nassert \"mise tool tiny --active\" \"1.0.0\"\n\nassert \"mise use dummy@latest\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.dummy]]\nversion = \\\"2.0.0\\\"\nbackend = \\\"asdf:dummy\\\"\n\n[[tools.tiny]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise tool dummy --requested\" \"latest\"\nassert \"mise tool tiny --requested\" \"1\"\nassert \"mise tool dummy --active\" \"2.0.0\"\nassert \"mise tool tiny --active\" \"1.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_use_retain_opts",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use dummy[foo=bar]@1.0.0\"\nassert \"cat mise.toml\" '[tools]\ndummy = { version = \"1.0.0\", foo = \"bar\" }'\nassert \"mise use -g dummy@1.0.0\"\nassert \"cat ~/.config/mise/config.toml\" '[tools]\ndummy = \"1.0.0\"'\n"
  },
  {
    "path": "e2e/cli/test_version",
    "content": "#!/usr/bin/env bash\n\nassert \"mise version --json\"\n"
  },
  {
    "path": "e2e/cli/test_watch",
    "content": "#!/usr/bin/env bash\n\nmise use dummy@latest\nmise use -g watchexec@latest\n\nmise tasks add example -- echo 'running example'\n\ntest_mise_watch() {\n\tlocal mise_path=\"$1\"\n\toutput_file=.watch_output\n\n\trm -f \"${output_file}\"\n\n\t$mise_path watch example -e '.aaa' >\"${output_file}\" &\n\tPID_TO_KILL=$!\n\n\twhile ! grep -q \"running example\" \"${output_file}\"; do\n\t\tsleep 0.5\n\tdone\n\n\tkill -SIGINT $PID_TO_KILL\n\n\tassert_contains \"cat ${output_file}\" \"running example\"\n}\n\n# Test with original mise\ntest_mise_watch \"mise\"\n\n# Test when mise is not in PATH\noriginal_mise=\"$(which mise)\"\nmkdir -p ./bin && mv \"$original_mise\" ./bin/mise\ntest_mise_watch \"./bin/mise\"\nmv ./bin/mise \"$original_mise\"\n"
  },
  {
    "path": "e2e/cli/test_where",
    "content": "#!/usr/bin/env bash\nexport MISE_EXPERIMENTAL=1\nexport MISE_LOCKFILE=1\n\nassert \"mise use dummy@3.1.0\"\nassert \"mise where dummy\" \"$MISE_DATA_DIR/installs/dummy/3.1.0\"\nassert \"mise install dummy@2\"\nassert \"mise where dummy@2\" \"$MISE_DATA_DIR/installs/dummy/2.0.0\"\nassert \"mise where dummy@3\" \"$MISE_DATA_DIR/installs/dummy/3.1.0\"\nassert \"mise alias set dummy my/dummy 3\"\nassert \"mise install dummy@my/dummy\"\nassert \"mise where dummy@my/dummy\" \"$MISE_DATA_DIR/installs/dummy/3\" # TODO: this should probably return 3.1.0\nassert \"mise uninstall dummy@my/dummy\"\nassert_fail \"mise where dummy@1111\" \"dummy@1111 not installed\"\n\necho 'tools.dummy = \"latest\"' >mise.toml\ncat <<EOF >mise.lock\n[[tools.dummy]]\nversion = \"3.0.0\"\nbackend = \"core:dummy\"\nEOF\nassert \"mise i\"\nassert \"mise where dummy\" \"$MISE_DATA_DIR/installs/dummy/3.0.0\"\n"
  },
  {
    "path": "e2e/cli/test_which",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use dummy@1.0.0\"\nassert \"mise which dummy\" \"$MISE_DATA_DIR/installs/dummy/1.0.0/bin/dummy\"\nassert \"mise which --plugin dummy\" \"dummy\"\nassert \"mise which --version dummy\" \"1.0.0\"\nassert \"mise which dummy --tool dummy@1.0.0\" \"$MISE_DATA_DIR/installs/dummy/1.0.0/bin/dummy\"\n"
  },
  {
    "path": "e2e/config/test_auto_install_false",
    "content": "#!/usr/bin/env bash\n\n# Test that auto_install=false prevents ALL automatic installation\n\n# Clean up any previous installs\nmise uninstall dummy@1.0.0 2>/dev/null || true\nmise uninstall dummy@ref:master 2>/dev/null || true\n\n# Test 1: mise exec with auto_install=false should NOT install tools passed as CLI args\ncat <<EOF >mise.toml\n[settings]\nauto_install = false\nEOF\n\n# This should fail because auto_install is disabled\nassert_fail \"mise exec dummy@1.0.0 -- dummy --version\" \"couldn't exec process\"\n\n# Test 2: mise exec with exec_auto_install=false should NOT install tools\ncat <<EOF >mise.toml\n[settings]\nexec_auto_install = false\nEOF\n\nassert_fail \"mise x dummy@1.0.0 -- dummy --version\" \"couldn't exec process\"\n\n# Test 3: mise run with task_run_auto_install=false should NOT install tools\ncat <<EOF >mise.toml\n[tools]\ndummy = '1.0.0'\n\n[settings]\ntask.run_auto_install = false\n\n[tasks.test]\nrun = 'dummy --version'\nEOF\n\nassert_fail \"mise run test\" \"not found\"\n\n# Test 4: Verify auto_install=false cascades to sub-settings\nmise uninstall dummy@1.0.0 2>/dev/null || true\n\ncat <<EOF >mise.toml\n[tools]\ndummy = '1.0.0'\n\n[settings]\nauto_install = false\n\n[tasks.test]\nrun = 'dummy --version'\nEOF\n\n# Both exec and run should fail when auto_install is false\nassert_fail \"mise x dummy@ref:master -- dummy --version\" \"couldn't exec process\"\nassert_fail \"mise run test\" \"not found\"\n\n# Test 5: Verify that explicit install still works\nassert \"mise install dummy@1.0.0\"\n\n# Now exec should work since it's already installed\nassert \"mise x dummy@1.0.0 -- dummy --version\"\nassert \"mise run test\"\n"
  },
  {
    "path": "e2e/config/test_config_alias",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntools.erlang = \"1.0.0-erlang\"\ntools.node = \"1.0.0-node\"\ntools.corenode = \"22.0.0\"\ntools.python = \"1.0.0-python\"\ntools.mytool = \"2\"\ntools.mytool-lts = \"lts\"\n\n[tool_alias]\nerlang = 'asdf:https://github.com/jdx/mise-tiny'\nnode = \"asdf:tiny\"\ncorenode = \"core:node\"\npython = 'asdf:jdx/mise-tiny'\nmytool = \"asdf:tiny\"\n[tool_alias.mytool-lts]\nbackend = \"asdf:tiny\"\nversions = {lts = \"1.0.1\"}\nEOF\n\nassert_contains \"mise x erlang -- mise-tiny\" \"mise-tiny: v1.0.0-erlang\"\nassert_contains \"mise x node -- rtx-tiny\" \"rtx-tiny: v1.0.0-node\"\nassert_contains \"mise x corenode -- node -v\" \"v22.0.0\"\nassert_contains \"mise x python -- mise-tiny\" \"mise-tiny: v1.0.0-python\"\nassert_contains \"mise x mytool -- rtx-tiny\" \"rtx-tiny: v2.1.0\"\nassert_contains \"mise x mytool-lts -- rtx-tiny\" \"rtx-tiny: v1.0.1\"\n\nassert_contains \"mise x rg@14.0.0 -- rg --version\" \"ripgrep 14.0.0\"\n"
  },
  {
    "path": "e2e/config/test_config_alias_github_edit",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tools.test-edit]\nversion = \"1.2.0\"\nasset_pattern = \"edit-1.2.0-aarch64-linux-gnu.tar.zst\"\n\n[tool_alias]\ntest-edit = \"github:microsoft/edit\"\nEOF\nassert \"mise install test-edit\"\n\n# Test that the alias works and test-edit command can be executed\nassert \"mise which edit\" ~/.local/share/mise/installs/test-edit/1.2.0/edit\n"
  },
  {
    "path": "e2e/config/test_config_auto_install_disable_tools",
    "content": "#!/usr/bin/env bash\n\n# Clean up any previous installs\nmise uninstall dummy@1.0.0 || true\n\n# Test auto_install_disable_tools via settings in mise.toml\ncat <<EOF >mise.toml\n[tools]\ndummy = '1.0.0'\n\n[settings]\nauto_install_disable_tools = [\"dummy\"]\nEOF\n\n# Should NOT auto-install dummy when running a command\nassert_fail \"mise exec dummy@1.0.0 -- dummy --version\" \"couldn't exec process\"\n\n# Remove auto_install_disable_tools and check auto-install works\ncat <<EOF >mise.toml\n[tools]\ndummy = '1.0.0'\nEOF\n\nassert \"mise exec dummy@1.0.0 -- dummy --version\"\n\n# Uninstall for env var test\nmise uninstall dummy@1.0.0 || true\n\n# Test auto_install_disable_tools via environment variable\ncat <<EOF >mise.toml\n[tools]\ndummy = '1.0.0'\nEOF\n\nMISE_AUTO_INSTALL_DISABLE_TOOLS=dummy assert_fail \"mise exec dummy@1.0.0 -- dummy --version\" \"couldn't exec process\"\nMISE_AUTO_INSTALL_DISABLE_TOOLS='' assert \"mise exec dummy@1.0.0 -- dummy --version\"\n"
  },
  {
    "path": "e2e/config/test_config_ceiling_paths",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test for MISE_CEILING_PATHS functionality\n# This tests that mise respects the ceiling paths configuration\n# which prevents traversing up the directory tree beyond specified paths\n\n# Create a test directory structure\nTEST_ROOT=$(pwd)\n\n# Setup directory structure\nmkdir -p \"$TEST_ROOT/parent/child/grandchild\"\n\n# Create config files at different levels using heredoc\ncat <<EOF >\"$TEST_ROOT/parent/.mise.toml\"\n[env]\nPARENT = \"true\"\nEOF\n\ncat <<EOF >\"$TEST_ROOT/parent/child/.mise.toml\"\n[env]\nCHILD = \"true\"\nEOF\n\ncat <<EOF >\"$TEST_ROOT/parent/child/grandchild/.mise.toml\"\n[env]\nGRANDCHILD = \"true\"\nEOF\ncd \"$TEST_ROOT/parent/child/grandchild\"\n\n# Test 1: Normal behavior without ceiling paths\necho \"Test 1: Without ceiling paths, should find all configs up to parent\"\nassert_contains \"mise env\" \"export GRANDCHILD=true\"\nassert_contains \"mise env\" \"export CHILD=true\"\nassert_contains \"mise env\" \"export PARENT=true\"\necho \"Test 1: Passed\"\n\n# Test 2: Set ceiling path to child directory\necho \"Test 2: With ceiling path at child, should not find parent or child config\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child\"\nassert_contains \"mise env\" \"export GRANDCHILD=true\"\nassert_not_contains \"mise env\" \"export CHILD=true\"\nassert_not_contains \"mise env\" \"export PARENT=true\"\necho \"Test 2: Passed\"\n\n# Test 3: Set ceiling path to grandchild directory\necho \"Test 3: With ceiling path at grandchild, should not find any config\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child/grandchild\"\nassert_not_contains \"mise env\" \"export GRANDCHILD=true\"\nassert_not_contains \"mise env\" \"export CHILD=true\"\nassert_not_contains \"mise env\" \"export PARENT=true\"\necho \"Test 3: Passed\"\n\n# Test 4: Multiple ceiling paths\necho \"Test 4: With multiple ceiling paths\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child:$TEST_ROOT/parent\"\nassert_contains \"mise env\" \"export GRANDCHILD=true\"\nassert_not_contains \"mise env\" \"export CHILD=true\"\nassert_not_contains \"mise env\" \"export PARENT=true\"\necho \"Test 4: Passed\"\n\n# Test 5: Ceiling path with non-existent directory\necho \"Test 5: With non-existent ceiling path, should find all configs\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/nonexistent\"\nassert_contains \"mise env\" \"export GRANDCHILD=true\"\nassert_contains \"mise env\" \"export CHILD=true\"\nassert_contains \"mise env\" \"export PARENT=true\"\necho \"Test 5: Passed\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/config/test_config_create_with_filename",
    "content": "#!/usr/bin/env bash\n\nexport MISE_DEFAULT_CONFIG_FILENAME=mise.config.toml\n\nmise use tiny\n\nassert_contains \"mise config\" \"mise.config.toml\"\n"
  },
  {
    "path": "e2e/config/test_config_enable_tool",
    "content": "#!/usr/bin/env bash\n\nmkdir foo\ncat <<EOF >mise.toml\n[tools]\ndummy = 'latest'\n\n[settings]\nenable_tools = [\"foo\"]\nEOF\n\nassert_not_contains \"mise tool dummy 2>&1\" \"Config Source\"\n"
  },
  {
    "path": "e2e/config/test_config_enable_tools_empty",
    "content": "#!/usr/bin/env bash\n\n# Test that empty MISE_ENABLE_TOOLS doesn't crash mise\nexport MISE_ENABLE_TOOLS=\"\"\nmise ls\n\n# Test with whitespace-only\nexport MISE_ENABLE_TOOLS=\"  \"\nmise ls\n\n# Test that it behaves as if enable_tools is not set (all tools enabled except disabled ones)\ncat <<EOF >mise.toml\n[tools]\ntiny = 'latest'\nEOF\n\n# With empty enable_tools, tools should still be available\nexport MISE_ENABLE_TOOLS=\"\"\nassert_contains \"mise ls\" \"tiny\"\n\n# Test with trailing comma\nexport MISE_ENABLE_TOOLS=\"tiny,\"\nassert_contains \"mise ls\" \"tiny\"\n\n# Test with comma-separated list with spaces\nexport MISE_ENABLE_TOOLS=\"tiny, dummy\"\nassert_contains \"mise ls\" \"tiny\"\n"
  },
  {
    "path": "e2e/config/test_config_env",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2209\n\necho \"tools.dummy = '1'\" >mise.toml\necho \"tools.dummy = '2'\" >mise.test.toml\necho \"tools.dummy = '3'\" >mise.ci.toml\n\nassert \"mise ls dummy\" \"dummy  1.1.0 (missing)  ~/workdir/mise.toml  1\"\nMISE_ENV=test assert \"mise ls dummy\" \"dummy  2.0.0 (missing)  ~/workdir/mise.test.toml  2\"\nMISE_ENV=ci assert \"mise ls dummy\" \"dummy  3 (missing)  ~/workdir/mise.ci.toml  3\"\nMISE_ENV=ci,test assert \"mise ls dummy\" \"dummy  2.0.0 (missing)  ~/workdir/mise.test.toml  2\"\nMISE_ENV=test,ci assert \"mise ls dummy\" \"dummy  3 (missing)  ~/workdir/mise.ci.toml  3\"\n"
  },
  {
    "path": "e2e/config/test_config_fmt",
    "content": "#!/usr/bin/env bash\n\nexit 0 # this isn't working right\ncat <<EOF >mise.toml\nenv_path = \".\"\nenv_file = \".env\"\nmin_version = \"0\"\n[tasks.a]\n[tools]\n[tasks.c]\n[task_config]\n[tasks.b]\n[_]\n[tool_alias]\n[env]\n[hooks]\n[plugins]\n[redactions]\n[[watch_files]]\npatterns = [ \"src/**/*.rs\" ]\nrun = \"test\"\n[vars]\n[settings]\nEOF\n\nassert \"mise fmt\"\nassert 'cat mise.toml' 'min_version = \"0\"\nenv_file = \".env\"\nenv_path = \".\"\n[_]\n[env]\n[vars]\n[hooks]\n[[watch_files]]\n[tools]\n[tasks.a]\n[tasks.b]\n[tasks.c]\n[task_config]\n[redactions]\n[tool_alias]\n[plugins]\n[settings]'\n"
  },
  {
    "path": "e2e/config/test_config_ignore",
    "content": "#!/usr/bin/env bash\n\nexport MISE_TRUSTED_CONFIG_PATHS=\"\"\n\nmkdir subdir\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1.0.0\"\n[settings]\ngo_download_mirror = \"mise.toml\"\nEOF\ncat <<EOF >subdir/mise.toml\n[tools]\ndummy = \"2.0.0\"\n[settings]\ngo_download_mirror = \"subdir/mise.toml\"\nEOF\n\ncd subdir || exit 1\n\nassert \"mise trust --all\"\nassert \"mise cfg\" \"~/workdir/mise.toml         dummy\n~/workdir/subdir/mise.toml  dummy\"\nassert \"mise ls dummy\" \"dummy  2.0.0 (missing)  ~/workdir/subdir/mise.toml  2.0.0\"\nassert \"mise settings get go_download_mirror\" \"subdir/mise.toml\"\nassert \"mise trust --ignore\"\nassert \"mise cfg\" \"~/workdir/mise.toml  dummy\"\nassert \"mise settings get go_download_mirror\" \"mise.toml\"\nassert \"mise ls dummy\" \"dummy  1.0.0 (missing)  ~/workdir/mise.toml  1.0.0\"\nassert \"mise trust .\"\nassert \"mise cfg\" \"~/workdir/mise.toml         dummy\n~/workdir/subdir/mise.toml  dummy\"\nassert \"MISE_IGNORED_CONFIG_PATHS=~/workdir/subdir mise cfg\" \"~/workdir/mise.toml  dummy\"\nassert \"MISE_IGNORED_CONFIG_PATHS=~ mise cfg\" \"\"\nassert \"mise trust --ignore mise.toml\"\nassert \"mise trust --ignore ..\"\nassert \"mise cfg\" \"\"\nassert \"mise trust --all\"\nassert \"mise cfg\" \"~/workdir/mise.toml         dummy\n~/workdir/subdir/mise.toml  dummy\"\n\nrm -rf \"$MISE_STATE_DIR\"\nexport MISE_PARANOID=1\nassert \"mise trust --all\"\nassert \"mise cfg\" \"~/workdir/mise.toml         dummy\n~/workdir/subdir/mise.toml  dummy\"\n"
  },
  {
    "path": "e2e/config/test_config_plugins",
    "content": "#!/usr/bin/env bash\n\ncat >mise.toml <<EOF\n[tools]\nerlang = '1'\n[plugins]\nerlang = 'https://github.com/jdx/mise-tiny'\nEOF\n\nassert \"mise x erlang -- mise-tiny\" \"mise-tiny: v1.1.0\"\n"
  },
  {
    "path": "e2e/config/test_config_post_tools",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[[env]]\nA_PATH = \"foo: {{ env.PATH }}\"\nB_PATH = { value = \"foo: {{ env.PATH }}\", tools = true }\n[[env]]\n_.path = {value = \"tiny-{{env.JDXCODE_TINY}}-tiny\", tools = true}\n\n[tools]\ntiny = \"1.0.0\"\nEOF\n\nmise i\nassert_not_contains \"mise env | grep A_PATH\" \"tiny\"\nassert_contains \"mise env | grep B_PATH\" \"tiny\"\n\nassert_contains \"mise dr path\" \"tiny-1.0.0-tiny\"\n"
  },
  {
    "path": "e2e/config/test_env_non_ascii",
    "content": "#!/usr/bin/env bash\n# Test that mise handles environment variables with non-ASCII/invalid UTF-8 gracefully\n# This reproduces the bug where invalid UTF-8 environment variables cause mise to panic\n\n# Test 1: Non-MISE environment variables with special characters should not cause panics\nexport SOME_VAR_WITH_UNICODE=\"Ü Ä Ö ß à é\"\nexport HOMEBREW_INSTALL_BADGE=\"✅\"\n\n# Basic commands should work without panicking\nassert \"mise --version\"\nassert \"mise env\"\n\n# Test 2: MISE_*_VERSION variables with Unicode should work\nexport MISE_NODE_VERSION=\"20.0.0\"\nexport MISE_PYTHON_VERSION=\"3.11\"\n\nassert \"mise env\"\n\n# Test 3: Test with actual command that was reported in bug\n# This should not panic (may fail due to network but shouldn't panic)\nmise ls-remote bun >/dev/null 2>&1 || true\n"
  },
  {
    "path": "e2e/config/test_env_path_ordering",
    "content": "#!/usr/bin/env bash\n\n# Test that env._.path configuration correctly orders paths, even when those\n# paths already exist in the original PATH. This ensures user-configured paths\n# take precedence over system defaults.\n#\n# Regression test for PATH ordering bug where env._.path entries were being\n# filtered out if they already existed in __MISE_ORIG_PATH.\n# Related to commit f4dca1b512321fce097125d06be6de8654361536\n\n# Create a test directory structure to simulate custom and system bin dirs\nmkdir -p \"$HOME/custom/bin\"\nmkdir -p \"$HOME/system/bin\"\n\n# Create dummy executables to test ordering\ncat >\"$HOME/custom/bin/test-tool\" <<'EOF'\n#!/usr/bin/env bash\necho \"custom version\"\nEOF\n\ncat >\"$HOME/system/bin/test-tool\" <<'EOF'\n#!/usr/bin/env bash\necho \"system version\"\nEOF\n\nchmod +x \"$HOME/custom/bin/test-tool\"\nchmod +x \"$HOME/system/bin/test-tool\"\n\n# Add system/bin to PATH (simulating a system-provided tool that's already in PATH)\nexport PATH=\"$HOME/system/bin:$PATH\"\n\n# Verify system tool is found first before mise config\nassert_contains \"test-tool\" \"system version\"\n\n# Activate mise shell integration\neval \"$(mise activate bash)\"\n\n# Create a mise config that explicitly prepends custom/bin via env._.path\n# This should work even though system/bin is already in the original PATH\ncat >mise.toml <<EOF\n[env]\n_.path = [\n  \"$HOME/custom/bin\",\n  \"$HOME/system/bin\",\n]\nEOF\n\n# Apply the configuration via hook-env\neval \"$(mise hook-env)\"\n\necho \"DEBUG: Final PATH=$PATH\"\necho \"DEBUG: __MISE_ORIG_PATH=${__MISE_ORIG_PATH:-not set}\"\n\n# Now the test-tool from custom/bin should be found first\nassert_contains \"test-tool\" \"custom version\"\n\n# Verify the PATH order by checking which comes first\nWHICH_OUTPUT=$(which test-tool)\necho \"DEBUG: which test-tool = $WHICH_OUTPUT\"\n\n# The path should be custom/bin (not system/bin)\nif [[ $WHICH_OUTPUT == *\"/custom/bin/test-tool\" ]]; then\n\techo \"SUCCESS: custom/bin comes before system/bin in PATH\"\nelse\n\techo \"FAIL: Expected custom/bin/test-tool but got $WHICH_OUTPUT\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/config/test_hooks",
    "content": "#!/usr/bin/env bash\n\nmkdir foo\ncat <<EOF >mise.toml\n[tools]\ndummy = 'latest'\n[hooks]\nenter = 'echo HOOK-ENTER'\nleave = 'echo HOOK-LEAVE'\ncd = 'echo HOOK-CD'\npreinstall = 'echo PREINSTALL'\npostinstall = 'echo POSTINSTALL'\nEOF\n\nassert_contains \"mise i 2>&1\" \"PREINSTALL\"\nassert_contains \"mise i dummy@1 2>&1\" \"POSTINSTALL\"\nassert_contains \"mise i 2>&1\" \"POSTINSTALL\"\nassert_contains \"mise i dummy@1 2>&1\" \"POSTINSTALL\"\neval \"$(mise hook-env)\"\n\ncd ~/workdir || exit 1\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\n\ncd ~ || exit 1\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\neval \"$(mise hook-env)\"\n\ncd ~/workdir || exit 1\nassert_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\neval \"$(mise hook-env)\"\n\ncd ~/workdir/foo || exit 1\nassert_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\neval \"$(mise hook-env)\"\n\ncd ~ || exit 1\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\neval \"$(mise hook-env)\"\n\ncd ~/workdir/foo || exit 1\nassert_contains \"mise hook-env 2>&1\" \"HOOK-CD\"\nassert_contains \"mise hook-env 2>&1\" \"HOOK-ENTER\"\nassert_not_contains \"mise hook-env 2>&1\" \"HOOK-LEAVE\"\neval \"$(mise hook-env)\"\n"
  },
  {
    "path": "e2e/config/test_hooks_config_root",
    "content": "#!/usr/bin/env bash\n\n# Test that config_root in hooks correctly points to the project root\n# even when the config file is in a .mise/ subdirectory\n# See: https://github.com/jdx/mise/discussions/6531\n\n# Create project structure with .mise/config.toml\nmkdir -p .mise\ncat <<EOF >.mise/config.toml\n[hooks]\nenter = 'echo CONFIG_ROOT={{config_root}}'\nEOF\n\n# Initialize mise and go to home first\neval \"$(mise hook-env)\"\n\n# Leave the workdir (go home)\ncd ~ || exit 1\neval \"$(mise hook-env)\"\n\n# Now re-enter the workdir to trigger the enter hook\ncd ~/workdir || exit 1\n\n# The config_root should be ~/workdir, not ~/workdir/.mise\nassert_contains \"mise hook-env 2>&1\" \"CONFIG_ROOT=$HOME/workdir\"\nassert_not_contains \"mise hook-env 2>&1\" \"CONFIG_ROOT=$HOME/workdir/.mise\"\n"
  },
  {
    "path": "e2e/config/test_hooks_error_handling",
    "content": "#!/usr/bin/env bash\n\n# Test that hook errors are handled gracefully (no panics, warnings shown)\n\n# Test 1: Hooks with a failing script should warn but not crash\ncat <<EOF >mise.toml\n[tools]\ndummy = 'latest'\n[hooks]\npreinstall = 'exit 1'\npostinstall = 'echo POST'\nEOF\n\n# Preinstall fails but postinstall should still run and install should succeed\nrm -rf ~/.local/share/mise/installs/dummy\noutput=$(mise i 2>&1)\nassert_contains \"echo '$output'\" \"hook in\"\nassert_contains \"echo '$output'\" \"failed:\"\n# postinstall should still fire even though preinstall failed\nassert_contains \"echo '$output'\" \"POST\"\n\n# Test 2: Invalid hook script (nonexistent command) should warn\nrm -rf ~/.local/share/mise/installs/dummy\ncat <<EOF >mise.toml\n[tools]\ndummy = 'latest'\n[hooks]\npreinstall = 'nonexistent_command_12345'\nEOF\n\n# Should warn about hook error but not crash\noutput=$(mise i 2>&1)\nassert_contains \"echo '$output'\" \"hook in\"\nassert_contains \"echo '$output'\" \"failed:\"\n"
  },
  {
    "path": "e2e/config/test_hooks_global",
    "content": "#!/usr/bin/env bash\n\n# Test that hooks defined in global config (~/.config/mise/config.toml) work\n# See: https://github.com/jdx/mise/discussions/5264\n# See: https://github.com/jdx/mise/discussions/5293\n# See: https://github.com/jdx/mise/discussions/4875\n\n# Set up global config with hooks\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[hooks]\nenter = 'echo GLOBAL-ENTER'\nleave = 'echo GLOBAL-LEAVE'\ncd = 'echo GLOBAL-CD'\npreinstall = 'echo GLOBAL-PREINSTALL'\npostinstall = 'echo GLOBAL-POSTINSTALL'\nEOF\n\n# Set up a project config with tools\ncat <<EOF >mise.toml\n[tools]\ndummy = 'latest'\nEOF\n\n# Global preinstall/postinstall hooks should fire during install\nassert_contains \"mise i 2>&1\" \"GLOBAL-PREINSTALL\"\nassert_contains \"mise i dummy@1 2>&1\" \"GLOBAL-POSTINSTALL\"\n\n# Initialize hook-env session\neval \"$(mise hook-env)\"\n\n# Navigate away and back to trigger enter/leave/cd\ncd ~ || exit 1\nassert_contains \"mise hook-env 2>&1\" \"GLOBAL-LEAVE\"\neval \"$(mise hook-env)\"\n\ncd ~/workdir || exit 1\nassert_contains \"mise hook-env 2>&1\" \"GLOBAL-ENTER\"\nassert_contains \"mise hook-env 2>&1\" \"GLOBAL-CD\"\neval \"$(mise hook-env)\"\n\n# cd within workdir should still trigger global cd hook\nmkdir -p subdir\ncd ~/workdir/subdir || exit 1\nassert_contains \"mise hook-env 2>&1\" \"GLOBAL-CD\"\neval \"$(mise hook-env)\"\n"
  },
  {
    "path": "e2e/config/test_hooks_installed_tools",
    "content": "#!/usr/bin/env bash\n\n# Test that global postinstall hooks receive MISE_INSTALLED_TOOLS JSON array\n\ncat <<EOF >mise.toml\n[tools]\ndummy = \"latest\"\n\n[hooks]\npostinstall = \"echo INSTALLED_TOOLS=\\$MISE_INSTALLED_TOOLS\"\nEOF\n\n# Remove any existing dummy installation to force reinstall\nrm -rf ~/.mise/installs/dummy\n\n# Run install and capture output\noutput=$(mise install dummy 2>&1)\n\n# Check that MISE_INSTALLED_TOOLS is set and contains JSON\nif [[ $output == *'INSTALLED_TOOLS=[{\"name\":\"dummy\"'* ]]; then\n\techo \"✓ MISE_INSTALLED_TOOLS contains JSON with tool info\"\nelse\n\techo \"✗ MISE_INSTALLED_TOOLS is NOT set correctly\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Check that it includes the version field\nif [[ $output == *'\"version\":'* ]]; then\n\techo \"✓ MISE_INSTALLED_TOOLS includes version field\"\nelse\n\techo \"✗ MISE_INSTALLED_TOOLS does NOT include version field\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/config/test_hooks_postinstall_env",
    "content": "#!/usr/bin/env bash\n\n# Test that postinstall hooks have access to pre_tools environment variables\n\n# Create a mise.toml with env vars that should be available before tools\ncat <<EOF >mise.toml\n[env]\n# Environment variable without tools=true (should be available in postinstall)\nPRE_TOOLS_VAR = \"available_before_tools\"\n\n# Environment variable explicitly with tools=false\nEXPLICIT_PRE_TOOLS = {value = \"explicitly_pre_tools\", tools = false}\n\n# Environment variable with tools=true (should NOT be available in postinstall)\nPOST_TOOLS_VAR = {value = \"available_after_tools\", tools = true}\n\n[tools]\ndummy = { version = \"latest\", postinstall = \"echo PRE_TOOLS_VAR=\\$PRE_TOOLS_VAR; echo EXPLICIT_PRE_TOOLS=\\$EXPLICIT_PRE_TOOLS; echo POST_TOOLS_VAR=\\$POST_TOOLS_VAR\" }\nEOF\n\n# Remove any existing dummy installation to force reinstall\nrm -rf ~/.mise/installs/dummy\n\n# Run install and capture output\noutput=$(mise install dummy 2>&1)\n\n# Check that pre_tools environment variables are available in postinstall\nif [[ $output == *\"PRE_TOOLS_VAR=available_before_tools\"* ]]; then\n\techo \"✓ PRE_TOOLS_VAR is available in postinstall\"\nelse\n\techo \"✗ PRE_TOOLS_VAR is NOT available in postinstall\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\nif [[ $output == *\"EXPLICIT_PRE_TOOLS=explicitly_pre_tools\"* ]]; then\n\techo \"✓ EXPLICIT_PRE_TOOLS is available in postinstall\"\nelse\n\techo \"✗ EXPLICIT_PRE_TOOLS is NOT available in postinstall\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# The post_tools var should be empty since it's marked as tools=true\nif [[ $output == *\"POST_TOOLS_VAR=\"* ]]; then\n\techo \"✓ POST_TOOLS_VAR is empty as expected\"\nelse\n\techo \"✗ POST_TOOLS_VAR is not empty\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Verify that POST_TOOLS_VAR with tools=true is NOT available in postinstall hook\nif [[ $output != *\"POST_TOOLS_VAR=available_after_tools\"* ]]; then\n\techo \"✓ POST_TOOLS_VAR with tools=true is not available as expected\"\nelse\n\techo \"✗ POST_TOOLS_VAR with tools=true should not be available\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/config/test_hooks_shell_env",
    "content": "#!/usr/bin/env bash\n\n# Test that shell hooks receive environment variables\n# (MISE_PROJECT_ROOT, MISE_CONFIG_ROOT, MISE_ORIGINAL_CWD)\n# See: https://github.com/jdx/mise/discussions/4013\n# See: https://github.com/jdx/mise/discussions/6054\n\ncat <<EOF >mise.toml\n[hooks.enter]\nshell = \"bash\"\nscript = 'echo SHELL_PROJECT_ROOT=\\$MISE_PROJECT_ROOT'\nEOF\n\n# Initialize session\neval \"$(mise hook-env)\"\n\n# Leave workdir\ncd ~ || exit 1\neval \"$(mise hook-env)\"\n\n# Re-enter to trigger enter hook - check that MISE_PROJECT_ROOT is exported\ncd ~/workdir || exit 1\n\n# The output should contain an export of MISE_PROJECT_ROOT before the script\nassert_contains \"mise hook-env 2>&1\" \"MISE_PROJECT_ROOT\"\nassert_contains \"mise hook-env 2>&1\" \"MISE_CONFIG_ROOT\"\n"
  },
  {
    "path": "e2e/config/test_hooks_task_ref",
    "content": "#!/usr/bin/env bash\n\n# Test task references in hooks\n# Verifies that hooks can reference mise tasks instead of inline scripts\n\ncat <<'EOF' >mise.toml\n[tools]\ndummy = 'latest'\n\n[tasks.setup]\nrun = 'echo TASK-SETUP-RAN'\n\n[tasks.teardown]\nrun = 'echo TASK-TEARDOWN-RAN'\n\n[hooks]\nenter = { task = \"setup\" }\nleave = { task = \"teardown\" }\npreinstall = { task = \"setup\" }\nEOF\n\n# Test preinstall hook with task reference\nassert_contains \"mise i 2>&1\" \"TASK-SETUP-RAN\"\n\neval \"$(mise hook-env)\"\n\n# Leave directory should trigger task\ncd ~ || exit 1\nassert_contains \"mise hook-env 2>&1\" \"TASK-TEARDOWN-RAN\"\neval \"$(mise hook-env)\"\n\n# Enter directory should trigger task\ncd ~/workdir || exit 1\nassert_contains \"mise hook-env 2>&1\" \"TASK-SETUP-RAN\"\neval \"$(mise hook-env)\"\n\n# Test array of hooks mixing scripts and task references\ncat <<'EOF' >mise.toml\n[tasks.my-task]\nrun = 'echo MIXED-TASK-RAN'\n\n[hooks]\nenter = [\"echo MIXED-SCRIPT-RAN\", { task = \"my-task\" }]\nEOF\n\ncd ~ || exit 1\neval \"$(mise hook-env)\"\ncd ~/workdir || exit 1\noutput=$(mise hook-env 2>&1)\nassert_contains \"echo '$output'\" \"MIXED-SCRIPT-RAN\"\nassert_contains \"echo '$output'\" \"MIXED-TASK-RAN\"\n"
  },
  {
    "path": "e2e/config/test_hooks_tool_env",
    "content": "#!/usr/bin/env bash\n\n# Test that tool-level postinstall hooks receive MISE_TOOL_NAME and MISE_TOOL_VERSION\n\ncat <<EOF >mise.toml\n[tools]\ndummy = { version = \"latest\", postinstall = \"echo TOOL_NAME=\\$MISE_TOOL_NAME TOOL_VERSION=\\$MISE_TOOL_VERSION INSTALL_PATH=\\$MISE_TOOL_INSTALL_PATH\" }\nEOF\n\n# Remove any existing dummy installation to force reinstall\nrm -rf ~/.mise/installs/dummy\n\n# Run install and capture output\noutput=$(mise install dummy 2>&1)\n\n# Check that MISE_TOOL_NAME is set\nif [[ $output == *\"TOOL_NAME=dummy\"* ]]; then\n\techo \"✓ MISE_TOOL_NAME is set correctly\"\nelse\n\techo \"✗ MISE_TOOL_NAME is NOT set correctly\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Check that MISE_TOOL_VERSION is set (should be a version string)\nif [[ $output == *\"TOOL_VERSION=\"* ]] && [[ $output != *\"TOOL_VERSION= \"* ]]; then\n\techo \"✓ MISE_TOOL_VERSION is set\"\nelse\n\techo \"✗ MISE_TOOL_VERSION is NOT set\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Check that MISE_TOOL_INSTALL_PATH is set (contains mise/installs/dummy)\nif [[ $output == *\"INSTALL_PATH=\"* ]] && [[ $output == *\"/mise/installs/dummy\"* ]]; then\n\techo \"✓ MISE_TOOL_INSTALL_PATH is set\"\nelse\n\techo \"✗ MISE_TOOL_INSTALL_PATH is NOT set correctly\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/config/test_min_version",
    "content": "#!/usr/bin/env bash\n\n# soft min_version: should warn and succeed, showing instructions\ncat >instructions.toml <<'TOML'\nmessage = \"To update, run brew upgrade mise\"\nTOML\n\ncat >mise.toml <<'TOML'\nmin_version = { soft = \"9999.0.0\" }\nTOML\n\nassert_contains 'MISE_SELF_UPDATE_AVAILABLE=false MISE_SELF_UPDATE_INSTRUCTIONS=./instructions.toml MISE_LOG_LEVEL=warn mise ls 2>&1' 'recommended'\nassert_contains 'MISE_SELF_UPDATE_AVAILABLE=false MISE_SELF_UPDATE_INSTRUCTIONS=./instructions.toml MISE_LOG_LEVEL=warn mise ls 2>&1' 'brew upgrade mise'\n\n# hard min_version: should fail and include instructions\ncat >mise.toml <<'TOML'\nmin_version = { hard = \"9999.0.0\" }\nTOML\n\nassert_fail 'MISE_SELF_UPDATE_AVAILABLE=false MISE_SELF_UPDATE_INSTRUCTIONS=./instructions.toml mise ls 2>&1' 'is required'\nassert_fail 'MISE_SELF_UPDATE_AVAILABLE=false MISE_SELF_UPDATE_INSTRUCTIONS=./instructions.toml mise ls 2>&1' 'brew upgrade mise'\n"
  },
  {
    "path": "e2e/config/test_miserc",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2209\n\n# Test that .miserc.toml can set MISE_ENV\n\necho \"tools.dummy = '1'\" >mise.toml\necho \"tools.dummy = '2'\" >mise.test.toml\necho 'env = [\"test\"]' >.miserc.toml\n\n# .miserc.toml should set MISE_ENV=test, loading mise.test.toml\nassert \"mise ls dummy\" \"dummy  2.0.0 (missing)  ~/workdir/mise.test.toml  2\"\n\n# Env var should override .miserc.toml\nMISE_ENV=ci assert \"mise ls dummy\" \"dummy  1.1.0 (missing)  ~/workdir/mise.toml  1\"\n\n# Test ceiling_paths in .miserc.toml - subdirectory should pick up parent miserc\nrm -f .miserc.toml\necho 'env = [\"test\"]' >.miserc.toml\nmkdir -p subdir\ncd subdir || exit 1\n\n# Should still pick up parent .miserc.toml and mise.test.toml\nassert \"mise ls dummy\" \"dummy  2.0.0 (missing)  ~/workdir/mise.test.toml  2\"\n\ncd .. || exit 1\n"
  },
  {
    "path": "e2e/config/test_netrc",
    "content": "#!/usr/bin/env bash\n\n# Test netrc file support for HTTP authentication\n\n# Create a netrc file in the test home\ncat >\"$HOME/.netrc\" <<'EOF'\nmachine example.com\n  login testuser\n  password testpassword\n\ndefault\n  login anonymous\n  password anon@example.com\nEOF\n\nchmod 600 \"$HOME/.netrc\"\n\n# Test 1: Verify netrc setting is enabled by default\nassert \"mise settings get netrc\" \"true\"\n\n# Test 2: Verify netrc_file setting can be configured\ncat >mise.toml <<EOF\n[settings]\nnetrc_file = \"$HOME/.custom-netrc\"\nEOF\n\n# Create custom netrc\ncat >\"$HOME/.custom-netrc\" <<'EOF'\nmachine custom.example.com\n  login customuser\n  password custompass\nEOF\nchmod 600 \"$HOME/.custom-netrc\"\n\nassert_contains \"mise settings get netrc_file\" \".custom-netrc\"\n\n# Test 3: Verify netrc can be disabled\ncat >mise.toml <<EOF\n[settings]\nnetrc = false\nEOF\n\nassert \"mise settings get netrc\" \"false\"\n\n# Test 4: Verify netrc can be disabled via environment variable\nrm mise.toml\nMISE_NETRC=false assert \"mise settings get netrc\" \"false\"\nMISE_NETRC=0 assert \"mise settings get netrc\" \"false\"\n\n# Test 5: Verify netrc is enabled by default when not explicitly set\nassert \"mise settings get netrc\" \"true\"\n\n# Test 6: Verify MISE_NETRC_FILE environment variable works\nMISE_NETRC_FILE=\"$HOME/.env-netrc\" assert_contains \"mise settings get netrc_file\" \".env-netrc\"\n\n# Test 7: Verify netrc file permission warning (Unix only)\nif [[ \"$(uname -s)\" == \"Linux\" || \"$(uname -s)\" == \"Darwin\" ]]; then\n\t# Create netrc with insecure permissions\n\tcat >\"$HOME/.netrc\" <<'EOF'\nmachine secure.example.com\n  login secureuser\n  password securepass\nEOF\n\tchmod 644 \"$HOME/.netrc\" # World-readable - insecure!\n\n\t# Create a simple mise.toml that would trigger an HTTP request (and thus load netrc)\n\tcat >mise.toml <<'EOF'\n[tools]\n\"http:perm-test\" = { version = \"1.0.0\", url = \"http://secure.example.com/tool.tar.gz\" }\nEOF\n\n\t# Run mise install which will attempt to load netrc and show warning\n\t# We redirect to capture stderr where warnings go\n\toutput=$(mise install 2>&1 || true)\n\n\tif echo \"$output\" | grep -qi \"insecure permissions\"; then\n\t\techo \"PASS: Warning shown for insecure netrc permissions\"\n\telse\n\t\techo \"FAIL: No warning for insecure netrc permissions (mode 644)\"\n\t\techo \"Output: $output\"\n\t\texit 1\n\tfi\n\n\t# Fix permissions and verify no warning\n\tchmod 600 \"$HOME/.netrc\"\n\toutput=$(mise install 2>&1 || true)\n\n\tif echo \"$output\" | grep -qi \"insecure permissions\"; then\n\t\techo \"FAIL: Warning shown even with secure permissions (600)\"\n\t\techo \"Output: $output\"\n\t\texit 1\n\telse\n\t\techo \"PASS: No warning with secure netrc permissions\"\n\tfi\n\n\t# Cleanup\n\trm -f mise.toml\n\tmise uninstall --all >/dev/null 2>&1 || true\nelse\n\techo \"SKIP: Permission check test (non-Unix OS)\"\nfi\n\n# Find available port\nfind_available_port() {\n\tpython3 -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\"\n}\n\n# Start local HTTP test server with header logging\nHEADERS_LOG_DIR=$(mktemp -d)\nSERVER_PORT=$(find_available_port)\npython3 \"${TEST_ROOT}/helpers/scripts/http_test_server.py\" \"$SERVER_PORT\" \"$HEADERS_LOG_DIR\" &\nSERVER_PID=$!\nsleep 1\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\trm -rf \"$HEADERS_LOG_DIR\"\n\trm -f /tmp/mise_http_test_port\n}\ntrap cleanup EXIT\n\n# Test 8: Verify Authorization header is sent when netrc has matching credentials\ncat >\"$HOME/.netrc\" <<EOF\nmachine 127.0.0.1\n  login testuser\n  password testpass123\nEOF\nchmod 600 \"$HOME/.netrc\"\n\nrm -f mise.toml\nrm -f \"$HEADERS_LOG_DIR\"/request_*.json\n\ncat >mise.toml <<EOF\n[tools]\n\"http:auth-test\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$SERVER_PORT/tool.tar.gz\" }\nEOF\n\n# Trigger HTTP request with mise install (will fail to extract but will make the request)\nmise install >/dev/null 2>&1 || true\n\n# Check headers log for Authorization\nif grep -qi '\"authorization\"' \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null; then\n\techo \"PASS: Authorization header was sent\"\nelse\n\techo \"FAIL: Authorization header was not sent\"\n\tcat \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null || echo \"No request logs found\"\n\texit 1\nfi\n\nrm -f mise.toml\nmise uninstall --all >/dev/null 2>&1 || true\n\n# Test 9: Verify NO Authorization header when netrc is disabled\ncat >\"$HOME/.netrc\" <<EOF\nmachine 127.0.0.1\n  login testuser\n  password testpass123\nEOF\nchmod 600 \"$HOME/.netrc\"\n\nrm -f \"$HEADERS_LOG_DIR\"/request_*.json\n\ncat >mise.toml <<EOF\n[settings]\nnetrc = false\n\n[tools]\n\"http:no-auth-test\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$SERVER_PORT/tool.tar.gz\" }\nEOF\n\nmise install >/dev/null 2>&1 || true\n\n# Check headers log - should NOT have Authorization\nif grep -qi '\"authorization\"' \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null; then\n\techo \"FAIL: Authorization header was sent when netrc was disabled\"\n\tcat \"$HEADERS_LOG_DIR\"/request_*.json\n\texit 1\nelse\n\techo \"PASS: No Authorization header when netrc disabled\"\nfi\n\nrm -f mise.toml\nmise uninstall --all >/dev/null 2>&1 || true\n\n# Test 10: Verify netrc credentials are used with URL replacements\n# The netrc lookup happens AFTER URL replacement, so use the replaced host\ncat >\"$HOME/.netrc\" <<EOF\nmachine 127.0.0.1\n  login urlrepl-user\n  password urlrepl-pass\nEOF\nchmod 600 \"$HOME/.netrc\"\n\nrm -f \"$HEADERS_LOG_DIR\"/request_*.json\n\ncat >mise.toml <<EOF\n[settings]\nurl_replacements = { \"http://fake.example.com\" = \"http://127.0.0.1:$SERVER_PORT\" }\n\n[tools]\n\"http:urlrepl-test\" = { version = \"1.0.0\", url = \"http://fake.example.com/tool.tar.gz\" }\nEOF\n\nmise install >/dev/null 2>&1 || true\n\n# Check headers log for Authorization\nif grep -qi '\"authorization\"' \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null; then\n\techo \"PASS: Authorization header sent with URL replacement\"\nelse\n\techo \"FAIL: Authorization header was not sent after URL replacement\"\n\tcat \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null || echo \"No request logs found\"\n\texit 1\nfi\n\nrm -f mise.toml\nmise uninstall --all >/dev/null 2>&1 || true\n\n# Test 11: Verify netrc credentials override GitHub token when URL is replaced\n# The netrc lookup happens AFTER URL replacement, netrc takes precedence over GitHub token\ncat >\"$HOME/.netrc\" <<EOF\nmachine 127.0.0.1\n  login override-user\n  password override-pass\nEOF\nchmod 600 \"$HOME/.netrc\"\n\nrm -f \"$HEADERS_LOG_DIR\"/request_*.json\n\ncat >mise.toml <<EOF\n[settings]\nurl_replacements = { \"https://api.github.com\" = \"http://127.0.0.1:$SERVER_PORT\" }\n\n[tools]\n\"http:github-override-test\" = { version = \"1.0.0\", url = \"https://api.github.com/tool.tar.gz\" }\nEOF\n\n# Set a GitHub token - this should be OVERRIDDEN by netrc credentials for 127.0.0.1\nGITHUB_TOKEN=\"test-github-token-12345\" mise install >/dev/null 2>&1 || true\n\n# Check that authorization header exists and contains Basic auth (from netrc), not the GitHub token\nif grep -q '\"authorization\": \"Basic' \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null; then\n\techo \"PASS: Netrc credentials override GitHub token after URL replacement\"\nelse\n\techo \"FAIL: Expected netrc Basic auth to override GitHub token\"\n\tcat \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null || echo \"No request logs found\"\n\texit 1\nfi\n\nrm -f mise.toml\nmise uninstall --all >/dev/null 2>&1 || true\n\n# Test 12: Verify mise uses custom netrc file location with actual HTTP request\n# Remove default netrc if it exists\nrm -f \"$HOME/.netrc\"\n\n# Create custom netrc in a non-default location\nCUSTOM_NETRC_PATH=\"$HOME/.config/custom-netrc-file\"\nmkdir -p \"$(dirname \"$CUSTOM_NETRC_PATH\")\"\ncat >\"$CUSTOM_NETRC_PATH\" <<EOF\nmachine 127.0.0.1\n  login custom-location-user\n  password custom-location-pass\nEOF\nchmod 600 \"$CUSTOM_NETRC_PATH\"\n\nrm -f \"$HEADERS_LOG_DIR\"/request_*.json\n\ncat >mise.toml <<EOF\n[settings]\nnetrc_file = \"$CUSTOM_NETRC_PATH\"\n\n[tools]\n\"http:custom-netrc-test\" = { version = \"1.0.0\", url = \"http://127.0.0.1:$SERVER_PORT/tool.tar.gz\" }\nEOF\n\nmise install >/dev/null 2>&1 || true\n\n# Check that authorization header exists (proving custom netrc was used)\nif grep -qi '\"authorization\"' \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null; then\n\techo \"PASS: Custom netrc file location was used\"\nelse\n\techo \"FAIL: No Authorization header found when using custom netrc location\"\n\tcat \"$HEADERS_LOG_DIR\"/request_*.json 2>/dev/null || echo \"No request logs found\"\n\texit 1\nfi\n\nrm -f mise.toml\nrm -f \"$CUSTOM_NETRC_PATH\"\nmise uninstall --all >/dev/null 2>&1 || true\n\necho \"All netrc tests passed!\"\n"
  },
  {
    "path": "e2e/config/test_no_config",
    "content": "#!/usr/bin/env bash\n\ntouch mise.toml\nassert_empty \"mise --no-config cfg\"\nMISE_NO_CONFIG=1 assert_empty \"mise cfg\"\n"
  },
  {
    "path": "e2e/config/test_path_post_activate_append",
    "content": "#!/usr/bin/env bash\n\n# Test that paths appended to PATH after `mise activate` are not reordered\n# to the front. Paths added after activation that appear at the end of PATH\n# should stay at the end after hook-env runs.\n#\n# Regression test for https://github.com/jdx/mise/discussions/7694\n# where `mise activate` would move post-activation appended paths to the\n# beginning of PATH, changing the intended priority order.\n\n# Create test directories\nmkdir -p \"$HOME/system/bin\"\nmkdir -p \"$HOME/appended/bin\"\n\n# Create executables in both dirs with the same name\ncat >\"$HOME/system/bin/test-priority\" <<'EOF'\n#!/usr/bin/env bash\necho \"system version\"\nEOF\n\ncat >\"$HOME/appended/bin/test-priority\" <<'EOF'\n#!/usr/bin/env bash\necho \"appended version\"\nEOF\n\nchmod +x \"$HOME/system/bin/test-priority\"\nchmod +x \"$HOME/appended/bin/test-priority\"\n\n# Set up initial PATH with system/bin\nexport PATH=\"$HOME/system/bin:$PATH\"\n\n# Activate mise (this captures __MISE_ORIG_PATH)\neval \"$(mise activate bash)\"\n\n# Simulate a user appending a path AFTER mise activation (e.g., path+=$FOO/bin in .zshrc)\nexport PATH=\"$PATH:$HOME/appended/bin\"\n\n# Create an empty mise.toml so hook-env has something to work with\ncat >mise.toml <<'EOF'\nEOF\n\n# Run hook-env to reconstruct PATH\neval \"$(mise hook-env)\"\n\necho \"DEBUG: Final PATH=$PATH\"\necho \"DEBUG: __MISE_ORIG_PATH=${__MISE_ORIG_PATH:-not set}\"\n\n# The system version should still win because system/bin was earlier in PATH\n# and appended/bin was added at the end\nassert_contains \"test-priority\" \"system version\"\n\n# Verify appended/bin is AFTER system/bin in PATH (not moved to front)\nSYSTEM_POS=$(echo \"$PATH\" | tr ':' '\\n' | grep -n \"system/bin\" | head -1 | cut -d: -f1)\nAPPENDED_POS=$(echo \"$PATH\" | tr ':' '\\n' | grep -n \"appended/bin\" | head -1 | cut -d: -f1)\n\necho \"DEBUG: system/bin at position $SYSTEM_POS, appended/bin at position $APPENDED_POS\"\n\nif [[ $APPENDED_POS -gt $SYSTEM_POS ]]; then\n\techo \"SUCCESS: appended/bin stays after system/bin in PATH\"\nelse\n\techo \"FAIL: appended/bin ($APPENDED_POS) was moved before system/bin ($SYSTEM_POS)\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/config/test_required_env_vars",
    "content": "#!/usr/bin/env bash\n\n# Test 1: Required env var defined before mise runs (should succeed)\nexport REQUIRED_VAR1=\"predefined_value\"\n\ncat <<EOF >mise.toml\n[env]\nREQUIRED_VAR1 = { required = true }\nNORMAL_VAR = \"normal_value\"\nEOF\n\n# This should succeed\nmise env >/dev/null\n\n# Test 2: Required env var defined in a later config file (should succeed)\nunset REQUIRED_VAR1\n\ncat <<EOF >mise.toml\n[env]\nREQUIRED_VAR2 = { required = true }\nNORMAL_VAR = \"normal_value\"\nEOF\n\ncat <<EOF >mise.local.toml\n[env]\nREQUIRED_VAR2 = \"overridden_in_local\"\nEOF\n\n# This should also succeed\nmise env >/dev/null\n\n# Test 3: Required env var not defined anywhere (should fail)\nrm -f mise.local.toml\n\ncat <<EOF >mise.toml\n[env]\nREQUIRED_VAR3 = { required = true }\nNORMAL_VAR = \"normal_value\"\nEOF\n\nunset REQUIRED_VAR3\n\n# This should fail with a clear error message\nif mise env 2>error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"cat error.log\" \"Required environment variable 'REQUIRED_VAR3' is not defined\"\n\n# Test 4: Multiple required vars, some defined, some not (should fail)\nexport REQUIRED_VAR4=\"defined\"\n\ncat <<EOF >mise.toml\n[env]\nREQUIRED_VAR4 = { required = true }\nREQUIRED_VAR5 = { required = true }\nNORMAL_VAR = \"normal_value\"\nEOF\n\nunset REQUIRED_VAR5\n\nif mise env 2>error2.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"cat error2.log\" \"Required environment variable 'REQUIRED_VAR5' is not defined\"\n"
  },
  {
    "path": "e2e/config/test_required_env_vars_help",
    "content": "#!/usr/bin/env bash\n# Tests for required environment variables with help text\n\nset -euo pipefail\n\nassert_contains() {\n\tlocal output\n\toutput=\"${1}\"\n\tshift\n\tif ! echo \"${output}\" | grep -q \"$@\"; then\n\t\techo \"Expected to find '$*' in:\"\n\t\techo \"${output}\"\n\t\texit 1\n\tfi\n}\n\n# Test 1: Required env var with boolean value\ncat >mise.toml <<'EOF'\n[env]\nREQUIRED_BOOL = { required = true }\nEOF\n\nunset REQUIRED_BOOL || true\n\n# This should fail with basic message\nif mise env 2>error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"$(cat error.log)\" \"Required environment variable 'REQUIRED_BOOL' is not defined\"\necho \"Test 1 passed: Boolean required validation works\"\n\n# Test 2: Required env var with help text\ncat >mise.toml <<'EOF'\n[env]\nAPI_KEY = { required = \"Set API_KEY to your API key from https://example.com/api-keys\" }\nEOF\n\nunset API_KEY || true\n\n# This should fail with help message\nif mise env 2>error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"$(cat error.log)\" \"Required environment variable 'API_KEY' is not defined\"\nassert_contains \"$(cat error.log)\" \"Help: Set API_KEY to your API key from https://example.com/api-keys\"\necho \"Test 2 passed: Help text is shown in error message\"\n\n# Test 3: Required env var with help text that's satisfied\ncat >mise.toml <<'EOF'\n[env]\nDATABASE_URL = { required = \"Set DATABASE_URL to your PostgreSQL connection string\" }\nEOF\n\n# This should succeed when env var is set\nexport DATABASE_URL=\"postgres://localhost/mydb\"\nmise env >/dev/null\necho \"Test 3 passed: Required env var with help text works when satisfied\"\n\n# Test 4: hook-env should only warn\ncat >mise.toml <<'EOF'\n[env]\nHOOK_TEST = { required = \"Set HOOK_TEST to enable feature X\" }\nEOF\n\nunset HOOK_TEST || true\n\n# hook-env should warn but not fail\nmise hook-env --shell bash 2>error.log >/dev/null\nassert_contains \"$(cat error.log)\" \"WARN\"\nassert_contains \"$(cat error.log)\" \"Help: Set HOOK_TEST to enable feature X\"\necho \"Test 4 passed: hook-env warns about missing required env vars\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/config/test_required_env_vars_hook_env",
    "content": "#!/usr/bin/env bash\n\n# Test that hook-env warns about missing required env vars instead of failing\n\n# Create test config with required env var\ncat <<EOF >mise.toml\n[env]\nREQUIRED_VAR_HOOK = { required = true }\nNORMAL_VAR = \"normal_value\"\nEOF\n\n# Ensure the required var is not set\nunset REQUIRED_VAR_HOOK\n\n# hook-env should succeed but emit a warning\nmise hook-env --shell bash >hook_output.log 2>hook_error.log\n\n# Check that hook-env succeeded and exported the normal var\n# Note: REQUIRED_VAR_HOOK should NOT be in output since it's not defined and has no value\nassert_contains \"cat hook_output.log\" \"export NORMAL_VAR=normal_value\"\n\n# Check that it emitted a warning\nassert_contains \"cat hook_error.log\" \"Required environment variable 'REQUIRED_VAR_HOOK' is not defined\"\n\n# Verify that regular mise env still fails\nif mise env 2>env_error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"cat env_error.log\" \"Required environment variable 'REQUIRED_VAR_HOOK' is not defined\"\n"
  },
  {
    "path": "e2e/config/test_required_env_vars_tools_filter",
    "content": "#!/usr/bin/env bash\n# Tests that required env vars are only validated when their tools filter matches\n\nset -euo pipefail\n\nassert_contains() {\n\tlocal output\n\toutput=\"${1}\"\n\tshift\n\tif ! echo \"${output}\" | grep -q \"$@\"; then\n\t\techo \"Expected to find '$*' in:\"\n\t\techo \"${output}\"\n\t\texit 1\n\tfi\n}\n\nassert_not_contains() {\n\tlocal output\n\toutput=\"${1}\"\n\tshift\n\tif echo \"${output}\" | grep -q \"$@\"; then\n\t\techo \"Did not expect to find '$*' in:\"\n\t\techo \"${output}\"\n\t\texit 1\n\tfi\n}\n\n# Test 1: env command should NOT check tool-specific required vars\ncat >mise.toml <<'EOF'\n[env]\nTOOL_REQUIRED = { required = true, tools = true }\nNORMAL_REQUIRED = { required = true }\nEOF\n\nunset TOOL_REQUIRED NORMAL_REQUIRED || true\n\n# This should fail only on NORMAL_REQUIRED, not TOOL_REQUIRED\nif mise env 2>error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"$(cat error.log)\" \"NORMAL_REQUIRED\"\nassert_not_contains \"$(cat error.log)\" \"TOOL_REQUIRED\"\necho \"Test 1 passed: env command doesn't check tool-specific required vars\"\n\n# Test 2: exec command SHOULD check tool-specific required vars\nexport NORMAL_REQUIRED=\"set\"\nunset TOOL_REQUIRED || true\n\nif mise exec -- echo test 2>error.log; then\n\techo \"ERROR: Expected mise exec to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"$(cat error.log)\" \"TOOL_REQUIRED\"\necho \"Test 2 passed: exec command checks tool-specific required vars\"\n\n# Test 3: Both vars satisfied should work\nexport TOOL_REQUIRED=\"set\"\nexport NORMAL_REQUIRED=\"set\"\n\nmise env >/dev/null\nmise exec -- echo test >/dev/null\necho \"Test 3 passed: Both types of required vars work when satisfied\"\n\n# Test 4: Non-tool directives with tools=false should be validated by env\ncat >mise.toml <<'EOF'\n[env]\nNON_TOOL_VAR = { required = \"Set NON_TOOL_VAR for development\" }\nEOF\n\nunset NON_TOOL_VAR || true\n\nif mise env 2>error.log; then\n\techo \"ERROR: Expected mise env to fail but it succeeded\"\n\texit 1\nfi\n\nassert_contains \"$(cat error.log)\" \"NON_TOOL_VAR\"\nassert_contains \"$(cat error.log)\" \"Set NON_TOOL_VAR for development\"\necho \"Test 4 passed: Non-tool directives are validated by env command\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/config/test_schema_tombi",
    "content": "#!/usr/bin/env bash\n\n# Validate that the mise JSON schema works correctly with tombi (strict mode).\n# Regression test for https://github.com/jdx/mise/discussions/8254\n# where unevaluatedProperties caused tombi to reject valid task properties.\n\n# Install tombi via mise\nmise use -g tombi\n\nSCHEMA_PATH=\"$ROOT/schema/mise.json\"\nTOMBI=\"mise x tombi -- tombi\"\n\n# Set up tombi config pointing to local schema\ncat >\"$HOME/tombi.toml\" <<EOF\ntoml-version = \"v1.0.0\"\n\n[schema]\nenabled = true\nstrict = true\n\n[[schemas]]\npath = \"file://$SCHEMA_PATH\"\ninclude = [\"mise.toml\"]\nEOF\n\n# Create a mise.toml exercising task properties that were previously broken\ncat >\"$HOME/workdir/mise.toml\" <<'TOML'\n[task_templates.base]\nquiet = true\ndir = \"{{config_root}}\"\n\n[tasks.build]\ndescription = \"Build the project\"\ndepends = [\"lint\"]\nrun = \"cargo build\"\ndir = \"{{config_root}}\"\nquiet = true\nusage = \"build [args]\"\n\n[tasks.lint]\nextends = \"base\"\nrun = \"cargo clippy\"\ndescription = \"Lint the project\"\nTOML\n\n# tombi lint should succeed with no errors (warnings about table order are ok)\ncd \"$HOME/workdir\"\nassert_succeed \"$TOMBI lint --offline --no-cache --quiet mise.toml\"\n\n# Verify that invalid properties on tasks are rejected\ncat >\"$HOME/workdir/mise-bad.toml\" <<'TOML'\n[tasks.build]\ndescription = \"Build the project\"\nrun = \"cargo build\"\nbogus_invalid_property = \"should fail\"\nTOML\n\ncat >\"$HOME/tombi.toml\" <<EOF\ntoml-version = \"v1.0.0\"\n\n[schema]\nenabled = true\nstrict = true\n\n[[schemas]]\npath = \"file://$SCHEMA_PATH\"\ninclude = [\"mise-bad.toml\", \"mise-bad-tmpl.toml\"]\nEOF\n\nassert_fail \"$TOMBI lint --offline --no-cache --quiet mise-bad.toml\"\n\n# Verify that extends is rejected on task_templates (not supported at runtime)\ncat >\"$HOME/workdir/mise-bad-tmpl.toml\" <<'TOML'\n[task_templates.derived]\nextends = \"base\"\nquiet = true\nTOML\n\nassert_fail \"$TOMBI lint --offline --no-cache --quiet mise-bad-tmpl.toml\"\n"
  },
  {
    "path": "e2e/config/test_tool_version_vars",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Test that env works with vars template (this already works)\ncat <<EOF >mise.toml\n[env]\nFOO = \"{{vars.BAR}}\"\n\n[vars]\nBAR = \"test\"\nEOF\n\nassert_contains \"mise env -s bash | grep FOO\" \"export FOO=test\"\n\n# Now test using vars in tool version\ncat <<EOF >mise.toml\n[vars]\nTINY_VERSION = \"3.1.0\"\n\n[tools]\ntiny = \"{{vars.TINY_VERSION}}\"\nEOF\n\n# Check that the tool request includes the expanded version\nmise install tiny@3.1.0 >/dev/null 2>&1 || true\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Test with more complex expression\ncat <<EOF >mise.toml\n[vars]\nNODE_MAJOR = \"20\"\n\n[tools]\nnode = \"{{vars.NODE_MAJOR}}\"\nEOF\n\n# Just check that it tries to resolve it correctly\nmise install node@20 >/dev/null 2>&1 || true\nassert_contains \"mise ls node\" \"20\"\n\n# Test using env variables in tool versions (should already work)\ncat <<EOF >mise.toml\n[tools]\ntiny = \"{{ env.MISE_TINY_VERSION | default(value='3.0.0') }}\"\nEOF\n\nMISE_TINY_VERSION=3.1.0 mise install >/dev/null 2>&1 || true\nMISE_TINY_VERSION=3.1.0 assert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Test vars that contain templates themselves\ncat <<EOF >mise.toml\n[vars]\nBASE_VERSION = \"3\"\nTINY_VERSION = \"{{vars.BASE_VERSION}}.1.0\"\n\n[tools]\ntiny = \"{{vars.TINY_VERSION}}\"\nEOF\n\n# This should resolve to 3.1.0\nassert_contains \"mise ls tiny\" \"3.1.0\"\n\n# Test more complex nested templating\ncat <<EOF >mise.toml\n[vars]\nMAJOR = \"20\"\nMINOR = \"11\"\nNODE_VERSION = \"{{vars.MAJOR}}.{{vars.MINOR}}.0\"\n\n[tools]\nnode = \"{{vars.NODE_VERSION}}\"\nEOF\n\n# This should resolve to 20.11.0\nassert_contains \"mise ls node\" \"20.11.0\"\n"
  },
  {
    "path": "e2e/config/test_tool_versions_alt",
    "content": "#!/usr/bin/env bash\n\nexport MISE_USE_TOML=0\nexport MISE_DEFAULT_TOOL_VERSIONS_FILENAME=.alternate-tool-versions\nexport MISE_DEFAULT_CONFIG_FILENAME=.MISSING\n\ncat <<EOF >\"$MISE_DEFAULT_TOOL_VERSIONS_FILENAME\"\ntiny 3.1.0\nEOF\n\nmise i tiny\nassert \"mise local\" \"tiny 3.1.0\"\nassert_contains \"mise exec -- rtx-tiny\" \"v3.1.0\"\n\nmise local -p tiny@2.0.0\nmise i tiny\nassert \"mise local -p\" \"tiny 2.0.0\"\nassert_contains \"mise exec -- rtx-tiny\" \"v2.0.0\"\n\nmise local -p tiny@3.5.0\nassert \"mise local tiny\" \"3.5.0\"\n"
  },
  {
    "path": "e2e/core/test_bun",
    "content": "#!/usr/bin/env bash\n\n# Enable idiomatic version files for bun\nmise settings set idiomatic_version_file_enable_tools bun\n\ncat <<EOF >.bun-version\n1.1.21\nEOF\n\nassert \"mise i\"\nassert_contains \"mise x bun -- bun -v\" \"1.1.21\"\n\nrequire_cmd node\nassert_contains 'mise x bun -- bunx cowsay \"hello world\"' \"hello world\"\n"
  },
  {
    "path": "e2e/core/test_deno",
    "content": "#!/usr/bin/env bash\n\nif [[ ${MISE_DISABLE_TOOLS:-} == *deno* ]]; then\n\twarn \"Skipping deno tests\"\n\texit 0\nfi\n\ncat <<EOF >.deno-version\n1.43.3\nEOF\n\n# Enable idiomatic version files for deno\nmise settings set idiomatic_version_file_enable_tools deno\n\nmise i deno\nassert_contains \"mise x deno -- deno -V\" \"deno 1.43.3\"\n"
  },
  {
    "path": "e2e/core/test_dotnet",
    "content": "#!/usr/bin/env bash\n\nexport MISE_DOTNET_ROOT=\"$MISE_DATA_DIR/dotnet-root\"\n\nassert_contains \"mise x dotnet@8.0.408 -- dotnet --version\" \"8.0.408\"\n\n# Test global.json idiomatic file support\nmise settings set idiomatic_version_file_enable_tools dotnet\n\ncat <<EOF >global.json\n{\n  \"sdk\": {\n    \"version\": \"8.0.408\"\n  }\n}\nEOF\n\nassert_contains \"mise x -- dotnet --version\" \"8.0.408\"\n"
  },
  {
    "path": "e2e/core/test_erlang_slow",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use erlang@27.2\"\nassert_contains \"mise x -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell\" \"27\"\nassert_contains \"mise x elixir@1.17.3 -- elixir --version 2>&1\" \"Elixir 1.17.3\"\nassert_contains \"mise x elixir@1.17.3 -- mix --version 2>&1\" \"Mix 1.17.3\"\n\nassert_not_contains \"mise env\" \"MIX_HOME\"\nassert_not_contains \"mise env\" \"MIX_ARCHIVES\"\nassert \"mise use elixir@1.17.3\"\nassert_contains \"mise env\" \"MIX_HOME\"\nassert_contains \"mise env\" \"MIX_ARCHIVES\"\n\n# Test that MIX_HOME is not overridden when set via mise set\nassert \"mise set MIX_HOME=/mise/set/mix/home\"\nassert_contains \"mise env\" \"MIX_HOME=/mise/set/mix/home\"\nassert \"mise unset MIX_HOME\"\n\n# Test that MIX_ARCHIVES is not overridden when set via mise set\nassert \"mise set MIX_ARCHIVES=/mise/set/mix/archives\"\nassert_contains \"mise env\" \"MIX_ARCHIVES=/mise/set/mix/archives\"\nassert \"mise unset MIX_ARCHIVES\"\n\n# Test that MIX_HOME is not overridden when set in pristine environment\n# When env var is already set, mise won't set it, so it won't appear in mise env output\nassert_not_contains \"MIX_HOME=/custom/mix/home mise env\" \"MIX_HOME=\"\n\n# Test that MIX_ARCHIVES is not overridden when set in pristine environment\n# When env var is already set, mise won't set it, so it won't appear in mise env output\nassert_not_contains \"MIX_ARCHIVES=/custom/mix/archives mise env\" \"MIX_ARCHIVES=\"\n"
  },
  {
    "path": "e2e/core/test_go_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_GO_DEFAULT_PACKAGES_FILE=\"$HOME/.default-go-packages\"\n\ncat >\"$MISE_GO_DEFAULT_PACKAGES_FILE\" <<EOF\ngithub.com/jdx/go-example # comment\nEOF\n\nmise use golang@1.20\n\nassert_contains \"mise x -- go version\" \"go version go1.20\"\nassert \"mise x -- go env GOBIN\" \"${MISE_DATA_DIR}/installs/go/1.20/bin\"\nassert_contains \"mise x -- go-example\" \"hello world\"\n\n# ensure go.mod does not prevent installation on version mismatch\nmkdir -p \"$HOME/go-mod/\"\ncd \"$HOME/go-mod/\" || exit 1\ncat >\"go.mod\" <<EOF\npackage github.com/jdx/go-example\ngo 1.22\nEOF\nassert_fail \"mise x go@1.21.4 -- go version\"\nassert_contains \"mise ls go\" \"go  1.21.4\"\ncd -\nrm -rf \"$HOME/go-mod/\"\n\n# Required to properly cleanup as go installs read-only sources\nchmod -R +w ~/go\n"
  },
  {
    "path": "e2e/core/test_gopath",
    "content": "#!/usr/bin/env bash\n\necho \"golang 1.20\" >.tool-versions\nmkdir 21\necho \"golang 1.21\" >21/.tool-versions\n\nexport MISE_GO_SET_GOPATH=1\n\neval \"$(mise activate bash)\"\n_mise_hook\n\nGO_20=$(mise latest golang@1.20)\nGO_21=$(mise latest golang@1.21)\n\nmise i golang@1.20 golang@1.21 && _mise_hook\n\nassert \"go env GOPATH\" \"$MISE_DATA_DIR/installs/go/$GO_20/packages\"\ncd 21 && _mise_hook\nassert \"go env GOPATH\" \"$MISE_DATA_DIR/installs/go/$GO_21/packages\"\ncd .. && _mise_hook\nassert \"go env GOPATH\" \"$MISE_DATA_DIR/installs/go/$GO_20/packages\"\n"
  },
  {
    "path": "e2e/core/test_java_corretto",
    "content": "#!/usr/bin/env bash\n\nassert_contains \"mise x java@corretto-8 -- java -version 2>&1\" \"Corretto-8\"\n"
  },
  {
    "path": "e2e/core/test_java_shorthand_vendor_slow",
    "content": "#!/usr/bin/env bash\n\n# Test default OpenJDK vendor\nmise i java@17\nassert_not_contains \"mise x java@17 -- java -version 2>&1\" 'Temurin-17'\nmise cache clear\n\n# Test setting shorthand vendor to Temurin\nmise settings set java.shorthand_vendor temurin\nmise i java@21\nassert_contains \"mise x java@21 -- java -version 2>&1\" 'Temurin-21'\n\n# Ensure sort order of ls-remote for shorthand vendor\ntemurin=$(mise ls-remote java@temurin-21 | sed 's/temurin-//')\n# Create regex pattern with escaped special chars and pipe-separated alternatives\npattern=$(echo \"$temurin\" | sed 's/\\./\\\\./g; s/+/\\\\+/g' | paste -sd '|' -)\nassert_matches \"mise ls-remote java@21\" \"$pattern\"\n"
  },
  {
    "path": "e2e/core/test_java_slow",
    "content": "#!/usr/bin/env bash\n\n# Enable idiomatic version files for java\nmise settings set idiomatic_version_file_enable_tools java\n\ncat <<EOF >.sdkmanrc\njava=17.0.2\nEOF\nmise i java\nassert_contains \"mise x java -- java -version 2>&1\" 'openjdk version \"17.0.2\"'\nrm .sdkmanrc\n\ncat <<EOF >.java-version\n17.0.2\nEOF\nassert_contains \"mise x java -- java -version 2>&1\" 'openjdk version \"17.0.2\"'\nrm .java-version\n\n# Test installing EA version of Java\n# Extract EA major version from: Early access: <a href=\"/27/\">JDK 27</a>\nEA_MAJOR=$(curl -sSL \"https://jdk.java.net\" | grep -o 'Early access:.*href=\"/[0-9]\\+/\"' | grep -oE '[0-9]+' | head -1)\nif [[ -z $EA_MAJOR ]]; then\n\tEA_MAJOR=27\nfi\nmise i \"java[release_type=ea]@openjdk-${EA_MAJOR}.0.0-ea\"\nassert_contains \"mise x java@openjdk-${EA_MAJOR}.0.0-ea -- java -version 2>&1\" \"openjdk version \\\"${EA_MAJOR}-ea\\\"\"\n"
  },
  {
    "path": "e2e/core/test_java_url_tracking_slow",
    "content": "#!/usr/bin/env bash\n\n# Test Java plugin URL tracking functionality\nexport MISE_LOCKFILE=1\nexport MISE_EXPERIMENTAL=1\n\n# Clean up any existing installations\nmise uninstall java@17.0.2 2>/dev/null || true\n\n# Create initial configuration\ncat <<EOF >mise.toml\n[tools]\njava = { version = \"17.0.2\" }\nEOF\n\n# Create lockfile\ntouch mise.lock\n\n# First install - should fetch URL from Java metadata API\necho \"=== First install - fetching URL from Java metadata API ===\"\nmise install\nassert_contains \"mise x java -- java -version 2>&1\" 'openjdk version \"17.0.2\"'\n\n# Verify URL is stored in lockfile\necho \"=== Verifying URL is stored in lockfile ===\"\nassert_contains \"cat mise.lock\" '[[tools.java]]'\nassert_contains \"cat mise.lock\" 'version = \"17.0.2\"'\nassert_contains \"cat mise.lock\" 'backend = \"core:java\"'\nassert_contains \"cat mise.lock\" 'url ='\n\n# Uninstall and reinstall - should reuse URL from lockfile\necho \"=== Reinstalling - should reuse URL from lockfile ===\"\nmise uninstall java@17.0.2\nmise install\nassert_contains \"mise x java -- java -version 2>&1\" 'openjdk version \"17.0.2\"'\n\n# Verify the tool still works after reinstall\necho \"=== Verifying tool still works after reinstall ===\"\nassert_contains \"mise x java -- java -version 2>&1\" 'openjdk version \"17.0.2\"'\n\necho \"=== Java URL tracking test completed successfully ===\"\n"
  },
  {
    "path": "e2e/core/test_java_vendor_prefix",
    "content": "#!/usr/bin/env bash\n\n# Test that fuzzy matching works with vendor prefixes like \"temurin-\", \"corretto-\", etc.\n# Regression test for https://github.com/jdx/mise/discussions/7328\n#\n# The bug: fuzzy_match_filter uses pattern ^{query}([-.].+)?$ which doesn't match\n# versions like \"temurin-25.0.1\" because after \"temurin-\" there's a digit, not \"-\" or \".\"\n\n# Regression: numeric queries should not match unintended versions.\n# For example \"11.0.1\" must not match \"11.0.10\".\nassert_contains \"mise latest java 11.0.1\" \"11.0.1\"\nassert_not_contains \"mise latest java 11.0.1\" \"11.0.10\"\n\n# Test 1: ls-remote with full prefix+version works\nassert_contains \"mise ls-remote java temurin-25\" \"temurin-25\"\n\n# Test 2: latest with full prefix+version works\nassert_contains \"mise latest java temurin-25\" \"temurin-25\"\n\n# Test 3: THE BUG - latest with just vendor prefix should work but doesn't\n# When doing `mise upgrade --bump`, it extracts just the prefix \"temurin-\"\n# and tries to find the latest version matching that prefix\nassert_contains \"mise latest java 'temurin-'\" \"temurin-\"\n\n# Test 4: Same bug with other vendors\nassert_contains \"mise latest java 'corretto-'\" \"corretto-\"\nassert_contains \"mise latest java 'zulu-'\" \"zulu-\"\n\n# Test 5: The original issue - upgrade with vendor prefix should not error\ncat <<EOF >mise.toml\n[tools]\njava = \"temurin-25\"\nEOF\n\nmise install java\nassert_not_contains \"mise upgrade java --bump --dry-run 2>&1\" \"no latest version found\"\n"
  },
  {
    "path": "e2e/core/test_node_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_NODE_COREPACK=1\nexport MISE_NODE_DEFAULT_PACKAGES_FILE=\"$PWD/.default-npm-packages\"\nexport NPM_CONFIG_FUND=false\n\nlatest=$(mise latest node)\necho \"v$latest\" >.node-version\necho \"zx\" >\"$MISE_NODE_DEFAULT_PACKAGES_FILE\"\n\n# Enable idiomatic version files for node\nmise settings set idiomatic_version_file_enable_tools node\n\nmise i node@lts/hydrogen\nmise i -f node\nassert_contains \"mise x node@lts/hydrogen -- node --version\" \"v18.\"\nassert \"mise x -- node --version\" \"v$latest\"\nassert_contains \"mise x -- which yarn\" \"yarn\"\nassert_contains \"mise x -- which zx\" \"zx\"\n\nmise use nodejs@20.1.0\nmise ls\nassert \"mise x -- node --version\" \"v20.1.0\"\nassert_contains \"mise ls-remote nodejs\" \"20.1.0\"\nmise use --rm node\n"
  },
  {
    "path": "e2e/core/test_package_json",
    "content": "#!/usr/bin/env bash\n\n# Test that package.json is used as an idiomatic version file\n\n# Enable idiomatic version files for node and pnpm\nmise settings set idiomatic_version_file_enable_tools \"node,pnpm\"\n\n# Test devEngines.runtime for node\ncat >package.json <<'EOF'\n{\n  \"devEngines\": {\n    \"runtime\": {\n      \"name\": \"node\",\n      \"version\": \">=22.0.0\"\n    }\n  }\n}\nEOF\n\nassert_contains \"mise current node\" \"22.\"\n\n# Test packageManager field for pnpm\ncat >package.json <<'EOF'\n{\n  \"packageManager\": \"pnpm@9.1.0+sha256.abcdef\"\n}\nEOF\n\nassert_contains \"mise current pnpm\" \"9.1.0\"\n\n# Test devEngines.packageManager overrides packageManager field\ncat >package.json <<'EOF'\n{\n  \"devEngines\": {\n    \"packageManager\": {\n      \"name\": \"pnpm\",\n      \"version\": \"^10.0.0\"\n    }\n  },\n  \"packageManager\": \"pnpm@9.1.0\"\n}\nEOF\n\nassert_contains \"mise current pnpm\" \"10.\"\n\n# Test package.json with no relevant fields doesn't break anything\ncat >package.json <<'EOF'\n{\n  \"name\": \"test-project\",\n  \"version\": \"1.0.0\"\n}\nEOF\n\n# Should not error, just no version detected\nassert \"mise current node\" \"\"\n"
  },
  {
    "path": "e2e/core/test_poetry_slow",
    "content": "#!/usr/bin/env bash\n\n# arrange\nexport MISE_PYTHON_COMPILE=1\nexport POETRY_HOME=\"$HOME/.poetry\"\n\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12.0\"\npoetry = {version=\"1.7.1\", pyproject=\"pyproject.toml\"}\nEOF\n\ncat >pyproject.toml <<EOF\n[tool.poetry]\nname = \"poetry-test\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"mise\"]\npackages = [{include = \"poetry_demo\"}]\n\n[tool.poetry.dependencies]\npython = \"^3.12\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\nEOF\n\nmkdir poetry_demo\ntouch poetry_demo/__init.py\n\n# act\neval \"$(mise activate bash)\"\n\nmise install python poetry\n_mise_hook\n\n# assert\nassert \"poetry --version\" \"Poetry (version 1.7.1)\"\n# Use assert_contains because older Poetry versions may print deprecation warnings\nassert_contains \"poetry run -- python3 -V\" \"Python 3.12.0\"\n"
  },
  {
    "path": "e2e/core/test_python_compile_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_PYTHON_COMPILE=1\nassert \"mise x python@3.12.3 -- python --version\" \"Python 3.12.3\"\n"
  },
  {
    "path": "e2e/core/test_python_precompiled",
    "content": "#!/usr/bin/env bash\n\nexport MISE_PYTHON_COMPILE=0\nassert_contains \"mise use python@3.12.3 2>&1\" \"cpython-\"\nassert_contains \"mise x -- python --version\" \"Python 3.12.3\"\n\nrm mise.toml\nmise rm python@3.12.3\n\n# Enable idiomatic version files for python\nmise settings set idiomatic_version_file_enable_tools python\n\necho '3.12.3' >.python-version\nassert_contains \"mise i 2>&1\" \"mise python@3.12.3\"\nassert_contains \"mise x -- python --version\" \"Python 3.12.3\"\n\n# Disable idiomatic version files for python to test override behavior\nmise settings set idiomatic_version_file_enable_tools \"[]\"\nmise use python@3.13\nassert_contains \"mise x -- python --version\" \"Python 3.13\"\n"
  },
  {
    "path": "e2e/core/test_python_uv_venv",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nexport MISE_EXPERIMENTAL=1\n\n# Test uv is used for manually defined venv\ncat >mise.toml <<EOF\n[env._.python]\nvenv = {path = \"my_venv\", create=true}\n\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\nEOF\n\nmise i\nassert \"mise x -- python --version\" \"Python 3.12.3\"\nassert_contains \"mise x -- uv --version\" \"uv 0.5.4\"\nassert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$PWD/my_venv\"\nassert \"mise x -- which python\" \"$PWD/my_venv/bin/python\"\nassert_not_contains \"ls $PWD/my_venv/\" \"include\" # stdlib virtual venv has an \"include\" folder while uv doesn't\n\n# Test \"source\" mode - only sources existing venv, doesn't create\nrm -rf .venv\nrm -f uv.lock\n\ncat >mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\n\n[settings]\npython.uv_venv_auto = \"source\"\nEOF\n\ntouch uv.lock\n\n# Without a .venv, should use system python path (not .venv)\nassert_not_contains \"mise env -s bash\" \"VIRTUAL_ENV\"\n\n# Create venv manually\nmise x -- uv venv\n\n# Now it should source the existing venv\nassert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\nassert \"mise x -- which python\" \"$PWD/.venv/bin/python\"\n# source mode should NOT set UV_PYTHON\nassert_not_contains \"mise env -s bash\" \"UV_PYTHON\"\n\n# Test \"create|source\" mode - creates venv if missing, sources it\nrm -rf .venv\n\ncat >mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\n\n[settings]\npython.uv_venv_auto = \"create|source\"\nEOF\n\n# Should create venv automatically and source it\nassert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\nassert \"mise x -- which python\" \"$PWD/.venv/bin/python\"\n# create|source mode should NOT set UV_PYTHON (unlike legacy true)\nassert_not_contains \"mise env -s bash\" \"UV_PYTHON\"\n\n# Test legacy \"true\" mode - should set UV_PYTHON\n# this will be deprecated in future releases\nrm -rf .venv\n\ncat >mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\n\n[settings]\npython.uv_venv_auto = true\nEOF\n\n# Should create venv and source it\nassert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\nassert \"mise x -- which python\" \"$PWD/.venv/bin/python\"\n# legacy true mode SHOULD set UV_PYTHON\nassert_contains \"mise env -s bash\" \"UV_PYTHON\"\n\n# Test boolean parsing from env vars - \"true\",\"1\", \"yes\",  should all work\nrm -rf .venv\n\ncat >mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\nEOF\n\nMISE_PYTHON_UV_VENV_AUTO=true assert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\nrm -rf .venv\nMISE_PYTHON_UV_VENV_AUTO=yes assert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\nrm -rf .venv\nMISE_PYTHON_UV_VENV_AUTO=1 assert_contains \"mise env -s bash\" \"VIRTUAL_ENV=$PWD/.venv\"\n\n# Test \"0\", \"no\", \"false\" should disable\nMISE_PYTHON_UV_VENV_AUTO=false assert_not_contains \"mise env -s bash\" \"VIRTUAL_ENV\"\nMISE_PYTHON_UV_VENV_AUTO=no assert_not_contains \"mise env -s bash\" \"VIRTUAL_ENV\"\nMISE_PYTHON_UV_VENV_AUTO=0 assert_not_contains \"mise env -s bash\" \"VIRTUAL_ENV\"\n\n# Test shim exclusion: the mise uv shim must NOT be called internally when creating\n# a venv via uv_venv_auto — doing so would trigger `mise exec`, which re-enters\n# env resolution and causes infinite subprocess recursion.\nrm -rf .venv uv.lock\nmkdir -p \"$MISE_DATA_DIR/shims\"\nrm -f \"$MISE_DATA_DIR/shims/uv\"\ncat >\"$MISE_DATA_DIR/shims/uv\" <<'SHIM'\n#!/bin/bash\necho \"ERROR: mise uv shim was invoked during venv creation\" >&2\nexit 99\nSHIM\nchmod +x \"$MISE_DATA_DIR/shims/uv\"\nORIG_PATH=\"$PATH\"\nexport PATH=\"$MISE_DATA_DIR/shims:$PATH\"\ncat >mise.toml <<EOF\n[settings]\npython.uv_venv_auto = \"create|source\"\nEOF\ntouch uv.lock\n# which_no_shims() skips $MISE_DATA_DIR/shims, so the fake shim is never called;\n# since no real uv is available either, venv creation is silently skipped.\noutput=$(mise env -s bash 2>&1 || true)\nassert_not_contains \"printf '%s' \\\"$output\\\"\" \"ERROR: mise uv shim was invoked during venv creation\"\nrm -f \"$MISE_DATA_DIR/shims/uv\" uv.lock\nexport PATH=\"$ORIG_PATH\"\n\n## Allows opt-out uv's venv\n#mkdir -p subdir\n#cat >subdir/mise.toml <<EOF\n#[env._.python]\n#venv = {path = \"my_subvenv\", create=true}\n#[tools]\n#python = \"3.12.3\"\n#uv = \"0.5.4\"\n#[settings]\n#python_venv_stdlib = true\n#EOF\n#\n#cd subdir || exit 1\n#mise i\n#assert \"mise x -- python --version\" \"Python 3.12.3\"\n#assert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$PWD/my_subvenv\"\n#assert \"mise x -- which python\" \"$PWD/my_subvenv/bin/python\"\n#assert_contains \"ls $PWD/my_subvenv/\" \"include\" # stdlib virtual venv has an \"include\" folder while uv doesn't\n#\n#cd .. || exit 1\n#cat >mise.toml <<EOF\n#[tools]\n#python = \"3.12.3\"\n#uv = \"0.5.4\"\n#[settings]\n#python.uv_venv_auto = \"source\"\n#EOF\n#touch uv.lock\n#\n#assert \"mise x -- which python\" \"$PWD/.venv/bin/python\"\n#assert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$PWD/.venv\"\n#assert \"mise env -D | grep UV_PYTHON\" \"UV_PYTHON=3.12.3\"\n#assert_not_contains \"ls $PWD/.venv\" \"include\" # stdlib virtual venv has an \"include\" folder while uv doesn't\n"
  },
  {
    "path": "e2e/core/test_python_uv_venv_x_tiny",
    "content": "#!/usr/bin/env bash\n# fixes https://github.com/jdx/mise/discussions/5999\n\nset -euo pipefail\n\nexport MISE_EXPERIMENTAL=1\n\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12.3\"\nuv = \"0.5.4\"\ntiny = \"3\"\n\n[settings]\npython.uv_venv_auto = \"create|source\"\nEOF\n\n# Ensure tiny plugin is available\nmise plugin install tiny >/dev/null 2>&1 || true\n\n# Simulate uv project to trigger uv_venv_auto\ntouch uv.lock\n\nmise i\n\n# Validate that uv venv takes precedence when executing via another tool\nassert \"mise x tiny@3 -- which python\" \"$PWD/.venv/bin/python\"\n"
  },
  {
    "path": "e2e/core/test_python_venv",
    "content": "#!/usr/bin/env bash\n\nexport MISE_PYTHON_DEFAULT_PACKAGES_FILE=\"$HOME/.default-python-packages\"\n\ncat >.mise.toml <<EOF\n[env._.python]\nvenv = {path = \"{{env.HOME}}/my_venv\", create=true}\n[tools]\npython = \"3.12.3\"\nEOF\n\nmise i\nassert \"mise x -- python --version\" \"Python 3.12.3\"\nassert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$HOME/my_venv\"\nassert \"mise x -- which python\" \"$HOME/my_venv/bin/python\"\n\n# verify nested virtualenv is used\nmkdir -p subdir\ncat >subdir/.mise.toml <<EOF\n[env._.python]\nvenv = {path = \"my_subvenv\", create=true}\nEOF\n\ncd subdir || exit\nmise i\nassert \"mise x -- python --version\" \"Python 3.12.3\"\nassert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$PWD/my_subvenv\"\nassert \"mise x -- which python\" \"$PWD/my_subvenv/bin/python\"\n"
  },
  {
    "path": "e2e/core/test_python_venv_with_go_backend_deadlock_slow",
    "content": "#!/usr/bin/env bash\n# Test for deadlock issue between Python venv creation and Go backend tools\n# This reproduces the scenario where go:* tools with dependencies would cause\n# a circular dependency during environment resolution while creating Python venv.\n# fixes https://github.com/jdx/mise/discussions/7059\nset -euo pipefail\n\ncat >.mise.toml <<EOF\n[tools]\ngo = \"1.25.4\"\npython = \"3.12.3\"\n\"go:github.com/charmbracelet/gum\" = \"v0.17.0\"\n\n[env]\n_.python.venv = {path = \"{{env.HOME}}/my_venv\", create=true}\nEOF\n\n# This should complete without timeout (previously would hang indefinitely)\n# The go backend tool resolution should not interfere with Python venv creation\ntimeout 60 mise install\n\n# Verify Python venv was created\nassert \"mise x -- python --version\" \"Python 3.12.3\"\nassert \"mise env -s bash | grep VIRTUAL_ENV\" \"export VIRTUAL_ENV=$HOME/my_venv\"\nassert \"mise x -- which python\" \"$HOME/my_venv/bin/python\"\n\n# Verify Go backend tool was installed and can run\nassert_contains \"mise x -- gum --version\" \"0.17.0\"\n\n# Required to properly cleanup as go installs read-only sources\nchmod -R +w ~/go\n"
  },
  {
    "path": "e2e/core/test_python_version_comments",
    "content": "#!/usr/bin/env bash\n\n# Test that .python-version files with comments are parsed correctly\nexport MISE_PYTHON_COMPILE=0\n\n# Enable idiomatic version files for python\nmise settings set idiomatic_version_file_enable_tools python\n\n# Test 1: Create .python-version with comments\ncat >.python-version <<'EOF'\n# This is a comment describing the Python version\n# Another comment line\n3.12.3 # inline comment\nEOF\n\n# Verify parsing - the list command should only show 3.12.3, not comment words\nassert_not_contains \"mise ls --current python 2>&1\" \"# (missing)\"\nassert_not_contains \"mise ls --current python 2>&1\" \"This (missing)\"\nassert_not_contains \"mise ls --current python 2>&1\" \"comment (missing)\"\nassert_not_contains \"mise ls --current python 2>&1\" \"inline (missing)\"\nassert_contains \"mise ls --current python 2>&1\" \"3.12.3\"\n\n# Test 2: Install and run Python\nassert_contains \"mise i 2>&1\" \"mise python@3.12.3\"\nassert_contains \"mise x -- python --version\" \"Python 3.12.3\"\n\n# Test 3: Test with multiple versions and comments\ncat >.python-versions <<'EOF'\n# Primary version\n3.12.3 # primary\n# Secondary version\n3.11.11 # secondary\nEOF\n\n# Verify both versions are parsed correctly\nassert_contains \"mise ls --current python 2>&1\" \"3.12.3\"\nassert_contains \"mise ls --current python 2>&1\" \"3.11.11\"\nassert_not_contains \"mise ls --current python 2>&1\" \"primary (missing)\"\nassert_not_contains \"mise ls --current python 2>&1\" \"secondary (missing)\"\n\n# Clean up\nrm -f .python-version .python-versions\nmise settings set idiomatic_version_file_enable_tools \"[]\"\n"
  },
  {
    "path": "e2e/core/test_ruby_build_slow",
    "content": "#!/usr/bin/env bash\n# Install and build ruby using ruby-build\n\n# tested in test_gem_slow\n#export MISE_RUBY_COMPILE=true\n#export MISE_RUBY_INSTALL=0\n#latest=$(mise latest ruby)\n#assert_contains \"mise x ruby@$latest -- ruby --version\" \"ruby $latest\"\n"
  },
  {
    "path": "e2e/core/test_ruby_from_gemfile",
    "content": "#!/usr/bin/env bash\n# Read ruby version from Gemfile\n\n# Enable idiomatic version files for ruby\nmise settings set idiomatic_version_file_enable_tools ruby\n\ncat >Gemfile <<EOF\nruby \"3.3.6\"\nEOF\n\nassert \"mise current ruby\" \"3.3.6\"\n"
  },
  {
    "path": "e2e/core/test_ruby_github_attestations",
    "content": "#!/usr/bin/env bash\n# Test GitHub artifact attestations verification for precompiled Ruby binaries\n\nset -euo pipefail\n\nexport MISE_RUBY_COMPILE=false\nexport MISE_RUBY_GITHUB_ATTESTATIONS=true\n\necho \"=== Testing Ruby GitHub Artifact Attestations Verification ===\"\n\n# Test: Install Ruby with GitHub artifact attestations verification enabled\necho \"Installing Ruby with GitHub artifact attestations verification enabled...\"\n\noutput=$(mise install ruby@3.4.8 2>&1) || true\necho \"$output\"\n\n# Check if attestation verification was attempted\nif echo \"$output\" | grep -q \"verify GitHub artifact attestations\"; then\n\techo \"✅ GitHub artifact attestations verification was attempted\"\nelse\n\techo \"❌ ERROR: GitHub artifact attestation verification message not found\"\n\texit 1\nfi\n\n# Cleanup\nmise uninstall ruby@3.4.8 2>/dev/null || true\n\necho \"\"\necho \"=== Ruby GitHub Artifact Attestations Test Passed ✓ ===\"\n"
  },
  {
    "path": "e2e/core/test_ruby_install_slow",
    "content": "#!/usr/bin/env bash\n# Install and build ruby using ruby-install\n# this test is super slow and we're already testing ruby-build, so skipping for now\n\n#export MISE_RUBY_COMPILE=true\n#export MISE_RUBY_INSTALL=1\n#latest=$(mise latest ruby)\n#assert_contains \"mise x ruby@$latest -- ruby --version\" \"ruby $latest\"\n#mise uninstall ruby\n#export MISE_RUBY_INSTALL_REPO=\"https://github.com/postmodern/ruby-install/archive/refs/heads/master.zip\"\n#latest=$(mise latest ruby)\n#assert_contains \"mise x ruby@$latest -- ruby --version\" \"ruby $latest\"\n"
  },
  {
    "path": "e2e/core/test_ruby_ls_remote",
    "content": "#!/usr/bin/env bash\n# Install and build ruby using ruby-build\n\nassert_contains \"mise ls-remote ruby@3\" \"3.0.0\"\nassert_contains \"mise ls-remote ruby@truffleruby-24\" \"truffleruby-24.0.0\"\nassert_contains \"mise ls-remote ruby@truffleruby+graalvm-24\" \"truffleruby+graalvm-24.0.0\"\n"
  },
  {
    "path": "e2e/core/test_ruby_precompiled",
    "content": "#!/usr/bin/env bash\n\n# Test precompiled Ruby binaries from jdx/ruby\nexport MISE_RUBY_COMPILE=false\n\n# Install precompiled Ruby 3.4.1\nassert_contains \"mise use ruby@3.4.1 2>&1\" \"ruby@3.4.1\"\nassert_contains \"mise x -- ruby --version\" \"ruby 3.4.1\"\n\n# Verify the installation works\nassert_succeed \"mise x -- gem --version\"\n\n# Clean up\nrm mise.toml\nmise rm ruby@3.4.1\n"
  },
  {
    "path": "e2e/core/test_rust",
    "content": "#!/usr/bin/env bash\n\nexport MISE_RUSTUP_HOME=\"$MISE_DATA_DIR/rustup\"\nexport MISE_CARGO_HOME=\"$MISE_DATA_DIR/cargo\"\n\nassert_contains \"mise x rust@1.81.0 -- rustc --version\" \"rustc 1.81.0\"\n\ncat <<EOF >rust-toolchain.toml\n[toolchain]\nchannel = \"1.81.0\"\nEOF\n\nassert_contains \"mise x -- rustc --version\" \"rustc 1.81.0\"\n"
  },
  {
    "path": "e2e/core/test_rust_system_fallback",
    "content": "#!/usr/bin/env bash\n\n# This test reproduces the issue where a system cargo/rustc installation\n# becomes unavailable after leaving a mise project that uses the rust tool\n# The issue occurs when:\n# 1. User has ~/.cargo/bin in their PATH from system rustup\n# 2. They use mise's rust tool which also adds ~/.cargo/bin\n# 3. When leaving the project, that path gets removed even though it was in the original PATH\n\n# Simulate system rustup by adding executables to $HOME/.cargo/bin\nmkdir -p \"$HOME/.cargo/bin\"\ncat >\"$HOME/.cargo/bin/rustc\" <<'EOF'\n#!/usr/bin/env bash\n# Simulate system rustup - version depends on RUSTUP_TOOLCHAIN env var\nif [ -n \"$RUSTUP_TOOLCHAIN\" ]; then\n\techo \"rustc 1.81.0 (from rustup with RUSTUP_TOOLCHAIN=$RUSTUP_TOOLCHAIN)\"\nelse\n\techo \"rustc 1.82.0 (from system rustup)\"\nfi\nEOF\nchmod +x \"$HOME/.cargo/bin/rustc\"\n\ncat >\"$HOME/.cargo/bin/cargo\" <<'EOF'\n#!/usr/bin/env bash\necho \"cargo from system rustup\"\nEOF\nchmod +x \"$HOME/.cargo/bin/cargo\"\n\n# Add .cargo/bin to PATH (simulating system rustup installation)\nexport PATH=\"$HOME/.cargo/bin:$PATH\"\n\n# Verify system rustc is available\nassert_contains \"rustc --version\" \"rustc 1.82.0 (from system rustup)\"\n\n# Activate mise\neval \"$(mise activate bash)\"\n\n# Verify system rustc is still available after activation\nassert_contains \"rustc --version\" \"rustc 1.82.0 (from system rustup)\"\n\n# Create a project directory with mise rust tool\nmkdir -p project\ncat >project/.mise.toml <<EOF\n[tools]\nrust = \"1.81.0\"\nEOF\n\n# DON'T create a global mise config - test without any config in parent dir\n\n# Enter the project and install mise rust\ncd project || exit 1\nmise install\neval \"$(mise hook-env)\"\n\n# Debug: Check PATH state in project\necho \"DEBUG: In project\"\necho \"DEBUG: PATH count of cargo/bin: $(echo \"$PATH\" | tr ':' '\\n' | grep -c '\\.cargo/bin' || echo 0)\"\necho \"DEBUG: RUSTUP_TOOLCHAIN: ${RUSTUP_TOOLCHAIN:-not set}\"\n\n# Verify mise rust is now active (either real rust 1.81.0 or our fake with RUSTUP_TOOLCHAIN set)\nassert_contains \"rustc --version\" \"1.81.0\"\n\n# Leave the project directory\n# shellcheck disable=SC2103\ncd ..\neval \"$(mise hook-env)\"\n\n# Debug: Check PATH state after leaving\necho \"DEBUG: After leaving project\"\necho \"DEBUG: PATH count of cargo/bin: $(echo \"$PATH\" | tr ':' '\\n' | grep -c '\\.cargo/bin' || echo 0)\"\necho \"DEBUG: RUSTUP_TOOLCHAIN: ${RUSTUP_TOOLCHAIN:-not set}\"\necho \"DEBUG: which rustc: $(which rustc 2>&1 || echo 'NOT FOUND')\"\n\n# BUG: System rustc should be available again since we're out of the project\n# and ~/.cargo/bin was in the original PATH\nassert_contains \"rustc --version\" \"rustc 1.82.0 (from system rustup)\"\n"
  },
  {
    "path": "e2e/core/test_rust_system_fallback_symlink",
    "content": "#!/usr/bin/env bash\n\n# This test verifies that symlinked paths are correctly identified as duplicates\n# when filtering PATH entries. Without canonicalization, mise would treat\n# symlinked paths as different from their targets, leading to PATH duplication.\n\n# Create the real cargo bin directory\nmkdir -p \"$HOME/.cargo-real/bin\"\n\n# Create a symlink from .cargo to .cargo-real\nln -s \"$HOME/.cargo-real\" \"$HOME/.cargo\"\n\n# Create fake rustc in the REAL directory\ncat >\"$HOME/.cargo-real/bin/rustc\" <<'EOF'\n#!/usr/bin/env bash\nif [ -n \"$RUSTUP_TOOLCHAIN\" ]; then\n\techo \"rustc 1.81.0 (mise version via symlink)\"\nelse\n\techo \"rustc 1.82.0 (system rustup via symlink)\"\nfi\nEOF\nchmod +x \"$HOME/.cargo-real/bin/rustc\"\n\n# Add the SYMLINK path to PATH (this is what users typically have)\nexport PATH=\"$HOME/.cargo/bin:$PATH\"\n\n# Verify system rustc is available via symlink\nassert_contains \"rustc --version\" \"rustc 1.82.0 (system rustup via symlink)\"\n\n# Activate mise\neval \"$(mise activate bash)\"\n\n# Create a project with mise rust\nmkdir -p project\ncat >project/.mise.toml <<EOF\n[tools]\nrust = \"1.81.0\"\nEOF\n\ncd project || exit 1\nmise install\neval \"$(mise hook-env)\"\n\n# Verify mise rust is active\nassert_contains \"rustc --version\" \"1.81.0\"\n\n# Leave the project\n# shellcheck disable=SC2103\ncd ..\neval \"$(mise hook-env)\"\n\n# CRITICAL: System rustc should still be accessible via the symlink\n# Without proper canonicalization, mise would:\n# 1. See ~/.cargo/bin in PATH (symlink)\n# 2. Install rust to ~/.cargo/bin (resolves to ~/.cargo-real/bin)\n# 3. Think these are different paths\n# 4. Remove ~/.cargo/bin when deactivating, breaking system rustup\nassert_contains \"rustc --version\" \"rustc 1.82.0 (system rustup via symlink)\"\n"
  },
  {
    "path": "e2e/core/test_swift_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_USE_VERSIONS_HOST=0\n\nMISE_DEBUG=1 mise use swift@6\nassert_matches \"mise x -- swift --version\" 'Swift version 6\\.'\n\nassert \"mise x spm:nicklockwood/SwiftFormat@0.53.10 -- swiftformat --version\" \"0.53.10\"\nassert \"mise x spm:https://github.com/nicklockwood/SwiftFormat.git@0.53.10 -- swiftformat --version\" \"0.53.10\"\n\n# test package with resources (`templates list` command depends on resources being installed)\n#assert \"mise x spm:SwiftGen/SwiftGen@6.6.2 --verbose -- swiftgen templates list --only colors\" \"colors:\n#   - literals-swift4\n#   - literals-swift5\n#   - swift4\n#   - swift5\n#---\n#You can also specify custom templates by path, using \\`templatePath\\` instead of \\`templateName\\`.\n#For more information, see the documentation on GitHub or use \\`swiftgen template doc\\`.\n#\"\n"
  },
  {
    "path": "e2e/core/test_system_node",
    "content": "#!/usr/bin/env bash\nrequire_cmd node\n\nsystem_node=\"$(which node)\"\n\nmise use node@20.0.0\nmise_node=\"$(mise which node)\"\n\nassert \"mise x node@system -- which node\" \"$system_node\"\nassert \"mise x -- which node\" \"$mise_node\"\n"
  },
  {
    "path": "e2e/core/test_zig_slow",
    "content": "#!/usr/bin/env bash\n\nassert \"mise x zig@0.13.0 -- zig version\" \"0.13.0\"\nassert \"mise x zig@master -- zig version\"\nassert \"mise x zig@2024.11.0-mach -- zig version\" \"0.14.0-dev.2577+271452d22\"\nassert \"mise x zig@mach-latest -- zig version\"\n"
  },
  {
    "path": "e2e/core/test_zigmod",
    "content": "#!/usr/bin/env bash\n\neval \"$(mise activate bash)\" && eval \"$(mise hook-env)\"\nmise plugin install https://github.com/kachick/asdf-zigmod\nassert_contains \"mise x zigmod@latest -- zigmod version\" \"zigmod\"\n"
  },
  {
    "path": "e2e/direnv/test_direnv",
    "content": "#!/usr/bin/env bash\nrequire_cmd direnv\n\n# Create a \"local\" dummy binary\nmkdir -p node_modules/.bin\ncat <<EOF >node_modules/.bin/dummy\n#!/usr/bin/env bash\necho \"I am Dummy from node_modules!\"\nEOF\nchmod +x node_modules/.bin/dummy\n\n# Some configuration for direnv\ncat <<EOF >.envrc\nPATH_add node_modules/.bin\nexport FIRST='first'\nEOF\ndirenv allow\n\nexport FIRST=\"last\"\n\n# Activate direnv and mise\neval \"$(mise activate bash --status)\"\neval \"$(direnv hook bash)\"\n\n# Tell mise to use dummy@latest\nmise use dummy@latest && _direnv_hook\n\n# Should use dummy@latest\nassert \"which dummy\" \"$PWD/node_modules/.bin/dummy\"\n# shellcheck disable=SC2016\nassert 'echo $FIRST' \"first\"\n\n# Allow direnv to use the .envrc file\n_direnv_hook\n\n# Should use dummy from node_modules (direnv PATH takes precedence)\nassert \"which dummy\" \"$PWD/node_modules/.bin/dummy\"\n# shellcheck disable=SC2016\nassert 'echo $FIRST' \"first\"\n"
  },
  {
    "path": "e2e/env/test_env_age_encryption",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Test basic age encryption with x25519 key\nexport MISE_EXPERIMENTAL=true\nrm -f mise.toml age.txt\n\n# Generate test age key\nmise x age -- age-keygen -o age.txt 2>/dev/null\nAGE_PUBLIC_KEY=$(grep \"# public key:\" age.txt | cut -d: -f2 | tr -d ' ')\nAGE_SECRET_KEY=$(grep \"AGE-SECRET-KEY-\" age.txt)\n\n# Test encrypting a small value (should not compress, uses simplified TOML format)\nMISE_EXPERIMENTAL=true mise set SMALL_SECRET=\"my-secret-value\" --age-encrypt --age-recipient \"$AGE_PUBLIC_KEY\"\nassert_contains \"cat mise.toml\" 'SMALL_SECRET = { age = \"'\nassert_not_contains \"cat mise.toml\" 'format ='\n\n# Test decrypting the value with mise set\nRESULT=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY\" mise set SMALL_SECRET)\nassert \"echo $RESULT\" \"my-secret-value\"\n\n# Test decrypting in env resolution with mise env\nassert_contains \"MISE_EXPERIMENTAL=true MISE_AGE_KEY=\\\"$AGE_SECRET_KEY\\\" mise env -s bash | grep SMALL_SECRET\" \"export SMALL_SECRET=my-secret-value\"\n\n# Test mise env shows decrypted value in list format\nENV_OUTPUT=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY\" mise env)\nassert_contains \"echo '$ENV_OUTPUT'\" \"SMALL_SECRET=my-secret-value\"\n\n# Test encrypting a large value (should compress, uses complex TOML format)\nLARGE_VALUE=$(python3 -c 'print(\"x\" * 2000)')\nMISE_EXPERIMENTAL=true mise set LARGE_SECRET=\"$LARGE_VALUE\" --age-encrypt --age-recipient \"$AGE_PUBLIC_KEY\"\nassert_contains \"cat mise.toml\" 'LARGE_SECRET = { age = { value ='\nassert_contains \"cat mise.toml\" 'format = \"zstd\"'\n\n# Test decrypting the large value with mise set\nRESULT=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY\" mise set LARGE_SECRET | head -c 10)\nassert \"echo $RESULT\" \"xxxxxxxxxx\"\n\n# Test large value decryption in mise env\nassert_contains \"MISE_EXPERIMENTAL=true MISE_AGE_KEY=\\\"$AGE_SECRET_KEY\\\" mise env -s bash | grep LARGE_SECRET\" \"export LARGE_SECRET=$LARGE_VALUE\"\n\n# Test mise env with multiple encrypted variables\nMISE_EXPERIMENTAL=true mise set ANOTHER_SECRET=\"another-value\" --age-encrypt --age-recipient \"$AGE_PUBLIC_KEY\"\nENV_BASH=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY\" mise env -s bash)\nassert_contains \"echo '$ENV_BASH'\" \"export SMALL_SECRET=my-secret-value\"\nassert_contains \"echo '$ENV_BASH'\" \"export ANOTHER_SECRET=another-value\"\n\n# Test with multiple recipients\nrm -f age2.txt\n# Temporarily move mise.toml to avoid decryption errors when running mise x\nmv mise.toml mise.toml.tmp\nmise x age -- age-keygen -o age2.txt 2>/dev/null\nmv mise.toml.tmp mise.toml\nif [ ! -f age2.txt ]; then\n\techo \"age2.txt not found after generation\"\n\texit 1\nfi\nAGE_PUBLIC_KEY2=$(grep \"# public key:\" age2.txt | cut -d: -f2 | tr -d ' ')\nAGE_SECRET_KEY2=$(grep \"AGE-SECRET-KEY-\" age2.txt)\n\nMISE_EXPERIMENTAL=true mise set MULTI_SECRET=\"multi-recipient-secret\" --age-encrypt \\\n\t--age-recipient \"$AGE_PUBLIC_KEY\" \\\n\t--age-recipient \"$AGE_PUBLIC_KEY2\"\n\n# Both keys should be able to decrypt via mise set\nRESULT=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY\" mise set MULTI_SECRET)\nassert \"echo $RESULT\" \"multi-recipient-secret\"\n\nRESULT=$(MISE_EXPERIMENTAL=true MISE_AGE_KEY=\"$AGE_SECRET_KEY2\" mise set MULTI_SECRET)\nassert \"echo $RESULT\" \"multi-recipient-secret\"\n\n# Both keys should be able to decrypt via mise env\nassert_contains \"MISE_EXPERIMENTAL=true MISE_AGE_KEY=\\\"$AGE_SECRET_KEY\\\" mise env | grep MULTI_SECRET\" \"MULTI_SECRET=multi-recipient-secret\"\n\n# Test second key with clean environment (only multi-recipient variable)\nrm -f mise.toml\nMISE_EXPERIMENTAL=true mise set MULTI_SECRET=\"multi-recipient-secret\" --age-encrypt \\\n\t--age-recipient \"$AGE_PUBLIC_KEY\" \\\n\t--age-recipient \"$AGE_PUBLIC_KEY2\"\nassert_contains \"MISE_EXPERIMENTAL=true MISE_AGE_KEY=\\\"$AGE_SECRET_KEY2\\\" mise env | grep MULTI_SECRET\" \"MULTI_SECRET=multi-recipient-secret\"\n\n# Test with age key file\ncat <<EOF >~/.config/mise/age.txt\n$AGE_SECRET_KEY\nEOF\n\nMISE_EXPERIMENTAL=true mise set KEY_FILE_SECRET=\"key-file-secret\" --age-encrypt --age-key-file age.txt\nRESULT=$(MISE_EXPERIMENTAL=true mise set KEY_FILE_SECRET)\nassert \"echo $RESULT\" \"key-file-secret\"\n\n# Test key file decryption in mise env\nassert_contains \"MISE_EXPERIMENTAL=true mise env | grep KEY_FILE_SECRET\" \"KEY_FILE_SECRET=key-file-secret\"\n\n# Test SSH recipient (if SSH key exists)\nif [ -f ~/.ssh/id_ed25519.pub ]; then\n\tMISE_EXPERIMENTAL=true mise set SSH_SECRET=\"ssh-encrypted-secret\" --age-encrypt --age-ssh-recipient ~/.ssh/id_ed25519.pub\n\n\t# Decrypt with SSH key via mise set\n\tif command -v age >/dev/null 2>&1; then\n\t\t# Only test if age CLI is available\n\t\tRESULT=$(MISE_EXPERIMENTAL=true mise set SSH_SECRET)\n\t\tassert_contains \"echo $RESULT\" \"ssh-encrypted-secret\"\n\n\t\t# Test SSH key decryption in mise env\n\t\tassert_contains \"MISE_EXPERIMENTAL=true mise env | grep SSH_SECRET\" \"SSH_SECRET=ssh-encrypted-secret\"\n\tfi\nfi\n\n# Test default recipient behavior (uses age.txt if available)\nrm -f mise.toml\ncat <<EOF >~/.config/mise/age.txt\n$AGE_SECRET_KEY\nEOF\n\n# Should work with defaults when age.txt exists\nMISE_EXPERIMENTAL=true mise set DEFAULT_SECRET=\"uses-default-key\" --age-encrypt\nRESULT=$(MISE_EXPERIMENTAL=true mise set DEFAULT_SECRET)\nassert \"echo $RESULT\" \"uses-default-key\"\n\n# Test default key decryption in mise env\nassert_contains \"MISE_EXPERIMENTAL=true mise env | grep DEFAULT_SECRET\" \"DEFAULT_SECRET=uses-default-key\"\n\n# Test error cases\n\n# Invalid recipient\nassert_fail \"MISE_EXPERIMENTAL=true mise set INVALID=value --age-encrypt --age-recipient invalid-key\"\n\n# No recipients available (remove defaults)\nrm -f ~/.config/mise/age.txt\nassert_fail \"MISE_EXPERIMENTAL=true mise set NO_RECIPIENT=value --age-encrypt\"\n\n# Decryption without key (strict mode should fail)\nrm -f ~/.config/mise/age.txt # Remove default key\nMISE_EXPERIMENTAL=true mise set ENCRYPTED_VALUE=\"encrypted\" --age-encrypt --age-recipient \"$AGE_PUBLIC_KEY\"\n# In strict mode, should fail when no key is available\nassert_fail \"MISE_EXPERIMENTAL=true mise set ENCRYPTED_VALUE\"\n\n# Test that mise env also fails when no key available (with encrypted values present)\nassert_fail \"MISE_EXPERIMENTAL=true mise env\"\n\n# Test mixed encrypted and plain values in mise env\nrm -f mise.toml\ncat <<EOF >~/.config/mise/age.txt\n$AGE_SECRET_KEY\nEOF\n\nMISE_EXPERIMENTAL=true mise set PLAIN_VAR=\"plain-value\"\nMISE_EXPERIMENTAL=true mise set ENCRYPTED_VAR=\"encrypted-value\" --age-encrypt --age-recipient \"$AGE_PUBLIC_KEY\"\n\n# Test mise env shows both correctly\nENV_ALL=$(MISE_EXPERIMENTAL=true mise env)\nassert_contains \"echo '$ENV_ALL'\" \"PLAIN_VAR=plain-value\"\nassert_contains \"echo '$ENV_ALL'\" \"ENCRYPTED_VAR=encrypted-value\"\n\n# Test shell-specific output formats\nENV_BASH=$(MISE_EXPERIMENTAL=true mise env -s bash)\nassert_contains \"echo '$ENV_BASH'\" \"export PLAIN_VAR=plain-value\"\nassert_contains \"echo '$ENV_BASH'\" \"export ENCRYPTED_VAR=encrypted-value\"\n\nENV_FISH=$(MISE_EXPERIMENTAL=true mise env -s fish)\nassert_contains \"echo '$ENV_FISH'\" \"set -gx PLAIN_VAR plain-value\"\nassert_contains \"echo '$ENV_FISH'\" \"set -gx ENCRYPTED_VAR encrypted-value\"\n\n# Test --prompt flag with age encryption\nrm -f mise.toml\ncat <<EOF >~/.config/mise/age.txt\n$AGE_SECRET_KEY\nEOF\n\n# Test that --prompt works even when variable doesn't exist yet\n# This simulates: mise set --age-encrypt PROMPT_SECRET --prompt\n# User would enter \"prompt-value\" when prompted\necho \"prompt-value\" | MISE_EXPERIMENTAL=true mise set --age-encrypt PROMPT_SECRET --prompt\nRESULT=$(MISE_EXPERIMENTAL=true mise set PROMPT_SECRET)\nassert \"echo $RESULT\" \"prompt-value\"\n\n# Verify it's actually encrypted in the file\nassert_contains \"cat mise.toml\" 'PROMPT_SECRET = { age = \"'\n\n# Test that --prompt works even when variable already exists\n# This should re-prompt and overwrite\necho \"new-prompt-value\" | MISE_EXPERIMENTAL=true mise set --age-encrypt PROMPT_SECRET --prompt\nRESULT=$(MISE_EXPERIMENTAL=true mise set PROMPT_SECRET)\nassert \"echo $RESULT\" \"new-prompt-value\"\n"
  },
  {
    "path": "e2e/env/test_env_cache",
    "content": "#!/usr/bin/env bash\n\n# Test env caching feature\n\n# Enable env caching with encryption key (as would be set by `mise activate`)\nexport MISE_ENV_CACHE=1\nexport __MISE_ENV_CACHE_KEY=\"dGVzdGtleXRlc3RrZXl0ZXN0a2V5dGVzdGtleXRlc3Q=\"\n\n# Create a basic config with env vars\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\nCACHE_TEST_VAR=\"value1\"\nEOF\n\n# First run should compute env and create cache\nassert_contains \"mise env -s bash\" \"CACHE_TEST_VAR=value1\"\n\n# Second run should use cached env (same result)\nassert_contains \"mise env -s bash\" \"CACHE_TEST_VAR=value1\"\n\n# Modify config - cache should be invalidated due to mtime change\nsleep 1 # Ensure mtime is different\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\nCACHE_TEST_VAR=\"value2\"\nEOF\n\n# Should reflect the new value\nassert_contains \"mise env -s bash\" \"CACHE_TEST_VAR=value2\"\n\n# Test that cache dir exists when caching is enabled\nassert_directory_exists \"$HOME/.local/state/mise/env-cache\"\n\n# Disable caching and verify it still works\nunset MISE_ENV_CACHE\n\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\nCACHE_TEST_VAR=\"value3\"\nEOF\n\nassert_contains \"mise env -s bash\" \"CACHE_TEST_VAR=value3\"\n"
  },
  {
    "path": "e2e/env/test_env_cache_fresh",
    "content": "#!/usr/bin/env bash\n\n# Test --fresh-env flag with caching\n\n# Enable env caching\nexport MISE_ENV_CACHE=1\n\n# Set up a cache encryption key as if activated\nexport __MISE_ENV_CACHE_KEY=\"dGVzdGtleXRlc3RrZXl0ZXN0a2V5dGVzdGtleXRlc3Q=\"\n\n# Create config\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\nFRESH_TEST_VAR=\"original\"\nEOF\n\n# First run caches\nmise exec -- true\n\n# Modify config\nsleep 1\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\nFRESH_TEST_VAR=\"modified\"\nEOF\n\n# Normal exec should see cache invalidated due to mtime change\nassert_contains \"mise exec -- bash -c 'echo \\$FRESH_TEST_VAR'\" \"modified\"\n\n# Verify --fresh-env flag exists on exec\nassert_contains \"mise exec --help\" \"fresh-env\"\n\n# Verify --fresh-env flag exists on run\nassert_contains \"mise run --help\" \"fresh-env\"\n"
  },
  {
    "path": "e2e/env/test_env_cache_plugin",
    "content": "#!/usr/bin/env bash\n\n# Test env caching with a plugin that returns cacheable=true\n# This verifies that when env_cache=true, plugins are NOT re-executed on every command\n\n# Enable env caching\nexport MISE_ENV_CACHE=1\nexport __MISE_ENV_CACHE_KEY=\"dGVzdGtleXRlc3RrZXl0ZXN0a2V5dGVzdGtleXRlc3Q=\"\n\n# Create a minimal vfox plugin that tracks execution\nPLUGIN_DIR=\"$MISE_DATA_DIR/plugins/test-cacheable-env\"\nmkdir -p \"$PLUGIN_DIR/hooks\"\n\n# Create metadata.lua\ncat >\"$PLUGIN_DIR/metadata.lua\" <<'EOFMETA'\nPLUGIN = {}\nPLUGIN.name = \"test-cacheable-env\"\nPLUGIN.version = \"1.0.0\"\nPLUGIN.homepage = \"https://example.com\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Test plugin for env caching\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nEOFMETA\n\n# Create counter file to track executions\nCOUNTER_FILE=\"$MISE_DATA_DIR/env_cache_test_counter\"\necho \"0\" >\"$COUNTER_FILE\"\n\n# Create mise_env.lua hook that increments counter and returns cacheable=true\ncat >\"$PLUGIN_DIR/hooks/mise_env.lua\" <<EOFHOOK\nfunction PLUGIN:MiseEnv(ctx)\n    -- Read and increment counter\n    local counter_file = \"$COUNTER_FILE\"\n    local f = io.open(counter_file, \"r\")\n    local count = tonumber(f:read(\"*all\")) or 0\n    f:close()\n\n    f = io.open(counter_file, \"w\")\n    f:write(tostring(count + 1))\n    f:close()\n\n    return {\n        env = {\n            {key = \"TEST_CACHEABLE_VAR\", value = \"cached_value_\" .. tostring(count + 1)}\n        },\n        cacheable = true,\n        watch_files = {}\n    }\nend\nEOFHOOK\n\n# Create config that uses the plugin module\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\n_.test-cacheable-env = {}\nEOF\n\n# Reset counter\necho \"0\" >\"$COUNTER_FILE\"\n\n# First run - should execute plugin and cache result\nmise env -s bash >/dev/null 2>&1\nFIRST_COUNT=$(cat \"$COUNTER_FILE\")\n\n# Second run - should use cache, NOT execute plugin again\nmise env -s bash >/dev/null 2>&1\nSECOND_COUNT=$(cat \"$COUNTER_FILE\")\n\n# Third run - should still use cache\nmise env -s bash >/dev/null 2>&1\nTHIRD_COUNT=$(cat \"$COUNTER_FILE\")\n\n# The counter should only be 1 (first run only)\n# If caching is broken, it would be 3\nif [ \"$FIRST_COUNT\" -eq 1 ] && [ \"$SECOND_COUNT\" -eq 1 ] && [ \"$THIRD_COUNT\" -eq 1 ]; then\n\techo \"SUCCESS: Plugin was only executed once (counter=$THIRD_COUNT), caching is working\"\nelse\n\techo \"FAILURE: Plugin was executed multiple times (first=$FIRST_COUNT, second=$SECOND_COUNT, third=$THIRD_COUNT)\"\n\techo \"Expected counter to remain at 1 after first execution\"\n\texit 1\nfi\n\n# Now modify the config to invalidate cache\nsleep 1\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\n_.test-cacheable-env = { modified = true }\nEOF\n\n# This run should re-execute the plugin due to config change\nmise env -s bash >/dev/null 2>&1\nFOURTH_COUNT=$(cat \"$COUNTER_FILE\")\n\nif [ \"$FOURTH_COUNT\" -eq 2 ]; then\n\techo \"SUCCESS: Plugin was re-executed after config change (counter=$FOURTH_COUNT)\"\nelse\n\techo \"FAILURE: Expected counter to be 2 after config change, got $FOURTH_COUNT\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/env/test_env_dotenv",
    "content": "#!/usr/bin/env bash\n\ncat >.mise.toml <<EOF\n[env]\nFOO = \"bar\"\nEOF\n\nassert \"mise env --dotenv | grep FOO\" \"FOO=bar\"\n"
  },
  {
    "path": "e2e/env/test_env_file",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[env]\nmise.file = ['.test-env']\nEOF\necho FOO_FROM_FILE=foo_from_file >.test-env\necho TEST_ENV2=foo >.test-env2\nassert \"mise x -- env | grep FOO_FROM_FILE\" \"FOO_FROM_FILE=foo_from_file\"\nassert \"MISE_ENV_FILE=.test-env2 mise x -- env | grep TEST_ENV2\" \"TEST_ENV2=foo\"\n\ncat <<EOF >mise.toml\n[env]\n_.file = 'not_present'\nEOF\nassert \"mise env\" # does not error\n\ncat <<EOF >mise.toml\n[env]\n_.file = 'a'\nEOF\necho 'export A=1' >a\nassert \"mise env | grep -v PATH\" \"export A=1\"\n\ncat <<EOF >mise.toml\n[env]\n_.file = { value = 'b.json' }\nEOF\necho '{\"B\": 2}' >b.json\nassert \"mise env | grep -v PATH\" \"export B=2\"\n\ncat <<EOF >mise.toml\n[env]\n_.file = ['a', 'b.json']\nEOF\necho 'export A=1' >a\necho '{\"B\": 2}' >b.json\nassert \"mise env | grep -v PATH\" \"export A=1\nexport B=2\"\n\ncat <<EOF >mise.toml\n[env]\n_.file = ['a', {path = 'b.json', tools = true}]\nEOF\necho 'export A=1' >a\necho '{\"B\": 2}' >b.json\nassert \"mise env | grep -v PATH\" \"export A=1\nexport B=2\"\n\ncat <<EOF >mise.toml\n[[env]]\n_.file = 'a'\n[[env]]\n_.file = [{ path = ['b.json'], tools = true }]\nEOF\necho 'export A=1' >a\necho '{\"B\": 2}' >b.json\nassert \"mise env | grep -v PATH\" \"export A=1\nexport B=2\"\n\ncat <<EOF >mise.toml\n[env]\nmise.file = ['{{env.HOME}}/.home-test-env']\nEOF\necho FOO_FROM_FILE=foo_from_file_home >~/.home-test-env\nassert \"mise x -- env | grep FOO_FROM_FILE\" \"FOO_FROM_FILE=foo_from_file_home\"\n"
  },
  {
    "path": "e2e/env/test_env_file_glob",
    "content": "#!/usr/bin/env bash\n\ncat <<'EOF' >.mise.toml\n[env]\n_.file = \"env.d/*.env\"\nEOF\n\nmkdir -p env.d\n\necho \"VAR1=1\" >env.d/1.env\necho \"VAR2=2\" >env.d/2.env\n\n# mise trust --verbose\nmise env -s bash\nassert_contains \"mise env -s bash\" \"VAR1=1\"\nassert_contains \"mise env -s bash\" \"VAR2=2\"\n"
  },
  {
    "path": "e2e/env/test_env_json",
    "content": "#!/usr/bin/env bash\nrequire_cmd jq\n\ncat >/tmp/.env-test <<EOF\nAAA=bbb\nEOF\n\ncat >.mise.toml <<EOF\n[tools]\ndeno = \"2\"\n\n[env]\n_.file = '/tmp/.env-test'\nFOO = \"bar\"\nEOF\n\nassert \"mise env --json dummy@latest | jq -r .FOO\" \"bar\"\n\nassert \"mise env --json-extended dummy@latest | jq -r '.FOO.value'\" \"bar\"\nassert_contains \"mise env --json-extended dummy@latest | jq -r '.FOO.source'\" \".mise.toml\"\n\nassert \"mise env --json-extended dummy@latest | jq -r '.AAA.value'\" \"bbb\"\nassert \"mise env --json-extended dummy@latest | jq -r '.AAA.source'\" \"/tmp/.env-test\"\n\nmise i\nassert \"mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.tool'\" \"deno\"\nassert_contains \"mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.value'\" \".deno\"\nassert_contains \"mise env --json-extended | jq -r '.DENO_INSTALL_ROOT.source'\" \".mise.toml\"\n\nassert_contains \"mise env --json-extended go@1.23.4 | jq -r '.GOBIN.value'\" \"go/1.23.4/bin\"\nassert_contains \"mise env --json-extended go@1.23.4 | jq -r '.GOBIN.tool'\" \"go\"\nassert_contains \"mise env --json-extended go@1.23.4 | jq -r '.GOBIN.source'\" \"\"\n"
  },
  {
    "path": "e2e/env/test_env_module_auto_install",
    "content": "#!/usr/bin/env bash\n\n# Path requires to be untrusted for test to work\nexport MISE_TRUSTED_CONFIG_PATHS=\"\"\n\nAUTO_PLUGIN_DIR=\"$MISE_DATA_DIR/plugins/mise-env-sample\"\n\ncat >mise.toml <<EOF\n[env]\n_.mise-env-sample = { path_to_add = \"/sample/path\" }\n\n[plugins]\nmise-env-sample = \"https://github.com/jdx/mise-env-sample\"\nEOF\n\nenv mise trust >/dev/null 2>&1\n\nOUTPUT=$(mise env -s bash)\n\nEXIT_CODE=$?\n\n# Verify the command exited successfully\nassert \"echo $EXIT_CODE\" \"0\"\n\n# Verify the plugin directory was created\nassert_directory_exists \"$AUTO_PLUGIN_DIR\"\n\n# Verify the env variable was set correctly by the plugin\nassert_contains \"echo $OUTPUT\" \"MISE_SAMPLE_ENV_KEY=foobar\"\n"
  },
  {
    "path": "e2e/env/test_env_module_cmd_exec_path",
    "content": "#!/usr/bin/env bash\n\n# Test that vfox env module hooks can find tools on PATH via cmd.exec.\n# When mise threads the constructed environment to cmd.exec, tools added\n# to PATH by earlier env directives (or from the toolset) should be\n# findable by plugins without workarounds like `mise which`.\n\n# Create a fake tool binary in a custom bin directory\nTOOL_BIN_DIR=\"$HOME/custom-tools\"\nmkdir -p \"$TOOL_BIN_DIR\"\ncat >\"$TOOL_BIN_DIR/my-test-tool\" <<'EOFTOOL'\n#!/usr/bin/env bash\necho \"tool_output_value\"\nEOFTOOL\nchmod +x \"$TOOL_BIN_DIR/my-test-tool\"\n\n# Create a vfox env module plugin that calls my-test-tool via cmd.exec\nPLUGIN_DIR=\"$MISE_DATA_DIR/plugins/test-cmd-env\"\nmkdir -p \"$PLUGIN_DIR/hooks\"\n\ncat >\"$PLUGIN_DIR/metadata.lua\" <<'EOFMETA'\nPLUGIN = {}\nPLUGIN.name = \"test-cmd-env\"\nPLUGIN.version = \"1.0.0\"\nPLUGIN.homepage = \"https://example.com\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Test that cmd.exec inherits mise-constructed PATH\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nEOFMETA\n\ncat >\"$PLUGIN_DIR/hooks/mise_env.lua\" <<'EOFHOOK'\nlocal cmd = require(\"cmd\")\n\nfunction PLUGIN:MiseEnv(ctx)\n    -- This should work because mise threads the constructed env\n    -- (including PATH with custom-tools) to cmd.exec\n    local ok, output = pcall(function()\n        return cmd.exec(\"my-test-tool\")\n    end)\n\n    if not ok then\n        return {\n            env = {{key = \"TEST_CMD_EXEC_RESULT\", value = \"TOOL_NOT_FOUND\"}},\n            cacheable = false,\n            watch_files = {}\n        }\n    end\n\n    -- Trim trailing whitespace\n    output = output:gsub(\"%s+$\", \"\")\n\n    return {\n        env = {{key = \"TEST_CMD_EXEC_RESULT\", value = output}},\n        cacheable = false,\n        watch_files = {}\n    }\nend\nEOFHOOK\n\n# Config: add custom-tools to PATH, then use the plugin module.\n# The _.path directive is processed first, so cmd.exec should see it.\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\n_.path = \"$TOOL_BIN_DIR\"\n_.test-cmd-env = {}\nEOF\n\n# Run mise env and check that the plugin found and executed the tool\nassert_contains \"mise env -s bash\" \"TEST_CMD_EXEC_RESULT=tool_output_value\"\n"
  },
  {
    "path": "e2e/env/test_env_module_cmd_exec_tools",
    "content": "#!/usr/bin/env bash\n\n# Test that tools=true on a module directive makes mise-managed tool\n# binaries available on PATH inside cmd.exec().\n\n# Create a vfox env module plugin that calls rtx-tiny (installed by the tiny tool)\nPLUGIN_DIR=\"$MISE_DATA_DIR/plugins/test-cmd-tools\"\nmkdir -p \"$PLUGIN_DIR/hooks\"\n\ncat >\"$PLUGIN_DIR/metadata.lua\" <<'EOFMETA'\nPLUGIN = {}\nPLUGIN.name = \"test-cmd-tools\"\nPLUGIN.version = \"1.0.0\"\nPLUGIN.homepage = \"https://example.com\"\nPLUGIN.license = \"MIT\"\nPLUGIN.description = \"Test that cmd.exec sees tool binaries with tools=true\"\nPLUGIN.minRuntimeVersion = \"0.3.0\"\nEOFMETA\n\ncat >\"$PLUGIN_DIR/hooks/mise_env.lua\" <<'EOFHOOK'\nlocal cmd = require(\"cmd\")\n\nfunction PLUGIN:MiseEnv(ctx)\n    local ok, output = pcall(function()\n        return cmd.exec(\"rtx-tiny\")\n    end)\n\n    local result = \"TOOL_NOT_FOUND\"\n    if ok then\n        result = output:gsub(\"%s+$\", \"\")\n    end\n\n    return {\n        env = {{key = \"TEST_CMD_TOOLS_RESULT\", value = result}},\n        cacheable = false,\n        watch_files = {}\n    }\nend\nEOFHOOK\n\n# First: without tools=true, the tool binary should NOT be found\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<'EOF'\n[tools]\ntiny = \"3\"\n\n[env]\n_.test-cmd-tools = {}\nEOF\n\nmise i\nassert_contains \"mise env -s bash\" \"TEST_CMD_TOOLS_RESULT=TOOL_NOT_FOUND\"\n\n# Second: with tools=true, the tool binary SHOULD be found\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<'EOF'\n[tools]\ntiny = \"3\"\n\n[env]\n_.test-cmd-tools = { tools = true }\nEOF\n\nassert_contains \"mise env -s bash\" \"TEST_CMD_TOOLS_RESULT='rtx-tiny:\"\n"
  },
  {
    "path": "e2e/env/test_env_path",
    "content": "#!/usr/bin/env bash\n\nmise use dummy@1.0.0\nassert_contains \"mise env -s bash | grep PATH\" \"/installs/dummy/1.0.0/bin\"\n\nmise use dummy@2.0.0\nassert_contains \"mise env -s bash | grep PATH\" \"/installs/dummy/2.0.0/bin\"\n\nassert_contains \"mise env -s bash dummy@1.0.1 | grep PATH\" \"/installs/dummy/1.0.1/bin\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = 'a'\nEOF\nassert \"mise dr path\" \"$PWD/a\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = ['a', 'b']\nEOF\nassert \"mise dr path\" \"$PWD/a\n$PWD/b\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = { path = \"a\", tools = true }\nEOF\nassert \"mise dr path\" \"$PWD/a\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = { path = [\"a\"], tools = true }\nEOF\nassert \"mise dr path\" \"$PWD/a\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = [{ path = \"a\", tools = true }, \"b\"]\nEOF\nassert \"mise dr path\" \"$PWD/a\n$PWD/b\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = { path = \"a\", tools = true }\nEOF\nassert \"mise dr path\" \"$PWD/a\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = [{ path = [\"a\", \"b\"], tools = true }]\nEOF\nassert \"mise dr path\" \"$PWD/a\n$PWD/b\"\n\ncat <<'EOF' >mise.toml\n[[env]]\n_.path = [{ path = \"a\", tools = true }, \"b\"]\n[[env]]\n_.path = \"c\"\nEOF\nassert \"mise dr path\" \"$PWD/a\n$PWD/b\n$PWD/c\"\n\ncat <<'EOF' >mise.toml\n[env]\n_.path = ['a', 'b']\nEOF\nmkdir -p sub_dir\ncd sub_dir\ncat <<'EOF' >mise.toml\n[env]\n_.path = ['c', 'd']\nEOF\nassert \"mise dr path\" \"$PWD/c\n$PWD/d\n${PWD%/*}/a\n${PWD%/*}/b\"\n"
  },
  {
    "path": "e2e/env/test_env_path_helper_bug",
    "content": "#!/usr/bin/env zsh\n# shellcheck disable=SC1071\nset -eu\n\n# Verifies that user PATH modifications after mise activation are respected\n\nmkdir -p homebrew/bin system/bin\n\ncat >homebrew/bin/tool <<'EOF'\n#!/usr/bin/env bash\necho \"homebrew-tool\"\nEOF\nchmod +x homebrew/bin/tool\n\ncat >system/bin/tool <<'EOF'\n#!/usr/bin/env bash\necho \"system-tool\"\nEOF\nchmod +x system/bin/tool\n\ncat >.mise.toml <<'EOF'\n[env]\n_.path = [\"homebrew/bin\"]\nEOF\n\n# Activate mise (homebrew/bin comes first)\neval \"$(mise activate zsh --status)\"\n\n# User explicitly prepends their own path after mise activation\n# This should be respected and remain first\nexport PATH=\"$PWD/system/bin:$PATH\"\n\n# System tool should be found (user's explicit choice)\ntest \"$(tool)\" = \"system-tool\" || exit 1\n\n# After precmd runs, user's explicit PATH modification should still be respected\n_mise_hook_precmd\n\n# User's path should still have priority over mise paths\ntest \"$(tool)\" = \"system-tool\" || exit 1\n"
  },
  {
    "path": "e2e/env/test_env_path_node_regression",
    "content": "#!/usr/bin/env bash\n\n# Test for regression reported in https://github.com/jdx/mise/discussions/5913\n# In version 2025.8.4, using _.path = [\"/foo\"] breaks mise use node\n\n# Disable GPG verification for this test\nexport MISE_GPG_VERIFY=false\n\n# Create dummy system node/npm that always fail to ensure we're testing mise's node\nmkdir -p \"$HOME/bin\"\ncat >\"$HOME/bin/node\" <<'EOF'\n#!/usr/bin/env bash\necho \"CALL TO SYSTEM node! args: $*\" >&2\nexit 1\nEOF\nchmod +x \"$HOME/bin/node\"\nexport PATH=\"$HOME/bin:$PATH\"\n\n# Create a mise.toml with env._.path configuration\ncat <<'EOF' >mise.toml\n[env]\n_.path = [\"/foo\"]\nEOF\n\n# Debug: Check initial PATH\necho \"Initial PATH: $PATH\"\n\n# Debug: Check what mise env shows before installation\nmise env -s bash | grep -E \"^(export )?PATH=\" || echo \"No PATH in mise env\"\n\n# This should succeed even with _.path set\nmise use node@20.18.0\n\n# Verify node is installed and available\nassert_contains \"mise ls node\" \"20.18.0\"\n\n# The node binary should be accessible through mise\nassert_contains \"mise x -- node --version\" \"v20.18.0\"\n\n# Also test that the path directive is still working\nassert_contains \"mise dr path\" \"/foo\"\n\n# Test 2: Legitimate use case - env._.path providing a build dependency\n# Clean up from previous test\nrm -f mise.toml\nmise uninstall node@20.18.0 || true\n\n# Create a fake build tool that node \"requires\" during installation\nmkdir -p build-tools\ncat >\"build-tools/required-build-tool\" <<'EOF'\n#!/usr/bin/env bash\necho \"Build tool executed successfully\"\nexit 0\nEOF\nchmod +x build-tools/required-build-tool\n\n# Create a custom node plugin that requires the build tool\nmkdir -p custom-node-plugin/bin\ncat >\"custom-node-plugin/bin/install\" <<'EOF'\n#!/usr/bin/env bash\nset -e\n\n# Check if required-build-tool is available\nif ! command -v required-build-tool &> /dev/null; then\n    echo \"ERROR: required-build-tool not found in PATH!\" >&2\n    exit 1\nfi\n\necho \"Found required build tool, proceeding with installation...\"\nrequired-build-tool\n\n# Simulate a successful installation by creating dummy binaries\nmkdir -p \"$ASDF_INSTALL_PATH/bin\"\necho '#!/usr/bin/env bash\necho \"v20.18.0\"' > \"$ASDF_INSTALL_PATH/bin/node\"\nchmod +x \"$ASDF_INSTALL_PATH/bin/node\"\n\necho '#!/usr/bin/env bash\necho \"10.8.2\"' > \"$ASDF_INSTALL_PATH/bin/npm\"\nchmod +x \"$ASDF_INSTALL_PATH/bin/npm\"\n\necho \"Custom node installation complete!\"\nEOF\nchmod +x custom-node-plugin/bin/install\n\ncat >\"custom-node-plugin/bin/list-all\" <<'EOF'\n#!/usr/bin/env bash\necho \"20.18.0\"\nEOF\nchmod +x custom-node-plugin/bin/list-all\n\n# Configure mise to use the custom plugin and add build-tools to PATH\ncat <<EOF >mise.toml\n[env]\n_.path = [\"./build-tools\"]\n\n[tools]\nnode = \"20.18.0\"\nEOF\n\n# Install the custom plugin\nexport MISE_NODE_REPO=\"file://$PWD/custom-node-plugin\"\nexport MISE_NODE_OVERRIDE_REPO=\"file://$PWD/custom-node-plugin\"\n\n# This should succeed because build-tools is in PATH via env._.path\nmise install node@20.18.0\n\n# Verify the installation worked\nassert_contains \"mise x -- node --version\" \"v20.18.0\"\nassert_contains \"mise x -- npm --version\" \"10.8.2\"\n"
  },
  {
    "path": "e2e/env/test_env_path_resolution",
    "content": "#!/usr/bin/env bash\n\n# This test verifies consistent path resolution using config_root for env._.path\n# and current behavior for env._.source as implemented.\n\necho \"=== GitHub Issue #6203: Path Resolution Inconsistency ===\"\necho \"This test verifies env._.path uses config_root for relative paths\"\necho \"and documents env._.source behavior with .config/mise/config.toml\"\necho \"\"\n\n# Set up test environment\nmkdir -p .config/mise\nmkdir -p .config/mise/tools/bin\nmkdir -p tools/bin\n\n# Create config file in .config/mise/config.toml\ncat >\".config/mise/config.toml\" <<EOF\n[env]\n_.source = \"script.sh\"\n_.path = [\"tools/bin\"]\nEOF\n\n# Create script in config directory\ncat >\".config/mise/script.sh\" <<EOF\nexport HELLO=CONFIG_DIR\nexport PATH=\"\\$HOME/configbin:\\$PATH\"\nEOF\n\n# Create script in project root\ncat >\"script.sh\" <<EOF\nexport HELLO=PROJECT_ROOT\nexport PATH=\"\\$HOME/projectbin:\\$PATH\"\nEOF\n\n# Create tools in config directory\necho 'echo \"CONFIG_DIR_TOOL\"' >.config/mise/tools/bin/test_tool\nchmod +x .config/mise/tools/bin/test_tool\n\n# Create tools in project root\necho 'echo \"PROJECT_ROOT_TOOL\"' >tools/bin/test_tool\nchmod +x tools/bin/test_tool\n\necho \"Test setup:\"\necho \"  Config file: .config/mise/config.toml\"\necho \"  Script in config dir: .config/mise/script.sh (HELLO=CONFIG_DIR)\"\necho \"  Script in project root: script.sh (HELLO=PROJECT_ROOT)\"\necho \"  Tools in config dir: .config/mise/tools/bin/test_tool\"\necho \"  Tools in project root: tools/bin/test_tool\"\necho \"\"\n\necho \"=== Testing env._.source behavior ===\"\nHELLO_VALUE=$(mise env -s bash | grep HELLO | cut -d= -f2)\necho \"HELLO value: $HELLO_VALUE\"\n\nif [ \"$HELLO_VALUE\" = \"PROJECT_ROOT\" ]; then\n\techo \"✓ env._.source resolves relative to PROJECT ROOT (not config file directory)\"\n\techo \"  This means 'script.sh' refers to ./script.sh, not .config/mise/script.sh\"\nelif [ \"$HELLO_VALUE\" = \"CONFIG_DIR\" ]; then\n\techo \"✓ env._.source resolves relative to CONFIG FILE DIRECTORY\"\n\techo \"  This means 'script.sh' refers to .config/mise/script.sh\"\nelse\n\techo \"✗ Unexpected behavior: HELLO=$HELLO_VALUE\"\nfi\n\necho \"\"\necho \"=== Testing env._.path behavior (should use config_root) ===\"\nPATH_VALUE=$(mise env -s bash | grep \"tools/bin\" | head -1)\necho \"PATH contains tools/bin: $(echo \"$PATH_VALUE\" | grep -o 'tools/bin' | head -1)\"\n\n# Test which tool is found\nTOOL_OUTPUT=$(mise exec -- test_tool 2>/dev/null || echo \"TOOL_NOT_FOUND\")\necho \"test_tool output: $TOOL_OUTPUT\"\n\nif [ \"$TOOL_OUTPUT\" = \"PROJECT_ROOT_TOOL\" ]; then\n\techo \"✓ env._.path resolves relative to CONFIG ROOT (project root for nested configs)\"\n\techo \"  This means 'tools/bin' refers to ./tools/bin\"\nelif [ \"$TOOL_OUTPUT\" = \"CONFIG_DIR_TOOL\" ]; then\n\techo \"✗ env._.path resolved relative to config file directory (unexpected)\"\nelse\n\techo \"✗ Unexpected behavior: $TOOL_OUTPUT\"\nfi\n\necho \"\"\necho \"=== Consistency Check ===\"\nif [ \"$TOOL_OUTPUT\" = \"PROJECT_ROOT_TOOL\" ]; then\n\techo \"✓ env._.path is consistent with config_root behavior\"\nelse\n\techo \"✗ env._.path is not consistent with config_root behavior\"\nfi\n\necho \"\"\necho \"=== GitHub Issue #6203 Summary ===\"\necho \"The user's test case in the GitHub issue demonstrates this exact problem:\"\necho \"1. They put a config file in .config/mise/config.toml\"\necho \"2. They put a script in .config/mise/script.sh\"\necho \"3. They expected env._.source = 'script.sh' to find the script in the config directory\"\necho \"4. But it actually finds the script in the project root (if it exists there)\"\necho \"5. This creates confusion about where to place files\"\necho \"\"\necho \"env._.path now uses config_root for relative paths (project root for nested configs).\"\n\n# Clean up\nrm -rf .config script.sh tools\n\necho \"\"\necho \"Test completed. This demonstrates the path resolution inconsistency\"\necho \"that is the core issue in GitHub discussion #6203.\"\n"
  },
  {
    "path": "e2e/env/test_env_profiles",
    "content": "#!/usr/bin/env bash\n\necho 'env.AAA = \"main\"' >.mise.toml\necho 'env.AAA = \"override-1\"' >mise.override1.toml\necho 'env.AAA = \"override-2\"' >mise.override2.toml\n\nassert \"mise env --json | jq -r .AAA\" \"main\"\nMISE_ENV=override1 assert \"mise env --json | jq -r .AAA\" \"override-1\"\nMISE_ENV=override1,override2 assert \"mise env --json | jq -r .AAA\" \"override-2\"\n\ncat <<EOF >mise.toml\n[tasks.print]\nrun = '{% if mise_env %}echo {{mise_env}}{% endif %}'\nEOF\nassert \"mise run print\" \"\"\nMISE_ENV=env1 assert \"mise run print\" \"[env1]\"\nMISE_ENV=env1,env2 assert \"mise run print\" \"[env1, env2]\"\nassert \"mise --env env3 run print\" \"[env3]\"\nassert \"mise -E env3,env4 run print\" \"[env3, env4]\"\n"
  },
  {
    "path": "e2e/env/test_env_shell_expand",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Test basic $VAR expansion\ncat <<'EOF' >mise.toml\n[env]\nFOO = \"hello\"\nBAR = \"$FOO-world\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep BAR\" \"export BAR=hello-world\"\n\n# Test ${VAR} brace syntax\ncat <<'EOF' >mise.toml\n[env]\nFOO = \"hello\"\nBAR = \"${FOO}_world\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep BAR\" \"export BAR=hello_world\"\n\n# Test ${VAR:-default} syntax\ncat <<'EOF' >mise.toml\n[env]\nBAR = \"${NONEXISTENT:-fallback}\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep BAR\" \"export BAR=fallback\"\n\n# Test expansion from initial environment\ncat <<'EOF' >mise.toml\n[env]\nFOO = \"$INITIAL_VAR\"\nEOF\nINITIAL_VAR=from_env MISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep FOO\" \"export FOO=from_env\"\n\n# Test disabled explicitly ($ stays literal, no warning)\ncat <<'EOF' >mise.toml\n[env]\nFOO = \"hello\"\nBAR = \"$FOO\"\nEOF\nMISE_ENV_SHELL_EXPAND=false assert_contains \"mise env -s bash | grep BAR\" 'export BAR='\\''$FOO'\\'\n\n# Test mixed Tera + shell expand\ncat <<'EOF' >mise.toml\n[env]\nFOO = \"hello\"\nBAR = \"{{ env.FOO }}-$FOO\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep BAR\" \"export BAR=hello-hello\"\n\n# Test tools=true vars can reference each other via $\ncat <<'EOF' >mise.toml\n[env]\nTOOL_HOME = { value = \"/opt/tools\", tools = true }\nTOOL_BIN = { value = \"$TOOL_HOME/bin\", tools = true }\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep TOOL_BIN\" \"export TOOL_BIN=/opt/tools/bin\"\n\n# Test tools=true var can reference a non-tools var via $\n# (non-tools vars are resolved first, so tools=true vars can see them)\ncat <<'EOF' >mise.toml\n[env]\nBASE_DIR = \"/opt/tools\"\nTOOL_BIN = { value = \"$BASE_DIR/bin\", tools = true }\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep TOOL_BIN\" \"export TOOL_BIN=/opt/tools/bin\"\n\n# Test chained $ expansion across multiple vars\ncat <<'EOF' >mise.toml\n[env]\nA = \"base\"\nB = \"$A/mid\"\nC = \"$B/end\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash | grep '^export C='\" \"export C=base/mid/end\"\n\n# Test warning for undefined var (bare $VAR)\ncat <<'EOF' >mise.toml\n[env]\nBAR = \"$UNDEFINED_VAR\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_contains \"mise env -s bash 2>&1\" \"env var 'UNDEFINED_VAR' is not defined\"\n\n# Test ${VAR:-} suppresses warning for undefined var\ncat <<'EOF' >mise.toml\n[env]\nBAR = \"${UNDEFINED_VAR:-}\"\nEOF\nMISE_ENV_SHELL_EXPAND=true assert_not_contains \"mise env -s bash 2>&1\" \"is not defined\"\n"
  },
  {
    "path": "e2e/env/test_env_source",
    "content": "#!/usr/bin/env bash\n\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n[env]\n_.source = \"{{ env.MISE_CONFIG_DIR }}/source.sh\"\nEOF\n\ncat >\"$MISE_CONFIG_DIR/source.sh\" <<EOF\nexport MISE_TEST_SOURCE=1234\nexport PATH=\"$HOME/newbin:$PATH\"\nEOF\n\nassert \"mise env -s bash | grep MISE_TEST_SOURCE\" \"export MISE_TEST_SOURCE=1234\"\nassert_contains \"mise env -s bash | grep PATH\" \"export PATH='$HOME/newbin:\"\n\n# TODO: this fails because of https://github.com/jdx/mise/blob/53c9144df8ef5d7d75f19c949be6231a05f7405a/src/config/config_file/mise_toml.rs#L838\n#cat >\"$MISE_CONFIG_DIR/config.toml\" <<EOF\n#[env]\n#_.source = \"{{ env.MISE_CONFIG_DIR }}/source.sh\"\n#_.path = [\n#    \"/{{ env.MISE_TEST_SOURCE }}\",\n#]\n#EOF\n#assert_contains \"mise env -s bash | grep PATH\" \"export PATH='/1234:\"\n"
  },
  {
    "path": "e2e/env/test_env_source_glob",
    "content": "#!/usr/bin/env bash\n\ncat >.mise.toml <<EOF\n[env]\n_.source = \"source.d/*.sh\"\nEOF\n\nmkdir -p source.d\n\ncat >source.d/1.sh <<EOF\n#!/usr/bin/env bash\nexport SOURCE1=1\nEOF\n\ncat >source.d/2.sh <<EOF\n#!/usr/bin/env bash\nexport SOURCE2=2\nEOF\n\nassert_contains \"mise env -s bash\" \"SOURCE1=1\"\nassert_contains \"mise env -s bash\" \"SOURCE2=2\"\n"
  },
  {
    "path": "e2e/env/test_env_template",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\ncat <<EOF >mise.toml\n[env]\nENV_TMPL_EXEC = \"{{ exec(command='echo foo') }}\"\nEOF\nassert_contains \"mise env -s zsh | grep ENV_TMPL_EXEC\" \"export ENV_TMPL_EXEC=foo\"\n\ncat <<EOF >mise.toml\n[env]\nB = \"{{ env.A }}\"\nEOF\nA=a assert_contains \"mise env -s bash | grep B\" \"export B=a\"\n\ncat <<EOF >mise.toml\n[env]\nA = \"a\"\nB = \"{{ env.A }}\"\nEOF\nassert_contains \"mise env -s bash | grep B\" \"export B=a\"\n\ncat <<EOF >mise.toml\n[env]\nFOO = \"foo\"\n\n[tasks.foo]\nenv.BAR = \"bar\"\n\nrun = \"\"\"\nprintf '\\$FOO: %s\\n' \\$FOO\nprintf '\\$BAR: %s\\n' \\$BAR\necho \"{% raw %}{{ env.FOO }}{% endraw %}: {{ env.FOO }}\"\necho \"{% raw %}{{ env.BAR }}{% endraw %}: {{ env.BAR }}\"\n\"\"\"\nEOF\nassert \"mise run --trace foo\" '$FOO: foo\n$BAR: bar\n{{ env.FOO }}: foo\n{{ env.BAR }}: bar'\n\ncat <<EOF >mise.toml\n[env]\nFOO = \"foo\"\n\n[tasks.foo]\nenv.BAR = \"{{ env.FOO }}\"\nenv.BAZ = \"{{ env.BAR }}\"\n\nrun = \"printf '\\$BAZ: %s\\n' \\$BAZ\"\nEOF\nassert \"mise run --trace foo\" '$BAZ: foo'\n\ncat <<EOF >mise.toml\n[env]\nFOO = \"/foo\"\n_.source = { path = \"env.sh\", tools = true }\n_.path = \"{{ env.FOO }}\"\nEOF\ncat <<EOF >env.sh\n#!/usr/bin/env bash\nexport BAR=\"\\$PATH\"\nEOF\nassert_contains \"mise env -s bash | grep BAR\" \"export BAR='/foo:\"\n\ncat <<EOF >mise.toml\n[vars]\nMY_VAR = \"my_var\"\n\n[env]\nFOO = \"{{vars.MY_VAR}}\"\nEOF\n\nassert_json_partial_object \"mise env --json\" \"FOO\" '{\n  \"FOO\": \"my_var\"\n}'\n\ncat <<EOF >mise.local.toml\n[vars]\nMY_VAR = \"mise.local.toml\"\nEOF\n\nassert_json_partial_object \"mise env --json\" \"FOO\" '{\n  \"FOO\": \"mise.local.toml\"\n}'\n"
  },
  {
    "path": "e2e/env/test_env_template_read_file",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Test basic read_file functionality\ncat <<EOF >test_version.txt\n1.2.3\nEOF\n\ncat <<EOF >mise.toml\n[env]\nVERSION = \"{{ read_file(path='test_version.txt') | trim }}\"\nEOF\n\nassert_contains \"mise env -s bash | grep VERSION\" \"export VERSION=1.2.3\"\n\n# Test read_file with relative path\nmkdir -p subdir\ncat <<EOF >subdir/info.txt\ntest-content\nEOF\n\ncat <<EOF >mise.toml\n[env]\nCONTENT = \"{{ read_file(path='subdir/info.txt') | trim }}\"\nEOF\n\nassert_contains \"mise env -s bash | grep CONTENT\" \"export CONTENT=test-content\"\n\n# Test read_file with multiple lines\ncat <<EOF >multiline.txt\nline1\nline2\nline3\nEOF\n\ncat <<EOF >mise.toml\n[env]\nMULTILINE = \"{{ read_file(path='multiline.txt') | replace(from='\\n', to=' ') | trim }}\"\nEOF\n\nassert_contains \"mise env -s bash | grep MULTILINE\" \"export MULTILINE='line1 line2 line3'\"\n\n# Test read_file with vars\ncat <<EOF >config.txt\nproduction\nEOF\n\ncat <<EOF >mise.toml\n[vars]\nCONFIG_FILE = \"config.txt\"\n\n[env]\nENVIRONMENT = \"{{ read_file(path=vars.CONFIG_FILE) | trim }}\"\nEOF\n\nassert_contains \"mise env -s bash | grep ENVIRONMENT\" \"export ENVIRONMENT=production\"\n\n# Test read_file with templated content (should read raw content)\ncat <<EOF >template_test.txt\n{{ env.USER }}\nEOF\n\ncat <<EOF >mise.toml\n[env]\nRAW_CONTENT = \"{{ read_file(path='template_test.txt') | trim }}\"\nEOF\n\nassert_contains \"mise env -s bash | grep RAW_CONTENT\" \"export RAW_CONTENT='{{ env.USER }}'\"\n\n# Test read_file is relative to config_root (not CWD)\n# Create a nested project structure with config files at different levels\nTEST_ROOT=$PWD\nmkdir -p project/subdir\ncd project\n\n# Create version files at each level\necho \"1.0.0\" >version.txt\necho \"2.0.0\" >subdir/version.txt\n\n# Create a data file only in parent\necho \"parent-only-data\" >parent-data.txt\n\n# Create mise.toml in parent directory\ncat <<EOF >mise.toml\n[env]\nPARENT_VERSION = \"{{ read_file(path='version.txt') | trim }}\"\nPARENT_DATA = \"{{ read_file(path='parent-data.txt') | trim }}\"\nEOF\n\n# Create mise.toml in subdirectory that reads its own version.txt\ncat <<EOF >subdir/mise.toml\n[env]\nSUB_VERSION = \"{{ read_file(path='version.txt') | trim }}\"\n# This should fail if uncommented - file doesn't exist relative to subdir:\n# SUB_PARENT_DATA = \"{{ read_file(path='parent-data.txt') | trim }}\"\nEOF\n\n# Test from parent directory - should read parent's version.txt (1.0.0)\nassert_contains \"mise env -s bash | grep PARENT_VERSION\" \"export PARENT_VERSION=1.0.0\"\nassert_contains \"mise env -s bash | grep PARENT_DATA\" \"export PARENT_DATA=parent-only-data\"\n\n# Test from subdirectory - should read both configs, each with their own files\ncd subdir\nassert_contains \"mise env -s bash | grep PARENT_VERSION\" \"export PARENT_VERSION=1.0.0\"\nassert_contains \"mise env -s bash | grep SUB_VERSION\" \"export SUB_VERSION=2.0.0\"\nassert_contains \"mise env -s bash | grep PARENT_DATA\" \"export PARENT_DATA=parent-only-data\"\n\n# Now test that running mise from a completely different directory still works\nPROJECT_DIR=$TEST_ROOT/project\ncd /tmp\nassert_contains \"mise env -s bash -C $PROJECT_DIR | grep PARENT_VERSION\" \"export PARENT_VERSION=1.0.0\"\nassert_contains \"mise env -s bash -C $PROJECT_DIR/subdir | grep SUB_VERSION\" \"export SUB_VERSION=2.0.0\"\n\n# Go back to original test directory\ncd \"$TEST_ROOT\"\n"
  },
  {
    "path": "e2e/env/test_env_tmpl_cache",
    "content": "#!/usr/bin/env bash\n\ncat <<'EOF' >mise.toml\n[env]\nNOW=\"{{ exec(command='date') }}\"\nEOF\n\nnow=$(mise env --json | jq -r '.NOW')\nsleep 1\nassert_not_contains \"mise env --json | jq -r '.NOW'\" \"$now\"\n\ncat <<'EOF' >mise.toml\n[env]\nNOW=\"{{ exec(command='date', cache_key='now') }}\"\nEOF\n\nnow=$(mise env --json | jq -r '.NOW')\nsleep 1\nassert \"mise env --json | jq -r '.NOW'\" \"$now\"\n\ncat <<'EOF' >mise.toml\n[env]\nNOW=\"{{ exec(command='date', cache_duration='2s') }}\"\nEOF\n\nnow=$(mise env --json | jq -r '.NOW')\nsleep 1\nassert \"mise env --json | jq -r '.NOW'\" \"$now\"\nsleep 1\nassert_not_contains \"mise env --json | jq -r '.NOW'\" \"$now\"\n"
  },
  {
    "path": "e2e/env/test_env_tools",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[env]\nFOO={value=\"bar\", tools=true}\nEOF\nassert_contains \"mise hook-env -s bash\" \"export FOO=bar\"\n\ncat <<EOF >mise.toml\n[env]\nWHICH={value=\"{{ exec(command='which which') }}\", tools=true}\nEOF\nassert_contains \"mise hook-env -s bash\" \"export WHICH=$(which which)\"\n\ncat <<EOF >mise.toml\n[tools]\ntiny = \"latest\"\n\n[env]\nTINY_V = { value = \"{{ tools.tiny.version }}\", tools = true }\nTINY_P = { value = \"{{ tools.tiny.path }}\", tools = true }\nEOF\nmise install tiny\nTINY_VERSION=$(mise latest tiny)\nTINY_PATH=$(mise where tiny)\nassert_contains \"mise hook-env -s bash\" \"export TINY_V=$TINY_VERSION\"\nassert_contains \"mise hook-env -s bash\" \"export TINY_P=$TINY_PATH\"\n\n# test multiple versions of the same tool (array access)\ncat <<EOF >mise.toml\n[tools]\ntiny = [\"3\", \"2\"]\n\n[env]\nTINY_V0 = { value = \"{{ tools.tiny[0].version }}\", tools = true }\nTINY_P0 = { value = \"{{ tools.tiny[0].path }}\", tools = true }\nTINY_V1 = { value = \"{{ tools.tiny[1].version }}\", tools = true }\nTINY_P1 = { value = \"{{ tools.tiny[1].path }}\", tools = true }\nEOF\nmise install tiny@3 tiny@2\nTINY_PATH0=$(mise where tiny@3)\nTINY_PATH1=$(mise where tiny@2)\nassert_contains \"mise hook-env -s bash\" \"export TINY_V0=3\"\nassert_contains \"mise hook-env -s bash\" \"export TINY_P0=$TINY_PATH0\"\nassert_contains \"mise hook-env -s bash\" \"export TINY_V1=2\"\nassert_contains \"mise hook-env -s bash\" \"export TINY_P1=$TINY_PATH1\"\n"
  },
  {
    "path": "e2e/env/test_fish_path_move_bug",
    "content": "#!/usr/bin/env bash\nrequire_cmd fish\n\n# This test verifies that hook-env outputs PATH in the correct format for fish shell.\n# The bug: hook-env was outputting `set -gx PATH '/path1:/path2:/path3'` (colon-separated string)\n# But fish expects: `set -gx PATH /path1 /path2 /path3` (space-separated list)\n# When fish receives a colon-separated string, it treats it as ONE path entry, which breaks\n# the filtering logic added in PR #6689 that prevents removing paths from original PATH.\n\n# Set up test environment\nmkdir -p project\n\n# Create test script\ncat >\"$TEST_DIR/test.fish\" <<'EOF'\n#!/usr/bin/env fish\n\n# Ensure we use the debug mise binary, not homebrew mise\n# The e2e framework sets PATH with the debug binary first, but we override it below\n# So we need to preserve the debug binary path\nset -l debug_mise_path (string match -r \".*/target/debug\" $PATH | head -1)\nif test -z \"$debug_mise_path\"\n    echo \"ERROR: Could not find debug mise in PATH\"\n    echo \"PATH: $PATH\"\n    exit 1\nend\n\necho \"DEBUG: using mise from:\" $debug_mise_path\necho \"DEBUG: mise version:\" (mise --version)\n\n# Set initial PATH with homebrew/bin, but keep debug mise first\nset -gx PATH $debug_mise_path /opt/homebrew/bin /usr/bin /bin\n\n# Activate mise\nmise activate fish | source\n\n# Create project with _.path that includes a path already in original PATH\necho \"[env]\n_.path = ['/opt/homebrew/bin']\" > project/.mise.toml\n\ncd project\n\n# Verify /opt/homebrew/bin is in PATH before entering project\nif not contains /opt/homebrew/bin $PATH\n    echo \"FAIL: /opt/homebrew/bin not in PATH before test\"\n    echo \"PATH: $PATH\"\n    exit 1\nend\n\necho \"Before entering project, PATH entries:\" (count $PATH)\n\n# Apply hook-env changes (enter project directory)\necho \"=== ENTERING PROJECT ===\"\n# Call the debug mise binary directly by absolute path to ensure we're testing the right binary\n$debug_mise_path/mise hook-env -s fish --force >/tmp/enter_stdout.txt 2>/tmp/enter_stderr.txt\nsource /tmp/enter_stdout.txt\n\necho \"In project, PATH entries:\" (count $PATH)\n\n# Verify /opt/homebrew/bin is still in PATH\nif not contains /opt/homebrew/bin $PATH\n    echo \"FAIL: /opt/homebrew/bin was removed when entering project\"\n    echo \"PATH: $PATH\"\n    cat /tmp/enter_stderr.txt\n    exit 1\nend\n\n# Now leave the directory - this is where the bug manifests\necho \"=== LEAVING PROJECT ===\"\ncd ..\n$debug_mise_path/mise hook-env -s fish --force >/tmp/leave_stdout.txt 2>/tmp/leave_stderr.txt\nsource /tmp/leave_stdout.txt\n\necho \"After leaving project, PATH entries:\" (count $PATH)\n\n# BUG: /opt/homebrew/bin should still be in PATH because it was in original PATH\n# Without the fix, it gets removed because fish treats colon-separated string as one entry\nif not contains /opt/homebrew/bin $PATH\n    echo \"FAIL: /opt/homebrew/bin was removed from PATH after leaving directory\"\n    echo \"This is the bug - paths in both original PATH and _.path get removed\"\n    echo \"PATH: $PATH\"\n    echo \"\"\n    echo \"=== ENTER DEBUG OUTPUT ===\"\n    cat /tmp/enter_stderr.txt\n    echo \"\"\n    echo \"=== LEAVE DEBUG OUTPUT ===\"\n    cat /tmp/leave_stderr.txt\n    exit 1\nend\n\necho \"SUCCESS: /opt/homebrew/bin remained in PATH after leaving directory\"\nEOF\n\nexec fish \"$TEST_DIR/test.fish\"\n"
  },
  {
    "path": "e2e/env/test_path_interleaved_regression",
    "content": "#!/usr/bin/env bash\n# Test for PATH regression where paths after the first original path match are lost\n# Issue: https://github.com/jdx/mise/discussions/6820\n\n# This test simulates the scenario where:\n# 1. Original PATH has system paths\n# 2. User adds some Homebrew paths\n# 3. Mise adds its tool paths\n# 4. User adds MORE Homebrew paths (which get interleaved with system paths)\n# Result: Paths after the first system path match were being lost\n\nexport MISE_EXPERIMENTAL=1\n\n# Simulate the PATH that existed when mise was first activated\n# (before user's full shell config ran)\nexport __MISE_ORIG_PATH=\"/usr/local/bin:/usr/bin:/bin\"\n\n# Simulate current PATH with interleaved Homebrew and system paths\n# This mimics a situation where:\n# - /opt/homebrew/opt/curl/bin was added before system paths\n# - /opt/homebrew/opt/findutils/libexec/gnubin was added after /usr/local/bin\n# - /opt/homebrew/opt/grep/libexec/gnubin was added after /usr/bin\nexport PATH=\"/opt/homebrew/opt/curl/bin:/usr/local/bin:/opt/homebrew/opt/findutils/libexec/gnubin:/usr/bin:/opt/homebrew/opt/grep/libexec/gnubin:/bin\"\n\n# Create a project with a tool\ncat >.mise.toml <<EOF\n[tools]\ntiny = \"latest\"\nEOF\n\n# Run hook-env and source it\neval \"$(mise hook-env -s bash)\"\n\n# Verify that all Homebrew paths are still present\n# The bug would cause paths after /usr/local/bin to be lost\nassert_contains \"echo $PATH\" \"/opt/homebrew/opt/curl/bin\"\nassert_contains \"echo $PATH\" \"/opt/homebrew/opt/findutils/libexec/gnubin\"\nassert_contains \"echo $PATH\" \"/opt/homebrew/opt/grep/libexec/gnubin\"\n\n# Verify system paths are still present\nassert_contains \"echo $PATH\" \"/usr/local/bin\"\nassert_contains \"echo $PATH\" \"/usr/bin\"\n"
  },
  {
    "path": "e2e/env/test_path_reorder_after_activate",
    "content": "#!/usr/bin/env bash\n\n# Test that PATH reordering done after `mise activate` is preserved by hook-env.\n# This simulates the scenario where ~/.zlogin (which runs after ~/.zshrc on login\n# shells) reorders PATH entries — e.g., moving a tool to the front for priority.\n#\n# Regression test for https://github.com/jdx/mise/discussions/8188\n# and https://github.com/jdx/mise/issues/8168\n\n# Save the mise binary path before we override PATH\nMISE_BIN=\"$(which mise)\"\n\n# Simulate the PATH captured during mise activate in ~/.zshrc\n# The original order has system-bin first, mytool/bin last\nexport __MISE_ORIG_PATH=\"$HOME/system-bin:/usr/local/bin:/usr/bin:/bin:$HOME/mytool/bin\"\n\n# Create test directories and executables\nmkdir -p \"$HOME/mytool/bin\"\nmkdir -p \"$HOME/system-bin\"\n\n# Simulate ~/.zlogin moving ~/mytool/bin to the FRONT of PATH\n# (this is what users do to override system binaries)\nexport PATH=\"$HOME/mytool/bin:$HOME/system-bin:/usr/local/bin:/usr/bin:/bin\"\n\ncat >mise.toml <<'EOF'\nEOF\n\n# Run hook-env using the saved binary path\neval \"$(\"$MISE_BIN\" hook-env -s bash)\"\n\necho \"DEBUG: PATH=$PATH\"\n\n# ~/mytool/bin should still be BEFORE ~/system-bin because the user\n# reordered it to the front after activation\nMYTOOL_POS=$(echo \"$PATH\" | tr ':' '\\n' | grep -n \"mytool/bin\" | head -1 | cut -d: -f1)\nSYSTEM_POS=$(echo \"$PATH\" | tr ':' '\\n' | grep -n \"system-bin\" | head -1 | cut -d: -f1)\n\necho \"DEBUG: mytool/bin at position $MYTOOL_POS, system-bin at position $SYSTEM_POS\"\n\nif [[ -z $MYTOOL_POS ]]; then\n\techo \"FAIL: mytool/bin not found in PATH\"\n\texit 1\nfi\n\nif [[ -z $SYSTEM_POS ]]; then\n\techo \"FAIL: system-bin not found in PATH\"\n\texit 1\nfi\n\nif [[ $MYTOOL_POS -lt $SYSTEM_POS ]]; then\n\techo \"SUCCESS: mytool/bin stays before system-bin (reorder preserved)\"\nelse\n\techo \"FAIL: mytool/bin ($MYTOOL_POS) was moved after system-bin ($SYSTEM_POS)\"\n\techo \"hook-env restored the original __MISE_ORIG_PATH order instead of the current order\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/env/test_poetry_path_slow",
    "content": "#!/usr/bin/env bash\n\n# Test MISE_ADD_PATH functionality with poetry plugin\n# This reproduces the regression reported in https://github.com/jdx/mise/discussions/5934\n# Poetry plugin internally sets MISE_ADD_PATH to add virtual environment to PATH\n\nexport POETRY_HOME=\"$HOME/.poetry\"\n\ncat >.mise.toml <<EOF\n[tools]\npython = \"3.12\"\npoetry = {version=\"1.8\", pyproject=\"pyproject.toml\"}\nEOF\n\ncat >pyproject.toml <<EOF\n[tool.poetry]\nname = \"test-project\"\nversion = \"0.1.0\"\ndescription = \"Test project for MISE_ADD_PATH\"\nauthors = [\"mise\"]\n\n[tool.poetry.dependencies]\npython = \"^3.12\"\npip-tools = \"^7.0\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\nEOF\n\n# Install Python and Poetry\nmise i\n\n# Install dependencies (this creates the virtual environment)\nmise x -- poetry install --no-root\n\n# Get the virtual environment path\nVENV_PATH=$(mise x -- poetry env info --path)\n\n# Test that poetry's virtual environment python is used\nassert_contains \"mise x -- which python\" \"$VENV_PATH/bin/python\"\nassert_contains \"mise x -- which pip\" \"$VENV_PATH/bin/pip\"\n\n# Test that pip-compile (installed in poetry venv) is accessible\nassert_contains \"mise x -- which pip-compile\" \"$VENV_PATH/bin/pip-compile\"\n\n# Test that the poetry virtual environment is properly added to PATH\nassert_contains \"mise env -s bash | grep '^export PATH='\" \"$VENV_PATH/bin\"\n"
  },
  {
    "path": "e2e/generate/test_generate_bootstrap",
    "content": "#!/usr/bin/env bash\n\nassert \"mise generate bootstrap -w\"\nassert \"./bin/mise version\"\n\nassert \"mise tasks add xxx -- echo 'running xxx'\"\nassert \"mise generate task-stubs --mise-bin ./bin/mise\"\nassert \"./bin/xxx\" \"running xxx\"\n\nassert \"mise generate bootstrap -l -w\"\n\n# ensure that that the commands don't rely on the global mise bin\noriginal_mise=\"$(which mise)\"\nmv \"$original_mise\" \"original_mise\"\n\nassert_contains \"./bin/mise tasks ls\" \"xxx\"\n\nassert_not_contains \"MISE_IGNORED_CONFIG_PATHS=$(pwd) ./bin/mise tasks ls\" \"xxx\"\n\necho '\n[tasks.other_task]\nrun = \"echo running other_task\"\n\n[tasks.my_task]\nrun = [\"{{mise_bin}} run other_task\"]\n' >mise.toml\n\nassert_contains \"./bin/mise run my_task\" \"running other_task\"\n\nmv \"original_mise\" \"$original_mise\"\n"
  },
  {
    "path": "e2e/generate/test_generate_config",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >.tool-versions\nnode 22\npython 3.9 3.10 3.11\nEOF\n\n# Use -n (dry-run) to print to stdout instead of writing to file\nassert \"mise generate config -n --tool-versions .tool-versions\" '[tools]\nnode = \"22\"\npython = [\"3.9\", \"3.10\", \"3.11\"]'\n"
  },
  {
    "path": "e2e/generate/test_generate_devcontainer",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Default devcontainer\n\nassert_json_partial_object \"mise generate devcontainer\" \"name,description,features,mounts,containerEnv,customizations\" '\n  {\n    \"name\": \"mise\",\n    \"image\": \"mcr.microsoft.com/devcontainers/base:ubuntu\",\n    \"features\": {\n      \"ghcr.io/devcontainers-extra/features/mise:1\": {}\n    },\n    \"customizations\": {\n      \"vscode\": {\n        \"extensions\": [\n          \"hverlin.mise-vscode\"\n        ]\n      }\n    },\n    \"mounts\": [],\n    \"containerEnv\": {}\n  }\n'\n\n# With custom name and image\nassert_json_partial_object \"mise generate devcontainer --name test --image testimage:latest\" \"name,description\" '\n  {\n    \"name\": \"test\",\n    \"image\": \"testimage:latest\"\n  }\n'\n\n# With mount\nassert_json_partial_object \"mise generate devcontainer --mount-mise-data\" \"name,description,features,mounts,containerEnv,postCreateCommand\" '\n  {\n    \"name\": \"mise\",\n    \"image\": \"mcr.microsoft.com/devcontainers/base:ubuntu\",\n    \"features\": {\n      \"ghcr.io/devcontainers-extra/features/mise:1\": {}\n    },\n    \"mounts\": [\n      {\n        \"source\": \"mise-data-volume\",\n        \"target\": \"/mnt/mise-data\",\n        \"type\": \"volume\"\n      }\n    ],\n    \"containerEnv\": {\n      \"MISE_DATA_DIR\": \"/mnt/mise-data\"\n    },\n    \"remoteEnv\": {\n      \"PATH\": \"${containerEnv:PATH}:/mnt/mise-data/shims\"\n    },\n    \"postCreateCommand\": \"sudo chown -R vscode:vscode /mnt/mise-data\"\n  }\n'\n"
  },
  {
    "path": "e2e/generate/test_generate_task_docs",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# Test the `mise generate task-docs` functionality (render_markdown)\n\n# Test 1: Basic task docs generation\ncat <<EOF >mise.toml\n[tasks.simple]\nrun = 'echo \"simple task\"'\ndescription = \"A simple task with no arguments\"\n\n[tasks.with-args]\nrun = 'echo \"arg={{arg(name=\"filename\")}}\"'\ndescription = \"Task with arguments\"\n\n[tasks.with-flags]\nrun = 'echo \"verbose={{flag(name=\"verbose\")}}\"'\ndescription = \"Task with flags\"\n\n[tasks.with-options]\nrun = 'echo \"user={{option(name=\"user\", default=\"admin\")}}\"'\ndescription = \"Task with options\"\nEOF\n\n# Test basic task docs generation\nassert_contains \"mise generate task-docs\" '## `simple`'\nassert_contains \"mise generate task-docs\" \"A simple task with no arguments\"\nassert_contains \"mise generate task-docs\" '## `with-args`'\nassert_contains \"mise generate task-docs\" \"Task with arguments\"\nassert_contains \"mise generate task-docs\" '## `with-flags`'\nassert_contains \"mise generate task-docs\" \"Task with flags\"\nassert_contains \"mise generate task-docs\" '## `with-options`'\nassert_contains \"mise generate task-docs\" \"Task with options\"\n\n# Test 2: Tasks with aliases and dependencies\ncat <<EOF >mise.toml\n[tasks.parent]\nrun = 'echo \"parent\"'\ndescription = \"Parent task\"\n\n[tasks.child]\nrun = 'echo \"child\"'\ndescription = \"Child task\"\nalias = \"c\"\ndepends = [\"parent\"]\nEOF\n\nassert_contains \"mise generate task-docs\" '## `parent`'\nassert_contains \"mise generate task-docs\" \"Parent task\"\nassert_contains \"mise generate task-docs\" '## `child`'\nassert_contains \"mise generate task-docs\" \"Child task\"\nassert_contains \"mise generate task-docs\" '**Aliases**: `c`'\n\n# Test 3: File-based tasks\nmkdir -p mise-tasks\ncat <<'EOF' >mise-tasks/file-task\n#!/usr/bin/env bash\n#MISE description=\"A file-based task\"\n#MISE alias=\"ft\"\necho \"file task\"\nEOF\nchmod +x mise-tasks/file-task\n\nassert_contains \"mise generate task-docs\" '## `file-task`'\nassert_contains \"mise generate task-docs\" \"A file-based task\"\nassert_contains \"mise generate task-docs\" '**Aliases**: `ft`'\n\n# Test 4: Tasks with complex usage specs\ncat <<'EOF' >mise-tasks/complex-task\n#!/usr/bin/env node\n//MISE description=\"Complex task with usage spec\"\n//USAGE flag \"-v --verbose\" help=\"Enable verbose output\"\n//USAGE flag \"-f --force\" help=\"Force operation\"\n//USAGE arg \"input\" help=\"Input file\"\n//USAGE arg \"output\" help=\"Output file\" default=\"stdout\"\n\nconsole.log(\"complex task\");\nEOF\nchmod +x mise-tasks/complex-task\n\nassert_contains \"mise generate task-docs\" '## `complex-task`'\nassert_contains \"mise generate task-docs\" \"Complex task with usage spec\"\n\n# Test 5: Hidden tasks should not appear\ncat <<EOF >mise.toml\n[tasks.visible]\nrun = 'echo \"visible\"'\ndescription = \"Visible task\"\n\n[tasks.hidden]\nrun = 'echo \"hidden\"'\ndescription = \"Hidden task\"\nhide = true\nEOF\n\nassert_contains \"mise generate task-docs\" '## `visible`'\nassert_contains \"mise generate task-docs\" \"Visible task\"\nassert_not_contains \"mise generate task-docs\" '## `hidden`'\nassert_not_contains \"mise generate task-docs\" \"Hidden task\"\n\n# Test 6: Output to file\ncat <<EOF >mise.toml\n[tasks.file-output]\nrun = 'echo \"file output task\"'\ndescription = \"Task for file output test\"\nEOF\n\nmise generate task-docs --output test_docs.md\nassert_contains \"cat test_docs.md\" '## `file-output`'\nassert_contains \"cat test_docs.md\" \"Task for file output test\"\n\n# Test 7: Multi-file output\nmkdir -p docs_output\nmise generate task-docs --multi --output docs_output\n\n# Check that individual markdown files are created with task names\nassert \"ls docs_output/file-output.md\" \"\"\n# The multi-file output creates separate files for each task\n# Just verify that the file contains task documentation\nassert_contains \"cat docs_output/file-output.md\" '##'\nassert_contains \"cat docs_output/file-output.md\" '**Usage**'\n\n# Test 7b: Multi-file output with --index\nrm -rf docs_output && mkdir -p docs_output\nmise generate task-docs --multi --index --output docs_output\n\n# Check that index.md is created with links to task files\nassert \"ls docs_output/index.md\" \"\"\nassert_contains \"cat docs_output/index.md\" \"# Tasks\"\nassert_contains \"cat docs_output/index.md\" \"[file-output](./file-output.md)\"\n\n# Test 8: Performance test - should be fast even with complex environment\ncat <<EOF >mise.toml\n[tasks.complex-env]\nrun = 'echo \"arg={{arg(name=\"test_arg\")}}\"'\ndescription = \"Task with complex environment\"\n\n[tasks.complex-env.env]\nTEST_VAR = \"test_value\"\n\n[tasks.complex-env.tools]\nnode = \"latest\"\nEOF\n\n# This should complete quickly (within 5 seconds)\ntimeout 5 mise generate task-docs >/dev/null || fail \"Task docs generation took too long\"\n\necho \"All render_markdown tests passed!\"\n"
  },
  {
    "path": "e2e/generate/test_generate_task_docs_inject",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\ncat <<EOF >mise.toml\n[tasks.test]\nrun = \"echo 'running test task'\"\ndescription = \"This is a test task\"\n[tasks.another_task]\nrun = \"echo 'running another task'\"\nalias = [\"alias1\", \"alias2\"]\nEOF\n\ncat <<EOF >task_docs.md\nhello world\n\n<!-- mise-tasks -->\n## \\`test\\`\n\n- **Usage**: \\`test\\`\n\nThis is a test task.\n\n## \\`another_task\\`\n\n- **Usage**: \\`another_task\\`\n- **Aliases**: \\`alias1\\`, \\`alias2\\`\n<!-- /mise-tasks -->\n\nhello world\nEOF\n\nmise generate task-docs --inject --output task_docs.md\n\nassert \"cat task_docs.md\" 'hello world\n\n<!-- mise-tasks -->\n## `another_task`\n\n- **Usage**: `another_task`\n- **Aliases**: `alias1`, `alias2`\n\n## `test`\n\n- **Usage**: `test`\n\nThis is a test task\n<!-- /mise-tasks -->\n\nhello world'\n"
  },
  {
    "path": "e2e/generate/test_generate_task_stubs",
    "content": "#!/usr/bin/env bash\n\nassert \"mise tasks add xxx -- echo 'running xxx'\"\nassert \"mise generate task-stubs\"\nassert \"./bin/xxx\" \"running xxx\"\n"
  },
  {
    "path": "e2e/generate/test_generate_tool_stub",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test mise generate tool-stub command functionality\n\n# Disable GPG verification to avoid test failures\nexport MISE_GPG_VERIFY=false\n\n# Find available port\nfind_available_port() {\n\tpython3 -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\"\n}\n\n# Start local HTTP test server\nSERVER_PORT=$(find_available_port)\npython3 \"${TEST_ROOT}/helpers/scripts/tool_stub_test_server.py\" \"$SERVER_PORT\" &\nSERVER_PID=$!\n\n# Wait for server to start\nsleep 1\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT\n\n# Create test project directory\nmkdir -p generate_tool_stub_test\ncd generate_tool_stub_test\n\n# Test 1: Basic tool stub generation with URL (skip download for speed)\nassert_succeed \"mise generate tool-stub test-tool-basic --url 'http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\n\n# Verify the generated stub exists and is executable\nassert_succeed \"test -x test-tool-basic\"\n\n# Verify the generated stub contains expected content\nassert_contains \"cat test-tool-basic\" \"#!/usr/bin/env -S mise tool-stub\"\nassert_contains \"cat test-tool-basic\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\n\n# Test 2: Tool stub generation with specific version\nassert_succeed \"mise generate tool-stub versioned-tool --version '1.2.3' --url 'http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\n\nassert_contains \"cat versioned-tool\" 'version = \"1.2.3\"'\n\n# Test 3: Tool stub generation with platform-specific URLs\nassert_succeed \"mise generate tool-stub platform-tool --platform-url 'linux-x64:http://127.0.0.1:$SERVER_PORT/status/200' --platform-url 'darwin-arm64:http://127.0.0.1:$SERVER_PORT/status/201' --skip-download\"\n\nassert_contains \"cat platform-tool\" \"[platforms.linux-x64]\"\nassert_contains \"cat platform-tool\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\nassert_contains \"cat platform-tool\" \"[platforms.darwin-arm64]\"\nassert_contains \"cat platform-tool\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/201\"'\n\n# Test 4: Tool stub generation with custom binary path\nassert_succeed \"mise generate tool-stub custom-bin-tool --url 'http://127.0.0.1:$SERVER_PORT/status/200' --bin 'bin/custom-binary' --skip-download\"\n\nassert_contains \"cat custom-bin-tool\" 'bin = \"bin/custom-binary\"'\n\n# Test 5: Error handling - missing URL and platform\nassert_fail \"mise generate tool-stub missing-url --skip-download\"\n\n# Test 6: Error handling - invalid platform format\nassert_fail \"mise generate tool-stub invalid-platform --platform-url 'invalid-format' --skip-download\"\n\n# Test 7: Valid platform names should work (no restriction)\nassert_succeed \"mise generate tool-stub custom-platform-tool --platform-url 'my-platform:http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\n\n# Test 8: Verify generated stub content is well-formed TOML\necho '#!/usr/bin/env -S mise tool-stub\n\nversion = \"1.0.0\"\nurl = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"' >simple-stub\nchmod +x simple-stub\n\n# Verify the stub file contains valid TOML content\nassert_contains \"cat simple-stub\" 'version = \"1.0.0\"'\nassert_contains \"cat simple-stub\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\n\n# Test 9: Help command\nassert_succeed \"mise generate tool-stub --help\"\nassert_contains \"mise generate tool-stub --help\" \"Generate a tool stub for HTTP-based tools\"\n\n# Test 10: Verify the command is available in mise generate\nassert_contains \"mise generate --help\" \"tool-stub\"\n\n# Test 11: Test appending platforms to existing stub\n# First create a stub with one platform\nassert_succeed \"mise generate tool-stub append-test --platform-url 'linux-x64:http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\nassert_contains \"cat append-test\" \"[platforms.linux-x64]\"\nassert_contains \"cat append-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\n\n# Now append another platform to the same stub\nassert_succeed \"mise generate tool-stub append-test --platform-url 'darwin-arm64:http://127.0.0.1:$SERVER_PORT/status/201' --skip-download\"\n\n# Verify both platforms exist\nassert_contains \"cat append-test\" \"[platforms.linux-x64]\"\nassert_contains \"cat append-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\nassert_contains \"cat append-test\" \"[platforms.darwin-arm64]\"\nassert_contains \"cat append-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/201\"'\n\n# Test 12: Test updating existing platform URL\nassert_succeed \"mise generate tool-stub update-test --platform-url 'linux-x64:http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\nassert_contains \"cat update-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\n\n# Update the same platform with a new URL\nassert_succeed \"mise generate tool-stub update-test --platform-url 'linux-x64:http://127.0.0.1:$SERVER_PORT/status/202' --skip-download\"\nassert_contains \"cat update-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/202\"'\n# Ensure old URL is not present\nassert_not_contains \"cat update-test\" 'url = \"http://127.0.0.1:'\"$SERVER_PORT\"'/status/200\"'\n\n# Test 13: Test error when trying to change version on existing stub\nassert_succeed \"mise generate tool-stub version-test --version '1.0.0' --url 'http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\nassert_contains \"cat version-test\" 'version = \"1.0.0\"'\n\n# Try to change version - should fail\nassert_fail \"mise generate tool-stub version-test --version '2.0.0' --url 'http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\n\n# Test 14: Test auto-platform detection from URL\n# Use a URL that contains platform information\nassert_succeed \"mise generate tool-stub auto-platform-test --platform-url 'https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz' --skip-download\"\nassert_contains \"cat auto-platform-test\" \"[platforms.macos-arm64]\"\nassert_contains \"cat auto-platform-test\" 'url = \"https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\"'\n\n# Test 15: Test auto-platform detection with Linux URL\nassert_succeed \"mise generate tool-stub linux-auto-test --platform-url 'https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz' --skip-download\"\nassert_contains \"cat linux-auto-test\" \"[platforms.linux-x64]\"\nassert_contains \"cat linux-auto-test\" 'url = \"https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz\"'\n\n# Test 16: Test mixed explicit and auto-detected platforms\n# First add with explicit platform\nassert_succeed \"mise generate tool-stub mixed-test --platform-url 'linux-x64:http://127.0.0.1:$SERVER_PORT/status/200' --skip-download\"\nassert_contains \"cat mixed-test\" \"[platforms.linux-x64]\"\n\n# Then add with auto-detected platform\nassert_succeed \"mise generate tool-stub mixed-test --platform-url 'https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz' --skip-download\"\n# Should have both platforms\nassert_contains \"cat mixed-test\" \"[platforms.linux-x64]\"\nassert_contains \"cat mixed-test\" \"[platforms.macos-arm64]\"\n\n# Test 17: Test error when platform cannot be auto-detected\nassert_fail \"mise generate tool-stub bad-auto-test --platform-url 'https://example.com/generic-tool.tar.gz' --skip-download\"\n\n# Test 18: Test auto-detection with URL query parameters\nassert_succeed \"mise generate tool-stub query-param-test --platform-url 'https://releases.example.com/tool-linux-x64.tar.gz?token=abc123&version=1.0' --skip-download\"\nassert_contains \"cat query-param-test\" \"[platforms.linux-x64]\"\n\n# Test 19: Test auto-detection with URL fragments\nassert_succeed \"mise generate tool-stub fragment-test --platform-url 'https://cdn.example.com/releases/tool-darwin-arm64.zip#main' --skip-download\"\nassert_contains \"cat fragment-test\" \"[platforms.macos-arm64]\"\n\necho \"All tool-stub generation tests passed!\"\n\n#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test mise generate tool-stub command with real downloads (slow test)\n\n# Disable GPG verification to avoid test failures\nexport MISE_GPG_VERIFY=false\n\n# Create test project directory\nmkdir -p generate_tool_stub_slow_test\ncd generate_tool_stub_slow_test\n\n# Test 1: Generate tool stub with checksum and size detection\n# Using a small, reliable file for testing\nassert_succeed \"mise generate tool-stub hello-stub --url 'http://127.0.0.1:$SERVER_PORT/json'\"\n\n# Verify the generated stub exists and is executable\nassert_succeed \"test -x hello-stub\"\n\n# Verify the generated stub contains checksum and size\nassert_contains \"cat hello-stub\" \"checksum =\"\nassert_contains \"cat hello-stub\" \"size =\"\n\n# Test 2: Test with a real GitHub release (small file)\nassert_succeed \"mise generate tool-stub gh-test-stub --url 'https://github.com/cli/cli/releases/download/v2.21.2/gh_2.21.2_checksums.txt'\"\n\n# Verify it has checksum and size\nassert_contains \"cat gh-test-stub\" \"checksum =\"\nassert_contains \"cat gh-test-stub\" \"size =\"\n\n# Test 3: Test binary path detection with a simple archive\n# This would require a real tar.gz file, so we'll skip this for now\n# as it's complex to set up in e2e tests\n\n# Test 4: Verify that generated stubs have valid TOML structure\nassert_contains \"cat hello-stub\" \"checksum =\"\nassert_contains \"cat hello-stub\" \"size =\"\nassert_contains \"cat gh-test-stub\" \"checksum =\"\nassert_contains \"cat gh-test-stub\" \"size =\"\n\necho \"All slow tool-stub generation tests passed!\"\n"
  },
  {
    "path": "e2e/generate/test_generate_tool_stub_archive_slow",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test mise generate tool-stub command with archive downloads and extraction\n\n# Enable experimental features for http backend\nexport MISE_EXPERIMENTAL=true\n\n# Test 1: Tool stub generation with real Node.js tar.gz archive\necho \"Testing tool-stub generation with Node.js tar.gz archive...\"\nassert_succeed \"mise generate tool-stub ./bin/node-test --bin 'bin/node' --platform-url 'macos-arm64:https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz' --platform-url 'linux-x64:https://nodejs.org/dist/v22.17.1/node-v22.17.1-linux-x64.tar.gz'\"\n\n# Verify the generated stub exists and is executable\nassert_succeed \"test -x ./bin/node-test\"\n\n# Verify the generated stub contains expected content\nassert_contains \"cat ./bin/node-test\" \"#!/usr/bin/env -S mise tool-stub\"\nassert_contains \"cat ./bin/node-test\" '[platforms.macos-arm64]'\nassert_contains \"cat ./bin/node-test\" 'url = \"https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\"'\nassert_contains \"cat ./bin/node-test\" '[platforms.linux-x64]'\nassert_contains \"cat ./bin/node-test\" 'url = \"https://nodejs.org/dist/v22.17.1/node-v22.17.1-linux-x64.tar.gz\"'\n\n# Check that it detected checksums and sizes\nassert_contains \"cat ./bin/node-test\" 'checksum = \"'\nassert_contains \"cat ./bin/node-test\" 'size = '\n\n# Check that it includes the explicitly specified binary path\nassert_contains \"cat ./bin/node-test\" 'bin = \"bin/node\"'\n\necho \"node-test stub content:\"\ncat ./bin/node-test\n\n# Test that the stub actually works by executing it\necho \"Testing that the generated node-test stub works with -v flag...\"\nassert \"./bin/node-test -v\" \"v22.17.1\"\necho \"Testing that the generated node-test stub also works with --version...\"\nassert \"./bin/node-test --version\" \"v22.17.1\"\n\n# Test 2: Tool stub generation with different platforms (should produce common bin)\necho \"Testing tool-stub generation with cross-platform URLs...\"\nassert_succeed \"mise generate tool-stub ./bin/cross-platform-tool --bin 'bin/node' --platform-url 'macos-arm64:https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz' --platform-url 'linux-x64:https://nodejs.org/dist/v22.17.1/node-v22.17.1-linux-x64.tar.gz'\"\n\n# Since we explicitly specified the bin, should have global bin field\nassert_contains \"cat ./bin/cross-platform-tool\" 'bin = \"bin/node\"'\nassert_contains \"cat ./bin/cross-platform-tool\" \"[platforms.macos-arm64]\"\nassert_contains \"cat ./bin/cross-platform-tool\" \"[platforms.linux-x64]\"\n\necho \"cross-platform-tool stub content:\"\ncat ./bin/cross-platform-tool\n\n# Test execution of the cross-platform stub (should work on current platform)\necho \"Testing that the generated cross-platform-tool stub works with -v flag...\"\nassert \"./bin/cross-platform-tool -v\" \"v22.17.1\"\necho \"Testing that the generated cross-platform-tool stub also works with --version...\"\nassert \"./bin/cross-platform-tool --version\" \"v22.17.1\"\n"
  },
  {
    "path": "e2e/generate/test_generate_tool_stub_bootstrap",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test that --bootstrap flag generates a working wrapper script\n\n# Generate a bootstrap stub for jq (a real tool we can test)\nmise generate tool-stub test-jq \\\n\t--platform-url \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64\" \\\n\t--platform-url \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-arm64\" \\\n\t--skip-download \\\n\t--bootstrap\n\n# Basic structure checks\nif ! head -1 test-jq | grep -q '#!/usr/bin/env bash'; then\n\techo \"FAIL: Expected bash shebang\"\n\texit 1\nfi\n\nif ! grep -q '__mise_tool_stub_bootstrap' test-jq; then\n\techo \"FAIL: Missing bootstrap function\"\n\texit 1\nfi\n\nif ! grep -q 'command -v mise' test-jq; then\n\techo \"FAIL: Missing PATH check for mise\"\n\texit 1\nfi\n\n# Check that TOML is stored in a comment block\nif ! grep -q '# MISE_TOOL_STUB:' test-jq; then\n\techo \"FAIL: Missing MISE_TOOL_STUB start marker\"\n\texit 1\nfi\nif ! grep -q '# :MISE_TOOL_STUB' test-jq; then\n\techo \"FAIL: Missing MISE_TOOL_STUB end marker\"\n\texit 1\nfi\n\n# Test appending a platform to existing bootstrap stub (without --bootstrap flag)\n# Should preserve bootstrap format automatically\nmise generate tool-stub test-jq \\\n\t--platform-url \"https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-macos-amd64\" \\\n\t--skip-download\n\n# Should still be a bootstrap stub\nif ! grep -q '__mise_tool_stub_bootstrap' test-jq; then\n\techo \"FAIL: Lost bootstrap wrapper after append\"\n\texit 1\nfi\n\n# Should have all three platforms now\nif ! grep -q 'linux-x64' test-jq; then\n\techo \"FAIL: Missing linux-x64 platform after append\"\n\texit 1\nfi\nif ! grep -q 'macos-arm64' test-jq; then\n\techo \"FAIL: Missing macos-arm64 platform after append\"\n\texit 1\nfi\nif ! grep -q 'macos-x64' test-jq; then\n\techo \"FAIL: Missing macos-x64 platform after append\"\n\texit 1\nfi\n\n# Actually execute the stub - it should find mise on PATH (since we're running under mise)\n# and run jq --version successfully\nOUTPUT=$(./test-jq --version 2>&1)\nif ! echo \"$OUTPUT\" | grep -q \"jq-\"; then\n\techo \"FAIL: Expected jq version output, got: $OUTPUT\"\n\texit 1\nfi\n\necho \"Test passed!\"\n"
  },
  {
    "path": "e2e/generate/test_generate_tool_stub_jq",
    "content": "#!/usr/bin/env bash\n\nmise g tool-stub ./bin/jq \\\n\t--platform-url https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64 \\\n\t--platform-url linux-x64:https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\n\nassert \"./bin/jq -V\" \"jq-1.8.1\"\nassert \"cat ./bin/jq\" '#!/usr/bin/env -S mise tool-stub\n\n[platforms.macos-arm64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64\"\nchecksum = \"blake3:d7f94364d8375d9004ac8169fdbb665f61360c2bcc7cceed1d7306dc6f8958b7\"\nsize = 841408 # 821.69 KiB\n\n[platforms.linux-x64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nchecksum = \"blake3:b0419e57743765a9682d7924816269862890716d7bd3c1b78b2a3dd1f311a7f9\"\nsize = 2255816 # 2.15 MiB'\n\nmise cache clear\n\ncat >./bin/jq <<EOF\n#! /usr/bin/env -S mise tool-stub\nplatforms.macos-arm64.url = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64\"\nplatforms.linux-x64.url = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nEOF\nassert \"./bin/jq -V\" \"jq-1.8.1\"\n\n# Test 404 error handling\nassert_fail \"mise g tool-stub ./bin/jq-404 \\\n\t--platform-url macos-arm64:https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64 \\\n\t--platform-url linux-x64:https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux-x64-does-not-exist\"\n\n# Test --fetch flag\ncat >./bin/jq-fetch <<EOF\n#!/usr/bin/env -S mise tool-stub\n\n[platforms.macos-arm64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64\"\n\n[platforms.linux-x64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nEOF\n\nmise g tool-stub ./bin/jq-fetch --fetch\n\nassert \"cat ./bin/jq-fetch\" '#!/usr/bin/env -S mise tool-stub\n\n[platforms.macos-arm64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64\"\nchecksum = \"blake3:d7f94364d8375d9004ac8169fdbb665f61360c2bcc7cceed1d7306dc6f8958b7\"\nsize = 841408 # 821.69 KiB\n\n[platforms.linux-x64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nchecksum = \"blake3:b0419e57743765a9682d7924816269862890716d7bd3c1b78b2a3dd1f311a7f9\"\nsize = 2255816 # 2.15 MiB'\n\n# Test --fetch with partial existing checksums (should only fetch missing ones)\ncat >./bin/jq-partial <<EOF\n#!/usr/bin/env -S mise tool-stub\n\n[platforms.macos-arm64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-macos-arm64\"\nchecksum = \"blake3:existing_checksum_should_not_change\"\nsize = 123456\n\n[platforms.linux-x64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nEOF\n\nmise g tool-stub ./bin/jq-partial --fetch\n\nassert_contains \"cat ./bin/jq-partial\" 'checksum = \"blake3:existing_checksum_should_not_change\"'\nassert_contains \"cat ./bin/jq-partial\" 'size = 123456'\nassert_contains \"cat ./bin/jq-partial\" '[platforms.linux-x64]\nurl = \"https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-linux64\"\nchecksum = \"blake3:b0419e57743765a9682d7924816269862890716d7bd3c1b78b2a3dd1f311a7f9\"\nsize = 2255816'\n"
  },
  {
    "path": "e2e/generate/test_generate_tool_stub_lock",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2103\n\n# Test mise generate tool-stub --lock functionality\n\n# Disable GPG verification to avoid test failures\nexport MISE_GPG_VERIFY=false\n\n# Create test project directory\nmkdir -p generate_tool_stub_lock_test/bin\ncd generate_tool_stub_lock_test\n\n# Test 1: Lock a non-HTTP tool stub (github:jdx/tiny)\ncat >bin/tiny <<'EOF'\n#!/usr/bin/env -S mise tool-stub\n\ntool = \"github:jdx/tiny\"\nversion = \"1\"\nbin = \"bin/tiny\"\nEOF\nchmod +x bin/tiny\n\nassert_succeed \"mise generate tool-stub bin/tiny --lock\"\n\n# Verify version was pinned to an exact version (not just \"1\")\nassert_not_contains \"cat bin/tiny\" 'version = \"1\"'\nassert_contains \"cat bin/tiny\" 'version = \"1.'\n\n# Verify [lock.platforms.*] sections were added\nassert_contains \"cat bin/tiny\" \"[lock.platforms.\"\nassert_contains \"cat bin/tiny\" \"url =\"\nassert_contains \"cat bin/tiny\" \"checksum =\"\n\n# Verify the shebang is preserved\nassert_contains \"cat bin/tiny\" \"#!/usr/bin/env -S mise tool-stub\"\n\n# Verify the tool field is preserved\nassert_contains \"cat bin/tiny\" 'tool = \"github:jdx/tiny\"'\n\n# Test 2: Bump version with --lock --version\nassert_succeed \"mise generate tool-stub bin/tiny --lock --version 2\"\n\n# Verify version was bumped\nassert_contains \"cat bin/tiny\" 'version = \"2.'\nassert_not_contains \"cat bin/tiny\" 'version = \"1.'\n\n# Verify lock sections still present after bump\nassert_contains \"cat bin/tiny\" \"[lock.platforms.\"\nassert_contains \"cat bin/tiny\" \"url =\"\n\n# Test 3: Re-lock preserves version (idempotent)\nlocked_version=$(grep 'version = ' bin/tiny | head -1 | sed 's/.*\"\\(.*\\)\".*/\\1/')\nassert_succeed \"mise generate tool-stub bin/tiny --lock\"\n\n# Version should be the same after re-locking\nassert_contains \"cat bin/tiny\" \"version = \\\"$locked_version\\\"\"\n\n# Test 4: Lock fails on non-existent file\nassert_fail \"mise generate tool-stub bin/nonexistent --lock\"\n\n# Test 5: Execute the locked stub to verify it works\nassert_contains \"mise tool-stub bin/tiny\" \"tiny v2.\"\n\necho \"All tool-stub lock tests passed!\"\n"
  },
  {
    "path": "e2e/helpers/scripts/git_http_backend_server.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nGit HTTP Backend Server for E2E Testing\nServes git repositories using git-http-backend CGI\n\"\"\"\n\nimport os\nimport sys\nimport subprocess\nimport tempfile\nimport shutil\nimport http.server\nimport socketserver\nfrom pathlib import Path\n\nclass GitHTTPHandler(http.server.BaseHTTPRequestHandler):\n    def __init__(self, *args, repo_dir=None, **kwargs):\n        self.repo_dir = repo_dir\n        super().__init__(*args, **kwargs)\n\n    def do_GET(self):\n        self.handle_git_request()\n\n    def do_POST(self):\n        self.handle_git_request()\n\n    def handle_git_request(self):\n        # Set up environment for git-http-backend\n        env = os.environ.copy()\n        env['GIT_PROJECT_ROOT'] = str(self.repo_dir)\n        env['GIT_HTTP_EXPORT_ALL'] = '1'\n\n        # Map /repo.git paths to /repo\n        path_info = self.path\n        if path_info.startswith('/repo.git'):\n            path_info = path_info.replace('/repo.git', '/repo', 1)\n\n        env['PATH_INFO'] = path_info\n        env['REQUEST_METHOD'] = self.command\n        env['QUERY_STRING'] = ''\n        env['REMOTE_ADDR'] = self.client_address[0]\n\n        if '?' in path_info:\n            env['PATH_INFO'], env['QUERY_STRING'] = path_info.split('?', 1)\n\n        # Read request body for POST\n        content_length = int(self.headers.get('Content-Length', 0))\n        request_body = self.rfile.read(content_length) if content_length > 0 else b''\n\n        # Set content type if provided\n        if 'Content-Type' in self.headers:\n            env['CONTENT_TYPE'] = self.headers['Content-Type']\n\n        # Run git-http-backend\n        try:\n            proc = subprocess.Popen(\n                ['git', 'http-backend'],\n                env=env,\n                stdin=subprocess.PIPE,\n                stdout=subprocess.PIPE,\n                stderr=subprocess.PIPE\n            )\n\n            stdout, stderr = proc.communicate(input=request_body)\n\n            if proc.returncode == 0:\n                # Parse CGI response\n                headers_done = False\n                lines = stdout.split(b'\\n')\n\n                # Default to 200 OK\n                self.send_response(200)\n\n                # Process headers\n                body_start = len(lines)  # Default to end if no separator found\n                for i, line in enumerate(lines):\n                    if not headers_done:\n                        if line == b'' or line == b'\\r':\n                            headers_done = True\n                            body_start = i + 1\n                            break\n                        elif b':' in line:\n                            header_line = line.decode('utf-8', errors='ignore').strip()\n                            if ':' in header_line:\n                                key, value = header_line.split(':', 1)\n                                self.send_header(key.strip(), value.strip())\n\n                # Always call end_headers even if no empty line was found\n                if not headers_done:\n                    # No empty line found, but we still need to end headers\n                    body_start = 0  # Treat entire output as body if no headers found\n\n                self.end_headers()\n\n                # Send body content\n                if body_start < len(lines):\n                    body = b'\\n'.join(lines[body_start:])\n                    self.wfile.write(body)\n            else:\n                self.send_error(500, f\"Git backend error: {stderr.decode()}\")\n\n        except Exception as e:\n            self.send_error(500, f\"Server error: {str(e)}\")\n\ndef create_test_repo(repo_path):\n    \"\"\"Create a minimal test repository\"\"\"\n    # Create a regular (non-bare) repository\n    subprocess.run(['git', 'init', repo_path], check=True)\n\n    # Configure git in the repository\n    subprocess.run(['git', 'config', 'user.name', 'Test User'], cwd=repo_path, check=True)\n    subprocess.run(['git', 'config', 'user.email', 'test@example.com'], cwd=repo_path, check=True)\n\n    # Create test files\n    xtasks_dir = Path(repo_path) / 'xtasks' / 'lint'\n    xtasks_dir.mkdir(parents=True)\n\n    ripgrep_file = xtasks_dir / 'ripgrep'\n    ripgrep_file.write_text('#!/usr/bin/env bash\\necho \"ripgrep task executed\"\\n')\n    ripgrep_file.chmod(0o755)\n\n    # Commit files\n    subprocess.run(['git', 'add', '.'], cwd=repo_path, check=True)\n    subprocess.run(['git', 'commit', '-m', 'Add test files'], cwd=repo_path, check=True)\n    subprocess.run(['git', 'tag', 'v2025.1.17'], cwd=repo_path, check=True)\n\n    # Handle branch naming\n    current_branch = subprocess.run(\n        ['git', 'branch', '--show-current'],\n        cwd=repo_path,\n        capture_output=True,\n        text=True\n    ).stdout.strip()\n\n    if current_branch != 'main':\n        subprocess.run(['git', 'branch', '-m', current_branch, 'main'], cwd=repo_path, check=True)\n\n    # Configure repo for HTTP serving\n    subprocess.run(['git', 'config', 'http.receivepack', 'true'], cwd=repo_path, check=True)\n    subprocess.run(['git', 'config', 'http.uploadpack', 'true'], cwd=repo_path, check=True)\n    subprocess.run(['git', 'update-server-info'], cwd=repo_path, check=True)\n\ndef start_server(port=0):\n    # Create temp directory\n    temp_dir = Path(tempfile.mkdtemp(prefix='mise_git_http_'))\n    repo_path = temp_dir / 'repo'\n\n    print(f\"Creating test repository at {repo_path}\")\n    create_test_repo(str(repo_path))\n\n    # Create handler with repo directory\n    def handler(*args, **kwargs):\n        return GitHTTPHandler(*args, repo_dir=temp_dir, **kwargs)\n\n    # Let the OS assign an available port if port=0\n    # This avoids race conditions between finding and binding\n    with socketserver.TCPServer((\"\", port), handler) as httpd:\n        actual_port = httpd.server_address[1]\n        print(f\"Git HTTP server running on port {actual_port}\")\n        print(f\"Repository URL: http://localhost:{actual_port}/repo.git\")\n\n        # Write the actual port to a file for the test to read\n        port_file = Path('/tmp/mise_git_http_port')\n        port_file.write_text(str(actual_port))\n\n        # Also write a ready marker file\n        ready_file = Path('/tmp/mise_git_http_ready')\n        ready_file.write_text('ready')\n\n        # Save cleanup info\n        with open('/tmp/mise_git_http_info', 'w') as f:\n            f.write(f\"{temp_dir}\\n\")\n\n        try:\n            httpd.serve_forever()\n        except KeyboardInterrupt:\n            print(\"\\nShutting down...\")\n        finally:\n            shutil.rmtree(temp_dir, ignore_errors=True)\n            port_file.unlink(missing_ok=True)\n            ready_file.unlink(missing_ok=True)\n\nif __name__ == '__main__':\n    port = int(sys.argv[1]) if len(sys.argv) > 1 else 0\n    start_server(port)"
  },
  {
    "path": "e2e/helpers/scripts/http_test_server.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nSimple HTTP Server for E2E Testing\nServes test files to avoid external network dependencies\n\nUsage:\n    http_test_server.py [port] [headers_log_dir]\n\nIf headers_log_dir is provided, request headers will be logged to files in that directory.\n\"\"\"\n\nimport http.server\nimport json\nimport socketserver\nimport sys\nfrom pathlib import Path\n\n# Global headers log directory (set via command line)\nHEADERS_LOG_DIR = None\n\n\nclass TestFileHandler(http.server.SimpleHTTPRequestHandler):\n    def do_GET(self):\n        \"\"\"Handle GET requests for test files\"\"\"\n        self._log_headers()\n\n        if self.path == '/test/mytask':\n            # Return the test task script\n            self.send_response(200)\n            self.send_header('Content-Type', 'text/plain')\n            self.end_headers()\n            content = '#!/usr/bin/env bash\\necho \"running mytask\"\\n'\n            self.wfile.write(content.encode('utf-8'))\n        else:\n            # Return 404 for other paths\n            self.send_error(404, \"File not found\")\n\n    def do_HEAD(self):\n        \"\"\"Handle HEAD requests\"\"\"\n        self._log_headers()\n        self.send_response(200)\n        self.end_headers()\n\n    def _log_headers(self):\n        \"\"\"Log request headers to file if log directory is configured\"\"\"\n        if HEADERS_LOG_DIR:\n            log_dir = Path(HEADERS_LOG_DIR)\n            log_dir.mkdir(parents=True, exist_ok=True)\n\n            # Use incrementing counter for log files\n            existing = list(log_dir.glob(\"request_*.json\"))\n            next_num = len(existing) + 1\n            log_file = log_dir / f\"request_{next_num:04d}.json\"\n\n            headers_dict = dict(self.headers)\n            log_data = {\n                \"path\": self.path,\n                \"method\": self.command,\n                \"headers\": headers_dict,\n            }\n            log_file.write_text(json.dumps(log_data, indent=2))\n\n    def log_message(self, format, *args):\n        \"\"\"Suppress log messages for cleaner test output\"\"\"\n        pass\n\n\ndef find_available_port():\n    \"\"\"Find an available port starting from 8080\"\"\"\n    import socket\n    for port in range(8080, 8200):\n        try:\n            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:\n                s.bind(('', port))\n                return port\n        except OSError:\n            continue\n    raise RuntimeError(\"No available ports found\")\n\n\ndef start_server(port=None, headers_log_dir=None):\n    \"\"\"Start the HTTP test server\"\"\"\n    global HEADERS_LOG_DIR\n    HEADERS_LOG_DIR = headers_log_dir\n\n    if port is None:\n        port = find_available_port()\n\n    with socketserver.TCPServer((\"\", port), TestFileHandler) as httpd:\n        print(f\"HTTP test server running on port {port}\")\n\n        # Save port info for tests\n        with open('/tmp/mise_http_test_port', 'w') as f:\n            f.write(str(port))\n\n        try:\n            httpd.serve_forever()\n        except KeyboardInterrupt:\n            print(\"\\nShutting down...\")\n        finally:\n            # Clean up port file\n            Path('/tmp/mise_http_test_port').unlink(missing_ok=True)\n\n\nif __name__ == '__main__':\n    port = int(sys.argv[1]) if len(sys.argv) > 1 else None\n    headers_log_dir = sys.argv[2] if len(sys.argv) > 2 else None\n    start_server(port, headers_log_dir)\n"
  },
  {
    "path": "e2e/helpers/scripts/tool_stub_test_server.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nHTTP Test Server for tool-stub E2E Testing\nServes mock endpoints to avoid external network dependencies\n\"\"\"\n\nimport http.server\nimport socketserver\nimport sys\nimport json\nfrom pathlib import Path\n\nclass ToolStubTestHandler(http.server.SimpleHTTPRequestHandler):\n    def do_GET(self):\n        \"\"\"Handle GET requests for test endpoints\"\"\"\n        if self.path == '/status/200':\n            self.send_response(200)\n            self.send_header('Content-Type', 'text/plain')\n            self.end_headers()\n            self.wfile.write(b'OK')\n        elif self.path == '/status/201':\n            self.send_response(201)\n            self.send_header('Content-Type', 'text/plain')\n            self.end_headers()\n            self.wfile.write(b'Created')\n        elif self.path == '/status/202':\n            self.send_response(202)\n            self.send_header('Content-Type', 'text/plain')\n            self.end_headers()\n            self.wfile.write(b'Accepted')\n        elif self.path == '/json':\n            self.send_response(200)\n            self.send_header('Content-Type', 'application/json')\n            self.end_headers()\n            content = json.dumps({\n                \"slideshow\": {\n                    \"author\": \"Yours Truly\",\n                    \"date\": \"date of publication\",\n                    \"title\": \"Sample Slide Show\"\n                }\n            })\n            self.wfile.write(content.encode('utf-8'))\n        else:\n            # Return 404 for other paths\n            self.send_error(404, \"File not found\")\n\n    def log_message(self, format, *args):\n        \"\"\"Suppress log messages for cleaner test output\"\"\"\n        pass\n\ndef start_server(port):\n    \"\"\"Start the HTTP test server\"\"\"\n    with socketserver.TCPServer((\"127.0.0.1\", port), ToolStubTestHandler) as httpd:\n        print(f\"Tool stub test server running on port {port}\", flush=True)\n        try:\n            httpd.serve_forever()\n        except KeyboardInterrupt:\n            print(\"\\nShutting down...\", flush=True)\n\nif __name__ == '__main__':\n    if len(sys.argv) < 2:\n        print(\"Usage: tool_stub_test_server.py <port>\", file=sys.stderr)\n        sys.exit(1)\n    port = int(sys.argv[1])\n    start_server(port)"
  },
  {
    "path": "e2e/lockfile/test_lockfile_alias",
    "content": "#!/usr/bin/env bash\n\n# Test that lockfile is respected when using version aliases\n# https://github.com/jdx/mise/discussions/8175\n\nexport MISE_LOCKFILE=1\n\ncat <<EOF >mise.toml\n[tools]\ntiny = \"myalias\"\n\n[tool_alias.tiny.versions]\nmyalias = \"2\"\n\n[settings]\nlockfile = true\nEOF\n\ncat <<EOF >mise.lock\n[[tools.tiny]]\nversion = \"2.0.0\"\nEOF\n\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"\nmise install\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"myalias\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"2.0.0\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_aqua_cross_platform_override",
    "content": "#!/usr/bin/env bash\n\n# Test that aqua lockfile URL resolution uses the target platform and does not\n# leak host-only overrides.\n\nexport MISE_EXPERIMENTAL=1\nexport MISE_LOCKFILE=1\n\ndetect_platform\n\nif [[ $MISE_PLATFORM_OS == \"macos\" ]]; then\n\tHOST_GOOS=\"darwin\"\nelif [[ $MISE_PLATFORM_OS == \"linux\" ]]; then\n\tHOST_GOOS=\"linux\"\nelse\n\techo \"Skipping unsupported host OS: $MISE_PLATFORM_OS\"\n\treturn 0\nfi\n\nTARGET_PLATFORM=\"windows-x64\"\nTARGET_AQUA_OS=\"windows\"\n\nREGISTRY_DIR=\"$PWD/aqua-registry-local\"\nmkdir -p \"$REGISTRY_DIR/pkgs/example/testtool\"\n\ncat <<EOF_REGISTRY >\"$REGISTRY_DIR/pkgs/example/testtool/registry.yaml\"\npackages:\n  - type: http\n    supported_envs:\n      - linux\n      - darwin\n      - windows\n    url: https://example.com/base-{{.OS}}-{{.Arch}}-{{.Version}}.zip\n    overrides:\n      - goos: $HOST_GOOS\n        url: https://example.com/host-{{.OS}}-{{.Arch}}-{{.Version}}.pkg\n        format: pkg\nEOF_REGISTRY\n\n(\n\tcd \"$REGISTRY_DIR\"\n\tgit init -q\n\tgit add pkgs/example/testtool/registry.yaml\n\tgit commit -qm \"init local aqua registry\"\n)\n\nexport MISE_AQUA_BAKED_REGISTRY=0\nexport MISE_AQUA_REGISTRY_URL=\"file://$REGISTRY_DIR\"\n\ncat <<'EOF_MISE' >mise.toml\n[tools]\n\"aqua:example/testtool\" = \"1.0.0\"\nEOF_MISE\n\noutput=$(mise lock --platform \"$TARGET_PLATFORM\" 2>&1)\nassert_contains \"echo '$output'\" \"Targeting 1 platform(s)\"\nassert_contains \"echo '$output'\" \"$TARGET_PLATFORM\"\n\nEXPECTED_URL=\"https://example.com/base-${TARGET_AQUA_OS}-amd64-1.0.0.zip\"\nassert_contains \"cat mise.lock\" \"\\\"platforms.$TARGET_PLATFORM\\\"\"\nassert_contains \"cat mise.lock\" \"url = \\\"$EXPECTED_URL\\\"\"\nassert_not_contains \"cat mise.lock\" \"https://example.com/host-\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_aqua_format_mismatch",
    "content": "#!/usr/bin/env bash\n\n# Test that lockfile URLs are invalidated when registry format changes\n# This simulates the terragrunt issue where the registry changed from\n# raw binary to tar.gz format, but lockfile had the old URL cached\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\n\n# Map platform to aqua asset naming\ncase \"$MISE_PLATFORM_OS\" in\nmacos) ASSET_OS=\"darwin\" ;;\nlinux) ASSET_OS=\"linux\" ;;\n*) ASSET_OS=\"unknown\" ;;\nesac\n\ncase \"$MISE_PLATFORM_ARCH\" in\narm64) ASSET_ARCH=\"arm64\" ;;\n*) ASSET_ARCH=\"amd64\" ;;\nesac\n\n# Use a tool that has tar.gz format (terragrunt >= 0.93.6)\n# Create a lockfile with an \"old\" URL that doesn't have the .tar.gz extension\n# This simulates what would happen if the lockfile was created before\n# the registry was updated to use tar.gz format\n\ncat <<EOF >mise.toml\n[tools]\nterragrunt = \"0.97.0\"\nEOF\n\n# Create lockfile with intentionally wrong asset name (missing .tar.gz)\n# The registry expects terragrunt_linux_amd64.tar.gz but we provide the old raw binary name\nOLD_WRONG_URL=\"https://github.com/gruntwork-io/terragrunt/releases/download/v0.97.0/terragrunt_${ASSET_OS}_${ASSET_ARCH}\"\ncat <<EOF >mise.lock\n[[tools.terragrunt]]\nversion = \"0.97.0\"\nbackend = \"aqua:gruntwork-io/terragrunt\"\n\"platforms.$MISE_PLATFORM\" = { url = \"$OLD_WRONG_URL\" }\nEOF\n\nrm -rf \"$MISE_DATA_DIR/installs/terragrunt\"\nrm -rf \"$MISE_DATA_DIR/downloads/terragrunt\"\n\n# Run mise install and capture output\n# It should detect the mismatch and download the correct asset\nOUTPUT=$(mise install 2>&1)\n\n# Should warn about the mismatch\nassert_contains \"echo \\\"$OUTPUT\\\"\" \"doesn't match registry\"\n\n# Should successfully install\nassert \"mise x terragrunt -- terragrunt --version\" \"terragrunt version v0.97.0\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_assets",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\n# Test creating a lockfile with inline table platforms\ncat <<EOF >mise.lock\n[[tools.tiny]]\nversion = \"1.0.0\"\nbackend = \"asdf:tiny\"\n\"platforms.linux-x64\" = { checksum = \"sha256:abc123\" }\n\n[[tools.dummy]]\nversion = \"2.0.0\"\nbackend = \"core:dummy\"\n\"platforms.linux-x64\" = { checksum = \"sha256:def456\", url = \"https://example.com/dummy-2.0.0-linux-x64.tar.gz\" }\nEOF\n\necho \"New format lockfile:\"\ncat mise.lock\n\n# Test that the lockfile is read correctly\nmise ls\n\necho \"After reading:\"\ncat mise.lock\n\n# Should have platforms with inline table format\nassert_contains \"cat mise.lock\" '\"platforms.linux-x64\"'\nassert_contains \"cat mise.lock\" 'checksum = \"sha256:abc123\"'\nassert_contains \"cat mise.lock\" 'checksum = \"sha256:def456\"'\nassert_contains \"cat mise.lock\" 'url = \"https://example.com/dummy-2.0.0-linux-x64.tar.gz\"'\n\n# Should not have individual tool asset sections\nassert_not_contains \"cat mise.lock\" \"[tools.tiny.assets]\"\nassert_not_contains \"cat mise.lock\" \"[tools.dummy.assets]\"\nassert_not_contains \"cat mise.lock\" \"[tools.tiny.checksums]\"\nassert_not_contains \"cat mise.lock\" \"[tools.dummy.checksums]\"\n\necho \"Platform-based format test passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_auto_lock",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\n# === Test 1: mise use auto-locks all platforms ===\n# When using a tool that supports cross-platform resolution (aqua tool),\n# the lockfile should automatically get entries for all 5 common platforms,\n# not just the current one.\n\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\ntouch mise.lock\nmise use \"aqua:jqlang/jq@1.7.1\"\n\n# Verify all 5 common platforms are in the lockfile (auto-locked)\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\nassert_contains \"cat mise.lock\" \"platforms.linux-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-x64\"\nassert_contains \"cat mise.lock\" \"platforms.macos-arm64\"\nassert_contains \"cat mise.lock\" \"platforms.windows-x64\"\nassert_contains \"cat mise.lock\" \"jqlang/jq\"\n\n# === Test 2: subsequent install doesn't modify lockfile ===\n# Simulates another developer running mise install - lockfile should not change\n# because all platforms are already populated.\n\ncp mise.lock mise.lock.before\nmise install\nassert \"diff mise.lock mise.lock.before\" \"\"\n\n# === Test 3: mise install auto-locks a newly added tool ===\n\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\n\"aqua:mikefarah/yq\" = \"4.44.6\"\nEOF\n\nmise install\nassert_contains \"cat mise.lock\" \"mikefarah/yq\"\nassert_contains \"cat mise.lock\" \"platforms.linux-x64\"\n\nrm -f mise.toml mise.lock mise.lock.before\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_backend",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\nassert \"mise tool gh --backend\" \"aqua:cli/cli\"\ncat <<EOF >mise.toml\n[tools.gh]\nversion = \"1.0.0\"\nEOF\ncat <<EOF >mise.lock\n[[tools.gh]]\nversion = \"1.0.0\"\nbackend = \"ubi:cli/cli[exe=gh]\"\nEOF\nassert \"mise tool gh --backend\" \"ubi:cli/cli[exe=gh]\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_cosign_opts_only",
    "content": "#!/usr/bin/env bash\n# Regression test: tools with cosign opts-only config should not record\n# cosign provenance in the lockfile, since we can't verify it natively.\n# See: https://github.com/jdx/mise/discussions/8547\n\nexport MISE_LOCKFILE=1\nexport MISE_AQUA_COSIGN=true\nexport MISE_AQUA_SLSA=false\nexport MISE_GITHUB_ATTESTATIONS=0\nexport MISE_AQUA__GITHUB_ATTESTATIONS=0\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\necho \"=== Testing cosign opts-only tool does not record cosign provenance ===\"\n\n# yamlfmt uses cosign with only opts (no key or bundle), which we can't verify natively\ncat <<EOF >mise.toml\n[tools]\nyamlfmt = \"0.21.0\"\nEOF\n\nmise lock --platform \"$PLATFORM\"\nassert \"test -f mise.lock\"\n\n# The lockfile should NOT contain cosign provenance for this tool\nassert_not_contains \"cat mise.lock\" 'provenance = \"cosign\"'\n\necho \"=== Testing install works without cosign provenance mismatch ===\"\n# This would fail with \"Lockfile requires cosign provenance ... but no verification was used\"\n# before the fix, since the lockfile recorded cosign provenance that can't be verified natively\nmise install\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\nmise uninstall yamlfmt@0.21.0 || true\n\necho \"cosign opts-only lockfile test passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_empty",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\n# Create base config\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\ntouch mise.lock\nassert \"mise install tiny@1.0.0\"\nassert \"mise use tiny@1\"\n\n# Base tool should be in mise.lock\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\n\n# Now let's empty out our tools, uninstall everything and confirm we just end up with an empty lockfile\nassert \"mise uninstall --all\"\nassert \"mise unuse tiny\"\nassert \"mise lock\"\n\n# empty lockfile should just have header and tools section\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[tools]\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_env",
    "content": "#!/usr/bin/env bash\n\n# Test that environment-specific configs create separate lockfiles\n# When MISE_ENV=test, tools from mise.test.toml go into mise.test.lock\n\nexport MISE_LOCKFILE=1\n\n# Create env-specific config only (to avoid override complexity)\ncat >mise.test.toml <<'EOF'\n[tools]\ntiny = \"2\"\nEOF\n\n# Create both lockfiles so they get updated\ntouch mise.lock mise.test.lock\n\n# Install version\nassert \"mise install tiny@2.1.0\"\n\n# With MISE_ENV=test, use the test config\n# Note: Must pass MISE_ENV in the command itself since assert uses bash -c\nassert \"MISE_ENV=test mise use tiny@2\"\n\n# Check that mise.test.lock has the tool (not mise.lock)\nassert_contains \"cat mise.test.lock\" 'version = \"2.1.0\"'\nassert_contains \"cat mise.test.lock\" '[[tools.tiny]]'\n# No env field should be in the lockfile (env is encoded in filename)\nassert_not_contains \"cat mise.test.lock\" 'env = '\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_env_base_override",
    "content": "#!/usr/bin/env bash\n\n# Test that when a tool exists in both base and env-specific configs,\n# it goes into both lockfiles independently (no cross-contamination)\n\nexport MISE_LOCKFILE=1\n\necho \"=== Setup: tiny in both base and dev config ===\"\n\ncat >mise.toml <<'EOF'\n[settings]\nlockfile = true\n\n[tools]\ntiny = \"1\"\nEOF\n\ncat >mise.dev.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\ntouch mise.lock mise.dev.lock\n\n# Install with base config first\nassert \"mise install tiny@1.0.1\"\n\necho \"=== Test: MISE_ENV=dev should create entries in both lockfiles ===\"\n\nassert \"MISE_ENV=dev mise install\"\n\n# The base lockfile should have the tool\nassert_contains \"cat mise.lock\" '[[tools.tiny]]'\n# The dev lockfile should also have the tool\nassert_contains \"cat mise.dev.lock\" '[[tools.tiny]]'\n# Neither should have env field (env is encoded in filename)\nassert_not_contains \"cat mise.lock\" 'env = '\nassert_not_contains \"cat mise.dev.lock\" 'env = '\n\necho \"=== Test: tool only in env config should only be in env lockfile ===\"\n\n# Remove tiny from base config\ncat >mise.toml <<'EOF'\n[settings]\nlockfile = true\nEOF\n\nrm -f mise.lock mise.dev.lock\ntouch mise.dev.lock\n\nassert \"MISE_ENV=dev mise install\"\n\n# Base lockfile should not exist or not have tiny (no tools in mise.toml)\nassert_fail \"grep -q 'tools.tiny' mise.lock 2>/dev/null\"\n# Dev lockfile should have tiny\nassert_contains \"cat mise.dev.lock\" '[[tools.tiny]]'\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.dev.lock mise.toml mise.dev.toml\n\necho \"lockfile env base override tests passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_env_resolution",
    "content": "#!/usr/bin/env bash\n\n# Test that MISE_ENV selects the correct locked version from separate lockfiles\n\nexport MISE_LOCKFILE=1\n\n# Create base config and env-specific config both requesting \"tiny\"\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"latest\"\nEOF\n\ncat >mise.test.toml <<'EOF'\n[tools]\ntiny = \"latest\"\nEOF\n\n# Install both versions FIRST (before creating lockfile)\n# This prevents install from overwriting our manually-crafted lockfile\nassert \"mise install tiny@1.0.0\"\nassert \"mise install tiny@2.1.0\"\n\n# Create separate lockfiles: base and env-specific\ncat >mise.lock <<'EOF'\n[[tools.tiny]]\nversion = \"1.0.0\"\nbackend = \"asdf:tiny\"\nEOF\n\ncat >mise.test.lock <<'EOF'\n[[tools.tiny]]\nversion = \"2.1.0\"\nbackend = \"asdf:tiny\"\nEOF\n\n# Without MISE_ENV, should use base version from mise.lock (1.0.0)\nassert \"mise where tiny\" \"$MISE_DATA_DIR/installs/tiny/1.0.0\"\n\n# With MISE_ENV=test, should use version from mise.test.lock (2.1.0)\n# Note: Must pass MISE_ENV in the command itself since assert uses bash -c\nassert \"MISE_ENV=test mise where tiny\" \"$MISE_DATA_DIR/installs/tiny/2.1.0\"\n\n# With MISE_ENV=production (no mise.production.lock), should fall back to base (1.0.0)\nassert \"MISE_ENV=production mise where tiny\" \"$MISE_DATA_DIR/installs/tiny/1.0.0\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_exec",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ntouch mise.lock\nassert \"mise install tiny@1.0.0\"\nassert \"mise use tiny@1\"\nassert \"mise current tiny\" \"1.0.0\"\nassert \"mise install tiny@1.0.1\"\nassert \"mise current tiny\" \"1.0.0\"\nassert \"mise x -- rtx-tiny\" \"rtx-tiny: v1.0.0 args:\"\n#TODO: assert \"mise x tiny -- rtx-tiny\" \"rtx-tiny: v1.0.0 args:\"\nassert \"mise x tiny@1.0.1 -- rtx-tiny\" \"rtx-tiny: v1.0.1 args:\"\nassert \"mise x -- rtx-tiny\" \"rtx-tiny: v1.0.0 args:\"\nassert \"mise x tiny@3.0.0 -- rtx-tiny\" \"rtx-tiny: v3.0.0 args:\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_install",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\ntouch mise.lock\nmise use tiny\ncat <<EOF >mise.lock\n[[tools.tiny]]\nversion = \"1.0.0\"\nEOF\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"\nmise install\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"latest\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"1.0.0\"\n\n# validates checksum\nmise use gh@2.62.0\ncat mise.lock\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM\\\"\"\nassert_contains \"cat mise.lock\" 'checksum = \"sha256:'\n\n# Test rewriting existing lockfile section with same content\n# Using inline table format\nGH_URL=\"https://github.com/cli/cli/releases/download/v2.62.0/gh_2.62.0_$(\n\tcase \"$PLATFORM\" in\n\tlinux-x64) echo \"linux_amd64\" ;;\n\tlinux-arm64) echo \"linux_arm64\" ;;\n\tmacos-x64) echo \"macOS_amd64\" ;;\n\tmacos-arm64) echo \"macOS_arm64\" ;;\n\t*) echo \"$PLATFORM\" ;;\n\tesac\n).zip\"\ncat <<EOF >mise.lock\n[[tools.gh]]\nversion = \"2.62.0\"\nbackend = \"aqua:cli/cli\"\n\"platforms.$PLATFORM\" = { checksum = \"blake3:aaaaa\", url = \"$GH_URL\" }\nEOF\nassert_fail \"mise i gh -f\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_local",
    "content": "#!/usr/bin/env bash\n\n# Test that local configs use mise.local.lock\n\nexport MISE_LOCKFILE=1\n\n# Create base config\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\n# Create local config\ncat >mise.local.toml <<'EOF'\n[tools]\ndummy = \"1.0.0\"\nEOF\n\n# Create both lockfiles\ntouch mise.lock\ntouch mise.local.lock\n\n# Install tools\nassert \"mise install tiny@1.0.0\"\nassert \"mise install dummy@1.0.0\"\n\n# Use the tools to trigger lockfile updates\n# Use --path to ensure tiny goes to mise.toml (not mise.local.toml which takes precedence)\nassert \"mise use tiny@1 --path mise.toml\"\n# Use dummy to trigger mise.local.lock update\nassert \"mise use dummy@1.0.0 --path mise.local.toml\"\n\n# Base tool should be in mise.lock\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\n\n# Local tool should be in mise.local.lock\nassert_contains \"cat mise.local.lock\" \"[[tools.dummy]]\"\nassert_contains \"cat mise.local.lock\" 'version = \"1.0.0\"'\n\n# mise.lock should NOT contain dummy\nassert_not_contains \"cat mise.lock\" \"dummy\"\n\n# mise.local.lock should NOT contain tiny\nassert_not_contains \"cat mise.local.lock\" \"tiny\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_locked_mode",
    "content": "#!/usr/bin/env bash\n\n# Test --locked mode enforcement during install and dry-run\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\n# Use jq via aqua backend, which supports lockfile URLs\ncat <<'EOF' >mise.toml\n[tools]\njq = \"1.7.1\"\nEOF\n\n# Uninstall jq so it's not already present\nmise uninstall jq@1.7.1 2>/dev/null || true\n\n# --- Test 1: --locked fails when no lockfile URL exists ---\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\nEOF\n\nassert_fail_contains \"mise install --locked 2>&1\" \"No lockfile URL found\"\n\n# --- Test 2: --locked --dry-run also fails when no lockfile URL exists ---\n# This is the key behavior: locked validation must run before dry-run short-circuit\nassert_fail_contains \"mise install --locked --dry-run 2>&1\" \"No lockfile URL found\"\n\n# --- Test 3: --locked --dry-run succeeds when lockfile URL exists ---\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.$PLATFORM\" = { url = \"https://example.com/jq-1.7.1.tar.gz\" }\nEOF\n\nassert_contains \"mise install --locked --dry-run 2>&1\" \"would install\"\n\n# --- Test 4: locked=true with MISE_LOCKFILE=false errors (contradictory config) ---\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.$PLATFORM\" = { url = \"https://example.com/jq-1.7.1.tar.gz\" }\nEOF\n\nMISE_LOCKFILE=0 assert_fail_contains \"mise install --locked --dry-run 2>&1\" \"locked mode requires lockfile to be enabled\"\n\n# --- Test 5: locked setting via config with lockfile=false errors ---\n# Unset MISE_LOCKFILE so the env var doesn't override the config file setting\nunset MISE_LOCKFILE\n\ncat <<'EOF' >mise.toml\n[tools]\njq = \"1.7.1\"\n[settings]\nlocked = true\nlockfile = false\nEOF\n\nassert_fail_contains \"mise install --dry-run 2>&1\" \"locked mode requires lockfile to be enabled\"\n\n# --- Test 6: locked=true with lockfile unset (not in config) works fine ---\ncat <<'EOF' >mise.toml\n[tools]\njq = \"1.7.1\"\n[settings]\nlocked = true\nEOF\n\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.$PLATFORM\" = { url = \"https://example.com/jq-1.7.1.tar.gz\" }\nEOF\n\nassert_contains \"mise install --dry-run 2>&1\" \"would install\"\n\n# --- Test 7: mise lock refuses to run in --locked mode ---\nexport MISE_LOCKFILE=1\n\ncat <<'EOF' >mise.toml\n[tools]\njq = \"1.7.1\"\nEOF\n\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.$PLATFORM\" = { url = \"https://example.com/jq-1.7.1.tar.gz\" }\nEOF\n\nassert_fail_contains \"mise lock --locked 2>&1\" \"mise lock is disabled in --locked mode\"\nMISE_LOCKED=1 assert_fail_contains \"mise lock 2>&1\" \"mise lock is disabled in --locked mode\"\n\n# Restore for any subsequent tests\nexport MISE_LOCKFILE=1\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_provenance",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\necho \"=== Testing mise lock writes provenance ===\"\n# Use a tool that has SLSA provenance in the aqua registry (sops)\ncat <<EOF >mise.toml\n[tools]\nsops = \"3.12.1\"\nEOF\n\n# Generate lockfile - provenance detection should be on by default\nmise lock --platform \"$PLATFORM\"\nassert \"test -f mise.lock\"\n# sops has SLSA provenance configured in the aqua registry\nassert_contains \"cat mise.lock\" 'provenance = \"slsa\"'\n\necho \"=== Testing provenance downgrade attack detection ===\"\nrm -f mise.lock mise.toml\n\n# Set up a tool via aqua backend\ncat <<EOF >mise.toml\n[tools]\n\"aqua:jqlang/jq\" = \"1.7.1\"\nEOF\n\n# Generate lockfile with real checksums/URLs for the current platform only\nmise lock --platform \"$PLATFORM\"\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM\\\"\"\n\n# Inject provenance into the lockfile (simulating a previously-verified install)\n# Use awk for portable sed-like editing (works on both macOS and Linux)\nawk -v platform=\"$PLATFORM\" '\n    # Remove existing provenance lines in the target platform section\n    /^provenance/ && in_section { next }\n    # Detect entering the target platform section and add provenance after the header\n    { print }\n    index($0, \"platforms.\" platform) > 0 { in_section=1; print \"provenance = \\\"github-attestations\\\"\" }\n    /^\\[/ { in_section=0 }\n' mise.lock >mise.lock.tmp && mv mise.lock.tmp mise.lock\nassert_contains \"cat mise.lock\" 'provenance = \"github-attestations\"'\n\n# Attempt install with provenance verification disabled.\n# The lockfile says provenance was verified, but settings are off,\n# so mise should refuse to install (downgrade/stripping attack).\nrm -rf \"$MISE_DATA_DIR/installs/aqua-jqlang-jq\"\nexport MISE_GITHUB_ATTESTATIONS=0\nexport MISE_AQUA__GITHUB_ATTESTATIONS=0\nassert_fail_contains \"mise install 2>&1\" \"downgrade attack\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\n\necho \"mise lockfile provenance tests passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_prune_stale_tools",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\n# Use local fixture plugin for tiny to avoid network access.\nln -sf \"$ROOT/test/data/plugins/tiny\" \"$MISE_DATA_DIR/plugins/tiny\"\nrm -f mise.toml mise.lock\n\necho \"=== Lockfile with initial tool ===\"\ncat <<EOF >mise.toml\n[tools]\ndummy = \"1.0.0\"\nEOF\n\nmise install dummy@1.0.0\nmise lock --platform linux-x64\nassert_contains \"cat mise.lock\" \"[[tools.dummy]]\"\nassert_not_contains \"cat mise.lock\" \"[[tools.tiny]]\"\n\necho \"=== Replace configured tool and relock ===\"\ncat <<EOF >mise.toml\n[tools]\ntiny = \"2.1.0\"\nEOF\n\nmise install tiny@2.1.0\nmise lock --platform linux-x64\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_not_contains \"cat mise.lock\" \"[[tools.dummy]]\"\n\necho \"=== Remove all tools and relock ===\"\ncat <<EOF >mise.toml\n[tools]\nEOF\n\nassert_contains \\\n\t\"mise lock --dry-run --platform linux-x64\" \\\n\t\"Dry run - would prune 1 stale tool entry\"\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\n\nOUTPUT=$(mise lock --platform linux-x64 2>&1)\nassert_contains \"echo \\\"$OUTPUT\\\"\" \"Pruned 1 stale tool entry\"\nassert_not_contains \"echo \\\"$OUTPUT\\\"\" \"No tools configured to lock\"\n# empty lockfile should just have header and tools section\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[tools]\"\n\necho \"=== Cleanup ===\"\nrm -f mise.toml mise.lock\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_python",
    "content": "#!/usr/bin/env bash\n\n# Test that core:python generates lockfile URLs from python-build-standalone\nexport MISE_LOCKFILE=1\n\ndetect_platform\n\ncat <<EOF >mise.toml\n[tools]\npython = \"3.13.5\"\nEOF\n\nrm -f mise.lock\n\noutput=$(mise lock --platform \"$MISE_PLATFORM\" 2>&1)\nassert_contains \"echo '$output'\" \"Processing 1 tool(s)\"\n\n# Verify lockfile has URL and checksum for python\nassert_contains \"cat mise.lock\" \"\\\"platforms.$MISE_PLATFORM\\\"\"\nassert_contains \"cat mise.lock\" \"github.com/astral-sh/python-build-standalone/releases/download\"\nassert_contains \"cat mise.lock\" \"sha256:\"\n\necho \"Lockfile content after mise lock:\"\ncat mise.lock\n\necho \"=== Testing that mise install verifies checksum against existing lockfile ===\"\nrm -rf \"$MISE_DATA_DIR/installs/python\"\nmise install python -f\nassert_contains \"cat mise.lock\" \"github.com/astral-sh/python-build-standalone/releases/download\"\nassert_contains \"cat mise.lock\" \"sha256:\"\n\necho \"Lockfile content after mise install:\"\ncat mise.lock\n\necho \"=== Testing checksum verification rejects corrupted checksums ===\"\n# Corrupt the checksum in the lockfile to verify that install catches it.\n# Replace the real sha256 hash with a bogus value using awk.\nawk '\n    /^checksum = \"sha256:/ { print \"checksum = \\\"sha256:0000000000000000000000000000000000000000000000000000000000000000\\\"\"; next }\n    { print }\n' mise.lock >mise.lock.tmp && mv mise.lock.tmp mise.lock\n\nassert_contains \"cat mise.lock\" \"sha256:0000000000000000000000000000000000000000000000000000000000000000\"\n\n# Install with corrupted checksum should fail with a checksum mismatch error\nrm -rf \"$MISE_DATA_DIR/installs/python\"\nassert_fail \"mise install python -f\" \"Checksum mismatch\"\n\nrm -f mise.lock mise.toml\n\necho \"Python lockfile URL test passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_symlink",
    "content": "#!/usr/bin/env bash\n\n# Test that if a lockfile is a symlink, that updating the lockfile keeps the symlink intact.\n\nexport MISE_LOCKFILE=1\n\n# Create base config\ncat >mise.toml <<'EOF'\n[tools]\ntiny = \"1\"\nEOF\n\n# Create a lockfile that is a symlink to another file.\n# Put it into a subdirectory to ensure that mise correctly resolves the symlink\n# target when updating from a different directory.\nmkdir example-dotfiles\ntouch example-dotfiles/real-mise.lock\nln -s example-dotfiles/real-mise.lock mise.lock\n\n# Install tools\nassert \"mise install tiny@1.0.0\"\n\n# Use the tools to trigger lockfile updates\nassert \"mise use tiny@1\"\n\n# Verify that the lockfile is still a symlink\nassert \"[[ -L mise.lock ]] && [[ $(readlink mise.lock) == example-dotfiles/real-mise.lock ]]\"\n\n# Base tool should be in mise.lock\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_contains \"cat mise.lock\" 'version = \"1.0.0\"'\n\n# Verify that updating from a subdirectory also resolves the symlink target correctly\nmkdir -p subdir\n( # Use subshell to avoid having to cd back (SC2103)\n\tcd subdir\n\n\t# Using a new version to ensure the lockfile is updated\n\tassert \"mise install tiny@2.1.0\"\n\tassert \"mise use tiny@2\"\n)\n\nassert \"[[ -L mise.lock ]] && [[ $(readlink mise.lock) == example-dotfiles/real-mise.lock ]]\"\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_contains \"cat mise.lock\" 'version = \"2.1.0\"'\n\n# Finally, let's test a dangling symlink scenario where the target file is deleted.\n\n# Remove the real lockfile, leaving a dangling symlink\nrm example-dotfiles/real-mise.lock\n\n# Attempt to update the lockfile.\n# This will overwrite the symlink with a new regular file since the target is missing.\nassert \"mise lock\"\n\n# Verify that the lockfile is no longer a symlink (since the target was missing)\nassert \"[[ ! -L mise.lock ]]\"\nassert_contains \"cat mise.lock\" \"[[tools.tiny]]\"\nassert_contains \"cat mise.lock\" 'version = \"2.1.0\"'\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_upgrade_prune",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise upgrade` correctly uninstalls old versions when lockfile is enabled\n# This is a regression test for https://github.com/jdx/mise/discussions/7991\n# The bug: When upgrading with lockfile enabled, old versions were incorrectly kept\n# because the tracked config check was using the old locked version instead of\n# resolving to the newest installed version.\n\nexport MISE_LOCKFILE=1\n\n# Clean up any existing installations\nmise uninstall dummy --all 2>/dev/null || true\nrm -f mise.toml mise.lock\n\n# Create config with a prefix version that matches multiple versions\ncat <<'EOF' >mise.toml\n[tools]\ndummy = \"1\"\nEOF\n\n# Create a lockfile with the old version locked\ntouch mise.lock\n\n# Install only the older version first\nmise install dummy@1.0.0\n\n# Verify old version is installed\nassert_contains \"mise ls --installed dummy\" \"1.0.0\"\nassert_not_contains \"mise ls --installed dummy\" \"1.1.0\"\n\n# The lockfile should now have 1.0.0 locked\nassert_contains \"cat mise.lock\" \"1.0.0\"\n\n# Now upgrade - this should:\n# 1. Install 1.1.0 (the latest matching version)\n# 2. Uninstall 1.0.0 (no longer needed)\nmise upgrade dummy\n\n# Verify NEW version is installed\nassert_contains \"mise ls --installed dummy\" \"1.1.0\"\n\n# Verify OLD version was uninstalled (this is the bug - it was being kept)\nassert_not_contains \"mise ls --installed dummy\" \"1.0.0\"\n\n# The lockfile should now have 1.1.0\nassert_contains \"cat mise.lock\" \"1.1.0\"\n\n# Clean up\nrm -f mise.toml mise.lock\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_urls",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\n# Expected URL for ripgrep based on platform\ncase \"$MISE_PLATFORM\" in\nmacos-arm64)\n\tURL=\"https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-aarch64-apple-darwin.tar.gz\"\n\t;;\nmacos-x64)\n\tURL=\"https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-apple-darwin.tar.gz\"\n\t;;\nlinux-arm64)\n\tURL=\"https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-aarch64-unknown-linux-musl.tar.gz\"\n\t;;\nlinux-x64)\n\tURL=\"https://github.com/BurntSushi/ripgrep/releases/download/14.1.1/ripgrep-14.1.1-x86_64-unknown-linux-musl.tar.gz\"\n\t;;\n*)\n\tURL=\"\"\n\t;;\nesac\n\n# Test that aqua backend stores URLs in lockfile\nrm -rf mise.lock\n\ntouch mise.lock\n\nmise use ripgrep@14.1.1\n\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM\\\"\"\nassert_contains \"cat mise.lock\" \"url = \\\"$URL\\\"\"\n\necho \"Lockfile content:\"\ncat mise.lock\n\necho \"\"\necho \"Aqua URL storage test passed!\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_use",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ntouch mise.lock\nassert \"mise install tiny@1.0.0\"\nassert \"mise use tiny@1\"\nassert \"mise install tiny@1.0.1\"\nassert \"mise config get -f mise.toml tools.tiny\" \"1\"\nassert \"mise where tiny\" \"$MISE_DATA_DIR/installs/tiny/1.0.0\"\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"1\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"1.0.0\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.tiny]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\n\nassert \"mise use tiny@1\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.tiny]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"1\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"1.0.0\"\n\nassert \"mise up tiny\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.tiny]]\nversion = \\\"1.1.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"1\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"1.1.0\"\n\nassert \"mise up tiny --bump\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.tiny]]\nversion = \\\"3.1.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"3\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"3.1.0\"\n\ncat <<EOF >mise.lock\n[[tools.tiny]]\nversion = \"1.0.0\"\nbackend = \"asdf:tiny\"\nEOF\nassert \"mise use tiny@1 tiny@2\"\nassert \"cat mise.lock\" \"$LOCKFILE_HEADER\n\n[[tools.tiny]]\nversion = \\\"1.0.0\\\"\nbackend = \\\"asdf:tiny\\\"\n\n[[tools.tiny]]\nversion = \\\"2.1.0\\\"\nbackend = \\\"asdf:tiny\\\"\"\nassert \"mise uninstall --all tiny\"\nassert \"mise install tiny\"\nassert \"mise ls tiny --json --current | jq -r '.[0].requested_version'\" \"1\"\nassert \"mise ls tiny --json --current | jq -r '.[0].version'\" \"1.0.0\"\nassert \"mise ls tiny --json --current | jq -r '.[1].requested_version'\" \"2\"\nassert \"mise ls tiny --json --current | jq -r '.[1].version'\" \"2.1.0\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_v_prefix",
    "content": "#!/usr/bin/env bash\n\n# Test that lockfile matching works when mise.toml uses \"v\" prefix but lockfile doesn't\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\n# --- Test: \"v\" prefix in mise.toml matches lockfile without \"v\" prefix ---\ncat <<'EOF' >mise.toml\n[tools]\njq = \"v1.7.1\"\nEOF\n\ncat <<EOF >mise.lock\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"aqua:jqlang/jq\"\n\"platforms.$PLATFORM\" = { url = \"https://example.com/jq-1.7.1.tar.gz\" }\nEOF\n\n# --locked --dry-run should succeed (version should match despite \"v\" prefix)\nassert_contains \"mise install --locked --dry-run 2>&1\" \"would install\"\n"
  },
  {
    "path": "e2e/lockfile/test_lockfile_vfox_provenance_slow",
    "content": "#!/usr/bin/env bash\n\nexport MISE_LOCKFILE=1\n\ndetect_platform\nPLATFORM=\"$MISE_PLATFORM\"\n\necho \"=== Testing mise lock writes URL for vfox tool ===\"\ncat <<EOF >mise.toml\n[tools]\n\"vfox:version-fox/vfox-cmake\" = \"3.30.2\"\nEOF\n\n# Generate lockfile - should include a URL from the vfox plugin\nmise lock --platform \"$PLATFORM\"\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"url =\"\n\necho \"=== Testing vfox provenance downgrade attack detection ===\"\nrm -f mise.lock\n\n# Regenerate a clean lockfile\nmise lock --platform \"$PLATFORM\"\nassert \"test -f mise.lock\"\nassert_contains \"cat mise.lock\" \"\\\"platforms.$PLATFORM\\\"\"\n\n# Inject provenance into the lockfile (simulating a previously-verified install).\n# NOTE: This awk matches every platform section header. It works here because\n# the fixture has a single tool. For multi-tool lockfiles, add the tool name\n# to the match (e.g. index($0, \"vfox:version-fox/vfox-cmake\") && ...).\nawk -v platform=\"$PLATFORM\" '\n    { print }\n    index($0, \"platforms.\" platform) > 0 { print \"provenance = \\\"github-attestations\\\"\" }\n' mise.lock >mise.lock.tmp && mv mise.lock.tmp mise.lock\nassert_contains \"cat mise.lock\" 'provenance = \"github-attestations\"'\n\n# Attempt install — the lockfile says provenance was verified, but the vfox\n# plugin does not actually perform attestation verification, so mise should\n# refuse to install (downgrade/stripping attack).\n# NOTE: The downgrade check fires after the download, so a network failure here\n# would produce a download error rather than \"downgrade attack\". This is an\n# inherent limitation of testing against a real tool; a local fixture mock\n# would be needed to make this assertion network-independent.\n# Remove any previously installed version to ensure mise install must re-download,\n# so the downgrade check is reached during this run.\nrm -rf \"$MISE_DATA_DIR/installs/vfox-version-fox-vfox-cmake\"\nassert_fail_contains \"mise install 2>&1\" \"downgrade attack\"\n\necho \"=== Cleanup ===\"\nrm -f mise.lock mise.toml\n\necho \"mise vfox lockfile provenance tests passed!\"\n"
  },
  {
    "path": "e2e/plugins/test_backend_plugin_install",
    "content": "#!/usr/bin/env bash\n\ncat >mise.toml <<EOF\n[tools]\n\"myplugin:eslint\" = \"9.38.0\"\n\"myplugin:prettier\" = \"3.6.2\"\n\n[plugins]\n\"vfox-backend:myplugin\" = \"https://github.com/jdx/vfox-npm\"\nEOF\n\nmise install\nassert_contains \"mise plugin ls\" \"myplugin\"\nassert \"mise current myplugin:eslint\" \"9.38.0\"\nassert \"mise current myplugin:prettier\" \"3.6.2\"\n"
  },
  {
    "path": "e2e/plugins/test_core_overloading",
    "content": "#!/usr/bin/env bash\n\nmise plugin i -f node https://github.com/mise-plugins/mise-tiny\nmise i node@latest\nassert \"mise x node@latest -- rtx-tiny\" \"rtx-tiny: v3.1.0 args:\"\n"
  },
  {
    "path": "e2e/plugins/test_env_plugin_shadow_warning",
    "content": "#!/usr/bin/env bash\n\n# Test: env-only vfox plugin shadowing a registry entry emits a warning at install time\n\n# Create a git repo that looks like a vfox env plugin\nrepo_dir=\"$TMPDIR/vfox-jq-env\"\nmkdir -p \"$repo_dir/hooks\"\ncat >\"$repo_dir/metadata.lua\" <<'SCRIPT'\nPLUGIN = {}\nPLUGIN.name = \"jq\"\nPLUGIN.version = \"0.0.1\"\nPLUGIN.description = \"test env plugin\"\nSCRIPT\ncat >\"$repo_dir/hooks/mise_env.lua\" <<'SCRIPT'\nfunction PLUGIN:MiseEnv(ctx)\n    return {\n        { key = \"JQ_TEST\", value = \"1\" }\n    }\nend\nSCRIPT\ngit -C \"$repo_dir\" init -q\ngit -C \"$repo_dir\" add .\ngit -C \"$repo_dir\" commit -q -m \"init\"\n\n# Install the env plugin with name \"jq\" (which exists in the registry)\nassert_contains \"mise plugin install jq file://$repo_dir 2>&1\" \"shadowing\"\n"
  },
  {
    "path": "e2e/plugins/test_install",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >.mise.toml\n[plugins]\ntiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\"\nEOF\n\n# installs with repo in .mise.toml\nassert_contains \"mise x tiny-ref@v3.1.0 -- rtx-tiny\" \"v3.1.0\"\n"
  },
  {
    "path": "e2e/plugins/test_plugin_install",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >.tool-versions\ntiny latest\nshfmt latest\nasdf:mise-plugins/mise-zprint latest\nEOF\n\n# install/uninstall multiple\nmise plugin install tiny shfmt zprint\nassert_contains \"mise plugin ls\" \"tiny\"\nassert_contains \"mise plugin ls\" \"shfmt\"\nassert_contains \"mise plugin ls\" \"zprint\"\n\nrm -rf \"$MISE_DATA_DIR/plugins/tiny\"\nmise plugin install https://github.com/mise-plugins/rtx-tiny.git\nassert_contains \"mise plugin ls\" \"tiny\"\nmise plugin install -f tiny\nassert_contains \"mise plugin ls\" \"tiny\"\n\nrm -rf \"$MISE_DATA_DIR/plugins/tiny\"\nmise plugin install tiny https://github.com/mise-plugins/rtx-tiny\nassert_contains \"mise plugin ls\" \"tiny\"\n\nrm -rf \"$MISE_DATA_DIR/plugins/tiny\"\nmise plugin install tiny https://github.com/mise-plugins/mise-tiny/archive/refs/heads/main.zip\nassert_contains \"mise plugin ls\" \"tiny\"\n\nrm -rf \"$MISE_DATA_DIR/plugins/vfox-cmake\"\nmise plugin install vfox-cmake https://github.com/mise-plugins/vfox-cmake/archive/refs/heads/main.zip\nassert_contains \"mise plugin ls\" \"vfox-cmake\"\n\nrm -rf \"$MISE_DATA_DIR/plugins/zprint\"\nmise plugin install --all\nassert_contains \"mise plugin ls\" \"zprint\"\n\nmise plugin uninstall tiny\nassert_not_contains \"mise plugin ls\" \"tiny\"\nmise plugin uninstall tiny\n\nmise plugin update\nmise plugin update shfmt\nmise i\n\nassert_contains \"mise plugin install mise-x 2>&1 || true\" \"No repository found for plugin mise-x\"\nassert_contains \"mise plugin add node 2>&1 || true\" \"node is a core plugin and does not need to be installed\"\n"
  },
  {
    "path": "e2e/plugins/test_plugin_link",
    "content": "#!/usr/bin/env bash\n\nassert \"mise plugin link -f tiny-link $MISE_DATA_DIR/plugins/dummy\" \"\"\nassert \"mise plugin ls\" \"dummy\ntiny-link\"\nassert \"mise plugin uninstall tiny-link\" \"\"\nassert \"mise plugin ls\" \"dummy\"\n"
  },
  {
    "path": "e2e/plugins/test_plugin_update",
    "content": "#!/usr/bin/env bash\n\nmise plugin install tiny https://github.com/mise-plugins/rtx-tiny.git\nmise plugins update tiny\n"
  },
  {
    "path": "e2e/plugins/test_plugins_outdated",
    "content": "#!/usr/bin/env bash\n\nmise plugin install tiny https://github.com/mise-plugins/rtx-tiny.git\n\n# freshly installed plugin should not appear as outdated\nassert_not_contains \"mise plugins ls --outdated\" \"tiny\"\n\n# verify --outdated flag works without error\nassert_succeed \"mise plugins ls --outdated\"\n\n# verify -o short flag works\nassert_succeed \"mise plugins ls -o\"\n\n# simulate outdated plugin by resetting to previous commit\n(cd \"$MISE_DATA_DIR/plugins/tiny\" && git reset --hard HEAD~1)\nassert_contains \"mise plugins ls --outdated\" \"tiny\"\n"
  },
  {
    "path": "e2e/plugins/test_plugins_section_auto_install",
    "content": "#!/usr/bin/env bash\n\n# Test that plugins in [plugins] section are auto-installed during mise install\n# even when there are no corresponding tools in [tools]\n\n# Use mise-env-fnox - an env-only plugin with no corresponding tool\nrm -rf \"$MISE_DATA_DIR/plugins/fnox-env\"\nmise plugin uninstall fnox-env 2>/dev/null || true\n\n# Create a config with only a plugin (no tools using it)\ncat <<EOF >mise.toml\n[plugins]\nfnox-env = \"https://github.com/jdx/mise-env-fnox\"\nEOF\n\n# Run mise install - plugin should be auto-installed even with no tools\nmise install\n\n# Verify plugin was actually installed (has git refs, not just registered)\n# Using --refs shows URL and git info only for installed plugins\nassert_contains \"mise plugin ls --refs\" \"fnox-env\"\nassert_contains \"mise plugin ls --refs\" \"https://github.com/jdx/mise-env-fnox\"\n\n# Now test with both a plugin-only entry and a tool\nrm -rf \"$MISE_DATA_DIR/plugins/fnox-env\"\nrm -rf \"$MISE_DATA_DIR/plugins/zprint\"\nmise plugin uninstall fnox-env 2>/dev/null || true\nmise plugin uninstall zprint 2>/dev/null || true\n\ncat <<EOF >mise.toml\n[plugins]\nfnox-env = \"https://github.com/jdx/mise-env-fnox\"\nzprint = \"https://github.com/mise-plugins/mise-zprint\"\n\n[tools]\nzprint = \"latest\"\nEOF\n\n# Run mise install - both plugins should be installed, zprint tool should be installed\nmise install\n\n# Verify both plugins were actually installed (have git refs)\n# The URL only appears in --refs output when the plugin is actually installed\nassert_contains \"mise plugin ls --refs\" \"https://github.com/jdx/mise-env-fnox\"\nassert_contains \"mise plugin ls --refs\" \"https://github.com/mise-plugins/mise-zprint\"\n\n# Verify zprint tool was installed\nassert_contains \"mise ls --installed zprint\" \"zprint\"\n"
  },
  {
    "path": "e2e/plugins/test_poetry_system_python_slow",
    "content": "#!/usr/bin/env bash\n\n# arrange\nexport POETRY_HOME=\"$HOME/.poetry\"\npython_version=\"$(python3 --version)\"\n\ncat >pyproject.toml <<EOF\n[tool.poetry]\nname = \"poetry-test\"\nversion = \"0.1.0\"\ndescription = \"\"\nauthors = [\"mise\"]\npackages = [{include = \"poetry_demo\"}]\n\n[tool.poetry.dependencies]\npython = \"3.*\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\nEOF\n\nmkdir poetry_demo\ntouch poetry_demo/__init.py\n\n# assert\neval \"$(mise activate bash)\"\n\nmise use poetry@1.7.1\n_mise_hook\n\n# assert\nassert \"poetry --version\" \"Poetry (version 1.7.1)\"\nassert_contains \"poetry run -- python3 -V\" \"$python_version\"\n"
  },
  {
    "path": "e2e/plugins/test_purge",
    "content": "#!/usr/bin/env bash\n\necho \"tiny 3.1.0\" >.tool-versions\n\nmise install tiny\nassert_contains \"mise ls --installed\" \"tiny\"\n\nmise plugin uninstall tiny\nassert_contains \"mise ls --installed\" \"tiny\"\n\nmise plugin install tiny\nassert_contains \"mise ls --installed\" \"tiny\"\n\nmise plugin uninstall tiny --purge\nassert_not_contains \"mise ls --installed\" \"tiny\"\n"
  },
  {
    "path": "e2e/plugins/test_tiny",
    "content": "#!/usr/bin/env bash\n\ncat >mise.toml <<EOF\n[tools]\ntiny = {version = \"latest\", postinstall = \"echo 'postinstall'\"}\n[plugins]\ntiny-ref = \"https://github.com/mise-plugins/rtx-tiny#c532b140abd4ca00d3e76651b9bd32a980bd483c\"\nEOF\n\nmise plugin install tiny\n\nmise ls\n\n# this will fail when calling bin/list-all, but it won't stop it from executing\nMISE_TINY_LIST_ALL_FAIL=1 MISE_TINY_VERSION=latest mise env >/dev/null\n\n# check bin/list-legacy-files\nassert \"mise current tiny\" \"3.1.0\"\nmise local --remove tiny\n\n# Enable idiomatic version files for tiny\nmise settings set idiomatic_version_file_enable_tools tiny\n\necho \"2.0\" >.tiny-version\nassert \"mise current tiny\" \"2.0.1\"\nrm .tiny-version\nmise local tiny@latest\nassert \"mise current tiny\" \"3.1.0\"\n\n# test outdated/upgrade\nmise settings experimental=true\nrm -rf \"$MISE_DATA_DIR/installs/tiny\"\nmise use tiny@3\nmv \"$MISE_DATA_DIR/installs/tiny/\"{3.1.0,3.0.0}\nassert \"mise current tiny\" \"3.0.0\"\nassert \"mise outdated tiny\" \"tiny  3  3.0.0  3.1.0 ~/workdir/mise.toml\"\nmise upgrade tiny\nassert \"mise current tiny\" \"3.1.0\"\nassert \"mise outdated tiny\" \"\"\n"
  },
  {
    "path": "e2e/plugins/test_tiny_shim",
    "content": "#!/usr/bin/env bash\n\nmise use tiny@latest\n\n# The shim should output the passed arguments in the correct order\nassert \"$HOME/.local/share/mise/shims/rtx-tiny --no-config --env foo --jobs 2 --raw --yes extra-arg\" \"rtx-tiny: v3.1.0 args: --no-config --env foo --jobs 2 --raw --yes extra-arg\"\n"
  },
  {
    "path": "e2e/plugins/test_version_range",
    "content": "#!/usr/bin/env bash\n\nassert_fail \"mise current tiny\"\n\nmise i tiny\n\nmise local tiny@sub-1:latest\nassert \"mise current tiny\" \"2.1.0\"\n\nmise local tiny@sub-1:lts\nassert \"mise current tiny\" \"2.1.0\"\n\nmise local tiny@sub-0.1:3.1\nassert \"mise current tiny\" \"3.0.1\"\n\nmise local tiny@sub-0.0.1:3.0.0\nassert \"mise current tiny\" \"2.1.0\"\n"
  },
  {
    "path": "e2e/registry/test_overrides",
    "content": "#!/usr/bin/env bash\n\n# Test 1: node defined before npm\ncat >mise.toml <<EOF\n[tools]\nnode = \"25.2.1\"\nnpm = \"11.7.0\"\nEOF\n\nmise install\nassert_contains \"mise x -- npm --version\" \"11.7.0\"\n\n# Test 2: npm defined before node\ncat >mise.toml <<EOF\n[tools]\nnpm = \"11.7.0\"\nnode = \"25.2.1\"\nEOF\n\nmise install\nassert_contains \"mise x -- npm --version\" \"11.7.0\"\n"
  },
  {
    "path": "e2e/registry/test_overrides_shims",
    "content": "#!/usr/bin/env bash\n\n# Test 1: node defined before npm — shim should use explicit npm\ncat >mise.toml <<EOF\n[tools]\nnode = \"20.10.0\"\nnpm = \"10.9.0\"\nEOF\n\nmise install\nmise reshim\nassert_contains \"$MISE_DATA_DIR/shims/npm --version\" \"10.9.0\"\n\n# Test 2: npm defined before node — shim should still use explicit npm\ncat >mise.toml <<EOF\n[tools]\nnpm = \"10.9.0\"\nnode = \"20.10.0\"\nEOF\n\nmise install\nmise reshim\nassert_contains \"$MISE_DATA_DIR/shims/npm --version\" \"10.9.0\"\n"
  },
  {
    "path": "e2e/run_all_tests",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" &>/dev/null && pwd)\"\nROOT=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\n\n# shellcheck source-path=SCRIPTDIR\nsource \"$SCRIPT_DIR/style.sh\"\n\nresolve_mise_bin() {\n\tif [[ -n ${MISE_E2E_BIN:-} ]]; then\n\t\tprintf '%s\\n' \"$MISE_E2E_BIN\"\n\t\treturn\n\tfi\n\tlocal candidate=\"${CARGO_TARGET_DIR:-$ROOT/target}/debug/mise\"\n\tif [[ -x $candidate ]]; then\n\t\tprintf '%s\\n' \"$candidate\"\n\t\treturn\n\tfi\n\tlocal mise_path\n\tif ! mise_path=\"$(command -v mise 2>/dev/null)\"; then\n\t\terr \"Could not find 'mise' in PATH and no local debug build was found. Set MISE_E2E_BIN or build/install mise.\"\n\t\treturn 1\n\tfi\n\tprintf '%s\\n' \"$mise_path\"\n}\n\nmise_wait_for_gh_rate_limit() {\n\tlocal mise_bin=\"$1\"\n\t# Allow explicit opt-out for local/dev runs.\n\tif [[ ${E2E_WAIT_FOR_GH_RATE_LIMIT:-1} != 1 ]]; then\n\t\treturn 0\n\tfi\n\tif \"$mise_bin\" which wait-for-gh-rate-limit >/dev/null 2>&1; then\n\t\t\"$mise_bin\" x -- wait-for-gh-rate-limit\n\telse\n\t\twarn \"wait-for-gh-rate-limit not available; skipping rate-limit wait\"\n\tfi\n}\n\n# Check for .release-skip-e2e and skip all tests if version matches\nRELEASE_SKIP_FILE=\"$ROOT/.release-skip-e2e\"\nVERSION=\"$(. \"$ROOT/scripts/get-version.sh\" | tr -d '\\n')\"\nif [[ -f $RELEASE_SKIP_FILE ]]; then\n\tif grep -Fxq \"$VERSION\" \"$RELEASE_SKIP_FILE\"; then\n\t\techo \"[e2e] Skipping all e2e tests: .release-skip-e2e contains $VERSION\" >&2\n\t\texit 0\n\tfi\nfi\n\npushd e2e\n# List test files with a portable fallback chain.\nlist_test_files() {\n\tlocal pattern=\"$1\"\n\tif command -v fd >/dev/null 2>&1; then\n\t\tfd -tf -g \"$pattern\" | sort\n\telif command -v rg >/dev/null 2>&1; then\n\t\trg --files -g \"$pattern\" | sort\n\telse\n\t\tfind . -type f -name \"$pattern\" | sed 's#^\\./##' | sort\n\tfi\n}\n\n# Avoid mapfile that is not available on bash 3.2 for compatibility with macOS\nSLOW_FILES=()\nwhile IFS= read -r line; do\n\tSLOW_FILES+=(\"$line\")\ndone < <(list_test_files \"test_*_slow\")\nFAST_FILES=()\nwhile IFS= read -r line; do\n\tFAST_FILES+=(\"$line\")\ndone < <(list_test_files \"test_*\" | grep -v \"_slow$\")\npopd\nFILES=(\"${FAST_FILES[@]}\" \"${SLOW_FILES[@]}\")\nMISE_BIN=\"$(resolve_mise_bin)\"\ntest_count=0\nskipped_count=0\nstatus=0\n\nsummary \"Test\" \"Duration\" \"Result\"\nsummary \"---\" \"---\" \"---\"\n\nfor index in \"${!FILES[@]}\"; do\n\tTEST_NAME=\"${FILES[$index]}\"\n\n\t# split tests into tranches to reduce test time\n\tif [[ -n ${TEST_TRANCHE_COUNT:-} ]]; then\n\t\tif [[ $((index % TEST_TRANCHE_COUNT)) -ne $TEST_TRANCHE ]]; then\n\t\t\tcontinue\n\t\tfi\n\tfi\n\n\t# Skip slow tests unless TEST_ALL == 1\n\tif [[ ${TEST_ALL:-0} != 1 && $TEST_NAME == *_slow ]]; then\n\t\t#    title=\"E2E test $TEST_NAME skipped\" file=\"e2e/$TEST_NAME\" warn \"slow tests are disabled\"\n\t\tskipped_count=$((skipped_count + 1))\n\t\tsummary \"$TEST_NAME\" \"-\" \":zap:\"\n\t\tcontinue\n\tfi\n\n\tmise_wait_for_gh_rate_limit \"$MISE_BIN\"\n\t# Actually run the test\n\t\"$ROOT/e2e/run_test\" \"$TEST_NAME\" # fail fast for now\n\t# if ! \"$ROOT/e2e/run_test\" \"$TEST_NAME\"; then\n\t#   status=1\n\t# fi\n\ttest_count=$((test_count + 1))\ndone\n\necho \"E2E: ran $test_count tests, skipped $skipped_count tests\" >&2\n\nexit \"$status\"\n"
  },
  {
    "path": "e2e/run_test",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" &>/dev/null && pwd)\"\nROOT=\"$(cd \"$SCRIPT_DIR\"/.. && pwd)\"\n\n# shellcheck source-path=SCRIPTDIR\nsource \"$SCRIPT_DIR/style.sh\"\n\nTEST=\"$1\"\n# Handle both relative and absolute paths\nif [[ $TEST == /* ]]; then\n\t# If it's an absolute path, use it as is\n\tTEST_SCRIPT=\"$TEST\"\nelif [[ $TEST == e2e/* ]]; then\n\t# If it starts with e2e/, treat it as relative to the project root\n\tTEST_SCRIPT=\"$ROOT/$TEST\"\nelse\n\t# Otherwise, treat it as relative to the e2e directory\n\tTEST_SCRIPT=\"$SCRIPT_DIR/$TEST\"\nfi\n\nsetup_isolated_env() {\n\tTEST_ISOLATED_DIR=\"$(mktemp --tmpdir --directory \"$(basename \"$TEST\").XXXXXX\")\"\n\tif [[ $(os) == \"macos\" ]]; then\n\t\tTEST_ISOLATED_DIR=\"$(realpath \"$TEST_ISOLATED_DIR\")\"\n\tfi\n\n\t# Use a fake HOME and a fake temporary directory\n\tTEST_HOME=\"$TEST_ISOLATED_DIR/home\"\n\tTEST_WORKDIR=\"$TEST_HOME/workdir\"\n\tTEST_TMPDIR=\"$TEST_ISOLATED_DIR/tmp\"\n\n\t# Tell mise to look for its directory in the isolated environment\n\tMISE_SYSTEM_DIR=\"$TEST_ISOLATED_DIR/etc/mise\"\n\tMISE_DATA_DIR=\"$TEST_HOME/.local/share/mise\"\n\tMISE_CACHE_DIR=\"$TEST_HOME/.cache/mise\"\n\tMISE_CONFIG_DIR=\"$TEST_HOME/.config/mise\"\n\tMISE_STATE_DIR=\"$TEST_HOME/.local/state/mise\"\n\n\t# Set default values\n\t: \"${CARGO_HOME:=$HOME/.cargo}\"\n\t: \"${RUSTUP_HOME:=$HOME/.rustup}\"\n}\n\ncreate_isolated_env() {\n\t# Create the required directories\n\tmkdir -p \"$TEST_HOME/bin\" \"$TEST_WORKDIR\" \"$TEST_TMPDIR\" \"$MISE_SYSTEM_DIR\" \"$MISE_DATA_DIR\" \"$MISE_STATE_DIR\" \"$MISE_CACHE_DIR\" \"$MISE_CONFIG_DIR\"\n\n\t# The dummy plugin is required for some tests\n\tmkdir -p \"$MISE_DATA_DIR/plugins\"\n\tln -s \"$ROOT/test/data/plugins/dummy\" \"$MISE_DATA_DIR/plugins/dummy\"\n}\n\nremove_isolated_env() {\n\trm -rf \"$TEST_ISOLATED_DIR\" &\n}\n\nwithin_isolated_env() {\n\tlocal proxy_vars=()\n\t[[ -n ${http_proxy:-} ]] && proxy_vars+=(http_proxy=\"$http_proxy\")\n\t[[ -n ${https_proxy:-} ]] && proxy_vars+=(https_proxy=\"$https_proxy\")\n\t[[ -n ${HTTP_PROXY:-} ]] && proxy_vars+=(HTTP_PROXY=\"$HTTP_PROXY\")\n\t[[ -n ${HTTPS_PROXY:-} ]] && proxy_vars+=(HTTPS_PROXY=\"$HTTPS_PROXY\")\n\t[[ -n ${no_proxy:-} ]] && proxy_vars+=(no_proxy=\"$no_proxy\")\n\t[[ -n ${NO_PROXY:-} ]] && proxy_vars+=(NO_PROXY=\"$NO_PROXY\")\n\n\tenv \\\n\t\t-i \\\n\t\t-C \"$TEST_WORKDIR\" \\\n\t\t- \\\n\t\tCARGO_HOME=\"$CARGO_HOME\" \\\n\t\tCARGO_LLVM_COV=\"${CARGO_LLVM_COV:-}\" \\\n\t\tCARGO_LLVM_COV_SHOW_ENV=\"${CARGO_LLVM_COV_SHOW_ENV:-}\" \\\n\t\tCARGO_LLVM_COV_TARGET_DIR=\"${CARGO_LLVM_COV_TARGET_DIR:-}\" \\\n\t\tGIT_AUTHOR_NAME=\"test\" \\\n\t\tGIT_AUTHOR_EMAIL=\"test@test.com\" \\\n\t\tGIT_COMMITTER_NAME=\"test\" \\\n\t\tGIT_COMMITTER_EMAIL=\"test@test.com\" \\\n\t\tGITHUB_ACTION=\"${GITHUB_ACTION:-}\" \\\n\t\tGITHUB_TOKEN=\"${GITHUB_TOKEN:-}\" \\\n\t\tGOPROXY=\"${GOPROXY:-}\" \\\n\t\tHOME=\"$TEST_HOME\" \\\n\t\tLD_LIBRARY_PATH=\"${LD_LIBRARY_PATH:-}\" \\\n\t\tLLVM_PROFILE_FILE=\"${LLVM_PROFILE_FILE:-}\" \\\n\t\t${proxy_vars[@]+\"${proxy_vars[@]}\"} \\\n\t\tMISE_CACHE_DIR=\"$MISE_CACHE_DIR\" \\\n\t\tMISE_CACHE_PRUNE_AGE=\"0\" \\\n\t\tMISE_CONFIG_DIR=\"$MISE_CONFIG_DIR\" \\\n\t\tMISE_DATA_DIR=\"$MISE_DATA_DIR\" \\\n\t\tMISE_DEBUG=\"${MISE_DEBUG:-0}\" \\\n\t\tMISE_EXPERIMENTAL=1 \\\n\t\tMISE_GPG_VERIFY=\"${MISE_GPG_VERIFY:-}\" \\\n\t\tMISE_LOG_LEVEL=\"${MISE_LOG_LEVEL:-}\" \\\n\t\tMISE_STATE_DIR=\"$MISE_STATE_DIR\" \\\n\t\tMISE_SYSTEM_DIR=\"$MISE_SYSTEM_DIR\" \\\n\t\tMISE_TIMINGS=\"${MISE_TIMINGS:-0}\" \\\n\t\tMISE_TMP_DIR=\"$TEST_TMPDIR\" \\\n\t\tMISE_TRACE=\"${MISE_TRACE:-0}\" \\\n\t\tMISE_TRUSTED_CONFIG_PATHS=\"$TEST_ISOLATED_DIR\" \\\n\t\tMISE_USE_VERSIONS_HOST=\"${MISE_USE_VERSIONS_HOST:-1}\" \\\n\t\tMISE_USE_VERSIONS_HOST_TRACK=0 \\\n\t\tMISE_YES=1 \\\n\t\tPATH=\"${CARGO_TARGET_DIR:-$ROOT/target}/debug:$HOME/mise/bin:$CARGO_HOME/bin:$TEST_HOME/bin:$HOME/.local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:/usr/bin:/bin\" \\\n\t\tROOT=\"$ROOT\" \\\n\t\tRUSTUP_HOME=\"$RUSTUP_HOME\" \\\n\t\tRUST_BACKTRACE=\"${RUST_BACKTRACE:-1}\" \\\n\t\tSHELL=\"$(type -p bash)\" \\\n\t\tTEST_DIR=\"$(dirname \"$TEST_SCRIPT\")\" \\\n\t\tTEST_NAME=\"$TEST\" \\\n\t\tTEST_ROOT=\"$SCRIPT_DIR\" \\\n\t\tTEST_SCRIPT=\"$TEST_SCRIPT\" \\\n\t\tTMPDIR=\"$TEST_TMPDIR\" \\\n\t\tEXCLUDE_FROM_CI=\"${CI:-}\" \\\n\t\t\"$@\" || return $?\n}\n\nrun_test() {\n\t# Check for problematic /tmp/mise.toml that can interfere with tests\n\tif [[ -f /tmp/mise.toml ]]; then\n\t\terr \"/tmp/mise.toml exists and will interfere with e2e tests. Please remove it.\"\n\t\treturn 1\n\tfi\n\n\tsetup_isolated_env\n\tcreate_isolated_env\n\n\tlocal status=0\n\n\tSTART=\"$(date +%s)\"\n\t# Check shebang to determine which shell to use\n\tlocal shebang\n\tshebang=\"$(head -n 1 \"$TEST_SCRIPT\")\"\n\tif [[ $shebang == \"#!/usr/bin/env zsh\"* ]]; then\n\t\twithin_isolated_env zsh -f -euo pipefail -c \"source \\\"$SCRIPT_DIR/assert.sh\\\" && source \\\"$TEST_SCRIPT\\\"\" || status=$?\n\telif [[ $shebang == \"#!/usr/bin/env fish\"* ]]; then\n\t\twithin_isolated_env fish --no-config \"$TEST_SCRIPT\" || status=$?\n\telse\n\t\twithin_isolated_env bash --noprofile --norc -euo pipefail -c \"source \\\"$SCRIPT_DIR/assert.sh\\\" && source \\\"$TEST_SCRIPT\\\"\" || status=$?\n\tfi\n\tEND=\"$(date +%s)\"\n\tDURATION=$((END - START))s\n\n\techo \"$TEST: $DURATION\" >&2\n\n\t# Check if test took >20s and isn't marked as slow\n\tDURATION_NUM=\"${DURATION%s}\"\n\tif [[ $DURATION_NUM -gt 20 && ! $TEST =~ \"_slow\"$ ]]; then\n\t\twarn \"Test $TEST took ${DURATION} (>20s) but is not marked as slow. Consider renaming to ${TEST}_slow\"\n\t\tif [[ -n ${GITHUB_ACTIONS:-} ]]; then\n\t\t\techo \"::warning title=Slow test not marked::Test $TEST took ${DURATION} (>20s). Consider renaming to ${TEST}_slow to improve CI performance.\" >&2\n\t\tfi\n\tfi\n\n\tif [[ $status == 0 ]]; then\n\t\tremove_isolated_env\n\t\tsummary \"$TEST\" \"$DURATION\" \":white_check_mark:\"\n\telse\n\t\ttitle=\"E2E test $TEST failed\" err \"exited with status code $status\"\n\t\techo \"Test environment can be examined in $TEST_ISOLATED_DIR\" >&2\n\t\tsummary \"$TEST\" \"$DURATION\" \":x:\"\n\tfi\n\n\treturn \"$status\"\n}\n\nos() {\n\tcase \"$(uname -s)\" in\n\tDarwin) echo \"macos\" ;;\n\tLinux) echo \"linux\" ;;\n\t*) echo \"unknown\" ;;\n\tesac\n}\n\nas_group \"E2E $TEST\" run_test\n"
  },
  {
    "path": "e2e/secrets/test_age_secrets_non_strict",
    "content": "#!/usr/bin/env bash\nset -x\n\n# Test that with age.strict=false, mise continues when age key is not available\n\nmise u age\n\n# Generate an age key\nage=\"$(mise x -- age-keygen 2>&1)\"\nage_pub=\"$(echo \"$age\" | grep \"# public key:\" | awk '{print $4}')\"\nMISE_AGE_KEY=\"$(echo \"$age\" | grep \"AGE-SECRET-KEY\")\"\nexport MISE_AGE_KEY\n# Encrypt the secret and add it to mise.toml\nmise set --age-encrypt --age-recipient \"$age_pub\" SECRET=mysecret\n\n# Verify that mise env works when age key is set\nassert_contains \"mise env\" \"SECRET=mysecret\"\n\n# Set non-strict mode\nmise settings set age.strict false\n\n# Clear age key to simulate missing key\nexport MISE_AGE_KEY=\nrm -f ~/.config/mise/age.txt\n\n# The env should not contain the decrypted secret since key is missing\nassert_not_contains \"mise env\" \"export SECRET=mysecret\"\n\n# Test with strict=true (default behavior)\nmise settings set age.strict true\n\n# This should fail\nassert_fail \"mise env\"\n"
  },
  {
    "path": "e2e/secrets/test_secrets",
    "content": "#!/usr/bin/env bash\nset -x\n\nmise use sops age\nage=\"$(mise x -- age-keygen 2>&1)\"\nage_pub=\"$(echo \"$age\" | grep -E \"(Public key:|# public key:)\" | head -1 | awk '{print $(NF)}')\"\nMISE_SOPS_AGE_KEY=\"$(echo \"$age\" | grep \"AGE-SECRET-KEY\")\"\nexport MISE_SOPS_AGE_KEY\n\n# json\necho '{ \"SECRET\": \"mysecret\" }' >.env.json\nmise x -- sops encrypt -i --age \"$age_pub\" .env.json\nassert \"mise set _.file=.env.json\"\nassert_contains \"mise env\" \"export SECRET=mysecret\"\n\n# yaml\nunset MISE_SOPS_AGE_KEY\nmise unset _.file\nrm .env.json\nage_output=\"$(mise x -- age-keygen -o ~/age.txt 2>&1)\"\nage_pub=\"$(echo \"$age_output\" | grep -E \"(Public key:|# public key:)\" | head -1 | awk '{print $(NF)}')\"\nmise settings set sops.age_key_file \"~/age.txt\"\necho 'SECRET: mysecret' >.env.yaml\nmise x -- sops encrypt -i --age \"$age_pub\" .env.yaml\nexport MISE_SOPS_AGE_KEY=\nassert \"mise set _.file=.env.yaml\"\nassert_contains \"mise env\" \"export SECRET=mysecret\"\n\n# sops\nmise settings set sops.rops 0\nassert_contains \"mise env\" \"export SECRET=mysecret\"\n"
  },
  {
    "path": "e2e/secrets/test_secrets_non_strict",
    "content": "#!/usr/bin/env bash\nset -x\n\n# Test that with sops.strict=false, mise continues when age key is not available\n\nmise use sops age\n\n# Create an encrypted file but don't set age key\nage=\"$(mise x -- age-keygen 2>&1)\"\nage_pub=\"$(echo \"$age\" | grep \"# public key:\" | awk '{print $4}')\"\n\n# json test with strict=false\necho '{ \"SECRET\": \"mysecret\" }' >.env.json\nmise x -- sops encrypt -i --age \"$age_pub\" .env.json\n\n# Set non-strict mode\nmise settings set sops.strict false\n\n# Clear age key to simulate missing key\nexport MISE_SOPS_AGE_KEY=\nrm -f ~/.config/mise/age.txt\n\n# Should continue without failing and not include the secret\nassert \"mise set _.file=.env.json\"\n# The env should not contain the decrypted secret since key is missing\nassert_not_contains \"mise env\" \"export SECRET=mysecret\"\n\n# Test with strict=true (default behavior)\nmise settings set sops.strict true\n\n# This should fail\nassert_fail \"mise env\"\n\n# Test with yaml files too\n# Clean up previous encrypted files to avoid interference\nrm -f .env.json .env.yaml\n# Temporarily clear file config to avoid decryption issues\nmise settings unset _.file\nmise x -- age-keygen -o ~/age.txt\nage_pub=\"$(grep \"# public key:\" ~/age.txt | awk '{print $4}')\"\necho 'SECRET: mysecret' >.env.yaml\nmise x -- sops encrypt -i --age \"$age_pub\" .env.yaml\n\n# Remove the key file\nrm -f ~/age.txt\nexport MISE_SOPS_AGE_KEY=\n\n# Set non-strict mode\nmise settings set sops.strict false\n\n# Should work with non-strict mode\nassert \"mise set _.file=.env.yaml\"\nassert_not_contains \"mise env\" \"export SECRET=mysecret\"\n\n# Reset to strict mode and verify it fails\nmise settings set sops.strict true\nassert_fail \"mise env\"\n"
  },
  {
    "path": "e2e/shell/fish_script.fish",
    "content": "#!/usr/bin/env fish\n# shellcheck disable=SC1072,SC1065,SC1064,SC1073,SC2103\n\nset -l fish_trace 1\nmise install tiny@3.1.0 tiny@2.0.0\nor exit\n\necho >.mise.toml '\n[tools]\ntiny = \"3.1.0\"\n[env]\nFOO = \"bar\"\n'\n\nmkdir subdir\necho >subdir/.mise.toml '\n[tools]\ntiny = \"2.0.0\"\n[env]\nFOO = \"quz\"\n'\n\nmise activate --status fish | source\n__mise_env_eval\n\nrtx-tiny | grep \"v3.1.0\"\nor exit\n\ncd subdir && __mise_env_eval\nrtx-tiny | grep \"v2.0.0\"\nor exit\n\ncd .. && __mise_env_eval\nrtx-tiny | grep \"v3.1.0\"\nor exit\n\nmise shell tiny@3.0.0 && __mise_env_eval\nrtx-tiny | grep \"v3.0.0\"\nor exit\n\nmise deactivate\n"
  },
  {
    "path": "e2e/shell/fish_shims_reorder_script.fish",
    "content": "#!/usr/bin/env fish\n# Test that mise activate --shims reorders shims to front of PATH\n# even when shims are already present (e.g. VS Code re-sourcing config.fish)\n# See: https://github.com/jdx/mise/discussions/6072\n\n# Get the mise binary path from argv (passed by the wrapper)\nset -l mise_dir $argv[1]\n\n# Ensure shims directory exists (fish_add_path skips non-existent dirs)\nmkdir -p $HOME/.local/share/mise/shims\n\n# Clear any pre-existing __MISE_BIN so the debug binary uses current_exe()\nset -e __MISE_BIN\n\n# Simulate VS Code scenario: shims already in PATH but at low priority\n# (after /opt/homebrew/bin, like VS Code would arrange it)\nset -gx PATH $mise_dir /opt/homebrew/bin /usr/bin $HOME/.local/share/mise/shims /bin\n\n# Helper to find path indices\nfunction find_path_indices\n    set -l shims_idx 0\n    set -l brew_idx 0\n    for i in (seq (count $PATH))\n        if test \"$PATH[$i]\" = \"$HOME/.local/share/mise/shims\"\n            set shims_idx $i\n        end\n        if test \"$PATH[$i]\" = \"/opt/homebrew/bin\"\n            set brew_idx $i\n        end\n    end\n    echo $shims_idx $brew_idx\nend\n\n# Verify shims are initially after /opt/homebrew/bin\nset -l indices (find_path_indices)\nset -l shims_idx $indices[1]\nset -l brew_idx $indices[2]\n\nif test $shims_idx -le $brew_idx\n    echo \"FAIL: shims should start after homebrew for this test to be meaningful\"\n    echo \"PATH: $PATH\"\n    exit 1\nend\n\necho \"Before: shims at index $shims_idx, brew at index $brew_idx (shims after brew)\"\n\n# Now activate with --shims using the mise binary, simulating config.fish re-source\n$mise_dir/mise activate fish --shims | source\n\n# Check that shims are now before /opt/homebrew/bin\nset indices (find_path_indices)\nset shims_idx $indices[1]\nset brew_idx $indices[2]\n\nif test $shims_idx -eq 0\n    echo \"FAIL: shims not found in PATH after activate --shims\"\n    echo \"PATH: $PATH\"\n    exit 1\nend\n\nif test $shims_idx -ge $brew_idx\n    echo \"FAIL: shims (index $shims_idx) should be before homebrew (index $brew_idx) after activate --shims\"\n    echo \"PATH: $PATH\"\n    exit 1\nend\n\necho \"After: shims at index $shims_idx, brew at index $brew_idx (shims before brew)\"\necho \"SUCCESS: shims reordered to front of PATH\"\n"
  },
  {
    "path": "e2e/shell/test_bash",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\n\n# TODO: fix this in CI\n#orig_path=\"$PATH\"\n#\n#cat <<EOF >.mise.toml\n#[tools]\n#tiny = \"3.1.0\"\n#[env]\n#FOO = \"bar\"\n#EOF\n#\n#mkdir subdir\n#cat <<EOF >subdir/.mise.toml\n#[tools]\n#tiny = \"2.0.0\"\n#[env]\n#FOO = \"quz\"\n#EOF\n#\n#eval \"$(mise activate bash --status)\" && _mise_hook\n#\n#assert_path() {\n#  local actual=\"${PATH/%$orig_path/}\"\n#  actual=\"${actual%:}\"\n#  actual=\"${actual%:}\"\n#  actual=\"${actual//$MISE_DATA_DIR\\/installs/INSTALLS}\"\n#  actual=\"${actual//$HOME/HOME}\"\n#  assert \"echo $actual\" \"$1\"\n#}\n#\n#TINY_310=\"INSTALLS/tiny/3.1.0/bin\"\n#TINY_200=\"INSTALLS/tiny/2.0.0/bin\"\n#\n#mise ls\n#mise i && _mise_hook\n#\n#echo \"$PATH\"\n#\n#assert_contains \"rtx-tiny\" \"v3.1.0\"\n#assert 'echo $FOO' \"bar\"\n#assert_path \"$TINY_310\"\n#\n#cd subdir && mise i && _mise_hook\n#assert_contains \"rtx-tiny\" \"v2.0.0\"\n#assert 'echo $FOO' \"quz\"\n#assert_path \"$TINY_200\"\n#\n#cd .. && _mise_hook\n#assert_contains \"rtx-tiny\" \"v3.1.0\"\n#assert 'echo $FOO' \"bar\"\n#assert_path \"$TINY_310\"\n#\n#export PATH=\"PRE:$PATH\"\n#cd subdir && _mise_hook\n#assert_contains \"rtx-tiny\" \"v2.0.0\"\n#assert 'echo $FOO' \"quz\"\n#assert_path \"PRE:$TINY_200\"\n#\n#mise shell tiny@3.0.0 && _mise_hook\n#assert_contains \"rtx-tiny\" \"v3.0.0\"\n#\n#mise deactivate\n#assert_path \"PRE\"\n"
  },
  {
    "path": "e2e/shell/test_bash_legacy_activate",
    "content": "#!/usr/bin/env bash\n\necho \"tiny 3.1.0\" >.tool-versions\nmkdir subdir\necho \"tiny 2.0.0\" >subdir/.tool-versions\n\nmise install tiny@3.1.0 tiny@2.0.0\n\n# shellcheck disable=SC1090\neval \"$(mise activate -s bash --status)\"\n\n_mise_hook\nassert_contains \"rtx-tiny\" \"v3.1.0\"\n\ncd subdir && _mise_hook\nassert_contains \"rtx-tiny\" \"v2.0.0\"\n\ncd .. && _mise_hook\nassert_contains \"rtx-tiny\" \"v3.1.0\"\n"
  },
  {
    "path": "e2e/shell/test_fish",
    "content": "#!/usr/bin/env bash\nrequire_cmd fish\nexec fish \"$TEST_DIR/fish_script.fish\"\n"
  },
  {
    "path": "e2e/shell/test_fish_shims_path_reorder",
    "content": "#!/usr/bin/env bash\nrequire_cmd fish\n\n# Resolve the mise binary directory before entering fish (which has no bash PATH)\nmise_dir=$(dirname \"$(which mise)\")\n\nexec fish --no-config \"$TEST_DIR/fish_shims_reorder_script.fish\" \"$mise_dir\"\n"
  },
  {
    "path": "e2e/shell/test_nushell",
    "content": "#! /usr/bin/env sh\n\n# run this test with either:\n# - mise run e2e nushell\n# - LD_LIBRARY_PATH=/usr/lib:/home/linuxbrew/.linuxbrew/lib mise run e2e nushell\n\nset -eu\n\nif ! command -v nu >/dev/null 2>&1; then\n\t# for now, treat these tests as optional if `nu` is unavailable\n\texit 0\nfi\n\nMISE_NUSHELL_INIT=$(mktemp e2e_nushell_init.XXXXXXXXXX)\n\n# nushell's `source` is a parser keyword:\n# https://www.nushell.sh/commands/docs/source.html\n# this means the sourced mise init file must exist before we run `nu`\n\n# use `env` to control the environment variables available to `nu`\n# - we need LD_LIBRARY_PATH so that mise can find libbz2.so.1.0\n# - we need PATH so that this test can find `mise`\nenv --ignore-environment LD_LIBRARY_PATH=\"${LD_LIBRARY_PATH}\" PATH=\"${PATH}\" mise activate nu >\"${MISE_NUSHELL_INIT}\"\n\n# equivalent of try/catch so we always cleanup the temporary file,\n# even if the test fails\nset +e\n\n# use `env` to control the environment variables available to `nu`\n# - we need LD_LIBRARY_PATH so that mise can find libbz2.so.1.0\n# - we need PATH so that this test can find `nu`\nenv --ignore-environment LD_LIBRARY_PATH=\"${LD_LIBRARY_PATH}\" PATH=\"${PATH}\" nu --no-config-file --commands \"use ${MISE_NUSHELL_INIT}\"\nNUSHELL_EXIT_CODE=${?}\n\nset -e\nrm --force --verbose \"${MISE_NUSHELL_INIT}\"\n\nexit \"${NUSHELL_EXIT_CODE}\"\n"
  },
  {
    "path": "e2e/shell/test_nushell_deactivation",
    "content": "#! /usr/bin/env sh\n\n# run this test with either:\n# - mise run e2e nushell\n# - LD_LIBRARY_PATH=/usr/lib:/home/linuxbrew/.linuxbrew/lib mise run e2e nushell\n\nset -eu\n\nif ! command -v nu >/dev/null 2>&1; then\n\t# for now, treat these tests as optional if `nu` is unavailable\n\texit 0\nfi\n\nMISE_NUSHELL_INIT=$(mktemp e2e_nushell_init.XXXXXXXXXX)\n\n# nushell's `source` is a parser keyword:\n# https://www.nushell.sh/commands/docs/source.html\n# this means the sourced mise init file must exist before we run `nu`\n\n# use `env` to control the environment variables available to `nu`\n# - we need __MISE_DIFF to trigger the deactivation code path\n# - we need LD_LIBRARY_PATH so that mise can find libbz2.so.1.0\n# - we need PATH so that this test can find `mise`\nenv --ignore-environment __MISE_DIFF=1 LD_LIBRARY_PATH=\"${LD_LIBRARY_PATH}\" PATH=\"${PATH}\" mise activate nu >\"${MISE_NUSHELL_INIT}\"\n\n# equivalent of try/catch so we always cleanup the temporary file,\n# even if the test fails\nset +e\n\n# use `env` to control the environment variables available to `nu`\n# - we need LD_LIBRARY_PATH so that mise can find libbz2.so.1.0\n# - we need PATH so that this test can find `nu`\nenv --ignore-environment LD_LIBRARY_PATH=\"${LD_LIBRARY_PATH}\" PATH=\"${PATH}\" nu --no-config-file --commands \"use ${MISE_NUSHELL_INIT}\"\nNUSHELL_EXIT_CODE=${?}\n\nset -e\nrm --force --verbose \"${MISE_NUSHELL_INIT}\"\n\nexit \"${NUSHELL_EXIT_CODE}\"\n"
  },
  {
    "path": "e2e/shell/test_xonsh",
    "content": "#!/usr/bin/env bash\nexec mise x uv -- uv tool run --with 'xonsh[full]' xonsh --no-rc \"$TEST_DIR/xonsh_script\"\n"
  },
  {
    "path": "e2e/shell/test_zsh",
    "content": "#!/usr/bin/env bash\nrequire_cmd zsh\nexec zsh \"$TEST_DIR/zsh_script\"\n"
  },
  {
    "path": "e2e/shell/xonsh_script",
    "content": "$XONSH_SHOW_TRACEBACK = True\n\ntiny1 = \"\"\"\n[tools]\ntiny = \"1.0.0\"\n\"\"\"\necho @(tiny1) > .mise.toml\n\ntiny2 = \"\"\"\n[tools]\ntiny = \"2.0.0\"\n\"\"\"\nmkdir -p subdir\necho @(tiny2) > subdir/.mise.toml\n\nmise install tiny@1.0.0 tiny@2.0.0\n\n# shellcheck disable=SC1073,SC1065,SC1064,SC1072\nexecx($(mise activate -s xonsh))\n\n# check that mise was activated at all\nassert 'mise' in aliases\nassert list(events.on_pre_prompt)[0].__name__ == 'mise_hook'\nassert list(events.on_chdir)[0].__name__ == 'mise_hook'\n\n# check that correct tiny version is being used\nevents.on_pre_prompt.fire() # prompt doesn't render in non-interactive mode, so do this manually\nassert $(rtx-tiny).strip() == 'rtx-tiny: v1.0.0 args:'\n\n# check that on_chdir hook is firing\ncd subdir\nassert $(rtx-tiny).strip() == 'rtx-tiny: v2.0.0 args:'\ncd ..\nassert $(rtx-tiny).strip() == 'rtx-tiny: v1.0.0 args:'\n\n# check that mise is correctly deactivated\nmise deactivate\nassert 'mise' not in aliases\nassert len(list(events.on_pre_prompt)) == 0\nassert len(list(events.on_chdir)) == 0\n"
  },
  {
    "path": "e2e/shell/zsh_script",
    "content": "#!/usr/bin/env zsh\n# shellcheck disable=SC1071\nset -euo pipefail\norig_path=\"$PATH\"\n\ncat <<EOF >.mise.toml\n[tools]\nnode = \"20.0.0\"\nEOF\n\nmkdir 18\ncat <<EOF >18/.mise.toml\n[tools]\nnode = \"18.0.0\"\nEOF\n\nassert_path() {\n\tlocal expected=\"${1//$HOME/\\~}\"\n\tlocal actual=\"${PATH/%$orig_path/}\"\n\tactual=\"${actual//$HOME/\\~}\"\n\tactual=\"${actual/%:/}\"\n\tif [[ $actual != \"$expected\" ]]; then\n\t\techo \"Invalid PATH:  $actual\"\n\t\techo \"Expected PATH: $expected\"\n\t\texit 1\n\tfi\n}\n\nmise install node@20.0.0 node@18.0.0\n# shellcheck disable=SC1090\neval \"$(mise activate zsh --status)\" && _mise_hook\n\n#mise install\ntest \"$(node -v)\" = \"v20.0.0\"\n\ncd 18 && _mise_hook\n#mise install\ntest \"$(node -v)\" = \"v18.0.0\"\n\ncd .. && _mise_hook\ntest \"$(node -v)\" = \"v20.0.0\"\n\nmise shell node@18.0.0 && _mise_hook\ntest \"$(node -v)\" = \"v18.0.0\"\n\nmise deactivate\nassert_path \"\"\n"
  },
  {
    "path": "e2e/style.sh",
    "content": "#!/usr/bin/env bash\n\nif [[ -n ${GITHUB_ACTION:-} ]]; then\n\t# Output GitHub action annotations\n\tannotate() {\n\t\tlocal parameters=\"\"\n\t\t[[ -n ${file:=${TEST_SCRIPT:-}} ]] && parameters=\"file=${file}\"\n\t\t[[ -n ${title:-} ]] && parameters=\"${parameters:+,}title=${title}\"\n\t\techo \"::${type:-debug}${parameters:+ ${parameters}}::$*\" >&2\n\t}\n\terr() { type=error annotate \"$*\"; }\n\twarn() { type=warning annotate \"$*\"; }\n\tnotice() { type=notice annotate \"$*\"; }\n\t# debug() { type=debug annotate \"$*\"; }\n\tdebug() { echo $'\\e[90m'\"$*\"$'\\e[0m' >&2; }\n\tstart_group() { echo \"::group::$*\" >&2; }\n\tend_group() { echo ::endgroup:: >&2; }\n\n\t# Yet use ANSI green color for the \"ok\" message\n\tok() { echo $'\\e[92m'\"$*\"$'\\e[0m' >&2; }\n\nelif [[ -t 2 ]]; then\n\t# Use ANSI coloring in terminal\n\tok() { echo $'\\e[92m'\"$*\"$'\\e[0m' >&2; }\n\terr() { echo $'\\e[91m'\"${title:+$title: }$*\"$'\\e[0m' >&2; }\n\twarn() { echo $'\\e[93m'\"${title:+$title: }$*\"$'\\e[0m' >&2; }\n\tnotice() { echo $'\\e[94m'\"$*\"$'\\e[0m' >&2; }\n\tdebug() { echo $'\\e[90m'\"$*\"$'\\e[0m' >&2; }\n\tstart_group() { echo $'\\e[1m'\">>> $*\"$'\\e[0m' >&2; }\n\tend_group() { echo >&2; }\n\nelse\n\t# No styling\n\tok() { echo \"SUCCESS: $*\" >&2; }\n\terr() { echo \"ERROR: ${title:+$title: }$*\" >&2; }\n\twarn() { echo \"WARNING: ${title:+$title: }$*\" >&2; }\n\tnotice() { echo \"NOTICE: $*\" >&2; }\n\tdebug() { echo \"DEBUG: $*\" >&2; }\n\tstart_group() { echo \">>> $*\" >&2; }\n\tend_group() { echo >&2; }\nfi\n\nif [[ -n ${GITHUB_STEP_SUMMARY:-} ]]; then\n\tsummary() { echo \"| $1 | $2 | $3 |\" >>\"$GITHUB_STEP_SUMMARY\"; }\nelse\n\tsummary() { true; }\nfi\n\nas_group() {\n\tlocal status=0\n\tstart_group \"$1\"\n\tshift\n\t\"$*\" || status=$?\n\tend_group\n\treturn \"$status\"\n}\n"
  },
  {
    "path": "e2e/sync/test_sync_nvm",
    "content": "#!/usr/bin/env bash\n\nexport NVM_DIR=\"$PWD/.nvm\"\n\ninstall_fake_node() {\n\tmkdir -p \"$1/bin\"\n\techo \"#!/usr/bin/env echo\" >\"$1/bin/node\"\n\tchmod +x \"$1/bin/node\"\n}\n\ninstall_fake_node \"$NVM_DIR/versions/node/v18.0.0\"\nmise sync node --nvm\nmise ls\nassert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/18.0.0\"\n\ninstall_fake_node \"$NVM_DIR/versions/node/v20.0.0\"\ninstall_fake_node \"$NVM_DIR/versions/node/v22.0.0\"\ninstall_fake_node \"$MISE_DATA_DIR/installs/node/20.0.0/bin\"\n\nmise sync node --nvm\nmise ls\nassert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/22.0.0\"\nassert_not_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/20.0.0\"\nassert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/18.0.0\"\n"
  },
  {
    "path": "e2e/sync/test_sync_nvm_slow",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC1091\n\nexport NVM_DIR=\"$PWD/.nvm\"\nmkdir -p \"$NVM_DIR\"\ncurl -L https://github.com/nvm-sh/nvm/archive/refs/tags/v0.40.0.tar.gz | tar -xz -C \"$NVM_DIR\" --strip-components=1\n. \"$NVM_DIR/nvm.sh\"\n\nnvm install 22.0.0\nmise sync node --nvm\nmise ls\nassert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/22.0.0\"\n\n# mise install node@20.0.0\n# nvm install 20.0.0\n# nvm install 18.0.0\n# mise sync node --nvm\n# mise ls\n# assert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/22.0.0\"\n# assert_not_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/20.0.0\"\n# assert_contains \"mise ls node --json | jq -r '.[] | .symlinked_to | select( . != null)'\" \"node/18.0.0\"\n"
  },
  {
    "path": "e2e/sync/test_sync_python_uv",
    "content": "#!/usr/bin/env bash\n\nassert \"mise use -g uv python@3.11.3\"\nassert \"mise x -- uv python install 3.11.1\"\nexport UV_PYTHON_DOWNLOADS=never\nassert \"mise sync python --uv\"\nassert \"mise x python@3.11.1 -- python -V\" \"Python 3.11.1\"\nassert \"mise x -- uv run -p 3.11.3 -- python -V\" \"Python 3.11.3\"\n"
  },
  {
    "path": "e2e/tasks/test_remote_task_with_tools",
    "content": "#!/usr/bin/env bash\n# Test that remote git tasks can access tools from mise.toml hierarchy\n# This reproduces issue #6557 where v2025.10.3 broke remote task tool resolution\n\nset -euo pipefail\n\necho \"=== Setting up test for remote task with tools ===\"\n\n# Create a parent directory with tool definition\nmkdir -p parent/child\ncd parent\n\n# Parent mise.toml with the tool\ncat >mise.toml <<'EOF'\n[tools]\nripgrep = \"latest\"\nEOF\n\n# Install the tool\nmise install\n\n# Verify tool is installed and accessible\nif ! mise where ripgrep >/dev/null 2>&1; then\n\techo \"ERROR: ripgrep not installed\"\n\texit 1\nfi\n\ncd child\n\n# Child mise.toml with remote task from mise repo (NO tools defined here)\n# This task uses ripgrep which should come from parent/mise.toml\ncat >mise.toml <<'EOF'\n[tasks.remote_lint]\nfile = \"git::https://github.com/jdx/mise.git//xtasks/lint/ripgrep?ref=main\"\nEOF\n\n# Trust and try to run the remote task\nmise trust\n\necho \"=== Running remote task that needs ripgrep from parent config ===\"\n\n# First, let's check what happens with a simple command task that uses rg\ncat >>mise.toml <<'EOF'\n\n[tasks.test_tool]\nrun = \"rg --version\"\nEOF\n\nmise trust\n\n# Run the simple local task to see if rg is available\necho \"Testing local task with rg:\"\nif mise run test_tool 2>&1 | tee /tmp/test_tool_output.txt | grep -q \"ripgrep\"; then\n\techo \"✓ Local task can find rg\"\nelse\n\techo \"✗ Local task cannot find rg\"\n\tcat /tmp/test_tool_output.txt\nfi\n\n# Now run the remote task\necho \"Testing remote task with rg:\"\nif mise run remote_lint 2>&1 | tee /tmp/remote_lint_output.txt | grep -E \"(command not found|rg: not found)\"; then\n\techo \"✗ FAIL: Remote task could not find ripgrep from parent config\"\n\techo \"Remote task output:\"\n\tcat /tmp/remote_lint_output.txt\n\texit 1\nelse\n\techo \"✓ PASS: Remote task successfully accessed ripgrep from parent config\"\n\techo \"Remote task ran successfully (may have linting errors but rg was found)\"\n\texit 0\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_add",
    "content": "#!/usr/bin/env bash\n\nmise tasks add pre-commit --depends \"test\" --depends \"render\" -- echo pre-commit\nassert \"cat mise.toml\" '[tasks.pre-commit]\ndepends = [\"test\", \"render\"]\nrun = \"echo pre-commit\"'\n\nmise tasks add --file pre-commit --depends \"test\" --depends \"render\" -- echo pre-commit\nassert \"cat mise-tasks/pre-commit\" '#!/usr/bin/env bash\n#MISE depends=[\"test\", \"render\"]\nset -euxo pipefail\n\necho pre-commit'\n"
  },
  {
    "path": "e2e/tasks/test_task_args_position",
    "content": "#!/usr/bin/env bash\n\n# Test that flags after task name go to task, not mise\n\ncat <<EOF >mise.toml\n[tasks.echo-args]\ndescription = \"Echo arguments passed to task\"\nrun = 'echo args:'\n\n[tasks.echo-with-usage]\ndescription = \"Task with usage args defined\"\nrun = 'echo \"got: {{arg(name=\"myarg\")}}\"'\nEOF\n\n# Test 1: Flags after task name should go to task\n# --jobs 4 appears after the task name, so it should be passed to the task\n# (args are appended to command string for tasks without formal args)\nassert \"mise run echo-args --jobs 4\" \"args: --jobs 4\"\n\n# Test 2: Flags before task name should be mise flags (not passed to task)\n# Here --dry-run is before task name, so it's a mise flag\n# Dry-run outputs to stderr, so we check that stdout is empty (task didn't run)\nassert \"mise run --dry-run echo-args\" \"\"\n\n# Test 3: Mixed flags - before goes to mise, after goes to task\nassert \"mise run echo-args --force\" \"args: --force\"\n\n# Test 4: Naked run - flags after task go to task\nassert \"mise echo-args --verbose\" \"args: --verbose\"\n\n# Test 5: Triple colon separator still works with flags after task\n# Note: Parallel execution means order may vary, so check each output is present\nassert_contains \"mise run echo-args arg1 ::: echo-args arg2\" \"args: arg1\"\nassert_contains \"mise run echo-args arg1 ::: echo-args arg2\" \"args: arg2\"\n\n# Test 6: Backward compat - explicit -- still works\nassert \"mise run echo-args -- --help\" \"args: --help\"\n\n# Test 7: --help on task WITHOUT usage defined should show task info\n# (task has no formal args, so mise shows help instead of executing)\nassert_contains \"mise run echo-args --help\" \"Task: echo-args\"\n\n# Test 8: --help on task WITH usage defined should show mise help\nassert_contains \"mise run echo-with-usage --help\" \"myarg\"\n"
  },
  {
    "path": "e2e/tasks/test_task_colon_matching",
    "content": "#!/usr/bin/env bash\n\n# Test that task names with colons are not incorrectly matched in non-monorepo context\n# Bug: `mise run build` was matching both `build` and `project:build` tasks\n\n# Create a regular mise.toml (NOT a monorepo)\ncat <<'EOF' >mise.toml\n[tasks.build]\nrun = 'echo \"build\"'\n\n[tasks.\"project:build\"]\nrun = 'echo \"project:build\"'\n\n[tasks.\"app:build\"]\nrun = 'echo \"app:build\"'\n\n[tasks.test]\nrun = 'echo \"test\"'\n\n[tasks.\"unit:test\"]\nrun = 'echo \"unit:test\"'\nEOF\n\n# Running 'mise run build' should ONLY run the 'build' task\n# It should NOT run 'project:build' or 'app:build'\nOUTPUT=$(mise run build)\n\n# Should run the build task\nassert_contains \"mise run build\" \"build\"\n\n# Should NOT run tasks with colons\nif echo \"$OUTPUT\" | grep -E \"project:build|app:build\"; then\n\techo \"ERROR: 'mise run build' incorrectly matched tasks with colons\"\n\techo \"Output:\"\n\techo \"$OUTPUT\"\n\texit 1\nfi\n\n# Similarly, 'mise run test' should only run 'test', not 'unit:test'\nOUTPUT2=$(mise run test)\n\nassert_contains \"mise run test\" \"test\"\n\nif echo \"$OUTPUT2\" | grep \"unit:test\"; then\n\techo \"ERROR: 'mise run test' incorrectly matched 'unit:test'\"\n\techo \"Output:\"\n\techo \"$OUTPUT2\"\n\texit 1\nfi\n\n# Also test with file-based tasks\nmkdir -p .mise/tasks\n\ncat <<'EOF' >.mise/tasks/deploy\n#!/usr/bin/env bash\necho \"deploy\"\nEOF\n\ncat <<'EOF' >.mise/tasks/prod:deploy\n#!/usr/bin/env bash\necho \"prod:deploy\"\nEOF\n\nchmod +x .mise/tasks/*\n\n# Running 'mise run deploy' should only run 'deploy', not 'prod:deploy'\nOUTPUT3=$(mise run deploy)\n\nassert_contains \"mise run deploy\" \"deploy\"\n\nif echo \"$OUTPUT3\" | grep \"prod:deploy\"; then\n\techo \"ERROR: 'mise run deploy' incorrectly matched 'prod:deploy'\"\n\techo \"Output:\"\n\techo \"$OUTPUT3\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_colon_syntax",
    "content": "#!/usr/bin/env bash\n\n# Test that :task syntax only works in monorepos\n\n# Test 1: Outside monorepo, :build should NOT work\ncat <<'EOF' >mise.toml\n[tasks.build]\nrun = 'echo \"build task\"'\n\n[tasks.\"project:build\"]\nrun = 'echo \"project:build task\"'\nEOF\n\n# Should fail with helpful error about monorepo setup\nassert_fail \"mise run ':build'\" \"require a monorepo root configuration\"\n\n# Test 2: In monorepo with experimental mode, :build SHOULD work\nexport MISE_EXPERIMENTAL=1\n\ncat <<'EOF' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"project\", \"app\"]\n\n[tasks.build]\nrun = 'echo \"root build task\"'\nEOF\n\nmkdir -p project\ncat <<'EOF' >project/mise.toml\n[tasks.build]\nrun = 'echo \"project build task\"'\nEOF\n\nmkdir -p app\ncat <<'EOF' >app/mise.toml\n[tasks.build]\nrun = 'echo \"app build task\"'\nEOF\n\n# Running ':build' from root should match root-level build task (not monorepo tasks)\nassert_contains \"mise run ':build'\" \"root build task\"\n\n# Should NOT run project:build or app:build from root\nOUTPUT_ROOT=$(mise run ':build')\nif echo \"$OUTPUT_ROOT\" | grep -E \"project build task|app build task\"; then\n\techo \"ERROR: 'mise run :build' from root incorrectly matched child tasks\"\n\texit 1\nfi\n\n# Running ':build' from project dir should only match //project:build\n(\n\tcd project\n\tassert_contains \"mise run ':build'\" \"project build task\"\n\n\t# Should NOT run app:build when we're in project directory\n\tOUTPUT=$(mise run ':build')\n\tif echo \"$OUTPUT\" | grep -q \"app build task\"; then\n\t\techo \"ERROR: 'mise run :build' from project dir incorrectly matched //app:build\"\n\t\texit 1\n\tfi\n)\n\n# Running ':build' from app dir should only match //app:build\n(\n\tcd app\n\tassert_contains \"mise run ':build'\" \"app build task\"\n\n\t# Should NOT run project:build when we're in app directory\n\tOUTPUT2=$(mise run ':build')\n\tif echo \"$OUTPUT2\" | grep -q \"project build task\"; then\n\t\techo \"ERROR: 'mise run :build' from app dir incorrectly matched //project:build\"\n\t\texit 1\n\tfi\n)\n\n# Test 3: Verify that 'mise run build' does NOT match monorepo tasks\nunset MISE_EXPERIMENTAL\n\ncat <<'EOF' >mise.toml\n[tasks.build]\nrun = 'echo \"root build\"'\n\n[tasks.\"project:build\"]\nrun = 'echo \"project build\"'\nEOF\n\n# Should only run 'build', not 'project:build'\nOUTPUT2=$(mise run build)\n\nassert_contains \"mise run build\" \"root build\"\n\nif echo \"$OUTPUT2\" | grep -q \"project build\"; then\n\techo \"ERROR: 'mise run build' incorrectly matched 'project:build'\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_completion",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tools]\n\"usage\" = { version = \"latest\", os = [\"linux\", \"macos\"] }\n\n[tasks.build]\nrun = 'echo build'\nEOF\n\nmise usage >./mise.usage.kdl\nassert \"mise exec -- usage complete-word --shell zsh -f ./mise.usage.kdl -- mise tasks run build -- -c ''\" \"'mise.toml'\n'mise.usage.kdl'\"\n"
  },
  {
    "path": "e2e/tasks/test_task_config_dir",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntask_config.dir = \"{{config_root}}/mywork\"\ntasks.a.run = \"pwd\"\nEOF\n\nmkdir -p mywork\nassert \"mise run a\" \"$(pwd)/mywork\"\n"
  },
  {
    "path": "e2e/tasks/test_task_default",
    "content": "#!/usr/bin/env bash\n\nassert \"mise tasks add --file foo:bar:baz -- echo baz\"\nassert \"mise tasks add --file foo:bar -- echo bar\"\nassert \"mise tasks add --file foo:_default.sh -- echo foo\"\nls -lR .\n\nassert \"mise tasks\" \"foo\nfoo:bar\nfoo:bar:baz\"\nassert \"mise tasks run foo:bar:baz\" \"baz\"\nassert \"mise tasks run foo:bar\" \"bar\"\n\nassert \"mise tasks run foo\" \"foo\"\n"
  },
  {
    "path": "e2e/tasks/test_task_delegation_dedup",
    "content": "#!/usr/bin/env bash\n\n# Regression test: task delegation via `run = [{ task }]` should not\n# re-run shared dependencies that already completed in the parent graph.\n\ncat <<'EOF' >mise.toml\n[tasks.setup]\nrun = \"echo '>>> SETUP RUNNING <<<'\"\n\n[tasks.lint]\nhide = true\ndepends = [\"setup\"]\nrun = \"echo 'lint done'\"\n\n[tasks.\"check:security\"]\nhide = true\ndepends = [\"setup\"]\nrun = \"echo 'security check done'\"\n\n[tasks.\"fix:security\"]\nhide = true\ndepends = [\"lint\"]\nrun = [{ task = \"check:security\" }]\n\n[tasks.all]\ndepends = [\"fix:security\"]\nEOF\n\n# \"setup\" output must appear exactly once (exclude the \"$ echo ...\" command line)\noutput=\"$(mise run -f all 2>&1)\"\ncount=\"$(echo \"$output\" | grep -v '^\\[setup\\] \\$' | grep -c '>>> SETUP RUNNING <<<')\"\nif [[ $count -ne 1 ]]; then\n\techo \"Expected setup to run exactly once, but it ran $count times\"\n\techo \"Full output:\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Verify all tasks actually ran\nassert_contains \"echo \\\"$output\\\"\" \"lint done\"\nassert_contains \"echo \\\"$output\\\"\" \"security check done\"\n\n# Standalone call should still trigger setup as a dependency\nassert_contains \"mise run -f check:security\" \">>> SETUP RUNNING <<<\"\nassert_contains \"mise run -f check:security\" \"security check done\"\n"
  },
  {
    "path": "e2e/tasks/test_task_dep_env",
    "content": "#!/usr/bin/env bash\n\n# Test passing env vars to task dependencies\n\n# Test shell-style env var syntax: \"FOO=bar mytask\"\ncat <<EOF >mise.toml\n[tasks.show-env]\nrun = 'echo \"FOO=\\$FOO BAZ=\\$BAZ\"'\n\n[tasks.with-env-string]\ndepends = [\"FOO=hello show-env\"]\nrun = 'echo done'\n\n[tasks.with-multiple-env]\ndepends = [\"FOO=hello BAZ=world show-env\"]\nrun = 'echo done'\nEOF\n\nassert_contains \"mise run with-env-string\" \"FOO=hello\"\nassert_contains \"mise run with-multiple-env\" \"FOO=hello BAZ=world\"\n\n# Test structured object syntax: { task = \"mytask\", env = { FOO = \"bar\" } }\ncat <<EOF >mise.toml\n[tasks.show-env]\nrun = 'echo \"FOO=\\$FOO BAZ=\\$BAZ\"'\n\n[tasks.with-env-object]\ndepends = [{ task = \"show-env\", env = { FOO = \"hello\", BAZ = \"world\" } }]\nrun = 'echo done'\n\n[tasks.with-env-and-args]\ndepends = [{ task = \"echo-args\", env = { FOO = \"test\" }, args = [\"arg1\", \"arg2\"] }]\nrun = 'echo done'\n\n[tasks.echo-args]\nrun = 'echo \"FOO=\\$FOO\" && echo'\nEOF\n\nassert_contains \"mise run with-env-object\" \"FOO=hello BAZ=world\"\nassert_contains \"mise run with-env-and-args\" \"FOO=test\"\n# Args are appended to the command line, verify they appear in output\nassert_contains \"mise run with-env-and-args\" \"arg1 arg2\"\n"
  },
  {
    "path": "e2e/tasks/test_task_dep_env_outputs",
    "content": "#!/usr/bin/env bash\n\n# Test 1: basic output caching works with dependencies\ncat <<EOF >mise.toml\n[tasks.build]\nrun = 'mkdir -p out && echo built > out/result.txt && echo built'\nsources = ['src/**/*']\noutputs = ['out/result.txt']\n\n[tasks.deploy]\ndepends = [\"build\"]\nrun = 'echo deployed'\nEOF\n\nmkdir -p src\necho \"v1\" >src/main.txt\n\n# First run builds\nassert_contains \"mise run deploy\" \"built\"\n# Second run uses cache\nassert_not_contains \"mise run deploy\" \"built\"\n# Touch source invalidates cache\ntouch src/main.txt\nassert_contains \"mise run deploy\" \"built\"\n\n# Test 2: output templates are re-rendered when dependency injects env vars\n# The build task uses {{env.BUILD_DIR}} in its output path with a default.\n# When deploy depends on \"BUILD_DIR=custom build\", the output path should\n# be re-rendered to \"custom/result.txt\" using the injected env.\ncat <<'EOF' >mise.toml\n[tasks.build]\nrun = 'mkdir -p ${BUILD_DIR:-out} && echo built > ${BUILD_DIR:-out}/result.txt && echo built'\nsources = ['src/**/*']\noutputs = ['{{ env.BUILD_DIR | default(value=\"out\") }}/result.txt']\n\n[tasks.deploy]\ndepends = [\"BUILD_DIR=custom build\"]\nrun = 'echo deployed'\nEOF\n\nrm -rf out custom\nmkdir -p src\necho \"v1\" >src/main.txt\n\n# First run should build (output doesn't exist yet)\nassert_contains \"mise run deploy\" \"built\"\n# Verify output was written to \"custom\" dir (not \"out\")\nassert \"test -f custom/result.txt && echo yes\" \"yes\"\n# Second run should use cache (output exists at custom/result.txt)\nassert_not_contains \"mise run deploy\" \"built\"\n# Touch source invalidates cache\ntouch src/main.txt\nassert_contains \"mise run deploy\" \"built\"\n"
  },
  {
    "path": "e2e/tasks/test_task_depends_post",
    "content": "#!/usr/bin/env bash\n\n# ensures depends_post and depends can be used on separate tasks\ncat <<EOF >mise.toml\n[tasks.one]\nrun = \"echo one\"\n\n[tasks.two]\ndepends = [\"one\"]\nrun = \"echo two\"\n\n[tasks.three]\ndepends_post = [\"two\"]\nrun = \"echo three\"\nEOF\nassert \"mise tasks deps\" \"one\nthree\ntwo\n├── three\n└── one\"\nassert \"mise run three\"\n\n# TODO: this does not work with how mise is designed currently. Tasks can only ever be run once per run session. This will require hefty refactoring if it is ever supported\n# uses depends and depends_post on the same task\n#cat <<EOF >mise.toml\n#tasks.\"util:donothing\" = \"\"\n#[tasks.hi]\n#depends = \"util:donothing\"\n#run = \"echo hi\"\n#depends_post = \"util:donothing\"\n#EOF\n#assert \"mise run hi\"\n"
  },
  {
    "path": "e2e/tasks/test_task_depends_post_multiple",
    "content": "#!/usr/bin/env bash\n\n# Test that multiple depends_post entries work correctly without hanging\ncat <<EOF >mise.toml\n[tasks.bar]\nrun = \"echo bar\"\n\n[tasks.foo]\nrun = \"echo foo\"\n\n[tasks.baz]\nrun = \"echo baz\"\ndepends_post = [\"foo\", \"bar\"]\nEOF\n\n# Test that task dependencies are resolved correctly\n# With depends_post, the dependencies appear as children in the tree\nassert \"mise tasks deps\" \"bar\n└── baz\nbaz\nfoo\n└── baz\"\n\n# Test that the task runs successfully (just check it doesn't hang)\nassert \"mise run baz\"\n\n# Test with three post dependencies\ncat <<EOF >mise.toml\n[tasks.one]\nrun = \"echo one\"\n\n[tasks.two]\nrun = \"echo two\"\n\n[tasks.three]\nrun = \"echo three\"\n\n[tasks.main]\nrun = \"echo main\"\ndepends_post = [\"one\", \"two\", \"three\"]\nEOF\n\nassert \"mise tasks deps\" \"main\none\n└── main\nthree\n└── main\ntwo\n└── main\"\n\nassert \"mise run main\"\n"
  },
  {
    "path": "e2e/tasks/test_task_depends_post_on_failure",
    "content": "#!/usr/bin/env bash\n\n# Test that depends_post tasks run even when the parent task fails\ncat <<EOF >mise.toml\n[tasks.cleanup]\nrun = \"echo cleanup ran\"\n\n[tasks.deploy]\ndepends_post = [\"cleanup\"]\nrun = \"echo deploying && exit 1\"\nEOF\n\n# The task should fail (deploy exits 1) but cleanup should still run\nassert_fail \"mise run deploy\" \"cleanup ran\"\n\n# Test with multiple post-deps: all should run on failure\ncat <<EOF >mise.toml\n[tasks.notify]\nrun = \"echo notified\"\n\n[tasks.cleanup]\nrun = \"echo cleaned up\"\n\n[tasks.deploy]\ndepends_post = [\"cleanup\", \"notify\"]\nrun = \"echo deploying && exit 1\"\nEOF\n\nassert_fail \"mise run deploy\" \"cleaned up\"\nassert_fail \"mise run deploy\" \"notified\"\n\n# Test that depends_post still works on success (no regression)\ncat <<EOF >mise.toml\n[tasks.cleanup]\nrun = \"echo cleanup ran\"\n\n[tasks.deploy]\ndepends_post = [\"cleanup\"]\nrun = \"echo deployed\"\nEOF\n\nassert_contains \"mise run deploy\" \"cleanup ran\"\nassert_contains \"mise run deploy\" \"deployed\"\n"
  },
  {
    "path": "e2e/tasks/test_task_depends_post_skipped_on_dep_failure",
    "content": "#!/usr/bin/env bash\n\n# Test that depends_post does NOT run when a pre-dependency (depends) fails\n# and the main task never executes.\n# Regression test for https://github.com/jdx/mise/discussions/8425\ncat <<EOF >mise.toml\n[tasks.check]\nrun = \"echo check-failed && exit 1\"\n\n[tasks.cleanup]\nrun = \"echo cleanup-should-not-run\"\n\n[tasks.deploy]\ndepends = [\"check\"]\ndepends_post = [\"cleanup\"]\nrun = \"echo deploying\"\nEOF\n\n# \"check\" fails -> \"deploy\" never runs -> \"cleanup\" (depends_post) should NOT run\noutput=\"$(MISE_FRIENDLY_ERROR=1 RUST_BACKTRACE=0 mise run deploy 2>&1)\" || true\nif [[ $output == *\"cleanup-should-not-run\"* ]]; then\n\tfail \"depends_post ran even though pre-dependency failed and main task never executed\"\nfi\nif [[ $output == *\"deploying\"* ]]; then\n\tfail \"main task ran even though pre-dependency failed\"\nfi\nassert_contains \"echo '$output'\" \"check-failed\"\nok \"depends_post correctly skipped when pre-dependency fails\"\n\n# Verify depends_post DOES run when the main task itself fails (not a pre-dep)\ncat <<EOF >mise.toml\n[tasks.cleanup]\nrun = \"echo cleanup-ran\"\n\n[tasks.deploy]\ndepends_post = [\"cleanup\"]\nrun = \"echo deploying && exit 1\"\nEOF\n\noutput=\"$(MISE_FRIENDLY_ERROR=1 RUST_BACKTRACE=0 mise run deploy 2>&1)\" || true\nassert_contains \"echo '$output'\" \"cleanup-ran\"\nok \"depends_post correctly runs when main task itself fails\"\n"
  },
  {
    "path": "e2e/tasks/test_task_deps",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.a.run = \"echo a\"\ntasks.b.depends = [\"a\"]\ntasks.b.run = \"echo b\"\ntasks.c.depends = [\"a\"]\ntasks.c.run = \"echo c\"\ntasks.c.wait_for = [\"b\"]\ntasks.d.depends = [\"c\"]\ntasks.d.run = \"echo d\"\ntasks.d.wait_for = [\"b\"]\nEOF\n\nassert \"mise run d\" \"a\nc\nd\"\n\nassert \"mise run d ::: b\" \"a\nb\nc\nd\"\n\ncat <<EOF >mise.toml\n[tasks.\"hello:1\"]\ndescription = \"Hello from 1\"\nrun = \"echo Hello from 1\"\n\n[tasks.\"hello:2\"]\ndescription = \"Hello from 2\"\nrun = \"echo Hello from 2\"\n\n[tasks.\"hello:all\"]\ndescription = \"Hello from all\"\ndepends = [\"hello:*\"]\nEOF\nassert_contains \"mise run hello:all\" \"[hello:1] Hello from 1\"\nassert_contains \"mise run hello:all\" \"[hello:2] Hello from 2\"\nassert \"mise tasks deps\" \"hello:1\nhello:2\nhello:all\n├── hello:2\n└── hello:1\"\nhello_all_info=\"$(mise tasks hello:all)\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"Task: hello:all\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"Description: Hello from all\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"Source: ~/workdir/mise.toml\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"Depends on: hello:*\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"name hello:all\"\nassert_contains \"printf '%s\\n' \\\"$hello_all_info\\\"\" \"bin hello:all\"\n\necho '' >mise.toml\n\nmkdir -p mise-tasks && echo \"\" >mise-tasks/build.sh && chmod +x mise-tasks/build.sh\nassert \"mise tasks deps build\" \"build\"\nassert \"mise tasks deps build.sh\" \"build\"\n"
  },
  {
    "path": "e2e/tasks/test_task_deps_circular",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.one]\nrun = \"echo one\"\ndepends = [\"two\"]\n\n[tasks.two]\ndepends = [\"three\"]\nrun = \"echo two\"\n\n[tasks.three]\ndepends = [\"one\"]\nrun = \"echo three\"\nEOF\n# this should fail not sure how it works.\nassert_fail \"mise run one\"\n"
  },
  {
    "path": "e2e/tasks/test_task_disable_spec_from_run_scripts",
    "content": "#!/usr/bin/env bash\n\n# Test for MISE_TASK_DISABLE_SPEC_FROM_RUN_SCRIPTS setting\n# When enabled, mise should NOT parse run scripts for arg()/option()/flag() to infer usage spec\n# It should only use the explicit `usage` field\n\n# Test 1: Without the setting (default), Tera functions in run scripts contribute to usage spec\ncat <<'EOF' >mise.toml\n[tasks.with-tera-args]\ndescription = \"Task with Tera template args\"\nrun = 'echo \"arg={{arg(name=\"myarg\")}} flag={{flag(name=\"myflag\")}}\"'\nEOF\n\n# Default behavior: arg/flag should appear in the usage spec\nassert_contains \"mise tasks info with-tera-args --json\" '\"name\": \"myarg\"'\nassert_contains \"mise tasks info with-tera-args --json\" '\"name\": \"myflag\"'\n\n# Test 2: With the setting enabled, Tera functions should NOT contribute to usage spec\nexport MISE_TASK_DISABLE_SPEC_FROM_RUN_SCRIPTS=1\n\ncat <<'EOF' >mise.toml\n[tasks.tera-only]\ndescription = \"Task with only Tera template args in run script\"\nrun = 'echo \"arg={{arg(name=\"teraarg\")}} option={{option(name=\"teraopt\")}}\"'\nEOF\n\n# With setting enabled: teraarg and teraopt should NOT appear in usage spec\nassert_not_contains \"mise tasks info tera-only --json\" '\"name\": \"teraarg\"'\nassert_not_contains \"mise tasks info tera-only --json\" '\"name\": \"teraopt\"'\n\n# Test 3: With setting enabled, explicit usage field should still work\ncat <<'EOF' >mise.toml\n[tasks.with-usage-field]\ndescription = \"Task with explicit usage field\"\nusage = '''\narg \"usagearg\" \"An argument from usage field\"\nflag \"--usageflag\" \"A flag from usage field\"\n'''\nrun = 'echo \"arg=$usage_usagearg flag=$usage_usageflag\"'\nEOF\n\n# With setting enabled: usage field args should still appear\nassert_contains \"mise tasks info with-usage-field --json\" '\"name\": \"usagearg\"'\nassert_contains \"mise tasks info with-usage-field --json\" '\"name\": \"usageflag\"'\n\n# Test 4: With setting enabled, usage field works but tera args in run scripts are ignored\ncat <<'EOF' >mise.toml\n[tasks.mixed-usage]\ndescription = \"Task with both usage field and Tera args\"\nusage = '''\narg \"fromfield\" \"Arg from usage field\"\n'''\nrun = 'echo \"field={{arg(name=\"fromfield\")}} tera={{arg(name=\"fromtera\")}}\"'\nEOF\n\n# Only the usage field arg should appear, not the tera template arg\nassert_contains \"mise tasks info mixed-usage --json\" '\"name\": \"fromfield\"'\nassert_not_contains \"mise tasks info mixed-usage --json\" '\"name\": \"fromtera\"'\n\n# Test 5: Verify tasks still run correctly with the setting enabled\ncat <<'EOF' >mise.toml\n[tasks.run-test]\ndescription = \"Task to verify running works\"\nusage = '''\narg \"myarg\" default=\"default_value\"\n'''\nrun = 'echo \"value=$usage_myarg\"'\nEOF\n\nassert \"mise run run-test\" \"value=default_value\"\nassert \"mise run run-test custom_value\" \"value=custom_value\"\n\n# Test 6: Verify ls --usage only shows usage field args when setting is enabled\ncat <<'EOF' >mise.toml\n[tasks.ls-test]\ndescription = \"Task for ls usage test\"\nusage = '''\narg \"visiblearg\" \"Should be visible\"\n'''\nrun = 'echo \"{{arg(name=\"hiddenarg\")}}\"'\nEOF\n\nassert_contains \"mise tasks ls --usage\" \"visiblearg\"\nassert_not_contains \"mise tasks ls --usage\" \"hiddenarg\"\n\nunset MISE_TASK_DISABLE_SPEC_FROM_RUN_SCRIPTS\n\n# Test 7: Verify default behavior is restored after unsetting\ncat <<'EOF' >mise.toml\n[tasks.restored-test]\ndescription = \"Test restored default behavior\"\nrun = 'echo \"arg={{arg(name=\"restoredarg\")}}\"'\nEOF\n\n# Without the setting, tera args should appear again\nassert_contains \"mise tasks info restored-test --json\" '\"name\": \"restoredarg\"'\n"
  },
  {
    "path": "e2e/tasks/test_task_display_truncation",
    "content": "#!/usr/bin/env bash\n\n# Test for task display truncation fix\n# This test verifies that task names/commands are not truncated at 60 characters\n# and instead use proper width calculations\n\ncat <<EOF >mise.toml\n[tasks.short]\nrun = 'echo \"short task\"'\n\n[tasks.medium-length-task-name]\nrun = 'echo \"medium length task with some reasonable command length here\"'\n\n[tasks.very-long-task-name-that-exceeds-sixty-characters-to-test-truncation]\nrun = 'echo \"this is a very long command that should not be immediately truncated\"'\n\n[tasks.super-duper-ultra-mega-extremely-long-task-name-that-definitely-exceeds-the-old-sixty-character-hard-limit]\nrun = 'echo \"super long command text that should show more than just the command name before truncation\"'\n\n[tasks.insanely-long-task-output]\nrun = 'echo \"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et e\"'\n\nEOF\n\n# Test task listing shows full names (not truncated at 60 chars)\nassert_contains \"mise tasks ls\" \"short\"\nassert_contains \"mise tasks ls\" \"medium-length-task-name\"\nassert_contains \"mise tasks ls\" \"very-long-task-name-that-exceeds-sixty-characters-to-test-truncation\"\nassert_contains \"mise tasks ls\" \"super-duper-ultra-mega-extremely-long-task-name-that-definitely-exceeds-the-old-sixty-character-hard-limit\"\n\n# Test that we can still run tasks with long names\nassert_succeed \"mise run short\"\nassert_succeed \"mise run medium-length-task-name\"\n\n# Verify the task runs successfully (main functionality not affected)\noutput=$(mise run short 2>&1)\nif [[ $output == *\"short task\"* ]]; then\n\tok \"[task execution] short task runs correctly\"\nelse\n\tfail \"[task execution] expected 'short task' in output, got: $output\"\nfi\n\n# Verify the task output is not truncated with ellipsis when CI is set\noutput=$(env CI=1 mise run insanely-long-task-output 2>&1)\nif [[ $output != *\"…\"* ]]; then\n\tok \"[task execution] insanely-long-task-output task runs correctly\"\nelse\n\tfail \"[task execution] no '…' expected in output, got: $output\"\nfi\n\necho \"Task display truncation test completed successfully\"\n"
  },
  {
    "path": "e2e/tasks/test_task_double_dash_behavior",
    "content": "#!/usr/bin/env bash\n\n# Test flag routing: mise flags ONLY work BEFORE task name, flags after task go to task\n\ncat <<'EOF' >mise.toml\n[tasks.echo_args]\nrun = 'echo \"args:$@\"'\nEOF\n\n# Test 1: Mise flags work ONLY before task name\n# -q before task = mise flag, -q after task = task arg\nassert \"mise run -q echo_args arg1 2>&1\" \"args: arg1\"\nassert_contains \"mise run echo_args -q arg1 2>&1\" \"args: -q arg1\"\nassert \"mise -q run echo_args arg1 2>&1\" \"args: arg1\"\n\n# Test 2: Naked runs - mise flags only before task name\nassert \"mise -q echo_args arg1 2>&1\" \"args: arg1\"\nassert_contains \"mise echo_args -q arg1 2>&1\" \"args: -q arg1\"\n\n# Test 3: Unknown flags go to task\ncat <<'EOF' >mise.toml\n[tasks.echo_args]\nrun = 'echo \"args:$@\"'\nEOF\n\nassert \"mise run echo_args -x\" \"args: -x\"\nassert \"mise run echo_args --custom\" \"args: --custom\"\nassert \"mise echo_args -x\" \"args: -x\"\nassert \"mise echo_args --custom\" \"args: --custom\"\n\n# Test 4: Explicit -- separator passes args to task (no prefix!)\nassert \"mise run echo_args -- -q\" \"args: -q\"\nassert \"mise run echo_args -- --help\" \"args: --help\"\nassert \"mise echo_args -- -q\" \"args: -q\"\nassert \"mise echo_args -- --help\" \"args: --help\"\n\n# Test 5: Multiple args after --\nassert \"mise run echo_args -- arg1 arg2 arg3\" \"args: arg1 arg2 arg3\"\nassert \"mise echo_args -- arg1 arg2 arg3\" \"args: arg1 arg2 arg3\"\n\n# Test 6: Mixed flags and args work correctly\nassert \"mise run -q echo_args -x arg1\" \"args: -x arg1\"\nassert \"mise -q echo_args --custom arg1\" \"args: --custom arg1\"\n\n# Test 7: Task with usage spec\ncat <<'EOF' >mise.toml\n[tasks.with_usage]\nrun = 'echo \"custom=$usage_custom file=$usage_file args=$@\"'\nusage = \"\"\"\nflag \"-x --custom\" help=\"Custom flag\"\narg \"<file>\" help=\"File to process\"\n\"\"\"\nEOF\n\n# Usage spec handles its own flags (parsed by usage spec, not passed as $@)\n# shellcheck disable=SC2016\nassert \"mise run with_usage -x myfile 2>&1\" '[with_usage] $ echo \"custom=$usage_custom file=$usage_file args=$@\"\ncustom=true file=myfile args='\n\n# But mise flags still go to mise (myfile is consumed by usage spec, not passed to $@)\nassert \"mise run -q with_usage myfile\" \"custom= file=myfile args=\"\n\n# Test 8: --help shows usage spec help\nassert \"mise run with_usage --help 2>&1 || true\" \"Usage: with_usage [-x --custom] <file>\n\nArguments:\n  <file>  File to process\n\nFlags:\n  -x --custom  Custom flag\"\n\n# Test 9: Help passed as explicit argument with -- (recreate echo_args task)\ncat <<'EOF' >mise.toml\n[tasks.echo_args]\nrun = 'echo \"args:$@\"'\nEOF\n\nassert \"mise run echo_args -- --help\" \"args: --help\"\n\n# Test 10: Tasks can use mise flags explicitly with --\ncat <<'EOF' >mise.toml\n[tasks.custom_quiet]\nrun = '''\n#!/usr/bin/env bash\nwhile getopts \"q\" opt; do\n  case $opt in\n    q) echo \"custom quiet flag received\" ;;\n  esac\ndone\n'''\nEOF\n\n# Task can receive -q via --\nassert \"mise run custom_quiet -- -q\" \"custom quiet flag received\"\nassert \"mise custom_quiet -- -q\" \"custom quiet flag received\"\n\n# With new behavior, -q after task name also goes to task\nassert \"mise run custom_quiet -q\" \"custom quiet flag received\"\nassert \"mise custom_quiet -q\" \"custom quiet flag received\"\n\n# Test 11: Complex scenarios\ncat <<'EOF' >mise.toml\n[tasks.complex]\nrun = 'echo \"received: $@\"'\nEOF\n\n# Multiple mise flags + task args\nassert \"mise run -q complex arg1 arg2\" \"received:  arg1 arg2\"\n\n# Mix of mise flags and unknown flags\nassert \"mise run -q complex -x -y\" \"received:  -x -y\"\n\n# Explicit -- overrides everything\nassert \"mise run complex -- -q -v arg1\" \"received:  -q -v arg1\"\n"
  },
  {
    "path": "e2e/tasks/test_task_edit_nested_names",
    "content": "#!/usr/bin/env bash\n\n# Test that task edit with nested colons (foo:bar:baz) creates the correct file structure\n# and can be run with `mise run foo:bar:baz`\n\n# Create a temporary editor script that just writes a simple task\nexport EDITOR=\"$PWD/fake-editor\"\ncat <<'EDITOR_EOF' >fake-editor\n#!/usr/bin/env bash\n# Don't actually open an editor, just ensure the file has some content\nif [ ! -s \"$1\" ]; then\n\tcat >\"$1\" <<'EOF'\n#!/usr/bin/env bash\nset -euxo pipefail\n\necho \"nested task executed\"\nEOF\nfi\nEDITOR_EOF\nchmod +x fake-editor\n\n# Test 1: Create a task with nested colons using task edit\necho \"Running: mise tasks edit foo:bar:baz --path\"\nTASK_PATH=$(mise tasks edit foo:bar:baz --path 2>&1)\n\n# Verify the file was created\nif [ ! -f \"$TASK_PATH\" ]; then\n\techo \"ERROR: Task file was not created at $TASK_PATH\"\n\texit 1\nfi\n\necho \"Task file created at: $TASK_PATH\"\n\n# Write content to the task file\ncat >\"$TASK_PATH\" <<'EOF'\n#!/usr/bin/env bash\nset -euxo pipefail\n\necho \"nested task executed\"\nEOF\nchmod +x \"$TASK_PATH\"\n\n# The key test: Can we run the task with its nested name?\n# Should successfully execute and output our message\nassert_contains \"mise run foo:bar:baz\" \"nested task executed\"\n\n# Test 2: Verify the task shows up in task list with the correct name\nassert_contains \"mise tasks ls\" \"foo:bar:baz\"\n\n# Test 3: Try editing an existing nested task (should not create duplicates)\nTASK_PATH2=$(mise tasks edit foo:bar:baz --path 2>&1)\n\nif [ \"$TASK_PATH\" != \"$TASK_PATH2\" ]; then\n\techo \"ERROR: Editing the same task twice gave different paths\"\n\techo \"First edit: $TASK_PATH\"\n\techo \"Second edit: $TASK_PATH2\"\n\texit 1\nfi\n\n# Test 4: Create a task with multiple levels of nesting\nTASK_PATH3=$(mise tasks edit deploy:prod:backend:api --path 2>&1)\n\nif [ ! -f \"$TASK_PATH3\" ]; then\n\techo \"ERROR: Deeply nested task file was not created at $TASK_PATH3\"\n\texit 1\nfi\n\necho \"Deeply nested task file created at: $TASK_PATH3\"\n\n# Write content to the deeply nested task\ncat >\"$TASK_PATH3\" <<'EOF'\n#!/usr/bin/env bash\nset -euxo pipefail\n\necho \"deeply nested task executed\"\nEOF\nchmod +x \"$TASK_PATH3\"\n\n# Run the deeply nested task\nassert_contains \"mise run deploy:prod:backend:api\" \"deeply nested task executed\"\n\n# Verify it shows up in the task list\nassert_contains \"mise tasks ls\" \"deploy:prod:backend:api\"\n"
  },
  {
    "path": "e2e/tasks/test_task_env_directives",
    "content": "#!/usr/bin/env bash\n\n# Test task environment directives: _.source, _.file, _.path\n\n# Test 1: _.file directive with .env file\necho \"TEST_FILE_VAR=from_env_file\" >.env\ncat <<EOF >mise.toml\n[tasks.test-env-file]\nrun = 'echo \"FILE_VAR=\\$TEST_FILE_VAR OTHER_VAR=\\$OTHER_VAR\"'\n[tasks.test-env-file.env]\n_.file = \".env\"\nOTHER_VAR = \"normal_value\"\nEOF\nassert \"mise run test-env-file\" \"FILE_VAR=from_env_file OTHER_VAR=normal_value\"\n\n# Test 2: _.source directive with shell script\ncat <<'EOF' >env_source.sh\nexport TEST_SOURCE_VAR=\"from_source_script\"\nexport ANOTHER_VAR=\"source_value\"\nEOF\ncat <<EOF >mise.toml\n[tasks.test-env-source]\nrun = 'echo \"SOURCE_VAR=\\$TEST_SOURCE_VAR ANOTHER_VAR=\\$ANOTHER_VAR REGULAR_VAR=\\$REGULAR_VAR\"'\n[tasks.test-env-source.env]\n_.source = \"env_source.sh\"\nREGULAR_VAR = \"regular_value\"\nEOF\nassert \"mise run test-env-source\" \"SOURCE_VAR=from_source_script ANOTHER_VAR=source_value REGULAR_VAR=regular_value\"\n\n# Test 3: _.path directive\nmkdir -p custom_bin\necho '#!/bin/bash\necho \"custom command executed\"' >custom_bin/custom_cmd\nchmod +x custom_bin/custom_cmd\ncat <<EOF >mise.toml\n[tasks.test-env-path]\nrun = 'custom_cmd'\n[tasks.test-env-path.env]\n_.path = \"./custom_bin\"\nEOF\nassert \"mise run test-env-path\" \"custom command executed\"\n\n# Test 4: Multiple directives combined\necho \"MULTI_FILE_VAR=from_multi_file\" >.env.multi\ncat <<'EOF' >multi_source.sh\nexport MULTI_SOURCE_VAR=\"from_multi_source\"\nEOF\ncat <<EOF >mise.toml\n[tasks.test-multi-env]\nrun = 'echo \"FILE=\\$MULTI_FILE_VAR SOURCE=\\$MULTI_SOURCE_VAR COMBINED=\\$COMBINED_VAR\" && custom_cmd'\n[tasks.test-multi-env.env]\n_.file = \".env.multi\"\n_.source = \"multi_source.sh\"\n_.path = \"./custom_bin\"\nCOMBINED_VAR = \"combined_value\"\nEOF\nassert \"mise run test-multi-env\" \"FILE=from_multi_file SOURCE=from_multi_source COMBINED=combined_value\ncustom command executed\"\n\n# Test 5: Arrays of files/sources\necho \"ARRAY1_VAR=value1\" >.env1\necho \"ARRAY2_VAR=value2\" >.env2\ncat <<'EOF' >source1.sh\nexport SOURCE1_VAR=\"source1_value\"\nEOF\ncat <<'EOF' >source2.sh\nexport SOURCE2_VAR=\"source2_value\"\nEOF\ncat <<EOF >mise.toml\n[tasks.test-env-arrays]\nrun = 'echo \"ARRAY1=\\$ARRAY1_VAR ARRAY2=\\$ARRAY2_VAR SOURCE1=\\$SOURCE1_VAR SOURCE2=\\$SOURCE2_VAR\"'\n[tasks.test-env-arrays.env]\n_.file = [\".env1\", \".env2\"]\n_.source = [\"source1.sh\", \"source2.sh\"]\nEOF\nassert \"mise run test-env-arrays\" \"ARRAY1=value1 ARRAY2=value2 SOURCE1=source1_value SOURCE2=source2_value\"\n\n# Test 6: Variable types (string, int, bool)\ncat <<EOF >mise.toml\n[tasks.test-env-types]\nrun = 'env | grep \"_VAR=\" | sort'\n[tasks.test-env-types.env]\nSTRING_VAR = \"test_string\"\nINT_VAR = 42\nBOOL_TRUE_VAR = true\nBOOL_FALSE_VAR = false\nEOF\nassert_contains \"mise run test-env-types\" \"BOOL_TRUE_VAR=true\"\nassert_contains \"mise run test-env-types\" \"INT_VAR=42\"\nassert_contains \"mise run test-env-types\" \"STRING_VAR=test_string\"\n# false values should unset the variable, so BOOL_FALSE_VAR should not be present\nassert_not_contains \"mise run test-env-types\" \"BOOL_FALSE_VAR\"\n\n# Test 7: Verify task info shows correct directive syntax\ncat <<EOF >mise.toml\n[tasks.test-info-display]\nrun = 'echo \"testing info display\"'\n[tasks.test-info-display.env]\nTEST_VAR = \"test_value\"\n_.file = \".env\"\n_.path = \"./custom_bin\"\n_.source = \"env_source.sh\"\nEOF\necho \"Testing task info directive display...\"\nassert_contains \"mise tasks info test-info-display\" '_.file = \".env\"'\nassert_contains \"mise tasks info test-info-display\" '_.path = \"./custom_bin\"'\nassert_contains \"mise tasks info test-info-display\" '_.source = \"env_source.sh\"'\nassert_contains \"mise tasks info test-info-display\" 'TEST_VAR=test_value'\n\n# Test 8: Verify task info JSON output shows correct directive syntax\nassert_contains \"mise tasks info test-info-display --json\" '\"_.file = \\\".env\\\"\"'\nassert_contains \"mise tasks info test-info-display --json\" '\"_.path = \\\"./custom_bin\\\"\"'\nassert_contains \"mise tasks info test-info-display --json\" '\"_.source = \\\"env_source.sh\\\"\"'\nassert_contains \"mise tasks info test-info-display --json\" '\"TEST_VAR=test_value\"'\n\necho \"All task environment directive tests passed!\"\n"
  },
  {
    "path": "e2e/tasks/test_task_env_flag_propagation",
    "content": "#!/usr/bin/env bash\n\n# Test that -E/--env flag is propagated to child tasks\n# See: https://github.com/jdx/mise/discussions/7865\n\n# Create env-specific config with env vars\ncat <<EOF >mise.dev.toml\n[env]\nMY_DEV_VAR = \"dev-value\"\nEOF\n\n# Create main config with tasks that depend on each other\ncat <<EOF >mise.toml\n[tasks.child]\nrun = 'echo \"MY_DEV_VAR=\\$MY_DEV_VAR\"'\n\n[tasks.parent]\ndepends = [\"child\"]\nrun = 'echo \"parent done\"'\n\n# A task that invokes mise run internally (simulates nested mise invocation)\n[tasks.nested-mise]\nrun = 'mise run child'\nEOF\n\n# Test 1: Child task should see env vars when called with -E\nassert_contains \"mise -E dev run child\" \"MY_DEV_VAR=dev-value\"\n\n# Test 2: Parent task should see env vars in its child when called with -E\nassert_contains \"mise -E dev run parent\" \"MY_DEV_VAR=dev-value\"\n\n# Test 3: Nested mise invocation should inherit MISE_ENV\nassert_contains \"mise -E dev run nested-mise\" \"MY_DEV_VAR=dev-value\"\n\n# Test 4: Same tests with --env instead of -E\nassert_contains \"mise --env dev run child\" \"MY_DEV_VAR=dev-value\"\nassert_contains \"mise --env dev run parent\" \"MY_DEV_VAR=dev-value\"\nassert_contains \"mise --env dev run nested-mise\" \"MY_DEV_VAR=dev-value\"\n"
  },
  {
    "path": "e2e/tasks/test_task_env_propagation",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.echo]\nenv = { \"SUB_TASK\" = \"sub_task_env\" }\nrun = 'echo \"\\$SUB_TASK \\$MY_VAR\"'\n\n\n[tasks.propagation]\nrun = [{ task = \"echo\" }]\nenv = { \"MY_VAR\" = \"my_variable\" }\nEOF\n\nassert_contains \"mise run echo\" \"sub_task_env \" # with trailing space\nassert_contains \"mise run propagation\" \"sub_task_env my_variable\"\n"
  },
  {
    "path": "e2e/tasks/test_task_failure_hang",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n# https://github.com/jdx/mise/discussions/6391\n\ncat <<EOF >mise.toml\n[tasks.fails]\nrun = '''\nsleep 1;\necho \"An error occurred!\"\nexit 1;\n'''\n\n[tasks.deponfails]\ndepends = [\"fails\"]\nrun = 'echo \"This will not run because the dependency fails.\"'\n\n[tasks.grouped]\nrun = [\n    { task = \"deponfails\" }\n]\nEOF\n\n# Test that task failure with dependencies does not hang\ntimeout 5s mise run grouped 2>&1 && exit_code=0 || exit_code=$?\n\n# Check if it was a timeout (exit code 124)\nif [ \"$exit_code\" -eq 124 ]; then\n\techo \"FAIL: Task hung after dependency failure (timeout reached)\"\n\texit 1\nfi\n\n# The command should fail with exit code 1\nif [ \"$exit_code\" -ne 1 ]; then\n\techo \"Expected exit code 1, got $exit_code\"\n\texit 1\nfi\n\necho \"Test passed: task with failing dependency did not hang\"\n"
  },
  {
    "path": "e2e/tasks/test_task_failure_hang_depends",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n# https://github.com/jdx/mise/discussions/6391\n\ncat <<EOF >mise.toml\n[tasks.clean]\nrun = 'echo \"Cleaning...\"'\n\n[tasks.install]\nwait_for = \"clean\"\nrun = \"sleep 1\"\n\n[tasks.lint]\ndepends = \"install\"\nrun = \"exit 1\"\n\n[tasks.test]\ndepends = \"install\"\nrun = \"exit 1\"\n\n[tasks.\"build:docker\"]\ndepends = \"install\"\nrun = \"exit 1\"\n\n[tasks.check]\ndepends = [\"lint\", \"test\", \"build:docker\"]\n\n[tasks.\"ci:check\"]\ndepends = [\"clean\", \"check\"] # this variant currently hangs\n\n# this variant now works after initial fix\n# run = [\n#   { task = \"clean\" },\n#   { task = \"check\" }\n# ]\nEOF\n\n# Test that task failure with dependencies does not hang\ntimeout 5s mise run --jobs 1 ci:check 2>&1 && exit_code=0 || exit_code=$?\n\n# Check if it was a timeout (exit code 124)\nif [ \"$exit_code\" -eq 124 ]; then\n\techo \"FAIL: Task hung after dependency failure (timeout reached)\"\n\texit 1\nfi\n\n# The command should fail with exit code 1\nif [ \"$exit_code\" -ne 1 ]; then\n\techo \"Expected exit code 1, got $exit_code\"\n\texit 1\nfi\n\necho \"Test passed: task with failing dependency did not hang\"\n"
  },
  {
    "path": "e2e/tasks/test_task_file_auto_install",
    "content": "#!/usr/bin/env bash\n\n# Test that tools defined in mise.toml are auto-installed for file tasks\n# Reproduces: https://github.com/jdx/mise/discussions/8014\n#\n# File tasks (scripts in mise-tasks/) previously didn't trigger auto-install\n# of tools from mise.toml because t.cf(config) returns None for file tasks.\n\ncat <<EOF >mise.toml\n[tools]\ntiny = \"1\"\n\n[settings]\ntask.run_auto_install = true\nEOF\n\nmkdir -p mise-tasks\ncat <<'EOF' >mise-tasks/mytask\n#!/usr/bin/env bash\nrtx-tiny\nEOF\nchmod +x mise-tasks/mytask\n\nassert_contains \"mise run mytask\" \"rtx-tiny: v1.1.0\"\n"
  },
  {
    "path": "e2e/tasks/test_task_file_resolution",
    "content": "#!/usr/bin/env bash\n\n# Test that task file paths are resolved relative to the config file location\n# This ensures tasks with `file = \"path/to/script\"` work from subdirectories\n\n# Create a script in a subdirectory\nmkdir -p scripts\ncat >scripts/test.sh <<'EOF'\n#!/usr/bin/env bash\necho \"Task executed successfully\"\necho \"Current directory: $(pwd)\"\nEOF\nchmod +x scripts/test.sh\n\n# Create mise.toml with a task that references the script\ncat >mise.toml <<'EOF'\n[tasks.test-file]\ndescription = \"Test task with file attribute\"\nfile = \"scripts/test.sh\"\nEOF\n\n# Trust the config\nmise trust\n\n# Test 1: Run the task from the root directory (should work)\nassert_contains \"mise run test-file\" \"Task executed successfully\"\n\n# Test 2: Run the task from a subdirectory (the fix - should work)\nmkdir -p subdir\n(\n\tcd subdir\n\tassert_contains \"mise run test-file\" \"Task executed successfully\"\n)\n\n# Test 3: Run from a nested subdirectory\nmkdir -p subdir/nested\n(\n\tcd subdir/nested\n\tassert_contains \"mise run test-file\" \"Task executed successfully\"\n)\n\n# Test 4: Verify the task shows up in task list from subdirectory\n(\n\tcd subdir\n\tassert_contains \"mise tasks ls\" \"test-file\"\n)\n\n# Test 5: Test with absolute path (should work from anywhere)\nABSOLUTE_SCRIPT=\"$(pwd)/scripts/test.sh\"\ncat >mise.toml <<EOF\n[tasks.test-absolute]\ndescription = \"Test task with absolute path\"\nfile = \"$ABSOLUTE_SCRIPT\"\nEOF\n\nmise trust\nassert_contains \"mise run test-absolute\" \"Task executed successfully\"\n\n(\n\tcd subdir\n\tassert_contains \"mise run test-absolute\" \"Task executed successfully\"\n)\n\n# Test 6: Test with templated path\ncat >mise.toml <<'EOF'\n[tasks.test-template]\ndescription = \"Test task with templated path\"\nfile = \"{{config_root}}/scripts/test.sh\"\nEOF\n\nmise trust\nassert_contains \"mise run test-template\" \"Task executed successfully\"\n\n(\n\tcd subdir\n\tassert_contains \"mise run test-template\" \"Task executed successfully\"\n)\n\necho \"All task file resolution tests passed!\"\n"
  },
  {
    "path": "e2e/tasks/test_task_flag_choices",
    "content": "#!/usr/bin/env bash\n\n# Test that flags with choices work in mise.toml tasks\n\ncat <<'EOF' >mise.toml\n[tasks.deploy]\nrun = 'echo \"Deploying to $usage_stage\"'\nusage = '''\nflag \"--stage <stage>\" default=\"preview\" {\n  choices \"preview\" \"production\"\n}\n'''\nEOF\n\n# Test with default value\nassert \"mise run deploy\" \"Deploying to preview\"\n\n# Test with valid choice\nassert \"mise run deploy --stage production\" \"Deploying to production\"\n\n# Test with invalid choice should fail\nassert_fail \"mise run deploy --stage invalid\"\n\n# Test flag choices using template syntax in run script\ncat <<'EOF' >mise.toml\n[tasks.deploy]\nrun = 'echo \"Deploying to {{flag(name=\"stage\", default=\"preview\", choices=[\"preview\", \"production\"])}}\"'\nEOF\n\n# Test with default value\nassert \"mise run deploy\" \"Deploying to preview\"\n\n# Test with valid choice\nassert \"mise run deploy --stage production\" \"Deploying to production\"\n\n# Test with invalid choice should fail\nassert_fail \"mise run deploy --stage invalid\"\n"
  },
  {
    "path": "e2e/tasks/test_task_flag_parsing",
    "content": "#!/usr/bin/env bash\n\n# Test that flags work with both `mise run` and naked runs\n\ncat <<'EOF' >mise.toml\n[tasks.mytask]\nrun = 'echo \"flag=$usage_flag\"'\nusage = '''\nflag \"--flag\"\n'''\nEOF\n\n# Test that -- works to pass flags to task\nassert \"mise run mytask -- --flag\" \"flag=true\"\nassert \"mise run mytask\" \"flag=\"\n\n# Test naked runs (without `run` subcommand)\nassert \"mise mytask --flag\" \"flag=true\"\nassert \"mise mytask\" \"flag=\"\n\n# Test with a flag that takes a value\ncat <<'EOF' >mise.toml\n[tasks.mytask]\nrun = 'echo \"level=$usage_level\"'\nusage = '''\nflag \"--level <level>\" default=\"info\"\n'''\nEOF\n\nassert \"mise run mytask -- --level debug\" \"level=debug\"\nassert \"mise run mytask\" \"level=info\"\n\n# Test naked runs with flag values\nassert \"mise mytask --level debug\" \"level=debug\"\nassert \"mise mytask\" \"level=info\"\n\n# Test with multiple flags\ncat <<'EOF' >mise.toml\n[tasks.mytask]\nrun = 'echo \"flag=$usage_flag output=$usage_output\"'\nusage = '''\nflag \"--flag\"\nflag \"--output <output>\" default=\"default.txt\"\n'''\nEOF\n\nassert \"mise run mytask -- --flag --output result.txt\" \"flag=true output=result.txt\"\nassert \"mise run mytask -- --output result.txt\" \"flag= output=result.txt\"\n\n# Test naked runs with multiple flags (--output is a mise flag, so use -- to pass both to task)\nassert \"mise mytask -- --flag --output result.txt\" \"flag=true output=result.txt\"\nassert \"mise mytask -- --output result.txt\" \"flag= output=result.txt\"\n\n# Test that mise global flags can be passed to tasks using --\ncat <<'EOF' >mise.toml\n[tasks.mytask]\nrun = 'echo \"verbose=$usage_verbose\"'\nusage = '''\nflag \"--verbose\"\n'''\nEOF\n\n# --verbose is a mise flag, so use -- to pass it to the task\nassert \"mise mytask -- --verbose\" \"verbose=true\"\nassert \"mise mytask\" \"verbose=\"\n"
  },
  {
    "path": "e2e/tasks/test_task_global_with_cwd_env",
    "content": "#!/usr/bin/env bash\n\n# Test that a global task with dir=\"{{cwd}}\" correctly inherits env vars from the project directory\n# Reproduces issue: https://github.com/jdx/mise/discussions/6716\n\n# Setup global config with a task that uses dir=\"{{cwd}}\"\ncat >~/.config/mise/config.toml <<EOF\n[tasks.test-global-task]\ndescription = \"Test task defined in global config with dir={{cwd}}\"\ndir = \"{{cwd}}\"\nrun = 'echo \"GLOBAL_VAR: \\$GLOBAL_VAR, PROJECT_VAR: \\$PROJECT_VAR\"'\n\n[env]\nGLOBAL_VAR = \"global-value\"\nEOF\n\n# Create a project directory with its own env vars\nPROJECT_DIR=\"$PWD/test-project\"\nmkdir -p \"$PROJECT_DIR\"\n\n# Project-level mise config with env vars\ncat >\"$PROJECT_DIR/mise.toml\" <<EOF\n[env]\nPROJECT_VAR = \"project-value\"\nGLOBAL_VAR = \"overridden-by-project\"\nEOF\n\n# Change to project directory and run the global task\ncd \"$PROJECT_DIR\"\n\n# Mark the project directory as trusted\nmise trust\n\n# Run the global task from the project directory\n# The task should inherit PROJECT_VAR and the overridden GLOBAL_VAR from the project config\n# The task should use the project-level env vars since dir=\"{{cwd}}\" means it runs in the project context\nassert_contains \"mise run test-global-task\" \"PROJECT_VAR: project-value\"\nassert_contains \"mise run test-global-task\" \"GLOBAL_VAR: overridden-by-project\"\n"
  },
  {
    "path": "e2e/tasks/test_task_help",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.atask]\nrun = 'echo {{arg(name=\"myarg\")}}'\n[tasks.npm]\nrun = 'echo npm'\nEOF\n\nassert \"mise run atask --help 2>&1 || true\" \"Usage: atask <myarg>\n\nArguments:\n  <myarg>\"\n\nassert_contains \"mise --help 2>&1 || true\" \"Usage: mise [OPTIONS] [TASK] [COMMAND]\"\nassert_contains \"mise install --help 2>&1 || true\" \"Usage: mise install [OPTIONS] [TOOL@VERSION]...\"\nassert_contains \"mise run --help 2>&1 || true\" \"Usage: run [OPTIONS] [TASK] [ARGS]...\"\nassert_contains \"mise atask -- --help 2>&1 || true\" \"Usage: atask <myarg>\"\n# If task has no usage defined, --help shows task info\nassert_contains \"mise run npm --help 2>&1 || true\" \"Task: npm\"\n# With --, --help is passed to the task script\nassert \"mise -q npm -- --help 2>&1 || true\" \"npm --help\"\nassert \"mise atask -q -- -- --help 2>&1 || true\" \"--help\"\nassert_contains \"mise run atask -q -- --help 2>&1 || true\" \"Usage: atask <myarg>\"\nassert_contains \"mise run atask -q -- foo --help 2>&1 || true\" \"Usage: atask <myarg>\"\nassert_contains \"mise run atask -q foo --help 2>&1 || true\" \"Usage: atask <myarg>\"\nassert_contains \"mise atask -q -- foo --help 2>&1 || true\" \"Usage: atask <myarg>\"\n# After the fix, --help shows task help even with extra args\nassert_contains \"mise atask -q foo --help 2>&1 || true\" \"Usage: atask <myarg>\"\n"
  },
  {
    "path": "e2e/tasks/test_task_help_with_cd",
    "content": "#!/usr/bin/env bash\n\n# Create a subdirectory with a task\nmkdir -p subdir\ncat <<EOF >subdir/mise.toml\n[tasks.build]\nrun = 'echo \"Building project\"'\ndescription = 'Build the project'\nEOF\n\n# For tasks WITHOUT usage spec, --help shows task info instead of executing\nassert_contains \"mise run --cd subdir build --help 2>&1 || true\" \"Task: build\"\nassert_contains \"mise run --cd subdir build --help 2>&1 || true\" \"Description: Build the project\"\n\n# -- separator still passes --help through to the task\nassert \"mise run --cd subdir build -- --help 2>&1 || true\" \"[build] $ echo \\\"Building project\\\" --help\nBuilding project --help\"\n\n# Also test with a task that has arguments\ncat <<EOF >subdir/mise.toml\n[tasks.deploy]\nrun = 'echo \"Deploying {{arg(name=\"env\")}}\"'\ndescription = 'Deploy to environment'\nEOF\n\nassert_contains \"mise run --cd subdir deploy --help 2>&1 || true\" \"Usage:\"\nassert_contains \"mise run --cd subdir deploy --help 2>&1 || true\" \"<env>\"\nassert_not_contains \"mise run --cd subdir deploy --help 2>&1 || true\" \"Deploying\"\n\n# Note: For tasks WITH usage specs (arg() calls), the usage library itself\n# intercepts --help even after --, so mise run deploy -- --help also shows help\n"
  },
  {
    "path": "e2e/tasks/test_task_idiomatic_version_file",
    "content": "#!/usr/bin/env bash\n\n# Test that tasks can use tools from idiomatic version files\n# Issue: Since v2025.10.3, idiomatic_version_file_enable_tools stopped working in task execution\n\n# First disable the parent /tmp/mise.toml experimental monorepo setting\n# to avoid interference with this test\nif [ -f /tmp/mise.toml ]; then\n\tmv /tmp/mise.toml /tmp/mise.toml.bak\n\ttrap \"mv /tmp/mise.toml.bak /tmp/mise.toml\" EXIT\nfi\n\n# Create a .node-version file\necho \"24.1.0\" >.node-version\n\n# Create mise.toml with idiomatic_version_file_enable_tools setting\ncat >mise.toml <<'EOF'\n[settings]\nidiomatic_version_file_enable_tools = [\"node\"]\n\n[tasks.call-node]\nrun = \"which node\"\nEOF\n\n# Trust the config\nmise trust\n\n# Install node from .node-version\nmise install\n\n# Run the task and verify it uses the mise-installed node\nassert_contains \"mise run call-node\" \".local/share/mise/installs/node/24\"\n"
  },
  {
    "path": "e2e/tasks/test_task_includes_glob",
    "content": "#!/usr/bin/env bash\n\n# Test glob pattern support in task_config.includes\n# See: https://github.com/jdx/mise/discussions/7860\n\n# Create a tasks directory with multiple task files\n# Note: Standalone task TOML files use a different format than mise.toml\nmkdir -p tasks\n\ncat <<EOF >tasks/build.toml\n[build]\nrun = 'echo \"building\"'\nEOF\n\ncat <<EOF >tasks/test.toml\n[test]\nrun = 'echo \"testing\"'\nEOF\n\ncat <<EOF >tasks/deploy.toml\n[deploy]\nrun = 'echo \"deploying\"'\nEOF\n\n# Create mise.toml with glob pattern in includes\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\"tasks/*.toml\"]\nEOF\n\n# Test that all tasks are discovered via glob pattern\nassert_contains \"mise tasks\" \"build\"\nassert_contains \"mise tasks\" \"test\"\nassert_contains \"mise tasks\" \"deploy\"\n\n# Test that the tasks actually run\nassert_contains \"mise run build\" \"building\"\nassert_contains \"mise run test\" \"testing\"\nassert_contains \"mise run deploy\" \"deploying\"\n\n# Test mixing glob with literal paths\ncat <<EOF >extra-tasks.toml\n[extra]\nrun = 'echo \"extra task\"'\nEOF\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\"tasks/*.toml\", \"extra-tasks.toml\"]\nEOF\n\nassert_contains \"mise tasks\" \"build\"\nassert_contains \"mise tasks\" \"extra\"\nassert_contains \"mise run extra\" \"extra task\"\n"
  },
  {
    "path": "e2e/tasks/test_task_info",
    "content": "#!/usr/bin/env bash\n\nmkdir -p mise-tasks && echo \"\" >mise-tasks/build.sh && chmod +x mise-tasks/build.sh\nassert \"mise tasks info build\" 'Task: build\nDescription:\nSource: ~/workdir/mise-tasks/build.sh\nFile: ~/workdir/mise-tasks/build.sh\n\nUsage Spec:\n  name build\n  bin build'\n\nassert_contains \"mise tasks info build.sh --json\" '\"name\": \"build\"'\n\nassert_json_partial_object \"mise tasks info build --json\" \"name,source,description\" '{\n  \"name\": \"build\",\n  \"source\": \"'\"$PWD\"'/mise-tasks/build.sh\",\n  \"description\": \"\"\n}'\n\nmise tasks add lint --depends \"build -v\" -- 'echo \"linting!\"'\nassert_json \"mise tasks info lint --json\" \"$(\n\tcat <<EOF\n{\n  \"name\": \"lint\",\n  \"aliases\": [],\n  \"description\": \"\",\n  \"source\": \"$(pwd)/mise.toml\",\n  \"depends\": [\n    [\n      \"build\",\n      \"-v\"\n    ]\n  ],\n  \"depends_post\": [],\n  \"wait_for\": [],\n  \"env\": [],\n  \"dir\": null,\n  \"hide\": false,\n  \"raw\": false,\n  \"interactive\": false,\n  \"sources\": [],\n  \"outputs\": [],\n  \"shell\": null,\n  \"quiet\": false,\n  \"silent\": false,\n  \"tools\": {},\n  \"run\": [\n    \"'echo \\\"linting!\\\"'\"\n  ],\n  \"file\": null,\n  \"usage_spec\": {\n    \"name\": \"lint\",\n    \"bin\": \"lint\",\n    \"cmd\": {\n      \"full_cmd\": [],\n      \"usage\": \"\",\n      \"subcommands\": {},\n      \"args\": [],\n      \"flags\": [],\n      \"mounts\": [],\n      \"hide\": false,\n      \"help\": \"\",\n      \"name\": \"lint\",\n      \"aliases\": [],\n      \"hidden_aliases\": [],\n      \"before_help_long\": \"- Depends: build -v\",\n      \"examples\": []\n    },\n    \"config\": {\n      \"props\": {}\n    },\n    \"usage\": \"\",\n    \"complete\": {}\n  }\n}\nEOF\n)\"\n"
  },
  {
    "path": "e2e/tasks/test_task_info_monorepo",
    "content": "#!/usr/bin/env bash\n\n# Tests for `mise tasks info` in a monorepo setup\n\ncat >mise.toml <<EOF\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"lib\"]\n\n[tasks.root_task]\nalias = \"some_root_task_alias\"\nrun = \"echo This is the root task\"\nEOF\n\nmkdir -p lib\ncat >lib/mise.toml <<EOF\n[tasks.echo]\nalias = [\"lib_echo_alias\", \"e\"]\nrun = \"\"\"\necho Hello, World!\n\"\"\"\nEOF\n\n# Test non-existent task\nassert_fail \"mise tasks info nonexistent\"\nassert_contains \"mise tasks info nonexistent 2>&1 || true\" \"Task not found: nonexistent\"\n\n# Test non-existent monorepo task\nassert_fail \"mise tasks info //lib:nonexistent\"\nassert_contains \"mise tasks info //lib:nonexistent 2>&1 || true\" \"Task not found: //lib:nonexistent\"\n\n# Test non-existent alias\nassert_fail \"mise tasks info //lib:fake_alias\"\nassert_contains \"mise tasks info //lib:fake_alias 2>&1 || true\" \"Task not found: //lib:fake_alias\"\n\n# Test root task info\nassert \"mise tasks info //:root_task\" 'Task: //:root_task\nAliases: some_root_task_alias\nDescription:\nSource: ~/workdir/mise.toml\n\nRun:\n  echo This is the root task\n\nUsage Spec:\n  name \"//:root_task\"\n  bin \"//:root_task\"'\n\nassert_contains \"mise tasks info //:root_task --json\" '\"name\": \"//:root_task\"'\n\n# test that shorthand works\nassert_contains \"mise tasks info root_task --json\" '\"name\": \"//:root_task\"'\nassert_contains \"mise tasks info some_root_task_alias --json\" '\"name\": \"//:root_task\"'\n\nassert \"mise tasks info //lib:echo\" 'Task: //lib:echo\nAliases: lib_echo_alias, e\nDescription:\nSource: ~/workdir/lib/mise.toml\n\nRun:\n  echo Hello, World!\n\nUsage Spec:\n  name \"//lib:echo\"\n  bin \"//lib:echo\"'\n\nassert_contains \"mise tasks info //lib:echo --json\" '\"name\": \"//lib:echo\"'\nassert_contains \"mise tasks info //lib:echo --json\" '\"source\": \"'\"$PWD\"'/lib/mise.toml\"'\n\n# Test lib task lookup by prefixed aliases (from root)\nassert_contains \"mise tasks info //lib:lib_echo_alias --json\" '\"name\": \"//lib:echo\"'\nassert_contains \"mise tasks info //lib:e --json\" '\"name\": \"//lib:echo\"'\n\n#### Test from subdirectory\ncd lib\n\n# Unprefixed aliases should work from within lib directory\nassert_contains \"mise tasks info lib_echo_alias --json\" '\"name\": \"//lib:echo\"'\nassert_contains \"mise tasks info e --json\" '\"name\": \"//lib:echo\"'\n\nassert \"mise tasks info //lib:echo\" 'Task: //lib:echo\nAliases: lib_echo_alias, e\nDescription:\nSource: ~/workdir/lib/mise.toml\n\nRun:\n  echo Hello, World!\n\nUsage Spec:\n  name \"//lib:echo\"\n  bin \"//lib:echo\"'\n"
  },
  {
    "path": "e2e/tasks/test_task_keep_order",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.a = \"echo a\"\ntasks.b = \"echo b\"\ntasks.c = \"echo c\"\ntasks.all.depends = ['a', 'b', 'c']\nEOF\nassert \"mise run -o keep-order all\" \"[a] a\n[b] b\n[c] c\"\n\ncat <<EOF >mise.toml\ntasks.a = \"echo a\"\ntasks.b = \"echo b ; exit 1\"\ntasks.all.depends = ['a', 'b']\nEOF\nassert_fail \"mise run -o keep-order all\" \"[b] b\"\n\n# Verify definition order is preserved even when later tasks finish first\ncat <<EOF >mise.toml\n[tasks.slow]\nrun = \"sleep 2 && echo slow\"\n\n[tasks.fast]\nrun = \"echo fast\"\n\n[tasks.all]\ndepends = ['slow', 'fast']\nEOF\noutput=$(MISE_JOBS=4 mise run -o keep-order all 2>&1)\nslow_pos=$(echo \"$output\" | grep -n '^\\[slow\\] slow$' | cut -d: -f1)\nfast_pos=$(echo \"$output\" | grep -n '^\\[fast\\] fast$' | cut -d: -f1)\nif [ \"$slow_pos\" -ge \"$fast_pos\" ]; then\n\techo \"keep-order did not preserve definition order: slow at $slow_pos, fast at $fast_pos\"\n\techo \"$output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_ls",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\n\t\"tasks.toml\",\n\t\"mytasks\",\n]\n[tasks.lint]\nrun = 'echo \"linting!\"'\nEOF\n\ncat <<EOF >tasks.toml\n[test]\nrun = 'echo \"testing!\"'\n[test-with-args]\nrun = 'echo \"{{arg()}} {{flag(name=\"force\")}} {{option(name=\"user\")}}\"'\ndepends = [\"test -v\", \"test\"]\nEOF\n\nmkdir -p .mise/tasks\ncat <<'EOF' >.mise/tasks/do-not-show\n#!/usr/bin/env bash\nEOF\nchmod +x .mise/tasks/do-not-show\n\nmkdir -p mytasks\ncat <<'EOF' >mytasks/filetask2\n#!/usr/bin/env bash\nEOF\nchmod +x mytasks/filetask2\n\ncat <<'EOF' >mytasks/filetask3.sh\n#!/usr/bin/env bash\nEOF\nchmod +x mytasks/filetask3.sh\n\nmkdir -p .config/mise/conf.d\ncat <<'EOF' >.config/mise/conf.d/confdtask-config.toml\n[tasks.confdtask]\nrun = 'echo \"confdtask\"'\nEOF\n\nassert \"mise tasks ls\" \"confdtask\nfiletask2\nfiletask3\nlint\ntest\ntest-with-args\"\n\nassert \"mise tasks -x ls\" \"confdtask          ./.config/mise/conf.d/confdtask-config.toml\nfiletask2          ./mytasks/filetask2\nfiletask3          ./mytasks/filetask3.sh\nlint               ./mise.toml\ntest               ./tasks.toml\ntest-with-args     ./tasks.toml\"\n\nassert_json \"mise tasks ls --json\" \"$(\n\tcat <<EOF\n[\n {\n   \"name\": \"confdtask\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/.config/mise/conf.d/confdtask-config.toml\",\n   \"depends\": [],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [\n     \"echo \\\"confdtask\\\"\"\n   ],\n   \"args\": [],\n   \"file\": null\n },\n {\n   \"name\": \"filetask2\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/mytasks/filetask2\",\n   \"depends\": [],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [],\n   \"args\": [],\n   \"file\": \"$(pwd)/mytasks/filetask2\"\n },\n {\n   \"name\": \"filetask3\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/mytasks/filetask3.sh\",\n   \"depends\": [],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [],\n   \"args\": [],\n   \"file\": \"$(pwd)/mytasks/filetask3.sh\"\n },\n {\n   \"name\": \"lint\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/mise.toml\",\n   \"depends\": [],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [\n     \"echo \\\"linting!\\\"\"\n   ],\n   \"args\": [],\n   \"file\": null\n },\n {\n   \"name\": \"test\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/tasks.toml\",\n   \"depends\": [],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [\n     \"echo \\\"testing!\\\"\"\n   ],\n   \"args\": [],\n   \"file\": null\n },\n {\n   \"name\": \"test-with-args\",\n   \"aliases\": [],\n   \"description\": \"\",\n   \"source\": \"$(pwd)/tasks.toml\",\n   \"depends\": [\n      [\"test\",\"-v\"],\n      \"test\"\n   ],\n   \"depends_post\": [],\n   \"wait_for\": [],\n   \"env\": [],\n   \"dir\": null,\n   \"hide\": false,\n   \"global\": false,\n   \"raw\": false,\n   \"interactive\": false,\n   \"sources\": [],\n   \"outputs\": [],\n   \"shell\": null,\n   \"quiet\": false,\n   \"silent\": false,\n   \"tools\": {},\n   \"usage\": \"\",\n   \"timeout\": null,\n   \"run\": [\n     \"echo \\\"{{arg()}} {{flag(name=\\\"force\\\")}} {{option(name=\\\"user\\\")}}\\\"\"\n   ],\n   \"args\": [],\n   \"file\": null\n }\n]\nEOF\n)\"\n"
  },
  {
    "path": "e2e/tasks/test_task_ls_complete_monorepo",
    "content": "#!/usr/bin/env bash\n# Verify task completion output includes monorepo tasks when using // paths\n\n# Root config marks repo as monorepo\ncat <<'CONFIG' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"apps/*\"]\n\n[tasks.root-task]\nrun = 'echo root'\nCONFIG\n\n# App subproject task that should appear in completions\nmkdir -p apps/web\ncat <<'CONFIG' >apps/web/mise.toml\n[tasks.update-snapshots]\ndescription = \"Update monorepo snapshots\"\nrun = 'echo updating snapshots'\nCONFIG\n\n# Completion output should include the //-prefixed task path with escaped colon\nassert_contains \"mise task ls --complete\" '//apps/web\\:update-snapshots:Update monorepo snapshots'\n"
  },
  {
    "path": "e2e/tasks/test_task_ls_global",
    "content": "#!/usr/bin/env bash\n\necho \"tasks.mylocal = { run = 'echo mylocal' }\" >mise.toml\necho \"tasks.myglobal = { run = 'echo myglobal' }\" >~/.config/mise/config.toml\nmkdir -p ~/.config/mise/tasks\ncat <<'EOF' >~/.config/mise/tasks/myglobalfile\n#!/usr/bin/env bash\necho myglobalfile\nEOF\nchmod +x ~/.config/mise/tasks/myglobalfile\n\nassert \"mise tasks\" \"myglobal\nmyglobalfile\nmylocal\"\nassert \"mise tasks --local\" \"mylocal\"\nassert \"mise tasks --global\" \"myglobal\nmyglobalfile\"\n"
  },
  {
    "path": "e2e/tasks/test_task_ls_usage",
    "content": "#!/usr/bin/env bash\n\n# Test the `mise tasks ls --usage` functionality (display_usage)\n\n# Test 1: Basic usage output with simple tasks\ncat <<EOF >mise.toml\n[tasks.simple]\nrun = 'echo \"simple task\"'\ndescription = \"A simple task with no arguments\"\n\n[tasks.with-args]\nrun = 'echo \"arg={{arg(name=\"myarg\")}}\"'\ndescription = \"Task with arguments\"\n\n[tasks.with-flags]\nrun = 'echo \"verbose={{flag(name=\"verbose\")}}\"'\ndescription = \"Task with flags\"\nEOF\n\n# Test basic usage output format contains expected tasks\nassert_contains \"mise tasks ls --usage\" 'cmd simple help=\"A simple task with no arguments\"'\nassert_contains \"mise tasks ls --usage\" 'cmd with-args help=\"Task with arguments\"'\nassert_contains \"mise tasks ls --usage\" 'cmd with-flags help=\"Task with flags\"'\n\n# Test 2: Tasks with aliases and dependencies\ncat <<EOF >mise.toml\n[tasks.parent]\nrun = 'echo \"parent\"'\ndescription = \"Parent task\"\n\n[tasks.child]\nrun = 'echo \"child\"'\ndescription = \"Child task\"\nalias = \"c\"\ndepends = [\"parent\"]\nEOF\n\nassert_contains \"mise tasks ls --usage\" 'cmd parent help=\"Parent task\"'\nassert_contains \"mise tasks ls --usage\" 'cmd child help=\"Child task\"'\nassert_contains \"mise tasks ls --usage\" 'alias c'\n\n# Test 3: File-based tasks\nmkdir -p mise-tasks\ncat <<'EOF' >mise-tasks/file-task\n#!/usr/bin/env bash\n#MISE description=\"A file-based task\"\necho \"file task\"\nEOF\nchmod +x mise-tasks/file-task\n\nassert_contains \"mise tasks ls --usage\" 'cmd file-task help=\"A file-based task\"'\n\n# Test 4: Hidden tasks should not appear\ncat <<EOF >mise.toml\n[tasks.visible]\nrun = 'echo \"visible\"'\ndescription = \"Visible task\"\n\n[tasks.hidden]\nrun = 'echo \"hidden\"'\ndescription = \"Hidden task\"\nhide = true\nEOF\n\nassert_contains \"mise tasks ls --usage\" 'cmd visible help=\"Visible task\"'\nassert_not_contains \"mise tasks ls --usage\" 'cmd hidden help=\"Hidden task\"'\n\n# Test 5: Task with no description\ncat <<EOF >mise.toml\n[tasks.no-desc]\nrun = 'echo \"no description\"'\nEOF\n\nassert_contains \"mise tasks ls --usage\" 'cmd no-desc'\n\n# Test 6: Performance test - should be fast even with complex environment\ncat <<EOF >mise.toml\n[tasks.complex-env]\nrun = 'echo \"arg={{arg(name=\"test_arg\")}}\"'\ndescription = \"Task with complex environment\"\n\n[tasks.complex-env.env]\nTEST_VAR = \"test_value\"\n\n[tasks.complex-env.tools]\nnode = \"latest\"\nEOF\n\n# This should complete quickly (within 5 seconds)\ntimeout 5 mise tasks ls --usage >/dev/null || fail \"Usage generation took too long\"\n\necho \"All usage display tests passed!\"\n"
  },
  {
    "path": "e2e/tasks/test_task_mise_env_profiles",
    "content": "#!/usr/bin/env bash\n\n# Test that tasks properly inherit environment from MISE_ENV-specific config files\n# Regression test for issue where monorepo task changes broke MISE_ENV env inheritance\n\n# Test 1 & 2: Basic MISE_ENV inheritance\ncat <<EOF >mise.toml\n[env]\nTEST_VAR = \"base_value\"\n\n[tasks.print-env]\nrun = 'echo \"TEST_VAR=\\$TEST_VAR\"'\nEOF\n\ncat <<EOF >.mise.override.toml\n[env]\nTEST_VAR = \"override_value\"\nOVERRIDE_ONLY_VAR = \"from_override_config\"\nEOF\n\n# Update task to print both variables\ncat <<EOF >mise.toml\n[env]\nTEST_VAR = \"base_value\"\n\n[tasks.print-env]\nrun = 'echo \"TEST_VAR=\\$TEST_VAR OVERRIDE_ONLY_VAR=\\$OVERRIDE_ONLY_VAR\"'\nEOF\n\n# Test 1: Task should use base value without MISE_ENV\nassert \"mise run print-env\" \"TEST_VAR=base_value OVERRIDE_ONLY_VAR=\"\n\n# Test 2: Task should use override value with MISE_ENV=override\nMISE_ENV=override assert \"mise run print-env\" \"TEST_VAR=override_value OVERRIDE_ONLY_VAR=from_override_config\"\n\n# Clean up for next test\nrm -f mise.toml .mise.override.toml\n\n# Test 3: Test with multiple environment profiles\ncat <<EOF >.mise.production.toml\n[env]\nTEST_VAR = \"production_value\"\nDATABASE_URL = \"postgres://prod\"\nEOF\n\ncat <<EOF >.mise.staging.toml\n[env]\nTEST_VAR = \"staging_value\"\nDATABASE_URL = \"postgres://staging\"\nEOF\n\ncat <<EOF >mise.toml\n[env]\nTEST_VAR = \"base_value\"\nDATABASE_URL = \"postgres://local\"\n\n[tasks.print-all-env]\nrun = 'echo \"TEST_VAR=\\$TEST_VAR DATABASE_URL=\\$DATABASE_URL\"'\nEOF\n\n# Test with different MISE_ENV values\nassert \"mise run print-all-env\" \"TEST_VAR=base_value DATABASE_URL=postgres://local\"\nMISE_ENV=production assert \"mise run print-all-env\" \"TEST_VAR=production_value DATABASE_URL=postgres://prod\"\nMISE_ENV=staging assert \"mise run print-all-env\" \"TEST_VAR=staging_value DATABASE_URL=postgres://staging\"\n\n# Test 4: Multiple MISE_ENV profiles (later ones override earlier ones)\nMISE_ENV=staging,production assert \"mise run print-all-env\" \"TEST_VAR=production_value DATABASE_URL=postgres://prod\"\n\n# Clean up for next test\nrm -f mise.toml .mise.production.toml .mise.staging.toml\n\n# Test 5: Task-specific env should override both base config and MISE_ENV config\ncat <<EOF >mise.toml\n[env]\nTEST_VAR = \"base_value\"\n\n[tasks.task-with-env]\nrun = 'echo \"TEST_VAR=\\$TEST_VAR\"'\n[tasks.task-with-env.env]\nTEST_VAR = \"task_override_value\"\nEOF\n\ncat <<EOF >.mise.custom.toml\n[env]\nTEST_VAR = \"custom_value\"\nEOF\n\n# Task env should override base config\nassert \"mise run task-with-env\" \"TEST_VAR=task_override_value\"\n# Task env should also override MISE_ENV config\nMISE_ENV=custom assert \"mise run task-with-env\" \"TEST_VAR=task_override_value\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_aliases",
    "content": "#!/usr/bin/env bash\n# Test that task aliases work properly in monorepo mode\n# Regression test for: https://github.com/jdx/mise/discussions/6854\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config with tasks that have aliases\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.format]\nalias = \"fmt\"\nrun = \"echo 'formatting code'\"\n\n[tasks.lint]\nalias = [\"l\", \"check\"]\nrun = \"echo 'linting code'\"\nTOML\n\n# Test 1: Running root task by full name\necho \"=== Test 1: Run root task by full name ===\"\noutput=$(mise run //:format 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"formatting code\" || (echo \"FAIL: Task did not run\" && exit 1)\n\n# Test 2: Running root task by alias (without //)\necho \"=== Test 2: Run root task by alias (without //) ===\"\noutput=$(mise run fmt 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"formatting code\" || (echo \"FAIL: Alias did not work\" && exit 1)\n\n# Test 3: Running root task by alias (with //)\necho \"=== Test 3: Run root task by alias (with //) ===\"\noutput=$(mise run //:fmt 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"formatting code\" || (echo \"FAIL: Alias with // prefix did not work\" && exit 1)\n\n# Test 4: Running task with multiple aliases\necho \"=== Test 4: Run task with multiple aliases ===\"\noutput=$(mise run //:l 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"linting code\" || (echo \"FAIL: First alias did not work\" && exit 1)\n\noutput=$(mise run //:check 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"linting code\" || (echo \"FAIL: Second alias did not work\" && exit 1)\n\n# Test 5: Nested project task with alias\nmkdir -p projects/backend\ncat <<'TOML' >projects/backend/mise.toml\n[tasks.build]\nalias = \"b\"\nrun = \"echo 'building backend'\"\nTOML\n\necho \"=== Test 5: Run nested project task by alias ===\"\noutput=$(mise run //projects/backend:b 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"building backend\" || (echo \"FAIL: Nested task alias did not work\" && exit 1)\n\n# Test 6: Task depends using alias\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.format]\nalias = \"fmt\"\nrun = \"echo 'formatting code'\"\n\n[tasks.deploy]\ndepends = [\"//:fmt\"]\nrun = \"echo 'deploying'\"\nTOML\n\necho \"=== Test 6: Task depends on alias ===\"\noutput=$(mise run //:deploy 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"formatting code\" || (echo \"FAIL: Dependency alias did not resolve\" && exit 1)\necho \"$output\" | grep -q \"deploying\" || (echo \"FAIL: Dependent task did not run\" && exit 1)\n\n# Test 7: Task depends on unprefixed alias (should resolve to monorepo task)\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.format]\nalias = \"fmt\"\nrun = \"echo 'formatting code'\"\n\n[tasks.test]\ndepends = [\"fmt\"]\nrun = \"echo 'running tests'\"\nTOML\n\necho \"=== Test 7: Task depends on unprefixed alias ===\"\noutput=$(mise run //:test 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"formatting code\" || (echo \"FAIL: Unprefixed dependency alias did not resolve\" && exit 1)\necho \"$output\" | grep -q \"running tests\" || (echo \"FAIL: Test task did not run\" && exit 1)\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_circular_deps",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task circular dependency detection\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Trust the root config so it can run\nmise trust\n\n# Test 1: Direct circular dependency (a -> b -> a)\necho \"=== Test 1: Direct circular dependency ===\"\nmkdir -p projects/circ1\ncat <<EOF >projects/circ1/mise.toml\n[tasks.a]\nrun = 'echo \"task a\"'\ndepends = [\":b\"]\n\n[tasks.b]\nrun = 'echo \"task b\"'\ndepends = [\":a\"]\nEOF\n\n# Should error with circular dependency\noutput=$(timeout 3 mise run '//projects/circ1:a' 2>&1 || true)\nif echo \"$output\" | grep -qiE \"circular dependency detected\"; then\n\techo \"SUCCESS: Direct circular dependency detected\"\nelse\n\techo \"Output: $output\"\n\techo \"ERROR: Expected circular dependency detection\"\n\texit 1\nfi\n\n# Test 2: Transitive circular dependency (a -> b -> c -> a)\necho \"=== Test 2: Transitive circular dependency ===\"\nmkdir -p projects/circ2\ncat <<EOF >projects/circ2/mise.toml\n[tasks.a]\nrun = 'echo \"task a\"'\ndepends = [\":b\"]\n\n[tasks.b]\nrun = 'echo \"task b\"'\ndepends = [\":c\"]\n\n[tasks.c]\nrun = 'echo \"task c\"'\ndepends = [\":a\"]\nEOF\n\noutput=$(timeout 3 mise run '//projects/circ2:a' 2>&1 || true)\nif echo \"$output\" | grep -qiE \"circular dependency detected\"; then\n\techo \"SUCCESS: Transitive circular dependency detected\"\nelse\n\techo \"Output: $output\"\n\techo \"ERROR: Expected circular dependency detection\"\n\texit 1\nfi\n\n# Test 3: Cross-project circular dependency\necho \"=== Test 3: Cross-project circular dependency ===\"\nmkdir -p projects/frontend projects/backend\ncat <<EOF >projects/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\ndepends = [\"//projects/backend:build\"]\nEOF\n\ncat <<EOF >projects/backend/mise.toml\n[tasks.build]\nrun = 'echo \"backend build\"'\ndepends = [\"//projects/frontend:build\"]\nEOF\n\noutput=$(timeout 3 mise run '//projects/frontend:build' 2>&1 || true)\nif echo \"$output\" | grep -qiE \"circular dependency detected\"; then\n\techo \"SUCCESS: Cross-project circular dependency detected\"\nelse\n\techo \"Output: $output\"\n\techo \"ERROR: Expected circular dependency detection\"\n\texit 1\nfi\n\n# Test 4: Self-dependency (should be caught)\necho \"=== Test 4: Self-dependency ===\"\nmkdir -p projects/self\ncat <<EOF >projects/self/mise.toml\n[tasks.build]\nrun = 'echo \"build\"'\ndepends = [\":build\"]\nEOF\n\noutput=$(timeout 3 mise run '//projects/self:build' 2>&1 || true)\n# Self-dependency is filtered out at line 327 in mod.rs, so it should run successfully\nif echo \"$output\" | grep -q \"build\"; then\n\techo \"SUCCESS: Self-dependency silently filtered (task ran once)\"\nelse\n\techo \"Output: $output\"\n\techo \"ERROR: Expected self-dependency to be filtered and task to run\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_config_context",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks use tools and env vars from their subdirectory mise.toml files\nexport MISE_EXPERIMENTAL=1\nexport MISE_NODE_VERIFY=0 # Skip GPG verification to avoid keyboxd issues\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\", \"libs/*\"]\n\n[env]\nROOT_VAR = \"root_value\"\nSHARED_VAR = \"root_shared\"\n\n[tools]\n# Root has no tools defined\n\n[tasks.root-task]\nrun = 'echo \"ROOT_VAR=\\$ROOT_VAR SHARED_VAR=\\$SHARED_VAR\"'\nEOF\n\n# Create frontend project with its own tools and env\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[env]\nFRONTEND_VAR = \"frontend_value\"\nSHARED_VAR = \"frontend_shared\"\nNODE_ENV = \"development\"\n\n[tools]\nnode = \"20\"\n\n[tasks.build]\nrun = '''\necho \"FRONTEND_VAR=\\$FRONTEND_VAR\"\necho \"SHARED_VAR=\\$SHARED_VAR\"\necho \"NODE_ENV=\\$NODE_ENV\"\necho \"ROOT_VAR=\\$ROOT_VAR\"\necho \"NODE_VERSION=\\$(node --version | sed 's/v//' | cut -d. -f1)\"\n'''\n\n[tasks.test]\nrun = 'echo \"frontend test\"'\nenv.TEST_VAR = \"from_task\"\nEOF\n\n# Create backend project with its own tools and env\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n[env]\nBACKEND_VAR = \"backend_value\"\nSHARED_VAR = \"backend_shared\"\nDATABASE_URL = \"postgres://localhost/backend\"\n\n[tools]\nnode = \"18\"\n\n[tasks.build]\nrun = '''\necho \"BACKEND_VAR=\\$BACKEND_VAR\"\necho \"SHARED_VAR=\\$SHARED_VAR\"\necho \"DATABASE_URL=\\$DATABASE_URL\"\necho \"ROOT_VAR=\\$ROOT_VAR\"\necho \"NODE_VERSION=\\$(node --version | sed 's/v//' | cut -d. -f1)\"\n'''\n\n[tasks.deploy]\nrun = 'echo \"deploying backend\"'\nEOF\n\n# Create libs/shared with minimal config\nmkdir -p libs/shared\ncat <<EOF >libs/shared/mise.toml\n[env]\nSHARED_LIB_VAR = \"shared_lib_value\"\n\n[tasks.build]\nrun = 'echo \"SHARED_LIB_VAR=\\$SHARED_LIB_VAR\"'\nEOF\n\n# Test 1: Root task should use root env vars\necho \"=== Test 1: Root task uses root env ===\"\nassert_contains \"mise run //:root-task\" \"ROOT_VAR=root_value\"\nassert_contains \"mise run //:root-task\" \"SHARED_VAR=root_shared\"\n\n# Test 2: Frontend task should use frontend env vars\necho \"=== Test 2: Frontend task uses frontend env ===\"\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\necho \"$output\" | grep -q \"FRONTEND_VAR=frontend_value\" || (echo \"FAIL: FRONTEND_VAR not set correctly\" && exit 1)\necho \"$output\" | grep -q \"SHARED_VAR=frontend_shared\" || (echo \"FAIL: SHARED_VAR not overridden by frontend\" && exit 1)\necho \"$output\" | grep -q \"NODE_ENV=development\" || (echo \"FAIL: NODE_ENV not set\" && exit 1)\n# ROOT_VAR should still be accessible (inherited from root)\necho \"$output\" | grep -q \"ROOT_VAR=root_value\" || (echo \"FAIL: ROOT_VAR not inherited\" && exit 1)\n# Should declare node 20 from frontend config\necho \"$output\" | grep -q \"NODE_VERSION=20\" || (echo \"FAIL: Node version not 20\" && exit 1)\n\n# Test 3: Backend task should use backend env vars and tools\necho \"=== Test 3: Backend task uses backend env and tools ===\"\noutput=$(mise run '//projects/backend:build')\necho \"$output\"\necho \"$output\" | grep -q \"BACKEND_VAR=backend_value\" || (echo \"FAIL: BACKEND_VAR not set\" && exit 1)\necho \"$output\" | grep -q \"SHARED_VAR=backend_shared\" || (echo \"FAIL: SHARED_VAR not overridden by backend\" && exit 1)\necho \"$output\" | grep -q \"DATABASE_URL=postgres://localhost/backend\" || (echo \"FAIL: DATABASE_URL not set\" && exit 1)\necho \"$output\" | grep -q \"ROOT_VAR=root_value\" || (echo \"FAIL: ROOT_VAR not inherited in backend\" && exit 1)\n# Should declare node 18 from backend config\necho \"$output\" | grep -q \"NODE_VERSION=18\" || (echo \"FAIL: Node version not 18\" && exit 1)\n\n# Test 4: Task-specific env should override config env\necho \"=== Test 4: Task-specific env overrides config env ===\"\noutput=$(mise run '//projects/frontend:test')\necho \"$output\"\n# Task defines TEST_VAR, should be available\n# Note: This test just verifies the task runs; we'd need to modify the task to echo TEST_VAR to verify it\n\n# Test 5: Libs task should use lib env\necho \"=== Test 5: Shared lib task uses shared lib env ===\"\noutput=$(mise run '//libs/shared:build')\necho \"$output\"\necho \"$output\" | grep -q \"SHARED_LIB_VAR=shared_lib_value\" || (echo \"FAIL: SHARED_LIB_VAR not set\" && exit 1)\n\n# Test 6: Running multiple monorepo tasks should use correct context for each\necho \"=== Test 6: Multiple tasks use correct contexts ===\"\noutput=$(mise run '//projects/frontend:build' ::: '//projects/backend:build')\necho \"$output\"\n# Frontend output should have frontend vars and declare node 20\necho \"$output\" | grep -q \"FRONTEND_VAR=frontend_value\" || (echo \"FAIL: Frontend vars not in multi-task output\" && exit 1)\necho \"$output\" | grep -q \"NODE_VERSION=20\" || (echo \"FAIL: Node 20 not in multi-task output\" && exit 1)\n# Backend output should have backend vars and declare node 18\necho \"$output\" | grep -q \"BACKEND_VAR=backend_value\" || (echo \"FAIL: Backend vars not in multi-task output\" && exit 1)\necho \"$output\" | grep -q \"NODE_VERSION=18\" || (echo \"FAIL: Node 18 not in multi-task output\" && exit 1)\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_config_roots",
    "content": "#!/usr/bin/env bash\n# Test [monorepo].config_roots for explicit config root listing\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config with explicit config_roots\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\n    \"packages/frontend\",\n    \"packages/backend\",\n    \"services/*\",\n]\n\n[tasks.root]\nrun = 'echo \"root task\"'\nTOML\n\n# Create packages that ARE in config_roots\nmkdir -p packages/frontend\ncat <<'TOML' >packages/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\nTOML\n\nmkdir -p packages/backend\ncat <<'TOML' >packages/backend/mise.toml\n[tasks.build]\nrun = 'echo \"backend build\"'\nTOML\n\n# Create services/* for glob test\nmkdir -p services/api\ncat <<'TOML' >services/api/mise.toml\n[tasks.serve]\nrun = 'echo \"api serve\"'\nTOML\n\nmkdir -p services/worker\ncat <<'TOML' >services/worker/mise.toml\n[tasks.process]\nrun = 'echo \"worker process\"'\nTOML\n\n# Create a package that is NOT in config_roots (should NOT be discovered)\nmkdir -p packages/ignored\ncat <<'TOML' >packages/ignored/mise.toml\n[tasks.hidden]\nrun = 'echo \"this should not appear\"'\nTOML\n\n# Create another directory that is NOT in config_roots\nmkdir -p libs/common\ncat <<'TOML' >libs/common/mise.toml\n[tasks.test]\nrun = 'echo \"this should not appear either\"'\nTOML\n\n# Test 1: Listed explicit paths are discovered\necho \"=== Test 1: Explicit paths are discovered ===\"\noutput=$(mise tasks --all 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"//packages/frontend:build\" || (echo \"FAIL: frontend not found\" && exit 1)\necho \"$output\" | grep -q \"//packages/backend:build\" || (echo \"FAIL: backend not found\" && exit 1)\n\n# Test 2: Glob patterns work (services/*)\necho \"=== Test 2: Glob patterns work ===\"\necho \"$output\" | grep -q \"//services/api:serve\" || (echo \"FAIL: services/api not found via glob\" && exit 1)\necho \"$output\" | grep -q \"//services/worker:process\" || (echo \"FAIL: services/worker not found via glob\" && exit 1)\n\n# Test 3: Unlisted paths are NOT discovered\necho \"=== Test 3: Unlisted paths are not discovered ===\"\nif echo \"$output\" | grep -q \"//packages/ignored:hidden\"; then\n\techo \"FAIL: packages/ignored should NOT be discovered\"\n\texit 1\nfi\nif echo \"$output\" | grep -q \"//libs/common:test\"; then\n\techo \"FAIL: libs/common should NOT be discovered\"\n\texit 1\nfi\n\n# Test 4: Tasks can still be run\necho \"=== Test 4: Tasks can be run ===\"\nmise run '//packages/frontend:build' | grep -q \"frontend build\" || (echo \"FAIL: couldn't run frontend task\" && exit 1)\nmise run '//services/api:serve' | grep -q \"api serve\" || (echo \"FAIL: couldn't run api task\" && exit 1)\n\necho \"=== All config_roots tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_dependencies",
    "content": "#!/usr/bin/env bash\n# Test that task dependencies work across different monorepo subdirectories\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-setup]\nrun = 'echo \"root-setup-done\" > /tmp/root-setup.txt'\nTOML\n\n# Create frontend that depends on root task\nmkdir -p projects/frontend\ncat <<'TOML' >projects/frontend/mise.toml\n[env]\nFRONTEND_ENV = \"production\"\n\n[tasks.build]\ndepends = [\"//:root-setup\"]\nrun = '''\necho \"Building frontend\"\nif [ ! -f /tmp/root-setup.txt ]; then\n  echo \"FAIL: root setup not run\"\n  exit 1\nfi\necho \"frontend built successfully\"\n'''\n\nTOML\n\n# Create backend that depends on shared lib\nmkdir -p projects/backend\ncat <<'TOML' >projects/backend/mise.toml\n[env]\nBACKEND_ENV = \"production\"\n\n[tasks.build]\ndepends = [\"//projects/frontend:build\"]\nrun = '''\necho \"Building backend (depends on frontend)\"\necho \"backend built successfully\"\n'''\n\n[tasks.deploy]\ndepends = [\"//projects/backend:build\", \"//projects/frontend:build\"]\nrun = '''\necho \"Deploying backend\"\necho \"Backend and frontend both built, deploying...\"\n'''\nTOML\n\n# Clean up any previous test artifacts\nrm -f /tmp/shared-lib.txt /tmp/root-setup.txt\n\n# Test 1: Frontend build depends on root task\necho \"=== Test 1: Frontend depends on root task ===\"\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\n# Root setup task ran (check by file existence - output may not show the echo)\n[ -f /tmp/root-setup.txt ] || (echo \"FAIL: Root setup not run\" && exit 1)\necho \"$output\" | grep -q \"frontend built successfully\" || (echo \"FAIL: Frontend build failed\" && exit 1)\n\n# Clean up for next test\nrm -f /tmp/shared-lib.txt /tmp/root-setup.txt\n\n# Test 2: Backend deploy depends on multiple projects\necho \"=== Test 2: Backend deploy depends on frontend (cross-project dependency) ===\"\noutput=$(mise run '//projects/backend:deploy')\necho \"$output\"\necho \"$output\" | grep -q \"Building backend\" || (echo \"FAIL: Backend not built\" && exit 1)\necho \"$output\" | grep -q \"Building frontend\" || (echo \"FAIL: Frontend not built as dependency\" && exit 1)\necho \"$output\" | grep -q \"Deploying backend\" || (echo \"FAIL: Backend deploy not run\" && exit 1)\n\n# Clean up\nrm -f /tmp/shared-lib.txt /tmp/root-setup.txt\n\necho \"=== All dependency tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_dependency_chain",
    "content": "#!/usr/bin/env bash\n# Test that task dependencies work with chains of local deps that include monorepo deps\n# Reproduces issue from https://github.com/jdx/mise/discussions/6564#discussioncomment-14669227\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"ProjectA\", \"ProjectB\"]\nTOML\n\n# Create ProjectB with a build task\nmkdir -p ProjectB\ncat <<'TOML' >ProjectB/mise.toml\n[tasks.build]\nrun = 'echo \"ProjectB build completed\"'\nTOML\n\n# Create ProjectA with a chain of dependencies\nmkdir -p ProjectA\ncat <<'TOML' >ProjectA/mise.toml\n[tasks.B]\ndepends = [\":C\"]\nrun = 'echo \"Task B executing\"'\n\n[tasks.C]\ndepends = [\":A\"]\nrun = 'echo \"Task C executing\"'\n\n[tasks.A]\ndepends = [\"//ProjectB:build\"]\nrun = 'echo \"Task A executing\"'\nTOML\n\n# Test: Run task B which depends on :C -> :A -> //ProjectB:build\necho \"=== Test: Task dependency chain with local and monorepo deps ===\"\noutput=$(mise run '//ProjectA:B')\necho \"$output\"\n\n# Verify all tasks ran in the correct order\necho \"$output\" | grep -q \"ProjectB build completed\" || (echo \"FAIL: ProjectB:build did not run\" && exit 1)\necho \"$output\" | grep -q \"Task A executing\" || (echo \"FAIL: Task A did not run\" && exit 1)\necho \"$output\" | grep -q \"Task C executing\" || (echo \"FAIL: Task C did not run\" && exit 1)\necho \"$output\" | grep -q \"Task B executing\" || (echo \"FAIL: Task B did not run\" && exit 1)\n\necho \"=== Dependency chain test passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_deps",
    "content": "#!/usr/bin/env bash\n\n# Test that :task dependency syntax works correctly in monorepo tasks\n# This tests the fix for: https://github.com/jdxcode/mise/issues/XXXX\n# When a task in a submodule has a dependency like `:before`, it should\n# resolve to the task in the same submodule, not fail with \"task not found\"\n\nexport MISE_EXPERIMENTAL=1\n\n# Set up monorepo structure\ncat <<'EOF' >mise.toml\nmin_version = \"2025.10.6\"\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"submodule\", \"project\", \"other\"]\n\n[settings]\nexperimental = true\nEOF\n\nmkdir -p submodule\ncat <<'EOF' >submodule/mise.toml\n[tasks.before]\nrun = 'echo \"before task executed\"'\n\n[tasks.\"do:item-1\"]\ndepends = [\":before\"]\nrun = 'echo \"do:item-1 task executed\"'\n\n[tasks.\"test:nested\"]\ndepends = [\":before\"]\nrun = 'echo \"test:nested task executed\"'\nEOF\n\n# Test 1: Task with colon in name should resolve dependencies correctly\n# The task //submodule:do:item-1 depends on :before, which should resolve to //submodule:before\nassert_contains \"mise run //submodule:do:item-1\" \"before task executed\"\nassert_contains \"mise run //submodule:do:item-1\" \"do:item-1 task executed\"\n\n# Test 2: Another task with colon should also work\nassert_contains \"mise run //submodule:test:nested\" \"before task executed\"\nassert_contains \"mise run //submodule:test:nested\" \"test:nested task executed\"\n\n# Test 3: Test with depends_post\nmkdir -p project\ncat <<'EOF' >project/mise.toml\n[tasks.cleanup]\nrun = 'echo \"cleanup task executed\"'\n\n[tasks.\"build:prod\"]\ndepends_post = [\":cleanup\"]\nrun = 'echo \"build:prod task executed\"'\nEOF\n\nassert_contains \"mise run //project:build:prod\" \"build:prod task executed\"\nassert_contains \"mise run //project:build:prod\" \"cleanup task executed\"\n\n# Test 4: Verify that dependencies are correctly scoped to their module\n# :before in other module should resolve to //other:before, not //submodule:before\nmkdir -p other\ncat <<'EOF' >other/mise.toml\n[tasks.before]\nrun = 'echo \"other before task executed\"'\n\n[tasks.\"main:task\"]\ndepends = [\":before\"]\nrun = 'echo \"other main task executed\"'\nEOF\n\n# Should run the \"other before\" task, not the \"submodule before\" task\nOUTPUT=$(mise run //other:main:task)\nassert_contains \"mise run //other:main:task\" \"other before task executed\"\nassert_contains \"mise run //other:main:task\" \"other main task executed\"\n\n# Verify it's NOT running the submodule's \"before\" task\nif echo \"$OUTPUT\" | grep -q \"before task executed\" && ! echo \"$OUTPUT\" | grep -q \"other before\"; then\n\techo \"ERROR: Task dependency incorrectly resolved to different module's task\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_dots_in_dir",
    "content": "#!/usr/bin/env bash\n# Test monorepo tasks with dots in directory names\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task executed\"'\nTOML\n\n# Create projects with dots in directory names\nmkdir -p \"projects/my.app\"\ncat <<'TOML' >\"projects/my.app/mise.toml\"\n[tasks.build]\nrun = 'echo \"building my.app\"'\n\n[tasks.test]\nrun = 'echo \"testing my.app\"'\nTOML\n\nmkdir -p \"projects/my.service.api\"\ncat <<'TOML' >\"projects/my.service.api/mise.toml\"\n[tasks.build]\nrun = 'echo \"building my.service.api\"'\n\n[tasks.deploy]\ndepends = [\"//projects/my.app:build\"]\nrun = 'echo \"deploying my.service.api\"'\nTOML\n\nmkdir -p \"projects/feature.v2.beta\"\ncat <<'TOML' >\"projects/feature.v2.beta/mise.toml\"\n[tasks.test]\nrun = 'echo \"testing feature.v2.beta\"'\nTOML\n\n# Test 1: List tasks for directory with single dot\necho \"=== Test 1: List tasks for my.app ===\"\nassert_contains \"mise tasks ls --all\" \"//projects/my.app:build\"\nassert_contains \"mise tasks ls --all\" \"//projects/my.app:test\"\n\n# Test 2: List tasks for directory with multiple dots\necho \"=== Test 2: List tasks for my.service.api ===\"\nassert_contains \"mise tasks ls --all\" \"//projects/my.service.api:build\"\nassert_contains \"mise tasks ls --all\" \"//projects/my.service.api:deploy\"\n\n# Test 3: List tasks for directory with version-like dots\necho \"=== Test 3: List tasks for feature.v2.beta ===\"\nassert_contains \"mise tasks ls --all\" \"//projects/feature.v2.beta:test\"\n\n# Test 4: Run task from directory with single dot\necho \"=== Test 4: Run build task from my.app ===\"\nassert_contains \"mise run '//projects/my.app:build'\" \"building my.app\"\n\n# Test 5: Run task from directory with multiple dots\necho \"=== Test 5: Run build task from my.service.api ===\"\nassert_contains \"mise run '//projects/my.service.api:build'\" \"building my.service.api\"\n\n# Test 6: Run task with dependency across directories with dots\necho \"=== Test 6: Run deploy with cross-directory dependency ===\"\noutput=$(mise run '//projects/my.service.api:deploy')\necho \"$output\"\necho \"$output\" | grep -q \"building my.app\" || (echo \"FAIL: Dependency task from my.app not run\" && exit 1)\necho \"$output\" | grep -q \"deploying my.service.api\" || (echo \"FAIL: Deploy task not run\" && exit 1)\n\n# Test 7: Wildcard matching with dots in directory names\necho \"=== Test 7: Wildcard matching ===\"\nassert_contains \"mise run '//projects/...:build'\" \"building my.app\"\nassert_contains \"mise run '//projects/...:build'\" \"building my.service.api\"\n\n# Test 8: Run all test tasks\necho \"=== Test 8: Run all test tasks ===\"\noutput=$(mise run '//...:test')\necho \"$output\"\necho \"$output\" | grep -q \"testing my.app\" || (echo \"FAIL: my.app test not run\" && exit 1)\necho \"$output\" | grep -q \"testing feature.v2.beta\" || (echo \"FAIL: feature.v2.beta test not run\" && exit 1)\n\n# Test 9: Verify no false positive matches between different projects\necho \"=== Test 9: Verify no false positive task matching ===\"\n# Running //projects/my.app:build should NOT run //projects/my.service.api:build\noutput=$(mise run '//projects/my.app:build')\necho \"$output\"\necho \"$output\" | grep -q \"building my.app\" || (echo \"FAIL: my.app build not run\" && exit 1)\n# Verify my.service.api:build was NOT run (would contain \"building my.service.api\")\nif echo \"$output\" | grep -q \"building my.service.api\"; then\n\techo \"FAIL: False positive - my.service.api:build should not have run\"\n\texit 1\nfi\necho \"SUCCESS: No false positive matches\"\n\n# Test 10: Verify simple patterns can match monorepo tasks\necho \"=== Test 10: Simple pattern matching ===\"\n# Create a simple task in the current directory for comparison\ncat <<'TOML' >>mise.toml\n\n[tasks.local-build]\nrun = 'echo \"local build\"'\nTOML\n\n# Test that pattern \"build\" matches monorepo tasks\noutput=$(mise tasks ls --all)\necho \"$output\"\n# Count how many \"build\" tasks exist (should be at least 3: my.app, my.service.api, and local-build)\nbuild_count=$(echo \"$output\" | grep -c \":build\\|local-build\" || true)\nif [ \"$build_count\" -lt 3 ]; then\n\techo \"FAIL: Expected at least 3 build tasks, found $build_count\"\n\texit 1\nfi\necho \"SUCCESS: Found $build_count build tasks\"\n\necho \"=== All tests with dots in directory names passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_edge_cases",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task edge cases: multiple dot extensions\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Create project structure with edge case tasks\nmkdir -p projects/frontend/mise-tasks\ncat <<EOF >projects/frontend/mise.toml\n[tasks.simple]\nrun = 'echo \"simple task\"'\nEOF\n\n# Test: Multiple dot extensions (e.g., backup.test.js)\n# When stripped, should become \"backup.test\" not \"backup\"\ncat <<'EOF' >projects/frontend/mise-tasks/backup.test.js\n#!/usr/bin/env node\nconsole.log(\"backup test\");\nEOF\nchmod +x projects/frontend/mise-tasks/backup.test.js\n\n# Verify task is discovered (display name strips one extension: backup.test)\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:backup.test\"\n\n# Test running with display name (without .js)\nassert_contains \"mise run '//projects/frontend:backup.test'\" \"backup test\"\n\n# Test running with full name (with .js)\nassert_contains \"mise run '//projects/frontend:backup.test.js'\" \"backup test\"\n\n# Test wildcard matching\nassert_contains \"mise run '//projects/...:backup*'\" \"backup test\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_env_version_override",
    "content": "#!/usr/bin/env bash\n# Test that MISE_*_VERSION environment variable overrides work for monorepo tasks\nexport MISE_EXPERIMENTAL=1\n\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tools]\ntiny = \"2.0.0\"\n\n[tasks.root-task]\nrun = 'rtx-tiny'\nEOF\n\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n[tasks.build]\nrun = 'rtx-tiny'\nEOF\n\nmise install tiny@2.0.0 tiny@3.0.0 tiny@3.1.0\n\necho \"=== Test 1: Without env override, uses config version ===\"\nassert_contains \"mise run //projects/backend:build\" \"v2.0.0\"\n\necho \"=== Test 2: With MISE_TINY_VERSION, should use env override version ===\"\nassert_contains \"MISE_TINY_VERSION=3.0.0 mise run //projects/backend:build\" \"v3.0.0\"\n\necho \"=== Test 3: Root task should respect env override ===\"\nassert_contains \"MISE_TINY_VERSION=3.0.0 mise run //:root-task\" \"v3.0.0\"\n\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[tools]\ntiny = \"2.0.0\"\n\n[tasks.build]\nrun = 'rtx-tiny'\nEOF\n\necho \"=== Test 4: Project with tools, env override should still win ===\"\nassert_contains \"MISE_TINY_VERSION=3.1.0 mise run //projects/frontend:build\" \"v3.1.0\"\n\necho \"=== All MISE_*_VERSION environment override tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_errors",
    "content": "#!/usr/bin/env bash\n# Test error cases: nested monorepos, malformed configs, circular dependencies\nexport MISE_EXPERIMENTAL=1\n\n# Test 1: Malformed config in subdirectory should warn but not break\necho \"=== Test 1: Malformed config in subdirectory ===\"\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task works\"'\nTOML\n\nmkdir -p projects/broken\ncat <<'TOML' >projects/broken/mise.toml\n[env]\nBAD_SYNTAX = this is not valid toml\nTOML\n\nmkdir -p projects/good\ncat <<'TOML' >projects/good/mise.toml\n[tasks.build]\nrun = 'echo \"good project built\"'\nTOML\n\n# Should warn about broken config but still load good project\noutput=$(mise run '//projects/good:build' 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"good project built\" || (echo \"FAIL: Good project should still work\" && exit 1)\n# Check that warning was issued (optional - depends on log level)\n# echo \"$output\" | grep -q -i \"failed to parse\" && echo \"Warning correctly issued for malformed config\"\n\n# Test 2: Nested monorepo (subdirectory with experimental_monorepo_root)\necho \"=== Test 2: Nested monorepo configuration ===\"\nrm -rf projects\nmkdir -p projects/nested\ncat <<'TOML' >projects/nested/mise.toml\n# This is potentially problematic - nested monorepo root\nexperimental_monorepo_root = true\n\n[tasks.nested-task]\nrun = 'echo \"nested task\"'\nTOML\n\nmkdir -p projects/normal\ncat <<'TOML' >projects/normal/mise.toml\n[tasks.normal-task]\nrun = 'echo \"normal task\"'\nTOML\n\n# Both should work, but nested one shouldn't create its own monorepo\noutput=$(mise run '//projects/normal:normal-task' 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"normal task\" || (echo \"FAIL: Normal task should work\" && exit 1)\n\noutput=$(mise run '//projects/nested:nested-task' 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"nested task\" || (echo \"FAIL: Nested task should still be accessible\" && exit 1)\n\n# Test 3: Missing dependency should fail gracefully\necho \"=== Test 3: Missing task dependency ===\"\nrm -rf projects\nmkdir -p projects/app\ncat <<'TOML' >projects/app/mise.toml\n[tasks.build]\ndepends = [\"//projects/nonexistent:build\"]\nrun = 'echo \"should not run\"'\nTOML\n\n# Should fail with clear error\noutput=$(mise run '//projects/app:build' 2>&1 || true)\necho \"$output\"\n# Should mention that dependency could not be found\nif echo \"$output\" | grep -q \"should not run\"; then\n\techo \"FAIL: Task with missing dependency should not execute\"\n\texit 1\nfi\n\n# Test 4: Task without experimental mode should fail\necho \"=== Test 4: Monorepo syntax without experimental mode ===\"\nrm -f mise.toml\ncat <<'TOML' >mise.toml\n# No experimental_monorepo_root flag\n\n[tasks.normal-task]\nrun = 'echo \"normal\"'\nTOML\n\nmkdir -p projects/app\ncat <<'TOML' >projects/app/mise.toml\n[tasks.build]\nrun = 'echo \"app build\"'\nTOML\n\n# Running with // syntax should fail or warn\nunset MISE_EXPERIMENTAL\noutput=$(mise run '//projects/app:build' 2>&1 || true)\necho \"$output\"\n# Should require experimental mode\necho \"$output\" | grep -q -i \"experimental\" || echo \"Note: May need experimental mode check\"\n\n# Test 5: Empty subdirectory mise.toml should not cause issues\necho \"=== Test 5: Empty subdirectory config ===\"\nexport MISE_EXPERIMENTAL=1\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root\"'\nTOML\n\nrm -rf projects\nmkdir -p projects/empty\ntouch projects/empty/mise.toml\n\nmkdir -p projects/working\ncat <<'TOML' >projects/working/mise.toml\n[tasks.build]\nrun = 'echo \"working build\"'\nTOML\n\n# Should handle empty config gracefully\noutput=$(mise run '//projects/working:build' 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"working build\" || (echo \"FAIL: Should handle empty configs\" && exit 1)\n\necho \"=== All error case tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_file_tasks",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task extension stripping for file tasks\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Create project structure with file tasks\nmkdir -p projects/frontend/mise-tasks\ncat <<EOF >projects/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\nEOF\n\n# Create file tasks with extensions in frontend\ncat <<'EOF' >projects/frontend/mise-tasks/test-e2e.js\n#!/usr/bin/env node\nconsole.log(\"frontend e2e tests\");\nEOF\nchmod +x projects/frontend/mise-tasks/test-e2e.js\n\ncat <<'EOF' >projects/frontend/mise-tasks/lint.sh\n#!/usr/bin/env bash\necho \"frontend linting\"\nEOF\nchmod +x projects/frontend/mise-tasks/lint.sh\n\nmkdir -p projects/backend/mise-tasks\ncat <<EOF >projects/backend/mise.toml\n[tasks.build]\nrun = 'echo \"backend build\"'\nEOF\n\n# Create file tasks with extensions in backend\ncat <<'EOF' >projects/backend/mise-tasks/test-api.py\n#!/usr/bin/env python3\nprint(\"backend api tests\")\nEOF\nchmod +x projects/backend/mise-tasks/test-api.py\n\ncat <<'EOF' >projects/backend/mise-tasks/migrate.rb\n#!/usr/bin/env ruby\nputs \"backend migrations\"\nEOF\nchmod +x projects/backend/mise-tasks/migrate.rb\n\n# Verify file tasks are discovered with --all\n# Note: Tasks are displayed WITHOUT extensions in listings (display_name strips them)\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:test-e2e\"\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:lint\"\nassert_contains \"mise tasks ls --all\" \"//projects/backend:test-api\"\nassert_contains \"mise tasks ls --all\" \"//projects/backend:migrate\"\n\n# Test running tasks WITHOUT extension (should work due to extension stripping)\nassert_contains \"mise run '//projects/frontend:test-e2e'\" \"frontend e2e tests\"\nassert_contains \"mise run '//projects/frontend:lint'\" \"frontend linting\"\nassert_contains \"mise run '//projects/backend:test-api'\" \"backend api tests\"\nassert_contains \"mise run '//projects/backend:migrate'\" \"backend migrations\"\n\n# Test running tasks WITH extension (should also work for exact match)\nassert_contains \"mise run '//projects/frontend:test-e2e.js'\" \"frontend e2e tests\"\nassert_contains \"mise run '//projects/frontend:lint.sh'\" \"frontend linting\"\nassert_contains \"mise run '//projects/backend:test-api.py'\" \"backend api tests\"\nassert_contains \"mise run '//projects/backend:migrate.rb'\" \"backend migrations\"\n\n# Test wildcard patterns with file tasks\nassert_contains \"mise run '//projects/frontend:test*'\" \"frontend e2e tests\"\nassert_contains \"mise run '//projects/backend:*'\" \"backend api tests\"\nassert_contains \"mise run '//projects/backend:*'\" \"backend migrations\"\n\n# Test ellipsis patterns with file tasks\nassert_contains \"mise run '//projects/...:lint'\" \"frontend linting\"\nassert_contains \"mise run '//projects/...:test*'\" \"frontend e2e tests\"\nassert_contains \"mise run '//projects/...:test*'\" \"backend api tests\"\n\n# From subdirectory, test without extension\ncd projects/frontend\nassert_contains \"mise run '//projects/frontend:test-e2e'\" \"frontend e2e tests\"\nassert_contains \"mise run '//projects/frontend:lint'\" \"frontend linting\"\n\n# Test task listing shows tasks without extensions (display_name behavior)\n# The internal name has the extension (test-e2e.js), but display strips it\n# Both with and without extension work for running tasks\nassert_contains \"mise tasks ls --all\" \"test-e2e\"\nassert_contains \"mise tasks ls --all\" \"lint\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_global_tasks",
    "content": "#!/usr/bin/env bash\n# Test that global tasks can be run from within a monorepo context\n# Regression test for: https://github.com/jdx/mise/discussions/6564#discussioncomment-15828264\nexport MISE_EXPERIMENTAL=1\n\n# Create a global config with a task\ncat >\"$MISE_CONFIG_DIR/config.toml\" <<'TOML'\n[tasks.hello]\nrun = \"echo hello-from-global\"\nTOML\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"packages/*\"]\n\n[tasks.root-task]\nrun = \"echo root-task-ran\"\nTOML\n\n# Create a subproject\nmkdir -p packages/foo\ncat <<'TOML' >packages/foo/mise.toml\n[tasks.foo-task]\nrun = \"echo foo-task-ran\"\nTOML\n\n# Test 1: Global task can be run from monorepo root\necho \"=== Test 1: Global task from monorepo root ===\"\nassert \"mise run hello\" \"hello-from-global\"\n\n# Test 2: Root task still works\necho \"=== Test 2: Root task still works ===\"\nassert \"mise run root-task\" \"root-task-ran\"\n\n# Test 3: Subproject task works with full monorepo syntax\necho \"=== Test 3: Subproject task with monorepo syntax ===\"\nassert \"mise run '//packages/foo:foo-task'\" \"foo-task-ran\"\n\n# Test 4: Global task visible in task list\necho \"=== Test 4: Global task visible in task list ===\"\nassert_contains \"mise tasks --all\" \"hello\"\n\n# Test 5: Explicit colon syntax should not fall back to global tasks\necho \"=== Test 5: Colon syntax does not fall back to global tasks ===\"\nassert_fail \"mise run :hello\"\n\necho \"=== All monorepo global task tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_includes",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task edge cases: multiple dot extensions\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Create project structure with task_config.includes\nmkdir -p projects/frontend/tasks\ncat <<EOF >projects/frontend/mise.toml\n[task_config]\nincludes = [\"tasks.toml\", \"tasks\"]\nEOF\n\n# Create included TOML file with a task\ncat <<EOF >projects/frontend/tasks.toml\n[toml-task]\nrun = 'echo \"task from toml\"'\nEOF\n\n# Create included script task\ncat <<'EOF' >projects/frontend/tasks/script-task.sh\n#!/usr/bin/env bash\necho \"task from script\"\nEOF\nchmod +x projects/frontend/tasks/script-task.sh\n\n# Create included script task with multiple extensions\ncat <<'EOF' >projects/frontend/tasks/another.long-name.sh\n#!/usr/bin/env bash\necho \"task with long name\"\nEOF\nchmod +x projects/frontend/tasks/another.long-name.sh\n\n# --- Assertions ---\n\n# Verify all tasks are discovered\nassert_contains \"mise tasks ls --debug --all\" \"//:root-task\"\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:toml-task\"\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:script-task\"\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:another.long-name\"\n\n# Verify running tasks from root\nassert_contains \"mise run '//projects/frontend:toml-task'\" \"task from toml\"\nassert_contains \"mise run '//projects/frontend:script-task'\" \"task from script\"\nassert_contains \"mise run '//projects/frontend:another.long-name'\" \"task with long name\"\nassert_contains \"mise run '//projects/frontend:another.long-name.sh'\" \"task with long name\"\n\n# Verify running from a subdirectory\ncd projects/frontend\nassert_contains \"mise run :toml-task\" \"task from toml\"\nassert_contains \"mise run :script-task\" \"task from script\"\nassert_contains \"mise run :another.long-name\" \"task with long name\"\n\n# Verify wildcard execution from subdirectory\noutput=$(mise run ':*')\nassert_contains \"echo '$output'\" \"task from toml\"\nassert_contains \"echo '$output'\" \"task from script\"\nassert_contains \"echo '$output'\" \"task with long name\"\n\ncd ../..\n\n# Verify wildcard execution from root\noutput=$(mise run '//projects/frontend:*')\nassert_contains \"echo '$output'\" \"task from toml\"\nassert_contains \"echo '$output'\" \"task from script\"\nassert_contains \"echo '$output'\" \"task with long name\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_includes_relative_path",
    "content": "#!/usr/bin/env bash\n\n# Test that task_config.includes with relative paths resolve correctly\n# relative to the config file's directory, not the search directory.\n# Also tests that bare task names (like \"build\") work from package directories.\n# See: https://github.com/jdx/mise/discussions/6564#discussioncomment-15655346\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo structure similar to the reported issue:\n# mise-monorepo/\n#   mise/\n#     config.toml (root config with experimental_monorepo_root)\n#     common.tasks.toml (shared tasks)\n#   packages/\n#     foo/\n#       mise/\n#         config.toml (includes ../../../mise/common.tasks.toml)\n\nmkdir -p mise\nmkdir -p packages/foo/mise\n\n# Create root config\ncat <<EOF >mise/config.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"packages/*\"]\n\n[settings]\nexperimental = true\n\n[tasks.root-task]\nrun = \"echo root-task ran\"\n\n[tasks.build]\ndescription = \"monorepo-wide build\"\nrun = \"echo monorepo root build ran\"\nEOF\n\n# Create common tasks file\ncat <<EOF >mise/common.tasks.toml\n[common-task]\nrun = \"echo common-task ran\"\n\n[build]\ndescription = \"common build task\"\nrun = \"echo common build ran\"\nEOF\n\n# Create package config with includes pointing to common tasks\n# The path is relative to the config root (packages/foo/)\ncat <<EOF >packages/foo/mise/config.toml\n[task_config]\nincludes = [\"../../mise/common.tasks.toml\"]\n\n[tasks.foo-task]\nrun = \"echo foo-task ran\"\nEOF\n\n# --- Test from root directory ---\n\n# Verify all tasks are discovered with --all\nassert_contains \"mise tasks --all\" \"//:build\"\nassert_contains \"mise tasks --all\" \"//:root-task\"\nassert_contains \"mise tasks --all\" \"//packages/foo:build\"\nassert_contains \"mise tasks --all\" \"//packages/foo:common-task\"\nassert_contains \"mise tasks --all\" \"//packages/foo:foo-task\"\n\n# Verify running tasks from root\nassert_contains \"mise run //packages/foo:common-task\" \"common-task ran\"\nassert_contains \"mise run //packages/foo:build\" \"common build ran\"\nassert_contains \"mise run //packages/foo:foo-task\" \"foo-task ran\"\n\n# --- Test from package directory ---\ncd packages/foo\n\n# Verify tasks are visible when running mise tasks from package directory\n# (This tests the first bug - tasks from includes not showing)\nassert_contains \"mise tasks\" \"//packages/foo:foo-task\"\nassert_contains \"mise tasks\" \"//packages/foo:build\"\nassert_contains \"mise tasks\" \"//packages/foo:common-task\"\n\n# Verify running tasks with :task syntax\nassert_contains \"mise run :common-task\" \"common-task ran\"\nassert_contains \"mise run :build\" \"common build ran\"\nassert_contains \"mise run :foo-task\" \"foo-task ran\"\n\n# Verify running tasks with bare names\n# (This tests the second bug - bare names should work after expansion)\nassert_contains \"mise run foo-task\" \"foo-task ran\"\nassert_contains \"mise run build\" \"common build ran\"\nassert_contains \"mise run common-task\" \"common-task ran\"\n\ncd ../..\n\n# --- Additional edge case: deeper nesting ---\nmkdir -p packages/bar/src/mise\n\n# Create a more deeply nested config with include going back multiple levels\ncat <<EOF >packages/bar/src/mise/config.toml\n[task_config]\nincludes = [\"../../../mise/common.tasks.toml\"]\n\n[tasks.bar-task]\nrun = \"echo bar-task ran\"\nEOF\n\n# Update monorepo config_roots to include deeper path\ncat <<EOF >mise/config.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"packages/*\", \"packages/bar/src\"]\n\n[settings]\nexperimental = true\n\n[tasks.root-task]\nrun = \"echo root-task ran\"\n\n[tasks.build]\ndescription = \"monorepo-wide build\"\nrun = \"echo monorepo root build ran\"\nEOF\n\n# Verify deeply nested includes work\nassert_contains \"mise tasks --all\" \"//packages/bar/src:bar-task\"\nassert_contains \"mise tasks --all\" \"//packages/bar/src:build\"\nassert_contains \"mise tasks --all\" \"//packages/bar/src:common-task\"\n\n# Run from deeply nested directory\ncd packages/bar/src\nassert_contains \"mise run :bar-task\" \"bar-task ran\"\nassert_contains \"mise run :common-task\" \"common-task ran\"\nassert_contains \"mise run bar-task\" \"bar-task ran\"\ncd ../../..\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_mise_env",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks properly load MISE_ENV-specific config files\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[env]\nROOT_VAR = \"root_value\"\nENV_VAR = \"root_default\"\n\n[tasks.root-task]\nrun = 'echo \"ROOT: ENV_VAR=\\$ENV_VAR DEV_VAR=\\$DEV_VAR\"'\nEOF\n\n# Create MISE_ENV-specific config at root\ncat <<EOF >mise.dev.toml\n[env]\nENV_VAR = \"root_dev\"\nDEV_VAR = \"root_dev_only\"\nEOF\n\n# Create frontend project with its own config\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[env]\nFRONTEND_VAR = \"frontend_value\"\nENV_VAR = \"frontend_default\"\n\n[tasks.build]\nrun = '''\necho \"FRONTEND_VAR=\\$FRONTEND_VAR\"\necho \"ENV_VAR=\\$ENV_VAR\"\necho \"DEV_VAR=\\$DEV_VAR\"\necho \"PROD_VAR=\\$PROD_VAR\"\necho \"ROOT_VAR=\\$ROOT_VAR\"\n'''\nEOF\n\n# Create MISE_ENV-specific config for frontend\ncat <<EOF >projects/frontend/mise.dev.toml\n[env]\nENV_VAR = \"frontend_dev\"\nDEV_VAR = \"frontend_dev_only\"\nEOF\n\ncat <<EOF >projects/frontend/mise.prod.toml\n[env]\nENV_VAR = \"frontend_prod\"\nPROD_VAR = \"frontend_prod_only\"\nEOF\n\n# Create backend project\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n[env]\nBACKEND_VAR = \"backend_value\"\nENV_VAR = \"backend_default\"\n\n[tasks.build]\nrun = '''\necho \"BACKEND_VAR=\\$BACKEND_VAR\"\necho \"ENV_VAR=\\$ENV_VAR\"\necho \"DEV_VAR=\\$DEV_VAR\"\necho \"ROOT_VAR=\\$ROOT_VAR\"\n'''\nEOF\n\n# Create MISE_ENV-specific config for backend\ncat <<EOF >projects/backend/mise.dev.toml\n[env]\nENV_VAR = \"backend_dev\"\nDEV_VAR = \"backend_dev_only\"\nEOF\n\n# Test 1: Root task with default MISE_ENV should use default values\necho \"=== Test 1: Root task with default env ===\"\nunset MISE_ENV\noutput=$(mise run //:root-task)\necho \"$output\"\nassert_contains \"echo '$output'\" \"ENV_VAR=root_default\"\n\n# Test 2: Root task with MISE_ENV=dev should load mise.dev.toml\necho \"=== Test 2: Root task with MISE_ENV=dev ===\"\noutput=$(MISE_ENV=dev mise run //:root-task)\necho \"$output\"\nassert_contains \"echo '$output'\" \"ENV_VAR=root_dev\"\nassert_contains \"echo '$output'\" \"DEV_VAR=root_dev_only\"\n\n# Test 3: Frontend task with default MISE_ENV should use frontend default\necho \"=== Test 3: Frontend task with default env ===\"\nunset MISE_ENV\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\nassert_contains \"echo '$output'\" \"ENV_VAR=frontend_default\"\nassert_contains \"echo '$output'\" \"FRONTEND_VAR=frontend_value\"\nassert_contains \"echo '$output'\" \"ROOT_VAR=root_value\"\n\n# Test 4: Frontend task with MISE_ENV=dev should load mise.dev.toml\necho \"=== Test 4: Frontend task with MISE_ENV=dev ===\"\noutput=$(MISE_ENV=dev mise run '//projects/frontend:build')\necho \"$output\"\n# Should load frontend/mise.dev.toml which overrides ENV_VAR\nassert_contains \"echo '$output'\" \"ENV_VAR=frontend_dev\"\n# Should load DEV_VAR from frontend/mise.dev.toml\nassert_contains \"echo '$output'\" \"DEV_VAR=frontend_dev_only\"\n# Should still have ROOT_VAR from root config\nassert_contains \"echo '$output'\" \"ROOT_VAR=root_value\"\n# Should have FRONTEND_VAR from base frontend config\nassert_contains \"echo '$output'\" \"FRONTEND_VAR=frontend_value\"\n\n# Test 5: Frontend task with MISE_ENV=prod should load mise.prod.toml\necho \"=== Test 5: Frontend task with MISE_ENV=prod ===\"\noutput=$(MISE_ENV=prod mise run '//projects/frontend:build')\necho \"$output\"\n# Should load frontend/mise.prod.toml which overrides ENV_VAR\nassert_contains \"echo '$output'\" \"ENV_VAR=frontend_prod\"\n# Should load PROD_VAR from frontend/mise.prod.toml\nassert_contains \"echo '$output'\" \"PROD_VAR=frontend_prod_only\"\n\n# Test 6: Backend task with MISE_ENV=dev should load backend's dev config\necho \"=== Test 6: Backend task with MISE_ENV=dev ===\"\noutput=$(MISE_ENV=dev mise run '//projects/backend:build')\necho \"$output\"\n# Should load backend/mise.dev.toml\nassert_contains \"echo '$output'\" \"ENV_VAR=backend_dev\"\nassert_contains \"echo '$output'\" \"DEV_VAR=backend_dev_only\"\nassert_contains \"echo '$output'\" \"BACKEND_VAR=backend_value\"\nassert_contains \"echo '$output'\" \"ROOT_VAR=root_value\"\n\n# Test 7: Verify that parent MISE_ENV configs are also loaded\n# Frontend should inherit root's dev config for DEV_VAR if not overridden\nmkdir -p projects/minimal\ncat <<EOF >projects/minimal/mise.toml\n[env]\nMINIMAL_VAR = \"minimal\"\n\n[tasks.build]\nrun = 'echo \"MINIMAL_VAR=\\$MINIMAL_VAR DEV_VAR=\\$DEV_VAR ENV_VAR=\\$ENV_VAR\"'\nEOF\n\necho \"=== Test 7: Minimal project inherits root MISE_ENV config ===\"\noutput=$(MISE_ENV=dev mise run '//projects/minimal:build')\necho \"$output\"\n# Should have its own var\nassert_contains \"echo '$output'\" \"MINIMAL_VAR=minimal\"\n# Should inherit DEV_VAR from root's mise.dev.toml\nassert_contains \"echo '$output'\" \"DEV_VAR=root_dev_only\"\n# Should inherit ENV_VAR from root's mise.dev.toml\nassert_contains \"echo '$output'\" \"ENV_VAR=root_dev\"\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_name_conflicts",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task name conflicts and resolution\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root with a \"build\" task\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/frontend\"]\n\n[tasks.build]\nrun = 'echo \"root build\"'\nEOF\n\n# Create project with also a \"build\" task\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\nEOF\n\nmise trust\n\n# Test 1: Monorepo root task must use // prefix\necho \"=== Test 1: Root task must use // prefix ===\"\noutput=$(mise run '//:build' 2>&1)\nif echo \"$output\" | grep -q \"root build\"; then\n\techo \"SUCCESS: Root task runs with // prefix\"\nelse\n\techo \"ERROR: Expected 'root build' in output\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Test 1b: Bare name at root should work the same as :build\necho \"=== Test 1b: Bare name 'build' should run root task ===\"\nassert_contains \"mise run build\" \"root build\"\n\n# Test 2: Monorepo path runs specific task\necho \"=== Test 2: Prefixed path runs specific task ===\"\noutput=$(mise run '//projects/frontend:build' 2>&1)\nif echo \"$output\" | grep -q \"frontend build\"; then\n\techo \"SUCCESS: Monorepo path runs specific task\"\nelse\n\techo \"ERROR: Expected 'frontend build' in output\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Test 3: From subdirectory, :task syntax runs local task\necho \"=== Test 3: From subdirectory :task runs local task ===\"\ncd projects/frontend\noutput=$(mise run ':build' 2>&1)\n# From subdirectory, :task should run local task\nif echo \"$output\" | grep -q \"frontend build\"; then\n\techo \"SUCCESS: From subdirectory :task runs local task\"\nelse\n\techo \"ERROR: Expected 'frontend build' from subdirectory with :task\"\n\techo \"Output: $output\"\n\texit 1\nfi\ncd ../..\n\n# Test 4: Tasks list shows both with full paths\necho \"=== Test 4: Tasks list shows both ===\"\noutput=$(mise tasks ls --all 2>&1)\nif echo \"$output\" | grep -q \"//:build\" && echo \"$output\" | grep -q \"//projects/frontend:build\"; then\n\techo \"SUCCESS: Both tasks visible in list\"\nelse\n\techo \"ERROR: Expected both tasks in list\"\n\techo \"Output: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_nested_config",
    "content": "#!/usr/bin/env bash\n\n# Test that nested config files (like .config/mise/config.toml) are properly\n# detected in monorepo subdirectories.\n#\n# When a subdir has a nested config, the include-only fallback should NOT run\n# and should NOT load default includes (which could overwrite tasks from the\n# nested config's custom includes).\n\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\nTOML\n\n# Create subdirectory with NESTED config path (.config/mise/config.toml)\n# instead of the simple mise.toml\nmkdir -p projects/nested-config/.config/mise\n\ncat <<'TOML' >projects/nested-config/.config/mise/config.toml\n# This is a nested config file - the subdir_has_config check must detect it\n\n[task_config]\n# Custom includes - ONLY these should be loaded\nincludes = [\"custom-tasks\"]\n\n[tasks.config-task]\nrun = \"echo 'task from nested config'\"\nTOML\n\n# Create tasks in the CUSTOM include path (specified in nested config)\n# Includes are resolved relative to the config root (projects/nested-config/),\n# so for .config/mise/config.toml, custom-tasks is at projects/nested-config/custom-tasks\nmkdir -p projects/nested-config/custom-tasks\ncat <<'SCRIPT' >projects/nested-config/custom-tasks/custom-task\n#!/usr/bin/env bash\necho \"task from custom includes\"\nSCRIPT\nchmod +x projects/nested-config/custom-tasks/custom-task\n\n# Create tasks in the DEFAULT include path (.mise/tasks)\n# These should NOT be loaded because the nested config exists\n# and has its own custom includes\nmkdir -p projects/nested-config/.mise/tasks\ncat <<'SCRIPT' >projects/nested-config/.mise/tasks/default-task\n#!/usr/bin/env bash\necho \"task from default includes - should NOT appear\"\nSCRIPT\nchmod +x projects/nested-config/.mise/tasks/default-task\n\n# --- Assertions ---\n\n# Test 1: Tasks from the nested config file should be discovered\nassert_contains \"mise tasks --all\" \"//projects/nested-config:config-task\"\nassert_contains \"mise run '//projects/nested-config:config-task'\" \"task from nested config\"\n\n# Test 2: Tasks from custom includes (specified in nested config) should be discovered\nassert_contains \"mise tasks --all\" \"//projects/nested-config:custom-task\"\nassert_contains \"mise run '//projects/nested-config:custom-task'\" \"task from custom includes\"\n\n# Test 3: Tasks from DEFAULT includes (.mise/tasks) should NOT be loaded\n# because the nested config exists and has its own includes\nassert_not_contains \"mise tasks --all\" \"//projects/nested-config:default-task\"\n\n# ============================================================================\n# Test case 2: Nested config using DEFAULT includes (no custom task_config.includes)\n# ============================================================================\n\n# Create another subdirectory with nested config but NO custom includes\nmkdir -p projects/nested-default/.config/mise\n\ncat <<'TOML' >projects/nested-default/.config/mise/config.toml\n# Nested config WITHOUT custom includes - should use default includes\n# Default includes are resolved relative to the config root (projects/nested-default/)\n\n[tasks.config-task2]\nrun = \"echo 'task from nested-default config'\"\nTOML\n\n# Create tasks in the DEFAULT include path, relative to the config root\n# For .config/mise/config.toml with config_root=projects/nested-default/,\n# the default \".mise/tasks\" resolves to projects/nested-default/.mise/tasks\nmkdir -p projects/nested-default/.mise/tasks\ncat <<'SCRIPT' >projects/nested-default/.mise/tasks/default-include-task\n#!/usr/bin/env bash\necho \"task from default includes in nested config\"\nSCRIPT\nchmod +x projects/nested-default/.mise/tasks/default-include-task\n\n# Also create tasks at the config-file-parent-relative path (.config/mise/.mise/tasks)\n# These should NOT be loaded (default includes are relative to config root, not config file parent)\nmkdir -p projects/nested-default/.config/mise/.mise/tasks\ncat <<'SCRIPT' >projects/nested-default/.config/mise/.mise/tasks/wrong-location-task\n#!/usr/bin/env bash\necho \"task from wrong location - should NOT appear\"\nSCRIPT\nchmod +x projects/nested-default/.config/mise/.mise/tasks/wrong-location-task\n\n# Test 5: Tasks from nested config using default includes should work\nassert_contains \"mise tasks --all\" \"//projects/nested-default:config-task2\"\nassert_contains \"mise run '//projects/nested-default:config-task2'\" \"task from nested-default config\"\n\n# Test 6: Tasks from default include path (relative to config root) should be loaded\nassert_contains \"mise tasks --all\" \"//projects/nested-default:default-include-task\"\nassert_contains \"mise run '//projects/nested-default:default-include-task'\" \"task from default includes in nested config\"\n\n# Test 7: Tasks from config-file-parent-relative .mise/tasks should NOT be loaded\n# (because includes are relative to config root, not config file location)\nassert_not_contains \"mise tasks --all\" \"//projects/nested-default:wrong-location-task\"\n\n# ============================================================================\n# Test case 3: 1-level nested config (.mise/config.toml)\n# This is a common alternative to .config/mise/config.toml\n# ============================================================================\n\nmkdir -p projects/mise-dir/.mise\n\ncat <<'TOML' >projects/mise-dir/.mise/config.toml\n# 1-level nested config at .mise/config.toml\n# Custom includes pointing to \"tasks\" (relative to config root projects/mise-dir/)\n[task_config]\nincludes = [\"tasks\"]\n\n[tasks.mise-dir-task]\nrun = \"echo 'task from .mise/config.toml'\"\nTOML\n\n# Create tasks in the config-root-relative include path (projects/mise-dir/tasks)\n# This is \"tasks\" relative to config root (projects/mise-dir/)\nmkdir -p projects/mise-dir/tasks\ncat <<'SCRIPT' >projects/mise-dir/tasks/config-relative-task\n#!/usr/bin/env bash\necho \"task from config-relative include\"\nSCRIPT\nchmod +x projects/mise-dir/tasks/config-relative-task\n\n# Create tasks in the config-file-parent-relative path (.mise/tasks)\n# These should NOT be loaded (includes resolve from config root, not config file parent)\nmkdir -p projects/mise-dir/.mise/tasks\ncat <<'SCRIPT' >projects/mise-dir/.mise/tasks/fallback-task\n#!/usr/bin/env bash\necho \"task from fallback - should NOT appear\"\nSCRIPT\nchmod +x projects/mise-dir/.mise/tasks/fallback-task\n\n# Test 8: Tasks from 1-level nested config should be discovered\nassert_contains \"mise tasks --all\" \"//projects/mise-dir:mise-dir-task\"\nassert_contains \"mise run '//projects/mise-dir:mise-dir-task'\" \"task from .mise/config.toml\"\n\n# Test 9: Tasks from config-root-relative includes should be loaded\nassert_contains \"mise tasks --all\" \"//projects/mise-dir:config-relative-task\"\nassert_contains \"mise run '//projects/mise-dir:config-relative-task'\" \"task from config-relative include\"\n\n# Test 10: Tasks from config-file-parent-relative path should NOT be loaded\nassert_not_contains \"mise tasks --all\" \"//projects/mise-dir:fallback-task\"\n\n# ============================================================================\n# Test case 4: Standard root-level configs (mise.toml, .mise.toml)\n# ============================================================================\n\n# Test with mise.toml (most common)\nmkdir -p projects/standard-config\ncat <<'TOML' >projects/standard-config/mise.toml\n[task_config]\nincludes = [\"tasks\"]\n\n[tasks.standard-task]\nrun = \"echo 'task from standard mise.toml'\"\nTOML\n\nmkdir -p projects/standard-config/tasks\ncat <<'SCRIPT' >projects/standard-config/tasks/file-task\n#!/usr/bin/env bash\necho \"file task from standard config\"\nSCRIPT\nchmod +x projects/standard-config/tasks/file-task\n\n# Test 11: Standard mise.toml should work\nassert_contains \"mise tasks --all\" \"//projects/standard-config:standard-task\"\nassert_contains \"mise run '//projects/standard-config:standard-task'\" \"task from standard mise.toml\"\nassert_contains \"mise tasks --all\" \"//projects/standard-config:file-task\"\nassert_contains \"mise run '//projects/standard-config:file-task'\" \"file task from standard config\"\n\n# Test with .mise.toml (alternative common format)\nmkdir -p projects/dotmise-config\ncat <<'TOML' >projects/dotmise-config/.mise.toml\n[tasks.dotmise-task]\nrun = \"echo 'task from .mise.toml'\"\nTOML\n\n# Test 12: .mise.toml should also work\nassert_contains \"mise tasks --all\" \"//projects/dotmise-config:dotmise-task\"\nassert_contains \"mise run '//projects/dotmise-config:dotmise-task'\" \"task from .mise.toml\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_optional_colon",
    "content": "#!/usr/bin/env bash\n\n# Test that the leading colon is optional for monorepo task running and dependencies\n# This tests that \"build\" works the same as \":build\" in monorepo contexts\n\nexport MISE_EXPERIMENTAL=1\n\n# Set up monorepo structure\ncat <<'EOF' >mise.toml\nmin_version = \"2025.10.6\"\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"app\", \"frontend\", \"backend\", \"services\", \"other\"]\n\n[settings]\nexperimental = true\nEOF\n\n# Test 1: Task dependencies without leading colon\nmkdir -p app\ncat <<'EOF' >app/mise.toml\n[tasks.setup]\nrun = 'echo \"setup task executed\"'\n\n[tasks.build]\ndepends = [\"setup\"]\nrun = 'echo \"build task executed\"'\n\n[tasks.test]\ndepends = [\"build\"]\nrun = 'echo \"test task executed\"'\nEOF\n\n# Dependencies without colon should work (resolve to same module)\nassert_contains \"mise run //app:build\" \"setup task executed\"\nassert_contains \"mise run //app:build\" \"build task executed\"\n\nassert_contains \"mise run //app:test\" \"setup task executed\"\nassert_contains \"mise run //app:test\" \"build task executed\"\nassert_contains \"mise run //app:test\" \"test task executed\"\n\n# Test 2: Running tasks from subdirectory without leading colon\n(\n\tcd app\n\tassert_contains \"mise run build\" \"setup task executed\"\n\tassert_contains \"mise run build\" \"build task executed\"\n)\n\n# Test 3: Mixed colon and non-colon syntax\nmkdir -p frontend\ncat <<'EOF' >frontend/mise.toml\n[tasks.lint]\nrun = 'echo \"lint task executed\"'\n\n[tasks.compile]\ndepends = [\":lint\"]  # colon syntax\nrun = 'echo \"compile task executed\"'\n\n[tasks.bundle]\ndepends = [\"compile\"]  # non-colon syntax\nrun = 'echo \"bundle task executed\"'\nEOF\n\nassert_contains \"mise run //frontend:bundle\" \"lint task executed\"\nassert_contains \"mise run //frontend:bundle\" \"compile task executed\"\nassert_contains \"mise run //frontend:bundle\" \"bundle task executed\"\n\n# Test 4: Task with colons in name and bare dependencies\nmkdir -p backend\ncat <<'EOF' >backend/mise.toml\n[tasks.before]\nrun = 'echo \"before task executed\"'\n\n[tasks.\"deploy:staging\"]\ndepends = [\"before\"]  # no colon\nrun = 'echo \"deploy:staging task executed\"'\n\n[tasks.\"deploy:prod\"]\ndepends = [\":before\", \"deploy:staging\"]  # mixed syntax\nrun = 'echo \"deploy:prod task executed\"'\nEOF\n\nassert_contains \"mise run //backend:deploy:staging\" \"before task executed\"\nassert_contains \"mise run //backend:deploy:staging\" \"deploy:staging task executed\"\n\nassert_contains \"mise run //backend:deploy:prod\" \"before task executed\"\nassert_contains \"mise run //backend:deploy:prod\" \"deploy:staging task executed\"\nassert_contains \"mise run //backend:deploy:prod\" \"deploy:prod task executed\"\n\n# Test 5: depends_post with bare task names\nmkdir -p services\ncat <<'EOF' >services/mise.toml\n[tasks.cleanup]\nrun = 'echo \"cleanup task executed\"'\n\n[tasks.process]\ndepends_post = [\"cleanup\"]\nrun = 'echo \"process task executed\"'\nEOF\n\nassert_contains \"mise run //services:process\" \"process task executed\"\nassert_contains \"mise run //services:process\" \"cleanup task executed\"\n\n# Test 6: Verify that dependencies are correctly scoped to their module\n# bare name \"before\" in different module should resolve to that module, not another\nmkdir -p other\ncat <<'EOF' >other/mise.toml\n[tasks.before]\nrun = 'echo \"other before task executed\"'\n\n[tasks.main]\ndepends = [\"before\"]\nrun = 'echo \"other main task executed\"'\nEOF\n\n# Should run the \"other before\" task, not the \"backend before\" task\nOUTPUT=$(mise run //other:main)\nassert_contains \"mise run //other:main\" \"other before task executed\"\nassert_contains \"mise run //other:main\" \"other main task executed\"\n\n# Verify it's NOT running the backend's \"before\" task\nif echo \"$OUTPUT\" | grep -q \"^before task executed$\"; then\n\techo \"ERROR: Task dependency incorrectly resolved to different module's task\"\n\texit 1\nfi\n\n# Test 7: Running task from subdirectory\n(\n\tcd frontend\n\tassert_contains \"mise run compile\" \"lint task executed\"\n\tassert_contains \"mise run compile\" \"compile task executed\"\n)\n\n# Test 8: Root level tasks - bare names work at root too\ncat <<'EOF' >>mise.toml\n[tasks.clean]\nrun = 'echo \"root clean task executed\"'\n\n[tasks.init]\ndepends = [\"clean\"]\nrun = 'echo \"root init task executed\"'\nEOF\n\n# Running with explicit //:init prefix\nassert_contains \"mise run //:init\" \"root clean task executed\"\nassert_contains \"mise run //:init\" \"root init task executed\"\n\n# Running from root directory with bare name should work the same\nassert_contains \"mise run init\" \"root clean task executed\"\nassert_contains \"mise run init\" \"root init task executed\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_path_directives",
    "content": "#!/usr/bin/env bash\n# Test that _.path directives from subdirectory configs work correctly\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[env]\n_.path = [\"./root-bin\"]\n\n[tasks.root-task]\nrun = 'echo \"PATH=\\$PATH\"'\nEOF\n\nmkdir -p root-bin\necho \"root-bin-file\" >root-bin/root-tool\n\n# Create frontend project with its own _.path\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[env]\n_.path = [\"./bin\", \"./node_modules/.bin\"]\n\n[tasks.build]\nrun = '''\necho \"PATH=\\$PATH\"\n'''\nEOF\n\nmkdir -p projects/frontend/bin\nmkdir -p projects/frontend/node_modules/.bin\necho \"frontend-bin\" >projects/frontend/bin/frontend-tool\necho \"node-module\" >projects/frontend/node_modules/.bin/npm\n\n# Create backend project with _.path\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n[env]\n_.path = [\"./scripts\"]\n\n[tasks.build]\nrun = 'echo \"PATH=\\$PATH\"'\nEOF\n\nmkdir -p projects/backend/scripts\necho \"backend-script\" >projects/backend/scripts/deploy\n\n# Test 1: Frontend task should have both root-bin and frontend paths\necho \"=== Test 1: Frontend _.path includes subdirectory paths ===\"\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\necho \"$output\" | grep -q \"projects/frontend/bin\" || (echo \"FAIL: frontend/bin not in PATH\" && exit 1)\necho \"$output\" | grep -q \"projects/frontend/node_modules/.bin\" || (echo \"FAIL: node_modules/.bin not in PATH\" && exit 1)\necho \"$output\" | grep -q \"root-bin\" || (echo \"FAIL: root-bin not in PATH\" && exit 1)\n\n# Test 2: Backend task should have root-bin and backend scripts\necho \"=== Test 2: Backend _.path includes subdirectory paths ===\"\noutput=$(mise run '//projects/backend:build')\necho \"$output\"\necho \"$output\" | grep -q \"projects/backend/scripts\" || (echo \"FAIL: backend/scripts not in PATH\" && exit 1)\necho \"$output\" | grep -q \"root-bin\" || (echo \"FAIL: root-bin not inherited in backend\" && exit 1)\n\n# Test 3: Root task should only have root-bin\necho \"=== Test 3: Root task has only root _.path ===\"\noutput=$(mise run //:root-task)\necho \"$output\"\necho \"$output\" | grep -q \"root-bin\" || (echo \"FAIL: root-bin not in root task\" && exit 1)\n\necho \"=== All _.path tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_relative_paths",
    "content": "#!/usr/bin/env bash\n# Test that relative paths in env directives resolve correctly from subdirectory configs\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[env]\nROOT_DATA = \"./root-data.txt\"\n\n[tasks.root-task]\nrun = 'cat \"\\$ROOT_DATA\"'\nEOF\n\necho \"root-data-content\" >root-data.txt\n\n# Create frontend project with relative path env\nmkdir -p projects/frontend\ncat <<'EOF' >projects/frontend/mise.toml\n[env]\nCONFIG_FILE = \"./config.json\"\nDATA_DIR = \"./data\"\nNESTED_FILE = \"../../shared/shared.txt\"\n\n[tasks.build]\nrun = '''\necho \"CONFIG_FILE=$CONFIG_FILE\"\necho \"DATA_DIR=$DATA_DIR\"\necho \"NESTED_FILE=$NESTED_FILE\"\ncat \"$CONFIG_FILE\"\ncat \"$NESTED_FILE\"\n'''\nEOF\n\ncat <<'EOF' >projects/frontend/config.json\n{\"name\": \"frontend\"}\nEOF\nmkdir -p projects/frontend/data\n\n# Create shared directory for nested relative path test\nmkdir -p shared\necho \"shared-content\" >shared/shared.txt\n\n# Create backend project with relative paths\nmkdir -p projects/backend\ncat <<'EOF' >projects/backend/mise.toml\n[env]\nENV_FILE = \"./.env\"\nSETTINGS_FILE = \"./settings.toml\"\n\n[tasks.deploy]\nrun = '''\ncat \"$ENV_FILE\"\ncat \"$SETTINGS_FILE\"\n'''\nEOF\n\ncat <<'EOF' >projects/backend/.env\nDATABASE_URL=postgres://localhost/db\nEOF\n\ncat <<'EOF' >projects/backend/settings.toml\n[server]\nport = 8080\nEOF\n\n# Test 1: Frontend relative paths resolve from subdirectory\necho \"=== Test 1: Frontend relative paths resolve correctly ===\"\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\n# Env vars contain relative paths as-is\necho \"$output\" | grep -q \"CONFIG_FILE=./config.json\" || (echo \"FAIL: CONFIG_FILE should be relative\" && exit 1)\necho \"$output\" | grep -q \"DATA_DIR=./data\" || (echo \"FAIL: DATA_DIR should be relative\" && exit 1)\n# But the paths should resolve correctly when used (reading files works)\necho \"$output\" | grep -q '{\"name\": \"frontend\"}' || (echo \"FAIL: Could not read config.json with relative path\" && exit 1)\necho \"$output\" | grep -q \"shared-content\" || (echo \"FAIL: Could not read nested relative path\" && exit 1)\n\n# Test 2: Backend relative paths work\necho \"=== Test 2: Backend relative paths resolve correctly ===\"\noutput=$(mise run '//projects/backend:deploy')\necho \"$output\"\necho \"$output\" | grep -q \"DATABASE_URL=postgres://localhost/db\" || (echo \"FAIL: Could not read .env\" && exit 1)\necho \"$output\" | grep -q \"port = 8080\" || (echo \"FAIL: Could not read settings.toml\" && exit 1)\n\n# Test 3: Root task relative paths resolve from root\necho \"=== Test 3: Root relative paths resolve from root ===\"\noutput=$(mise run //:root-task)\necho \"$output\"\necho \"$output\" | grep -q \"root-data-content\" || (echo \"FAIL: Root relative path incorrect\" && exit 1)\n\necho \"=== All relative path tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_run_project_local_tasks",
    "content": "#!/usr/bin/env bash\n# Test that project tasks can call other local tasks using :task syntax\nexport MISE_EXPERIMENTAL=1\n\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/backend\"]\nTOML\n\nmkdir -p projects/backend\ncat <<'TOML' >projects/backend/mise.toml\n[tasks.hello]\nrun = \"echo 'hello from backend'\"\n\n[tasks.runs-hello]\nrun = { task = \":hello\" }\n\n[tasks.depends-hello]\ndepends = [ \":hello\" ]\nTOML\n\necho \"=== Test 1: Call backend hello ===\"\noutput=$(mise run //projects/backend:hello 2>&1)\necho \"$output\"\n\necho \"=== Test 2: Call backend task that runs hello ===\"\noutput=$(mise run //projects/backend:runs-hello)\necho \"$output\"\necho \"$output\" | grep -q \"hello from backend\" || (echo \"FAIL: :task pattern in run block not resolved\" && exit 1)\n\necho \"=== Test 3: Call backend task that depends on hello ===\"\noutput=$(mise run //projects/backend:depends-hello)\necho \"$output\"\necho \"$output\" | grep -q \"hello from backend\" || (echo \"FAIL: :task pattern in depends not resolved\" && exit 1)\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_run_project_tasks",
    "content": "#!/usr/bin/env bash\n# Test that project tasks can be called from root task run blocks\n# Regression test for: https://github.com/jdx/mise/discussions/6739\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config with a task that calls a project task via run block\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.call-backend-via-run]\nrun = [\n    { task = \"//projects/backend:hello\" }\n]\n\n[tasks.call-backend-via-depends]\ndepends = [\"//projects/backend:hello\"]\nrun = \"echo 'after dependency'\"\nTOML\n\n# Create backend project with a simple task\nmkdir -p projects/backend\ncat <<'TOML' >projects/backend/mise.toml\n[tasks.hello]\nrun = \"echo 'hello from backend'\"\nTOML\n\n# Test 1: Calling project task from root task run block (this should work but currently fails)\necho \"=== Test 1: Call project task from root task run block ===\"\noutput=$(mise run //:call-backend-via-run 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"hello from backend\" || (echo \"FAIL: Project task not called from run block\" && exit 1)\n\n# Test 2: Calling project task via depends (this already works)\necho \"=== Test 2: Call project task from root task depends ===\"\noutput=$(mise run //:call-backend-via-depends)\necho \"$output\"\necho \"$output\" | grep -q \"hello from backend\" || (echo \"FAIL: Project task not called from depends\" && exit 1)\necho \"$output\" | grep -q \"after dependency\" || (echo \"FAIL: Root task did not run after dependency\" && exit 1)\n\n# Test 3: Multiple project tasks in run block\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[tasks.call-multiple]\nrun = [\n    { task = \"//projects/backend:hello\" },\n    { task = \"//projects/frontend:greet\" }\n]\nTOML\n\nmkdir -p projects/frontend\ncat <<'TOML' >projects/frontend/mise.toml\n[tasks.greet]\nrun = \"echo 'greetings from frontend'\"\nTOML\n\necho \"=== Test 3: Call multiple project tasks from root task run block ===\"\noutput=$(mise run //:call-multiple)\necho \"$output\"\necho \"$output\" | grep -q \"hello from backend\" || (echo \"FAIL: Backend task not called\" && exit 1)\necho \"$output\" | grep -q \"greetings from frontend\" || (echo \"FAIL: Frontend task not called\" && exit 1)\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_syntax",
    "content": "#!/usr/bin/env bash\n# Test basic monorepo task syntax (//pkg:task addressing)\n# These tests verify the fundamental task addressing works, not inheritance\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config with tasks\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"example-pkg\", \"libs/*\"]\n\n[tasks.rootTask]\nrun = \"echo 'task from root'\"\n\n[tasks.build]\nrun = \"echo 'root build'\"\nTOML\n\n# Create subdirectory with its own tasks\nmkdir -p example-pkg\ncat <<'TOML' >example-pkg/mise.toml\n[tasks.build]\nrun = \"echo 'example-pkg build'\"\n\n[tasks.localTask]\nrun = \"echo 'local task'\"\nTOML\n\n# Create intermediate parent with tasks\nmkdir -p libs\ncat <<'TOML' >libs/mise.toml\n[tasks.build]\nrun = \"echo 'libs build'\"\nTOML\n\nmkdir -p libs/example-lib1\ncat <<'TOML' >libs/example-lib1/mise.toml\n[tasks.build]\nrun = \"echo 'example-lib1 build'\"\nTOML\n\n# --- Tests for basic monorepo syntax ---\n\n# Test 1: Root tasks appear in task list with // prefix\nassert_contains \"mise tasks --all\" \"//:rootTask\"\nassert_contains \"mise tasks --all\" \"//:build\"\n\n# Test 2: Root tasks can be run with // prefix\nassert_contains \"mise run //:rootTask\" \"task from root\"\n\n# Test 3: Subpackage local tasks can be run\nassert_contains \"mise run //example-pkg:build\" \"example-pkg build\"\nassert_contains \"mise run //example-pkg:localTask\" \"local task\"\n\n# Test 4: Child's local task shadows parent's task of same name\nassert_contains \"mise run //libs/example-lib1:build\" \"example-lib1 build\"\n\n# Test 5: Local task runs from its definition directory\ncat <<'TOML' >example-pkg/mise.toml\n[tasks.showdir]\nrun = \"pwd\"\nTOML\n\nassert_contains \"mise run //example-pkg:showdir\" \"example-pkg\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_tasks_deps_command",
    "content": "#!/usr/bin/env bash\n\n# Test that `mise tasks deps` command works with monorepo task paths.\n# The `mise tasks deps` command should be able to show dependency trees for\n# monorepo tasks like //mydir:task, not just tasks in the current directory.\n\nexport MISE_EXPERIMENTAL=1\n\n# Set up monorepo structure\ncat <<'EOF' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"mydir\"]\n\n[tasks.root]\ndepends = [\"//mydir:child\"]\nrun = \"echo root\"\nEOF\n\nmkdir -p mydir\ncat <<'EOF' >mydir/mise.toml\n[tasks.child]\ndepends = [\":grandchild\"]\nrun = \"echo child\"\n\n[tasks.grandchild]\nrun = \"echo grandchild\"\nEOF\n\n# Verify tasks are discovered\nassert_contains \"mise tasks --all\" \"//mydir:child\"\nassert_contains \"mise tasks --all\" \"//mydir:grandchild\"\n\n# Verify tasks can be run (sanity check)\nassert_contains \"mise run //mydir:child\" \"grandchild\"\nassert_contains \"mise run //mydir:child\" \"child\"\n\n# Test: mise tasks deps should work with monorepo task paths\nassert_contains \"mise tasks deps //mydir:child\" \"//mydir:child\"\nassert_contains \"mise tasks deps //mydir:child\" \"//mydir:grandchild\"\n\n# Test with full prefix\nassert_contains \"mise tasks deps //:root\" \"//:root\"\nassert_contains \"mise tasks deps //:root\" \"//mydir:child\"\n\n# Test from subdirectory - should still work with full monorepo paths\n(\n\tcd mydir\n\tassert_contains \"mise tasks deps //mydir:child\" \"//mydir:child\"\n\tassert_contains \"mise tasks deps //mydir:grandchild\" \"//mydir:grandchild\"\n)\n\n# Test shorthand from root\nassert_contains \"mise tasks deps root\" \"//:root\"\n\n# Test --dot output format works with monorepo tasks\nassert_contains \"mise tasks deps --dot //mydir:child\" \"label\"\nassert_contains \"mise tasks deps --dot //mydir:child\" \"//mydir:child\"\n\n# Test error message shows correct available tasks for monorepo context\nOUTPUT=$(mise tasks deps //mydir:nonexistent 2>&1 || true)\nassert_contains \"echo '$OUTPUT'\" \"//mydir:child\"\n\n# Test multiple tasks argument\nassert_contains \"mise tasks deps //mydir:child //mydir:grandchild\" \"//mydir:child\"\nassert_contains \"mise tasks deps //mydir:child //mydir:grandchild\" \"//mydir:grandchild\"\n\n# Test multiple tasks with mixed monorepo and root paths\nassert_contains \"mise tasks deps //:root //mydir:grandchild\" \"//:root\"\nassert_contains \"mise tasks deps //:root //mydir:grandchild\" \"//mydir:grandchild\"\n\n# Test --hidden flag with hidden tasks\ncat <<'EOF' >mydir/mise.toml\n[tasks.child]\ndepends = [\":grandchild\"]\nrun = \"echo child\"\n\n[tasks.grandchild]\nrun = \"echo grandchild\"\n\n[tasks.secret]\nhide = true\nrun = \"echo secret\"\nEOF\n\n# Without --hidden, secret task should not appear in deps output\nOUTPUT=$(mise tasks deps 2>&1)\nassert_not_contains \"echo '$OUTPUT'\" \"secret\"\n\n# With --hidden, secret task should appear\nassert_contains \"mise tasks deps --hidden\" \"//mydir:secret\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_tera_templates",
    "content": "#!/usr/bin/env bash\n# Test that tera templating works correctly with {{config_root}} in subdirectory configs\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'TOML' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\"]\n\n[env]\nROOT_DIR = \"{{config_root}}\"\nPROJECT_NAME = \"monorepo\"\n\n[tasks.root-task]\nrun = 'echo \"ROOT_DIR=$ROOT_DIR\"'\nTOML\n\n# Create frontend with tera templates\nmkdir -p projects/frontend\ncat <<'TOML' >projects/frontend/mise.toml\n[env]\nFRONTEND_ROOT = \"{{config_root}}\"\nBUILD_DIR = \"{{config_root}}/dist\"\nASSETS_PATH = \"{{config_root}}/assets\"\n# Test nested template evaluation\nFULL_PATH = \"{{env.FRONTEND_ROOT}}/src\"\n\n[tasks.build]\nrun = '''\necho \"FRONTEND_ROOT=$FRONTEND_ROOT\"\necho \"BUILD_DIR=$BUILD_DIR\"\necho \"ASSETS_PATH=$ASSETS_PATH\"\necho \"FULL_PATH=$FULL_PATH\"\n'''\nTOML\n\nmkdir -p projects/frontend/dist\nmkdir -p projects/frontend/assets\n\n# Create backend with tera templates\nmkdir -p projects/backend\ncat <<'TOML' >projects/backend/mise.toml\n[env]\nBACKEND_ROOT = \"{{config_root}}\"\nLOG_FILE = \"{{config_root}}/logs/app.log\"\nCONFIG_PATH = \"{{config_root}}/config\"\n\n[tasks.start]\nrun = '''\necho \"BACKEND_ROOT=$BACKEND_ROOT\"\necho \"LOG_FILE=$LOG_FILE\"\necho \"CONFIG_PATH=$CONFIG_PATH\"\n'''\nTOML\n\nmkdir -p projects/backend/logs\nmkdir -p projects/backend/config\n\n# Test 1: Frontend config_root resolves to frontend directory\necho \"=== Test 1: Frontend {{config_root}} resolves to subdirectory ===\"\noutput=$(mise run '//projects/frontend:build')\necho \"$output\"\necho \"$output\" | grep -q \"FRONTEND_ROOT=.*projects/frontend\" || (echo \"FAIL: FRONTEND_ROOT should point to projects/frontend\" && exit 1)\necho \"$output\" | grep -q \"BUILD_DIR=.*projects/frontend/dist\" || (echo \"FAIL: BUILD_DIR incorrect\" && exit 1)\necho \"$output\" | grep -q \"ASSETS_PATH=.*projects/frontend/assets\" || (echo \"FAIL: ASSETS_PATH incorrect\" && exit 1)\necho \"$output\" | grep -q \"FULL_PATH=.*projects/frontend/src\" || (echo \"FAIL: Nested template not evaluated\" && exit 1)\n\n# Test 2: Backend config_root resolves to backend directory\necho \"=== Test 2: Backend {{config_root}} resolves to subdirectory ===\"\noutput=$(mise run '//projects/backend:start')\necho \"$output\"\necho \"$output\" | grep -q \"BACKEND_ROOT=.*projects/backend\" || (echo \"FAIL: BACKEND_ROOT should point to projects/backend\" && exit 1)\necho \"$output\" | grep -q \"LOG_FILE=.*projects/backend/logs/app.log\" || (echo \"FAIL: LOG_FILE incorrect\" && exit 1)\necho \"$output\" | grep -q \"CONFIG_PATH=.*projects/backend/config\" || (echo \"FAIL: CONFIG_PATH incorrect\" && exit 1)\n\n# Test 3: Root task config_root resolves to monorepo root\necho \"=== Test 3: Root {{config_root}} resolves to monorepo root ===\"\noutput=$(mise run //:root-task)\necho \"$output\"\n# Root DIR should not contain projects/ subdirectory path\nif echo \"$output\" | grep -q \"ROOT_DIR=.*projects/\"; then\n\techo \"FAIL: Root config_root should not include projects/ path\"\n\texit 1\nfi\necho \"$output\" | grep -q \"ROOT_DIR=\" || (echo \"FAIL: ROOT_DIR not set\" && exit 1)\n\necho \"=== All tera template tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_tool_inheritance",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks inherit tools from parent mise.toml files\nexport MISE_EXPERIMENTAL=1\nexport MISE_NODE_VERIFY=0 # Skip GPG verification to avoid keyboxd issues\n\n# Create monorepo root config with shared tools\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\", \"projects/backend/*\"]\n\n[tools]\n# Root defines node that should be inherited by all subdirectories\nnode = \"20\"\n\n[tasks.root-task]\nrun = 'node --version'\nEOF\n\n# Create frontend project that overrides node version\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[tools]\n# Frontend overrides with node 18\nnode = \"18\"\n\n[tasks.build]\nrun = 'echo \"NODE_VERSION=\\$(node --version | sed \"s/v//\" | cut -d. -f1)\"'\nEOF\n\n# Create backend project with NO tools defined - should inherit from root\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n# No tools section - should inherit node 20 from root\n\n[tasks.build]\nrun = 'echo \"NODE_VERSION=\\$(node --version | sed \"s/v//\" | cut -d. -f1)\"'\nEOF\n\n# Create nested project to test multi-level inheritance\nmkdir -p projects/backend/api\ncat <<EOF >projects/backend/api/mise.toml\n# No tools section - should inherit from parent hierarchy\n\n[tasks.build]\nrun = 'echo \"NODE_VERSION=\\$(node --version | sed \"s/v//\" | cut -d. -f1)\"'\nEOF\n\n# Install tools\nmise install\n\n# Test 1: Root task should use node 20 from root config\necho \"=== Test 1: Root task uses node 20 from root config ===\"\nassert_contains \"mise run //:root-task\" \"v20\"\n\n# Test 2: Frontend task should use node 18 (overridden)\necho \"=== Test 2: Frontend task uses node 18 (overridden) ===\"\nassert_contains \"mise run //projects/frontend:build\" \"NODE_VERSION=18\"\n\n# Test 3: Backend task should inherit node 20 from root\necho \"=== Test 3: Backend task inherits node 20 from root ===\"\nassert_contains \"mise run //projects/backend:build\" \"NODE_VERSION=20\"\n\n# Test 4: Nested api task should inherit node 20 from root through parent\necho \"=== Test 4: Nested api task inherits node 20 from root ===\"\nassert_contains \"mise run //projects/backend/api:build\" \"NODE_VERSION=20\"\n\necho \"=== All tool inheritance tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_tool_inheritance_intermediate",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks inherit tools from intermediate parent directories\nexport MISE_EXPERIMENTAL=1\nexport MISE_NODE_VERIFY=0\n\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"parent/*\"]\nEOF\n\nmkdir -p parent\ncat <<EOF >parent/mise.toml\n[tools]\nnode = \"20\"\nEOF\n\nmkdir -p parent/child\ncat <<EOF >parent/child/mise.toml\n[tasks.build]\nrun = 'echo \"NODE_VERSION=\\$(node --version | cut -c2- | cut -d. -f1)\"'\nEOF\n\n# Install node from the parent directory where it's defined\n(cd parent && mise install)\n\necho \"=== Test: Child task inherits node 20 from intermediate parent ===\"\nassert_contains \"mise run //parent/child:build\" \"NODE_VERSION=20\"\n\necho \"=== Intermediate parent tool inheritance test passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_triple_colon_with_deps",
    "content": "#!/usr/bin/env bash\n\n# Test that ::: syntax works correctly when tasks have relative :dependency syntax\n# The ::: syntax allows running multiple task groups in sequence.\n# Each task group should correctly resolve its own relative dependencies.\n#\n# Example: `mise run //project-a:ci ::: //project-b:ci`\n# Each project's :ci task may have `depends = [\":bootstrap\"]` which should\n# resolve to that project's own :bootstrap task, not the monorepo root's.\n\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'EOF' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"libs/*\", \"apps/*\", \"tools/*\"]\n\n[settings]\nexperimental = true\nEOF\n\n# Create first project with format depending on bootstrap\nmkdir -p libs/shared\ncat <<'EOF' >libs/shared/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"shared bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"shared format executed\"'\n\n[tasks.lint]\ndepends = [\":bootstrap\"]\nrun = 'echo \"shared lint executed\"'\nEOF\n\n# Create second project with same pattern\nmkdir -p apps/frontend\ncat <<'EOF' >apps/frontend/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"frontend bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"frontend format executed\"'\n\n[tasks.build]\ndepends = [\":bootstrap\"]\nrun = 'echo \"frontend build executed\"'\nEOF\n\n# Create third project with same pattern\nmkdir -p apps/backend\ncat <<'EOF' >apps/backend/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"backend bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"backend format executed\"'\n\n[tasks.test]\ndepends = [\":format\"]\nrun = 'echo \"backend test executed\"'\nEOF\n\n# Create a project WITHOUT bootstrap to ensure it doesn't interfere\nmkdir -p tools/cli\ncat <<'EOF' >tools/cli/mise.toml\n[tasks.format]\nrun = 'echo \"cli format executed\"'\nEOF\n\n# Verify tasks are discovered correctly\nassert_contains \"mise tasks --all\" \"//libs/shared:format\"\nassert_contains \"mise tasks --all\" \"//libs/shared:bootstrap\"\nassert_contains \"mise tasks --all\" \"//apps/frontend:format\"\nassert_contains \"mise tasks --all\" \"//apps/frontend:bootstrap\"\nassert_contains \"mise tasks --all\" \"//apps/backend:format\"\nassert_contains \"mise tasks --all\" \"//apps/backend:bootstrap\"\nassert_contains \"mise tasks --all\" \"//tools/cli:format\"\n\n# Test 1: Basic ::: syntax with relative dependencies\n# Each task should resolve :bootstrap to its own project's bootstrap\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format\" \"shared bootstrap executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format\" \"shared format executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format\" \"frontend bootstrap executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format\" \"frontend format executed\"\n\n# Test 2: ::: with three projects - all should resolve their own dependencies\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"shared bootstrap executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"shared format executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"frontend bootstrap executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"frontend format executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"backend bootstrap executed\"\nassert_contains \"mise run //libs/shared:format ::: //apps/frontend:format ::: //apps/backend:format\" \"backend format executed\"\n\n# Test 3: ::: with chained relative dependencies\n# backend:test depends on :format which depends on :bootstrap\nassert_contains \"mise run //apps/backend:test ::: //libs/shared:lint\" \"backend bootstrap executed\"\nassert_contains \"mise run //apps/backend:test ::: //libs/shared:lint\" \"backend format executed\"\nassert_contains \"mise run //apps/backend:test ::: //libs/shared:lint\" \"backend test executed\"\nassert_contains \"mise run //apps/backend:test ::: //libs/shared:lint\" \"shared bootstrap executed\"\nassert_contains \"mise run //apps/backend:test ::: //libs/shared:lint\" \"shared lint executed\"\n\n# Test 4: ::: mixing project with dependencies and project without\n# tools/cli:format has no dependencies, others do\nassert_contains \"mise run //tools/cli:format ::: //libs/shared:format\" \"cli format executed\"\nassert_contains \"mise run //tools/cli:format ::: //libs/shared:format\" \"shared bootstrap executed\"\nassert_contains \"mise run //tools/cli:format ::: //libs/shared:format\" \"shared format executed\"\n\n# Test 5: ::: with wildcard in one group\n# Wildcard should expand and resolve dependencies, then ::: group runs separately\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"frontend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"frontend format executed\"\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"backend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"backend format executed\"\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"shared bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: //libs/shared:lint\" \"shared lint executed\"\n\n# Test 6: ::: with wildcards in multiple groups\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"frontend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"frontend format executed\"\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"backend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"backend format executed\"\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"shared bootstrap executed\"\nassert_contains \"mise run '//apps/...:format' ::: '//libs/...:format'\" \"shared format executed\"\n\necho \"=== All ::: with dependencies tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_trust",
    "content": "#!/usr/bin/env bash\n\n# Test that trusting a monorepo root implicitly trusts all descendant configs\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"projects/*\", \"projects/frontend/*\"]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Create nested project structure\nmkdir -p projects/frontend/components\ncat <<EOF >projects/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\nEOF\n\ncat <<EOF >projects/frontend/components/mise.toml\n[tasks.test]\nrun = 'echo \"component test\"'\nEOF\n\n# Trust the root config\nmise trust\n\n# Verify that all tasks are accessible without additional trust prompts\n# The lack of \"not trusted\" warnings in stderr indicates implicit trust is working\nassert_contains \"mise tasks ls --all 2>&1\" \"//:root-task\"\nassert_contains \"mise tasks ls --all 2>&1\" \"//projects/frontend:build\"\nassert_contains \"mise tasks ls --all 2>&1\" \"//projects/frontend/components:test\"\n\n# Verify no trust warnings appear\nassert_not_contains \"mise tasks ls --all 2>&1\" \"not trusted\"\nassert_not_contains \"mise tasks ls --all 2>&1\" \"Trust them\"\n\n# Verify we can run tasks from nested configs\nassert_contains \"mise run '//projects/frontend:build'\" \"frontend build\"\nassert_contains \"mise run '//projects/frontend/components:test'\" \"component test\"\n\n# Test that trust warnings DO appear for configs outside monorepo\n# Create a parent directory with its own config (not part of monorepo)\nmkdir -p ../parent-dir\ncat <<EOF >../parent-dir/mise.toml\n[tasks.parent-task]\nrun = 'echo \"parent task\"'\nEOF\n\n# Clear trust to simulate untrusted state\n# We need to explicitly unset MISE_TRUSTED_CONFIG_PATHS to test trust warnings\nexport MISE_TRUSTED_CONFIG_PATHS=\"\"\n\n# Verify trust error appears for the parent config (command should fail)\nassert_contains \"MISE_YES=0 mise -C ../parent-dir tasks ls 2>&1 || true\" \"are not trusted\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_usage_env",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks can use env vars in usage spec (issue #7828)\n# When a task uses `env=\"NAME\"` in its usage spec, the env var from the\n# child config should be available at parse time.\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"backend\"]\nEOF\n\n# Create backend project with env and task using usage with env= attribute\nmkdir -p backend\ncat <<EOF >backend/mise.toml\n[env]\nNAME = \"john\"\n\n[tasks.test]\nusage = '''\n  flag \"--name <name>\" env=\"NAME\"\n'''\nrun = '''\necho \"Name: {{usage.name}}\"\n'''\nEOF\n\n# Test 1: Running monorepo task with usage env should work\necho \"=== Test 1: Monorepo task with usage env= attribute ===\"\noutput=$(mise run '//backend:test' 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"Name: john\" || (echo \"FAIL: Expected 'Name: john' in output\" && exit 1)\n\n# Test 2: Passing explicit arg should override env default\necho \"=== Test 2: Explicit arg overrides env default ===\"\noutput=$(mise run '//backend:test' -- --name=\"alice\" 2>&1)\necho \"$output\"\necho \"$output\" | grep -q \"Name: alice\" || (echo \"FAIL: Expected 'Name: alice' when passing --name\" && exit 1)\n\n# Test 3: Task help should display without error\necho \"=== Test 3: Task help displays correctly ===\"\noutput=$(mise run '//backend:test' --help 2>&1)\necho \"$output\"\n# Should show the flag in help output\necho \"$output\" | grep -q \"\\-\\-name\" || (echo \"FAIL: Expected --name flag in help output\" && exit 1)\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_validation",
    "content": "#!/usr/bin/env bash\n\n# Test validation for monorepo task paths\n\n# Test 1: Running monorepo task without MISE_EXPERIMENTAL should error\nunset MISE_EXPERIMENTAL\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[tasks.local]\nrun = 'echo \"local task\"'\nEOF\n\n# Should fail with helpful error about MISE_EXPERIMENTAL\nassert_fail \"mise run '//some:task'\" \"require experimental mode\"\n\n# Test 2: Running monorepo task with MISE_EXPERIMENTAL but without monorepo root should error\nexport MISE_EXPERIMENTAL=1\ncat <<EOF >mise.toml\n[tasks.local]\nrun = 'echo \"local task\"'\nEOF\n\n# Should fail with helpful error about experimental_monorepo_root\nassert_fail \"mise run '//some:task'\" \"require a monorepo root configuration\"\n\n# Test 3: Wildcard patterns should also trigger validation\nunset MISE_EXPERIMENTAL\ncat <<EOF >mise.toml\n[tasks.local]\nrun = 'echo \"local task\"'\nEOF\n\n# Wildcard pattern without experimental mode should fail\nassert_fail \"mise run '//...:build'\" \"require experimental mode\"\n\n# Test 4: Three-dot syntax should also trigger validation\nassert_fail \"mise run '...:build'\" \"require experimental mode\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_vars",
    "content": "#!/usr/bin/env bash\n# Test that monorepo tasks properly load [vars] from subdirectory configs\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config with vars\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"infra/stacks/*\"]\n\n[vars]\nROOT_VAR = \"root_value\"\nSHARED_VAR = \"from_root\"\n\n[tasks.root-greet]\nrun = 'echo \"ROOT_VAR={{vars.ROOT_VAR}} SHARED_VAR={{vars.SHARED_VAR}}\"'\nEOF\n\n# Create subdirectory config with its own vars and tasks\nmkdir -p infra/stacks/gcp\ncat <<EOF >infra/stacks/gcp/mise.toml\n[vars]\nGCP_VAR = \"gcp_value\"\nSHARED_VAR = \"from_gcp\"\n\n[tasks.greet]\nrun = 'echo \"GCP_VAR={{vars.GCP_VAR}} SHARED_VAR={{vars.SHARED_VAR}} ROOT_VAR={{vars.ROOT_VAR}}\"'\n\n[tasks.greet-dev]\nrun = 'echo \"DEV_VAR={{vars.DEV_VAR}} SHARED_VAR={{vars.SHARED_VAR}}\"'\nEOF\n\n# Create MISE_ENV-specific config for the subdirectory\ncat <<EOF >infra/stacks/gcp/mise.dev.toml\n[vars]\nDEV_VAR = \"dev_value\"\nSHARED_VAR = \"from_gcp_dev\"\nEOF\n\n# Test 1: Root task sees root vars\necho \"=== Test 1: Root task sees root vars ===\"\nunset MISE_ENV\noutput=$(mise run //:root-greet)\necho \"$output\"\nassert_contains \"echo '$output'\" \"ROOT_VAR=root_value\"\nassert_contains \"echo '$output'\" \"SHARED_VAR=from_root\"\n\n# Test 2: Subdirectory task sees its own vars, inherits root vars, and overrides shared vars\necho \"=== Test 2: Subdirectory task var resolution ===\"\nunset MISE_ENV\noutput=$(mise run '//infra/stacks/gcp:greet')\necho \"$output\"\n# Core bug fix: subdirectory vars are loaded\nassert_contains \"echo '$output'\" \"GCP_VAR=gcp_value\"\n# Subdirectory vars override root vars of the same name\nassert_contains \"echo '$output'\" \"SHARED_VAR=from_gcp\"\n# Subdirectory task still inherits root vars it doesn't override\nassert_contains \"echo '$output'\" \"ROOT_VAR=root_value\"\n\n# Test 3: Subdirectory task with MISE_ENV sees env-specific vars\necho \"=== Test 3: MISE_ENV-specific vars in subdirectory ===\"\noutput=$(MISE_ENV=dev mise run '//infra/stacks/gcp:greet-dev')\necho \"$output\"\nassert_contains \"echo '$output'\" \"DEV_VAR=dev_value\"\n# MISE_ENV vars should override base vars\nassert_contains \"echo '$output'\" \"SHARED_VAR=from_gcp_dev\"\n\n# Test 4: Per-task vars override subdirectory config vars\necho \"=== Test 4: Per-task vars override subdirectory config vars ===\"\ncat <<EOF >infra/stacks/gcp/mise.toml\n[vars]\nGCP_VAR = \"gcp_value\"\nSHARED_VAR = \"from_gcp\"\n\n[tasks.greet]\nrun = 'echo \"GCP_VAR={{vars.GCP_VAR}} SHARED_VAR={{vars.SHARED_VAR}} ROOT_VAR={{vars.ROOT_VAR}}\"'\n\n[tasks.greet-dev]\nrun = 'echo \"DEV_VAR={{vars.DEV_VAR}} SHARED_VAR={{vars.SHARED_VAR}}\"'\n\n[tasks.greet-override]\nrun = 'echo \"GCP_VAR={{vars.GCP_VAR}} SHARED_VAR={{vars.SHARED_VAR}}\"'\nvars = { SHARED_VAR = \"task_override\" }\nEOF\nunset MISE_ENV\noutput=$(mise run '//infra/stacks/gcp:greet-override')\necho \"$output\"\n# Per-task var overrides config-level var\nassert_contains \"echo '$output'\" \"SHARED_VAR=task_override\"\n# Config-level var not overridden at task level is still accessible\nassert_contains \"echo '$output'\" \"GCP_VAR=gcp_value\"\n\necho \"=== All tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_wildcard_with_deps",
    "content": "#!/usr/bin/env bash\n\n# Test that wildcard patterns work correctly when tasks have relative :dependency syntax\n# e.g., `mise run '//...:format'` where each project's format task has `depends = [\":bootstrap\"]`\n# should resolve :bootstrap to each project's own bootstrap task.\n\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<'EOF' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"libs/*\", \"apps/*\", \"tools/*\"]\n\n[settings]\nexperimental = true\nEOF\n\n# Create first project with format depending on bootstrap\nmkdir -p libs/shared\ncat <<'EOF' >libs/shared/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"shared bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"shared format executed\"'\n\n[tasks.lint]\ndepends = [\":bootstrap\"]\nrun = 'echo \"shared lint executed\"'\nEOF\n\n# Create second project with same pattern\nmkdir -p apps/frontend\ncat <<'EOF' >apps/frontend/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"frontend bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"frontend format executed\"'\n\n[tasks.build]\ndepends = [\":bootstrap\"]\nrun = 'echo \"frontend build executed\"'\nEOF\n\n# Create third project with same pattern\nmkdir -p apps/backend\ncat <<'EOF' >apps/backend/mise.toml\n[tasks.bootstrap]\nrun = 'echo \"backend bootstrap executed\"'\n\n[tasks.format]\ndepends = [\":bootstrap\"]\nrun = 'echo \"backend format executed\"'\n\n[tasks.test]\ndepends = [\":format\"]\nrun = 'echo \"backend test executed\"'\nEOF\n\n# Create a project WITHOUT bootstrap to ensure it doesn't interfere\nmkdir -p tools/cli\ncat <<'EOF' >tools/cli/mise.toml\n[tasks.format]\nrun = 'echo \"cli format executed\"'\nEOF\n\n# Verify tasks are discovered correctly\nassert_contains \"mise tasks --all\" \"//libs/shared:format\"\nassert_contains \"mise tasks --all\" \"//libs/shared:bootstrap\"\nassert_contains \"mise tasks --all\" \"//apps/frontend:format\"\nassert_contains \"mise tasks --all\" \"//apps/frontend:bootstrap\"\nassert_contains \"mise tasks --all\" \"//apps/backend:format\"\nassert_contains \"mise tasks --all\" \"//apps/backend:bootstrap\"\nassert_contains \"mise tasks --all\" \"//tools/cli:format\"\n\n# Test 1: Individual task execution works (baseline)\nassert_contains \"mise run //libs/shared:format\" \"shared bootstrap executed\"\nassert_contains \"mise run //libs/shared:format\" \"shared format executed\"\n\nassert_contains \"mise run //apps/frontend:format\" \"frontend bootstrap executed\"\nassert_contains \"mise run //apps/frontend:format\" \"frontend format executed\"\n\nassert_contains \"mise run //apps/backend:format\" \"backend bootstrap executed\"\nassert_contains \"mise run //apps/backend:format\" \"backend format executed\"\n\n# Test 2: Wildcard with dependencies should work\nassert_contains \"mise run '//...:format'\" \"shared bootstrap executed\"\nassert_contains \"mise run '//...:format'\" \"shared format executed\"\nassert_contains \"mise run '//...:format'\" \"frontend bootstrap executed\"\nassert_contains \"mise run '//...:format'\" \"frontend format executed\"\nassert_contains \"mise run '//...:format'\" \"backend bootstrap executed\"\nassert_contains \"mise run '//...:format'\" \"backend format executed\"\nassert_contains \"mise run '//...:format'\" \"cli format executed\"\n\n# Test 3: Partial wildcard with dependencies\nassert_contains \"mise run '//apps/...:format'\" \"frontend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format'\" \"frontend format executed\"\nassert_contains \"mise run '//apps/...:format'\" \"backend bootstrap executed\"\nassert_contains \"mise run '//apps/...:format'\" \"backend format executed\"\n\n# Test 4: Task name wildcard with dependencies\nassert_contains \"mise run '//libs/shared:*'\" \"shared bootstrap executed\"\nassert_contains \"mise run '//libs/shared:*'\" \"shared format executed\"\nassert_contains \"mise run '//libs/shared:*'\" \"shared lint executed\"\n\n# Test 5: Chained dependencies through wildcards\n# backend:test depends on :format which depends on :bootstrap\nassert_contains \"mise run '//apps/backend:test'\" \"backend bootstrap executed\"\nassert_contains \"mise run '//apps/backend:test'\" \"backend format executed\"\nassert_contains \"mise run '//apps/backend:test'\" \"backend test executed\"\n\n# Test 6: Wildcard should work for tasks with chained relative dependencies\nassert_contains \"mise run '//...:test'\" \"backend bootstrap executed\"\nassert_contains \"mise run '//...:test'\" \"backend format executed\"\nassert_contains \"mise run '//...:test'\" \"backend test executed\"\n\necho \"=== All wildcard with dependencies tests passed! ===\"\n"
  },
  {
    "path": "e2e/tasks/test_task_monorepo_wildcards",
    "content": "#!/usr/bin/env bash\n\n# Test monorepo task wildcards with ellipsis for paths and asterisk for task names\nexport MISE_EXPERIMENTAL=1\n\n# Create monorepo root config\ncat <<EOF >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\n  \"projects/frontend\",\n  \"projects/backend\",\n  \"projects/services/api/v1\",\n  \"projects/tools/cli\",\n  \"libs/shared\",\n  \"libs/shared/utils\"\n]\n\n[tasks.root-task]\nrun = 'echo \"root task\"'\nEOF\n\n# Create project structure with nested tasks\nmkdir -p projects/frontend\ncat <<EOF >projects/frontend/mise.toml\n[tasks.build]\nrun = 'echo \"frontend build\"'\n\n[tasks.test]\nrun = 'echo \"frontend test\"'\n\n[tasks.\"test:unit\"]\nrun = 'echo \"frontend test:unit\"'\n\n[tasks.\"test:integration\"]\nrun = 'echo \"frontend test:integration\"'\nEOF\n\nmkdir -p projects/backend\ncat <<EOF >projects/backend/mise.toml\n[tasks.build]\nrun = 'echo \"backend build\"'\n\n[tasks.test]\nrun = 'echo \"backend test\"'\n\n[tasks.deploy]\nrun = 'echo \"backend deploy\"'\nEOF\n\nmkdir -p libs/shared\ncat <<EOF >libs/shared/mise.toml\n[tasks.build]\nrun = 'echo \"shared build\"'\n\n[tasks.lint]\nrun = 'echo \"shared lint\"'\nEOF\n\n# Verify monorepo tasks are discovered with --all flag\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:build\"\nassert_contains \"mise tasks ls --all\" \"//projects/backend:build\"\nassert_contains \"mise tasks ls --all\" \"//libs/shared:build\"\n\n# By default (without --all), only shows tasks from current hierarchy\n# At root, this includes the root task (shown as //:root-task)\nassert_contains \"mise tasks ls\" \"//:root-task\"\nassert_not_contains \"mise tasks ls\" \"//projects/frontend:build\"\nassert_not_contains \"mise tasks ls\" \"//projects/backend:build\"\nassert_not_contains \"mise tasks ls\" \"//libs/shared:build\"\n\n# Test from subdirectory - shows local tasks with full monorepo paths\ncd projects/frontend\nassert_contains \"mise tasks ls\" \"//:root-task\"\nassert_contains \"mise tasks ls\" \"//projects/frontend:build\"\nassert_contains \"mise tasks ls\" \"//projects/frontend:test\"\nassert_not_contains \"mise tasks ls\" \"//projects/backend:build\"\nassert_not_contains \"mise tasks ls\" \"//libs/shared:build\"\n\n# From subdirectory with --all - should see everything\nassert_contains \"mise tasks ls --all\" \"//projects/frontend:build\"\nassert_contains \"mise tasks ls --all\" \"//projects/backend:build\"\nassert_contains \"mise tasks ls --all\" \"//libs/shared:build\"\n\n# Go back to root\ncd ../..\n\n# Test ellipsis for path matching - match all build tasks\nassert_contains \"mise run '//...:build'\" \"frontend build\"\nassert_contains \"mise run '//...:build'\" \"backend build\"\nassert_contains \"mise run '//...:build'\" \"shared build\"\n\n# Test ellipsis with path prefix - match all test tasks under projects/\nassert_contains \"mise run '//projects/...:test'\" \"frontend test\"\nassert_contains \"mise run '//projects/...:test'\" \"backend test\"\nassert_not_contains \"mise run '//projects/...:test'\" \"shared\"\n\n# Test asterisk for task name matching - all tasks in backend\nassert_contains \"mise run '//projects/backend:*'\" \"backend build\"\nassert_contains \"mise run '//projects/backend:*'\" \"backend test\"\nassert_contains \"mise run '//projects/backend:*'\" \"backend deploy\"\n\n# Test asterisk with prefix - match tasks starting with test:\nassert_contains \"mise run '//projects/frontend:test:*'\" \"frontend test:unit\"\nassert_contains \"mise run '//projects/frontend:test:*'\" \"frontend test:integration\"\nassert_not_contains \"mise run '//projects/frontend:test:*'\" \"frontend build\"\n\n# Test that relative patterns (without //) are not supported\nassert_fail \"mise run 'projects/...:build'\" \"relative path syntax\"\n\n# Test combined patterns - ellipsis in path, asterisk in task\nassert_contains \"mise run '//projects/...:test*'\" \"frontend test\"\nassert_contains \"mise run '//projects/...:test*'\" \"frontend test:unit\"\nassert_contains \"mise run '//projects/...:test*'\" \"frontend test:integration\"\nassert_contains \"mise run '//projects/...:test*'\" \"backend test\"\n\n# Test ellipsis wildcard in different positions\n# Create test structure with nested directories\nmkdir -p projects/services/api/v1\ncat <<SUBEOF >projects/services/api/v1/mise.toml\n[tasks.deploy]\nrun = 'echo \"api v1 deploy\"'\nSUBEOF\n\nmkdir -p projects/tools/cli\ncat <<SUBEOF >projects/tools/cli/mise.toml\n[tasks.build]\nrun = 'echo \"cli build\"'\nSUBEOF\n\nmkdir -p libs/shared/utils\ncat <<SUBEOF >libs/shared/utils/mise.toml\n[tasks.test]\nrun = 'echo \"utils test\"'\nSUBEOF\n\n# Test 1: ... at the START of path (matches any depth before)\n# Pattern: //.../cli:build should match //projects/tools/cli:build\nassert_contains \"mise run '//.../cli:build'\" \"cli build\"\n\n# Test 2: ... in the MIDDLE of path\n# Pattern: //projects/.../api:task should match //projects/services/api/v1:deploy\nassert_contains \"mise run '//projects/.../v1:deploy'\" \"api v1 deploy\"\n\n# Pattern: //libs/.../utils:test should match //libs/shared/utils:test\nassert_contains \"mise run '//libs/.../utils:test'\" \"utils test\"\n\n# Test 3: ... at the END of path (matches all subdirectories)\n# Pattern: //projects/tools/...:build should match //projects/tools/cli:build\nassert_contains \"mise run '//projects/tools/...:build'\" \"cli build\"\n\n# Pattern: //projects/...:deploy should match //projects/services/api/v1:deploy\nassert_contains \"mise run '//projects/...:deploy'\" \"api v1 deploy\"\n\n# Test 4: Multiple ... in one pattern\n# Pattern: //projects/.../api/...:deploy should match //projects/services/api/v1:deploy\nassert_contains \"mise run '//projects/.../api/...:deploy'\" \"api v1 deploy\"\n\n# Test 5: ... alone (matches everything)\nassert_contains \"mise run '//...:build'\" \"cli build\"\nassert_contains \"mise run '//...:test'\" \"utils test\"\n\n# Verify tasks are discovered\nassert_contains \"mise tasks --all\" \"//projects/services/api/v1:deploy\"\nassert_contains \"mise tasks --all\" \"//projects/tools/cli:build\"\nassert_contains \"mise tasks --all\" \"//libs/shared/utils:test\"\n"
  },
  {
    "path": "e2e/tasks/test_task_nested_quiet",
    "content": "#!/usr/bin/env bash\n\n# Test that quiet directive is respected in nested task calls\n# even when parent task has multiple dependencies (which triggers prefix mode)\n\ncat <<EOF >mise.toml\n[tasks.dep1]\nrun = 'echo dep1'\n\n[tasks.dep2]\nrun = 'echo dep2'\n\n[tasks.\"child:quiet\"]\nquiet = true\nrun = 'echo child output'\n\n[tasks.parent]\ndepends = ['dep1', 'dep2']\nrun = 'mise run child:quiet'\nEOF\n\n# When parent has multiple deps, it would previously export MISE_TASK_OUTPUT=prefix\n# which would override the child task's quiet=true setting\n# After the fix, the child task should respect its quiet directive\n# Note: dep1 and dep2 run in parallel so their order is non-deterministic\nassert_contains \"mise run parent\" \"[dep1] dep1\"\nassert_contains \"mise run parent\" \"[dep2] dep2\"\nassert_contains \"mise run parent\" \"[parent] child output\"\n"
  },
  {
    "path": "e2e/tasks/test_task_option_tera_behaviors",
    "content": "#!/usr/bin/env bash\n\n# Repro tests for inconsistent tera behaviour with {{ option() }} from\n# discussion https://github.com/jdx/mise/discussions/6646\n\n# wtf:echo\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:echo\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  echo val={{ val }}\n\"\"\"\nEOF\nassert \"mise run wtf:echo\" \"val=\"\nassert \"mise run wtf:echo --val=hello\" \"val=hello\"\n\n# wtf:eq-shell\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:eq-shell\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  if [ \"{{ val }}\" = \"hello\" ]; then echo 'was hello'; else echo 'not hello'; fi\n\"\"\"\nEOF\nassert \"mise run wtf:eq-shell\" \"not hello\"\nassert \"mise run wtf:eq-shell --val=hello\" \"was hello\"\n\n# wtf:eq-tera\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:eq-tera\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {% if val == \"hello\" %}\n    echo 'was eq hello'\n  {% else %}\n    echo 'not eq hello'\n  {% endif %}\n\"\"\"\nEOF\nassert \"mise run wtf:eq-tera\" \"not eq hello\"\nassert \"mise run wtf:eq-tera --val=hello\" \"was eq hello\"\n\n# wtf:defined\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:defined\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {% if val is defined %}\n    echo 'was defined'\n  {% else %}\n    echo 'not defined'\n  {% endif %}\n\"\"\"\nEOF\nassert \"mise run wtf:defined\" \"was defined\"\nassert \"mise run wtf:defined --val=hello\" \"was defined\"\n\n# wtf:truthy\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:truthy\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {% if val %}\n    echo 'was truthy'\n  {% else %}\n    echo 'not truthy'\n  {% endif %}\n\"\"\"\nEOF\nassert \"mise run wtf:truthy\" \"not truthy\"\nassert \"mise run wtf:truthy --val=hello\" \"was truthy\"\n\n# wtf:throw (should fail currently due to throw(message=null) during arg parsing pass)\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:throw\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {{ throw(message=val) }}\n\"\"\"\nEOF\nassert_fail_contains \"mise run wtf:throw\" \"ERROR task failed\"\nassert_fail_contains \"mise run wtf:throw --val=hello\" \"ERROR hello\"\n#\n# wtf:default (default filter applied prior to throw)\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:default\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {% set val = val | default(value='???') %}\n  {{ throw(message=val) }}\n\"\"\"\nEOF\nassert_fail_contains \"mise run wtf:default\" \"ERROR task failed\"\nassert_fail_contains \"mise run wtf:default --val=hello\" \"ERROR hello\"\n\n# wtf:as_str (filter produces empty string by default)\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:as_str\"]\nrun = \"\"\"\n  {% set val = option(name='val') %}\n  {{ throw(message=val | as_str) }}\n\"\"\"\nEOF\nassert_fail_contains \"mise run wtf:as_str\" \"ERROR task failed\"\nassert_fail_contains \"mise run wtf:as_str --val=hello\" \"ERROR hello\"\n\n# wtf:option-default (option default used in throw path)\ncat <<'EOF' >mise.toml\n[tasks.\"wtf:option-default\"]\nrun = \"\"\"\n  {% set val = option(name='val', default='???') %}\n  {{ throw(message=val) }}\n\"\"\"\nEOF\nassert_fail_contains \"mise run wtf:option-default\" \"ERROR '???'\"\n"
  },
  {
    "path": "e2e/tasks/test_task_options",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.mytask = 'echo {{option(name=\"foo\")}}'\nEOF\n\nassert \"mise run mytask --foo bar\" \"bar\"\nassert \"mise run mytask -- --foo bar\" \"bar\"\nassert \"mise mytask --foo bar\" \"bar\"\nassert \"mise mytask -- --foo bar\" \"bar\"\n"
  },
  {
    "path": "e2e/tasks/test_task_parallel_execution",
    "content": "#!/usr/bin/env bash\n\n# Test for parallel task execution reliability (GitHub issue #5451)\n# This test verifies that tasks with ::: syntax run concurrently rather than sequentially\n\nset -euo pipefail\n\n# Create a temporary file to track task execution order and timing\ntemp_log=$(mktemp)\ntrap 'rm -f $temp_log' EXIT\n\ncat <<EOF >mise.toml\n[tools]\npoetry = \"latest\"\n\n[tasks.process1]\nrun = '''\necho \"\\$(date +%s%N) process1 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process1 end\" >> $temp_log\necho \"process1 complete\"\n'''\n\n[tasks.process2]\nrun = '''\necho \"\\$(date +%s%N) process2 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process2 end\" >> $temp_log\necho \"process2 complete\"\n'''\n\n[tasks.process3]\nrun = '''\necho \"\\$(date +%s%N) process3 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process3 end\" >> $temp_log\necho \"process3 complete\"\n'''\n\n[tasks.process4]\nrun = '''\necho \"\\$(date +%s%N) process4 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process4 end\" >> $temp_log\necho \"process4 complete\"\n'''\n\n[tasks.process5]\nrun = '''\necho \"\\$(date +%s%N) process5 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process5 end\" >> $temp_log\necho \"process5 complete\"\n'''\n\n[tasks.process6]\nrun = '''\necho \"\\$(date +%s%N) process6 start\" >> $temp_log\nsleep 2\necho \"\\$(date +%s%N) process6 end\" >> $temp_log\necho \"process6 complete\"\n'''\n\n[tasks.run-all]\nrun = \"mise run process1 ::: process2 ::: process3 ::: process4 ::: process5 ::: process6\"\nEOF\n\nassert \"mise install\"\n\necho \"Testing parallel task execution (running 3 times for reliability)...\"\n\n# Run the test 3 times to ensure reliability\nfor test_run in {1..3}; do\n\techo \"\"\n\techo \"=== Test Run $test_run/3 ===\"\n\n\t# Clear the log file for each run\n\trm -f \"$temp_log\"\n\n\t# Record start time for overall execution time measurement\n\tstart_time=$(date +%s)\n\n\t# Run the tasks and capture output\n\ttask_output=$(mise run run-all)\n\n\t# Record end time\n\tend_time=$(date +%s)\n\ttotal_time=$((end_time - start_time))\n\n\techo \"Total execution time: ${total_time}s\"\n\n\t# Read the log file to analyze timing\n\techo \"Task execution log:\"\n\tcat \"$temp_log\" | sort\n\n\t# Parse start/end times using bash3-compatible arrays (mapfile is bash4+).\n\tstart_times=()\n\twhile IFS= read -r ts; do\n\t\tstart_times+=(\"$ts\")\n\tdone < <(grep \"start\" \"$temp_log\" | awk '{print $1}' | sort -n)\n\tend_times=()\n\twhile IFS= read -r ts; do\n\t\tend_times+=(\"$ts\")\n\tdone < <(grep \"end\" \"$temp_log\" | awk '{print $1}' | sort -n)\n\n\techo \"Analyzing task start times...\"\n\n\tif [ ${#start_times[@]} -ne 6 ]; then\n\t\techo \"ERROR: Expected 6 task start times, got ${#start_times[@]}\"\n\t\texit 1\n\tfi\n\n\tif [ ${#end_times[@]} -ne 6 ]; then\n\t\techo \"ERROR: Expected 6 task end times, got ${#end_times[@]}\"\n\t\texit 1\n\tfi\n\n\t# Calculate time differences between task starts (in nanoseconds)\n\t# For parallel execution, all tasks should start within a small window (< 1 second)\n\tfirst_start=${start_times[0]}\n\tlast_start=${start_times[5]}\n\tstart_spread=$((last_start - first_start))\n\n\t# Convert nanoseconds to milliseconds for easier interpretation\n\tstart_spread_ms=$((start_spread / 1000000))\n\n\techo \"Time between first and last task start: ${start_spread_ms}ms\"\n\n\t# Check if tasks started in parallel (within 1 second = 1000ms)\n\tif [ $start_spread_ms -gt 1000 ]; then\n\t\techo \"WARNING: Tasks may not be running in parallel. Start spread: ${start_spread_ms}ms\"\n\t\techo \"This could indicate the original issue is still present.\"\n\telse\n\t\techo \"✓ Tasks started concurrently (within ${start_spread_ms}ms)\"\n\tfi\n\n\t# Critical check: Ensure all tasks start before any task completes\n\t# This is essential for true parallel execution\n\techo \"Checking that all tasks start before any complete...\"\n\tlast_start_time=${start_times[5]}\n\tfirst_end_time=${end_times[0]}\n\n\tif [ \"$last_start_time\" -gt \"$first_end_time\" ]; then\n\t\techo \"ERROR: Some tasks completed before all tasks started!\"\n\t\techo \"Last task started at: $last_start_time\"\n\t\techo \"First task completed at: $first_end_time\"\n\t\techo \"This indicates sequential execution, not parallel execution.\"\n\t\texit 1\n\telse\n\t\techo \"✓ All tasks started before any completed - confirming parallel execution\"\n\tfi\n\n\t# Check total execution time\n\t# If running sequentially: 6 tasks * 2 seconds = ~12 seconds\n\t# If running in parallel: ~2-3 seconds (plus overhead)\n\tif [ $total_time -gt 8 ]; then\n\t\techo \"ERROR: Total execution time too long (${total_time}s). Tasks appear to be running sequentially.\"\n\t\techo \"Expected: ~2-4 seconds for parallel execution\"\n\t\techo \"Got: ${total_time}s (suggests sequential execution)\"\n\t\texit 1\n\telse\n\t\techo \"✓ Total execution time acceptable (${total_time}s) - suggests parallel execution\"\n\tfi\n\n\t# Verify all tasks completed successfully using the captured output\n\tfor i in {1..6}; do\n\t\tif ! grep -q \"process${i} complete\" <<<\"$task_output\"; then\n\t\t\techo \"ERROR: process${i} did not complete successfully\"\n\t\t\texit 1\n\t\tfi\n\tdone\n\n\techo \"✓ All tasks completed successfully in test run $test_run\"\ndone\n\necho \"\"\necho \"✓ All 3 test runs passed - Parallel task execution test passed\"\n"
  },
  {
    "path": "e2e/tasks/test_task_prefix_args_disambiguation",
    "content": "#!/usr/bin/env bash\n\n# Test that task output prefixes include args only when the same task runs\n# multiple times with different arguments (disambiguation), and omit args\n# when there's no conflict.\n\ncat <<'EOF' >mise.toml\n[tasks.greet]\nrun = 'echo \"hello $1\"'\n\n[tasks.build]\nrun = 'echo \"building\"'\nEOF\n\n# When the same task runs twice with different args, prefixes should include args\noutput=\"$(mise run greet alice ::: greet bob 2>&1)\"\nassert_contains \"echo \\\"$output\\\"\" \"[greet alice]\"\nassert_contains \"echo \\\"$output\\\"\" \"[greet bob]\"\n\n# When a task runs only once, prefix should NOT include args\noutput=\"$(mise run greet alice 2>&1)\"\nassert_not_contains \"echo \\\"$output\\\"\" \"[greet alice]\"\nassert_contains \"echo \\\"$output\\\"\" \"[greet]\"\n\n# Different tasks should not trigger disambiguation\noutput=\"$(mise run greet alice ::: build 2>&1)\"\nassert_not_contains \"echo \\\"$output\\\"\" \"[greet alice]\"\nassert_contains \"echo \\\"$output\\\"\" \"[greet]\"\nassert_contains \"echo \\\"$output\\\"\" \"[build]\"\n"
  },
  {
    "path": "e2e/tasks/test_task_project_root",
    "content": "#!/usr/bin/env bash\n\nmise tasks add a:b:c --file -- echo \\$MISE_PROJECT_ROOT\nassert \"mise a:b:c\" \"$PWD\"\n"
  },
  {
    "path": "e2e/tasks/test_task_raw_output",
    "content": "#!/usr/bin/env bash\n\n# Test that raw tasks get interleave output even when task.output=prefix is set\n# This ensures raw=true takes priority over task.output setting\n\ncat <<EOF >mise.toml\n[settings]\ntask.output = \"prefix\"\n\n[tasks.normal]\nrun = 'echo normal task'\n\n[tasks.raw_task]\nraw = true\nrun = 'echo raw task output'\nEOF\n\n# Normal task should use prefix output (from settings)\nassert_contains \"mise run normal\" \"[normal] normal task\"\n\n# Raw task should get interleave output mode, meaning stdout goes directly\n# without the [task_name] prefix being applied to the actual output\nassert \"mise run raw_task\" \"raw task output\"\n\n# Verify stdout doesn't have the prefix (only check stdout, not stderr)\nstdout_output=$(mise run raw_task 2>/dev/null)\nif [[ $stdout_output == *\"[raw_task]\"* ]]; then\n\techo \"FAIL: raw task stdout should not have prefix\"\n\texit 1\nfi\necho \"SUCCESS: raw task stdout has no prefix\"\n"
  },
  {
    "path": "e2e/tasks/test_task_redactions",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\nredactions = [\"SECRET\"]\n[env]\nSECRET = \"my_secret\"\n\n[tasks.a]\nrun = 'echo secret: \\$SECRET'\nEOF\n\nassert \"mise run a\" \"secret: [redacted]\"\n\ncat <<EOF >mise.toml\nredactions = [\"secret\"]\n[tasks.a]\nrun = 'echo secret: {{ vars.secret }}'\n\n[vars]\nsecret = \"my_secret\"\nEOF\nassert \"mise run a\" \"secret: [redacted]\"\n\ncat <<EOF >mise.toml\nredactions = [\"SECRET*\"]\n[env]\nSECRET_FOO = \"my_secret_wild\"\n\n[tasks.a]\nrun = 'echo secret: \\$SECRET_FOO'\nEOF\nassert \"mise run a\" \"secret: [redacted]\"\n\ncat <<EOF >mise.toml\n[env]\nSECRET= {value = \"my_secret\", redact = true}\n\n[tasks.a]\nrun = 'echo secret: \\$SECRET'\nEOF\nassert \"mise run a\" \"secret: [redacted]\"\n\necho '{ \"SECRET\": \"my_secret\" }' >.env.json\ncat <<EOF >mise.toml\n[env]\n_.file = {path = \".env.json\", redact = true}\n\n[tasks.a]\nrun = 'echo secret: \\$SECRET'\nEOF\nassert \"mise run a\" \"secret: [redacted]\"\n\ncat <<'TOML' >mise.toml\n[env]\nEMPTY_SECRET = { value = \"\", redact = true }\n\n[tasks.empty_redaction]\nrun = 'echo \"Hello $EMPTY_SECRET\"'\nTOML\nassert \"mise run empty_redaction\" \"Hello \"\n\ncat <<'TOML' >mise.toml\n[env]\nSECRET_WITH_TOOLS = { value = \"tools_secret\", tools = true, redact = true }\n\n[tasks.a]\nrun = 'echo secret: $SECRET_WITH_TOOLS'\nTOML\nassert \"mise run a\" \"secret: [redacted]\"\n\n# Test task-specific env._.file with redactions pattern\necho '{ \"NOTIFY_AVATAR\": \"task_file_secret\" }' >.env.json\ncat <<'TOML' >mise.toml\nredactions = [\"NOTIFY_*\"]\n[tasks.a]\nrun = \"echo secret: $NOTIFY_AVATAR\"\nenv._.file = \".env.json\"\nTOML\nassert \"mise run a\" \"secret: [redacted]\"\n\n# Test task-specific env._.file with redact=true\necho '{ \"TASK_SECRET\": \"task_secret_val\" }' >.env.json\ncat <<'TOML' >mise.toml\n[tasks.a]\nrun = \"echo secret: $TASK_SECRET\"\nenv._.file = {path = \".env.json\", redact = true}\nTOML\nassert \"mise run a\" \"secret: [redacted]\"\n"
  },
  {
    "path": "e2e/tasks/test_task_remote_git_https",
    "content": "#!/usr/bin/env bash\n\n#################################################################################\n# Setup\n#################################################################################\n\n# Clean up any previous server files\nrm -f /tmp/mise_git_http_port /tmp/mise_git_http_ready /tmp/mise_git_http_info\n\n# Start local git HTTP server with OS-assigned port to avoid race conditions\npython3 \"${TEST_ROOT}/helpers/scripts/git_http_backend_server.py\" 0 &\nSERVER_PID=$!\n\n# Wait for server to be ready (with timeout)\nwait_for_server() {\n\tlocal max_attempts=30 # 30 seconds timeout\n\tlocal attempt=1\n\n\twhile [ $attempt -le $max_attempts ]; do\n\t\tif [ -f /tmp/mise_git_http_ready ] && [ -f /tmp/mise_git_http_port ]; then\n\t\t\treturn 0\n\t\tfi\n\t\tsleep 1\n\t\tattempt=$((attempt + 1))\n\tdone\n\n\techo \"ERROR: Git HTTP server failed to start within 30 seconds\"\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\texit 1\n}\n\nwait_for_server\n\n# Read the actual port from the file\nSERVER_PORT=$(cat /tmp/mise_git_http_port)\nLOCAL_GIT_URL=\"http://localhost:${SERVER_PORT}/repo.git\"\n\n# Update cache directory paths for local server\nREMOTE_TASKS_DIR=\"${MISE_CACHE_DIR}/remote-git-tasks-cache\"\n# Hash for localhost URL will be different than GitHub URL\nLOCAL_CACHE_HASH=$(echo -n \"${LOCAL_GIT_URL}v2025.1.17\" | shasum -a 256 | cut -d' ' -f1)\nMISE_LOCAL_CACHE_DIR=\"${REMOTE_TASKS_DIR}/${LOCAL_CACHE_HASH}\"\n\ncargo init --name hello_cargo\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\trm -f /tmp/mise_git_http_port /tmp/mise_git_http_ready /tmp/mise_git_http_info\n}\ntrap cleanup EXIT\n\n#################################################################################\n# Test remote tasks with no ref\n#################################################################################\n\ncat <<EOF >mise.toml\n[tasks.remote_lint_https_latest]\nfile  = \"git::${LOCAL_GIT_URL}//xtasks/lint/ripgrep\"\nEOF\n\nassert_contains \"mise tasks\" \"remote_lint_https_latest\"\nassert_succeed \"mise run remote_lint_https_latest\" # Remote task should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\nassert_succeed \"MISE_TASK_REMOTE_NO_CACHE=true mise run remote_lint_https_latest\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nassert_succeed \"mise run --no-cache remote_lint_https_latest\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nassert_succeed \"mise run remote_lint_https_latest\" # Cache should be used\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\n#################################################################################\n# Test remote tasks with with ref\n#################################################################################\n\ncat <<EOF >mise.toml\n[tasks.remote_lint_https_ref]\nfile  = \"git::${LOCAL_GIT_URL}//xtasks/lint/ripgrep?ref=v2025.1.17\"\nEOF\n\nassert_contains \"mise tasks\" \"remote_lint_https_ref\"\nassert_succeed \"mise run remote_lint_https_ref\" # Remote task should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\nassert_directory_exists \"${MISE_LOCAL_CACHE_DIR}\"\nassert_directory_not_empty \"${MISE_LOCAL_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\nassert_succeed \"MISE_TASK_REMOTE_NO_CACHE=true mise run remote_lint_https_ref\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nassert_succeed \"mise run --no-cache remote_lint_https_ref\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_exists \"${MISE_LOCAL_CACHE_DIR}\"\n\nassert_succeed \"mise run remote_lint_https_ref\" # Cache should be used\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\nassert_directory_exists \"${MISE_LOCAL_CACHE_DIR}\"\nassert_directory_not_empty \"${MISE_LOCAL_CACHE_DIR}\"\n\n#################################################################################\n# Test usage and info commands with git remote tasks\n# Verifies fix for https://github.com/jdx/mise/discussions/7578\n#################################################################################\n\n# Usage should work and show task in completion output\nassert_contains \"mise tasks ls --usage\" 'cmd remote_lint_https_ref'\n\n# Info should show local cached path, not git URL\nassert_contains \"mise tasks info remote_lint_https_ref\" \"remote-git-tasks-cache\"\nassert_not_contains \"mise tasks info remote_lint_https_ref\" \"git::http\"\n\n# JSON output should also work\nassert_contains \"mise tasks info remote_lint_https_ref --json\" '\"file\":'\nassert_contains \"mise tasks info remote_lint_https_ref --json\" \"remote-git-tasks-cache\"\n\n# Validate should work with remote tasks\nassert_succeed \"mise tasks validate remote_lint_https_ref\"\n"
  },
  {
    "path": "e2e/tasks/test_task_remote_git_includes",
    "content": "#!/usr/bin/env bash\n\n#################################################################################\n# Setup\n#################################################################################\n\n# Clean up any previous server files\nrm -f /tmp/mise_git_http_port /tmp/mise_git_http_ready /tmp/mise_git_http_info\n\n# Start local git HTTP server with OS-assigned port to avoid race conditions\npython3 \"${TEST_ROOT}/helpers/scripts/git_http_backend_server.py\" 0 &\nSERVER_PID=$!\n\n# Wait for server to be ready (with timeout)\nwait_for_server() {\n\tlocal max_attempts=30 # 30 seconds timeout\n\tlocal attempt=1\n\n\twhile [ $attempt -le $max_attempts ]; do\n\t\tif [ -f /tmp/mise_git_http_ready ] && [ -f /tmp/mise_git_http_port ]; then\n\t\t\treturn 0\n\t\tfi\n\t\tsleep 1\n\t\tattempt=$((attempt + 1))\n\tdone\n\n\techo \"ERROR: Git HTTP server failed to start within 30 seconds\"\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\texit 1\n}\n\nwait_for_server\n\n# Read the actual port from the file\nSERVER_PORT=$(cat /tmp/mise_git_http_port)\nLOCAL_GIT_URL=\"http://localhost:${SERVER_PORT}/repo.git\"\n\n# Update cache directory paths for local server\nREMOTE_TASKS_DIR=\"${MISE_CACHE_DIR}/remote-git-tasks-cache\"\n\ncargo init --name hello_cargo\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\trm -f /tmp/mise_git_http_port /tmp/mise_git_http_ready /tmp/mise_git_http_info\n}\ntrap cleanup EXIT\n\n#################################################################################\n# Test remote git directory includes with no ref\n#################################################################################\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\n    \"git::${LOCAL_GIT_URL}//xtasks/lint\"\n]\nEOF\n\n# The xtasks/lint directory contains multiple task files\n# We should be able to see and run them\nassert_contains \"mise tasks\" \"ripgrep\"\nassert_succeed \"mise run ripgrep\" # Remote task from included directory should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\n#################################################################################\n# Test remote git directory includes with ref\n#################################################################################\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\n    \"git::${LOCAL_GIT_URL}//xtasks/lint?ref=v2025.1.17\"\n]\nEOF\n\nassert_contains \"mise tasks\" \"ripgrep\"\nassert_succeed \"mise run ripgrep\" # Remote task should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\n#################################################################################\n# Test remote git directory includes with no cache\n#################################################################################\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\n    \"git::${LOCAL_GIT_URL}//xtasks/lint\"\n]\nEOF\n\nassert_succeed \"MISE_TASK_REMOTE_NO_CACHE=true mise run ripgrep\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\n\nassert_succeed \"mise run ripgrep\" # Cache should be used\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\n#################################################################################\n# Test mixed local and remote includes\n#################################################################################\n\n# Create a local tasks directory\nmkdir -p local-tasks\ncat <<'EOF' >local-tasks/local_task\n#!/usr/bin/env bash\necho \"Local task executed\"\nEOF\nchmod +x local-tasks/local_task\n\ncat <<EOF >mise.toml\n[task_config]\nincludes = [\n    \"local-tasks\",\n    \"git::${LOCAL_GIT_URL}//xtasks/lint\"\n]\nEOF\n\n# Both local and remote tasks should be available\nassert_contains \"mise tasks\" \"local_task\"\nassert_contains \"mise tasks\" \"ripgrep\"\nassert_succeed \"mise run local_task\"\nassert_succeed \"mise run ripgrep\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/tasks/test_task_remote_git_ssh",
    "content": "#!/usr/bin/env bash\n\nif [ -n \"$EXCLUDE_FROM_CI\" ]; then\n\techo \"This test is not supported in CI, because it requires a SSH key to be added to the GitHub account\"\n\texit 0\nfi\n\n#################################################################################\n# Setup\n#################################################################################\n\nREMOTE_TASKS_DIR=\"${MISE_CACHE_DIR}/remote-git-tasks-cache\"\n#MISE_V2025117_CACHE_DIR=\"${REMOTE_TASKS_DIR}/27d097acd7d7d15682b9d5f22bfa7c363b1951a50bbbd2aff3923eb949be0ef0\"\n\ncargo init --name hello_cargo\n\n#################################################################################\n# Test remote tasks with no ref\n#################################################################################\n\ncat <<EOF >mise.toml\n[tasks.remote_lint_ssh_latest]\nfile  = \"git::ssh://git@github.com/jdx/mise.git//xtasks/lint/ripgrep\"\nEOF\n\nassert_contains \"mise tasks\" \"remote_lint_ssh_latest\"\nassert_succeed \"mise run remote_lint_ssh_latest\" # Remote task should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\nassert_succeed \"MISE_TASK_REMOTE_NO_CACHE=true mise run remote_lint_ssh_latest\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nassert_succeed \"mise run --no-cache remote_lint_ssh_latest\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nassert_succeed \"mise run remote_lint_ssh_latest\" # Cache should be used\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\n# #################################################################################\n# # Test remote tasks with with ref\n# #################################################################################\n\ncat <<EOF >mise.toml\n[tasks.remote_lint_ssh_ref]\nfile  = \"git::ssh://git@github.com/jdx/mise.git//xtasks/lint/ripgrep?ref=v2025.1.17\"\nEOF\n\nassert_contains \"mise tasks\" \"remote_lint_ssh_ref\"\nassert_succeed \"mise run remote_lint_ssh_ref\" # Remote task should be downloaded\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n#assert_directory_exists \"${MISE_V2025117_CACHE_DIR}\"\n#assert_directory_not_empty \"${MISE_V2025117_CACHE_DIR}\"\n\nmise cache clear # Clear cache to force redownload\n\nassert_succeed \"MISE_TASK_REMOTE_NO_CACHE=true mise run remote_lint_ssh_ref\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nassert_succeed \"mise run --no-cache remote_lint_ssh_ref\" # Remote task should be redownloaded\nassert_directory_not_exists \"${REMOTE_TASKS_DIR}\"\n#assert_directory_not_exists \"${MISE_V2025117_CACHE_DIR}\"\n\nassert_succeed \"mise run remote_lint_ssh_ref\" # Cache should be used\nassert_directory_exists \"${REMOTE_TASKS_DIR}\"\nassert_directory_not_empty \"${REMOTE_TASKS_DIR}\"\n#assert_directory_exists \"${MISE_V2025117_CACHE_DIR}\"\n#assert_directory_not_empty \"${MISE_V2025117_CACHE_DIR}\"\n\n#################################################################################\n# Test usage and info commands with git remote tasks (SSH)\n# Verifies fix for https://github.com/jdx/mise/discussions/7578\n#################################################################################\n\n# Usage should work and show task in completion output\nassert_contains \"mise tasks ls --usage\" 'cmd remote_lint_ssh_ref'\n\n# Info should show local cached path, not git URL\nassert_contains \"mise tasks info remote_lint_ssh_ref\" \"remote-git-tasks-cache\"\nassert_not_contains \"mise tasks info remote_lint_ssh_ref\" \"git::ssh\"\n\n# JSON output should also work\nassert_contains \"mise tasks info remote_lint_ssh_ref --json\" '\"file\":'\nassert_contains \"mise tasks info remote_lint_ssh_ref --json\" \"remote-git-tasks-cache\"\n\n# Validate should work with remote tasks\nassert_succeed \"mise tasks validate remote_lint_ssh_ref\"\n"
  },
  {
    "path": "e2e/tasks/test_task_remote_http",
    "content": "#!/usr/bin/env bash\n\n#################################################################################\n# Setup\n#################################################################################\n\nfind_available_port() {\n\tpython3 -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\"\n}\n\n# Start HTTP test server\nHTTP_PORT=$(find_available_port)\npython3 \"${TEST_ROOT}/helpers/scripts/http_test_server.py\" \"$HTTP_PORT\" &\nHTTP_SERVER_PID=$!\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$HTTP_SERVER_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT\n\n# Wait for server to start\nsleep 1\n\ncat <<EOF >mise.toml\n[tasks.remote_http_task]\nfile = \"http://localhost:${HTTP_PORT}/test/mytask\"\ndescription = \"HTTP remote task\"\nEOF\n\n#################################################################################\n# Test usage and info with HTTP remote tasks (non-git)\n# Verifies fix for https://github.com/jdx/mise/discussions/6603\n#################################################################################\n\n# Usage should work for HTTP remote tasks\nassert_contains \"mise tasks ls --usage\" 'cmd remote_http_task help=\"HTTP remote task\"'\n\n# Info should show local cached path, not HTTP URL\nassert_contains \"mise tasks info remote_http_task\" \"remote-http-tasks-cache\"\nassert_not_contains \"mise tasks info remote_http_task\" \"http://localhost\"\n\n# Validate should work with remote tasks\nassert_succeed \"mise tasks validate remote_http_task\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_depends",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.build]\nrun = 'echo build'\n[tasks.all]\ndepends = ['build a', 'build b', 'build c']\nEOF\nassert \"mise run all | sort\" \"[build a] build a\n[build b] build b\n[build c] build c\"\n\ncat <<EOF >mise.toml\n[tasks.build1]\nrun = 'echo build'\n[tasks.build2]\ndepends = ['build1 a']\nrun = 'echo build'\n[tasks.all]\ndepends = ['build1 a', 'build2 b']\nrun = \"echo all\"\nEOF\nassert \"mise run all\" \"build a\nbuild b\nall\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_file",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >.mise.toml\n[tasks.configtask]\nrun = 'echo \"configtask:\"'\n[tasks.lint]\nrun = 'echo \"linting!\"'\n[tasks.test]\nrun = 'echo \"testing!\"'\nEOF\n\nmkdir -p .mise/tasks\ncat <<'EOF' >.mise/tasks/filetask\n#!/usr/bin/env bash\n#MISE description=\"This is a test build script\"\n#MISE depends=[\"lint\", \"test\"]\n#MISE sources=[\".test-tool-versions\"]\n#MISE outputs=[\"$MISE_PROJECT_ROOT/test-e2e/test-build-output.txt\"]\n#MISE env={TEST_BUILDSCRIPT_ENV_VAR = \"VALID\"}\n\nset -euxo pipefail\ncd \"$MISE_PROJECT_ROOT\" || exit 1\necho \"running test-build script\"\nmkdir -p test-e2e\necho \"TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR\" >test-e2e/test-build-output.txt\necho \"ARGS: $*\" >>test-e2e/test-build-output.txt\nEOF\nchmod +x .mise/tasks/filetask\n\nmise r --cd \"$PWD\" configtask arg1 arg2 ::: filetask arg1 arg2\nassert \"cat test-e2e/test-build-output.txt\" \"TEST_BUILDSCRIPT_ENV_VAR: VALID\nARGS: arg1 arg2\"\n\nassert \"mise run test arg1 arg2 arg3\" \"testing! arg1 arg2 arg3\"\n\ncat <<'EOF' >.mise/tasks/filetask\n#!/usr/bin/env bash\n#USAGE flag \"-u --user <user>\" help=\"User to run as\"\n#USAGE flag \"-p --port <port>\" help=\"Port to run on\" default=\"8080\"\n\necho \"user=$usage_user\"\necho \"port=$usage_port\"\nEOF\n\ncat <<'EOF' >.mise/tasks/filetask.bat\n#windows filetask\n#USAGE flag \"-u --user <user>\" help=\"User to run as\"\n#USAGE flag \"-p --port <port>\" help=\"Port to run on\" default=\"8080\"\n\necho \"user=$usage_user\"\necho \"port=$usage_port\"\nEOF\nassert \"mise run filetask --user=jdx\" \"user=jdx\nport=8080\"\nassert \"mise run filetask --port=8081\" \"user=\nport=8081\"\nassert_contains \"mise run filetask --help 2>&1 || true\" \"-u --user <user>\"\nassert_contains \"mise run filetask --help 2>&1 || true\" \"-p --port <port>\"\n\ncat <<'EOF' >.mise/tasks/jstask\n#!/usr/bin/env node\n//MISE description=\"This is a test build script\"\n//MISE env={MYVAR = \"1\"}\n\nconsole.log(`MYVAR: ${process.env.MYVAR}`);\nEOF\nchmod +x .mise/tasks/jstask\nassert \"mise run jstask\" \"MYVAR: 1\"\nassert \"mise tasks -x\" \"configtask     ./.mise.toml\nfiletask       ./.mise/tasks/filetask\njstask         ./.mise/tasks/jstask    This is a test build script\nlint           ./.mise.toml\ntest           ./.mise.toml\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_groups",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.t1]\nrun = 'echo one'\n\n[tasks.t2]\nrun = 'echo two'\n\n[tasks.t3]\nrun = 'echo three'\n\n[tasks.grouped]\nrun = [\n  { task = 't1' },\n  { tasks = ['t2','t3'] },\n  'echo end',\n]\nEOF\n\n# All outputs should appear\nassert_contains \"mise run grouped\" \"one\"\nassert_contains \"mise run grouped\" \"two\"\nassert_contains \"mise run grouped\" \"three\"\nassert_contains \"mise run grouped\" \"end\"\n\n# Ensure trailing script runs after grouped tasks complete\nassert_matches \"mise run grouped\" \"one(.|\\n)*end\"\nassert_matches \"mise run grouped\" \"two(.|\\n)*end\"\nassert_matches \"mise run grouped\" \"three(.|\\n)*end\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_output",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.a]\nrun = 'echo running a'\n[tasks.b]\ndepends = 'a'\nrun = 'echo running b'\n[tasks.c]\ndepends = ['b']\nrun = 'echo running c'\n[tasks.all]\ndepends = ['a', 'b', 'c']\ndepends_post = 'z'\nrun = 'echo running all'\n[tasks.d]\nrun = 'echo running d'\n[tasks.z]\nrun = 'echo running z'\nEOF\n\nMISE_TASK_OUTPUT=silent assert_empty \"mise run all\" \"\"\nMISE_TASK_OUTPUT=quiet assert \"mise run all\" \"running a\nrunning b\nrunning c\nrunning all\nrunning z\"\n# test that task.output config setting works the same as MISE_TASK_OUTPUT env var\ncat <<EOF >mise.toml\n[settings]\ntask.output = \"silent\"\n[tasks.a]\nrun = 'echo running a'\n[tasks.b]\ndepends = 'a'\nrun = 'echo running b'\n[tasks.c]\ndepends = ['b']\nrun = 'echo running c'\n[tasks.all]\ndepends = ['a', 'b', 'c']\ndepends_post = 'z'\nrun = 'echo running all'\n[tasks.d]\nrun = 'echo running d'\n[tasks.z]\nrun = 'echo running z'\nEOF\nassert_empty \"mise run all\" \"\"\ncat <<EOF >mise.toml\n[settings]\ntask.output = \"quiet\"\n[tasks.a]\nrun = 'echo running a'\n[tasks.b]\ndepends = 'a'\nrun = 'echo running b'\n[tasks.c]\ndepends = ['b']\nrun = 'echo running c'\n[tasks.all]\ndepends = ['a', 'b', 'c']\ndepends_post = 'z'\nrun = 'echo running all'\n[tasks.d]\nrun = 'echo running d'\n[tasks.z]\nrun = 'echo running z'\nEOF\nassert \"mise run all\" \"running a\nrunning b\nrunning c\nrunning all\nrunning z\"\ncat <<EOF >mise.toml\n[tasks.a]\nrun = 'echo running a'\n[tasks.b]\ndepends = 'a'\nrun = 'echo running b'\n[tasks.c]\ndepends = ['b']\nrun = 'echo running c'\n[tasks.all]\ndepends = ['a', 'b', 'c']\ndepends_post = 'z'\nrun = 'echo running all'\n[tasks.d]\nrun = 'echo running d'\n[tasks.z]\nrun = 'echo running z'\nEOF\nMISE_TASK_OUTPUT=interleave assert \"mise run all\" \"running a\nrunning b\nrunning c\nrunning all\nrunning z\"\nMISE_TASK_OUTPUT=prefix assert \"mise run all\" \"[a] running a\n[b] running b\n[c] running c\n[all] running all\n[z] running z\"\n# defaults to interleave if linear dependency graph\nassert \"mise run all\" \"running a\nrunning b\nrunning c\nrunning all\nrunning z\"\n# now the graph isn't linear so it uses prefix\nassert_contains \"mise run a ::: d\" \"[a] running a\"\nassert_contains \"mise run a ::: d\" \"[d] running d\"\nassert \"mise tasks deps\" \"a\nall\n├── c\n│   └── b\n│       └── a\n├── b\n│   └── a\n└── a\nb\n└── a\nc\n└── b\n    └── a\nd\nz\n└── all\n    ├── c\n    │   └── b\n    │       └── a\n    ├── b\n    │   └── a\n    └── a\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_sources",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.test]\nrun = 'cat input > test.txt && echo done'\nsources = ['input']\noutputs = ['test.txt']\nEOF\necho \"hello world\" >input\n\nmkdir subdir && cd subdir || exit 1\nassert \"mise -q test\" \"done\"\nassert_not_contains \"mise -q test\" \"done\"\ntouch ../input\nassert \"mise -q test\" \"done\"\ntouch ../test.txt\nassert_not_contains \"mise -q test\" \"done\"\ntouch ../mise.toml\nassert \"mise -q test\" \"done\"\n\ncat <<EOF >mise.toml\n[tasks.hi]\nsources = [\"o*\"]\noutputs = [\"newer\"]\nrun = \"echo hi\"\nEOF\n\ntouch older\nsleep 0.1\ntouch newer\nmkdir subdir && cd subdir || exit 1\nassert_empty \"mise -q hi\"\nassert_empty \"mise -q hi\"\ntouch ../older\nassert \"mise -q hi\" \"hi\"\n\ncat <<EOF >mise.toml\n[tasks.hi]\nsources = [\"{{cwd}}/input\"]\nrun = \"echo hi\"\nEOF\n\nmkdir subdir && cd subdir || exit 1\nassert \"mise -q hi\" \"hi\"\nassert_empty \"mise -q hi\"\ntouch input\nassert \"mise -q hi\" \"hi\"\nassert_empty \"mise -q hi\"\n\ncat <<EOF >mise.toml\n[tasks.hi]\nsources = [\"{{cwd}}/input\"]\noutputs = { auto = true }\nrun = \"echo hi\"\nEOF\n\nmkdir subdir && cd subdir || exit 1\nassert \"mise -q hi\" \"hi\"\nassert_empty \"mise -q hi\"\ntouch input\nassert \"mise -q hi\" \"hi\"\nassert_empty \"mise -q hi\"\n\nmkdir src out\ncat <<EOF >mise.toml\n[tasks.build]\nsources = [\"{{cwd}}/src/**/*\"]\noutputs = [\"{{cwd}}/out/**/*\"]\nrun = \"touch out/done.txt && echo done\"\nEOF\nassert \"touch src/foo.txt\"\nassert \"mise build\" \"done\"\nassert_empty \"mise build\"\nassert \"touch src/foo.txt\"\nassert \"touch src/bar.txt\"\nassert \"mise build\" \"done\"\nassert_empty \"mise build\"\nassert \"rm src/foo.txt\"\nassert \"mise build\" \"done\"\nassert_empty \"mise build\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_tmpl",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\nenv.BAR = \"bar\"\ntasks.a = \"echo {{ env.BAR }}\"\nEOF\nassert \"mise run a\" \"bar\"\n\ncat <<EOF >mise.toml\nenv.BAR = \"a\"\ntasks.a = \"echo a\"\ntasks.b.depends = [\"{{ env.BAR }}\"]\nEOF\nassert \"mise run b\" \"a\"\n"
  },
  {
    "path": "e2e/tasks/test_task_run_toml",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.multi = ['echo a', 'echo b']\n[tasks.configtask]\nrun = 'echo \"configtask:\"'\n[tasks.lint]\nrun = 'echo \"linting!\"'\n[tasks.test]\nrun = 'echo \"testing!\"'\n[tasks.test-with-args]\nrun = 'echo \"{{arg()}} {{flag(name=\"force\")}} {{option(name=\"user\")}}\"'\n[tasks.test-with-defaults]\nrun = 'echo {{arg(default=\"arg1\")}} {{option(name=\"user\", default=\"user1\")}}'\n[tasks.test-with-template]\nrun = 'echo {{1 + 1}}'\n[tasks.int]\nenv = { DEBUG = 0 } # should be parsed as a string\nrun = 'echo DEBUG=\\$DEBUG'\nEOF\n\nassert \"mise run multi c\" \"a\nb c\"\nassert \"mise run test arg1 arg2 arg3\" \"testing! arg1 arg2 arg3\"\nassert \"mise run test-with-args foo --force --user=user\" \"foo true user\"\nassert \"mise run test-with-defaults\" \"arg1 user1\"\nassert \"mise run test-with-defaults arg2 --user=user2\" \"arg2 user2\"\nassert \"mise run test-with-template\" \"2\"\nassert \"mise int\" \"DEBUG=0\"\n\ncat <<EOF >mise.windows.toml\ntasks.configtask = \"echo configtask:windows\"\nEOF\nassert \"mise run -E windows configtask\" \"configtask:windows\"\nassert \"mise run -P windows configtask\" \"configtask:windows\"\nMISE_ENV=windows assert \"mise run configtask\" \"configtask:windows\"\nMISE_PROFILE=windows assert \"mise run configtask\" \"configtask:windows\"\n\ncat <<EOF >mise.toml\n[tasks.a]\nusage = '''\narg \"myarg\" \"myarg description\" default=\"foo\"\n'''\nrun = 'echo {{arg(name=\"myarg\")}}'\nEOF\nassert \"mise run a\" \"foo\"\n"
  },
  {
    "path": "e2e/tasks/test_task_sequence_cli_groups",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Repro for discussion #6255: CLI groups with ::: and jobs=1.\n# This test validates stop-on-failure semantics without relying on task order.\n\ncat <<EOF >mise.toml\n[tasks.a_fail]\nrun = \"echo a_fail; exit 1\"\n\n[tasks.b_ok]\nrun = \"echo b_ok\"\n\n[tasks.c_ok]\nrun = \"echo c_ok\"\n\n[tasks.d_ok]\nrun = \"echo d_ok\"\n\n[tasks.e_ok]\nrun = \"echo e_ok\"\nEOF\n\n# Without --continue-on-error, with --jobs 1, we should stop after the first failure\noutput=$(mise run --jobs 1 a_fail ::: b_ok ::: c_ok ::: d_ok ::: e_ok 2>&1) && exit_code=0 || exit_code=$?\n\nif [ \"$exit_code\" -eq 0 ]; then\n\techo \"Expected non-zero exit code without --continue-on-error\"\n\techo \"$output\"\n\texit 1\nfi\n\nif ! echo \"$output\" | grep -q \"^a_fail$\"; then\n\techo \"Expected to see output from failing task a_fail\"\n\techo \"$output\"\n\texit 1\nfi\n\nfor t in b_ok c_ok d_ok e_ok; do\n\tif echo \"$output\" | grep -q \"^$t$\"; then\n\t\techo \"Did not expect task $t to run without --continue-on-error\"\n\t\techo \"$output\"\n\t\texit 1\n\tfi\ndone\n\n# With --continue-on-error, all tasks should run, but exit non-zero\noutput=$(mise run --continue-on-error --jobs 1 a_fail ::: b_ok ::: c_ok ::: d_ok ::: e_ok 2>&1) && exit_code=0 || exit_code=$?\n\nif [ \"$exit_code\" -eq 0 ]; then\n\techo \"Expected non-zero exit code with --continue-on-error if a task fails\"\n\techo \"$output\"\n\texit 1\nfi\n\nfor t in a_fail b_ok c_ok d_ok e_ok; do\n\tif ! echo \"$output\" | grep -q \"^$t$\"; then\n\t\techo \"Expected to see output from task $t with --continue-on-error\"\n\t\techo \"$output\"\n\t\texit 1\n\tfi\ndone\n\necho \"cli groups with jobs=1 behave as expected\"\n"
  },
  {
    "path": "e2e/tasks/test_task_sequence_failure",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n# https://github.com/jdx/mise/discussions/6257\n\ncat <<EOF >mise.toml\n[tasks.fail_task]\nrun = \"exit 1\"\n\n[tasks.success_task]\nrun = \"echo 'This should not run if previous task fails'\"\n\n[tasks.sequence]\nrun = [\n  { task = \"fail_task\" },\n  { task = \"success_task\" },\n]\nEOF\n\n# Test that task sequence stops on failure\noutput=$(mise run sequence 2>&1) && exit_code=0 || exit_code=$?\n\n# The sequence should fail with exit code 1\nif [ \"$exit_code\" -ne 1 ]; then\n\techo \"Expected exit code 1, got $exit_code\"\n\texit 1\nfi\n\n# The second task should not have run\nif echo \"$output\" | grep -q \"This should not run\"; then\n\techo \"Second task ran when it shouldn't have\"\n\texit 1\nfi\n\n# Test that --continue-on-error allows subsequent tasks to run\noutput=$(mise run --continue-on-error sequence 2>&1) && exit_code=0 || exit_code=$?\n\n# The sequence should still exit with 1 (at least one task failed)\nif [ \"$exit_code\" -ne 1 ]; then\n\techo \"Expected exit code 1 with --continue-on-error, got $exit_code\"\n\texit 1\nfi\n\n# The second task SHOULD have run with --continue-on-error\nif ! echo \"$output\" | grep -q \"This should not run\"; then\n\techo \"Second task didn't run with --continue-on-error\"\n\texit 1\nfi\n\necho \"Test passed: task sequence correctly handles failures\"\n"
  },
  {
    "path": "e2e/tasks/test_task_sequence_jobs1",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Verify that running a task sequence with --jobs=1 executes tasks and exits\n\ncat <<EOF >mise.toml\n[tasks.a]\nrun = \"echo A\"\n\n[tasks.b]\nrun = \"echo B\"\n\n[tasks.sequence]\nrun = [\n  { task = \"a\" },\n  { task = \"b\" },\n]\nEOF\n\noutput=$(mise run --jobs=1 sequence 2>&1) && exit_code=0 || exit_code=$?\n\nif [ \"$exit_code\" -ne 0 ]; then\n\techo \"Expected exit code 0, got $exit_code\"\n\techo \"$output\"\n\texit 1\nfi\n\nif ! echo \"$output\" | grep -q \"A\"; then\n\techo \"Did not find output from task a\"\n\techo \"$output\"\n\texit 1\nfi\n\nif ! echo \"$output\" | grep -q \"B\"; then\n\techo \"Did not find output from task b\"\n\techo \"$output\"\n\texit 1\nfi\n\necho \"jobs=1 sequence ran successfully\"\n"
  },
  {
    "path": "e2e/tasks/test_task_sequence_keep_order",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Verify that keep-order output mode does not panic and preserves order\n\ncat <<EOF >mise.toml\n[tasks.a]\nrun = \"printf 'A1\\nA2'\"\n\n[tasks.b]\nrun = \"printf 'B1\\nB2'\"\n\n[tasks.sequence]\nrun = [\n  { task = \"a\" },\n  { task = \"b\" },\n]\nEOF\n\noutput=$(MISE_TASK_OUTPUT=keep-order mise run sequence 2>&1) && exit_code=0 || exit_code=$?\n\nif [ \"$exit_code\" -ne 0 ]; then\n\techo \"Expected exit code 0, got $exit_code\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Ensure there is no panic message\nif echo \"$output\" | grep -qi \"panicked\"; then\n\techo \"Found panic in output\"\n\techo \"$output\"\n\texit 1\nfi\n\n# Verify order: all A lines before B lines\napos=$(echo \"$output\" | grep -n \"^\\\\[a\\\\] A1$\" | cut -d: -f1 | head -n1 || true)\nif [ -z \"$apos\" ]; then\n\techo \"Did not find [a] A1\"\n\techo \"$output\"\n\texit 1\nfi\n\nbpos=$(echo \"$output\" | grep -n \"^\\\\[b\\\\] B1$\" | cut -d: -f1 | head -n1 || true)\nif [ -z \"$bpos\" ]; then\n\techo \"Did not find [b] B1\"\n\techo \"$output\"\n\texit 1\nfi\n\nif [ \"$apos\" -ge \"$bpos\" ]; then\n\techo \"Output for task a did not appear before task b\"\n\techo \"$output\"\n\texit 1\nfi\n\necho \"keep-order sequence ran successfully\"\n"
  },
  {
    "path": "e2e/tasks/test_task_shell",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.shell-invalid]\nshell = 'invalid_shell'\nrun = 'echo \"invalid shell\"'\n[tasks.shell]\nshell = 'bash -c'\nrun = 'echo \"using shell $0\"'\nEOF\n\nassert \"mise run shell\" \"using shell bash\"\nassert_fail \"mise run shell-invalid\" \"invalid shell\"\n\ncat <<EOF >mise.toml\ntasks.escapeme = \"echo \\\"{{arg(name='a')}}\\\"\"\ntasks.escapeme_var = \"echo \\\"{{arg(name='a', var=true)}}\\\"\"\ntasks.bashshebang1 = \"\"\"\n#!/usr/bin/env -S bash\necho \"{{arg(name='a')}}\"\necho \"{{arg(name='b', var=true)}}\"\n\"\"\"\ntasks.bashshebang2 = \"\"\"\n#!/usr/bin/env bash\necho \"{{arg(name='a')}}\"\necho \"{{arg(name='b', var=true)}}\"\n\"\"\"\ntasks.bashshebang3 = \"\"\"\n#!/bin/bash\necho \"{{arg(name='a')}}\"\necho \"{{arg(name='b', var=true)}}\"\n\"\"\"\ntasks.escapenode = \"\"\"\n#!/usr/bin/env -S python3\nprint(\"{{arg(name='a')}}\")\nprint(\"{{arg(name='b', var=true)}}\")\n\"\"\"\nEOF\n\nassert \"mise run escapeme 'hello world'\" \"'hello world'\"\nassert \"mise run escapeme_var hello 'world of mise'\" \"hello 'world of mise'\"\nassert \"mise run bashshebang1 'a with space' hello 'world of mise'\" \"'a with space'\nhello 'world of mise'\"\nassert \"mise run bashshebang2 my_a hello 'world of mise'\" \"my_a\nhello 'world of mise'\"\nassert \"mise run bashshebang3 my_a hello 'world of mise'\" \"my_a\nhello 'world of mise'\"\nassert \"mise run escapenode my_a hello 'world of mise'\" \"my_a\nhello 'world of mise'\"\nassert \"mise run escapenode 'a with space' hello 'world of mise'\" \"a with space\nhello 'world of mise'\"\n"
  },
  {
    "path": "e2e/tasks/test_task_shorthand_monorepo",
    "content": "#!/usr/bin/env bash\n\n# Test that monorepo task shorthand syntax (mise //path:task and mise :task) works\n# This tests the fix for the bug where these patterns only worked with 'mise run'\n\nexport MISE_EXPERIMENTAL=1\n\ncat <<'EOF' >mise.toml\nexperimental_monorepo_root = true\n\n[monorepo]\nconfig_roots = [\"project\", \"app\", \"deep/nested/dir\"]\n\n[tasks.build]\nrun = 'echo \"root build task\"'\nEOF\n\nmkdir -p project\ncat <<'EOF' >project/mise.toml\n[tasks.build]\nrun = 'echo \"project build task\"'\nEOF\n\nmkdir -p app\ncat <<'EOF' >app/mise.toml\n[tasks.build]\nrun = 'echo \"app build task\"'\nEOF\n\n# Test 1: mise //project:build (shorthand, without 'run')\nassert_contains \"mise '//project:build'\" \"project build task\"\n\n# Test 2: mise //app:build (shorthand, without 'run')\nassert_contains \"mise '//app:build'\" \"app build task\"\n\n# Test 3: mise :build from root (should run root task)\nassert_contains \"mise ':build'\" \"root build task\"\n\n# Test 4: mise :build from project directory (should run project task)\n(cd project && assert_contains \"mise ':build'\" \"project build task\")\n\n# Test 5: mise :build from app directory (should run app task)\n(cd app && assert_contains \"mise ':build'\" \"app build task\")\n\n# Test 6: Verify that the shorthand syntax is equivalent to 'mise run'\nOUTPUT_SHORTHAND=$(mise '//project:build')\nOUTPUT_RUN=$(mise run '//project:build')\nif [ \"$OUTPUT_SHORTHAND\" != \"$OUTPUT_RUN\" ]; then\n\techo \"ERROR: Shorthand 'mise //project:build' output differs from 'mise run //project:build'\"\n\techo \"Shorthand output: $OUTPUT_SHORTHAND\"\n\techo \"Run output: $OUTPUT_RUN\"\n\texit 1\nfi\n\n# Test 7: Test with nested subdirectories\nmkdir -p deep/nested/dir\ncat <<'EOF' >deep/nested/dir/mise.toml\n[tasks.test]\nrun = 'echo \"nested task\"'\nEOF\n\nassert_contains \"mise '//deep/nested/dir:test'\" \"nested task\"\n\n(cd deep/nested/dir && assert_contains \"mise ':test'\" \"nested task\")\n"
  },
  {
    "path": "e2e/tasks/test_task_silent_streams",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.stdout_only]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\n[tasks.stderr_only]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\n[tasks.both_silent]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\n[tasks.silent_stdout]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\nsilent = \"stdout\"\n[tasks.silent_stderr]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\nsilent = \"stderr\"\n[tasks.silent_bool]\nrun = 'echo \"this is stdout\" && echo \"this is stderr\" >&2'\nsilent = true\nEOF\n\n# Test silent = \"stdout\" - should only suppress stdout\nassert \"mise run silent_stdout 2>&1\" \"this is stderr\"\n\n# Test silent = \"stderr\" - should only suppress stderr\nassert \"mise run silent_stderr 2>&1\" \"this is stdout\"\n\n# Test silent = true - should suppress both streams\nassert_empty \"mise run silent_bool 2>&1\" \"\"\n\n# Test without silent - should show both\nassert_contains \"mise run stdout_only 2>&1\" \"this is stdout\"\nassert_contains \"mise run stdout_only 2>&1\" \"this is stderr\"\n\n# Test with parallel execution to ensure output routing works\ncat <<EOF >>mise.toml\n[tasks.para1]\nrun = 'echo \"para1 stdout\" && echo \"para1 stderr\" >&2'\nsilent = \"stdout\"\n[tasks.para2]\nrun = 'echo \"para2 stdout\" && echo \"para2 stderr\" >&2'\nsilent = \"stderr\"\nEOF\n\n# Parallel tasks with selective silent - both streams should appear\nassert_contains \"mise run para1 ::: para2 2>&1\" \"para1 stderr\"\nassert_contains \"mise run para1 ::: para2 2>&1\" \"para2 stdout\"\nassert_not_contains \"mise run para1 ::: para2 2>&1\" \"para1 stdout\"\nassert_not_contains \"mise run para1 ::: para2 2>&1\" \"para2 stderr\"\n"
  },
  {
    "path": "e2e/tasks/test_task_skip",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.a = \"echo running a\"\ntasks.b = \"echo running b\"\ntasks.c = \"echo running c\"\ntasks.all.run = \"echo testing!\"\ntasks.all.depends = [\"a\", \"b\", \"c\"]\nEOF\n\nassert_contains \"mise run all\" \"running b\"\nMISE_TASK_SKIP=b assert_not_contains \"mise run all\" \"running b\"\n"
  },
  {
    "path": "e2e/tasks/test_task_skip_deps",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.a]\nrun = \"echo a\"\n\n[tasks.b]\ndepends = [\"a\"]\nrun = \"echo b\"\n\n[tasks.c]\nwait_for = [\"b\"]\nrun = \"echo c\"\n\n[tasks.d]\ndepends = [\"b\"]\ndepends_post = [\"c\"]\nrun = \"echo d\"\n\n[tasks.e]\nrun = [{ task = \"a\" }, { task = \"b\" }]\nEOF\n\n# Test normal, with dependencies\nassert \"mise run d\" \"a\nb\nd\nc\"\n\n# Test --skip-deps\nassert \"mise run --skip-deps d\" \"d\"\nassert \"MISE_TASK_SKIP_DEPENDS=true mise run d\" \"d\"\n\n# Test --skip-deps, multiple tasks\nassert_contains \"mise run --skip-deps c ::: b\" \"c\"\nassert_contains \"mise run --skip-deps c ::: b\" \"b\"\nassert_not_contains \"mise run --skip-deps c ::: b\" \"a\"\n\n# Test --skip-deps, nested dependencies\nassert \"mise run --skip-deps e\" \"a\nb\"\n\n# Test task.skip_depends setting\ncat <<EOF >mise.toml\n[settings]\ntask.skip_depends = true\n\n[tasks.a]\nrun = \"echo a\"\n\n[tasks.b]\ndepends = [\"a\"]\nrun = \"echo b\"\n\n[tasks.f]\nrun = [{ task = \"a\" }, { task = \"b\" }]\nEOF\n\nassert \"mise run b\" \"b\"\nassert \"mise run f\" \"a\nb\"\n"
  },
  {
    "path": "e2e/tasks/test_task_source_freshness",
    "content": "#!/usr/bin/env bash\n\n# Test warning for missing outputs after task execution\ncat <<EOF >mise.toml\n[tasks.nooutput]\nrun = 'echo ran but no output created'\nsources = ['input.txt']\noutputs = ['missing_output.txt']\nEOF\n\necho \"source\" >input.txt\n# Should warn about missing output\nassert_contains \"mise run nooutput 2>&1\" \"did not generate expected output\"\n\n# Test size-based detection (file size changes should trigger rebuild)\ncat <<EOF >mise.toml\n[tasks.sizetest]\nrun = 'echo rebuilt'\nsources = ['sized.txt']\noutputs = ['sizeout.txt']\nEOF\n\necho \"small\" >sized.txt\necho \"out\" >sizeout.txt\nsleep 0.1\ntouch sizeout.txt\n\n# First run should skip (output is newer)\nassert_empty \"mise run -q sizetest\"\n\n# Change file content/size - this changes the metadata hash\necho \"much larger content now\" >sized.txt\n# Make output NEWER than source (so mtime comparison alone would say fresh)\nsleep 0.1\ntouch sizeout.txt\n# Should rebuild because size changed in the metadata hash\nassert \"mise run -q sizetest\" \"rebuilt\"\n\n# Test that normal source/output freshness still works\ncat <<EOF >mise.toml\n[tasks.fresh]\nrun = 'echo built'\nsources = ['src.txt']\noutputs = ['out.txt']\nEOF\n\necho \"source\" >src.txt\nsleep 0.1\necho \"output\" >out.txt\n\n# Output is newer, should skip\nassert_empty \"mise run -q fresh\"\n\n# Touch source to make it newer\nsleep 0.1\ntouch src.txt\n\n# Source is newer, should rebuild\nassert \"mise run -q fresh\" \"built\"\n\n# Test rename detection (path is part of the hash)\ncat <<EOF >mise.toml\n[tasks.rename]\nrun = 'echo rebuilt'\nsources = ['*.src']\noutputs = ['rename.out']\nEOF\n\necho \"content\" >original.src\necho \"out\" >rename.out\nsleep 0.1\ntouch rename.out\n\n# First run should skip (output is newer)\nassert_empty \"mise run -q rename\"\n\n# Rename the source file (same content, same size, but different path)\nmv original.src renamed.src\n# Make output NEWER than source so only the path change triggers rebuild\nsleep 0.1\ntouch rename.out\n# Should rebuild because path changed in the metadata hash\nassert \"mise run -q rename\" \"rebuilt\"\n\n# Test glob output patterns - should not warn when glob matches files\ncat <<EOF >mise.toml\n[tasks.globout]\nrun = 'touch output1.gen output2.gen'\nsources = ['input.txt']\noutputs = ['*.gen']\nEOF\n\necho \"source\" >input.txt\n# Should run and NOT warn (glob matches created files)\nassert_not_contains \"mise run globout 2>&1\" \"did not generate expected output\"\n\n# Test glob output patterns - should warn when glob matches no files\ncat <<EOF >mise.toml\n[tasks.noglobout]\nrun = 'echo no files created'\nsources = ['input.txt']\noutputs = ['*.nomatch']\nEOF\n\necho \"source\" >input.txt\n# Should warn about missing glob output\nassert_contains \"mise run noglobout 2>&1\" \"did not generate expected output\"\n"
  },
  {
    "path": "e2e/tasks/test_task_source_freshness_with_cwd",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.cwd_task]\nrun = \"cat input.txt\"\ndir = \"{{cwd}}\"\nsources = [\"input.txt\"]\noutputs = { auto = true }\nEOF\n\nmkdir a\nmkdir b\n\necho \"running a\" >a/input.txt\necho \"running b 1\" >b/input.txt\n\n# Should first run and then skip\npushd a\nassert \"mise run -q cwd_task\" \"running a\"\nassert_empty \"mise run -q cwd_task\"\npopd\n\n# Should first run again as directory was changed and then skip\npushd b\nassert \"mise run -q cwd_task\" \"running b 1\"\nassert_empty \"mise run -q cwd_task\"\npopd\n\necho \"running b 2\" >b/input.txt\n\n# Should still skip as input in this directory was not changed\npushd a\nassert_empty \"mise run -q cwd_task\"\npopd\n\n# Should run again as input in this directory was changed\npushd b\nassert \"mise run -q cwd_task\" \"running b 2\"\nassert_empty \"mise run -q cwd_task\"\npopd\n"
  },
  {
    "path": "e2e/tasks/test_task_standalone",
    "content": "#!/usr/bin/env bash\n\n# Find available port\nfind_available_port() {\n\tpython3 -c \"import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()\"\n}\n\n# Start local HTTP test server\nSERVER_PORT=$(find_available_port)\npython3 \"${TEST_ROOT}/helpers/scripts/http_test_server.py\" \"$SERVER_PORT\" &\nSERVER_PID=$!\n\n# Wait for server to start\nsleep 1\n\n# Ensure cleanup on exit\ncleanup() {\n\tkill \"$SERVER_PID\" 2>/dev/null || true\n\trm -f /tmp/mise_http_test_port\n}\ntrap cleanup EXIT\n\ncat <<EOF >mytask\n#!/usr/bin/env bash\necho \"running mytask\"\nEOF\nchmod +x mytask\n\nassert \"mise run ./mytask\" \"running mytask\"\n\ncat <<EOF >mise.toml\n[tasks.mytask]\nfile = \"./mytask\"\nEOF\n\nmkdir -p subdir\ncd subdir || exit 1\nassert \"mise run mytask\" \"running mytask\"\ncd .. || exit 1\n\ncat <<EOF >mise.toml\ntasks.mytask.file = \"http://localhost:${SERVER_PORT}/test/mytask\"\nEOF\nassert \"mise run mytask\" \"running mytask\"\n"
  },
  {
    "path": "e2e/tasks/test_task_templates",
    "content": "#!/usr/bin/env bash\n\n# Test task templates feature (requires experimental = true)\n\n# First, test that extends fails without experimental flag\ncat <<'EOF' >mise.toml\n[task_templates.\"python:build\"]\nrun = \"echo building python\"\ndescription = \"Build a Python project\"\n\n[tasks.build]\nextends = \"python:build\"\nEOF\n\n# Should fail without experimental mode (override the env var)\nassert_fail \"MISE_EXPERIMENTAL=0 mise run build\" \"experimental = true\"\n\n# Now enable experimental mode and test basic template functionality\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo building python\"\ndescription = \"Build a Python project\"\n\n[tasks.build]\nextends = \"python:build\"\nEOF\n\n# Basic template extension should work\nassert \"mise run build\" \"building python\"\n\n# Test local override of run command\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo template build\"\ndescription = \"Template description\"\n\n[tasks.build]\nextends = \"python:build\"\nrun = \"echo local build\"\nEOF\n\nassert \"mise run build\" \"local build\"\n\n# Test tools deep merge\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo tools: python={{ env.MISE_TOOL_OPTS_PYTHON | default(value='none') }} node={{ env.MISE_TOOL_OPTS_NODE | default(value='none') }}\"\ntools = { python = \"3.12\", node = \"18\" }\n\n[tasks.build]\nextends = \"python:build\"\ntools = { node = \"20\" }  # Override node version, keep python from template\nEOF\n\n# The tools should be merged - task list should show both tools\nassert_contains \"mise tasks build\" \"python\"\nassert_contains \"mise tasks build\" \"node\"\n\n# Test env deep merge\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo FOO=$FOO BAR=$BAR\"\nenv = { FOO = \"template_foo\", BAR = \"template_bar\" }\n\n[tasks.build]\nextends = \"python:build\"\nenv = { FOO = \"local_foo\" }  # Override FOO, keep BAR from template\nEOF\n\nassert \"mise run build\" \"FOO=local_foo BAR=template_bar\"\n\n# Test description from template (when local is empty)\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo build\"\ndescription = \"Template description\"\n\n[tasks.build]\nextends = \"python:build\"\nEOF\n\nassert_contains \"mise tasks build\" \"Template description\"\n\n# Test local description overrides template\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:build\"]\nrun = \"echo build\"\ndescription = \"Template description\"\n\n[tasks.build]\nextends = \"python:build\"\ndescription = \"Local description\"\nEOF\n\nassert_contains \"mise tasks build\" \"Local description\"\nassert_not_contains \"mise tasks build\" \"Template description\"\n\n# Test depends from template (using task name, not :prefix syntax)\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:test\"]\nrun = \"echo testing\"\ndepends = [\"build\"]\n\n[tasks.build]\nrun = \"echo building\"\n\n[tasks.test]\nextends = \"python:test\"\nEOF\n\nassert \"mise run test\" \"building\ntesting\"\n\n# Test depends local override (local takes precedence completely)\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"python:test\"]\nrun = \"echo testing\"\ndepends = [\"prep\"]\n\n[tasks.prep]\nrun = \"echo prep\"\n\n[tasks.lint]\nrun = \"echo linting\"\n\n[tasks.test]\nextends = \"python:test\"\ndepends = [\"lint\"]  # Override, should NOT also run prep\nEOF\n\nassert \"mise run test\" \"linting\ntesting\"\nassert_not_contains \"mise run test\" \"prep\"\n\n# Test template not found error\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[tasks.build]\nextends = \"nonexistent:template\"\nEOF\n\nassert_fail \"mise run build\" \"not found\"\n\n# Test namespaced template names with colons\ncat <<'EOF' >mise.toml\n[settings]\nexperimental = true\n\n[task_templates.\"rust:cargo:build\"]\nrun = \"echo cargo build\"\n\n[tasks.build]\nextends = \"rust:cargo:build\"\nEOF\n\nassert \"mise run build\" \"cargo build\"\n\necho '' >mise.toml\n"
  },
  {
    "path": "e2e/tasks/test_task_timeout",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test timeout via CLI flag (global timeout for entire run)\ncat <<EOF >mise.toml\n[tasks.task1]\nrun = \"sleep 1 && echo 'Task 1 done'\"\n\n[tasks.task2]\nrun = \"sleep 1 && echo 'Task 2 done'\"\n\n[tasks.task3]\nrun = \"sleep 5 && echo 'Task 3 should not appear'\"\nEOF\n\necho \"Testing global timeout via CLI flag...\"\noutput=\"$(mise run --timeout=3s task1 ::: task2 ::: task3 2>&1 || true)\"\nif [[ $output != *\"timed out\"* ]]; then\n\techo \"ERROR: Expected 'timed out' in output, got: $output\"\n\texit 1\nfi\necho \"✓ CLI flag global timeout works\"\n\n# Test timeout via task config (individual task timeout)\ncat <<EOF >mise.toml\n[tasks.quick]\nrun = \"echo 'Quick task'\"\ntimeout = \"5s\"\n\n[tasks.slow]\nrun = \"sleep 2 && echo 'Slow task done'\"\ntimeout = \"5s\"\n\n[tasks.too_slow]\nrun = \"sleep 10 && echo 'Should not appear'\"\ntimeout = \"1s\"\nEOF\n\necho \"Testing individual task timeout (too_slow should time out)...\"\noutput=\"$(mise run too_slow 2>&1 || true)\"\nif [[ $output != *\"timed out\"* ]]; then\n\techo \"ERROR: Expected 'timed out' in output, got: $output\"\n\texit 1\nfi\necho \"✓ Individual task timeout works\"\n\necho \"Testing task completes within timeout...\"\nmise run quick 2>&1\nmise run slow 2>&1\necho \"✓ Tasks within timeout complete successfully\"\n\n# Test timeout via environment variable (global)\ncat <<EOF >mise.toml\n[tasks.env_test1]\nrun = \"sleep 1 && echo 'Task 1'\"\n\n[tasks.env_test2]\nrun = \"sleep 2 && echo 'Task 2'\"\nEOF\n\necho \"Testing global timeout via environment variable...\"\noutput=\"$(MISE_TASK_TIMEOUT=2s mise run env_test1 ::: env_test2 2>&1 || true)\"\nif [[ $output != *\"timed out\"* ]]; then\n\techo \"ERROR: Expected 'timed out' in output, got: $output\"\n\texit 1\nfi\necho \"✓ Environment variable global timeout works\"\n\n# Test task timeout is independent per task\ncat <<EOF >mise.toml\n[tasks.parallel1]\nrun = \"sleep 2 && echo 'Parallel 1 done'\"\ntimeout = \"3s\"\n\n[tasks.parallel2]\nrun = \"sleep 2 && echo 'Parallel 2 done'\"\ntimeout = \"3s\"\nEOF\n\necho \"Testing parallel tasks with individual timeouts...\"\nmise run parallel1 ::: parallel2 2>&1\necho \"✓ Parallel tasks with individual timeouts work\"\n\n# Test using duration formats\ncat <<EOF >mise.toml\n[tasks.duration_test]\nrun = \"sleep 1 && echo 'Duration test done'\"\ntimeout = \"2s\"\nEOF\n\necho \"Testing duration format parsing...\"\nmise run duration_test 2>&1\necho \"✓ Duration format works\"\n\n# Test global timeout + per-task timeout serve distinct purposes\ncat <<EOF >mise.toml\n[settings]\ntask_timeout = \"10s\"\n\n[tasks.quick_task]\nrun = \"sleep 1 && echo 'Quick done'\"\ntimeout = \"5s\"\n\n[tasks.slow_task]\nrun = \"sleep 8 && echo 'Slow done'\"\ntimeout = \"3s\"\nEOF\n\necho \"Testing global + per-task timeout interaction...\"\noutput=\"$(mise run quick_task ::: slow_task 2>&1 || true)\"\nif [[ $output != *\"timed out\"* ]]; then\n\techo \"ERROR: Expected per-task timeout to fire, got: $output\"\n\texit 1\nfi\nif [[ $output != *\"Quick done\"* ]]; then\n\techo \"ERROR: quick_task should have completed, got: $output\"\n\texit 1\nfi\necho \"✓ Global + per-task timeout interaction works\"\n\necho \"All timeout tests passed!\"\n"
  },
  {
    "path": "e2e/tasks/test_task_tools",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[tasks.a]\ntools = { tiny = \"1\" }\nrun = \"rtx-tiny\"\n[tasks.b]\ndepends = [\"a\"]\ntools = { tiny = \"2\" }\nrun = \"rtx-tiny\"\nEOF\n\nassert \"mise run b\" \"rtx-tiny: v1.1.0 args:\nrtx-tiny: v2.1.0 args:\"\n"
  },
  {
    "path": "e2e/tasks/test_task_tools_env_cache",
    "content": "#!/usr/bin/env bash\n\n# Test that task-level tools work correctly when the config has an [env] section\n# and multiple tasks run, some with tools and some without.\n# Reproduces issue: https://github.com/jdx/mise/discussions/7778\n#\n# The bug: When env resolution cache is used, it doesn't account for task-specific\n# tools. Task A (no tools) runs first and caches env. Task B (has tools) uses\n# cached env which doesn't have its tools in PATH.\n\ncat <<EOF >mise.toml\n[env]\nTEST_VAR = \"test-value\"\n\n[tasks.build]\nrun = \"echo building\"\n\n[tasks.deploy-aws]\nrun = \"rtx-tiny\"\ntools = { tiny = \"1\" }\nwait_for = [\"build\"]\n\n[tasks.deploy]\ndepends = [\"build\", \"deploy-aws\"]\nEOF\n\n# Running deploy directly should work (deploy-aws gets its tools)\nassert_contains \"mise run deploy\" \"rtx-tiny: v1.1.0\"\n\n# Running deploy-aws directly should also work\nassert_contains \"mise run deploy-aws\" \"rtx-tiny: v1.1.0\"\n\n# Test with multiple dependency tasks where one has tools and one doesn't\ncat <<EOF >mise.toml\n[env]\nFOO = \"bar\"\n\n[tasks.no-tools]\nrun = \"echo no-tools-task\"\n\n[tasks.with-tools]\nrun = \"rtx-tiny\"\ntools = { tiny = \"2\" }\n\n[tasks.parent]\ndepends = [\"no-tools\", \"with-tools\"]\nEOF\n\n# Both dependency tasks should execute correctly\nassert_contains \"mise run parent\" \"no-tools-task\"\nassert_contains \"mise run parent\" \"rtx-tiny: v2.1.0\"\n"
  },
  {
    "path": "e2e/tasks/test_task_ubi_autoinstall",
    "content": "#!/usr/bin/env bash\n\n# Test that ubi tool options are preserved during auto-install via `mise run`\n# Reproduces: https://github.com/jdx/mise/discussions/6582\n\ncat <<EOF >mise.toml\n[tools]\n\"ubi:databricks/cli\" = { version = \"0.233.0\", exe = \"databricks\" }\n\n[tasks.test]\nrun = \"databricks --version\"\nEOF\n\n# This should auto-install databricks with the exe=\"databricks\" option\n# Without the fix, it would fail with \"could not find any files matching [cli*]\"\nassert_contains \"mise run test\" \"0.233.0\"\n"
  },
  {
    "path": "e2e/tasks/test_task_untrusted_config_error",
    "content": "#!/usr/bin/env bash\n\n# Test that untrusted config files give a helpful error message\n# Issue: https://github.com/jdx/mise/discussions/6631\n\n# Ensure we start with a clean slate - no trusted configs\nexport MISE_TRUSTED_CONFIG_PATHS=\"\"\n\n# Create a config file with a task\ncat <<EOF >mise.toml\n[tasks.make]\nrun = \"echo 'hello from task'\"\nEOF\n\n# Running a task from an untrusted config should give a helpful error\n# It should either:\n# 1. Prompt the user to trust the config (when interactive), or\n# 2. Show a clear \"config not trusted\" error (not \"no tasks defined\")\n#\n# This test verifies we don't get the misleading \"no tasks defined\" error\noutput=$(MISE_YES=0 mise run make 2>&1 || true)\n\n# The error should mention \"trust\" or \"untrusted\", not just \"no tasks defined\"\nif echo \"$output\" | grep -q \"no tasks defined.*Are you in a project directory\"; then\n\techo \"FAIL: Got misleading 'no tasks defined' error instead of trust error\"\n\techo \"Output: $output\"\n\texit 1\nfi\n\n# Verify we get a trust-related error\nif echo \"$output\" | grep -qi \"trust\"; then\n\techo \"PASS: Got trust-related error message\"\nelse\n\techo \"FAIL: Expected trust-related error, got: $output\"\n\texit 1\nfi\n"
  },
  {
    "path": "e2e/tasks/test_task_usage",
    "content": "#!/usr/bin/env bash\n\n# tests that \"test.sh\" gets mapped to \"test\" except when an existing task is there named \"test\"\nassert \"mise tasks add --file test.sh --description sh\"\nassert \"mise tasks ls\" \"test  sh\"\nassert_json_partial_array \"mise tasks ls --json\" \"name,description,source\" \"[\n  {\n    \\\"name\\\": \\\"test\\\",\n    \\\"description\\\": \\\"sh\\\",\n    \\\"source\\\": \\\"$PWD/mise-tasks/test.sh\\\"\n  }\n]\"\nassert \"mise tasks ls --usage\" 'cmd test help=sh {\n    arg \"[-- ARGS_LAST]…\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks.\" required=#false var=#true hide=#true\n}'\n\nassert \"mise tasks add --file test --description no-sh\"\nassert \"mise tasks ls\" \"test     no-sh\ntest.sh  sh\"\nassert_json_partial_array \"mise tasks ls --json\" \"name,description,source\" \"[\n  {\n    \\\"name\\\": \\\"test\\\",\n    \\\"description\\\": \\\"no-sh\\\",\n    \\\"source\\\": \\\"$PWD/mise-tasks/test\\\"\n  },\n  {\n    \\\"name\\\": \\\"test.sh\\\",\n    \\\"description\\\": \\\"sh\\\",\n    \\\"source\\\": \\\"$PWD/mise-tasks/test.sh\\\"\n  }\n]\"\n\nassert_json_partial_array \"mise tasks ls --json\" \"name,description,source\" \"$(\n\tcat <<EOF\n[\n  {\n    \"name\": \"test\",\n    \"description\": \"no-sh\",\n    \"source\": \"$PWD/mise-tasks/test\"\n  },\n  {\n    \"name\": \"test.sh\",\n    \"description\": \"sh\",\n    \"source\": \"$PWD/mise-tasks/test.sh\"\n  }\n]\nEOF\n)\"\n\nassert \"mise tasks ls --usage\" 'cmd test help=no-sh {\n    arg \"[-- ARGS_LAST]…\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks.\" required=#false var=#true hide=#true\n}\ncmd test.sh help=sh {\n    arg \"[-- ARGS_LAST]…\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks.\" required=#false var=#true hide=#true\n}'\n\ntouch script.sh\nchmod +x script.sh\ncat <<EOF >mise.toml\n[tasks.mytask]\nrun = [\n  'echo abc',\n  './script.sh {{flag(name=\"test\", default=\"false\")}}',\n]\nEOF\n\nassert \"mise run mytask\" \"abc\"\n\nmkdir -p mise-tasks\ncat <<EOF >mise-tasks/test-args\n#!/usr/bin/env bash\n#MISE description=\"Compare block IDs between grower and packer tenants\"\n#USAGE flag \"-g --grower <growerTenant>\" required=#true var=#true help=\"The grower tenant ID(s) to compare\"\n#USAGE flag \"-p --packer <packerTenant>\" required=#true help=\"The packer tenant ID to match against\"\n\necho \"grower: \\$usage_grower\"\necho \"packer: \\$usage_packer\"\nEOF\nchmod +x mise-tasks/test-args\n\n# assert_fail \"mise run test-args --grower 1 -g 2\" \"Missing required flag: --packer <packer>\"\nassert \"mise run --trace test-args --grower 1 -g 2 --packer 3\" \"grower: 1 2\npacker: 3\"\n\ncat <<'EOF' >mise.toml\n[tasks.usage-env]\nusage = '''\narg \"myarg\" \"myarg description\" default=\"foo\"\n'''\nrun = 'echo myarg=$usage_myarg'\nEOF\n\nassert \"mise run usage-env\" \"myarg=foo\"\nassert \"mise run usage-env bar\" \"myarg=bar\"\n\ncat <<'EOF' >mise.toml\n[tasks.usage-env]\nusage = '''\nflag \"-m --myflag <myflag>\" default=\"foo\"\n'''\nrun = 'echo myflag=$usage_myflag'\nEOF\n\nassert \"mise run usage-env\" \"myflag=foo\"\nassert \"mise run usage-env -m bar\" \"myflag=bar\"\nassert \"mise run usage-env --myflag bar\" \"myflag=bar\"\n\ncat <<'EOF' >mise.toml\n[tasks.usage-env]\nusage = '''\narg \"myarg\" \"myarg description\" default=\"foo\"\n'''\nrun = [\n'echo \"Command 1: $usage_myarg\"',\n'echo \"Command 2: {{arg(name=\"myarg\", default=\"bar\")}} $usage_myarg\"',\n]\nEOF\n\nassert \"mise run usage-env\" \"\\\nCommand 1: foo\nCommand 2: foo foo\"\nassert \"mise run usage-env baz\" \"\\\nCommand 1: baz\nCommand 2: baz baz\"\n\ncat <<'EOF' >mise.toml\n[tasks.usage-env]\nusage = '''\nflag \"-m --myflag <myflag>\" default=\"false\"\n'''\nrun = [\n'echo \"Command 1: $usage_myflag\"',\n'echo \"Command 2: {{flag(name=\"myflag\", default=\"false\")}} $usage_myflag\"',\n]\nEOF\n\nassert \"mise run usage-env\" \"\\\nCommand 1: false\nCommand 2: false false\"\nassert \"mise run usage-env -m true\" \"\\\nCommand 1: true\nCommand 2: true true\"\nassert \"mise run usage-env --myflag true\" \"\\\nCommand 1: true\nCommand 2: true true\"\n\ncat <<'EOF' >mise.toml\n[tasks.usage-env]\nusage = '''\narg \"myarg\" \"myarg description\"\n'''\nrun = [\n'echo \"Command 1: $usage_myarg\"',\n'echo \"Command 2: {{arg(name=\"myarg\", default=\"bar\")}} $usage_myarg\"',\n]\nEOF\n\nassert_fail \"mise run usage-env\"\n"
  },
  {
    "path": "e2e/tasks/test_task_usage_env",
    "content": "#!/usr/bin/env bash\n\n# Test env attribute for args in file tasks\nmkdir -p mise-tasks\ncat <<'EOF' >mise-tasks/file-task-arg-env\n#!/usr/bin/env bash\n#USAGE arg \"<input>\" env=\"MY_INPUT\" help=\"Input file\"\n#USAGE arg \"<output>\" env=\"MY_OUTPUT\" help=\"Output file\" default=\"out.txt\"\n\necho \"input=$usage_input\"\necho \"output=$usage_output\"\nEOF\nchmod +x mise-tasks/file-task-arg-env\n\n# Test with CLI args (highest priority)\nassert \"mise run file-task-arg-env foo bar\" \"input=foo\noutput=bar\"\n\n# Test with env vars (middle priority)\nassert \"MY_INPUT=env-input MY_OUTPUT=env-output mise run file-task-arg-env\" \"input=env-input\noutput=env-output\"\n\n# Test with default (lowest priority)\nassert \"MY_INPUT=env-input mise run file-task-arg-env\" \"input=env-input\noutput=out.txt\"\n\n# Test CLI overrides env var\nassert \"MY_INPUT=env-input mise run file-task-arg-env cli-input\" \"input=cli-input\noutput=out.txt\"\n\n# Test CLI overrides both env var and default\nassert \"MY_INPUT=env-input MY_OUTPUT=env-output mise run file-task-arg-env cli-input cli-output\" \"input=cli-input\noutput=cli-output\"\n\n# Test env attribute for flags in file tasks\ncat <<'EOF' >mise-tasks/file-task-flag-env\n#!/usr/bin/env bash\n#USAGE flag \"-u --user <user>\" env=\"MY_USER\" help=\"User to run as\"\n#USAGE flag \"-p --port <port>\" env=\"MY_PORT\" help=\"Port to run on\" default=\"8080\"\n\necho \"user=$usage_user\"\necho \"port=$usage_port\"\nEOF\nchmod +x mise-tasks/file-task-flag-env\n\n# Test with CLI flags (highest priority)\nassert \"mise run file-task-flag-env --user=cli-user --port=3000\" \"user=cli-user\nport=3000\"\n\n# Test with env vars (middle priority)\nassert \"MY_USER=env-user MY_PORT=9000 mise run file-task-flag-env\" \"user=env-user\nport=9000\"\n\n# Test with default (lowest priority)\nassert \"MY_USER=env-user mise run file-task-flag-env\" \"user=env-user\nport=8080\"\n\n# Test CLI overrides env var\nassert \"MY_USER=env-user mise run file-task-flag-env --user=cli-user\" \"user=cli-user\nport=8080\"\n\n# Test CLI overrides both env var and default\nassert \"MY_USER=env-user MY_PORT=9000 mise run file-task-flag-env --user=cli-user --port=3000\" \"user=cli-user\nport=3000\"\n\n# Test short flags\nassert \"MY_USER=env-user mise run file-task-flag-env -u cli-user\" \"user=cli-user\nport=8080\"\n\n# Test env attribute shows in help\nassert_contains \"mise run file-task-flag-env --help 2>&1 || true\" \"[env: MY_USER]\"\nassert_contains \"mise run file-task-flag-env --help 2>&1 || true\" \"[env: MY_PORT]\"\n"
  },
  {
    "path": "e2e/tasks/test_task_usage_env_inherited",
    "content": "#!/usr/bin/env bash\n# Test that usage env= attributes can read from inherited shell environment\n# This tests issue jdx/usage#468 where env-backed arguments always used defaults\n\n# Set a test env var in the shell environment\nexport TEST_HOST=\"myhost.local\"\n\n# Create a task that uses env= to read from inherited environment\ncat <<'EOF' >mise.toml\n[tasks.test]\nusage = '''\narg \"[host]\" env=\"TEST_HOST\" default=\"localhost\"\n'''\nrun = 'echo \"Host: ${usage_host}\"'\nEOF\n\n# Test 1: env= should read from inherited shell environment\nassert_contains \"mise run test\" \"Host: myhost.local\"\n\n# Test 2: Explicit arg should override env default\nassert_contains \"mise run test explicit.host\" \"Host: explicit.host\"\n\n# Test 3: Without env var set, should use default\nunset TEST_HOST\nassert_contains \"mise run test\" \"Host: localhost\"\n"
  },
  {
    "path": "e2e/tasks/test_task_usage_env_tera",
    "content": "#!/usr/bin/env bash\n\n# Test env attribute with tera templates for args\ncat <<'EOF' >mise.toml\n[tasks.tera-arg-env]\nusage = '''\narg \"<input>\" env=\"MY_INPUT\" help=\"Input file\"\narg \"<output>\" env=\"MY_OUTPUT\" help=\"Output file\" default=\"out.txt\"\n'''\nrun = [\n  'echo \"Command 1: $usage_input $usage_output\"',\n  'echo \"Command 2: {{arg(name=\"input\")}} {{arg(name=\"output\")}}\"',\n]\nEOF\n\n# Test with CLI args (highest priority)\nassert \"mise run tera-arg-env foo bar\" \"Command 1: foo bar\nCommand 2: foo bar\"\n\n# Test with env vars (middle priority)\nassert \"MY_INPUT=env-input MY_OUTPUT=env-output mise run tera-arg-env\" \"Command 1: env-input env-output\nCommand 2: env-input env-output\"\n\n# Test with default (lowest priority)\nassert \"MY_INPUT=env-input mise run tera-arg-env\" \"Command 1: env-input out.txt\nCommand 2: env-input out.txt\"\n\n# Test CLI overrides env var\nassert \"MY_INPUT=env-input mise run tera-arg-env cli-input\" \"Command 1: cli-input out.txt\nCommand 2: cli-input out.txt\"\n\n# Test env attribute with tera templates for flags\ncat <<'EOF' >mise.toml\n[tasks.tera-flag-env]\nusage = '''\nflag \"-u --user <user>\" env=\"MY_USER\" help=\"User to run as\"\nflag \"-p --port <port>\" env=\"MY_PORT\" help=\"Port to run on\" default=\"8080\"\n'''\nrun = [\n  'echo \"Command 1: $usage_user $usage_port\"',\n  'echo \"Command 2: {{flag(name=\"user\", default=\"\")}} {{flag(name=\"port\", default=\"8080\")}}\"',\n]\nEOF\n\n# Test with CLI flags (highest priority)\nassert \"mise run tera-flag-env --user=cli-user --port=3000\" \"Command 1: cli-user 3000\nCommand 2: cli-user 3000\"\n\n# Test with env vars (middle priority)\nassert \"MY_USER=env-user MY_PORT=9000 mise run tera-flag-env\" \"Command 1: env-user 9000\nCommand 2: env-user 9000\"\n\n# Test with default (lowest priority)\nassert \"MY_USER=env-user mise run tera-flag-env\" \"Command 1: env-user 8080\nCommand 2: env-user 8080\"\n\n# Test CLI overrides env var\nassert \"MY_USER=env-user mise run tera-flag-env --user=cli-user\" \"Command 1: cli-user 8080\nCommand 2: cli-user 8080\"\n\n# Test mixed usage - env var and tera template with different defaults\ncat <<'EOF' >mise.toml\n[tasks.tera-mixed]\nusage = '''\nflag \"-v --verbose\" env=\"MY_VERBOSE\" help=\"Verbose mode\" default=\"false\"\n'''\nrun = [\n  'echo \"Env var: $usage_verbose\"',\n  'echo \"Tera: {{flag(name=\"verbose\", default=\"false\")}}\"',\n]\nEOF\n\n# Without env var or flag\nassert \"mise run tera-mixed\" \"Env var: false\nTera: false\"\n\n# With env var\nassert \"MY_VERBOSE=true mise run tera-mixed\" \"Env var: true\nTera: true\"\n\n# TODO: Boolean flags with env vars don't currently convert to $usage_* environment variables correctly\n# The usage-lib's as_env() method doesn't properly handle boolean flag values\n# These tests are commented out until this is fixed\n# # With CLI flag\n# assert \"mise run tera-mixed --verbose\" \"Env var: true\n# Tera: true\"\n\n# # CLI overrides env var\n# assert \"MY_VERBOSE=false mise run tera-mixed --verbose\" \"Env var: true\n# Tera: true\"\n"
  },
  {
    "path": "e2e/tasks/test_task_usage_env_toml",
    "content": "#!/usr/bin/env bash\n\n# Test env attribute for args in TOML tasks\ncat <<'EOF' >mise.toml\n[tasks.toml-task-arg-env]\nusage = '''\narg \"<input>\" env=\"MY_INPUT\" help=\"Input file\"\narg \"<output>\" env=\"MY_OUTPUT\" help=\"Output file\" default=\"out.txt\"\n'''\nrun = '''\necho \"input=$usage_input\"\necho \"output=$usage_output\"\n'''\nEOF\n\n# Test with CLI args (highest priority)\nassert \"mise run toml-task-arg-env foo bar\" \"input=foo\noutput=bar\"\n\n# Test with env vars (middle priority)\nassert \"MY_INPUT=env-input MY_OUTPUT=env-output mise run toml-task-arg-env\" \"input=env-input\noutput=env-output\"\n\n# Test with default (lowest priority)\nassert \"MY_INPUT=env-input mise run toml-task-arg-env\" \"input=env-input\noutput=out.txt\"\n\n# Test CLI overrides env var\nassert \"MY_INPUT=env-input mise run toml-task-arg-env cli-input\" \"input=cli-input\noutput=out.txt\"\n\n# Test CLI overrides both env var and default\nassert \"MY_INPUT=env-input MY_OUTPUT=env-output mise run toml-task-arg-env cli-input cli-output\" \"input=cli-input\noutput=cli-output\"\n\n# Test env attribute for flags in TOML tasks\ncat <<'EOF' >mise.toml\n[tasks.toml-task-flag-env]\nusage = '''\nflag \"-u --user <user>\" env=\"MY_USER\" help=\"User to run as\"\nflag \"-p --port <port>\" env=\"MY_PORT\" help=\"Port to run on\" default=\"8080\"\n'''\nrun = '''\necho \"user=$usage_user\"\necho \"port=$usage_port\"\n'''\nEOF\n\n# Test with CLI flags (highest priority)\nassert \"mise run toml-task-flag-env --user=cli-user --port=3000\" \"user=cli-user\nport=3000\"\n\n# Test with env vars (middle priority)\nassert \"MY_USER=env-user MY_PORT=9000 mise run toml-task-flag-env\" \"user=env-user\nport=9000\"\n\n# Test with default (lowest priority)\nassert \"MY_USER=env-user mise run toml-task-flag-env\" \"user=env-user\nport=8080\"\n\n# Test CLI overrides env var\nassert \"MY_USER=env-user mise run toml-task-flag-env --user=cli-user\" \"user=cli-user\nport=8080\"\n\n# Test CLI overrides both env var and default\nassert \"MY_USER=env-user MY_PORT=9000 mise run toml-task-flag-env --user=cli-user --port=3000\" \"user=cli-user\nport=3000\"\n\n# Test short flags\nassert \"MY_USER=env-user mise run toml-task-flag-env -u cli-user\" \"user=cli-user\nport=8080\"\n\n# Test env attribute shows in help\nassert_contains \"mise run toml-task-flag-env --help 2>&1 || true\" \"[env: MY_USER]\"\nassert_contains \"mise run toml-task-flag-env --help 2>&1 || true\" \"[env: MY_PORT]\"\n\n# Test with required arg and env var satisfies requirement\ncat <<'EOF' >mise.toml\n[tasks.toml-required-env]\nusage = '''\narg \"<input>\" env=\"MY_REQUIRED_INPUT\" help=\"Required input\"\n'''\nrun = 'echo \"input=$usage_input\"'\nEOF\n\n# Should fail without env var or CLI arg\nassert_fail \"mise run toml-required-env\"\n\n# Should succeed with env var\nassert \"MY_REQUIRED_INPUT=from-env mise run toml-required-env\" \"input=from-env\"\n\n# Should succeed with CLI arg\nassert \"mise run toml-required-env from-cli\" \"input=from-cli\"\n"
  },
  {
    "path": "e2e/tasks/test_task_usage_map_tera",
    "content": "#!/usr/bin/env bash\n\n# Test the `usage` map inside Tera run scripts for inline tasks\n\n# Basic args + flags with defaults\ncat <<'EOF' >mise.toml\n[tasks.usage-tera]\ndescription = \"Test usage map in tera run scripts\"\nusage = '''\narg \"<environment>\" help=\"Target environment\"\nflag \"-v --verbose\" help=\"Enable verbose output\"\nflag \"--region <region>\" help=\"AWS region\" default=\"us-east-1\"\n'''\nrun = '''\necho \"Deploying to {{ usage.environment }} in {{ usage.region }}\"\n{% if usage.verbose %}\necho \"Verbose mode enabled\"\n{% endif %}\n'''\nEOF\n\nassert \"mise run usage-tera staging\" \"Deploying to staging in us-east-1\"\nassert \"mise run usage-tera staging --region us-west-2\" \"Deploying to staging in us-west-2\"\nassert \"mise run usage-tera staging --verbose\" \"\\\nDeploying to staging in us-east-1\nVerbose mode enabled\"\nassert \"mise run usage-tera staging --region eu-central-1 --verbose\" \"\\\nDeploying to staging in eu-central-1\nVerbose mode enabled\"\n\n# Variadic args exposed as arrays in the usage map\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-tags]\ndescription = \"Test variadic args in usage map\"\nusage = '''\narg \"<environment>\" help=\"Target environment\"\narg \"[tags]\" var=#true\n'''\nrun = '''\necho \"env={{ usage.environment }}\"\necho \"tag_count={{ usage.tags | length }}\"\n{% for tag in usage.tags %}\necho \"tag={{ tag }}\"\n{% endfor %}\n'''\nEOF\n\nassert \"mise run usage-tera-tags prod foo bar\" \"\\\nenv=prod\ntag_count=2\ntag=foo\ntag=bar\"\n\n# Hyphenated flag names become snake_case keys on the usage map (e.g. --foo-bar -> usage.foo_bar)\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-hyphen]\ndescription = \"Test hyphenated flag name mapping to snake_case\"\nusage = '''\nflag \"--foo-bar <foo-bar>\" help=\"Hyphenated flag\"\n'''\nrun = '''\necho \"foo_bar={{ usage.foo_bar }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-hyphen --foo-bar value\" \"foo_bar=value\"\n\n# Variadic flags exposed as arrays in the usage map\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-var-flag]\ndescription = \"Test variadic flags in usage map\"\nusage = '''\nflag \"--tag <tag>\" help=\"Tag\" var=#true\n'''\nrun = '''\necho \"tag_count={{ usage.tag | length }}\"\n{% for tag in usage.tag %}\necho \"tag={{ tag }}\"\n{% endfor %}\n'''\nEOF\n\nassert \"mise run usage-tera-var-flag --tag foo --tag bar\" \"\\\ntag_count=2\ntag=foo\ntag=bar\"\n\nassert \"mise run usage-tera-var-flag --tag foo\" \"\\\ntag_count=1\ntag=foo\"\n\n# Variadic flags are exposed as arrays and can be joined\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-var-flag-join]\ndescription = \"Test variadic flags joined with a separator\"\nusage = '''\nflag \"--tag <tag>\" help=\"Tag\" var=#true\n'''\nrun = '''\necho \"tags={{ usage.tag | join(sep='::') }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-var-flag-join --tag foo --tag bar\" \"tags=foo::bar\"\n\n# Variadic flags with multiple defaults are exposed as arrays in the usage map\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-var-flag-default]\ndescription = \"Test variadic flags with default in usage map\"\nusage = '''\nflag \"--tag <tag>\" help=\"Tag\" var=#true {\n    default {\n        \"foo\"\n        \"bar\"\n    }\n}\n'''\nrun = '''\necho \"tags={{ usage.tag | join(sep='::') }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-var-flag-default\" \"tags=foo::bar\"\n\n# Variadic flags with string defaults stay as single element (not split)\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-var-flag-default-string]\ndescription = \"Test variadic flags with string default in usage map\"\nusage = '''\nflag \"--tag <tag>\" help=\"Tag\" var=#true default=\"foo bar\"\n'''\nrun = '''\necho \"tags={{ usage.tag | join(sep='::') }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-var-flag-default-string\" \"tags=foo bar\"\n\n# Args with defaults\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-arg-default]\ndescription = \"Test arg with default in usage map\"\nusage = '''\narg \"<name>\" default=\"world\"\n'''\nrun = '''\necho \"Hello, {{ usage.name }}!\"\n'''\nEOF\n\nassert \"mise run usage-tera-arg-default\" \"Hello, world!\"\nassert \"mise run usage-tera-arg-default -- Alice\" \"Hello, Alice!\"\n\n# Variadic args with multiple defaults\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-var-arg-default]\ndescription = \"Test variadic arg with defaults in usage map\"\nusage = '''\narg \"[names]\" var=#true {\n    default {\n        \"alice\"\n        \"bob\"\n    }\n}\n'''\nrun = '''\necho \"Hello, {{ usage.names | join(sep=' and ') }}!\"\n'''\nEOF\n\nassert \"mise run usage-tera-var-arg-default\" \"Hello, alice and bob!\"\nassert \"mise run usage-tera-var-arg-default -- charlie\" \"Hello, charlie!\"\n\n# Path filters (file_stem, basename, dirname, extname) work with required args\n# Regression test for https://github.com/jdx/mise/discussions/7239\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-file-stem]\ndescription = \"Test file_stem filter with required arg\"\nusage = '''\narg \"<file>\" help=\"The file path\"\n'''\nrun = '''\necho \"stem={{ usage.file | file_stem }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-file-stem -- /path/to/myfile.txt\" \"stem=myfile\"\nassert \"mise run usage-tera-file-stem -- foo.bar.baz\" \"stem=foo.bar\"\n\n# Test all path filters together\ncat <<'EOF' >mise.toml\n[tasks.usage-tera-path-filters]\ndescription = \"Test all path filters with required arg\"\nusage = '''\narg \"<file>\" help=\"The file path\"\n'''\nrun = '''\necho \"dirname={{ usage.file | dirname }}\"\necho \"basename={{ usage.file | basename }}\"\necho \"extname={{ usage.file | extname }}\"\necho \"file_stem={{ usage.file | file_stem }}\"\n'''\nEOF\n\nassert \"mise run usage-tera-path-filters -- /path/to/file.txt\" \"\\\ndirname=/path/to\nbasename=file.txt\nextname=txt\nfile_stem=file\"\n"
  },
  {
    "path": "e2e/tasks/test_task_validate",
    "content": "#!/usr/bin/env bash\n\n# Test successful validation\ncat <<EOF >mise.toml\n[tasks.valid]\nrun = \"echo valid\"\n\n[tasks.meta-task]\ndepends = [\"valid\"]\nEOF\n\nassert_contains \"mise tasks validate\" \"✓ All 2 task(s) validated successfully\"\n\n# Test circular dependency detection\ncat <<EOF >mise.toml\n[tasks.a]\nrun = \"echo a\"\ndepends = [\"b\"]\n\n[tasks.b]\nrun = \"echo b\"\ndepends = [\"a\"]\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Circular dependency detected\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"circular-dependency\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"a -> b -> a\"\n\n# Test missing dependency\ncat <<EOF >mise.toml\n[tasks.valid]\nrun = \"echo valid\"\n\n[tasks.invalid]\nrun = \"echo invalid\"\ndepends = [\"non-existent\"]\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Dependency 'non-existent' not found\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"missing-dependency\"\n\n# Test invalid timeout\ncat <<EOF >mise.toml\n[tasks.bad-timeout]\nrun = \"echo test\"\ntimeout = \"not-a-duration\"\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Invalid timeout format\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"invalid-timeout\"\n\n# Test valid timeout formats\ncat <<EOF >mise.toml\n[tasks.good-timeout-1]\nrun = \"echo test\"\ntimeout = \"30s\"\n\n[tasks.good-timeout-2]\nrun = \"echo test\"\ntimeout = \"5m\"\n\n[tasks.good-timeout-3]\nrun = \"echo test\"\ntimeout = \"1h\"\nEOF\n\nassert_contains \"mise tasks validate\" \"✓ All 3 task(s) validated successfully\"\n\n# Test duplicate aliases (should only report once, not for each task)\ncat <<EOF >mise.toml\n[tasks.task1]\nrun = \"echo 1\"\nalias = \"myalias\"\n\n[tasks.task2]\nrun = \"echo 2\"\nalias = \"myalias\"\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Alias 'myalias' is used by multiple tasks\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"alias-conflict\"\n# Verify the error is only reported once (not duplicated for each task)\nerror_count=$(mise tasks validate 2>&1 | grep -c \"Alias 'myalias' is used by multiple tasks\" || true)\n[ \"$error_count\" = \"1\" ] || (echo \"Expected 1 alias conflict error, got $error_count\" && exit 1)\n\n# Test empty task\ncat <<EOF >mise.toml\n[tasks.empty]\ndescription = \"empty task\"\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Task has no executable content\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"no-execution\"\n\n# Test invalid glob pattern\ncat <<EOF >mise.toml\n[tasks.bad-glob]\nrun = \"echo test\"\nsources = [\"[invalid-glob\"]\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Invalid source glob pattern\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"invalid-glob-pattern\"\n\n# Test JSON output\ncat <<EOF >mise.toml\n[tasks.valid]\nrun = \"echo valid\"\n\n[tasks.invalid]\nrun = \"echo invalid\"\ndepends = [\"missing\"]\nEOF\n\nassert_contains \"mise tasks validate --json 2>&1 || true\" '\"tasks_validated\": 2'\nassert_contains \"mise tasks validate --json 2>&1 || true\" '\"errors\": 1'\nassert_contains \"mise tasks validate --json 2>&1 || true\" '\"category\": \"missing-dependency\"'\n\n# Test errors-only flag\ncat <<EOF >mise.toml\n[tasks.error-task]\ndepends = [\"missing\"]\n\n[tasks.warning-task]\nfile = \"./non-executable.sh\"\nEOF\n\ntouch non-executable.sh\nassert_contains \"mise tasks validate --errors-only 2>&1 || true\" \"error-task\"\nassert_not_contains \"mise tasks validate --errors-only 2>&1 || true\" \"warning-task\"\n\n# Test specific task validation\ncat <<EOF >mise.toml\n[tasks.good]\nrun = \"echo good\"\n\n[tasks.bad]\ndepends = [\"missing\"]\nEOF\n\nassert_contains \"mise tasks validate good\" \"✓ All 1 task(s) validated successfully\"\nassert_contains \"mise tasks validate bad 2>&1 || true\" \"Dependency 'missing' not found\"\n\n# Test validation with file-based tasks\nmkdir -p mise-tasks\ncat <<'SCRIPT' >mise-tasks/filetask.sh\n#!/usr/bin/env bash\n#MISE description=\"Test file task\"\n#MISE depends=[\"valid\"]\necho \"file task\"\nSCRIPT\nchmod +x mise-tasks/filetask.sh\n\ncat <<EOF >mise.toml\n[tasks.valid]\nrun = \"echo valid\"\nEOF\n\nassert_contains \"mise tasks validate filetask\" \"✓ All 1 task(s) validated successfully\"\n\n# Test missing file\ncat <<EOF >mise.toml\n[tasks.missing-file]\nfile = \"./does-not-exist.sh\"\nEOF\n\nassert_contains \"mise tasks validate 2>&1 || true\" \"Task file not found\"\nassert_contains \"mise tasks validate 2>&1 || true\" \"missing-file\"\n\n# Clean up before next test\nrm -rf mise-tasks non-executable.sh\n\n# Test that run entries can reference tasks by alias (not just by name)\ncat <<'EOF' >mise.toml\n[tasks.build]\nrun = \"echo building\"\nalias = \"b\"\n\n[tasks.deploy]\nrun = [\n  { task = \"b\" }\n]\nEOF\n\nassert_contains \"mise tasks validate\" \"✓ All 2 task(s) validated successfully\"\n\n# Test that command-line validation can use task aliases\nassert_contains \"mise tasks validate b\" \"✓ All 1 task(s) validated successfully\"\nassert_contains \"mise tasks validate build\" \"✓ All 1 task(s) validated successfully\"\n\n# Test unknown field validation in file tasks\nmkdir -p mise-tasks\ncat <<'SCRIPT' >mise-tasks/bad-field\n#!/usr/bin/env bash\n#MISE description=\"Test file task\"\n#MISE not_a_valid_field=\"this should error\"\necho \"should not run\"\nSCRIPT\nchmod +x mise-tasks/bad-field\n\nassert_contains \"mise tasks validate bad-field 2>&1 || true\" \"unknown field\"\nassert_contains \"mise tasks validate bad-field 2>&1 || true\" \"not_a_valid_field\"\n\n# Clean up\nrm -rf mise-tasks\n\n# Test unknown field validation in TOML tasks\ncat <<EOF >mise.toml\n[tasks.toml-bad-field]\nrun = \"echo test\"\nnot_a_valid_field = \"this should error\"\nEOF\n\nassert_contains \"mise tasks validate toml-bad-field 2>&1 || true\" \"unknown field\"\nassert_contains \"mise tasks validate toml-bad-field 2>&1 || true\" \"not_a_valid_field\"\n\n# Clean up mise.toml before next test\nrm -f mise.toml\n\n# Test multiple alias fields (both alias and aliases)\nmkdir -p mise-tasks\ncat <<'SCRIPT' >mise-tasks/multiple-alias\n#!/usr/bin/env bash\n#MISE description=\"Task with both alias and aliases\"\n#MISE alias=\"single\"\n#MISE aliases=[\"multi1\", \"multi2\"]\necho \"should not run\"\nSCRIPT\nchmod +x mise-tasks/multiple-alias\n\nassert_contains \"mise tasks validate multiple-alias 2>&1 || true\" \"Cannot define both 'alias' and 'aliases'\"\n"
  },
  {
    "path": "e2e/tasks/test_task_vars",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\ntasks.a.run = \"echo foo: {{vars.foo}}\"\nvars.foo = \"bar\"\nEOF\nassert \"mise run a\" \"foo: bar\"\n\ncat <<EOF >mise.toml\ntasks.a.run = \"echo foo: {{vars.foo}}\"\nvars.foo = \"{{cwd}}\"\nEOF\nassert \"mise run a\" \"foo: $(pwd)\"\n\necho '{ \"SECRET\": \"123\" }' >.env.json\ncat <<EOF >mise.toml\ntasks.a.run = \"echo foo: {{vars.SECRET}}\"\nvars._.file = \".env.json\"\nEOF\nassert \"mise run a\" \"foo: 123\"\n\ncat <<EOF >mise.toml\ntasks.a.run = \"echo foo: {{vars.bar}}\"\nvars.foo = \"bar\"\nvars.bar = \"bar: {{vars.foo}}\"\nEOF\nassert \"mise run a\" \"foo: bar: bar\"\n\n# Per-task vars override config-level vars\ncat <<EOF >mise.toml\n[vars]\ngreeting = \"hello\"\nname = \"world\"\n\n[tasks.a]\nrun = \"echo {{vars.greeting}} {{vars.name}}\"\nvars = { greeting = \"hi\" }\nEOF\nassert \"mise run a\" \"hi world\"\n\n# Per-task var templates can reference base (config-level) vars\ncat <<EOF >mise.toml\n[vars]\nbase = \"base_value\"\n\n[tasks.a]\nrun = \"echo {{vars.derived}}\"\nvars = { derived = \"derived from {{vars.base}}\" }\nEOF\nassert \"mise run a\" \"derived from base_value\"\n"
  },
  {
    "path": "e2e/tasks/test_task_wait_for_env",
    "content": "#!/usr/bin/env bash\n\n# Test 1: wait_for with name-only matching against env overrides\n# \"test\" has no direct dependency on \"setup\", only wait_for.\n# \"build\" depends on \"VERBOSE=1 setup\".\n# Without the name-based matching fix, wait_for would fail to find \"setup\"\n# because it's running as \"VERBOSE=1 setup\".\n# Use a file to verify ordering: setup sleeps then writes, test writes after.\ncat <<EOF >mise.toml\n[tasks.setup]\nrun = 'sleep 0.3 && echo setup >> order.txt'\n\n[tasks.build]\ndepends = [\"VERBOSE=1 setup\"]\nrun = 'echo build'\n\n[tasks.test]\nwait_for = [\"setup\"]\nrun = 'echo test >> order.txt'\nEOF\n\nrm -f order.txt\nmise run test ::: build\nassert \"cat order.txt\" \"setup\ntest\"\n\n# Test 2: wait_for with name-only matching against args overrides\ncat <<'EOF' >mise.toml\n[tasks.setup]\nrun = 'sleep 0.3 && echo setup >> order.txt # args: $@'\n\n[tasks.build]\ndepends = [\"setup myarg\"]\nrun = 'echo build'\n\n[tasks.test]\nwait_for = [\"setup\"]\nrun = 'echo test >> order.txt'\nEOF\n\nrm -f order.txt\nmise run test ::: build\nassert \"cat order.txt\" \"setup\ntest\"\n\n# Test 3: wait_for with env specified should do identity matching\ncat <<EOF >mise.toml\n[tasks.setup]\nrun = 'sleep 0.3 && echo setup >> order.txt'\n\n[tasks.build]\ndepends = [\"VERBOSE=1 setup\"]\nrun = 'echo build'\n\n[tasks.test]\nwait_for = [\"VERBOSE=1 setup\"]\nrun = 'echo test >> order.txt'\nEOF\n\nrm -f order.txt\nmise run test ::: build\nassert \"cat order.txt\" \"setup\ntest\"\n\n# Test 4: wait_for with args specified should do identity matching\ncat <<'EOF' >mise.toml\n[tasks.setup]\nrun = 'sleep 0.3 && echo setup >> order.txt # args: $@'\n\n[tasks.build]\ndepends = [\"setup myarg\"]\nrun = 'echo build'\n\n[tasks.test]\nwait_for = [\"setup myarg\"]\nrun = 'echo test >> order.txt'\nEOF\n\nrm -f order.txt\nmise run test ::: build\nassert \"cat order.txt\" \"setup\ntest\"\n"
  },
  {
    "path": "e2e/tasks/test_task_watch_skip_deps",
    "content": "#!/usr/bin/env bash\n\nmise use -g watchexec\n\ncat <<EOF >mise.toml\n[tasks.a]\nrun = \"echo a\"\nsources = [\"a.txt\"]\n[tasks.b]\ndepends = [\"a\"]\nrun = \"echo b\"\nsources = [\"b.txt\"]\nEOF\n\ntouch a.txt b.txt\n\nLOG_FILE=$(mktemp)\nmise watch b --skip-deps >\"$LOG_FILE\" 2>&1 &\nWATCH_PID=$!\n\ntrap 'kill $WATCH_PID' EXIT\n\nsleep 1\n\necho \"\" >\"$LOG_FILE\" # clear the log file to skip-deps capture the output of the re-run\n\ntouch b.txt\nsleep 1\n\noutput=$(cat \"$LOG_FILE\")\n\nif [[ $output != *\"[b] $ echo b\"* ]]; then\n\tfail \"Expected output to contain '[b] $ echo b', got: $output\"\nfi\nif [[ $output == *\"[a] $ echo a\"* ]]; then\n\tfail \"Expected output to not contain '[a] $ echo a', got: $output\"\nfi\nok \"mise watch b --skip-deps\"\n"
  },
  {
    "path": "e2e/tasks/test_task_wildcard_no_self_match",
    "content": "#!/usr/bin/env bash\n\n# Test that task glob pattern \"test:*\" does not match the \"test\" task itself.\n# This prevents circular invocation when a parent task delegates to its children.\n# See: https://github.com/jdx/mise/discussions/8138\n\ncat <<'EOF' >mise.toml\n[tasks.\"test:foo\"]\nrun = 'echo foo'\n\n[tasks.\"test:bar\"]\nrun = 'echo bar'\n\n[tasks.test]\nrun = [\n  { task = \"test:*\" },\n]\nEOF\n\n# \"mise run test\" should run test:foo and test:bar without circular dependency\nassert_contains \"mise run test\" \"foo\"\nassert_contains \"mise run test\" \"bar\"\n"
  },
  {
    "path": "e2e/tasks/test_tasks_ceiling_paths",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# Test for MISE_CEILING_PATHS functionality\n# This tests that mise respects the ceiling paths configuration\n# which prevents traversing up the directory tree beyond specified paths\n\n# Create a test directory structure\nTEST_ROOT=$(pwd)\n\n# Setup directory structure\nmkdir -p \"$TEST_ROOT/parent/child/grandchild\"\n\n# Create config files at different levels using heredoc\nmkdir -p \"$TEST_ROOT/parent/mise-tasks\"\ncat <<EOF >\"$TEST_ROOT/parent/mise-tasks/task-parent\"\n#!/usr/bin/env bash\necho parent\nEOF\nchmod +x \"$TEST_ROOT/parent/mise-tasks/task-parent\"\n\nmkdir -p \"$TEST_ROOT/parent/child/mise-tasks\"\ncat <<EOF >\"$TEST_ROOT/parent/child/mise-tasks/task-child\"\n#!/usr/bin/env bash\necho child\nEOF\nchmod +x \"$TEST_ROOT/parent/child/mise-tasks/task-child\"\n\nmkdir -p \"$TEST_ROOT/parent/child/grandchild/mise-tasks\"\ncat <<EOF >\"$TEST_ROOT/parent/child/grandchild/mise-tasks/task-grandchild\"\n#!/usr/bin/env bash\necho grandchild\nEOF\nchmod +x \"$TEST_ROOT/parent/child/grandchild/mise-tasks/task-grandchild\"\n\ncd \"$TEST_ROOT/parent/child/grandchild\"\n\n# Test 1: Normal behavior without ceiling paths\necho \"Test 1: Without ceiling paths, should find all tasks up to parent\"\nassert_contains \"mise tasks\" \"task-grandchild\"\nassert_contains \"mise tasks\" \"task-child\"\nassert_contains \"mise tasks\" \"task-parent\"\necho \"Test 1: Passed\"\n\n# Test 2: Set ceiling path to child directory\necho \"Test 2: With ceiling path at child, should not find parent or child tasks\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child\"\nassert_contains \"mise tasks\" \"task-grandchild\"\nassert_not_contains \"mise tasks\" \"task-child\"\nassert_not_contains \"mise tasks\" \"task-parent\"\necho \"Test 2: Passed\"\n\n# Test 3: Set ceiling path to grandchild directory\necho \"Test 3: With ceiling path at grandchild, should not find any tasks\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child/grandchild\"\nassert_not_contains \"mise tasks\" \"task-grandchild\"\nassert_not_contains \"mise tasks\" \"task-child\"\nassert_not_contains \"mise tasks\" \"task-parent\"\necho \"Test 3: Passed\"\n\n# Test 4: Multiple ceiling paths\necho \"Test 4: With multiple ceiling paths\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/parent/child:$TEST_ROOT/parent\"\nassert_contains \"mise tasks\" \"task-grandchild\"\nassert_not_contains \"mise tasks\" \"task-child\"\nassert_not_contains \"mise tasks\" \"task-parent\"\necho \"Test 4: Passed\"\n\n# Test 5: Ceiling path with non-existent directory\necho \"Test 5: With non-existent ceiling path, should find all tasks\"\nexport MISE_CEILING_PATHS=\"$TEST_ROOT/nonexistent\"\nassert_contains \"mise tasks\" \"task-grandchild\"\nassert_contains \"mise tasks\" \"task-child\"\nassert_contains \"mise tasks\" \"task-parent\"\necho \"Test 5: Passed\"\n\necho \"All tests passed!\"\n"
  },
  {
    "path": "e2e/test_top_runtimes",
    "content": "#!/usr/bin/env bash\n\nexit 0 # disable for now for faster releases\n\n# top 50 plugins by stargazers:\n# 687 nodejs\n# 507 ruby\n# 469 python\n# 393 direnv\n# 353 elixir\n# 351 erlang\n# 321 golang\n# 285 java\n# 170 hashicorp\n# 160 php\n# 147 postgres\n# 117 rust\n# 113 yarn\n# 102 deno\n# 93 kubectl\n# 81 action-validator\n# 75 dotnet-core\n# 73 flutter\n# 68 crystal\n# 49 neovim\n# 47 poetry\n# 46 haskell\n# 42 link\n# 38 lua\n# 38 bun\n# 35 redis\n# 35 gcloud\n# 34 helm\n# 33 gleam\n# 32 awscli\n# 30 dart\n# 28 pyapp\n# 27 kotlin\n# 26 pnpm\n# 23 ocaml\n# 22 rebar\n# 20 julia\n# 20 elm\n# 18 r\n# 17 nim\n# 17 alias\n# 16 mysql\n# 16 minikube\n# 16 gradle\n# 15 zig\n# 15 shellcheck\n# 15 scala\n# 15 maven\n# 15 kustomize\n# 15 graalvm\n\nmise exec node -- node -v\nmise exec python -- python -V\nmise exec direnv -- direnv --version\nmise exec erlang -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell\nmise exec elixir erlang -- elixir --version\nmise exec golang -- go version\nmise exec java -- java -version\nmise exec terraform -- terraform -v\nmise exec yarn -- yarn --version\nmise exec deno -- deno --version\nmise exec bun -- bun --version\nmise exec kubectl -- kubectl version --client\nmise exec dotnet-core -- dotnet --list-sdks\nmise exec flutter -- flutter --version\nmise exec crystal -- crystal -v\nmise exec neovim -- nvim --version\n\n#mise exec php -- php -v php is a bit slow to install, works fine though\n#mise exec rust -- rustc -V # does not seem to work correctly\n#mise exec postgres -- psql -v # hard one to install\n"
  },
  {
    "path": "e2e/tools/test_path_order",
    "content": "#!/usr/bin/env bash\n\ncat <<EOF >mise.toml\n[env]\n_.path = [\"bin\", \"bin2\"]\n[tools]\ndummy = \"1.0.0\"\njq = \"1.7.1\"\nEOF\n\nmkdir bin subdir subdir/bin\ncat <<EOF >subdir/mise.toml\n[env]\n_.path = [\"bin\", \"bin2\"]\n[tools]\ndummy = \"2.0.0\"\npitchfork = \"0.1.5\"\nEOF\n\ncd subdir\nmise i\n\nassert \"mise bin-paths\" \"$MISE_DATA_DIR/installs/dummy/2.0.0/bin\n$MISE_DATA_DIR/installs/pitchfork/0.1.5\n$MISE_DATA_DIR/installs/jq/1.7.1\"\n\nassert \"mise env | grep PATH\" \"export PATH='$HOME/workdir/subdir/bin:$HOME/workdir/subdir/bin2:$HOME/workdir/bin:$HOME/workdir/bin2:$MISE_DATA_DIR/installs/dummy/2.0.0/bin:$MISE_DATA_DIR/installs/pitchfork/0.1.5:$MISE_DATA_DIR/installs/jq/1.7.1:$PATH'\"\nassert \"mise hook-env | grep PATH | tail -n1\" \"export PATH='$HOME/workdir/subdir/bin:$HOME/workdir/subdir/bin2:$HOME/workdir/bin:$HOME/workdir/bin2:$MISE_DATA_DIR/installs/dummy/2.0.0/bin:$MISE_DATA_DIR/installs/pitchfork/0.1.5:$MISE_DATA_DIR/installs/jq/1.7.1:$PATH'\"\n"
  },
  {
    "path": "e2e/tools/test_runtime_symlinks",
    "content": "#!/usr/bin/env bash\n\nmise i dummy@1.0.1 dummy@1.0.2 dummy@1.10.0 dummy@2.0.0 dummy@2.1.0\nassert \"ls -l $MISE_DATA_DIR/installs/dummy | grep '\\->' | awk '{print \\$(NF-2),\\$(NF)}'\" \"1 ./1.10.0\n1.0 ./1.0.2\n1.10 ./1.10.0\n2 ./2.1.0\n2.0 ./2.0.0\n2.1 ./2.1.0\nlatest ./2.1.0\"\n"
  },
  {
    "path": "e2e-win/7z.Tests.ps1",
    "content": "Describe '7z' {\n    BeforeAll {\n        $cfg = \".\\mise.local.toml\"\n        $content = @\"\n[tools]\n\"github:ip7z/7zip\" = { version = \"25.00\", asset_pattern = \"*-extra.7z\" }\n\"@\n        $content | Out-File $cfg\n        Get-Content $cfg\n    }\n\n    AfterAll {\n        Remove-Item $cfg -ErrorAction Ignore\n    }\n\n    It 'executes 7za 25.00' {\n        mise install\n        mise x github:ip7z/7zip -- 7za | Out-String | Should -Match \"7-Zip \\(a\\) 25\\.00\"\n    }\n}\n\nDescribe '7z-strip-components' {\n    BeforeAll {\n        $cfg = \".\\mise.local.toml\"\n        $content = @\"\n[tools]\n\"http:ip7z/7zip\" = { version = \"25.00\", url = \"https://mise.jdx.dev/test-fixtures/7z2500-extra.7z\" }\n\"@\n        $content | Out-File $cfg\n        Get-Content $cfg\n    }\n\n    AfterAll {\n        Remove-Item $cfg -ErrorAction Ignore\n    }\n\n    It 'executes 7za 25.00' {\n        mise install\n        mise x http:ip7z/7zip -- 7za | Out-String | Should -Match \"7-Zip \\(a\\) 25\\.00\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/backend/aqua_bin_path.Tests.ps1",
    "content": "Describe 'backend_aqua' {\n    It 'executes tree-sitter via aqua backend on Windows' {\n        mise x aqua:tree-sitter/tree-sitter -- tree-sitter --version | Should -BeLike \"tree-sitter *\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/backend/github_docker_compose.Tests.ps1",
    "content": "Describe 'backend_github' {\n    BeforeAll {\n        @\"\n[tools]\n\"github:docker/compose\" = \"2.29.1\"\n\"@ | Set-Content -Path \"mise.toml\"\n    }\n\n    AfterAll {\n        Remove-Item \"mise.toml\" -ErrorAction SilentlyContinue\n    }\n\n    It 'installs and executes docker-compose via github backend' {\n        mise install -f github:docker/compose\n        mise exec github:docker/compose -- docker-compose version | Should -BeLike \"Docker Compose version *\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/backend/http_binary_clean.Tests.ps1",
    "content": "Describe 'backend_http' {\n    BeforeAll {\n        $env:MISE_EXPERIMENTAL = \"1\"\n        @\"\n[tools]\n\"http:docker-compose\" = { version = \"2.29.1\", url = \"https://github.com/docker/compose/releases/download/v{version}/docker-compose-windows-x86_64.exe\" }\n\"@ | Set-Content -Path \"mise.toml\"\n    }\n\n    AfterAll {\n        Remove-Item -Path Env:\\MISE_EXPERIMENTAL -ErrorAction SilentlyContinue\n        Remove-Item \"mise.toml\" -ErrorAction SilentlyContinue\n    }\n\n    It 'installs and executes docker-compose via http backend with binary cleaning' {\n        mise install -f http:docker-compose\n        mise exec http:docker-compose -- docker-compose version | Should -BeLike \"Docker Compose version *\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/conda.Tests.ps1",
    "content": "Describe 'conda' {\n    It 'executes ripgrep via conda backend' {\n        mise x conda:ripgrep@14.1.0 -- rg --version | Out-String | Should -Match \"ripgrep 14\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/config_ceiling_paths.Tests.ps1",
    "content": "Describe 'config_ceiling_paths' {\n    BeforeAll {\n        # Create test directory structure\n        $TestRoot = Get-Location\n        $ParentDir = Join-Path $TestRoot \"parent\"\n        $ChildDir = Join-Path $ParentDir \"child\"\n        $GrandchildDir = Join-Path $ChildDir \"grandchild\"\n\n        New-Item -ItemType Directory -Path $ParentDir -Force | Out-Null\n        New-Item -ItemType Directory -Path $ChildDir -Force | Out-Null\n        New-Item -ItemType Directory -Path $GrandchildDir -Force | Out-Null\n\n        # Create config files at different levels\n        $ParentConfig = Join-Path $ParentDir \".mise.toml\"\n        $ChildConfig = Join-Path $ChildDir \".mise.toml\"\n        $GrandchildConfig = Join-Path $GrandchildDir \".mise.toml\"\n\n        @\"\n[env]\nPARENT = \"true\"\n\"@ | Out-File $ParentConfig\n\n        @\"\n[env]\nCHILD = \"true\"\n\"@ | Out-File $ChildConfig\n\n        @\"\n[env]\nGRANDCHILD = \"true\"\n\"@ | Out-File $GrandchildConfig\n\n        # Change to grandchild directory for tests\n        Set-Location $GrandchildDir\n    }\n\n    AfterAll {\n        # Clean up test directories\n        Set-Location $TestRoot\n        Remove-Item -Path (Join-Path $TestRoot \"parent\") -Recurse -Force -ErrorAction Ignore\n        Remove-Item Env:MISE_CEILING_PATHS -ErrorAction Ignore\n    }\n\n    It 'finds all configs without ceiling paths' {\n        Remove-Item Env:MISE_CEILING_PATHS -ErrorAction Ignore\n        $output = mise env | Out-String\n        $output | Should -Match \"export GRANDCHILD=true\"\n        $output | Should -Match \"export CHILD=true\"\n        $output | Should -Match \"export PARENT=true\"\n    }\n\n    It 'respects ceiling path at child directory' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"parent\\child\"\n        $output = mise env | Out-String\n        $output | Should -Match \"export GRANDCHILD=true\"\n        $output | Should -Not -Match \"export CHILD=true\"\n        $output | Should -Not -Match \"export PARENT=true\"\n    }\n\n    It 'respects ceiling path at grandchild directory' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"parent\\child\\grandchild\"\n        $output = mise env | Out-String\n        $output | Should -Not -Match \"export GRANDCHILD=true\"\n        $output | Should -Not -Match \"export CHILD=true\"\n        $output | Should -Not -Match \"export PARENT=true\"\n    }\n\n    It 'handles multiple ceiling paths' {\n        $ChildPath = Join-Path $TestRoot \"parent\\child\"\n        $ParentPath = Join-Path $TestRoot \"parent\"\n        $env:MISE_CEILING_PATHS = \"$ChildPath;$ParentPath\"\n        $output = mise env | Out-String\n        $output | Should -Match \"export GRANDCHILD=true\"\n        $output | Should -Not -Match \"export CHILD=true\"\n        $output | Should -Not -Match \"export PARENT=true\"\n    }\n\n    It 'handles non-existent ceiling path' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"nonexistent\"\n        $output = mise env | Out-String\n        $output | Should -Match \"export GRANDCHILD=true\"\n        $output | Should -Match \"export CHILD=true\"\n        $output | Should -Match \"export PARENT=true\"\n    }\n}"
  },
  {
    "path": "e2e-win/go.Tests.ps1",
    "content": "\nDescribe 'go' {\n    It 'executes go 1.23.3' {\n        mise x go@1.23.3 -- where go\n        mise x go@1.23.3 -- go version | Should -BeLike \"go version go1.23.3 windows/*\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/helm.Tests.ps1",
    "content": "Describe 'helm' {\n    It 'installs helm 3.14.3' {\n        mise x helm@3.14.3 -- helm version --short | Should -BeLike \"v3.14.3*\"\n    }\n} \n"
  },
  {
    "path": "e2e-win/java.Tests.ps1",
    "content": "\nDescribe 'java' {\n    It 'executes java@temurin-21' {\n        mise x java@temurin-21 -- java --version | Select -Last 1 | Should -BeLike '*Temurin-21.*'\n    }\n}\n"
  },
  {
    "path": "e2e-win/node.Tests.ps1",
    "content": "\nDescribe 'node' {\n    It 'executes node 22.0.0' {\n        mise x node@22.0.0 -- node -v | Should -be \"v22.0.0\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/npm_backend.Tests.ps1",
    "content": "Describe 'npm_backend' {\n    It 'installs npm:prettier 3.6.2 with npm' {\n        mise x node@24.4.1 npm:prettier@3.6.2 -- prettier --version | Should -be \"3.6.2\"\n    }\n    It 'installs npm:cowsay 1.6.0 with bun' {\n        $env:MISE_NPM_BUN = \"true\"\n        mise x node@24.4.1 bun@1.2.19 npm:cowsay@1.6.0 -- cowsay --version | Should -be \"1.6.0\"\n        Remove-Item Env:MISE_NPM_BUN\n    }\n}\n"
  },
  {
    "path": "e2e-win/path.Tests.ps1",
    "content": "Describe 'path-env' {\n    It 'mise x produces the same path environment for successive runs' {\n        $paths = 1..10 | ForEach-Object {\n            $output = \"$(mise x -- cmd.exe /d /s /c \"echo %path%\")\".Trim()\n            $output\n        }\n        $paths | Should -HaveCount 10\n        $paths | ForEach-Object { \n            $_ | Should -Not -Match \"ECHO is on.\"\n            $_.Length | Should -BeExactly $paths[0].Length\n            $_ | Should -BeExactly $paths[0]\n        }\n    }\n}\n"
  },
  {
    "path": "e2e-win/prepare.Tests.ps1",
    "content": "\nDescribe 'prepare' {\n    BeforeAll {\n        $script:originalPath = Get-Location\n        # Set experimental since prepare requires it\n        $env:MISE_EXPERIMENTAL = \"1\"\n    }\n\n    AfterAll {\n        Set-Location $script:originalPath\n        Remove-Item -Path Env:\\MISE_TRUSTED_CONFIG_PATHS -ErrorAction SilentlyContinue\n        Remove-Item -Path Env:\\MISE_EXPERIMENTAL -ErrorAction SilentlyContinue\n    }\n\n    It 'lists no providers when no lockfiles exist' {\n        # Create unique test directory to avoid config inheritance from repo root\n        $testDir = Join-Path $TestDrive ([System.Guid]::NewGuid().ToString())\n        New-Item -ItemType Directory -Path $testDir | Out-Null\n        Set-Location $testDir\n        $env:MISE_TRUSTED_CONFIG_PATHS = $testDir\n\n        try {\n            mise prepare --list | Should -Match 'No prepare providers found'\n        } finally {\n            Set-Location $script:originalPath\n            Remove-Item -Path $testDir -Recurse -Force -ErrorAction SilentlyContinue\n        }\n    }\n\n    # Note: Provider detection tests are skipped on Windows due to config discovery\n    # complexities. The prepare functionality is fully tested on Linux e2e tests.\n    # See e2e/cli/test_prepare for comprehensive coverage.\n}\n"
  },
  {
    "path": "e2e-win/python.Tests.ps1",
    "content": "\nDescribe 'python' {\n    It 'executes python 3.12.0' {\n        mise x python@3.12.0 -- where python\n        mise x python@3.12.0 -- python --version | Should -Be \"Python 3.12.0\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/run.ps1",
    "content": "param(\n    [string]$TestName\n)\n\n$config = New-PesterConfiguration\n$config.Run.Path = $PSScriptRoot\n$config.Run.Exit = $true\n$config.TestResult.Enabled = $true\n\nif ($TestName) {\n    $config.Filter.FullName = $TestName\n}\n\n$env:PATH = \"$PSScriptRoot\\..\\target\\debug;$env:PATH\"\n\nInvoke-Pester -Configuration $config\n"
  },
  {
    "path": "e2e-win/rust.Tests.ps1",
    "content": "\nDescribe 'rust' {\n    It 'installs rust 1.83.0' {\n        $env:MISE_CARGO_HOME = \"%TEMP%\\.cargo\"\n        $env:MISE_RUSTUP_HOME = \"%TEMP%\\.rustup\"\n        mise x rust@1.83.0 -- rustc -V | Should -BeLike \"rustc 1.83.0*\"\n        Remove-Item Env:MISE_CARGO_HOME\n        Remove-Item Env:MISE_RUSTUP_HOME\n    }\n\n    It 'executes rust 1.82.0' {\n        mise x rust@1.82.0 -- rustc -V | Should -BeLike \"rustc 1.82.0*\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/shim.Tests.ps1",
    "content": "Describe 'shim_mode' {\n\n    BeforeAll {\n        function changeShimMode {\n            param (\n                [string]$mode\n            )\n\n            mise settings windows_shim_mode $mode\n            mise reshim --force\n        }\n\n        $shimPath = Join-Path -Path $env:MISE_DATA_DIR -ChildPath \"shims\"\n    }\n\n    AfterAll {\n        mise settings unset windows_shim_mode\n    }\n\n    It 'run on symlink' {\n        changeShimMode \"symlink\"\n\n        mise x go@1.23.3 -- where go\n        mise x go@1.23.3 -- go version | Should -BeLike \"go version go1.23.3 windows/*\"\n        \n        (Get-Item -Path (Join-Path -Path $shimPath -ChildPath go.exe)).LinkType | Should -Be \"SymbolicLink\"\n    }\n\n    It 'run on file' {\n        changeShimMode \"file\"\n\n        mise x go@1.23.3 -- where go\n        mise x go@1.23.3 -- go version | Should -BeLike \"go version go1.23.3 windows/*\"\n\n        (Get-Item -Path  (Join-Path -Path $shimPath -ChildPath go.cmd)).LinkType | Should -Be $null\n    }\n\n    It 'run on exe' {\n        changeShimMode \"exe\"\n\n        $wherePath = mise x go@1.23.3 -- where go\n        $LASTEXITCODE | Should -Be 0\n        $wherePath | Should -BeLike \"*go.exe\"\n        mise x go@1.23.3 -- go version | Should -BeLike \"go version go1.23.3 windows/*\"\n\n        $goShim = Get-Item -Path (Join-Path -Path $shimPath -ChildPath go.exe)\n        $goShim.LinkType | Should -Be $null\n        $goShim.Length | Should -BeGreaterThan 0\n    }\n\n    It 'run on hardlink' {\n        mise settings windows_shim_mode \"hardlink\"\n\n        # make mise is on same filesystem\n        $misePath = (Get-Command -Type Application mise -all | Select-Object -First 1).Source\n        $binPath = (Join-Path -Path $env:MISE_DATA_DIR -ChildPath \"bin\")\n        $newMisePath = (Join-Path -Path $binPath -ChildPath \"mise.exe\")\n        New-Item -ItemType Directory -Path $binPath -Force\n        Copy-Item  $misePath $newMisePath\n\n        &$newMisePath reshim --force\n\n        &$newMisePath x go@1.23.3 -- where go\n        &$newMisePath x go@1.23.3 -- go version | Should -BeLike \"go version go1.23.3 windows/*\"\n\n        (Get-Item -Path (Join-Path -Path $shimPath -ChildPath go.exe)).LinkType | Should -Be \"HardLink\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/shim_recursion.Tests.ps1",
    "content": "Describe 'shim_exec_recursion' {\n    # Regression test: when not_found_auto_install preserves shims in PATH,\n    # `mise x -- tool` should not resolve \"tool\" to a shim in the shims\n    # directory, which would cause infinite process spawning on Windows.\n    #\n    # We verify this by checking that which::which_in resolves the real tool\n    # binary (in toolDir) rather than the shim (in shimPath), even when the\n    # shims directory appears before toolDir in PATH.\n\n    BeforeAll {\n        $script:originalPath = Get-Location\n        Set-Location TestDrive:\n        $env:MISE_TRUSTED_CONFIG_PATHS = $TestDrive\n\n        $script:shimPath = Join-Path -Path $env:MISE_DATA_DIR -ChildPath \"shims\"\n\n        # Create a fake \"mytool\" binary that echoes a marker\n        $script:toolDir = Join-Path $TestDrive \"toolbin\"\n        New-Item -ItemType Directory -Path $script:toolDir -Force | Out-Null\n        @'\n@echo off\necho REAL_TOOL_OUTPUT\n'@ | Out-File -FilePath (Join-Path $script:toolDir \"mytool.cmd\") -Encoding ascii -NoNewline\n\n        # Create a shim script for mytool in the shims directory (mimics \"file\" mode).\n        # If the fix fails and exec resolves to this shim, the `where` command below\n        # would show the shim path instead of the real tool path.\n        New-Item -ItemType Directory -Path $script:shimPath -Force | Out-Null\n        @'\n@echo off\necho SHIM_NOT_REAL\n'@ | Out-File -FilePath (Join-Path $script:shimPath \"mytool.cmd\") -Encoding ascii -NoNewline\n\n        # Put shims BEFORE toolDir in PATH (the problematic ordering).\n        # The fix should strip shims from the exec lookup path so the real\n        # tool is resolved instead of the shim.\n        $env:PATH = \"$($script:shimPath);$($script:toolDir);$env:PATH\"\n    }\n\n    AfterAll {\n        Remove-Item -Path (Join-Path $script:shimPath \"mytool.cmd\") -ErrorAction SilentlyContinue\n        Remove-Item -Path $script:toolDir -Recurse -ErrorAction SilentlyContinue\n        Set-Location $script:originalPath\n        Remove-Item -Path Env:\\MISE_TRUSTED_CONFIG_PATHS -ErrorAction SilentlyContinue\n    }\n\n    It 'mise x resolves real tool, not shim' {\n        # Without the fix, which::which_in would resolve to the shim.\n        # With the fix, shims are stripped from the lookup path and the\n        # real tool in $toolDir is found instead.\n        $result = mise x -- mytool\n        $LASTEXITCODE | Should -Be 0\n        $result | Should -Contain \"REAL_TOOL_OUTPUT\"\n        $result | Should -Not -Contain \"SHIM_NOT_REAL\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/symlink.Tests.ps1",
    "content": "Describe 'windows runtime symlink' {\n\n    BeforeAll {\n        $cfg = \".\\mise.local.toml\"\n        $tool = \"yq\"\n\n        $content = @\"\n[tools]\n$tool = \"latest\"\n\"@\n        $content | Out-File $cfg\n        Get-Content $cfg\n    }\n\n    AfterAll {\n        Remove-Item $cfg -ErrorAction Ignore\n    }\n\n    It 'version is correct, not latest' {\n        mise install yq@4.45.4\n\n        # correct output\n        # mise/2025.5.15/bin/mise ls yq\n        # Tool  Version  Source                                        Requested\n        # yq    4.45.4   D:\\Users\\qianlongzt\\.config\\mise\\config.toml  latest\n\n        # wrong output\n        # mise/2025.5.16/bin/mise ls yq\n        # Tool  Version  Source                                        Requested\n        # yq    latest   D:\\Users\\qianlongzt\\.config\\mise\\config.toml  latest\n        # yq    4.45.4\n\n        # https://github.com/jdx/mise/discussions/5254\n\n        $output = mise ls --json yq\n        $output | jq '.[] | select(.source ) | .version' | Should -Be '\"4.45.4\"'\n        $output | jq '.[] | select(.version == \"latest\" ) | .version' | Should -Be $null\n    }\n}\n"
  },
  {
    "path": "e2e-win/task.Tests.ps1",
    "content": "\nDescribe 'task' {\n    BeforeAll {\n        $originalPath = Get-Location\n        Set-Location TestDrive:\n        # Trust the TestDrive config path - use $TestDrive for physical path, not PSDrive path\n        $env:MISE_TRUSTED_CONFIG_PATHS = $TestDrive\n\n        # Create mise.toml that includes tasks directory\n        @'\n[task_config]\nincludes = [\"tasks\"]\n'@ | Out-File -FilePath \"mise.toml\" -Encoding utf8NoBOM\n\n        # Create tasks directory\n        New-Item -ItemType Directory -Path \"tasks\" -Force | Out-Null\n\n        # Create filetask.bat\n        @'\n@echo off\necho mytask\n'@ | Out-File -FilePath \"tasks\\filetask.bat\" -Encoding ascii -NoNewline\n\n        # Create filetask (no extension) for MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS test\n        @'\n@echo off\necho mytask\n'@ | Out-File -FilePath \"tasks\\filetask\" -Encoding ascii -NoNewline\n\n        # Create testtask.ps1 for pwsh test\n        @'\nWrite-Output \"windows\"\n'@ | Out-File -FilePath \"tasks\\testtask.ps1\" -Encoding utf8NoBOM\n    }\n\n    AfterAll {\n        Set-Location $originalPath\n        Remove-Item -Path Env:\\MISE_TRUSTED_CONFIG_PATHS -ErrorAction SilentlyContinue\n    }\n\n    BeforeEach {\n        Remove-Item -Path Env:\\MISE_WINDOWS_EXECUTABLE_EXTENSIONS -ErrorAction SilentlyContinue\n        Remove-Item -Path Env:\\MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS -ErrorAction SilentlyContinue\n        Remove-Item -Path Env:\\MISE_USE_FILE_SHELL_FOR_EXECUTABLE_TASKS -ErrorAction SilentlyContinue\n    }\n\n    It 'executes a task' {\n        mise run filetask.bat | Select -Last 1 | Should -Be 'mytask'\n    }\n\n    It 'executes a task without extension' {\n        $env:MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS = \"bat\"\n        mise run filetask | Select -Last 1 | Should -Be 'mytask'\n    }\n\n    It 'executes a shebang task with bash' {\n        # Create a file task with a bash shebang and no extension\n        @\"\n#!/usr/bin/env bash\necho \"from-bash\"\n\"@ | Out-File -FilePath \"tasks\\shebangtask\" -Encoding utf8NoBOM -NoNewline\n        mise run shebangtask | Select -Last 1 | Should -Be 'from-bash'\n    }\n\n    It 'executes a task in pwsh' {\n        $env:MISE_WINDOWS_EXECUTABLE_EXTENSIONS = \"ps1\"\n        $env:MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS = \"pwsh.exe\"\n        $env:MISE_USE_FILE_SHELL_FOR_EXECUTABLE_TASKS = \"true\"\n        mise run testtask | Select -Last 1 | Should -Be 'windows'\n    }\n}\n"
  },
  {
    "path": "e2e-win/task_args.Tests.ps1",
    "content": "Describe 'task argument quoting' {\n    BeforeAll {\n        $originalPath = Get-Location\n        Set-Location TestDrive:\n\n        @'\n[tasks.type]\nrun = \"type\"\n'@ | Out-File -FilePath \"mise.toml\" -Encoding utf8\n\n        # Create directory and file with spaces\n        New-Item -ItemType Directory -Path \"test dir\" -Force | Out-Null\n        Set-Content -Path \"test dir\\file.txt\" -Value \"test content\"\n    }\n\n    AfterAll {\n        Remove-Item -Path \"test dir\" -Recurse -Force -ErrorAction SilentlyContinue\n        Remove-Item -Path \"mise.toml\" -Force -ErrorAction SilentlyContinue\n        Set-Location $originalPath\n    }\n\n    It 'handles file path with spaces' {\n        $output = mise run type \".\\test dir\\file.txt\"\n        $output | Should -Match \"test content\"\n    }\n}\n"
  },
  {
    "path": "e2e-win/tasks_ceiling_paths.Tests.ps1",
    "content": "Describe 'tasks_ceiling_paths' {\n    BeforeAll {\n        # Create test directory structure\n        $TestRoot = Get-Location\n        $ParentDir = Join-Path $TestRoot \"parent\"\n        $ChildDir = Join-Path $ParentDir \"child\"\n        $GrandchildDir = Join-Path $ChildDir \"grandchild\"\n\n        New-Item -ItemType Directory -Path $ParentDir -Force | Out-Null\n        New-Item -ItemType Directory -Path $ChildDir -Force | Out-Null\n        New-Item -ItemType Directory -Path $GrandchildDir -Force | Out-Null\n\n        # Create task directories\n        $ParentTasks = Join-Path $ParentDir \"mise-tasks\"\n        $ChildTasks = Join-Path $ChildDir \"mise-tasks\"\n        $GrandchildTasks = Join-Path $GrandchildDir \"mise-tasks\"\n\n        New-Item -ItemType Directory -Path $ParentTasks -Force | Out-Null\n        New-Item -ItemType Directory -Path $ChildTasks -Force | Out-Null\n        New-Item -ItemType Directory -Path $GrandchildTasks -Force | Out-Null\n\n        # Create task files\n        $ParentTask = Join-Path $ParentTasks \"task-parent.ps1\"\n        $ChildTask = Join-Path $ChildTasks \"task-child.ps1\"\n        $GrandchildTask = Join-Path $GrandchildTasks \"task-grandchild.ps1\"\n\n        @\"\n#!/usr/bin/env pwsh\nWrite-Output \"parent\"\n\"@ | Out-File $ParentTask\n\n        @\"\n#!/usr/bin/env pwsh\nWrite-Output \"child\"\n\"@ | Out-File $ChildTask\n\n        @\"\n#!/usr/bin/env pwsh\nWrite-Output \"grandchild\"\n\"@ | Out-File $GrandchildTask\n\n        # Change to grandchild directory for tests\n        Set-Location $GrandchildDir\n    }\n\n    AfterAll {\n        # Clean up test directories\n        Set-Location $TestRoot\n        Remove-Item -Path (Join-Path $TestRoot \"parent\") -Recurse -Force -ErrorAction Ignore\n        Remove-Item Env:MISE_CEILING_PATHS -ErrorAction Ignore\n    }\n\n    It 'finds all tasks without ceiling paths' {\n        Remove-Item Env:MISE_CEILING_PATHS -ErrorAction Ignore\n        $output = mise tasks | Out-String\n        $output | Should -Match \"task-grandchild\"\n        $output | Should -Match \"task-child\"\n        $output | Should -Match \"task-parent\"\n    }\n\n    It 'respects ceiling path at child directory' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"parent\\child\"\n        $output = mise tasks | Out-String\n        $output | Should -Match \"task-grandchild\"\n        $output | Should -Not -Match \"task-child\"\n        $output | Should -Not -Match \"task-parent\"\n    }\n\n    It 'respects ceiling path at grandchild directory' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"parent\\child\\grandchild\"\n        $output = mise tasks | Out-String\n        $output | Should -Not -Match \"task-grandchild\"\n        $output | Should -Not -Match \"task-child\"\n        $output | Should -Not -Match \"task-parent\"\n    }\n\n    It 'handles multiple ceiling paths' {\n        $ChildPath = Join-Path $TestRoot \"parent\\child\"\n        $ParentPath = Join-Path $TestRoot \"parent\"\n        $env:MISE_CEILING_PATHS = \"$ChildPath;$ParentPath\"\n        $output = mise tasks | Out-String\n        $output | Should -Match \"task-grandchild\"\n        $output | Should -Not -Match \"task-child\"\n        $output | Should -Not -Match \"task-parent\"\n    }\n\n    It 'handles non-existent ceiling path' {\n        $env:MISE_CEILING_PATHS = Join-Path $TestRoot \"nonexistent\"\n        $output = mise tasks | Out-String\n        $output | Should -Match \"task-grandchild\"\n        $output | Should -Match \"task-child\"\n        $output | Should -Match \"task-parent\"\n    }\n}"
  },
  {
    "path": "e2e-win/uv.Tests.ps1",
    "content": "\nDescribe 'uv' {\n  BeforeEach {\n    $originalPath = Get-Location\n    Set-Location TestDrive:\n  }\n\n  AfterEach {\n    mise trust --untrust --yes .mise.toml\n    Set-Location $originalPath | Out-Null\n  }\n\n  It 'executes from the venv Scripts directory' {\n    @(\n    '[env._.python]',\n    'venv = {path = \"my_venv\", create=true}',\n    '[tools]',\n    'python = \"3.12.3\"',\n    'uv = \"0.8.21\"',\n    '[settings]',\n    'python.uv_venv_auto = \"source\"'\n    ) | Set-Content .mise.toml\n    mise trust --yes .mise.toml\n\n    # Define the character set\n    $chars = (48..57) + (65..90) + (97..122) # 0-9, A-Z, a-z\n\n    # Generate a random string of a specific length (e.g., 10 characters)\n    $randomString = -join ($chars | Get-Random -Count 10 | ForEach-Object {[char]$_})\n\n    mise x -- uv init .\n    mise x -- uv add --active --link-mode=copy cowsay\n\n    mise i\n\n    mise x -- cowsay -t $randomString | Out-String | Should -BeLikeExactly \"*$randomString*\"\n\n    mise x -- python -c \"import sys; print(sys.executable)\" | Should -BeLikeExactly \"*my_venv\\Scripts\\python.exe\"\n  }\n}\n"
  },
  {
    "path": "e2e-win/vfox.Tests.ps1",
    "content": "Describe 'vfox' {\n    BeforeAll {\n        # vfox-npm is a custom backend which requires experimental mode\n        $env:MISE_EXPERIMENTAL = \"1\"\n    }\n\n    It 'executes vfox backend command execution' {\n        # Test that vfox backend can execute commands cross-platform\n        # This tests the cmd.exec function that was fixed for Windows compatibility\n        $result = mise x vfox:version-fox/vfox-nodejs -- node -v\n        $result | Should -Not -BeNullOrEmpty\n        $result | Should -Match \"v\\d+\\.\\d+\\.\\d+\"\n    }\n\n    It 'installs and uses vfox plugin' {\n        # Test installing a vfox plugin and using it\n        $pluginName = \"vfox-test-plugin\"\n        \n        # Clean up any existing test plugin\n        mise plugins uninstall $pluginName -ErrorAction SilentlyContinue\n        \n        # Test that we can list available vfox plugins\n        $plugins = mise registry | Select-String \"vfox:\"\n        $plugins | Should -Not -BeNullOrEmpty\n        \n        # Test installing a specific version using a working vfox plugin\n        $result = mise install vfox:version-fox/vfox-nodejs@24.4.0\n        # The install result might be empty but the tool should still work\n        \n        # Test using the installed version\n        $version = mise x vfox:version-fox/vfox-nodejs@24.4.0 -- node -v\n        $version | Should -Be \"v24.4.0\"\n    }\n\n    It 'handles vfox plugin:tool format' {\n        # Test the plugin:tool format that uses backend methods\n        $result = mise x vfox:version-fox/vfox-nodejs -- node --version\n        $result | Should -Not -BeNullOrEmpty\n        $result | Should -Match \"v\\d+\\.\\d+\\.\\d+\"\n    }\n\n    It 'installs and uses vfox-npm plugin' {\n        # Test installing and using the vfox-npm plugin\n        # First, ensure the vfox-npm plugin is installed\n        mise plugin install -f vfox-npm https://github.com/jdx/vfox-npm\n        \n        # Test installing a specific npm tool through vfox-npm\n        mise install vfox-npm:prettier@3.0.0 --debug\n        # The install result might be empty but the tool should still work\n        \n        # Test using the installed npm tool\n        $which = mise where vfox-npm:prettier@3.0.0\n        $which | Should -Match \"vfox-npm-prettier\"\n        $version = mise x vfox-npm:prettier@3.0.0 -- prettier --version\n        $version | Should -Be \"3.0.0\"\n        \n        # Test that the tool is available in the current environment\n        $prettierVersion = mise x vfox-npm:prettier -- prettier --version\n        $prettierVersion | Should -Not -BeNullOrEmpty\n        $prettierVersion | Should -Match \"\\d+\\.\\d+\\.\\d+\"\n    }\n} \n"
  },
  {
    "path": "e2e-win/zig.Tests.ps1",
    "content": "Describe 'zig' {\n    It 'executes zig 0.13.0' {\n        mise x zig@0.13.0 -- zig version | Should -be \"0.13.0\"\n    }\n\n    It 'executes zig 2024.11.0-mach' {\n        mise x zig@2024.11.0-mach -- zig version | Should -be \"0.14.0-dev.2577+271452d22\"\n    }\n}\n"
  },
  {
    "path": "flake.nix",
    "content": "{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n    flake-utils.url = \"github:numtide/flake-utils\";\n  };\n\n  outputs = { self, nixpkgs, flake-utils }:\n    {\n      overlay = final: prev: {\n        mise = prev.callPackage ./default.nix { };\n      };\n    } // flake-utils.lib.eachDefaultSystem(system:\n      let\n        pkgs = import nixpkgs { inherit system; };\n        mise = pkgs.callPackage ./default.nix { };\n      in\n        {\n          packages = {\n            inherit mise;\n            default = mise;\n          };\n\n          devShells.default = pkgs.mkShell {\n            name = \"mise-develop\";\n\n            inputsFrom = [ mise ];\n\n            nativeBuildInputs = with pkgs; [\n              just\n              clippy\n              rustfmt\n              shellcheck\n              shfmt\n              nodejs\n              cargo-release\n              cargo-insta\n            ];\n          };\n        }\n    );\n}\n"
  },
  {
    "path": "hk.pkl",
    "content": "amends \"package://github.com/jdx/hk/releases/download/v1.18.1/hk@1.18.1#/Config.pkl\"\nimport \"package://github.com/jdx/hk/releases/download/v1.18.1/hk@1.18.1#/Builtins.pkl\"\n\nlocal bash_glob = List(\"*.sh\", \"xtasks/**\", \"scripts/**\", \"e2e/**\")\nlocal bash_exclude = List(\"*.ps1\", \"**/*.fish\", \"*.ts\", \"*.js\", \"*.json\", \"*.bat\", \"**/.*\", \"src/assets/bash_zsh_support/**\", \"e2e/shell/xonsh_script\", \"**/*.py\", \"**/*.xsh\")\nlocal linters = new Mapping<String, Step> {\n    // uses builtin prettier linter config\n    [\"prettier\"] = (Builtins.prettier) {\n      batch = false\n      exclude = \"crates/aqua-registry/aqua-registry/**\"\n    }\n    //[\"clippy\"] = (Builtins.cargo_clippy) {\n    //  check = \"cargo clippy --manifest-path {{workspace_indicator}} --all-features -- -Dwarnings\"\n    //  fix = \"cargo clippy --manifest-path {{workspace_indicator}} --all-features --fix --allow-dirty --allow-staged -- -Dwarnings\"\n    //}\n    [\"cargo-fmt\"] {\n      glob = List(\"**/*.rs\")\n      check = \"cargo fmt --all -- --check\"\n      fix = \"cargo fmt --all\"\n    }\n    [\"cargo-check\"] = (Builtins.cargo_check) {\n      check = \"cargo check --all-features\"\n    }\n    [\"shellcheck\"] = (Builtins.shellcheck) {\n      glob = bash_glob\n      exclude = bash_exclude\n      batch = true\n      check = \"shellcheck -x {{ files }}\"\n    }\n    [\"shfmt\"] = (Builtins.shfmt) {\n      check_list_files = \"\"\"\nfiles=$(shfmt -l -s {{ files }})\nif [ -n \"$files\" ]; then\n  echo \"$files\"\n  exit 1\nfi\n\"\"\"\n      fix = \"shfmt -w -s {{ files }}\"\n      glob = bash_glob\n      exclude = bash_exclude\n    }\n\n    // uses custom pkl linter config\n    [\"pkl\"] {\n        glob = \"**/*.pkl\"\n        check = \"pkl eval {{files}} >/dev/null\"\n    }\n\n    // uses taplo for TOML formatting and validation\n    [\"taplo\"] {\n        glob = List(\"**/*.toml\")\n        exclude = List(\"docs/registry/\") // exclude docs/registry/ symlink\n        check = \"taplo fmt --check {{files}} && taplo check {{files}}\"\n        fix = \"taplo fmt {{files}} && taplo check {{files}}\"\n    }\n\n    // uses lua-language-server to check vfox test plugin Lua files\n    // excludes embedded-plugins/ which are vendored from external repos\n    [\"lua-check\"] {\n        glob = List(\"crates/vfox/plugins/**/*.lua\")\n        check = \"lua-language-server --check crates/vfox/plugins/\"\n    }\n    [\"stylua\"] {\n        glob = List(\"crates/vfox/plugins/**/*.lua\")\n        check = \"stylua --check crates/vfox/plugins/\"\n        fix = \"stylua crates/vfox/plugins/\"\n    }\n    [\"actionlint\"] {\n        glob = List(\".github/workflows/*.yml\")\n        check = \"SHELLCHECK_OPTS='--exclude=SC1090 --exclude=SC2046 --exclude=SC2086 --exclude=SC2129' actionlint\"\n    }\n    [\"markdownlint\"] {\n        glob = List(\"**/*.md\")\n        check = \"markdownlint {{ files }}\"\n        fix = \"markdownlint --fix {{ files }}\"\n    }\n    [\"schema\"] {\n        glob = List(\"schema/**/*.json\")\n        check = \"ajv compile -s schema/mise.json --spec=draft2019 --strict-schema=true && ajv compile -s schema/mise-task.json --spec=draft2019 --strict-schema=true && ajv compile -s schema/mise.plugin.json --spec=draft2020 --strict-schema=true\"\n    }\n}\n\nhooks {\n    [\"fix\"] {\n        fix = true\n        steps = linters\n    }\n    [\"check\"] {\n        steps = linters\n    }\n}\n"
  },
  {
    "path": "llms.txt",
    "content": "# mise (mise-en-place) - Development Environment Tool\n\n## What is mise?\n\nmise (pronounced \"meez\") is a development environment setup tool that manages:\n1. **Dev Tools**: Version management for programming languages and tools (like asdf, nvm, pyenv, rbenv)\n2. **Environments**: Environment variable management (can replace direnv)\n3. **Tasks**: Task runner for project automation (can replace make, npm scripts)\n\nmise supports hundreds of development tools and can automatically switch between different versions based on your project directory.\n\n## Installation\n\n### Quick Install (Linux/macOS)\n```bash\ncurl https://mise.run | sh\n```\n\n### Other Methods\n- **Homebrew**: `brew install mise`\n- **Windows**: `winget install jdx.mise` or `scoop install mise`\n- **Debian/Ubuntu**: Available via apt repository\n- **Fedora**: Available via dnf repository\n\n## Core Configuration\n\n### mise.toml\nThe main configuration file for mise. Can be named:\n- `mise.toml` (project-specific)\n- `mise.local.toml` (local, not committed to git)\n- `~/.config/mise/config.toml` (global)\n\nExample `mise.toml`:\n```toml\n[tools]\nnode = \"20\"\npython = \"3.11\"\nterraform = \"1.0.0\"\ngo = \"latest\"\n\n[env]\nNODE_ENV = \"development\"\nDATABASE_URL = \"postgresql://localhost/myapp\"\n\n[tasks.test]\nrun = \"npm test\"\ndescription = \"Run tests\"\n\n[tasks.build]\nrun = \"npm run build\"\ndeps = [\"test\"]\n```\n\n### .tool-versions (asdf compatibility)\nmise is compatible with asdf's `.tool-versions` format:\n```\nnode 20.0.0\npython 3.11.5\nterraform 1.0.0\n```\n\n## Essential Commands\n\n### Tool Management\n- `mise use node@20` - Install and set node version (updates config)\n- `mise use -g node@20` - Set global default\n- `mise install` - Install all tools from config\n- `mise install node@20` - Install specific version\n- `mise ls` - List installed tools\n- `mise ls-remote node` - List available versions\n\n### Execution\n- `mise exec node@20 -- node script.js` - Run command with specific tool version\n- `mise x node@20 -- node script.js` - Shorthand for exec\n- `mise run test` - Run defined task\n- `mise test` - Shorthand (if no command conflict)\n\n### Environment\n- `mise activate bash` - Activate mise in shell (add to .bashrc)\n- `mise activate zsh` - Activate mise in zsh (add to .zshrc)  \n- `mise activate fish` - Activate mise in fish\n- `mise env` - Show current environment\n- `mise set KEY=value` - Set environment variable\n\n### Information\n- `mise doctor` - Check mise setup\n- `mise config` - Show loaded config files\n- `mise current` - Show active tool versions\n- `mise which node` - Show path to tool\n\n## Key Concepts\n\n### Activation vs Shims vs Exec\n1. **Activation** (`mise activate`): Recommended for interactive shells. Updates PATH automatically when changing directories.\n2. **Shims**: Symlinks that intercept tool calls. Good for CI/CD and IDEs.\n3. **Exec** (`mise exec`): Run commands with mise environment without activation.\n\n### Tool Scopes\n- `node@20.1.0` - Exact version\n- `node@20` - Latest 20.x version\n- `node@latest` - Latest available version\n- `node@lts` - Latest LTS version\n- `ref:master` - Build from git ref\n- `prefix:1.19` - Latest matching prefix\n- `path:/custom/path` - Use custom installation\n\n### Configuration Hierarchy\nConfig files are loaded in order (later overrides earlier):\n1. Global: `~/.config/mise/config.toml`\n2. Parent directories: `mise.toml` files going up the tree\n3. Current directory: `mise.toml`\n4. Local: `mise.local.toml`\n\n## Tasks\n\n### TOML Tasks\n```toml\n[tasks.build]\nrun = \"cargo build\"\ndescription = \"Build the project\"\ndepends = [\"install\"]\n\n[tasks.test]\nrun = \"cargo test\"\ndepends = [\"build\"]\n```\n\n### File Tasks\nCreate executable scripts in `mise-tasks/` directory:\n```bash\n#!/usr/bin/env bash\n#MISE description=\"Run tests\"\ncargo test\n```\n\n### Task Features\n- Parallel execution by default\n- Dependency management\n- File watching (`mise watch`)\n- Environment variable passing\n\n## Environment Variables\n\n### Settings\n- `MISE_DATA_DIR` - Where tools are installed (`~/.local/share/mise`)\n- `MISE_CONFIG_DIR` - Config directory (`~/.config/mise`)\n- `MISE_CACHE_DIR` - Cache directory\n- `MISE_GITHUB_TOKEN` - GitHub token for API access\n\n### Tool-specific\n- `MISE_NODE_VERSION=20` - Override node version\n- `MISE_PYTHON_VERSION=3.11` - Override python version\n\n## Common Patterns\n\n### Project Setup\n```bash\n# Initialize project\ncd my-project\nmise use node@20 python@3.11\nmise install\n\n# Add environment variables\nmise set NODE_ENV=development\nmise set DATABASE_URL=postgresql://localhost/myapp\n```\n\n### Global Tools\n```bash\n# Set global defaults\nmise use -g node@lts python@3.11 go@latest\n```\n\n### CI/CD\n```bash\n# Install mise and tools\ncurl https://mise.run | sh\nexport PATH=\"$HOME/.local/bin:$PATH\"\nmise install\nmise run build\n```\n\n## Troubleshooting\n\n### Common Issues\n- **Rate limiting**: Set `MISE_GITHUB_TOKEN` for GitHub API access\n- **Tool not found**: Run `mise doctor` to check setup\n- **Slow performance**: Check `mise cache clear` if stale\n- **Permission errors**: Ensure proper file permissions\n\n### Debugging\n- `mise doctor` - Comprehensive health check\n- `mise config` - Show config file loading order\n- `mise env` - Show current environment\n- `mise which <tool>` - Show tool path resolution\n\n## Plugin System\n\nmise uses plugins to support different tools:\n- Compatible with asdf plugins\n- Automatic plugin installation\n- Custom plugin repositories supported\n- Plugin shortcuts in registry\n\n## Migration from asdf\n\nmise is largely compatible with asdf:\n- Reads `.tool-versions` files\n- Uses asdf plugins\n- Similar commands (with improvements)\n- Can run alongside asdf temporarily\n\n## Best Practices\n\n1. Use `mise.toml` for committed project configuration\n2. Use `mise.local.toml` for local overrides\n3. Activate mise in shell for interactive use\n4. Use shims for CI/CD and IDE integration\n5. Set `MISE_GITHUB_TOKEN` to avoid rate limits\n6. Use `mise doctor` regularly to check setup\n7. Pin versions in production environments\n8. Use tasks for project automation\n\n## Advanced Features\n\n### Tool Options\n```toml\n[tools]\nnode = { version = \"20\", postinstall = \"corepack enable\" }\npython = { version = \"3.11\", virtualenv = \"myproject\" }\n```\n\n### Hooks\n```toml\n[hooks]\nenter = \"mise install --quiet\"\nleave = \"deactivate\"\n```\n\n### Multiple Versions\n```toml\n[tools]\npython = [\"3.10\", \"3.11\", \"3.12\"]  # Install multiple versions\n```\n\n## Development & Contributing\n\n### Setting Up Development Environment\n\nmise is written in Rust and uses itself for development tasks. To contribute to mise:\n\n#### Prerequisites\n- Rust (latest stable)\n- Node.js\n- `pipx` or `uv` \n- Bash (newer than macOS default)\n\n#### Getting Started\n```bash\n# Clone the repository\ngit clone https://github.com/jdx/mise.git\ncd mise\n\n# Install dependencies and build\nmise run build\n\n# Run sanity check\nmise run build\n```\n\n#### Development Setup\nCreate a development shim to easily run mise during development:\n\n```bash\n# Create ~/.local/bin/@mise\n#!/bin/sh\nexec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- \"$@\"\n```\n\nThen use `@mise` to run the development version:\n```bash\n@mise --help\neval \"$(@mise activate zsh)\"\n```\n\n### Testing\n\nmise has a comprehensive test suite with multiple types of tests to ensure reliability and functionality across different platforms and scenarios.\n\n#### Unit Tests\nUnit tests are fast, focused tests for individual components and functions:\n\n```bash\n# Run all unit tests\ncargo test --all-features\n\n# Run specific unit tests\ncargo test <test_name>\n\n# Run tests with verbose output\ncargo test --all-features -- --nocapture\n\n# Run tests in series (not parallel)\nRUST_TEST_THREADS=1 cargo test --all-features\n```\n\n**Unit test structure:**\n- Located in `src/` directory alongside source code\n- Use Rust's built-in test framework\n- Test individual functions and modules\n- Fast execution (used for quick feedback during development)\n\n#### E2E Tests\nEnd-to-end tests validate the complete functionality of mise in realistic scenarios:\n\n```bash\n# Run all E2E tests\nmise run test:e2e\n\n# Run specific E2E test\n./e2e/run_test test_name\n\n# Run E2E tests matching pattern\n./e2e/run_test task  # runs tests matching *task*\n\n# Run all tests including slow ones\nTEST_ALL=1 mise run test:e2e\n```\n\n**E2E test structure:**\n- Located in `e2e/` directory\n- Organized by functionality:\n  - `e2e/cli/` - Command-line interface tests\n  - `e2e/core/` - Core functionality tests\n  - `e2e/env/` - Environment variable tests\n  - `e2e/tasks/` - Task runner tests\n  - `e2e/config/` - Configuration tests\n  - `e2e/tools/` - Tool management tests\n  - `e2e/shell/` - Shell integration tests\n  - `e2e/backend/` - Backend tests\n  - `e2e/plugins/` - Plugin tests\n\n**E2E test categories:**\n- **Fast tests** (`test_*`): Run in normal test suites\n- **Slow tests** (`test_*_slow`): Only run when `TEST_ALL=1` is set\n- **Isolated environment**: Each test runs in a clean, isolated environment\n\n#### Coverage Tests\nCoverage tests measure how much of the codebase is covered by tests:\n\n```bash\n# Run coverage tests\nmise run test:coverage\n\n# Coverage tests run in parallel tranches for CI\nTEST_TRANCHE=0 TEST_TRANCHE_COUNT=8 mise run test:coverage\n```\n\n#### Windows E2E Tests\nWindows has its own test suite written in PowerShell:\n\n```powershell\n# Run all Windows E2E tests\npwsh e2e-win\\run.ps1\n\n# Run specific Windows tests\npwsh e2e-win\\run.ps1 task  # run tests matching *task*\n```\n\n#### Plugin Tests\nTest plugin functionality across different backends:\n\n```bash\n# Test specific plugin\nmise test-tool ripgrep\n\n# Test all plugins in registry\nmise test-tool --all\n\n# Test all plugins in config files\nmise test-tool --all-config\n\n# Test with parallel jobs\nmise test-tool --all --jobs 4\n```\n\n#### Test Environment Setup\nTests run in isolated environments to avoid conflicts:\n\n```bash\n# Disable mise during development testing\nexport MISE_DISABLE_TOOLS=1\n\n# Run tests with specific environment\nMISE_TRUSTED_CONFIG_PATHS=$PWD cargo test\n```\n\n#### Test Assertions\nThe E2E tests use a custom assertion framework (`e2e/assert.sh`):\n\n```bash\n# Basic assertions\nassert \"command\" \"expected_output\"\nassert_contains \"command\" \"substring\"\nassert_fail \"command\" \"expected_error\"\n\n# JSON assertions\nassert_json \"command\" '{\"key\": \"value\"}'\nassert_json_partial_array \"command\" \"fields\" '[{...}]'\n\n# File/directory assertions\nassert_directory_exists \"/path/to/dir\"\nassert_directory_not_exists \"/path/to/dir\"\nassert_empty \"command\"\n```\n\n#### Running Specific Test Categories\n\n```bash\n# Run all tests (unit + e2e)\nmise run test\n\n# Run only unit tests\nmise run test:unit\n\n# Run only e2e tests\nmise run test:e2e\n\n# Run tests with shuffle (for detecting order dependencies)\nmise run test:shuffle\n\n# Run nightly tests (with bleeding edge Rust)\nrustup default nightly && mise run test\n```\n\n#### Running Single Tests\n\n**Unit Tests:**\n```bash\n# Run a specific unit test by name\ncargo test test_name\n\n# Run tests matching a pattern\ncargo test pattern\n\n# Run tests in a specific module\ncargo test module_name\n\n# Run a single test with output\ncargo test test_name -- --nocapture\n\n# Run a single test file (if organized by file)\ncargo test --test test_file_name\n```\n\n**E2E Tests:**\n```bash\n# Run a specific E2E test by name\n./e2e/run_test test_name\n\n# Run E2E tests matching a pattern\nmise run test:e2e pattern\n\n# Examples:\n./e2e/run_test test_use                    # Run specific test\n./e2e/run_test test_config_set            # Run config-related test\nmise run test:e2e task                     # Run all tests matching \"task\"\n```\n\n**Plugin Tests:**\n```bash\n# Test a specific plugin\nmise test-tool ripgrep\n\n# Test a plugin with verbose output\nmise test-tool ripgrep --raw\n\n# Test multiple plugins\nmise test-tool ripgrep jq terraform\n```\n\n**Windows Tests:**\n```powershell\n# Run a specific Windows test\npwsh e2e-win\\run.ps1 -TestName \"test_name\"\n\n# Run tests matching a pattern\npwsh e2e-win\\run.ps1 task\n```\n\n#### Test Development Tips\n\n1. **Test naming**: Use descriptive names that explain what's being tested\n2. **Test isolation**: Each test should be independent and clean up after itself\n3. **Use slow tests sparingly**: Mark long-running tests as `_slow` to avoid CI timeouts\n4. **Mock external dependencies**: Use dummy plugins and mock data when possible\n5. **Test edge cases**: Include tests for error conditions and boundary cases\n\n#### Performance Testing\n```bash\n# Run performance benchmarks\nmise run test:perf\n\n# Build performance test workspace\nmise run test:build-perf-workspace\n```\n\n#### Snapshot Testing\nUsed for testing output consistency:\n\n```bash\n# Update test snapshots when output changes\nmise run snapshots\n\n# Use cargo-insta for snapshot testing\ncargo insta test --accept --unreferenced delete\n```\n\n### Available Development Tasks\n\nUse `mise tasks` to see all available development tasks:\n\n#### Common Tasks\n- `mise run build` - Build the project\n- `mise run test` - Run all tests (unit + E2E)\n- `mise run test:unit` - Run unit tests only\n- `mise run test:e2e` - Run E2E tests only\n- `mise run lint` - Run linting\n- `mise run lint:fix` - Run linting with fixes\n- `mise run format` - Format code\n- `mise run clean` - Clean build artifacts\n- `mise run snapshots` - Update test snapshots\n- `mise run render` - Generate documentation and completions\n\n#### Documentation Tasks\n- `mise run docs` - Start documentation development server\n- `mise run docs:build` - Build documentation\n- `mise run render:help` - Generate help documentation\n- `mise run render:completions` - Generate shell completions\n\n#### Release Tasks\n- `mise run release` - Create a release\n- `mise run ci` - Run CI tasks (format, build, test)\n\n### Project Structure\n\n```\nmise/\n├── src/           # Main Rust source code\n├── e2e/           # End-to-end tests\n├── docs/          # Documentation\n├── tasks.toml     # Development tasks\n├── mise.toml      # Project configuration\n├── Cargo.toml     # Rust project configuration\n└── xtasks/        # Additional build scripts\n```\n\n### Pre-commit Hooks & Code Quality\n\nmise uses multiple approaches for ensuring code quality and running pre-commit hooks:\n\n#### hk (Modern Hook Manager)\nmise uses [hk](https://hk.jdx.dev) (pronounced \"hook\") as its primary hook manager for linting and code quality checks. hk is a modern alternative to lefthook written by the same author as mise.\n\n**hk Configuration:**\nThe project uses `hk.pkl` (written in the Pkl configuration language) to define linting rules:\n\n```bash\n# Run all linting checks\nhk check --all\n\n# Run linting with fixes\nhk fix --all\n\n# Run specific linter\nhk check --step shellcheck\n```\n\n**Available Linters in hk:**\n- **prettier**: Code formatting for multiple languages\n- **clippy**: Rust linting with `cargo clippy`\n- **shellcheck**: Shell script linting\n- **shfmt**: Shell script formatting\n- **pkl**: Pkl configuration file validation\n\n**Using hk in Development:**\n```bash\n# Install hk via mise\nmise use hk\n\n# Run linting (used in CI and pre-commit)\nmise run lint  # This runs hk check --all\n\n# Run linting with fixes\nhk fix --all\n\n# Check specific file types\nhk check --step prettier\nhk check --step shellcheck\n```\n\n#### Traditional Pre-commit Hooks (Alternative)\nmise also supports traditional pre-commit hooks through multiple methods:\n\n**Option 1: Using lefthook (Legacy)**\n```bash\n# Install lefthook\nmise use lefthook\n\n# Install the git hooks\nlefthook install\n\n# Run pre-commit manually\nlefthook run pre-commit\n```\n\n**Option 2: Using standard pre-commit framework**\n```bash\n# Install pre-commit\nmise use pre-commit\n\n# Install the git hooks\npre-commit install\n\n# Run pre-commit manually\npre-commit run --all-files\n```\n\n**Option 3: Using mise's built-in git hook generation**\n```bash\n# Generate a git pre-commit hook that runs mise tasks\nmise generate git-pre-commit --write --task=pre-commit\n\n# This creates .git/hooks/pre-commit that runs:\n# mise run pre-commit\n```\n\n#### Pre-commit Task Configuration\nmise defines a `pre-commit` task that runs the main linting checks:\n\n```toml\n[pre-commit]\nenv = { PRE_COMMIT = 1 }\nrun = [\"mise run lint\"]\n```\n\nThis task:\n1. Sets `PRE_COMMIT=1` environment variable\n2. Runs `mise run lint`, which executes `hk check --all`\n\n#### Setting Up Pre-commit Hooks\n**Recommended approach using hk:**\n```bash\n# Install hk\nmise use hk\n\n# Set up git hook to run mise's pre-commit task\nmise generate git-pre-commit --write --task=pre-commit\n\n# Or manually create .git/hooks/pre-commit:\ncat > .git/hooks/pre-commit << 'EOF'\n#!/bin/sh\nexec mise run pre-commit\nEOF\nchmod +x .git/hooks/pre-commit\n```\n\n**Alternative approach using standard pre-commit:**\n```bash\n# Install pre-commit\nmise use pre-commit\n\n# Install hooks defined in .pre-commit-config.yaml\npre-commit install\n```\n\n#### Running Pre-commit Checks Manually\n```bash\n# Run all pre-commit checks\nmise run pre-commit\n\n# Run specific linting checks\nmise run lint\n\n# Run linting with fixes\nhk fix --all\n\n# Run checks on specific files\nhk check --files=\"src/**/*.rs\"\n```\n\n#### Environment Variables for Hooks\nWhen hooks run, they have access to these environment variables:\n- `PRE_COMMIT=1`: Indicates the code is running in pre-commit context\n- `STAGED`: Git staged files (when using mise's git hook generation)\n- `MISE_PRE_COMMIT=1`: Set by mise's generated git hooks\n\n### Testing Configuration\n\n- **Unit tests**: Fast tests for individual components\n- **E2E tests**: Integration tests that test the full application\n- **Slow tests**: Only run with `TEST_ALL=1` environment variable\n- **Windows tests**: Separate PowerShell-based test suite\n\n### Development Tips\n\n1. **Disable mise during development**: If you use mise in your shell, disable it when running tests to avoid conflicts\n2. **Use dev container**: Docker setup available (currently needs fixing)\n3. **Test specific features**: Use `cargo test <test_name>` for targeted testing\n4. **Update snapshots**: Use `mise run snapshots` when changing test outputs\n5. **Rate limiting**: Set `MISE_GITHUB_TOKEN` to avoid GitHub API rate limits during development\n\n### Dependency Management\n\nmise uses several tools to validate dependencies and code quality:\n\n- **cargo-deny**: Validates licenses, security advisories, and dependency duplicates\n- **cargo-msrv**: Verifies minimum supported Rust version compatibility\n- **cargo-machete**: Detects unused dependencies in Cargo.toml\n\nThese checks run automatically in CI and can be run locally:\n```bash\n# Install tools\nmise use cargo-deny cargo-msrv cargo-machete\n\n# Run checks\ncargo deny check\ncargo msrv verify\ncargo machete --with-metadata\n```\n\n### Contributing Guidelines\n\n1. **Before starting**: File an issue or discuss in Discord for non-obvious changes\n2. **Look for issues**: Check \"help wanted\" and \"good first issue\" labels\n3. **Test thoroughly**: Ensure both unit and E2E tests pass\n4. **Follow conventions**: Use existing code style and patterns\n5. **Update documentation**: Add/update docs for new features\n\n#### Pull Request Workflow\n1. **PR titles**: Must follow conventional commit format (validated automatically)\n2. **Auto-formatting**: Code will be automatically formatted by autofix.ci\n3. **CI checks**: All tests must pass across Linux, macOS, and Windows\n4. **Coverage**: New code should maintain or improve test coverage\n5. **Dependencies**: New dependencies are validated with cargo-deny\n\n#### GitHub Actions Development\nIf modifying GitHub Actions workflows:\n- Use `actionlint` to validate workflow files: `mise run lint`\n- Self-hosted runners are configured for performance testing\n- Configuration variables are allowed (see `.github/actionlint.yaml`)\n\n### Conventional Commits\n\nmise uses [Conventional Commits](https://www.conventionalcommits.org/) for consistent commit messages and automated changelog generation. All commits should follow this format:\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n#### Commit Types\n\n- **feat**: New features (🚀 Features)\n- **fix**: Bug fixes (🐛 Bug Fixes)\n- **refactor**: Code refactoring (🚜 Refactor)\n- **doc**: Documentation changes (📚 Documentation)\n- **style**: Code style changes (🎨 Styling)\n- **perf**: Performance improvements (⚡ Performance)\n- **test**: Testing changes (🧪 Testing)\n- **chore**: Maintenance tasks, dependency updates\n- **revert**: Reverting previous changes (◀️ Revert)\n\n#### Examples\n\n```bash\nfeat(cli): add new command for listing plugins\nfix(parser): handle edge case in version parsing\nrefactor(config): simplify configuration loading logic\ndoc(readme): update installation instructions\ntest(e2e): add tests for new plugin functionality\nchore(deps): update dependencies to latest versions\n```\n\n#### Scopes\n\nCommon scopes used in mise:\n- `cli` - Command line interface changes\n- `config` - Configuration system changes\n- `parser` - Parsing logic changes\n- `deps` - Dependency updates\n- `security` - Security-related changes\n\n#### Breaking Changes\n\nFor breaking changes, add `!` after the type or include `BREAKING CHANGE:` in the footer:\n\n```bash\nfeat(api)!: remove deprecated configuration options\n# OR\nfeat(api): remove deprecated configuration options\n\nBREAKING CHANGE: The old configuration format is no longer supported\n```\n\n### Packaging Testing\n\nFor testing package installation:\n\n#### Ubuntu/Debian\n```bash\n# Test apt installation\ndocker run -ti --rm ubuntu\napt update -y && apt install -y curl\n# ... installation steps\n```\n\n#### Fedora\n```bash\n# Test dnf installation  \ndocker run -ti --rm fedora\ndnf install -y dnf-plugins-core\n# ... installation steps\n```\n\n### CI/CD & Pull Request Automation\n\nmise uses several automated workflows to maintain code quality and streamline development:\n\n#### Automated Code Formatting\n- **autofix.ci**: Automatically formats code and fixes linting issues in PRs\n- Runs `mise run render` and `mise run lint-fix` automatically\n- Commits fixes directly to the PR branch\n\n#### PR Title Validation\n- **semantic-pr-lint**: Validates PR titles follow conventional commit format\n- PR titles must match: `<type>[optional scope]: <description>`\n- Example: `feat(cli): add new command for listing plugins`\n\n#### Continuous Integration\n- **Cross-platform testing**: Ubuntu, macOS, and Windows\n- **Unit tests**: Fast component-level tests\n- **E2E tests**: Full integration testing with multiple test tranches\n- **Coverage testing**: Code coverage across 8 parallel test runs\n- **Dependency validation**: `cargo deny`, `cargo msrv`, `cargo machete`\n\n#### Release Automation\n- **release-plz**: Automated release management based on conventional commits\n- Automatically creates release PRs and publishes releases\n- Runs daily via scheduled workflow\n- Handles version bumping and changelog generation\n\n## mise Codebase Architecture\n\n### Overview\n\nmise is a Rust-based tool with a modular architecture designed around three main concepts:\n1. **Tool Version Management** - Managing different versions of development tools\n2. **Environment Management** - Setting up environment variables and project contexts\n3. **Task Running** - Executing project tasks with dependency management\n\n### Core Architecture Components\n\n#### 1. **Main Entry Point** (`src/main.rs`)\n- Asynchronous Tokio runtime with multi-threading\n- Global error handling and panic hooks\n- CLI argument parsing and routing\n- Multi-progress reporting system\n\n#### 2. **CLI Layer** (`src/cli/`)\n- **Command Structure**: Each command is a separate module (e.g., `install.rs`, `use.rs`, `run.rs`)\n- **Argument Parsing**: Uses `clap` for command-line argument handling\n- **Command Execution**: Async command execution with proper error handling\n- **Key Commands**:\n  - `install` - Install tool versions\n  - `use` - Add tools to configuration\n  - `run` - Execute tasks\n  - `env` - Environment management\n  - `shell` - Shell integration\n\n#### 3. **Backend System** (`src/backend/`)\nThe backend system is the core abstraction for tool management:\n\n**Backend Trait**: Common interface for all tool backends\n```rust\npub trait Backend: Debug + Send + Sync {\n    async fn list_remote_versions(&self) -> Result<Vec<String>>;\n    async fn install_version(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()>;\n    async fn uninstall_version(&self, tv: &ToolVersion) -> Result<()>;\n    // ... other methods\n}\n```\n\n**Backend Types**:\n- **Core Backends**: Built-in support (Node.js, Python, etc.)\n- **ASDF Backends**: External plugin system compatibility\n- **Aqua Backends**: Package manager integration\n- **Language-specific**: npm, cargo, pipx, gem, go, etc.\n- **Universal**: ubi (GitHub releases)\n\n#### 4. **Configuration System** (`src/config/`)\n**Hierarchical Configuration**:\n- `Config` struct manages all configuration sources\n- `ConfigFile` trait for different config formats:\n  - `MiseToml` - Main configuration format\n  - `ToolVersions` - ASDF compatibility\n  - `IdiomaticVersion` - Language-specific files (`.nvmrc`, `.python-version`)\n\n**Configuration Hierarchy**:\n1. System config (`/etc/mise/config.toml`)\n2. Global config (`~/.config/mise/config.toml`)\n3. Project configs (searched up directory tree)\n4. Environment-specific configs (`mise.dev.toml`)\n\n#### 5. **Toolset Management** (`src/toolset/`)\n**Core Components**:\n- `Toolset` - Collection of tools for a specific context\n- `ToolVersion` - Represents a specific version of a tool\n- `ToolRequest` - User request for a tool (e.g., `node@18`)\n- `ToolsetBuilder` - Constructs toolsets from configuration\n\n**Tool Resolution Flow**:\n1. Parse configuration files\n2. Resolve version specifications\n3. Build toolset with dependencies\n4. Install missing tools\n5. Set up environment\n\n#### 6. **Task System** (`src/task/`)\n**Task Components**:\n- `Task` struct with metadata, dependencies, and execution info\n- `Deps` - Dependency graph management using petgraph\n- `TaskFileProvider` - Discovers tasks from files and configuration\n- Parallel execution with dependency resolution\n\n**Task Types**:\n- **TOML Tasks**: Defined in `mise.toml`\n- **File Tasks**: Executable scripts in task directories\n- **Command Tasks**: Simple command execution\n- **Script Tasks**: Inline script execution\n\n#### 7. **Plugin System** (`src/plugins/`)\n**Plugin Architecture**:\n- `Plugin` trait for extensibility\n- `AsdfPlugin` - ASDF plugin compatibility\n- `VfoxPlugin` - Vfox plugin system\n- `ScriptManager` - Manages plugin scripts\n\n**Plugin Types**:\n- **Core Plugins**: Built into mise\n- **External Plugins**: Downloaded from repositories\n- **Local Plugins**: Custom local implementations\n\n#### 8. **Shell Integration** (`src/shell/`)\n**Shell Support**:\n- Bash, Zsh, Fish, PowerShell support\n- `Shell` trait for shell-specific behavior\n- Activation scripts for environment setup\n- Hook system for directory changes\n\n#### 9. **Environment Management** (`src/env*.rs`)\n**Environment Components**:\n- `EnvDiff` - Tracks environment changes\n- `EnvDirective` - Configuration for environment variables\n- `PathEnv` - PATH management\n- Context-aware environment resolution\n\n#### 10. **Caching System** (`src/cache.rs`)\n**Cache Management**:\n- `CacheManager` - Generic caching with TTL\n- File-based caching for versions, metadata\n- Automatic cache invalidation\n- Per-backend cache isolation\n\n### Key Design Patterns\n\n#### 1. **Trait-Based Architecture**\n- `Backend` trait for tool management\n- `ConfigFile` trait for configuration formats\n- `Shell` trait for shell integration\n- `Plugin` trait for extensibility\n\n#### 2. **Async/Await Throughout**\n- Tokio runtime for async operations\n- Parallel tool installations\n- Concurrent task execution\n- Non-blocking I/O operations\n\n#### 3. **Error Handling**\n- `eyre` crate for error management\n- Structured error types\n- Context-aware error reporting\n- Graceful fallback behavior\n\n#### 4. **Configuration Hierarchy**\n- Multiple configuration sources\n- Inheritance and overrides\n- Environment-specific configurations\n- Validation and trust system\n\n#### 5. **Dependency Management**\n- Tool dependencies (e.g., Node.js for npm tools)\n- Task dependencies with DAG resolution\n- Parallel execution with proper ordering\n- Circular dependency detection\n\n### Data Flow\n\n1. **Initialization**: Load configuration hierarchy\n2. **Tool Discovery**: Find available backends and versions\n3. **Resolution**: Resolve tool requests to specific versions\n4. **Installation**: Install missing tools in dependency order\n5. **Environment Setup**: Configure PATH and environment variables\n6. **Execution**: Run tasks or provide shell integration\n\n### Testing Architecture\n\n**Test Structure**:\n- **Unit Tests**: Component-level testing with mocks\n- **Integration Tests**: End-to-end CLI testing\n- **E2E Tests**: Real-world scenario testing\n- **Snapshot Tests**: Output comparison testing\n\n**Test Organization**:\n- `src/` - Unit tests alongside source code\n- `e2e/` - End-to-end test scripts\n- `test/` - Test fixtures and utilities\n- `src/snapshots/` - Snapshot test data\n\nThis architecture provides a flexible, extensible foundation for managing development environments while maintaining compatibility with existing tools and workflows.\n\nThis covers the essential information about mise for LLMs to help users effectively use the tool for development environment management and contribute to its development."
  },
  {
    "path": "man/man1/mise.1",
    "content": ".TH MISE 1\n.SH NAME\nmise \\- The front\\-end to your dev env\n.SH SYNOPSIS\n\\fBmise\\fR [OPTIONS] [<TASK>] [<TASK_ARGS>] ... [<TASK_ARGS_LAST>] ... [COMMAND]\n.SH DESCRIPTION\nmise manages dev tools, env vars, and runs tasks. https://github.com/jdx/mise\n.PP\n.SH OPTIONS\n.TP\n\\fB\\-c, \\-\\-continue\\-on\\-error\\fR\nContinue running tasks even if one fails\n.TP\n\\fB\\-C, \\-\\-cd\\fR \\fI<DIR>\\fR\nChange directory before running command\n.TP\n\\fB\\-E, \\-\\-env\\fR \\fI<ENV>\\fR\nSet the environment for loading `mise.<ENV>.toml`\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce the operation\n.TP\n\\fB\\-i, \\-\\-interleave\\fR\nSet the log output verbosity\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nHow many jobs to run in parallel [default: 8]\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nDry run, don't actually do anything\n.TP\n\\fB\\-p, \\-\\-prefix\\fR\n.TP\n\\fB\\-P, \\-\\-profile\\fR \\fI<PROFILE>\\fR\nSet the profile (environment)\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nSuppress non\\-error messages\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\n.TP\n\\fB\\-t, \\-\\-tool\\fR \\fI<TOOL@VERSION>\\fR\nTool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\n.TP\n\\fB\\-v, \\-\\-verbose\\fR\nShow extra output (use \\-vv for even more)\n.TP\n\\fB\\-V, \\-\\-version\\fR\n.TP\n\\fB\\-y, \\-\\-yes\\fR\nAnswer yes to all confirmation prompts\n.TP\n\\fB\\-\\-debug\\fR\nSets log level to debug\n.TP\n\\fB\\-\\-log\\-level\\fR \\fI<LEVEL>\\fR\n.TP\n\\fB\\-\\-no\\-config\\fR\nDo not load any config files\n\nCan also use `MISE_NO_CONFIG=1`\n.TP\n\\fB\\-\\-no\\-env\\fR\nDo not load environment variables from config files\n\nCan also use `MISE_NO_ENV=1`\n.TP\n\\fB\\-\\-no\\-hooks\\fR\nDo not execute hooks from config files\n\nCan also use `MISE_NO_HOOKS=1`\n.TP\n\\fB\\-\\-no\\-timings\\fR\nHides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`\n.TP\n\\fB\\-\\-output\\fR \\fI<OUTPUT>\\fR\n.TP\n\\fB\\-\\-raw\\fR\nRead/write directly to stdin/stdout/stderr instead of by line\n.TP\n\\fB\\-\\-locked\\fR\nRequire lockfile URLs to be present during installation\n\nFails if tools don't have pre\\-resolved URLs in the lockfile for the current platform.\nThis prevents API calls to GitHub, aqua registry, etc.\nCan also be enabled via MISE_LOCKED=1 or settings.locked=true\n.TP\n\\fB\\-\\-silent\\fR\nSuppress all task output and mise non\\-error messages\n.TP\n\\fB\\-\\-timings\\fR\nShows elapsed time after each task completes\n\nDefault to always show with `MISE_TASK_TIMINGS=1`\n.TP\n\\fB\\-\\-trace\\fR\nSets log level to trace\n.SH ARGUMENTS\n.TP\n\\fB<TASK>\\fR\nTask to run.\n\nShorthand for `mise tasks run <TASK>`.\n.TP\n\\fB<TASK_ARGS>\\fR\nTask arguments\n.SH COMMANDS\n.TP\n\\fBactivate\\fR\nInitializes mise in the current shell session\n.TP\n\\fBtool\\-alias\\fR\nManage tool version aliases.\n.TP\n\\fBtool\\-alias get\\fR\nShow an alias for a plugin\n.TP\n\\fBtool\\-alias ls\\fR\nList tool version aliases\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBtool\\-alias set\\fR\nAdd/update an alias for a backend/plugin\n.RS\n\\fIAliases: \\fRadd, create\n.RE\n.TP\n\\fBtool\\-alias unset\\fR\nClears an alias for a backend/plugin\n.RS\n\\fIAliases: \\fRrm, remove, delete, del\n.RE\n.TP\n\\fBbackends\\fR\nManage backends\n.RS\n\\fIAliases: \\fRb\n.RE\n.TP\n\\fBbackends ls\\fR\nList built\\-in backends\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBbin\\-paths\\fR\nList all the active runtime bin paths\n.TP\n\\fBcache\\fR\nManage the mise cache\n.TP\n\\fBcache clear\\fR\nDeletes all cache files in mise\n.RS\n\\fIAliases: \\fRc\n.RE\n.TP\n\\fBcache path\\fR\nShow the cache directory path\n.RS\n\\fIAliases: \\fRdir\n.RE\n.TP\n\\fBcache prune\\fR\nRemoves stale mise cache files\n.RS\n\\fIAliases: \\fRp\n.RE\n.TP\n\\fBcompletion\\fR\nGenerate shell completions\n.TP\n\\fBconfig\\fR\nManage config files\n.RS\n\\fIAliases: \\fRcfg\n.RE\n.TP\n\\fBconfig get\\fR\nDisplay the value of a setting in a mise.toml file\n.TP\n\\fBconfig ls\\fR\nList config files currently in use\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBconfig set\\fR\nSet the value of a setting in a mise.toml file\n.TP\n\\fBdeactivate\\fR\nDisable mise for current shell session\n.TP\n\\fBdoctor\\fR\nCheck mise installation for possible problems\n.RS\n\\fIAliases: \\fRdr\n.RE\n.TP\n\\fBdoctor path\\fR\nPrint the current PATH entries mise is providing\n.TP\n\\fBen\\fR\nStarts a new shell with the mise environment built from the current configuration\n.TP\n\\fBenv\\fR\nExports env vars to activate mise a single time\n.RS\n\\fIAliases: \\fRe\n.RE\n.TP\n\\fBexec\\fR\nExecute a command with tool(s) set\n.RS\n\\fIAliases: \\fRx\n.RE\n.TP\n\\fBfmt\\fR\nFormats mise.toml\n.TP\n\\fBgenerate\\fR\nGenerate files for various tools/services\n.RS\n\\fIAliases: \\fRgen\n.RE\n.TP\n\\fBgenerate bootstrap\\fR\nGenerate a script to download+execute mise\n.TP\n\\fBgenerate config\\fR\nGenerate a mise.toml file\n.TP\n\\fBgenerate devcontainer\\fR\nGenerate a devcontainer to execute mise\n.TP\n\\fBgenerate git\\-pre\\-commit\\fR\nGenerate a git pre\\-commit hook\n.RS\n\\fIAliases: \\fRpre\\-commit\n.RE\n.TP\n\\fBgenerate github\\-action\\fR\nGenerate a GitHub Action workflow file\n.TP\n\\fBgenerate task\\-docs\\fR\nGenerate documentation for tasks in a project\n.TP\n\\fBgenerate task\\-stubs\\fR\nGenerates shims to run mise tasks\n.TP\n\\fBgenerate tool\\-stub\\fR\nGenerate a tool stub for HTTP\\-based tools\n.TP\n\\fBimplode\\fR\nRemoves mise CLI and all related data\n.TP\n\\fBedit\\fR\nEdit mise.toml interactively\n.TP\n\\fBinstall\\fR\nInstall a tool version\n.RS\n\\fIAliases: \\fRi\n.RE\n.TP\n\\fBinstall\\-into\\fR\nInstall a tool version to a specific path\n.TP\n\\fBlatest\\fR\nGets the latest available version for a plugin\n.TP\n\\fBlink\\fR\nSymlinks a tool version into mise\n.RS\n\\fIAliases: \\fRln\n.RE\n.TP\n\\fBlock\\fR\nUpdate lockfile checksums and URLs for all specified platforms\n.TP\n\\fBls\\fR\nList installed and active tool versions\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBls\\-remote\\fR\nList runtime versions available for install.\n.TP\n\\fBmcp\\fR\n[experimental] Run Model Context Protocol (MCP) server\n.TP\n\\fBoutdated\\fR\nShows outdated tool versions\n.TP\n\\fBplugins\\fR\nManage plugins\n.RS\n\\fIAliases: \\fRp\n.RE\n.TP\n\\fBplugins install\\fR\nInstall a plugin\n.RS\n\\fIAliases: \\fRi, a, add\n.RE\n.TP\n\\fBplugins link\\fR\nSymlinks a plugin into mise\n.RS\n\\fIAliases: \\fRln\n.RE\n.TP\n\\fBplugins ls\\fR\nList installed plugins\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBplugins ls\\-remote\\fR\n\n.RS\n\\fIAliases: \\fRlist\\-remote, list\\-all\n.RE\n.TP\n\\fBplugins uninstall\\fR\nRemoves a plugin\n.RS\n\\fIAliases: \\fRremove, rm\n.RE\n.TP\n\\fBplugins update\\fR\nUpdates a plugin to the latest version\n.RS\n\\fIAliases: \\fRup, upgrade\n.RE\n.TP\n\\fBprepare\\fR\n[experimental] Ensure project dependencies are ready\n.RS\n\\fIAliases: \\fRprep\n.RE\n.TP\n\\fBprune\\fR\nDelete unused versions of tools\n.TP\n\\fBregistry\\fR\nList available tools to install\n.TP\n\\fBreshim\\fR\nCreates new shims based on bin paths from currently installed tools.\n.TP\n\\fBrun\\fR\nRun task(s)\n.RS\n\\fIAliases: \\fRr\n.RE\n.TP\n\\fBsearch\\fR\nSearch for tools in the registry\n.TP\n\\fBself\\-update\\fR\nUpdates mise itself.\n.TP\n\\fBset\\fR\nSet environment variables in mise.toml\n.TP\n\\fBsettings\\fR\nShow current settings\n.TP\n\\fBsettings add\\fR\nAdds a setting to the configuration file\n.TP\n\\fBsettings get\\fR\nShow a current setting\n.TP\n\\fBsettings ls\\fR\nShow current settings\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBsettings set\\fR\nAdd/update a setting\n.RS\n\\fIAliases: \\fRcreate\n.RE\n.TP\n\\fBsettings unset\\fR\nClears a setting\n.RS\n\\fIAliases: \\fRrm, remove, delete, del\n.RE\n.TP\n\\fBshell\\fR\nSets a tool version for the current session.\n.RS\n\\fIAliases: \\fRsh\n.RE\n.TP\n\\fBshell\\-alias\\fR\nManage shell aliases.\n.TP\n\\fBshell\\-alias get\\fR\nShow the command for a shell alias\n.TP\n\\fBshell\\-alias ls\\fR\nList shell aliases\n.RS\n\\fIAliases: \\fRlist\n.RE\n.TP\n\\fBshell\\-alias set\\fR\nAdd/update a shell alias\n.RS\n\\fIAliases: \\fRadd, create\n.RE\n.TP\n\\fBshell\\-alias unset\\fR\nRemoves a shell alias\n.RS\n\\fIAliases: \\fRrm, remove, delete, del\n.RE\n.TP\n\\fBsync\\fR\nSynchronize tools from other version managers with mise\n.TP\n\\fBsync node\\fR\nSymlinks all tool versions from an external tool into mise\n.TP\n\\fBsync python\\fR\nSymlinks all tool versions from an external tool into mise\n.TP\n\\fBsync ruby\\fR\nSymlinks all ruby tool versions from an external tool into mise\n.TP\n\\fBtasks\\fR\nManage tasks\n.RS\n\\fIAliases: \\fRt\n.RE\n.TP\n\\fBtasks add\\fR\nCreate a new task\n.TP\n\\fBtasks deps\\fR\nDisplay a tree visualization of a dependency graph\n.TP\n\\fBtasks edit\\fR\nEdit a task with $EDITOR\n.TP\n\\fBtasks info\\fR\nGet information about a task\n.TP\n\\fBtasks ls\\fR\nList available tasks to execute\n.TP\n\\fBtasks run\\fR\nRun task(s)\n.RS\n\\fIAliases: \\fRr\n.RE\n.TP\n\\fBtasks validate\\fR\nValidate tasks for common errors and issues\n.TP\n\\fBtest\\-tool\\fR\nTest a tool installs and executes\n.TP\n\\fBtool\\fR\nGets information about a tool\n.TP\n\\fBtool\\-stub\\fR\nExecute a tool stub\n.TP\n\\fBtrust\\fR\nMarks a config file as trusted\n.TP\n\\fBuninstall\\fR\nRemoves installed tool versions\n.TP\n\\fBunset\\fR\nRemove environment variable(s) from the config file.\n.TP\n\\fBunuse\\fR\nRemoves installed tool versions from mise.toml\n.RS\n\\fIAliases: \\fRrm, remove\n.RE\n.TP\n\\fBupgrade\\fR\nUpgrades outdated tools\n.RS\n\\fIAliases: \\fRup\n.RE\n.TP\n\\fBuse\\fR\nInstalls a tool and adds the version to mise.toml.\n.RS\n\\fIAliases: \\fRu\n.RE\n.TP\n\\fBversion\\fR\nDisplay the version of mise\n.RS\n\\fIAliases: \\fRv\n.RE\n.TP\n\\fBwatch\\fR\nRun task(s) and watch for changes to rerun it\n.RS\n\\fIAliases: \\fRw\n.RE\n.TP\n\\fBwhere\\fR\nDisplay the installation path for a tool\n.TP\n\\fBwhich\\fR\nShows the path that a tool's bin points to.\n.SH \"MISE ACTIVATE\"\nInitializes mise in the current shell session\n\nThis should go into your shell's rc file or login shell.\nOtherwise, it will only take effect in the current session.\n(e.g. ~/.zshrc, ~/.zprofile, ~/.zshenv, ~/.bashrc, ~/.bash_profile, ~/.profile, ~/.config/fish/config.fish, or $PROFILE for powershell)\n\nTypically, this can be added with something like the following:\n\n    echo 'eval \"$(mise activate zsh)\"' >> ~/.zshrc\n\nHowever, this requires that \"mise\" is in your PATH. If it is not, you need to\nspecify the full path like this:\n\n    echo 'eval \"$(/path/to/mise activate zsh)\"' >> ~/.zshrc\n\nCustomize status output with `status` settings.\n.PP\n\\fBUsage:\\fR mise activate [OPTIONS] [<SHELL_TYPE>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nSuppress non\\-error messages\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\nShell type to generate the script for\n.TP\n\\fB\\-\\-no\\-hook\\-env\\fR\nDo not automatically call hook\\-env\n\nThis can be helpful for debugging mise. If you run `eval \"$(mise activate \\-\\-no\\-hook\\-env)\"`, then you can call `mise hook\\-env` manually which will output the env vars to stdout without actually modifying the environment. That way you can do things like `mise hook\\-env \\-\\-trace` to get more information or just see the values that hook\\-env is outputting.\n.TP\n\\fB\\-\\-shims\\fR\nUse shims instead of modifying PATH\nEffectively the same as:\n\n    PATH=\"$HOME/.local/share/mise/shims:$PATH\"\n\n`mise activate \\-\\-shims` does not support all the features of `mise activate`.\nSee https://mise.jdx.dev/dev\\-tools/shims.html#shims\\-vs\\-path for more information\n.TP\n\\fB\\-\\-status\\fR\nShow \"mise: <PLUGIN>@<VERSION>\" message when changing directories\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SHELL_TYPE>\\fR\nShell type to generate the script for\n.SH \"MISE TOOL-ALIAS\"\nManage tool version aliases.\n.PP\n\\fBUsage:\\fR mise tool\\-alias [OPTIONS] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-p, \\-\\-plugin\\fR \\fI<PLUGIN>\\fR\nfilter aliases by plugin\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't show table header\n.SH \"MISE TOOL-ALIAS GET\"\nShow an alias for a plugin\n\nThis is the contents of a tool_alias.<PLUGIN> entry in ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise tool\\-alias get <PLUGIN> <ALIAS>\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nThe plugin to show the alias for\n.TP\n\\fB<ALIAS>\\fR\nThe alias to show\n.SH \"MISE TOOL-ALIAS LS\"\nList tool version aliases\nShows the aliases that can be specified.\nThese can come from user config or from plugins in `bin/list\\-aliases`.\n\nFor user config, aliases are defined like the following in `~/.config/mise/config.toml`:\n\n    [tool_alias.node.versions]\n    lts = \"22.0.0\"\n.PP\n\\fBUsage:\\fR mise tool\\-alias ls [OPTIONS] [<TOOL>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't show table header\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL>\\fR\nShow aliases for <TOOL>\n.SH \"MISE TOOL-ALIAS SET\"\nAdd/update an alias for a backend/plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise tool\\-alias set <PLUGIN> <ALIAS> [<VALUE>]\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nThe backend/plugin to set the alias for\n.TP\n\\fB<ALIAS>\\fR\nThe alias to set\n.TP\n\\fB<VALUE>\\fR\nThe value to set the alias to\n.SH \"MISE TOOL-ALIAS UNSET\"\nClears an alias for a backend/plugin\n\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise tool\\-alias unset <PLUGIN> [<ALIAS>]\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nThe backend/plugin to remove the alias from\n.TP\n\\fB<ALIAS>\\fR\nThe alias to remove\n.SH \"MISE BIN-PATHS\"\nList all the active runtime bin paths\n.PP\n\\fBUsage:\\fR mise bin\\-paths [<TOOL@VERSION>] ...\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to look up\ne.g.: ruby@3\n.SH \"MISE CACHE CLEAR\"\nDeletes all cache files in mise\n.PP\n\\fBUsage:\\fR mise cache clear [OPTIONS] [<PLUGIN>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-outdate\\fR\nMark all cache files as old\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nPlugin(s) to clear cache for e.g.: node, python\n.SH \"MISE CACHE PRUNE\"\nRemoves stale mise cache files\n\nBy default, this command will remove files that have not been accessed in 30 days.\nChange this with the MISE_CACHE_PRUNE_AGE environment variable.\n.PP\n\\fBUsage:\\fR mise cache prune [OPTIONS] [<PLUGIN>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-v, \\-\\-verbose\\fR\nShow pruned files\n.TP\n\\fB\\-\\-dry\\-run\\fR\nJust show what would be pruned\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nPlugin(s) to clear cache for e.g.: node, python\n.SH \"MISE COMPLETION\"\nGenerate shell completions\n.PP\n\\fBUsage:\\fR mise completion [OPTIONS] [<SHELL>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL_TYPE>\\fR\nShell type to generate completions for\n.TP\n\\fB\\-\\-include\\-bash\\-completion\\-lib\\fR\nInclude the bash completion library in the bash completion script\n\nThis is required for completions to work in bash, but it is not included by default\nyou may source it separately or enable this flag to enable it in the script.\n.TP\n\\fB\\-\\-usage\\fR\nAlways use usage for completions.\nCurrently, usage is the default for fish and bash but not zsh since it has a few quirks\nto work out first.\n\nThis requires the `usage` CLI to be installed.\nhttps://usage.jdx.dev\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SHELL>\\fR\nShell type to generate completions for\n.SH \"MISE CONFIG\"\nManage config files\n.PP\n\\fBUsage:\\fR mise config [OPTIONS] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-\\-no\\-header\\fR\nDo not print table header\n.TP\n\\fB\\-\\-tracked\\-configs\\fR\nList all tracked config files\n.SH \"MISE CONFIG GET\"\nDisplay the value of a setting in a mise.toml file\n.PP\n\\fBUsage:\\fR mise config get [OPTIONS] [<KEY>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-file\\fR \\fI<FILE>\\fR\nThe path to the mise.toml file to edit\n\nIf not provided, the nearest mise.toml file will be used\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<KEY>\\fR\nThe path of the config to display\n.SH \"MISE CONFIG LS\"\nList config files currently in use\n.PP\n\\fBUsage:\\fR mise config ls [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-\\-no\\-header\\fR\nDo not print table header\n.TP\n\\fB\\-\\-tracked\\-configs\\fR\nList all tracked config files\n.SH \"MISE CONFIG SET\"\nSet the value of a setting in a mise.toml file\n.PP\n\\fBUsage:\\fR mise config set [OPTIONS] <KEY> [<VALUE>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-file\\fR \\fI<FILE>\\fR\nThe path to the mise.toml file to edit\n\nIf not provided, the nearest mise.toml file will be used\n.TP\n\\fB\\-t, \\-\\-type\\fR \\fI<TYPE>\\fR\n.RS\n\\fIDefault: \\fRinfer\n.RE\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<KEY>\\fR\nThe path of the config to display\n.TP\n\\fB<VALUE>\\fR\nThe value to set the key to (optional if provided as KEY=VALUE)\n.SH \"MISE DOCTOR\"\nCheck mise installation for possible problems\n.PP\n\\fBUsage:\\fR mise doctor [OPTIONS] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\n.SH \"MISE DOCTOR PATH\"\nPrint the current PATH entries mise is providing\n.PP\n\\fBUsage:\\fR mise doctor path [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-full\\fR\nPrint all entries including those not provided by mise\n.SH \"MISE EN\"\nStarts a new shell with the mise environment built from the current configuration\n\nThis is an alternative to `mise activate` that allows you to explicitly start a mise session.\nIt will have the tools and environment variables in the configs loaded.\nNote that changing directories will not update the mise environment.\n.PP\n\\fBUsage:\\fR mise en [OPTIONS] [<DIR>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\nShell to start\n\nDefaults to $SHELL\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<DIR>\\fR\nDirectory to start the shell in\n.RS\n\\fIDefault: \\fR.\n.RE\n.SH \"MISE ENV\"\nExports env vars to activate mise a single time\n\nUse this if you don't want to permanently install mise. It's not necessary to\nuse this if you have `mise activate` in your shell rc file.\n.PP\n\\fBUsage:\\fR mise env [OPTIONS] [<TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-D, \\-\\-dotenv\\fR\nOutput in dotenv format\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\nShell type to generate environment variables for\n.TP\n\\fB\\-\\-json\\-extended\\fR\nOutput in JSON format with additional information (source, tool)\n.TP\n\\fB\\-\\-redacted\\fR\nOnly show redacted environment variables\n.TP\n\\fB\\-\\-values\\fR\nOnly show values of environment variables\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to use\n.SH \"MISE EXEC\"\nExecute a command with tool(s) set\n\nuse this to avoid modifying the shell session or running ad\\-hoc commands with mise tools set.\n\nTools will be loaded from mise.toml, though they can be overridden with <RUNTIME> args\nNote that only the plugin specified will be overridden, so if a `mise.toml` file\nincludes \"node 20\" but you run `mise exec python@3.11`; it will still load node@20.\n\nThe \"\\-\\-\" separates runtimes from the commands to pass along to the subprocess.\n.PP\n\\fBUsage:\\fR mise exec [OPTIONS] [<TOOL@VERSION>] ... [<COMMAND>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-c, \\-\\-command\\fR \\fI<C>\\fR\nCommand string to execute\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-\\-fresh\\-env\\fR\nBypass the environment cache and recompute the environment\n.TP\n\\fB\\-\\-no\\-prepare\\fR\nSkip automatic dependency preparation\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets \\-\\-jobs=1\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to start e.g.: node@20 python@3.10\n.TP\n\\fB<COMMAND>\\fR\nCommand string to execute (same as \\-\\-command)\n.SH \"MISE FMT\"\nFormats mise.toml\n\nSorts keys and cleans up whitespace in mise.toml\n.PP\n\\fBUsage:\\fR mise fmt [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nFormat all files from the current directory\n.TP\n\\fB\\-c, \\-\\-check\\fR\nCheck if the configs are formatted, no formatting is done\n.TP\n\\fB\\-s, \\-\\-stdin\\fR\nRead config from stdin and write its formatted version into stdout\n.SH \"MISE GENERATE BOOTSTRAP\"\nGenerate a script to download+execute mise\n\nThis is designed to be used in a project where contributors may not have mise installed.\n.PP\n\\fBUsage:\\fR mise generate bootstrap [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-l, \\-\\-localize\\fR\nSandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\n\nThis is necessary if users may use a different version of mise outside the project.\n.TP\n\\fB\\-V, \\-\\-version\\fR \\fI<VERSION>\\fR\nSpecify mise version to fetch\n.TP\n\\fB\\-w, \\-\\-write\\fR \\fI<WRITE>\\fR\ninstead of outputting the script to stdout, write to a file and make it executable\n.TP\n\\fB\\-\\-localized\\-dir\\fR \\fI<LOCALIZED_DIR>\\fR\nDirectory to put localized data into\n.RS\n\\fIDefault: \\fR.mise\n.RE\n.SH \"MISE GENERATE CONFIG\"\nGenerate a mise.toml file\n.PP\n\\fBUsage:\\fR mise generate config [OPTIONS] [<PATH>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nShow what would be generated without writing to file\n.TP\n\\fB\\-t, \\-\\-tool\\-versions\\fR \\fI<TOOL_VERSIONS>\\fR\nPath to a .tool\\-versions file to import tools from\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PATH>\\fR\nPath to the config file to create\n.SH \"MISE GENERATE DEVCONTAINER\"\nGenerate a devcontainer to execute mise\n.PP\n\\fBUsage:\\fR mise generate devcontainer [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-i, \\-\\-image\\fR \\fI<IMAGE>\\fR\nThe image to use for the devcontainer\n.TP\n\\fB\\-m, \\-\\-mount\\-mise\\-data\\fR\nBind the mise\\-data\\-volume to the devcontainer\n.TP\n\\fB\\-n, \\-\\-name\\fR \\fI<NAME>\\fR\nThe name of the devcontainer\n.TP\n\\fB\\-w, \\-\\-write\\fR\nwrite to .devcontainer/devcontainer.json\n.SH \"MISE GENERATE GIT-PRE-COMMIT\"\nGenerate a git pre\\-commit hook\n\nThis command generates a git pre\\-commit hook that runs a mise task like `mise run pre\\-commit`\nwhen you commit changes to your repository.\n\nStaged files are passed to the task as `STAGED`.\n\nFor more advanced pre\\-commit functionality, see mise's sister project: https://hk.jdx.dev/\n.PP\n\\fBUsage:\\fR mise generate git\\-pre\\-commit [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-t, \\-\\-task\\fR \\fI<TASK>\\fR\nThe task to run when the pre\\-commit hook is triggered\n.RS\n\\fIDefault: \\fRpre\\-commit\n.RE\n.TP\n\\fB\\-w, \\-\\-write\\fR\nwrite to .git/hooks/pre\\-commit and make it executable\n.TP\n\\fB\\-\\-hook\\fR \\fI<HOOK>\\fR\nWhich hook to generate (saves to .git/hooks/$hook)\n.RS\n\\fIDefault: \\fRpre\\-commit\n.RE\n.SH \"MISE GENERATE GITHUB-ACTION\"\nGenerate a GitHub Action workflow file\n\nThis command generates a GitHub Action workflow file that runs a mise task like `mise run ci`\nwhen you push changes to your repository.\n.PP\n\\fBUsage:\\fR mise generate github\\-action [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-t, \\-\\-task\\fR \\fI<TASK>\\fR\nThe task to run when the workflow is triggered\n.RS\n\\fIDefault: \\fRci\n.RE\n.TP\n\\fB\\-w, \\-\\-write\\fR\nwrite to .github/workflows/$name.yml\n.TP\n\\fB\\-\\-name\\fR \\fI<NAME>\\fR\nthe name of the workflow to generate\n.RS\n\\fIDefault: \\fRci\n.RE\n.SH \"MISE GENERATE TASK-DOCS\"\nGenerate documentation for tasks in a project\n.PP\n\\fBUsage:\\fR mise generate task\\-docs [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-i, \\-\\-inject\\fR\ninserts the documentation into an existing file\n\nThis will look for a special comment, `<!\\-\\- mise\\-tasks \\-\\->`, and replace it with the generated documentation.\nIt will replace everything between the comment and the next comment, `<!\\-\\- /mise\\-tasks \\-\\->` so it can be\nrun multiple times on the same file to update the documentation.\n.TP\n\\fB\\-I, \\-\\-index\\fR\nwrite only an index of tasks, intended for use with `\\-\\-multi`\n.TP\n\\fB\\-m, \\-\\-multi\\fR\nrender each task as a separate document, requires `\\-\\-output` to be a directory\n.TP\n\\fB\\-o, \\-\\-output\\fR \\fI<OUTPUT>\\fR\nwrites the generated docs to a file/directory\n.TP\n\\fB\\-r, \\-\\-root\\fR \\fI<ROOT>\\fR\nroot directory to search for tasks\n.TP\n\\fB\\-s, \\-\\-style\\fR \\fI<STYLE>\\fR\n.RS\n\\fIDefault: \\fRsimple\n.RE\n.SH \"MISE GENERATE TASK-STUBS\"\nGenerates shims to run mise tasks\n\nBy default, this will build shims like ./bin/<task>. These can be paired with `mise generate bootstrap`\nso contributors to a project can execute mise tasks without installing mise into their system.\n.PP\n\\fBUsage:\\fR mise generate task\\-stubs [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-d, \\-\\-dir\\fR \\fI<DIR>\\fR\nDirectory to create task stubs inside of\n.RS\n\\fIDefault: \\fRbin\n.RE\n.TP\n\\fB\\-m, \\-\\-mise\\-bin\\fR \\fI<MISE_BIN>\\fR\nPath to a mise bin to use when running the task stub.\n\nUse `\\-\\-mise\\-bin=./bin/mise` to use a mise bin generated from `mise generate bootstrap`\n.RS\n\\fIDefault: \\fRmise\n.RE\n.SH \"MISE GENERATE TOOL-STUB\"\nGenerate a tool stub for HTTP\\-based tools\n\nThis command generates tool stubs that can automatically download and execute\ntools from HTTP URLs. It can detect checksums, file sizes, and binary paths\nautomatically by downloading and analyzing the tool.\n\nWhen generating stubs with platform\\-specific URLs, the command will append new\nplatforms to existing stub files rather than overwriting them. This allows you\nto incrementally build cross\\-platform tool stubs.\n.PP\n\\fBUsage:\\fR mise generate tool\\-stub [OPTIONS] <OUTPUT>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-b, \\-\\-bin\\fR \\fI<BIN>\\fR\nBinary path within the extracted archive\n\nIf not specified and the archive is downloaded, will auto\\-detect the most likely binary\n.TP\n\\fB\\-\\-bootstrap\\fR\nWrap stub in a bootstrap script that installs mise if not already present\n\nWhen enabled, generates a bash script that:\n1. Checks if mise is installed at the expected path\n2. If not, downloads and installs mise using the embedded installer\n3. Executes the tool stub using mise\n.TP\n\\fB\\-\\-bootstrap\\-version\\fR \\fI<BOOTSTRAP_VERSION>\\fR\nSpecify mise version for the bootstrap script\n\nBy default, uses the latest version from the install script.\nUse this to pin to a specific version (e.g., \"2025.1.0\").\n.TP\n\\fB\\-\\-fetch\\fR\nFetch checksums and sizes for an existing tool stub file\n\nThis reads an existing stub file and fills in any missing checksum/size fields by downloading the files. URLs must already be present in the stub.\n.TP\n\\fB\\-\\-http\\fR \\fI<HTTP>\\fR\nHTTP backend type to use\n.RS\n\\fIDefault: \\fRhttp\n.RE\n.TP\n\\fB\\-\\-lock\\fR\nResolve and embed lockfile data (exact version + platform URLs/checksums) into an existing stub file for reproducible installs without runtime API calls\n.TP\n\\fB\\-\\-platform\\-bin\\fR \\fI<PLATFORM_BIN>\\fR\nPlatform\\-specific binary paths in the format platform:path\n\nExamples: \\-\\-platform\\-bin windows\\-x64:tool.exe \\-\\-platform\\-bin linux\\-x64:bin/tool\n.TP\n\\fB\\-\\-platform\\-url\\fR \\fI<PLATFORM_URL>\\fR\nPlatform\\-specific URLs in the format platform:url or just url (auto\\-detect platform)\n\nWhen the output file already exists, new platforms will be appended to the existing platforms table. Existing platform URLs will be updated if specified again.\n\nIf only a URL is provided (without platform:), the platform will be automatically detected from the URL filename.\n\nExamples: \\-\\-platform\\-url linux\\-x64:https://... \\-\\-platform\\-url https://nodejs.org/dist/v22.17.1/node\\-v22.17.1\\-darwin\\-arm64.tar.gz\n.TP\n\\fB\\-\\-skip\\-download\\fR\nSkip downloading for checksum and binary path detection (faster but less informative)\n.TP\n\\fB\\-u, \\-\\-url\\fR \\fI<URL>\\fR\nURL for downloading the tool\n\nExample: https://github.com/owner/repo/releases/download/v2.0.0/tool\\-linux\\-x64.tar.gz\n.TP\n\\fB\\-\\-version\\fR \\fI<VERSION>\\fR\nVersion of the tool\n.RS\n\\fIDefault: \\fRlatest\n.RE\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<OUTPUT>\\fR\nOutput file path for the tool stub\n.SH \"MISE IMPLODE\"\nRemoves mise CLI and all related data\n\nSkips config directory by default.\n.PP\n\\fBUsage:\\fR mise implode [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nList directories that would be removed without actually removing them\n.TP\n\\fB\\-\\-config\\fR\nAlso remove config directory\n.SH \"MISE EDIT\"\nEdit mise.toml interactively\n.PP\n\\fBUsage:\\fR mise edit [OPTIONS] [<PATH>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nShow what would be generated without writing to file\n.TP\n\\fB\\-t, \\-\\-tool\\-versions\\fR \\fI<TOOL_VERSIONS>\\fR\nPath to a .tool\\-versions file to import tools from\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PATH>\\fR\nPath to the config file to create\n.SH \"MISE INSTALL\"\nInstall a tool version\n\nInstalls a tool version to `~/.local/share/mise/installs/<PLUGIN>/<VERSION>`\nInstalling alone will not activate the tools so they won't be in PATH.\nTo install and/or activate in one command, use `mise use` which will create a `mise.toml` file\nin the current directory to activate this tool when inside the directory.\nAlternatively, run `mise exec <TOOL>@<VERSION> \\-\\- <COMMAND>` to execute a tool without creating config files.\n\nTools will be installed in parallel. To disable, set `\\-\\-jobs=1` or `MISE_JOBS=1`\n.PP\n\\fBUsage:\\fR mise install [OPTIONS] [<TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce reinstall even if already installed\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nShow what would be installed without actually installing\n.TP\n\\fB\\-v, \\-\\-verbose\\fR\nShow installation output\n\nThis argument will print plugin output such as download, configuration, and compilation output.\n.TP\n\\fB\\-\\-before\\fR \\fI<BEFORE>\\fR\nOnly install versions released before this date\n\nSupports absolute dates like \"2024\\-06\\-01\" and relative durations like \"90d\" or \"1y\".\n.TP\n\\fB\\-\\-dry\\-run\\-code\\fR\nLike \\-\\-dry\\-run but exits with code 1 if there are tools to install\n\nThis is useful for scripts to check if tools need to be installed.\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets \\-\\-jobs=1\n.TP\n\\fB\\-\\-shared\\fR \\fI<SHARED>\\fR\n[experimental] Install tool(s) to a shared directory\n\nInstalls to the specified directory instead of the default install location.\nMay require elevated permissions depending on the path.\n.TP\n\\fB\\-\\-system\\fR\n[experimental] Install tool(s) to the system\\-wide shared directory\n\nInstalls to /usr/local/share/mise/installs (or MISE_SYSTEM_DATA_DIR/installs).\nMay require elevated permissions (e.g. sudo).\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to install e.g.: node@20\n.SH \"MISE INSTALL-INTO\"\nInstall a tool version to a specific path\n\nUsed for building a tool to a directory for use outside of mise\n.PP\n\\fBUsage:\\fR mise install\\-into <TOOL@VERSION> <PATH>\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool to install e.g.: node@20\n.TP\n\\fB<PATH>\\fR\nPath to install the tool into\n.SH \"MISE LATEST\"\nGets the latest available version for a plugin\n\nSupports prefixes such as `node@20` to get the latest version of node 20.\n.PP\n\\fBUsage:\\fR mise latest [OPTIONS] <TOOL@VERSION> [<ASDF_VERSION>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-i, \\-\\-installed\\fR\nShow latest installed instead of available version\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool to get the latest version of\n.TP\n\\fB<ASDF_VERSION>\\fR\nThe version prefix to use when querying the latest version same as the first argument after the \"@\" used for asdf compatibility\n.SH \"MISE LINK\"\nSymlinks a tool version into mise\n\nUse this for adding installs either custom compiled outside mise or built with a different tool.\n.PP\n\\fBUsage:\\fR mise link [OPTIONS] <TOOL@VERSION> <PATH>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-force\\fR\nOverwrite an existing tool version if it exists\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool name and version to create a symlink for\n.TP\n\\fB<PATH>\\fR\nThe local path to the tool version\ne.g.: ~/.nvm/versions/node/v20.0.0\n.SH \"MISE LOCK\"\nUpdate lockfile checksums and URLs for all specified platforms\n\nUpdates checksums and download URLs for all platforms already specified in the lockfile.\nIf no lockfile exists, shows what would be created based on the current configuration.\nThis allows you to refresh lockfile data for platforms other than the one you're currently on.\nOperates on the lockfile in the current config root. Use TOOL arguments to target specific tools.\n.PP\n\\fBUsage:\\fR mise lock [OPTIONS] [<TOOL>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nShow what would be updated without making changes\n.TP\n\\fB\\-p, \\-\\-platform\\fR \\fI<PLATFORM>\\fR\nComma\\-separated list of platforms to target\ne.g.: linux\\-x64,macos\\-arm64,windows\\-x64\nIf not specified, all platforms already in lockfile will be updated\n.TP\n\\fB\\-\\-local\\fR\nUpdate mise.local.lock instead of mise.lock\nUse for tools defined in .local.toml configs\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL>\\fR\nTool(s) to update in lockfile\ne.g.: node python\nIf not specified, all tools in lockfile will be updated\n.SH \"MISE LS\"\nList installed and active tool versions\n\nThis command lists tools that mise \"knows about\".\nThese may be tools that are currently installed, or those\nthat are in a config file (active) but may or may not be installed.\n\nIt's a useful command to get the current state of your tools.\n.PP\n\\fBUsage:\\fR mise ls [OPTIONS] [<INSTALLED_TOOL>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-c, \\-\\-current\\fR\nOnly show tool versions currently specified in a mise.toml\n.TP\n\\fB\\-g, \\-\\-global\\fR\nOnly show tool versions currently specified in the global mise.toml\n.TP\n\\fB\\-i, \\-\\-installed\\fR\nOnly show tool versions that are installed (Hides tools defined in mise.toml but not installed)\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-local\\fR\nOnly show tool versions currently specified in the local mise.toml\n.TP\n\\fB\\-m, \\-\\-missing\\fR\nDisplay missing tool versions\n.TP\n\\fB\\-o, \\-\\-offline\\fR\nDon't fetch information such as outdated versions\n.TP\n\\fB\\-p, \\-\\-plugin\\fR \\fI<TOOL_FLAG>\\fR\n.TP\n\\fB\\-\\-all\\-sources\\fR\nDisplay all tracked config sources for tools\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't display headers\n.TP\n\\fB\\-\\-outdated\\fR\nDisplay whether a version is outdated\n.TP\n\\fB\\-\\-prefix\\fR \\fI<PREFIX>\\fR\nDisplay versions matching this prefix\n.TP\n\\fB\\-\\-prunable\\fR\nList only tools that can be pruned with `mise prune`\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<INSTALLED_TOOL>\\fR\nOnly show tool versions from [TOOL]\n.SH \"MISE LS-REMOTE\"\nList runtime versions available for install.\n\nNote that the results may be cached, run `mise cache clean` to clear the cache and get fresh results.\n.PP\n\\fBUsage:\\fR mise ls\\-remote [OPTIONS] [<TOOL@VERSION>] [<PREFIX>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-all\\fR\nShow all installed plugins and versions\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format (includes version metadata like created_at timestamps when available)\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool to get versions for\n.TP\n\\fB<PREFIX>\\fR\nThe version prefix to use when querying the latest version\nsame as the first argument after the \"@\"\n.SH \"MISE OUTDATED\"\nShows outdated tool versions\n\nSee `mise upgrade` to upgrade these versions.\n.PP\n\\fBUsage:\\fR mise outdated [OPTIONS] [<TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-bump\\fR\nCompares against the latest versions available, not what matches the current config\n\nFor example, if you have `node = \"20\"` in your config by default `mise outdated` will only\nshow other 20.x versions, not 21.x or 22.x versions.\n\nUsing this flag, if there are 21.x or newer versions it will display those instead of 20.x.\n.TP\n\\fB\\-\\-local\\fR\nOnly show outdated tools defined in local config files\n\nThis will only show tools that are defined in project\\-local mise.toml and\nwill skip tools defined in the global config (~/.config/mise/config.toml).\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't show table header\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to show outdated versions for\ne.g.: node@20 python@3.10\nIf not specified, all tools in global and local configs will be shown\n.SH \"MISE PLUGINS\"\nManage plugins\n.PP\n\\fBUsage:\\fR mise plugins [OPTIONS] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nlist all available remote plugins\n\nsame as `mise plugins ls\\-remote`\n.TP\n\\fB\\-c, \\-\\-core\\fR\nThe built\\-in plugins only\nNormally these are not shown\n.TP\n\\fB\\-u, \\-\\-urls\\fR\nShow the git url for each plugin\ne.g.: https://github.com/mise\\-plugins/vfox\\-cmake.git\n.TP\n\\fB\\-\\-refs\\fR\nShow the git refs for each plugin\ne.g.: main 1234abc\n.TP\n\\fB\\-\\-user\\fR\nList installed plugins\n\nThis is the default behavior but can be used with \\-\\-core\nto show core and user plugins\n.SH \"MISE PLUGINS INSTALL\"\nInstall a plugin\n\nnote that mise automatically can install plugins when you install a tool\ne.g.: `mise install cmake@3.30` will autoinstall the cmake plugin\n\nThis behavior can be modified in ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise plugins install [OPTIONS] [<NEW_PLUGIN>] [<GIT_URL>] [<REST>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nInstall all missing plugins\nThis will only install plugins that have matching shorthands.\ni.e.: they don't need the full git repo url\n.TP\n\\fB\\-f, \\-\\-force\\fR\nReinstall even if plugin exists\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n.TP\n\\fB\\-v, \\-\\-verbose\\fR\nShow installation output\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<NEW_PLUGIN>\\fR\nThe name of the plugin to install\ne.g.: cmake, poetry\nCan specify multiple plugins: `mise plugins install cmake poetry`\n.TP\n\\fB<GIT_URL>\\fR\nThe git url of the plugin\n.SH \"MISE PLUGINS LINK\"\nSymlinks a plugin into mise\n\nThis is used for developing a plugin.\n.PP\n\\fBUsage:\\fR mise plugins link [OPTIONS] <NAME> [<DIR>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-force\\fR\nOverwrite existing plugin\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<NAME>\\fR\nThe name of the plugin\ne.g.: cmake, poetry\n.TP\n\\fB<DIR>\\fR\nThe local path to the plugin\ne.g.: ./vfox\\-cmake\n.SH \"MISE PLUGINS LS\"\nList installed plugins\n\nCan also show remotely available plugins to install.\n.PP\n\\fBUsage:\\fR mise plugins ls [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nList all available remote plugins\nSame as `mise plugins ls\\-remote`\n.TP\n\\fB\\-c, \\-\\-core\\fR\nThe built\\-in plugins only\nNormally these are not shown\n.TP\n\\fB\\-o, \\-\\-outdated\\fR\nShow plugins with available updates\nChecks the remote for newer versions and only displays plugins that are outdated\n.TP\n\\fB\\-u, \\-\\-urls\\fR\nShow the git url for each plugin\ne.g.: https://github.com/mise\\-plugins/vfox\\-cmake.git\n.TP\n\\fB\\-\\-refs\\fR\nShow the git refs for each plugin\ne.g.: main 1234abc\n.TP\n\\fB\\-\\-user\\fR\nList installed plugins\n.SH \"MISE PLUGINS LS-REMOTE\"\n\nList all available remote plugins\n\nThe full list is here: https://github.com/jdx/mise/blob/main/registry/\n\nExamples:\n\n    $ mise plugins ls\\-remote\n\n.PP\n\\fBUsage:\\fR mise plugins ls\\-remote [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-u, \\-\\-urls\\fR\nShow the git url for each plugin e.g.: https://github.com/mise\\-plugins/mise\\-poetry.git\n.TP\n\\fB\\-\\-only\\-names\\fR\nOnly show the name of each plugin by default it will show a \"*\" next to installed plugins\n.SH \"MISE PLUGINS UNINSTALL\"\nRemoves a plugin\n.PP\n\\fBUsage:\\fR mise plugins uninstall [OPTIONS] [<PLUGIN>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nRemove all plugins\n.TP\n\\fB\\-p, \\-\\-purge\\fR\nAlso remove the plugin's installs, downloads, and cache\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nPlugin(s) to remove\n.SH \"MISE PLUGINS UPDATE\"\nUpdates a plugin to the latest version\n\nnote: this updates the plugin itself, not the runtime versions\n.PP\n\\fBUsage:\\fR mise plugins update [OPTIONS] [<PLUGIN>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\nDefault: 4\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PLUGIN>\\fR\nPlugin(s) to update\n.SH \"MISE PREPARE\"\n[experimental] Ensure project dependencies are ready\n\nRuns all applicable prepare steps for the current project.\nThis checks if dependency lockfiles are newer than installed outputs\n(e.g., package\\-lock.json vs node_modules/) and runs install commands\nif needed.\n\nProviders with `auto = true` are automatically invoked before `mise x` and `mise run`\nunless skipped with the \\-\\-no\\-prepare flag.\n.PP\n\\fBUsage:\\fR mise prepare [OPTIONS] [<PROVIDER>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-explain\\fR\nShow why a provider is fresh or stale (requires a provider argument)\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce run all prepare steps even if outputs are fresh\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nOnly check if prepare is needed, don't run commands\n.TP\n\\fB\\-\\-list\\fR\nShow what prepare steps are available\n.TP\n\\fB\\-\\-only\\fR \\fI<ONLY>\\fR\nRun specific prepare rule(s) only\n.TP\n\\fB\\-\\-skip\\fR \\fI<SKIP>\\fR\nSkip specific prepare rule(s)\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<PROVIDER>\\fR\nProvider to operate on (runs only this provider, or use with \\-\\-explain)\n.SH \"MISE PRUNE\"\nDelete unused versions of tools\n\nmise tracks which config files have been used in ~/.local/state/mise/tracked\\-configs\nVersions which are no longer the latest specified in any of those configs are deleted.\nVersions installed only with environment variables `MISE_<PLUGIN>_VERSION` will be deleted,\nas will versions only referenced on the command line `mise exec <PLUGIN>@<VERSION>`.\n\nYou can list prunable tools with `mise ls \\-\\-prunable`\n.PP\n\\fBUsage:\\fR mise prune [OPTIONS] [<INSTALLED_TOOL>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nDo not actually delete anything\n.TP\n\\fB\\-\\-configs\\fR\nPrune only tracked and trusted configuration links that point to non\\-existent configurations\n.TP\n\\fB\\-\\-dry\\-run\\-code\\fR\nLike \\-\\-dry\\-run but exits with code 1 if there are tools to prune\n\nThis is useful for scripts to check if tools need to be pruned.\n.TP\n\\fB\\-\\-tools\\fR\nPrune only unused versions of tools\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<INSTALLED_TOOL>\\fR\nPrune only these tools\n.SH \"MISE REGISTRY\"\nList available tools to install\n\nThis command lists the tools available in the registry as shorthand names.\n\nFor example, `poetry` is shorthand for `asdf:mise\\-plugins/mise\\-poetry`.\n.PP\n\\fBUsage:\\fR mise registry [OPTIONS] [<NAME>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-b, \\-\\-backend\\fR \\fI<BACKEND>\\fR\nShow only tools for this backend\n.TP\n\\fB\\-\\-complete\\fR\nPrint all tools with descriptions for shell completions\n.TP\n\\fB\\-\\-hide\\-aliased\\fR\nHide aliased tools\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<NAME>\\fR\nShow only the specified tool's full name\n.SH \"MISE RESHIM\"\nCreates new shims based on bin paths from currently installed tools.\n\nThis creates new shims in ~/.local/share/mise/shims for CLIs that have been added.\nmise will try to do this automatically for commands like `npm i \\-g` but there are\nother ways to install things (like using yarn or pnpm for node) that mise does\nnot know about and so it will be necessary to call this explicitly.\n\nIf you think mise should automatically call this for a particular command, please\nopen an issue on the mise repo. You can also setup a shell function to reshim\nautomatically (it's really fast so you don't need to worry about overhead):\n\n    npm() {\n      command npm \"$@\"\n      mise reshim\n    }\n\nNote that this creates shims for _all_ installed tools, not just the ones that are\ncurrently active in mise.toml.\n.PP\n\\fBUsage:\\fR mise reshim [OPTIONS] [<PLUGIN>] [<VERSION>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-force\\fR\nRemoves all shims before reshimming\n.SH \"MISE RUN\"\nRun task(s)\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n    [tasks.build]\n    run = \"npm run build\"\n    sources = [\"src/**/*.ts\"]\n    outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise\\-tasks`, `.mise\\-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n    $ cat .mise/tasks/build<<EOF\n    #!/usr/bin/env bash\n    npm run build\n    EOF\n    $ mise run build\n.PP\n\\fBUsage:\\fR mise run [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-c, \\-\\-continue\\-on\\-error\\fR\nContinue running tasks even if one fails\n.TP\n\\fB\\-C, \\-\\-cd\\fR \\fI<CD>\\fR\nChange to this directory before executing the command\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce the tasks to run even if outputs are up to date\n.TP\n\\fB\\-i, \\-\\-interleave\\fR\nPrint directly to stdout/stderr instead of by line\nDefaults to true if \\-\\-jobs == 1\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of tasks to run in parallel\n[default: 4]\nConfigure with `jobs` config or `MISE_JOBS` env var\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nDon't actually run the task(s), just print them in order of execution\n.TP\n\\fB\\-o, \\-\\-output\\fR \\fI<OUTPUT>\\fR\nChange how tasks information is output when running tasks\n\n\\- `prefix` \\- Print stdout/stderr by line, prefixed with the task's label\n\\- `interleave` \\- Print directly to stdout/stderr instead of by line\n\\- `replacing` \\- Stdout is replaced each time, stderr is printed as is\n\\- `timed` \\- Only show stdout lines if they are displayed for more than 1 second\n\\- `keep\\-order` \\- Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n\\- `quiet` \\- Don't show extra output\n\\- `silent` \\- Don't show any output including stdout and stderr from the task except for errors\n.TP\n\\fB\\-p, \\-\\-prefix\\fR\nPrint stdout/stderr by line, prefixed with the task's label\nDefaults to true if \\-\\-jobs > 1\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nDon't show extra output\n.TP\n\\fB\\-r, \\-\\-raw\\fR\nRead/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\nShell to use to run toml tasks\n\nDefaults to `sh \\-c \\-o errexit \\-o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task.\n.TP\n\\fB\\-S, \\-\\-silent\\fR\nDon't show any output except for errors\n.TP\n\\fB\\-t, \\-\\-tool\\fR \\fI<TOOL@VERSION>\\fR\nTool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\n.TP\n\\fB\\-\\-fresh\\-env\\fR\nBypass the environment cache and recompute the environment\n.TP\n\\fB\\-\\-no\\-cache\\fR\nDo not use cache on remote tasks\n.TP\n\\fB\\-\\-no\\-prepare\\fR\nSkip automatic dependency preparation\n.TP\n\\fB\\-\\-no\\-timings\\fR\nHides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`\n.TP\n\\fB\\-\\-skip\\-deps\\fR\nRun only the specified tasks skipping all dependencies\n.TP\n\\fB\\-\\-timeout\\fR \\fI<TIMEOUT>\\fR\nTimeout for the task to complete\ne.g.: 30s, 5m\n.TP\n\\fB\\-\\-timings\\fR\nShows elapsed time after each task completes\n\nDefault to always show with `MISE_TASK_TIMINGS=1`\n.SH \"MISE SEARCH\"\nSearch for tools in the registry\n\nThis command searches a tool in the registry.\n\nBy default, it will show all tools that fuzzy match the search term. For\nnon\\-fuzzy matches, use the `\\-\\-match\\-type` flag.\n.PP\n\\fBUsage:\\fR mise search [OPTIONS] [<NAME>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-i, \\-\\-interactive\\fR\nShow interactive search\n.TP\n\\fB\\-m, \\-\\-match\\-type\\fR \\fI<MATCH_TYPE>\\fR\nMatch type: equal, contains, or fuzzy\n.RS\n\\fIDefault: \\fRfuzzy\n.RE\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't display headers\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<NAME>\\fR\nThe tool to search for\n.SH \"MISE SELF-UPDATE\"\nUpdates mise itself.\n\nUses the GitHub Releases API to find the latest release and binary.\nBy default, this will also update any installed plugins.\nUses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits.\n\nThis command is not available if mise is installed via a package manager.\n.PP\n\\fBUsage:\\fR mise self\\-update [OPTIONS] [<VERSION>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-force\\fR\nUpdate even if already up to date\n.TP\n\\fB\\-y, \\-\\-yes\\fR\nSkip confirmation prompt\n.TP\n\\fB\\-\\-no\\-plugins\\fR\nDisable auto\\-updating plugins\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<VERSION>\\fR\nUpdate to a specific version\n.SH \"MISE SET\"\nSet environment variables in mise.toml\n\nBy default, this command modifies `mise.toml` in the current directory.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee https://mise.jdx.dev/configuration.html#target\\-file\\-for\\-write\\-operations\n\nUse `\\-E <env>` to create/modify environment\\-specific config files like `mise.<env>.toml`.\n.PP\n\\fBUsage:\\fR mise set [OPTIONS] [<ENV_VAR>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-E, \\-\\-env\\fR \\fI<ENV>\\fR\nCreate/modify an environment\\-specific config file like .mise.<env>.toml\n.TP\n\\fB\\-g, \\-\\-global\\fR\nSet the environment variable in the global config file\n.TP\n\\fB\\-\\-age\\-encrypt\\fR\n[experimental] Encrypt the value with age before storing\n.TP\n\\fB\\-\\-age\\-key\\-file\\fR \\fI<PATH>\\fR\n[experimental] Age identity file for encryption\n\nDefaults to ~/.config/mise/age.txt if it exists\n.TP\n\\fB\\-\\-age\\-recipient\\fR \\fI<RECIPIENT>\\fR\n[experimental] Age recipient (x25519 public key) for encryption\n\nCan be used multiple times. Requires \\-\\-age\\-encrypt.\n.TP\n\\fB\\-\\-age\\-ssh\\-recipient\\fR \\fI<PATH_OR_PUBKEY>\\fR\n[experimental] SSH recipient (public key or path) for age encryption\n\nCan be used multiple times. Requires \\-\\-age\\-encrypt.\n.TP\n\\fB\\-\\-complete\\fR\nRender completions\n.TP\n\\fB\\-\\-file\\fR \\fI<FILE>\\fR\nThe TOML file to update\n\nCan be a file path or directory. If a directory is provided, will create/use mise.toml in that directory.\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`.\n.TP\n\\fB\\-\\-no\\-redact\\fR\nShow raw values instead of redacting secrets\n.TP\n\\fB\\-\\-prompt\\fR\nPrompt for environment variable values\n.TP\n\\fB\\-\\-remove, \\-\\-rm, \\-\\-unset\\fR \\fI<ENV_KEY>\\fR\nRemove the environment variable from config file\n\nCan be used multiple times.\n.TP\n\\fB\\-\\-stdin\\fR\nRead the value from stdin (for multiline input)\n\nWhen using \\-\\-stdin, provide a single key without a value. The value will be read from stdin until EOF.\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<ENV_VAR>\\fR\nEnvironment variable(s) to set\ne.g.: NODE_ENV=production\n.SH \"MISE SETTINGS\"\nShow current settings\n\nThis is the contents of ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool\\-alias`\n.PP\n\\fBUsage:\\fR mise settings [OPTIONS] [<SETTING>] [<VALUE>] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nList all settings\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n.TP\n\\fB\\-T, \\-\\-toml\\fR\nOutput in TOML format\n.TP\n\\fB\\-\\-complete\\fR\nPrint all settings with descriptions for shell completions\n.TP\n\\fB\\-\\-json\\-extended\\fR\nOutput in JSON format with sources\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SETTING>\\fR\nName of setting\n.TP\n\\fB<VALUE>\\fR\nSetting value to set\n.SH \"MISE SETTINGS ADD\"\nAdds a setting to the configuration file\n\nUsed with an array setting, this will append the value to the array.\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise settings add [OPTIONS] <SETTING> [<VALUE>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SETTING>\\fR\nThe setting to set\n.TP\n\\fB<VALUE>\\fR\nThe value to set (optional if provided as KEY=VALUE)\n.SH \"MISE SETTINGS GET\"\nShow a current setting\n\nThis is the contents of a single entry in ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool\\-alias get`\n.PP\n\\fBUsage:\\fR mise settings get [OPTIONS] <SETTING>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SETTING>\\fR\nThe setting to show\n.SH \"MISE SETTINGS LS\"\nShow current settings\n\nThis is the contents of ~/.config/mise/config.toml\n\nNote that aliases are also stored in this file\nbut managed separately with `mise tool\\-alias`\n.PP\n\\fBUsage:\\fR mise settings ls [OPTIONS] [<SETTING>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nList all settings\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n.TP\n\\fB\\-T, \\-\\-toml\\fR\nOutput in TOML format\n.TP\n\\fB\\-\\-complete\\fR\nPrint all settings with descriptions for shell completions\n.TP\n\\fB\\-\\-json\\-extended\\fR\nOutput in JSON format with sources\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SETTING>\\fR\nName of setting\n.SH \"MISE SETTINGS SET\"\nAdd/update a setting\n\nThis modifies the contents of ~/.config/mise/config.toml by default.\nWith `\\-\\-local`, modifies the local config file instead.\nSee https://mise.jdx.dev/configuration.html#target\\-file\\-for\\-write\\-operations\n.PP\n\\fBUsage:\\fR mise settings set [OPTIONS] <SETTING> [<VALUE>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<SETTING>\\fR\nThe setting to set\n.TP\n\\fB<VALUE>\\fR\nThe value to set (optional if provided as KEY=VALUE)\n.SH \"MISE SETTINGS UNSET\"\nClears a setting\n\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise settings unset [OPTIONS] <KEY>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-l, \\-\\-local\\fR\nUse the local config file instead of the global one\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<KEY>\\fR\nThe setting to remove\n.SH \"MISE SHELL\"\nSets a tool version for the current session.\n\nOnly works in a session where mise is already activated.\n\nThis works by setting environment variables for the current shell session\nsuch as `MISE_NODE_VERSION=20` which is \"eval\"ed as a shell function created by `mise activate`.\n.PP\n\\fBUsage:\\fR mise shell [OPTIONS] <TOOL@VERSION> ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-u, \\-\\-unset\\fR\nRemoves a previously set version\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets \\-\\-jobs=1\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to use\n.SH \"MISE SHELL-ALIAS\"\nManage shell aliases.\n.PP\n\\fBUsage:\\fR mise shell\\-alias [OPTIONS] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't show table header\n.SH \"MISE SHELL-ALIAS GET\"\nShow the command for a shell alias\n.PP\n\\fBUsage:\\fR mise shell\\-alias get <shell_alias>\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<shell_alias>\\fR\nThe alias to show\n.SH \"MISE SHELL-ALIAS LS\"\nList shell aliases\n\nShows the shell aliases that are set in the current directory.\nThese are defined in `mise.toml` under the `[shell_alias]` section.\n.PP\n\\fBUsage:\\fR mise shell\\-alias ls [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-no\\-header\\fR\nDon't show table header\n.SH \"MISE SHELL-ALIAS SET\"\nAdd/update a shell alias\n\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise shell\\-alias set <shell_alias> [<COMMAND>]\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<shell_alias>\\fR\nThe alias name\n.TP\n\\fB<COMMAND>\\fR\nThe command to run (optional if provided as ALIAS=COMMAND)\n.SH \"MISE SHELL-ALIAS UNSET\"\nRemoves a shell alias\n\nThis modifies the contents of ~/.config/mise/config.toml\n.PP\n\\fBUsage:\\fR mise shell\\-alias unset <shell_alias>\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<shell_alias>\\fR\nThe alias to remove\n.SH \"MISE SYNC NODE\"\nSymlinks all tool versions from an external tool into mise\n\nFor example, use this to import all Homebrew node installs into mise\n\nThis won't overwrite any existing installs but will overwrite any existing symlinks\n.PP\n\\fBUsage:\\fR mise sync node [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-brew\\fR\nGet tool versions from Homebrew\n.TP\n\\fB\\-\\-nodenv\\fR\nGet tool versions from nodenv\n.TP\n\\fB\\-\\-nvm\\fR\nGet tool versions from nvm\n.SH \"MISE SYNC PYTHON\"\nSymlinks all tool versions from an external tool into mise\n\nFor example, use this to import all pyenv installs into mise\n\nThis won't overwrite any existing installs but will overwrite any existing symlinks\n.PP\n\\fBUsage:\\fR mise sync python [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-pyenv\\fR\nGet tool versions from pyenv\n.TP\n\\fB\\-\\-uv\\fR\nSync tool versions with uv (2\\-way sync)\n.SH \"MISE SYNC RUBY\"\nSymlinks all ruby tool versions from an external tool into mise\n.PP\n\\fBUsage:\\fR mise sync ruby [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-brew\\fR\nGet tool versions from Homebrew\n.SH \"MISE TASKS\"\nManage tasks\n.PP\n\\fBUsage:\\fR mise tasks [OPTIONS] [<TASK>] [COMMAND]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-g, \\-\\-global\\fR\nOnly show global tasks\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-local\\fR\nOnly show non\\-global tasks\n.TP\n\\fB\\-x, \\-\\-extended\\fR\nShow all columns\n.TP\n\\fB\\-\\-all\\fR\nLoad all tasks from the entire monorepo, including sibling directories.\nBy default, only tasks from the current directory hierarchy are loaded.\n.TP\n\\fB\\-\\-complete\\fR\nDisplay tasks for usage completion\n.TP\n\\fB\\-\\-hidden\\fR\nShow hidden tasks\n.TP\n\\fB\\-\\-no\\-header\\fR\nDo not print table header\n.TP\n\\fB\\-\\-sort\\fR \\fI<COLUMN>\\fR\nSort by column. Default is name.\n.TP\n\\fB\\-\\-sort\\-order\\fR \\fI<SORT_ORDER>\\fR\nSort order. Default is asc.\n.TP\n\\fB\\-\\-usage\\fR\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nTask name to get info of\n.SH \"MISE TASKS ADD\"\nCreate a new task\n\nAdds a task to the local mise.toml file.\nSee https://mise.jdx.dev/configuration.html#target\\-file\\-for\\-write\\-operations\n.PP\n\\fBUsage:\\fR mise tasks add [OPTIONS] <TASK> [<RUN>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-alias\\fR \\fI<ALIAS>\\fR\nOther names for the task\n.TP\n\\fB\\-d, \\-\\-depends\\fR \\fI<DEPENDS>\\fR\nAdd dependencies to the task\n.TP\n\\fB\\-D, \\-\\-dir\\fR \\fI<DIR>\\fR\nRun the task in a specific directory\n.TP\n\\fB\\-f, \\-\\-file\\fR\nCreate a file task instead of a toml task\n.TP\n\\fB\\-H, \\-\\-hide\\fR\nHide the task from `mise tasks` and completions\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nDo not print the command before running\n.TP\n\\fB\\-r, \\-\\-raw\\fR\nDirectly connect stdin/stdout/stderr\n.TP\n\\fB\\-s, \\-\\-sources\\fR \\fI<SOURCES>\\fR\nGlob patterns of files this task uses as input\n.TP\n\\fB\\-w, \\-\\-wait\\-for\\fR \\fI<WAIT_FOR>\\fR\nWait for these tasks to complete if they are to run\n.TP\n\\fB\\-\\-depends\\-post\\fR \\fI<DEPENDS_POST>\\fR\nDependencies to run after the task runs\n.TP\n\\fB\\-\\-description\\fR \\fI<DESCRIPTION>\\fR\nDescription of the task\n.TP\n\\fB\\-\\-outputs\\fR \\fI<OUTPUTS>\\fR\nGlob patterns of files this task creates, to skip if they are not modified\n.TP\n\\fB\\-\\-run\\-windows\\fR \\fI<RUN_WINDOWS>\\fR\nCommand to run on windows\n.TP\n\\fB\\-\\-shell\\fR \\fI<SHELL>\\fR\nRun the task in a specific shell\n.TP\n\\fB\\-\\-silent\\fR\nDo not print the command or its output\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nTasks name to add\n.SH \"MISE TASKS DEPS\"\nDisplay a tree visualization of a dependency graph\n.PP\n\\fBUsage:\\fR mise tasks deps [OPTIONS] [<TASKS>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-dot\\fR\nDisplay dependencies in DOT format\n.TP\n\\fB\\-\\-hidden\\fR\nShow hidden tasks\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASKS>\\fR\nTasks to show dependencies for\nCan specify multiple tasks by separating with spaces\ne.g.: mise tasks deps lint test check\n.SH \"MISE TASKS EDIT\"\nEdit a task with $EDITOR\n\nThe task will be created as a standalone script if it does not already exist.\n.PP\n\\fBUsage:\\fR mise tasks edit [OPTIONS] <TASK>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-p, \\-\\-path\\fR\nDisplay the path to the task instead of editing it\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nTask to edit\n.SH \"MISE TASKS INFO\"\nGet information about a task\n.PP\n\\fBUsage:\\fR mise tasks info [OPTIONS] <TASK>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nName of the task to get information about\n.SH \"MISE TASKS LS\"\nList available tasks to execute\nThese may be included from the config file or from the project's .mise/tasks directory\nmise will merge all tasks from all parent directories into this list.\n\nSo if you have global tasks in `~/.config/mise/tasks/*` and project\\-specific tasks in\n~/myproject/.mise/tasks/*, then they'll both be available but the project\\-specific\ntasks will override the global ones if they have the same name.\n.PP\n\\fBUsage:\\fR mise tasks ls [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-g, \\-\\-global\\fR\nOnly show global tasks\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-l, \\-\\-local\\fR\nOnly show non\\-global tasks\n.TP\n\\fB\\-x, \\-\\-extended\\fR\nShow all columns\n.TP\n\\fB\\-\\-all\\fR\nLoad all tasks from the entire monorepo, including sibling directories.\nBy default, only tasks from the current directory hierarchy are loaded.\n.TP\n\\fB\\-\\-complete\\fR\nDisplay tasks for usage completion\n.TP\n\\fB\\-\\-hidden\\fR\nShow hidden tasks\n.TP\n\\fB\\-\\-no\\-header\\fR\nDo not print table header\n.TP\n\\fB\\-\\-sort\\fR \\fI<COLUMN>\\fR\nSort by column. Default is name.\n.TP\n\\fB\\-\\-sort\\-order\\fR \\fI<SORT_ORDER>\\fR\nSort order. Default is asc.\n.TP\n\\fB\\-\\-usage\\fR\n.SH \"MISE TASKS RUN\"\nRun task(s)\n\nThis command will run a task, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a task, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n    [tasks.build]\n    run = \"npm run build\"\n    sources = [\"src/**/*.ts\"]\n    outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise\\-tasks`, `.mise\\-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n    $ cat .mise/tasks/build<<EOF\n    #!/usr/bin/env bash\n    npm run build\n    EOF\n    $ mise run build\n.PP\n\\fBUsage:\\fR mise tasks run [OPTIONS] [<TASK>] [<ARGS>] ... [<ARGS_LAST>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-c, \\-\\-continue\\-on\\-error\\fR\nContinue running tasks even if one fails\n.TP\n\\fB\\-C, \\-\\-cd\\fR \\fI<CD>\\fR\nChange to this directory before executing the command\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce the tasks to run even if outputs are up to date\n.TP\n\\fB\\-i, \\-\\-interleave\\fR\nPrint directly to stdout/stderr instead of by line\nDefaults to true if \\-\\-jobs == 1\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of tasks to run in parallel\n[default: 4]\nConfigure with `jobs` config or `MISE_JOBS` env var\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nDon't actually run the task(s), just print them in order of execution\n.TP\n\\fB\\-o, \\-\\-output\\fR \\fI<OUTPUT>\\fR\nChange how tasks information is output when running tasks\n\n\\- `prefix` \\- Print stdout/stderr by line, prefixed with the task's label\n\\- `interleave` \\- Print directly to stdout/stderr instead of by line\n\\- `replacing` \\- Stdout is replaced each time, stderr is printed as is\n\\- `timed` \\- Only show stdout lines if they are displayed for more than 1 second\n\\- `keep\\-order` \\- Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n\\- `quiet` \\- Don't show extra output\n\\- `silent` \\- Don't show any output including stdout and stderr from the task except for errors\n.TP\n\\fB\\-p, \\-\\-prefix\\fR\nPrint stdout/stderr by line, prefixed with the task's label\nDefaults to true if \\-\\-jobs > 1\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nDon't show extra output\n.TP\n\\fB\\-r, \\-\\-raw\\fR\nRead/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var\n.TP\n\\fB\\-s, \\-\\-shell\\fR \\fI<SHELL>\\fR\nShell to use to run toml tasks\n\nDefaults to `sh \\-c \\-o errexit \\-o pipefail` on unix, and `cmd /c` on Windows\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\nOr it can be overridden with the `shell` property on a task.\n.TP\n\\fB\\-S, \\-\\-silent\\fR\nDon't show any output except for errors\n.TP\n\\fB\\-t, \\-\\-tool\\fR \\fI<TOOL@VERSION>\\fR\nTool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\n.TP\n\\fB\\-\\-fresh\\-env\\fR\nBypass the environment cache and recompute the environment\n.TP\n\\fB\\-\\-no\\-cache\\fR\nDo not use cache on remote tasks\n.TP\n\\fB\\-\\-no\\-prepare\\fR\nSkip automatic dependency preparation\n.TP\n\\fB\\-\\-no\\-timings\\fR\nHides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`\n.TP\n\\fB\\-\\-skip\\-deps\\fR\nRun only the specified tasks skipping all dependencies\n.TP\n\\fB\\-\\-timeout\\fR \\fI<TIMEOUT>\\fR\nTimeout for the task to complete\ne.g.: 30s, 5m\n.TP\n\\fB\\-\\-timings\\fR\nShows elapsed time after each task completes\n\nDefault to always show with `MISE_TASK_TIMINGS=1`\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nTasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\n.RS\n\\fIDefault: \\fRdefault\n.RE\n.TP\n\\fB<ARGS>\\fR\nArguments to pass to the tasks. Use \":::\" to separate tasks\n.TP\n\\fB<ARGS_LAST>\\fR\nArguments to pass to the tasks. Use \":::\" to separate tasks\n.SH \"MISE TASKS VALIDATE\"\nValidate tasks for common errors and issues\n.PP\n\\fBUsage:\\fR mise tasks validate [OPTIONS] [<TASKS>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-\\-errors\\-only\\fR\nOnly show errors (skip warnings)\n.TP\n\\fB\\-\\-json\\fR\nOutput validation results in JSON format\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASKS>\\fR\nTasks to validate\nIf not specified, validates all tasks\n.SH \"MISE TEST-TOOL\"\nTest a tool installs and executes\n.PP\n\\fBUsage:\\fR mise test\\-tool [OPTIONS] [<TOOLS>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nTest every tool specified in registry/\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-\\-all\\-config\\fR\nTest all tools specified in config files\n.TP\n\\fB\\-\\-include\\-non\\-defined\\fR\nAlso test tools not defined in registry/, guessing how to test it\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets \\-\\-jobs=1\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOLS>\\fR\nTool(s) to test\n.SH \"MISE TOOL\"\nGets information about a tool\n.PP\n\\fBUsage:\\fR mise tool [OPTIONS] <TOOL>\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nOutput in JSON format\n.TP\n\\fB\\-\\-active\\fR\nOnly show active versions\n.TP\n\\fB\\-\\-backend\\fR\nOnly show backend field\n.TP\n\\fB\\-\\-config\\-source\\fR\nOnly show config source\n.TP\n\\fB\\-\\-description\\fR\nOnly show description field\n.TP\n\\fB\\-\\-installed\\fR\nOnly show installed versions\n.TP\n\\fB\\-\\-requested\\fR\nOnly show requested versions\n.TP\n\\fB\\-\\-tool\\-options\\fR\nOnly show tool options\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL>\\fR\nTool name to get information about\n.SH \"MISE TOOL-STUB\"\nExecute a tool stub\n\nTool stubs are executable files containing TOML configuration that specify which tool to run and how to run it. They provide a convenient way to create portable, self\\-contained executables that automatically manage tool installation and execution.\n\nA tool stub consists of: \\- A shebang line: #!/usr/bin/env \\-S mise tool\\-stub \\- TOML configuration specifying the tool, version, and options \\- Optional comments describing the tool's purpose\n\nExample stub file: #!/usr/bin/env \\-S mise tool\\-stub # Node.js v20 development environment\n\ntool = \"node\" version = \"20.0.0\" bin = \"node\"\n\nThe stub will automatically install the specified tool version if missing and execute it with any arguments passed to the stub.\n\nFor more information, see: https://mise.jdx.dev/dev\\-tools/tool\\-stubs.html\n.PP\n\\fBUsage:\\fR mise tool\\-stub <FILE> [<ARGS>] ...\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<FILE>\\fR\nPath to the TOML tool stub file to execute\n\nThe stub file must contain TOML configuration specifying the tool and version to run. At minimum, it should specify a 'version' field. Other common fields include 'tool', 'bin', and backend\\-specific options.\n.TP\n\\fB<ARGS>\\fR\nArguments to pass to the tool\n\nAll arguments after the stub file path will be forwarded to the underlying tool. Use '\\-\\-' to separate mise arguments from tool arguments if needed.\n.SH \"MISE TRUST\"\nMarks a config file as trusted\n\nThis means mise will parse the file with potentially dangerous\nfeatures enabled.\n\nThis includes:\n\\- environment variables\n\\- templates\n\\- `path:` plugin versions\n.PP\n\\fBUsage:\\fR mise trust [OPTIONS] [<CONFIG_FILE>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nTrust all config files in the current directory and its parents\n.TP\n\\fB\\-\\-ignore\\fR\nDo not trust this config and ignore it in the future\n.TP\n\\fB\\-\\-show\\fR\nShow the trusted status of config files from the current directory and its parents.\nDoes not trust or untrust any files.\n.TP\n\\fB\\-\\-untrust\\fR\nNo longer trust this config, will prompt in the future\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<CONFIG_FILE>\\fR\nThe config file to trust\n.SH \"MISE UNINSTALL\"\nRemoves installed tool versions\n\nThis only removes the installed version, it does not modify mise.toml.\n.PP\n\\fBUsage:\\fR mise uninstall [OPTIONS] [<INSTALLED_TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-a, \\-\\-all\\fR\nDelete all installed versions\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nDo not actually delete anything\n.TP\n\\fB\\-\\-dry\\-run\\-code\\fR\nLike \\-\\-dry\\-run but exits with code 1 if there are tools to uninstall\n\nThis is useful for scripts to check if tools need to be uninstalled.\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<INSTALLED_TOOL@VERSION>\\fR\nTool(s) to remove\n.SH \"MISE UNSET\"\nRemove environment variable(s) from the config file.\n\nBy default, this command modifies `mise.toml` in the current directory.\n.PP\n\\fBUsage:\\fR mise unset [OPTIONS] [<ENV_KEY>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-f, \\-\\-file\\fR \\fI<FILE>\\fR\nSpecify a file to use instead of `mise.toml`\n.TP\n\\fB\\-g, \\-\\-global\\fR\nUse the global config file\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<ENV_KEY>\\fR\nEnvironment variable(s) to remove\ne.g.: NODE_ENV\n.SH \"MISE UNUSE\"\nRemoves installed tool versions from mise.toml\n\nBy default, this will use the `mise.toml` file that has the tool defined.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee https://mise.jdx.dev/configuration.html#target\\-file\\-for\\-write\\-operations\n\nIn the following order:\n  \\- If `\\-\\-global` is set, it will use the global config file.\n  \\- If `\\-\\-path` is set, it will use the config file at the given path.\n  \\- If `\\-\\-env` is set, it will use `mise.<env>.toml`.\n  \\- If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n  \\- If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n  \\- Otherwise just \"mise.toml\" or global config if cwd is home directory.\n\nWill also prune the installed version if no other configurations are using it.\n.PP\n\\fBUsage:\\fR mise unuse [OPTIONS] <INSTALLED_TOOL@VERSION> ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-e, \\-\\-env\\fR \\fI<ENV>\\fR\nCreate/modify an environment\\-specific config file like .mise.<env>.toml\n.TP\n\\fB\\-g, \\-\\-global\\fR\nUse the global config file (`~/.config/mise/config.toml`) instead of the local one\n.TP\n\\fB\\-p, \\-\\-path\\fR \\fI<PATH>\\fR\nSpecify a path to a config file or directory\n\nIf a directory is specified, it will look for a config file in that directory following the rules above.\n.TP\n\\fB\\-\\-no\\-prune\\fR\nDo not also prune the installed version\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<INSTALLED_TOOL@VERSION>\\fR\nTool(s) to remove\n.SH \"MISE UPGRADE\"\nUpgrades outdated tools\n\nBy default, this keeps the range specified in mise.toml. So if you have node@20 set, it will\nupgrade to the latest 20.x.x version available. See the `\\-\\-bump` flag to use the latest version\nand bump the version in mise.toml.\n\nThis will update mise.lock if it is enabled, see https://mise.jdx.dev/configuration/settings.html#lockfile\n.PP\n\\fBUsage:\\fR mise upgrade [OPTIONS] [<INSTALLED_TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-i, \\-\\-interactive\\fR\nDisplay multiselect menu to choose which tools to upgrade\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-l, \\-\\-bump\\fR\nUpgrades to the latest version available, bumping the version in mise.toml\n\nFor example, if you have `node = \"20.0.0\"` in your mise.toml but 22.1.0 is the latest available,\nthis will install 22.1.0 and set `node = \"22.1.0\"` in your config.\n\nIt keeps the same precision as what was there before, so if you instead had `node = \"20\"`, it\nwould change your config to `node = \"22\"`.\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nJust print what would be done, don't actually do it\n.TP\n\\fB\\-x, \\-\\-exclude\\fR \\fI<INSTALLED_TOOL>\\fR\nTool(s) to exclude from upgrading\ne.g.: go python\n.TP\n\\fB\\-\\-before\\fR \\fI<BEFORE>\\fR\nOnly upgrade to versions released before this date\n\nSupports absolute dates like \"2024\\-06\\-01\" and relative durations like \"90d\" or \"1y\".\nThis can be useful for reproducibility or security purposes.\n\nThis only affects fuzzy version matches like \"20\" or \"latest\".\nExplicitly pinned versions like \"22.5.0\" are not filtered.\n.TP\n\\fB\\-\\-dry\\-run\\-code\\fR\nLike \\-\\-dry\\-run but exits with code 1 if there are outdated tools\n\nThis is useful for scripts to check if tools need to be upgraded.\n.TP\n\\fB\\-\\-local\\fR\nOnly upgrade tools defined in local config files\n\nThis will only upgrade tools that are defined in project\\-local mise.toml and\nwill skip tools defined in the global config (~/.config/mise/config.toml).\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets \\-\\-jobs=1\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<INSTALLED_TOOL@VERSION>\\fR\nTool(s) to upgrade\ne.g.: node@20 python@3.10\nIf not specified, all current tools will be upgraded\n.SH \"MISE USE\"\nInstalls a tool and adds the version to mise.toml.\n\nThis will install the tool version if it is not already installed.\nBy default, this will use a `mise.toml` file in the current directory.\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\nthe lowest precedence file (`mise.toml`) will be used.\nSee https://mise.jdx.dev/configuration.html#target\\-file\\-for\\-write\\-operations\n\nIn the following order:\n  \\- If `\\-\\-global` is set, it will use the global config file.\n  \\- If `\\-\\-path` is set, it will use the config file at the given path.\n  \\- If `\\-\\-env` is set, it will use `mise.<env>.toml`.\n  \\- If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n  \\- If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n  \\- Otherwise just \"mise.toml\" or global config if cwd is home directory.\n\nUse the `\\-\\-global` flag to use the global config file instead.\n.PP\n\\fBUsage:\\fR mise use [OPTIONS] [<TOOL@VERSION>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-e, \\-\\-env\\fR \\fI<ENV>\\fR\nCreate/modify an environment\\-specific config file like .mise.<env>.toml\n.TP\n\\fB\\-f, \\-\\-force\\fR\nForce reinstall even if already installed\n.TP\n\\fB\\-g, \\-\\-global\\fR\nUse the global config file (`~/.config/mise/config.toml`) instead of the local one\n.TP\n\\fB\\-j, \\-\\-jobs\\fR \\fI<JOBS>\\fR\nNumber of jobs to run in parallel\n[default: 4]\n.TP\n\\fB\\-n, \\-\\-dry\\-run\\fR\nPerform a dry run, showing what would be installed and modified without making changes\n.TP\n\\fB\\-p, \\-\\-path\\fR \\fI<PATH>\\fR\nSpecify a path to a config file or directory\n\nIf a directory is specified, it will look for a config file in that directory following the rules above.\n.TP\n\\fB\\-\\-before\\fR \\fI<BEFORE>\\fR\nOnly install versions released before this date\n\nSupports absolute dates like \"2024\\-06\\-01\" and relative durations like \"90d\" or \"1y\".\n.TP\n\\fB\\-\\-dry\\-run\\-code\\fR\nLike \\-\\-dry\\-run but exits with code 1 if there are changes to make\n\nThis is useful for scripts to check if tools need to be added or removed.\n.TP\n\\fB\\-\\-fuzzy\\fR\nSave fuzzy version to config file\n\ne.g.: `mise use \\-\\-fuzzy node@20` will save 20 as the version\nthis is the default behavior unless `MISE_PIN=1`\n.TP\n\\fB\\-\\-pin\\fR\nSave exact version to config file\ne.g.: `mise use \\-\\-pin node@20` will save 20.0.0 as the version\nSet `MISE_PIN=1` to make this the default behavior\n\nConsider using mise.lock as a better alternative to pinning in mise.toml:\nhttps://mise.jdx.dev/configuration/settings.html#lockfile\n.TP\n\\fB\\-\\-raw\\fR\nDirectly pipe stdin/stdout/stderr from plugin to user Sets `\\-\\-jobs=1`\n.TP\n\\fB\\-\\-remove\\fR \\fI<PLUGIN>\\fR\nRemove the plugin(s) from config file\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to add to config file\n\ne.g.: node@20, cargo:ripgrep@latest npm:prettier@3\nIf no version is specified, it will default to @latest\n\nTool options can be set with this syntax:\n\n    mise use ubi:BurntSushi/ripgrep[exe=rg]\n.SH \"MISE VERSION\"\nDisplay the version of mise\n\nDisplays the version, os, architecture, and the date of the build.\n\nIf the version is out of date, it will display a warning.\n.PP\n\\fBUsage:\\fR mise version [OPTIONS]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-J, \\-\\-json\\fR\nPrint the version information in JSON format\n.SH \"MISE WATCH\"\nRun task(s) and watch for changes to rerun it\n\nThis command uses the `watchexec` tool to watch for changes to files and rerun the specified task(s).\nIt must be installed for this command to work, but you can install it with `mise use \\-g watchexec@latest`.\n\nFor more advanced process management (daemon management, auto\\-restart, readiness checks,\ncron scheduling), see mise's sister project: https://pitchfork.jdx.dev\n.PP\n\\fBUsage:\\fR mise watch [OPTIONS] [<TASK>] [<ARGS>] ...\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-t, \\-\\-task\\-flag\\fR \\fI<TASK_FLAG>\\fR\nTasks to run\n.TP\n\\fB\\-g, \\-\\-glob\\fR \\fI<GLOB>\\fR\nFiles to watch\nDefaults to sources from the task(s)\n.TP\n\\fB\\-\\-skip\\-deps\\fR\nRun only the specified tasks skipping all dependencies\n.TP\n\\fB\\-w, \\-\\-watch\\fR \\fI<PATH>\\fR\nWatch a specific file or directory\n\nBy default, Watchexec watches the current directory.\n\nWhen watching a single file, it's often better to watch the containing directory instead, and filter on the filename. Some editors may replace the file with a new one when saving, and some platforms may not detect that or further changes.\n\nUpon starting, Watchexec resolves a \"project origin\" from the watched paths. See the help for '\\-\\-project\\-origin' for more information.\n\nThis option can be specified multiple times to watch multiple files or directories.\n\nThe special value '/dev/null', provided as the only path watched, will cause Watchexec to not watch any paths. Other event sources (like signals or key events) may still be used.\n.TP\n\\fB\\-W, \\-\\-watch\\-non\\-recursive\\fR \\fI<PATH>\\fR\nWatch a specific directory, non\\-recursively\n\nUnlike '\\-w', folders watched with this option are not recursed into.\n\nThis option can be specified multiple times to watch multiple directories non\\-recursively.\n.TP\n\\fB\\-F, \\-\\-watch\\-file\\fR \\fI<PATH>\\fR\nWatch files and directories from a file\n\nEach line in the file will be interpreted as if given to '\\-w'.\n\nFor more complex uses (like watching non\\-recursively), use the argfile capability: build a file containing command\\-line options and pass it to watchexec with `@path/to/argfile`.\n\nThe special value '\\-' will read from STDIN; this in incompatible with '\\-\\-stdin\\-quit'.\n.TP\n\\fB\\-c, \\-\\-clear\\fR \\fI<MODE>\\fR\nClear screen before running command\n\nIf this doesn't completely clear the screen, try '\\-\\-clear=reset'.\n.TP\n\\fB\\-o, \\-\\-on\\-busy\\-update\\fR \\fI<MODE>\\fR\nWhat to do when receiving events while the command is running\n\nDefault is to 'do\\-nothing', which ignores events while the command is running, so that changes that occur due to the command are ignored, like compilation outputs. You can also use 'queue' which will run the command once again when the current run has finished if any events occur while it's running, or 'restart', which terminates the running command and starts a new one. Finally, there's 'signal', which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.\n\nThe signal can be specified with the '\\-\\-signal' option.\n.RS\n\\fIDefault: \\fRdo\\-nothing\n.RE\n.TP\n\\fB\\-r, \\-\\-restart\\fR\nRestart the process if it's still running\n\nThis is a shorthand for '\\-\\-on\\-busy\\-update=restart'.\n.TP\n\\fB\\-s, \\-\\-signal\\fR \\fI<SIGNAL>\\fR\nSend a signal to the process when it's still running\n\nSpecify a signal to send to the process when it's still running. This implies '\\-\\-on\\-busy\\-update=signal'; otherwise the signal used when that mode is 'restart' is controlled by '\\-\\-stop\\-signal'.\n\nSee the long documentation for '\\-\\-stop\\-signal' for syntax.\n\nSignals are not supported on Windows at the moment, and will always be overridden to 'kill'. See '\\-\\-stop\\-signal' for more on Windows \"signals\".\n.TP\n\\fB\\-\\-stop\\-signal\\fR \\fI<SIGNAL>\\fR\nSignal to send to stop the command\n\nThis is used by 'restart' and 'signal' modes of '\\-\\-on\\-busy\\-update' (unless '\\-\\-signal' is provided). The restart behaviour is to send the signal, wait for the command to exit, and if it hasn't exited after some time (see '\\-\\-timeout\\-stop'), forcefully terminate it.\n\nThe default on unix is \"SIGTERM\".\n\nInput is parsed as a full signal name (like \"SIGTERM\"), a short signal name (like \"TERM\"), or a signal number (like \"15\"). All input is case\\-insensitive.\n\nOn Windows this option is technically supported but only supports the \"KILL\" event, as Watchexec cannot yet deliver other events. Windows doesn't have signals as such; instead it has termination (here called \"KILL\" or \"STOP\") and \"CTRL+C\", \"CTRL+BREAK\", and \"CTRL+CLOSE\" events. For portability the unix signals \"SIGKILL\", \"SIGINT\", \"SIGTERM\", and \"SIGHUP\" are respectively mapped to these.\n.TP\n\\fB\\-\\-stop\\-timeout\\fR \\fI<TIMEOUT>\\fR\nTime to wait for the command to exit gracefully\n\nThis is used by the 'restart' mode of '\\-\\-on\\-busy\\-update'. After the graceful stop signal is sent, Watchexec will wait for the command to exit. If it hasn't exited after this time, it is forcefully terminated.\n\nTakes a unit\\-less value in seconds, or a time span value such as \"5min 20s\". Providing a unit\\-less value is deprecated and will warn; it will be an error in the future.\n\nThe default is 10 seconds. Set to 0 to immediately force\\-kill the command.\n\nThis has no practical effect on Windows as the command is always forcefully terminated; see '\\-\\-stop\\-signal' for why.\n.RS\n\\fIDefault: \\fR10s\n.RE\n.TP\n\\fB\\-\\-map\\-signal\\fR \\fI<SIGNAL:SIGNAL>\\fR\nTranslate signals from the OS to signals to send to the command\n\nTakes a pair of signal names, separated by a colon, such as \"TERM:INT\" to map SIGTERM to SIGINT. The first signal is the one received by watchexec, and the second is the one sent to the command. The second can be omitted to discard the first signal, such as \"TERM:\" to not do anything on SIGTERM.\n\nIf SIGINT or SIGTERM are mapped, then they no longer quit Watchexec. Besides making it hard to quit Watchexec itself, this is useful to send pass a Ctrl\\-C to the command without also terminating Watchexec and the underlying program with it, e.g. with \"INT:INT\".\n\nThis option can be specified multiple times to map multiple signals.\n\nSignal syntax is case\\-insensitive for short names (like \"TERM\", \"USR2\") and long names (like \"SIGKILL\", \"SIGHUP\"). Signal numbers are also supported (like \"15\", \"31\"). On Windows, the forms \"STOP\", \"CTRL+C\", and \"CTRL+BREAK\" are also supported to receive, but Watchexec cannot yet deliver other \"signals\" than a STOP.\n.TP\n\\fB\\-d, \\-\\-debounce\\fR \\fI<TIMEOUT>\\fR\nTime to wait for new events before taking action\n\nWhen an event is received, Watchexec will wait for up to this amount of time before handling it (such as running the command). This is essential as what you might perceive as a single change may actually emit many events, and without this behaviour, Watchexec would run much too often. Additionally, it's not infrequent that file writes are not atomic, and each write may emit an event, so this is a good way to avoid running a command while a file is partially written.\n\nAn alternative use is to set a high value (like \"30min\" or longer), to save power or bandwidth on intensive tasks, like an ad\\-hoc backup script. In those use cases, note that every accumulated event will build up in memory.\n\nTakes a unit\\-less value in milliseconds, or a time span value such as \"5sec 20ms\". Providing a unit\\-less value is deprecated and will warn; it will be an error in the future.\n\nThe default is 50 milliseconds. Setting to 0 is highly discouraged.\n.RS\n\\fIDefault: \\fR50ms\n.RE\n.TP\n\\fB\\-\\-stdin\\-quit\\fR\nExit when stdin closes\n\nThis watches the stdin file descriptor for EOF, and exits Watchexec gracefully when it is closed. This is used by some process managers to avoid leaving zombie processes around.\n.TP\n\\fB\\-\\-no\\-vcs\\-ignore\\fR\nDon't load gitignores\n\nAmong other VCS exclude files, like for Mercurial, Subversion, Bazaar, DARCS, Fossil. Note that Watchexec will detect which of these is in use, if any, and only load the relevant files. Both global (like '~/.gitignore') and local (like '.gitignore') files are considered.\n\nThis option is useful if you want to watch files that are ignored by Git.\n.TP\n\\fB\\-\\-no\\-project\\-ignore\\fR\nDon't load project\\-local ignores\n\nThis disables loading of project\\-local ignore files, like '.gitignore' or '.ignore' in the\nwatched project. This is contrasted with '\\-\\-no\\-vcs\\-ignore', which disables loading of Git\nand other VCS ignore files, and with '\\-\\-no\\-global\\-ignore', which disables loading of global\nor user ignore files, like '~/.gitignore' or '~/.config/watchexec/ignore'.\n\nSupported project ignore files:\n\n  \\- Git: .gitignore at project root and child directories, .git/info/exclude, and the file pointed to by `core.excludesFile` in .git/config.\n  \\- Mercurial: .hgignore at project root and child directories.\n  \\- Bazaar: .bzrignore at project root.\n  \\- Darcs: _darcs/prefs/boring\n  \\- Fossil: .fossil\\-settings/ignore\\-glob\n  \\- Ripgrep/Watchexec/generic: .ignore at project root and child directories.\n\nVCS ignore files (Git, Mercurial, Bazaar, Darcs, Fossil) are only used if the corresponding\nVCS is discovered to be in use for the project/origin. For example, a .bzrignore in a Git\nrepository will be discarded.\n.TP\n\\fB\\-\\-no\\-global\\-ignore\\fR\nDon't load global ignores\n\nThis disables loading of global or user ignore files, like '~/.gitignore',\n\\&'~/.config/watchexec/ignore', or '%APPDATA%\\\\Bazzar\\\\2.0\\\\ignore'. Contrast with\n\\&'\\-\\-no\\-vcs\\-ignore' and '\\-\\-no\\-project\\-ignore'.\n\nSupported global ignore files\n\n  \\- Git (if core.excludesFile is set): the file at that path\n  \\- Git (otherwise): the first found of $XDG_CONFIG_HOME/git/ignore, %APPDATA%/.gitignore, %USERPROFILE%/.gitignore, $HOME/.config/git/ignore, $HOME/.gitignore.\n  \\- Bazaar: the first found of %APPDATA%/Bazzar/2.0/ignore, $HOME/.bazaar/ignore.\n  \\- Watchexec: the first found of $XDG_CONFIG_HOME/watchexec/ignore, %APPDATA%/watchexec/ignore, %USERPROFILE%/.watchexec/ignore, $HOME/.watchexec/ignore.\n\nLike for project files, Git and Bazaar global files will only be used for the corresponding\nVCS as used in the project.\n.TP\n\\fB\\-\\-no\\-default\\-ignore\\fR\nDon't use internal default ignores\n\nWatchexec has a set of default ignore patterns, such as editor swap files, `*.pyc`, `*.pyo`, `.DS_Store`, `.bzr`, `_darcs`, `.fossil\\-settings`, `.git`, `.hg`, `.pijul`, `.svn`, and Watchexec log files.\n.TP\n\\fB\\-\\-no\\-discover\\-ignore\\fR\nDon't discover ignore files at all\n\nThis is a shorthand for '\\-\\-no\\-global\\-ignore', '\\-\\-no\\-vcs\\-ignore', '\\-\\-no\\-project\\-ignore', but even more efficient as it will skip all the ignore discovery mechanisms from the get go.\n\nNote that default ignores are still loaded, see '\\-\\-no\\-default\\-ignore'.\n.TP\n\\fB\\-\\-ignore\\-nothing\\fR\nDon't ignore anything at all\n\nThis is a shorthand for '\\-\\-no\\-discover\\-ignore', '\\-\\-no\\-default\\-ignore'.\n\nNote that ignores explicitly loaded via other command line options, such as '\\-\\-ignore' or '\\-\\-ignore\\-file', will still be used.\n.TP\n\\fB\\-p, \\-\\-postpone\\fR\nWait until first change before running command\n\nBy default, Watchexec will run the command once immediately. With this option, it will instead wait until an event is detected before running the command as normal.\n.TP\n\\fB\\-\\-delay\\-run\\fR \\fI<DURATION>\\fR\nSleep before running the command\n\nThis option will cause Watchexec to sleep for the specified amount of time before running the command, after an event is detected. This is like using \"sleep 5 && command\" in a shell, but portable and slightly more efficient.\n\nTakes a unit\\-less value in seconds, or a time span value such as \"2min 5s\". Providing a unit\\-less value is deprecated and will warn; it will be an error in the future.\n.TP\n\\fB\\-\\-poll\\fR \\fI<INTERVAL>\\fR\nPoll for filesystem changes\n\nBy default, and where available, Watchexec uses the operating system's native file system watching capabilities. This option disables that and instead uses a polling mechanism, which is less efficient but can work around issues with some file systems (like network shares) or edge cases.\n\nOptionally takes a unit\\-less value in milliseconds, or a time span value such as \"2s 500ms\", to use as the polling interval. If not specified, the default is 30 seconds. Providing a unit\\-less value is deprecated and will warn; it will be an error in the future.\n\nAliased as '\\-\\-force\\-poll'.\n.TP\n\\fB\\-\\-shell\\fR \\fI<SHELL>\\fR\nUse a different shell\n\nBy default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix\\-likes, and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec detects is the running shell.\n\nWith this option, you can override that and use a different shell, for example one with more features or one which has your custom aliases and functions.\n\nIf the value has spaces, it is parsed as a command line, and the first word used as the shell program, with the rest as arguments to the shell.\n\nThe command is run with the '\\-c' flag (except for 'cmd' on Windows, where it's '/C').\n\nThe special value 'none' can be used to disable shell use entirely. In that case, the command provided to Watchexec will be parsed, with the first word being the executable and the rest being the arguments, and executed directly. Note that this parsing is rudimentary, and may not work as expected in all cases.\n\nUsing 'none' is a little more efficient and can enable a stricter interpretation of the input, but it also means that you can't use shell features like globbing, redirection, control flow, logic, or pipes.\n\nExamples:\n\nUse without shell:\n\n$ watchexec \\-n \\-\\- zsh \\-x \\-o shwordsplit scr\n\nUse with powershell core:\n\n$ watchexec \\-\\-shell=pwsh \\-\\- Test\\-Connection localhost\n\nUse with CMD.exe:\n\n$ watchexec \\-\\-shell=cmd \\-\\- dir\n\nUse with a different unix shell:\n\n$ watchexec \\-\\-shell=bash \\-\\- 'echo $BASH_VERSION'\n\nUse with a unix shell and options:\n\n$ watchexec \\-\\-shell='zsh \\-x \\-o shwordsplit' \\-\\- scr\n.TP\n\\fB\\-n\\fR\nShorthand for '\\-\\-shell=none'\n.TP\n\\fB\\-\\-emit\\-events\\-to\\fR \\fI<MODE>\\fR\nConfigure event emission\n\nWatchexec can emit event information when running a command, which can be used by the child\nprocess to target specific changed files.\n\nOne thing to take care with is assuming inherent behaviour where there is only chance.\nNotably, it could appear as if the `RENAMED` variable contains both the original and the new\npath being renamed. In previous versions, it would even appear on some platforms as if the\noriginal always came before the new. However, none of this was true. It's impossible to\nreliably and portably know which changed path is the old or new, \"half\" renames may appear\n(only the original, only the new), \"unknown\" renames may appear (change was a rename, but\nwhether it was the old or new isn't known), rename events might split across two debouncing\nboundaries, and so on.\n\nThis option controls where that information is emitted. It defaults to 'none', which doesn't\nemit event information at all. The other options are 'environment' (deprecated), 'stdio',\n\\&'file', 'json\\-stdio', and 'json\\-file'.\n\nThe 'stdio' and 'file' modes are text\\-based: 'stdio' writes absolute paths to the stdin of\nthe command, one per line, each prefixed with `create:`, `remove:`, `rename:`, `modify:`,\nor `other:`, then closes the handle; 'file' writes the same thing to a temporary file, and\nits path is given with the $WATCHEXEC_EVENTS_FILE environment variable.\n\nThere are also two JSON modes, which are based on JSON objects and can represent the full\nset of events Watchexec handles. Here's an example of a folder being created on Linux:\n\n```json\n  {\n    \"tags\": [\n      {\n        \"kind\": \"path\",\n        \"absolute\": \"/home/user/your/new\\-folder\",\n        \"filetype\": \"dir\"\n      },\n      {\n        \"kind\": \"fs\",\n        \"simple\": \"create\",\n        \"full\": \"Create(Folder)\"\n      },\n      {\n        \"kind\": \"source\",\n        \"source\": \"filesystem\",\n      }\n    ],\n    \"metadata\": {\n      \"notify\\-backend\": \"inotify\"\n    }\n  }\n```\n\nThe fields are as follows:\n\n  \\- `tags`, structured event data.\n  \\- `tags[].kind`, which can be:\n    * 'path', along with:\n      + `absolute`, an absolute path.\n      + `filetype`, a file type if known ('dir', 'file', 'symlink', 'other').\n    * 'fs':\n      + `simple`, the \"simple\" event type ('access', 'create', 'modify', 'remove', or 'other').\n      + `full`, the \"full\" event type, which is too complex to fully describe here, but looks like 'General(Precise(Specific))'.\n    * 'source', along with:\n      + `source`, the source of the event ('filesystem', 'keyboard', 'mouse', 'os', 'time', 'internal').\n    * 'keyboard', along with:\n      + `keycode`. Currently only the value 'eof' is supported.\n    * 'process', for events caused by processes:\n      + `pid`, the process ID.\n    * 'signal', for signals sent to Watchexec:\n      + `signal`, the normalised signal name ('hangup', 'interrupt', 'quit', 'terminate', 'user1', 'user2').\n    * 'completion', for when a command ends:\n      + `disposition`, the exit disposition ('success', 'error', 'signal', 'stop', 'exception', 'continued').\n      + `code`, the exit, signal, stop, or exception code.\n  \\- `metadata`, additional information about the event.\n\nThe 'json\\-stdio' mode will emit JSON events to the standard input of the command, one per\nline, then close stdin. The 'json\\-file' mode will create a temporary file, write the\nevents to it, and provide the path to the file with the $WATCHEXEC_EVENTS_FILE\nenvironment variable.\n\nFinally, the 'environment' mode was the default until 2.0. It sets environment variables\nwith the paths of the affected files, for filesystem events:\n\n$WATCHEXEC_COMMON_PATH is set to the longest common path of all of the below variables,\nand so should be prepended to each path to obtain the full/real path. Then:\n\n  \\- $WATCHEXEC_CREATED_PATH is set when files/folders were created\n  \\- $WATCHEXEC_REMOVED_PATH is set when files/folders were removed\n  \\- $WATCHEXEC_RENAMED_PATH is set when files/folders were renamed\n  \\- $WATCHEXEC_WRITTEN_PATH is set when files/folders were modified\n  \\- $WATCHEXEC_META_CHANGED_PATH is set when files/folders' metadata were modified\n  \\- $WATCHEXEC_OTHERWISE_CHANGED_PATH is set for every other kind of pathed event\n\nMultiple paths are separated by the system path separator, ';' on Windows and ':' on unix.\nWithin each variable, paths are deduplicated and sorted in binary order (i.e. neither\nUnicode nor locale aware).\n\nThis is the legacy mode, is deprecated, and will be removed in the future. The environment\nis a very restricted space, while also limited in what it can usefully represent. Large\nnumbers of files will either cause the environment to be truncated, or may error or crash\nthe process entirely. The $WATCHEXEC_COMMON_PATH is also unintuitive, as demonstrated by the\nmultiple confused queries that have landed in my inbox over the years.\n.RS\n\\fIDefault: \\fRnone\n.RE\n.TP\n\\fB\\-\\-only\\-emit\\-events\\fR\nOnly emit events to stdout, run no commands.\n\nThis is a convenience option for using Watchexec as a file watcher, without running any commands. It is almost equivalent to using `cat` as the command, except that it will not spawn a new process for each event.\n\nThis option requires `\\-\\-emit\\-events\\-to` to be set, and restricts the available modes to `stdio` and `json\\-stdio`, modifying their behaviour to write to stdout instead of the stdin of the command.\n.TP\n\\fB\\-E, \\-\\-env\\fR \\fI<KEY=VALUE>\\fR\nAdd env vars to the command\n\nThis is a convenience option for setting environment variables for the command, without setting them for the Watchexec process itself.\n\nUse key=value syntax. Multiple variables can be set by repeating the option.\n.TP\n\\fB\\-\\-wrap\\-process\\fR \\fI<MODE>\\fR\nConfigure how the process is wrapped\n\nBy default, Watchexec will run the command in a process group in Unix, and in a Job Object in Windows.\n\nSome Unix programs prefer running in a session, while others do not work in a process group.\n\nUse 'group' to use a process group, 'session' to use a process session, and 'none' to run the command directly. On Windows, either of 'group' or 'session' will use a Job Object.\n.RS\n\\fIDefault: \\fRgroup\n.RE\n.TP\n\\fB\\-N, \\-\\-notify\\fR\nAlert when commands start and end\n\nWith this, Watchexec will emit a desktop notification when a command starts and ends, on supported platforms. On unsupported platforms, it may silently do nothing, or log a warning.\n.TP\n\\fB\\-\\-color\\fR \\fI<MODE>\\fR\nWhen to use terminal colours\n\nSetting the environment variable `NO_COLOR` to any value is equivalent to `\\-\\-color=never`.\n.RS\n\\fIDefault: \\fRauto\n.RE\n.TP\n\\fB\\-\\-timings\\fR\nPrint how long the command took to run\n\nThis may not be exactly accurate, as it includes some overhead from Watchexec itself. Use the `time` utility, high\\-precision timers, or benchmarking tools for more accurate results.\n.TP\n\\fB\\-q, \\-\\-quiet\\fR\nDon't print starting and stopping messages\n\nBy default Watchexec will print a message when the command starts and stops. This option disables this behaviour, so only the command's output, warnings, and errors will be printed.\n.TP\n\\fB\\-\\-bell\\fR\nRing the terminal bell on command completion\n.TP\n\\fB\\-\\-project\\-origin\\fR \\fI<DIRECTORY>\\fR\nSet the project origin\n\nWatchexec will attempt to discover the project's \"origin\" (or \"root\") by searching for a variety of markers, like files or directory patterns. It does its best but sometimes gets it it wrong, and you can override that with this option.\n\nThe project origin is used to determine the path of certain ignore files, which VCS is being used, the meaning of a leading '/' in filtering patterns, and maybe more in the future.\n\nWhen set, Watchexec will also not bother searching, which can be significantly faster.\n.TP\n\\fB\\-\\-workdir\\fR \\fI<DIRECTORY>\\fR\nSet the working directory\n\nBy default, the working directory of the command is the working directory of Watchexec. You can change that with this option. Note that paths may be less intuitive to use with this.\n.TP\n\\fB\\-e, \\-\\-exts\\fR \\fI<EXTENSIONS>\\fR\nFilename extensions to filter to\n\nThis is a quick filter to only emit events for files with the given extensions. Extensions can be given with or without the leading dot (e.g. 'js' or '.js'). Multiple extensions can be given by repeating the option or by separating them with commas.\n.TP\n\\fB\\-f, \\-\\-filter\\fR \\fI<PATTERN>\\fR\nFilename patterns to filter to\n\nProvide a glob\\-like filter pattern, and only events for files matching the pattern will be emitted. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\n.TP\n\\fB\\-\\-filter\\-file\\fR \\fI<PATH>\\fR\nFiles to load filters from\n\nProvide a path to a file containing filters, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '\\-\\-filter' option.\n\nThis can also be used via the $WATCHEXEC_FILTER_FILES environment variable.\n.TP\n\\fB\\-J, \\-\\-filter\\-prog\\fR \\fI<EXPRESSION>\\fR\n[experimental] Filter programs.\n\n/!\\\\ This option is EXPERIMENTAL and may change and/or vanish without notice.\n\nProvide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in '\\-\\-emit\\-events\\-to' and must return a boolean. Invalid programs will make watchexec fail to start; use '\\-v' to see program runtime errors.\n\nIn addition to the jaq stdlib, watchexec adds some custom filter definitions:\n\n\\- 'path | file_meta' returns file metadata or null if the file does not exist.\n\n\\- 'path | file_size' returns the size of the file at path, or null if it does not exist.\n\n\\- 'path | file_read(bytes)' returns a string with the first n bytes of the file at path. If the file is smaller than n bytes, the whole file is returned. There is no filter to read the whole file at once to encourage limiting the amount of data read and processed.\n\n\\- 'string | hash', and 'path | file_hash' return the hash of the string or file at path. No guarantee is made about the algorithm used: treat it as an opaque value.\n\n\\- 'any | kv_store(key)', 'kv_fetch(key)', and 'kv_clear' provide a simple key\\-value store. Data is kept in memory only, there is no persistence. Consistency is not guaranteed.\n\n\\- 'any | printout', 'any | printerr', and 'any | log(level)' will print or log any given value to stdout, stderr, or the log (levels = error, warn, info, debug, trace), and pass the value through (so '[1] | log(\"debug\") | .[]' will produce a '1' and log '[1]').\n\nAll filtering done with such programs, and especially those using kv or filesystem access, is much slower than the other filtering methods. If filtering is too slow, events will back up and stall watchexec. Take care when designing your filters.\n\nIf the argument to this option starts with an '@', the rest of the argument is taken to be the path to a file containing a jaq program.\n\nJaq programs are run in order, after all other filters, and short\\-circuit: if a filter (jaq or not) rejects an event, execution stops there, and no other filters are run. Additionally, they stop after outputting the first value, so you'll want to use 'any' or 'all' when iterating, otherwise only the first item will be processed, which can be quite confusing!\n\nFind user\\-contributed programs or submit your own useful ones at <https://github.com/watchexec/watchexec/discussions/592>.\n\n## Examples:\n\nRegexp ignore filter on paths:\n\n\\&'all(.tags[] | select(.kind == \"path\"); .absolute | test(\"[.]test[.]js$\")) | not'\n\nPass any event that creates a file:\n\n\\&'any(.tags[] | select(.kind == \"fs\"); .simple == \"create\")'\n\nPass events that touch executable files:\n\n\\&'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | metadata | .executable)'\n\nIgnore files that start with shebangs:\n\n\\&'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | read(2) == \"#!\") | not'\n.TP\n\\fB\\-i, \\-\\-ignore\\fR \\fI<PATTERN>\\fR\nFilename patterns to filter out\n\nProvide a glob\\-like filter pattern, and events for files matching the pattern will be excluded. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\n.TP\n\\fB\\-\\-ignore\\-file\\fR \\fI<PATH>\\fR\nFiles to load ignores from\n\nProvide a path to a file containing ignores, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '\\-\\-ignore' option.\n\nThis can also be used via the $WATCHEXEC_IGNORE_FILES environment variable.\n.TP\n\\fB\\-\\-fs\\-events\\fR \\fI<EVENTS>\\fR\nFilesystem events to filter to\n\nThis is a quick filter to only emit events for the given types of filesystem changes. Choose from 'access', 'create', 'remove', 'rename', 'modify', 'metadata'. Multiple types can be given by repeating the option or by separating them with commas. By default, this is all types except for 'access'.\n\nThis may apply filtering at the kernel level when possible, which can be more efficient, but may be more confusing when reading the logs.\n.RS\n\\fIDefault: \\fRcreate,remove,rename,modify,metadata\n.RE\n.TP\n\\fB\\-\\-no\\-meta\\fR\nDon't emit fs events for metadata changes\n\nThis is a shorthand for '\\-\\-fs\\-events create,remove,rename,modify'. Using it alongside the '\\-\\-fs\\-events' option is non\\-sensical and not allowed.\n.TP\n\\fB\\-\\-print\\-events\\fR\nPrint events that trigger actions\n\nThis prints the events that triggered the action when handling it (after debouncing), in a human readable form. This is useful for debugging filters.\n\nUse '\\-vvv' instead when you need more diagnostic information.\n.TP\n\\fB\\-\\-manual\\fR\nShow the manual page\n\nThis shows the manual page for Watchexec, if the output is a terminal and the 'man' program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TASK>\\fR\nTasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: `mise run task1 arg1 arg2 ::: task2 arg1 arg2`\n.TP\n\\fB<ARGS>\\fR\nTask and arguments to run\n.SH \"MISE WHERE\"\nDisplay the installation path for a tool\n\nThe tool must be installed for this to work.\n.PP\n\\fBUsage:\\fR mise where <TOOL@VERSION> [<ASDF_VERSION>]\n.PP\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<TOOL@VERSION>\\fR\nTool(s) to look up\ne.g.: ruby@3\nif \"@<PREFIX>\" is specified, it will show the latest installed version\nthat matches the prefix\notherwise, it will show the current, active installed version\n.TP\n\\fB<ASDF_VERSION>\\fR\nthe version prefix to use when querying the latest version\nsame as the first argument after the \"@\"\nused for asdf compatibility\n.SH \"MISE WHICH\"\nShows the path that a tool's bin points to.\n\nUse this to figure out what version of a tool is currently active.\n.PP\n\\fBUsage:\\fR mise which [OPTIONS] [<BIN_NAME>]\n.PP\n\\fBOptions:\\fR\n.PP\n.TP\n\\fB\\-t, \\-\\-tool\\fR \\fI<TOOL@VERSION>\\fR\nUse a specific tool@version\ne.g.: `mise which npm \\-\\-tool=node@20`\n.TP\n\\fB\\-\\-complete\\fR\n.TP\n\\fB\\-\\-plugin\\fR\nShow the plugin name instead of the path\n.TP\n\\fB\\-\\-version\\fR\nShow the version instead of the path\n\\fBArguments:\\fR\n.PP\n.TP\n\\fB<BIN_NAME>\\fR\nThe bin to look up\n"
  },
  {
    "path": "minisign.key.age",
    "content": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyOGtFYjZaMlN0Z1FvcG8w\nVlhIOExmZlVtOS9TVDVobzBBUklCNFBkbHo4CkJxaDYxQjJTYWZkS3dGWmZjY0F0\nVEt6Z0k5bkw0RmxBVXZRYjM4RFQ4MWMKLS0tIHo4RFFxeVc1Z1JzVS82aGV4dWkw\nTHRLeHRlcElEU3RwTlVDVXZ6NmsrVDgKdWCh+DjlUPZL6KSSEShIvEmKH0DioW5g\njSZD9Hyew8s8uIe8z7ioDWM3pMH4+6FdN6jAKlzeyhUTKhyUGdAWL246KUZnlEsl\nLCMqYDb2H5eVuP44jsTYi63hqXFIhKAGhlO2fRPSIPufUSJBD0XeqHKbpdBx3iPA\nKY6WHC8SDeBpKIsRTUQgFPC4mOn8xKuMpo4ST/5cmLNv/GwQv2j+Tpi2aVNcE8tV\nRr8pnEs2OnIbIKsaQA27MwLh5/bch0UByW5MtTylSGb2veQxsMJVZ+Zkt3CW5WlW\nelFgepKlOwCTy0zJxkJfRujJ5FFAO1w0sLzRMYEAg9GgapPCI5LCosFHzBrEPCK6\nRNylZXWcPdNbGJ1DSjwSgK4ktttS1tw3vyc/9IAg\n-----END AGE ENCRYPTED FILE-----\n"
  },
  {
    "path": "minisign.pub",
    "content": "untrusted comment: minisign public key 64113EDF160FDEC2\nRWTC3g8W3z4RZK3V3qv7fa1QY4JEWyBtqIHW+85QlJpZc5yG+uNYNBSZ\n"
  },
  {
    "path": "mise.code-workspace",
    "content": "{\n  \"folders\": [\n    {\n      \"path\": \".\",\n    },\n  ],\n  \"settings\": {\n    \"shellcheck.ignorePatterns\": {\n      \"completions/mise.bash\": true,\n    },\n    \"markdownlint.lintWorkspaceGlobs\": [\n      \"**/*.{md,mkd,mdwn,mdown,markdown,markdn,mdtxt,mdtext,workbook}\",\n      \"!**/*.code-search\",\n      \"!**/bower_components\",\n      \"!**/node_modules\",\n      \"!**/.git\",\n      \"!**/vendor\",\n      \"!**/CHANGELOG.md\"\n    ],\n    \"files.exclude\": {\n      \"aqua-registry/**\": true\n    },\n    \"markdown.validate.enabled\": true,\n  },\n}\n"
  },
  {
    "path": "mise.toml",
    "content": "#:schema ./schema/mise.json\nmin_version = \"2024.1.1\"\n\n[env]\n_.path = [\"./target/debug\", \"./node_modules/.bin\"]\n\n[tools]\n\"actionlint\" = \"latest\"\nage = \"latest\"\nbun = \"latest\"\ncargo-binstall = \"latest\"\ncommunique = \"latest\"\n\"cargo:cargo-edit\" = \"latest\"\n\"cargo:cargo-insta\" = \"latest\"\n\"cargo:cargo-release\" = \"latest\"\n\"cargo:git-cliff\" = \"latest\"\n\"cargo:toml-cli\" = \"latest\"\n\"cargo:usage-cli\" = { version = \"latest\", os = [\"linux\", \"macos\"] }\ngh = \"latest\"\nhk = \"latest\"\njq = \"latest\"\nfd = \"latest\"\nlua-language-server = \"latest\"\nstylua = \"latest\"\n\"npm:markdownlint-cli\" = \"latest\"\n\"npm:prettier\" = \"3\"\n\"npm:ajv-cli\" = \"latest\"\npkl = \"latest\"\n#\"python\" = { version = \"latest\", virtualenv = \"{{env.HOME}}/.cache/venv\" }\n\"ripgrep\" = \"latest\"\n\"shellcheck\" = \"latest\"\n\"shfmt\" = \"latest\"\ntaplo = \"latest\"\nwait-for-gh-rate-limit = \"latest\"\nsops = \"latest\"\nnode = \"24\"\n\n[task_config]\nincludes = [\"tasks.toml\", \"xtasks\"]\n"
  },
  {
    "path": "mise.usage.kdl",
    "content": "min_usage_version \"2.11\"\nname mise\nbin mise\nabout \"The front-end to your dev env\"\nlong_about \"mise manages dev tools, env vars, and runs tasks. https://github.com/jdx/mise\"\ndefault_subcommand run\nusage \"Usage: mise [OPTIONS] [TASK] [COMMAND]\"\nflag \"-c --continue-on-error\" help=\"Continue running tasks even if one fails\" hide=#true\nflag \"-C --cd\" help=\"Change directory before running command\" global=#true {\n    arg <DIR>\n}\nflag \"-E --env\" help=\"Set the environment for loading `mise.<ENV>.toml`\" var=#true global=#true {\n    arg <ENV>\n}\nflag \"-f --force\" help=\"Force the operation\" hide=#true\nflag \"-i --interleave\" help=\"Set the log output verbosity\" hide=#true\nflag \"-j --jobs\" help=\"How many jobs to run in parallel [default: 8]\" global=#true {\n    arg <JOBS>\n}\nflag \"-n --dry-run\" help=\"Dry run, don't actually do anything\" hide=#true\nflag \"-p --prefix\" hide=#true\nflag \"-P --profile\" help=\"Set the profile (environment)\" var=#true hide=#true global=#true {\n    arg <PROFILE>\n}\nflag \"-q --quiet\" help=\"Suppress non-error messages\" global=#true\nflag \"-s --shell\" hide=#true {\n    arg <SHELL>\n}\nflag \"-t --tool\" help=\"Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\" var=#true hide=#true {\n    arg <TOOL@VERSION>\n}\nflag \"-v --verbose\" help=\"Show extra output (use -vv for even more)\" var=#true global=#true count=#true\nflag \"-V --version\" hide=#true\nflag \"-y --yes\" help=\"Answer yes to all confirmation prompts\" global=#true\nflag --debug help=\"Sets log level to debug\" hide=#true global=#true\nflag --log-level hide=#true global=#true {\n    arg <LEVEL> {\n        choices trace debug info warning error\n    }\n}\nflag --no-config help=\"Do not load any config files\" {\n    long_help \"Do not load any config files\\n\\nCan also use `MISE_NO_CONFIG=1`\"\n}\nflag --no-env help=\"Do not load environment variables from config files\" {\n    long_help \"Do not load environment variables from config files\\n\\nCan also use `MISE_NO_ENV=1`\"\n}\nflag --no-hooks help=\"Do not execute hooks from config files\" {\n    long_help \"Do not execute hooks from config files\\n\\nCan also use `MISE_NO_HOOKS=1`\"\n}\nflag --no-timings help=\"Hides elapsed time after each task completes\" hide=#true {\n    long_help \"Hides elapsed time after each task completes\\n\\nDefault to always hide with `MISE_TASK_TIMINGS=0`\"\n}\nflag --output {\n    arg <OUTPUT>\n}\nflag --raw help=\"Read/write directly to stdin/stdout/stderr instead of by line\" global=#true\nflag --locked help=\"Require lockfile URLs to be present during installation\" global=#true {\n    long_help \"Require lockfile URLs to be present during installation\\n\\nFails if tools don't have pre-resolved URLs in the lockfile for the current platform.\\nThis prevents API calls to GitHub, aqua registry, etc.\\nCan also be enabled via MISE_LOCKED=1 or settings.locked=true\"\n}\nflag --silent help=\"Suppress all task output and mise non-error messages\" global=#true\nflag --timings help=\"Shows elapsed time after each task completes\" hide=#true {\n    long_help \"Shows elapsed time after each task completes\\n\\nDefault to always show with `MISE_TASK_TIMINGS=1`\"\n}\nflag --trace help=\"Sets log level to trace\" hide=#true global=#true\narg \"[TASK]\" help=\"Task to run\" help_long=\"Task to run.\\n\\nShorthand for `mise tasks run <TASK>`.\" required=#false\narg \"[TASK_ARGS]…\" help=\"Task arguments\" required=#false var=#true hide=#true\narg \"[-- TASK_ARGS_LAST]…\" required=#false var=#true hide=#true\ncmd activate help=\"Initializes mise in the current shell session\" {\n    long_help \"Initializes mise in the current shell session\\n\\nThis should go into your shell's rc file or login shell.\\nOtherwise, it will only take effect in the current session.\\n(e.g. ~/.zshrc, ~/.zprofile, ~/.zshenv, ~/.bashrc, ~/.bash_profile, ~/.profile, ~/.config/fish/config.fish, or $PROFILE for powershell)\\n\\nTypically, this can be added with something like the following:\\n\\n    echo 'eval \\\"$(mise activate zsh)\\\"' >> ~/.zshrc\\n\\nHowever, this requires that \\\"mise\\\" is in your PATH. If it is not, you need to\\nspecify the full path like this:\\n\\n    echo 'eval \\\"$(/path/to/mise activate zsh)\\\"' >> ~/.zshrc\\n\\nCustomize status output with `status` settings.\"\n    after_long_help \"Examples:\\n\\n    $ eval \\\"$(mise activate bash)\\\"\\n    $ eval \\\"$(mise activate zsh)\\\"\\n    $ mise activate fish | source\\n    $ execx($(mise activate xonsh))\\n    $ (&mise activate pwsh) | Out-String | Invoke-Expression\\n\"\n    flag \"-q --quiet\" help=\"Suppress non-error messages\"\n    flag \"-s --shell\" help=\"Shell type to generate the script for\" hide=#true {\n        arg <SHELL> {\n            choices bash elvish fish nu xonsh zsh pwsh\n        }\n    }\n    flag --no-hook-env help=\"Do not automatically call hook-env\" {\n        long_help \"Do not automatically call hook-env\\n\\nThis can be helpful for debugging mise. If you run `eval \\\"$(mise activate --no-hook-env)\\\"`, then you can call `mise hook-env` manually which will output the env vars to stdout without actually modifying the environment. That way you can do things like `mise hook-env --trace` to get more information or just see the values that hook-env is outputting.\"\n    }\n    flag --shims help=\"Use shims instead of modifying PATH\\nEffectively the same as:\" {\n        long_help \"Use shims instead of modifying PATH\\nEffectively the same as:\\n\\n    PATH=\\\"$HOME/.local/share/mise/shims:$PATH\\\"\\n\\n`mise activate --shims` does not support all the features of `mise activate`.\\nSee https://mise.jdx.dev/dev-tools/shims.html#shims-vs-path for more information\"\n    }\n    flag --status help=\"Show \\\"mise: <PLUGIN>@<VERSION>\\\" message when changing directories\" hide=#true\n    arg \"[SHELL_TYPE]\" help=\"Shell type to generate the script for\" required=#false {\n        choices bash elvish fish nu xonsh zsh pwsh\n    }\n}\ncmd tool-alias help=\"Manage tool version aliases.\" {\n    alias alias aliases hide=#true\n    flag \"-p --plugin\" help=\"filter aliases by plugin\" {\n        arg <PLUGIN>\n    }\n    flag --no-header help=\"Don't show table header\"\n    cmd get help=\"Show an alias for a plugin\" {\n        long_help \"Show an alias for a plugin\\n\\nThis is the contents of a tool_alias.<PLUGIN> entry in ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise tool-alias get node lts-hydrogen\\n    20.0.0\\n\"\n        arg <PLUGIN> help=\"The plugin to show the alias for\"\n        arg <ALIAS> help=\"The alias to show\"\n    }\n    cmd ls help=\"List tool version aliases\\nShows the aliases that can be specified.\\nThese can come from user config or from plugins in `bin/list-aliases`.\" {\n        alias list\n        long_help \"List tool version aliases\\nShows the aliases that can be specified.\\nThese can come from user config or from plugins in `bin/list-aliases`.\\n\\nFor user config, aliases are defined like the following in `~/.config/mise/config.toml`:\\n\\n    [tool_alias.node.versions]\\n    lts = \\\"22.0.0\\\"\"\n        after_long_help \"Examples:\\n\\n    $ mise tool-alias ls\\n    node  lts-jod      22\\n\"\n        flag --no-header help=\"Don't show table header\"\n        arg \"[TOOL]\" help=\"Show aliases for <TOOL>\" required=#false\n    }\n    cmd set help=\"Add/update an alias for a backend/plugin\" {\n        alias add create\n        long_help \"Add/update an alias for a backend/plugin\\n\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise tool-alias set maven asdf:mise-plugins/mise-maven\\n    $ mise tool-alias set node lts-jod 22.0.0\\n\"\n        arg <PLUGIN> help=\"The backend/plugin to set the alias for\"\n        arg <ALIAS> help=\"The alias to set\"\n        arg \"[VALUE]\" help=\"The value to set the alias to\" required=#false\n    }\n    cmd unset help=\"Clears an alias for a backend/plugin\" {\n        alias rm remove delete del\n        long_help \"Clears an alias for a backend/plugin\\n\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise tool-alias unset maven\\n    $ mise tool-alias unset node lts-jod\\n\"\n        arg <PLUGIN> help=\"The backend/plugin to remove the alias from\"\n        arg \"[ALIAS]\" help=\"The alias to remove\" required=#false\n    }\n}\ncmd asdf hide=#true help=\"[internal] simulates asdf for plugins that call \\\"asdf\\\" internally\" {\n    arg \"[ARGS]…\" help=\"all arguments\" required=#false double_dash=automatic var=#true\n}\ncmd backends help=\"Manage backends\" {\n    alias b\n    alias backend backend-list hide=#true\n    cmd ls help=\"List built-in backends\" {\n        alias list\n        after_long_help \"Examples:\\n\\n    $ mise backends ls\\n    aqua\\n    asdf\\n    cargo\\n    core\\n    dotnet\\n    gem\\n    go\\n    npm\\n    pipx\\n    spm\\n    ubi\\n    vfox\\n\"\n    }\n}\ncmd bin-paths help=\"List all the active runtime bin paths\" {\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to look up\\ne.g.: ruby@3\" required=#false var=#true\n}\ncmd cache help=\"Manage the mise cache\" {\n    long_help \"Manage the mise cache\\n\\nRun `mise cache` with no args to view the current cache directory.\"\n    cmd clear help=\"Deletes all cache files in mise\" {\n        alias c\n        alias clean hide=#true\n        flag --outdate help=\"Mark all cache files as old\" hide=#true\n        arg \"[PLUGIN]…\" help=\"Plugin(s) to clear cache for e.g.: node, python\" required=#false var=#true\n    }\n    cmd path help=\"Show the cache directory path\" {\n        alias dir\n    }\n    cmd prune help=\"Removes stale mise cache files\" {\n        alias p\n        long_help \"Removes stale mise cache files\\n\\nBy default, this command will remove files that have not been accessed in 30 days.\\nChange this with the MISE_CACHE_PRUNE_AGE environment variable.\"\n        flag \"-v --verbose\" help=\"Show pruned files\" var=#true count=#true\n        flag --dry-run help=\"Just show what would be pruned\"\n        arg \"[PLUGIN]…\" help=\"Plugin(s) to clear cache for e.g.: node, python\" required=#false var=#true\n    }\n}\ncmd completion help=\"Generate shell completions\" {\n    alias complete completions hide=#true\n    after_long_help \"Examples:\\n\\n    $ mise completion bash --include-bash-completion-lib > ~/.local/share/bash-completion/completions/mise\\n    $ mise completion zsh  > /usr/local/share/zsh/site-functions/_mise\\n    $ mise completion fish > ~/.config/fish/completions/mise.fish\\n    $ mise completion powershell >> $PROFILE\\n\"\n    flag \"-s --shell\" help=\"Shell type to generate completions for\" hide=#true {\n        arg <SHELL_TYPE> {\n            choices bash fish powershell zsh\n        }\n    }\n    flag --include-bash-completion-lib help=\"Include the bash completion library in the bash completion script\" {\n        long_help \"Include the bash completion library in the bash completion script\\n\\nThis is required for completions to work in bash, but it is not included by default\\nyou may source it separately or enable this flag to enable it in the script.\"\n    }\n    flag --usage help=\"Always use usage for completions.\\nCurrently, usage is the default for fish and bash but not zsh since it has a few quirks\\nto work out first.\" hide=#true {\n        long_help \"Always use usage for completions.\\nCurrently, usage is the default for fish and bash but not zsh since it has a few quirks\\nto work out first.\\n\\nThis requires the `usage` CLI to be installed.\\nhttps://usage.jdx.dev\"\n    }\n    arg \"[SHELL]\" help=\"Shell type to generate completions for\" required=#false {\n        choices bash fish powershell zsh\n    }\n}\ncmd config help=\"Manage config files\" {\n    alias cfg\n    alias toml hide=#true\n    after_long_help \"Examples:\\n\\n    $ mise config ls\\n    Path                        Tools\\n    ~/.config/mise/config.toml  pitchfork\\n    ~/src/mise/mise.toml        actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta\\n\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag --no-header help=\"Do not print table header\"\n    flag --tracked-configs help=\"List all tracked config files\"\n    cmd get help=\"Display the value of a setting in a mise.toml file\" {\n        after_long_help \"Examples:\\n\\n    $ mise toml get tools.python\\n    3.12\\n\"\n        flag \"-f --file\" help=\"The path to the mise.toml file to edit\" {\n            long_help \"The path to the mise.toml file to edit\\n\\nIf not provided, the nearest mise.toml file will be used\"\n            arg <FILE>\n        }\n        arg \"[KEY]\" help=\"The path of the config to display\" required=#false\n    }\n    cmd ls help=\"List config files currently in use\" {\n        alias list\n        after_long_help \"Examples:\\n\\n    $ mise config ls\\n    Path                        Tools\\n    ~/.config/mise/config.toml  pitchfork\\n    ~/src/mise/mise.toml        actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta\\n\"\n        flag \"-J --json\" help=\"Output in JSON format\"\n        flag --no-header help=\"Do not print table header\"\n        flag --tracked-configs help=\"List all tracked config files\"\n    }\n    cmd set help=\"Set the value of a setting in a mise.toml file\" {\n        after_long_help \"Examples:\\n\\n    $ mise config set tools.python 3.12\\n    $ mise config set settings.always_keep_download true\\n    $ mise config set env.TEST_ENV_VAR ABC\\n    $ mise config set settings.disable_tools --type list node,rust\\n\\n    # Type for `settings` is inferred\\n    $ mise config set settings.jobs 4\\n\"\n        flag \"-f --file\" help=\"The path to the mise.toml file to edit\" {\n            long_help \"The path to the mise.toml file to edit\\n\\nIf not provided, the nearest mise.toml file will be used\"\n            arg <FILE>\n        }\n        flag \"-t --type\" default=infer {\n            arg <TYPE> {\n                choices infer string integer float bool list set\n            }\n        }\n        arg <KEY> help=\"The path of the config to display\"\n        arg \"[VALUE]\" help=\"The value to set the key to (optional if provided as KEY=VALUE)\" required=#false\n    }\n}\ncmd current hide=#true help=\"Shows current active and installed runtime versions\" {\n    long_help \"Shows current active and installed runtime versions\\n\\nThis is similar to `mise ls --current`, but this only shows the runtime\\nand/or version. It's designed to fit into scripts more easily.\"\n    after_long_help \"Examples:\\n\\n    # outputs `.tool-versions` compatible format\\n    $ mise current\\n    python 3.11.0 3.10.0\\n    shfmt 3.6.0\\n    shellcheck 0.9.0\\n    node 20.0.0\\n\\n    $ mise current node\\n    20.0.0\\n\\n    # can output multiple versions\\n    $ mise current python\\n    3.11.0 3.10.0\\n\"\n    arg \"[PLUGIN]\" help=\"Plugin to show versions of e.g.: ruby, node, cargo:eza, npm:prettier, etc\" required=#false\n}\ncmd deactivate help=\"Disable mise for current shell session\" {\n    long_help \"Disable mise for current shell session\\n\\nThis can be used to temporarily disable mise in a shell session.\"\n    after_long_help \"Examples:\\n\\n    $ mise deactivate\\n\"\n}\ncmd direnv hide=#true help=\"Output direnv function to use mise inside direnv\" {\n    long_help \"Output direnv function to use mise inside direnv\\n\\nSee https://mise.jdx.dev/direnv.html for more information\\n\\nBecause this generates the idiomatic files based on currently installed plugins,\\nyou should run this command after installing new plugins. Otherwise\\ndirenv may not know to update environment variables when idiomatic file versions change.\"\n    cmd activate hide=#true help=\"Output direnv function to use mise inside direnv\" {\n        long_help \"Output direnv function to use mise inside direnv\\n\\nSee https://mise.jdx.dev/direnv.html for more information\\n\\nBecause this generates the idiomatic files based on currently installed plugins,\\nyou should run this command after installing new plugins. Otherwise\\ndirenv may not know to update environment variables when idiomatic file versions change.\"\n        after_long_help \"Examples:\\n\\n    $ mise direnv activate > ~/.config/direnv/lib/use_mise.sh\\n    $ echo 'use mise' > .envrc\\n    $ direnv allow\\n\"\n    }\n    cmd envrc hide=#true help=\"[internal] This is an internal command that writes an envrc file\\nfor direnv to consume.\"\n    cmd exec hide=#true help=\"[internal] This is an internal command that writes an envrc file\\nfor direnv to consume.\"\n}\ncmd doctor help=\"Check mise installation for possible problems\" {\n    alias dr\n    after_long_help \"Examples:\\n\\n    $ mise doctor\\n    [WARN] plugin node is not installed\\n\"\n    flag \"-J --json\"\n    cmd path help=\"Print the current PATH entries mise is providing\" {\n        alias paths hide=#true\n        after_long_help \"Examples:\\n\\n    Get the current PATH entries mise is providing\\n    $ mise doctor path\\n    /home/user/.local/share/mise/installs/node/24.0.0/bin\\n    /home/user/.local/share/mise/installs/rust/1.90.0/bin\\n    /home/user/.local/share/mise/installs/python/3.10.0/bin\\n\"\n        flag \"-f --full\" help=\"Print all entries including those not provided by mise\"\n    }\n}\ncmd en help=\"Starts a new shell with the mise environment built from the current configuration\" {\n    long_help \"Starts a new shell with the mise environment built from the current configuration\\n\\nThis is an alternative to `mise activate` that allows you to explicitly start a mise session.\\nIt will have the tools and environment variables in the configs loaded.\\nNote that changing directories will not update the mise environment.\"\n    after_long_help \"Examples:\\n\\n    $ mise en .\\n    $ node -v\\n    v20.0.0\\n\\n    Skip loading bashrc:\\n    $ mise en -s \\\"bash --norc\\\"\\n\\n    Skip loading zshrc:\\n    $ mise en -s \\\"zsh -f\\\"\\n\"\n    flag \"-s --shell\" help=\"Shell to start\" {\n        long_help \"Shell to start\\n\\nDefaults to $SHELL\"\n        arg <SHELL>\n    }\n    arg \"[DIR]\" help=\"Directory to start the shell in\" required=#false default=.\n}\ncmd env help=\"Exports env vars to activate mise a single time\" {\n    alias e\n    long_help \"Exports env vars to activate mise a single time\\n\\nUse this if you don't want to permanently install mise. It's not necessary to\\nuse this if you have `mise activate` in your shell rc file.\"\n    after_long_help \"Examples:\\n\\n    $ eval \\\"$(mise env -s bash)\\\"\\n    $ eval \\\"$(mise env -s zsh)\\\"\\n    $ mise env -s fish | source\\n    $ execx($(mise env -s xonsh))\\n\"\n    flag \"-D --dotenv\" help=\"Output in dotenv format\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-s --shell\" help=\"Shell type to generate environment variables for\" {\n        arg <SHELL> {\n            choices bash elvish fish nu xonsh zsh pwsh\n        }\n    }\n    flag --json-extended help=\"Output in JSON format with additional information (source, tool)\"\n    flag --redacted help=\"Only show redacted environment variables\"\n    flag --values help=\"Only show values of environment variables\"\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to use\" required=#false var=#true\n}\ncmd exec help=\"Execute a command with tool(s) set\" {\n    alias x\n    long_help \"Execute a command with tool(s) set\\n\\nuse this to avoid modifying the shell session or running ad-hoc commands with mise tools set.\\n\\nTools will be loaded from mise.toml, though they can be overridden with <RUNTIME> args\\nNote that only the plugin specified will be overridden, so if a `mise.toml` file\\nincludes \\\"node 20\\\" but you run `mise exec python@3.11`; it will still load node@20.\\n\\nThe \\\"--\\\" separates runtimes from the commands to pass along to the subprocess.\"\n    after_long_help \"Examples:\\n\\n    $ mise exec node@20 -- node ./app.js  # launch app.js using node-20.x\\n    $ mise x node@20 -- node ./app.js     # shorter alias\\n\\n    # Specify command as a string:\\n    $ mise exec node@20 python@3.11 --command \\\"node -v && python -V\\\"\\n\\n    # Run a command in a different directory:\\n    $ mise x -C /path/to/project node@20 -- node ./app.js\\n\"\n    flag \"-c --command\" help=\"Command string to execute\" {\n        arg <C>\n    }\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag --fresh-env help=\"Bypass the environment cache and recompute the environment\"\n    flag --no-prepare help=\"Skip automatic dependency preparation\"\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to start e.g.: node@20 python@3.10\" required=#false var=#true\n    arg \"[-- COMMAND]…\" help=\"Command string to execute (same as --command)\" required=#false var=#true\n}\ncmd fmt help=\"Formats mise.toml\" {\n    long_help \"Formats mise.toml\\n\\nSorts keys and cleans up whitespace in mise.toml\"\n    after_long_help \"Examples:\\n\\n    $ mise fmt\\n\"\n    flag \"-a --all\" help=\"Format all files from the current directory\"\n    flag \"-c --check\" help=\"Check if the configs are formatted, no formatting is done\"\n    flag \"-s --stdin\" help=\"Read config from stdin and write its formatted version into stdout\"\n}\ncmd generate subcommand_required=#true help=\"Generate files for various tools/services\" {\n    alias gen\n    alias g hide=#true\n    cmd bootstrap help=\"Generate a script to download+execute mise\" {\n        long_help \"Generate a script to download+execute mise\\n\\nThis is designed to be used in a project where contributors may not have mise installed.\"\n        after_long_help \"Examples:\\n\\n    $ mise generate bootstrap >./bin/mise\\n    $ chmod +x ./bin/mise\\n    $ ./bin/mise install – automatically downloads mise to .mise if not already installed\\n\"\n        flag \"-l --localize\" help=\"Sandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\" {\n            long_help \"Sandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\\n\\nThis is necessary if users may use a different version of mise outside the project.\"\n        }\n        flag \"-V --version\" help=\"Specify mise version to fetch\" {\n            arg <VERSION>\n        }\n        flag \"-w --write\" help=\"instead of outputting the script to stdout, write to a file and make it executable\" {\n            arg <WRITE>\n        }\n        flag --localized-dir help=\"Directory to put localized data into\" default=.mise {\n            arg <LOCALIZED_DIR>\n        }\n    }\n    cmd config help=\"Generate a mise.toml file\" {\n        after_long_help \"Examples:\\n\\n    $ mise edit             # edit mise.toml interactively\\n    $ mise edit .mise.toml  # edit a specific file\\n    $ mise edit -y          # skip interactive editor\\n    $ mise edit -n          # preview without writing\\n\"\n        flag \"-n --dry-run\" help=\"Show what would be generated without writing to file\"\n        flag \"-t --tool-versions\" help=\"Path to a .tool-versions file to import tools from\" {\n            arg <TOOL_VERSIONS>\n        }\n        arg \"[PATH]\" help=\"Path to the config file to create\" required=#false\n    }\n    cmd devcontainer help=\"Generate a devcontainer to execute mise\" {\n        after_long_help \"Examples:\\n\\n    $ mise generate devcontainer\\n\"\n        flag \"-i --image\" help=\"The image to use for the devcontainer\" {\n            arg <IMAGE>\n        }\n        flag \"-m --mount-mise-data\" help=\"Bind the mise-data-volume to the devcontainer\"\n        flag \"-n --name\" help=\"The name of the devcontainer\" {\n            arg <NAME>\n        }\n        flag \"-w --write\" help=\"write to .devcontainer/devcontainer.json\"\n    }\n    cmd git-pre-commit help=\"Generate a git pre-commit hook\" {\n        alias pre-commit\n        long_help \"Generate a git pre-commit hook\\n\\nThis command generates a git pre-commit hook that runs a mise task like `mise run pre-commit`\\nwhen you commit changes to your repository.\\n\\nStaged files are passed to the task as `STAGED`.\\n\\nFor more advanced pre-commit functionality, see mise's sister project: https://hk.jdx.dev/\"\n        after_long_help \"Examples:\\n\\n    $ mise generate git-pre-commit --write --task=pre-commit\\n    $ git commit -m \\\"feat: add new feature\\\" # runs `mise run pre-commit`\\n\"\n        flag \"-t --task\" help=\"The task to run when the pre-commit hook is triggered\" default=pre-commit {\n            arg <TASK>\n        }\n        flag \"-w --write\" help=\"write to .git/hooks/pre-commit and make it executable\"\n        flag --hook help=\"Which hook to generate (saves to .git/hooks/$hook)\" default=pre-commit {\n            arg <HOOK>\n        }\n    }\n    cmd github-action help=\"Generate a GitHub Action workflow file\" {\n        long_help \"Generate a GitHub Action workflow file\\n\\nThis command generates a GitHub Action workflow file that runs a mise task like `mise run ci`\\nwhen you push changes to your repository.\"\n        after_long_help \"Examples:\\n\\n    $ mise generate github-action --write --task=ci\\n    $ git commit -m \\\"feat: add new feature\\\"\\n    $ git push # runs `mise run ci` on GitHub\\n\"\n        flag \"-t --task\" help=\"The task to run when the workflow is triggered\" default=ci {\n            arg <TASK>\n        }\n        flag \"-w --write\" help=\"write to .github/workflows/$name.yml\"\n        flag --name help=\"the name of the workflow to generate\" default=ci {\n            arg <NAME>\n        }\n    }\n    cmd task-docs help=\"Generate documentation for tasks in a project\" {\n        after_long_help \"Examples:\\n\\n    $ mise generate task-docs\\n\"\n        flag \"-i --inject\" help=\"inserts the documentation into an existing file\" {\n            long_help \"inserts the documentation into an existing file\\n\\nThis will look for a special comment, `<!-- mise-tasks -->`, and replace it with the generated documentation.\\nIt will replace everything between the comment and the next comment, `<!-- /mise-tasks -->` so it can be\\nrun multiple times on the same file to update the documentation.\"\n        }\n        flag \"-I --index\" help=\"write only an index of tasks, intended for use with `--multi`\"\n        flag \"-m --multi\" help=\"render each task as a separate document, requires `--output` to be a directory\"\n        flag \"-o --output\" help=\"writes the generated docs to a file/directory\" {\n            arg <OUTPUT>\n        }\n        flag \"-r --root\" help=\"root directory to search for tasks\" {\n            arg <ROOT>\n        }\n        flag \"-s --style\" default=simple {\n            arg <STYLE> {\n                choices simple detailed\n            }\n        }\n    }\n    cmd task-stubs help=\"Generates shims to run mise tasks\" {\n        long_help \"Generates shims to run mise tasks\\n\\nBy default, this will build shims like ./bin/<task>. These can be paired with `mise generate bootstrap`\\nso contributors to a project can execute mise tasks without installing mise into their system.\"\n        after_long_help \"Examples:\\n\\n    $ mise tasks add test -- echo 'running tests'\\n    $ mise generate task-stubs\\n    $ ./bin/test\\n    running tests\\n\"\n        flag \"-d --dir\" help=\"Directory to create task stubs inside of\" default=bin {\n            arg <DIR>\n        }\n        flag \"-m --mise-bin\" help=\"Path to a mise bin to use when running the task stub.\" default=mise {\n            long_help \"Path to a mise bin to use when running the task stub.\\n\\nUse `--mise-bin=./bin/mise` to use a mise bin generated from `mise generate bootstrap`\"\n            arg <MISE_BIN>\n        }\n    }\n    cmd tool-stub help=\"Generate a tool stub for HTTP-based tools\" {\n        long_help \"Generate a tool stub for HTTP-based tools\\n\\nThis command generates tool stubs that can automatically download and execute\\ntools from HTTP URLs. It can detect checksums, file sizes, and binary paths\\nautomatically by downloading and analyzing the tool.\\n\\nWhen generating stubs with platform-specific URLs, the command will append new\\nplatforms to existing stub files rather than overwriting them. This allows you\\nto incrementally build cross-platform tool stubs.\"\n        after_long_help \"Examples:\\n\\n    Generate a tool stub for a single URL:\\n    $ mise generate tool-stub ./bin/gh --url \\\"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_linux_amd64.tar.gz\\\"\\n\\n    Generate a tool stub with platform-specific URLs:\\n    $ mise generate tool-stub ./bin/rg \\\\\\n        --platform-url linux-x64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz \\\\\\n        --platform-url darwin-arm64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-aarch64-apple-darwin.tar.gz\\n\\n    Append additional platforms to an existing stub:\\n    $ mise generate tool-stub ./bin/rg \\\\\\n        --platform-url linux-x64:https://example.com/rg-linux.tar.gz\\n    $ mise generate tool-stub ./bin/rg \\\\\\n        --platform-url darwin-arm64:https://example.com/rg-darwin.tar.gz\\n    # The stub now contains both platforms\\n\\n    Use auto-detection for platform from URL:\\n    $ mise generate tool-stub ./bin/node \\\\\\n        --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\\n    # Platform 'macos-arm64' will be auto-detected from the URL\\n\\n    Generate with platform-specific binary paths:\\n    $ mise generate tool-stub ./bin/tool \\\\\\n        --platform-url linux-x64:https://example.com/tool-linux.tar.gz \\\\\\n        --platform-url windows-x64:https://example.com/tool-windows.zip \\\\\\n        --platform-bin windows-x64:tool.exe\\n\\n    Generate without downloading (faster):\\n    $ mise generate tool-stub ./bin/tool --url \\\"https://example.com/tool.tar.gz\\\" --skip-download\\n\\n    Fetch checksums for an existing stub:\\n    $ mise generate tool-stub ./bin/jq --fetch\\n    # This will read the existing stub and download files to fill in any missing checksums/sizes\\n\\n    Generate a bootstrap stub that installs mise if needed:\\n    $ mise generate tool-stub ./bin/tool --url \\\"https://example.com/tool.tar.gz\\\" --bootstrap\\n    # The stub will check for mise and install it automatically before running the tool\\n\\n    Generate a bootstrap stub with a pinned mise version:\\n    $ mise generate tool-stub ./bin/tool --url \\\"https://example.com/tool.tar.gz\\\" --bootstrap --bootstrap-version 2025.1.0\\n\\n    Lock an existing tool stub with pinned version and platform URLs/checksums:\\n    $ mise generate tool-stub ./bin/node --lock\\n\\n    Bump the version in a locked stub:\\n    $ mise generate tool-stub ./bin/node --lock --version 22\\n    # Resolves the latest node 22.x, pins it, and updates platform URLs/checksums\\n\"\n        flag \"-b --bin\" help=\"Binary path within the extracted archive\" {\n            long_help \"Binary path within the extracted archive\\n\\nIf not specified and the archive is downloaded, will auto-detect the most likely binary\"\n            arg <BIN>\n        }\n        flag --bootstrap help=\"Wrap stub in a bootstrap script that installs mise if not already present\" {\n            long_help \"Wrap stub in a bootstrap script that installs mise if not already present\\n\\nWhen enabled, generates a bash script that:\\n1. Checks if mise is installed at the expected path\\n2. If not, downloads and installs mise using the embedded installer\\n3. Executes the tool stub using mise\"\n        }\n        flag --bootstrap-version help=\"Specify mise version for the bootstrap script\" {\n            long_help \"Specify mise version for the bootstrap script\\n\\nBy default, uses the latest version from the install script.\\nUse this to pin to a specific version (e.g., \\\"2025.1.0\\\").\"\n            arg <BOOTSTRAP_VERSION>\n        }\n        flag --fetch help=\"Fetch checksums and sizes for an existing tool stub file\" {\n            long_help \"Fetch checksums and sizes for an existing tool stub file\\n\\nThis reads an existing stub file and fills in any missing checksum/size fields by downloading the files. URLs must already be present in the stub.\"\n        }\n        flag --http help=\"HTTP backend type to use\" default=http {\n            arg <HTTP>\n        }\n        flag --lock help=\"Resolve and embed lockfile data (exact version + platform URLs/checksums) into an existing stub file for reproducible installs without runtime API calls\"\n        flag --platform-bin help=\"Platform-specific binary paths in the format platform:path\" var=#true {\n            long_help \"Platform-specific binary paths in the format platform:path\\n\\nExamples: --platform-bin windows-x64:tool.exe --platform-bin linux-x64:bin/tool\"\n            arg <PLATFORM_BIN>\n        }\n        flag --platform-url help=\"Platform-specific URLs in the format platform:url or just url (auto-detect platform)\" var=#true {\n            long_help \"Platform-specific URLs in the format platform:url or just url (auto-detect platform)\\n\\nWhen the output file already exists, new platforms will be appended to the existing platforms table. Existing platform URLs will be updated if specified again.\\n\\nIf only a URL is provided (without platform:), the platform will be automatically detected from the URL filename.\\n\\nExamples: --platform-url linux-x64:https://... --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\"\n            arg <PLATFORM_URL>\n        }\n        flag --skip-download help=\"Skip downloading for checksum and binary path detection (faster but less informative)\"\n        flag \"-u --url\" help=\"URL for downloading the tool\" {\n            long_help \"URL for downloading the tool\\n\\nExample: https://github.com/owner/repo/releases/download/v2.0.0/tool-linux-x64.tar.gz\"\n            arg <URL>\n        }\n        flag --version help=\"Version of the tool\" default=latest {\n            arg <VERSION>\n        }\n        arg <OUTPUT> help=\"Output file path for the tool stub\"\n    }\n}\ncmd global hide=#true help=\"Sets/gets the global tool version(s)\" {\n    long_help \"Sets/gets the global tool version(s)\\n\\nDisplays the contents of global config after writing.\\nThe file is `$HOME/.config/mise/config.toml` by default. It can be changed with `$MISE_GLOBAL_CONFIG_FILE`.\\nIf `$MISE_GLOBAL_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `mise.toml`.\\nOtherwise, it will be parsed as a `.tool-versions` file.\\n\\nUse MISE_ASDF_COMPAT=1 to default the global config to ~/.tool-versions\\n\\nUse `mise local` to set a tool version locally in the current directory.\"\n    after_long_help \"Examples:\\n    # set the current version of node to 20.x\\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\\n    $ mise global --fuzzy node@20\\n\\n    # set the current version of node to 20.x\\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\\n    $ mise global --pin node@20\\n\\n    # show the current version of node in ~/.tool-versions\\n    $ mise global node\\n    20.0.0\\n\"\n    flag --fuzzy help=\"Save fuzzy version to `~/.tool-versions`\\ne.g.: `mise global --fuzzy node@20` will save `node 20` to ~/.tool-versions\\nthis is the default behavior unless MISE_ASDF_COMPAT=1\"\n    flag --path help=\"Get the path of the global config file\"\n    flag --pin help=\"Save exact version to `~/.tool-versions`\\ne.g.: `mise global --pin node@20` will save `node 20.0.0` to ~/.tool-versions\"\n    flag --remove help=\"Remove the plugin(s) from ~/.tool-versions\" var=#true {\n        arg <PLUGIN>\n    }\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to add to .tool-versions\\ne.g.: node@20\\nIf this is a single tool with no version, the current value of the global\\n.tool-versions will be displayed\" required=#false var=#true\n}\ncmd hook-env hide=#true help=\"[internal] called by activate hook to update env vars directory change\" {\n    flag \"-f --force\" help=\"Skip early exit check\"\n    flag \"-q --quiet\" help=\"Hide warnings such as when a tool is not installed\"\n    flag \"-s --shell\" help=\"Shell type to generate script for\" {\n        arg <SHELL> {\n            choices bash elvish fish nu xonsh zsh pwsh\n        }\n    }\n    flag --reason help=\"Reason for calling hook-env (e.g., \\\"precmd\\\", \\\"chpwd\\\")\" hide=#true {\n        arg <REASON> {\n            choices precmd chpwd\n        }\n    }\n    flag --status help=\"Show \\\"mise: <PLUGIN>@<VERSION>\\\" message when changing directories\" hide=#true\n}\ncmd hook-not-found hide=#true help=\"[internal] called by shell when a command is not found\" {\n    flag \"-s --shell\" help=\"Shell type to generate script for\" {\n        arg <SHELL> {\n            choices bash elvish fish nu xonsh zsh pwsh\n        }\n    }\n    arg <BIN> help=\"Attempted bin to run\"\n}\ncmd implode help=\"Removes mise CLI and all related data\" {\n    long_help \"Removes mise CLI and all related data\\n\\nSkips config directory by default.\"\n    flag \"-n --dry-run\" help=\"List directories that would be removed without actually removing them\"\n    flag --config help=\"Also remove config directory\"\n}\ncmd edit help=\"Edit mise.toml interactively\" {\n    after_long_help \"Examples:\\n\\n    $ mise edit             # edit mise.toml interactively\\n    $ mise edit .mise.toml  # edit a specific file\\n    $ mise edit -y          # skip interactive editor\\n    $ mise edit -n          # preview without writing\\n\"\n    flag \"-n --dry-run\" help=\"Show what would be generated without writing to file\"\n    flag \"-t --tool-versions\" help=\"Path to a .tool-versions file to import tools from\" {\n        arg <TOOL_VERSIONS>\n    }\n    arg \"[PATH]\" help=\"Path to the config file to create\" required=#false\n}\ncmd install help=\"Install a tool version\" {\n    alias i\n    long_help \"Install a tool version\\n\\nInstalls a tool version to `~/.local/share/mise/installs/<PLUGIN>/<VERSION>`\\nInstalling alone will not activate the tools so they won't be in PATH.\\nTo install and/or activate in one command, use `mise use` which will create a `mise.toml` file\\nin the current directory to activate this tool when inside the directory.\\nAlternatively, run `mise exec <TOOL>@<VERSION> -- <COMMAND>` to execute a tool without creating config files.\\n\\nTools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1`\"\n    after_long_help \"Examples:\\n\\n    $ mise install node@20.0.0  # install specific node version\\n    $ mise install node@20      # install fuzzy node version\\n    $ mise install node         # install version specified in mise.toml\\n    $ mise install              # installs everything specified in mise.toml\\n\"\n    flag \"-f --force\" help=\"Force reinstall even if already installed\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag \"-n --dry-run\" help=\"Show what would be installed without actually installing\"\n    flag \"-v --verbose\" help=\"Show installation output\" var=#true count=#true {\n        long_help \"Show installation output\\n\\nThis argument will print plugin output such as download, configuration, and compilation output.\"\n    }\n    flag --before help=\"Only install versions released before this date\" {\n        long_help \"Only install versions released before this date\\n\\nSupports absolute dates like \\\"2024-06-01\\\" and relative durations like \\\"90d\\\" or \\\"1y\\\".\"\n        arg <BEFORE>\n    }\n    flag --dry-run-code help=\"Like --dry-run but exits with code 1 if there are tools to install\" {\n        long_help \"Like --dry-run but exits with code 1 if there are tools to install\\n\\nThis is useful for scripts to check if tools need to be installed.\"\n    }\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    flag --shared help=\"[experimental] Install tool(s) to a shared directory\" {\n        long_help \"[experimental] Install tool(s) to a shared directory\\n\\nInstalls to the specified directory instead of the default install location.\\nMay require elevated permissions depending on the path.\"\n        arg <SHARED>\n    }\n    flag --system help=\"[experimental] Install tool(s) to the system-wide shared directory\" {\n        long_help \"[experimental] Install tool(s) to the system-wide shared directory\\n\\nInstalls to /usr/local/share/mise/installs (or MISE_SYSTEM_DATA_DIR/installs).\\nMay require elevated permissions (e.g. sudo).\"\n    }\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to install e.g.: node@20\" required=#false var=#true\n}\ncmd install-into help=\"Install a tool version to a specific path\" {\n    long_help \"Install a tool version to a specific path\\n\\nUsed for building a tool to a directory for use outside of mise\"\n    after_long_help \"Examples:\\n\\n    # install node@20.0.0 into ./mynode\\n    $ mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v\\n    20.0.0\\n\"\n    arg <TOOL@VERSION> help=\"Tool to install e.g.: node@20\"\n    arg <PATH> help=\"Path to install the tool into\"\n}\ncmd latest help=\"Gets the latest available version for a plugin\" {\n    long_help \"Gets the latest available version for a plugin\\n\\nSupports prefixes such as `node@20` to get the latest version of node 20.\"\n    after_long_help \"Examples:\\n\\n    $ mise latest node@20  # get the latest version of node 20\\n    20.0.0\\n\\n    $ mise latest node     # get the latest stable version of node\\n    20.0.0\\n\"\n    flag \"-i --installed\" help=\"Show latest installed instead of available version\"\n    arg <TOOL@VERSION> help=\"Tool to get the latest version of\"\n    arg \"[ASDF_VERSION]\" help=\"The version prefix to use when querying the latest version same as the first argument after the \\\"@\\\" used for asdf compatibility\" required=#false hide=#true\n}\ncmd link help=\"Symlinks a tool version into mise\" {\n    alias ln\n    long_help \"Symlinks a tool version into mise\\n\\nUse this for adding installs either custom compiled outside mise or built with a different tool.\"\n    after_long_help \"Examples:\\n\\n    # build node-20.0.0 with node-build and link it into mise\\n    $ node-build 20.0.0 ~/.nodes/20.0.0\\n    $ mise link node@20.0.0 ~/.nodes/20.0.0\\n\\n    # have mise use the node version provided by Homebrew\\n    $ brew install node\\n    $ mise link node@brew $(brew --prefix node)\\n    $ mise use node@brew\\n\"\n    flag \"-f --force\" help=\"Overwrite an existing tool version if it exists\"\n    arg <TOOL@VERSION> help=\"Tool name and version to create a symlink for\"\n    arg <PATH> help=\"The local path to the tool version\\ne.g.: ~/.nvm/versions/node/v20.0.0\"\n}\ncmd local hide=#true help=\"Sets/gets tool version in local .tool-versions or mise.toml\" {\n    alias l hide=#true\n    long_help \"Sets/gets tool version in local .tool-versions or mise.toml\\n\\nUse this to set a tool's version when within a directory\\nUse `mise global` to set a tool version globally\\nThis uses `.tool-version` by default unless there is a `mise.toml` file or if `MISE_USE_TOML`\\nis set. A future v2 release of mise will default to using `mise.toml`.\"\n    after_long_help \"Examples:\\n    # set the current version of node to 20.x for the current directory\\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\\n    $ mise local node@20\\n\\n    # set node to 20.x for the current project (recurses up to find .tool-versions)\\n    $ mise local -p node@20\\n\\n    # set the current version of node to 20.x for the current directory\\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\\n    $ mise local --fuzzy node@20\\n\\n    # removes node from .tool-versions\\n    $ mise local --remove=node\\n\\n    # show the current version of node in .tool-versions\\n    $ mise local node\\n    20.0.0\\n\"\n    flag \"-p --parent\" help=\"Recurse up to find a .tool-versions file rather than using the current directory only\\nby default this command will only set the tool in the current directory (\\\"$PWD/.tool-versions\\\")\"\n    flag --fuzzy help=\"Save fuzzy version to `.tool-versions` e.g.: `mise local --fuzzy node@20` will save `node 20` to .tool-versions This is the default behavior unless MISE_ASDF_COMPAT=1\"\n    flag --path help=\"Get the path of the config file\"\n    flag --pin help=\"Save exact version to `.tool-versions`\\ne.g.: `mise local --pin node@20` will save `node 20.0.0` to .tool-versions\"\n    flag --remove help=\"Remove the plugin(s) from .tool-versions\" var=#true {\n        arg <PLUGIN>\n    }\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to add to .tool-versions/mise.toml\\ne.g.: node@20\\nif this is a single tool with no version,\\nthe current value of .tool-versions/mise.toml will be displayed\" required=#false var=#true\n}\ncmd lock help=\"Update lockfile checksums and URLs for all specified platforms\" {\n    long_help \"Update lockfile checksums and URLs for all specified platforms\\n\\nUpdates checksums and download URLs for all platforms already specified in the lockfile.\\nIf no lockfile exists, shows what would be created based on the current configuration.\\nThis allows you to refresh lockfile data for platforms other than the one you're currently on.\\nOperates on the lockfile in the current config root. Use TOOL arguments to target specific tools.\"\n    after_long_help \"Examples:\\n\\n    $ mise lock                       # update lockfile for all common platforms\\n    $ mise lock node python           # update only node and python\\n    $ mise lock --platform linux-x64  # update only linux-x64 platform\\n    $ mise lock --dry-run             # show what would be updated\\n    $ mise lock --local               # update mise.local.lock for local configs\\n\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\" {\n        arg <JOBS>\n    }\n    flag \"-n --dry-run\" help=\"Show what would be updated without making changes\"\n    flag \"-p --platform\" help=\"Comma-separated list of platforms to target\\ne.g.: linux-x64,macos-arm64,windows-x64\\nIf not specified, all platforms already in lockfile will be updated\" var=#true {\n        arg <PLATFORM>\n    }\n    flag --local help=\"Update mise.local.lock instead of mise.lock\\nUse for tools defined in .local.toml configs\"\n    arg \"[TOOL]…\" help=\"Tool(s) to update in lockfile\\ne.g.: node python\\nIf not specified, all tools in lockfile will be updated\" required=#false var=#true\n}\ncmd ls help=\"List installed and active tool versions\" {\n    alias list\n    long_help \"List installed and active tool versions\\n\\nThis command lists tools that mise \\\"knows about\\\".\\nThese may be tools that are currently installed, or those\\nthat are in a config file (active) but may or may not be installed.\\n\\nIt's a useful command to get the current state of your tools.\"\n    after_long_help \"Examples:\\n\\n    $ mise ls\\n    node    20.0.0 ~/src/myapp/.tool-versions latest\\n    python  3.11.0 ~/.tool-versions           3.10\\n    python  3.10.0\\n\\n    $ mise ls --current\\n    node    20.0.0 ~/src/myapp/.tool-versions 20\\n    python  3.11.0 ~/.tool-versions           3.11.0\\n\\n    $ mise ls --json\\n    {\\n      \\\"node\\\": [\\n        {\\n          \\\"version\\\": \\\"20.0.0\\\",\\n          \\\"install_path\\\": \\\"/Users/jdx/.mise/installs/node/20.0.0\\\",\\n          \\\"source\\\": {\\n            \\\"type\\\": \\\"mise.toml\\\",\\n            \\\"path\\\": \\\"/Users/jdx/mise.toml\\\"\\n          }\\n        }\\n      ],\\n      \\\"python\\\": [...]\\n    }\\n\\n    $ mise ls --all-sources\\n    node    20.0.0  ~/src/myapp/mise.toml  20\\n                    ~/.config/mise/config.toml  latest\\n\"\n    flag \"-c --current\" help=\"Only show tool versions currently specified in a mise.toml\"\n    flag \"-g --global\" help=\"Only show tool versions currently specified in the global mise.toml\"\n    flag \"-i --installed\" help=\"Only show tool versions that are installed (Hides tools defined in mise.toml but not installed)\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-l --local\" help=\"Only show tool versions currently specified in the local mise.toml\"\n    flag \"-m --missing\" help=\"Display missing tool versions\"\n    flag \"-o --offline\" help=\"Don't fetch information such as outdated versions\" hide=#true\n    flag \"-p --plugin\" hide=#true {\n        arg <TOOL_FLAG>\n    }\n    flag --all-sources help=\"Display all tracked config sources for tools\"\n    flag --no-header help=\"Don't display headers\"\n    flag --outdated help=\"Display whether a version is outdated\"\n    flag --prefix help=\"Display versions matching this prefix\" {\n        arg <PREFIX>\n    }\n    flag --prunable help=\"List only tools that can be pruned with `mise prune`\"\n    arg \"[INSTALLED_TOOL]…\" help=\"Only show tool versions from [TOOL]\" required=#false var=#true\n}\ncmd ls-remote help=\"List runtime versions available for install.\" {\n    alias list-all list-remote hide=#true\n    long_help \"List runtime versions available for install.\\n\\nNote that the results may be cached, run `mise cache clean` to clear the cache and get fresh results.\"\n    after_long_help \"Examples:\\n\\n    $ mise ls-remote node\\n    18.0.0\\n    20.0.0\\n\\n    $ mise ls-remote node@20\\n    20.0.0\\n    20.1.0\\n\\n    $ mise ls-remote node 20\\n    20.0.0\\n    20.1.0\\n\\n    $ mise ls-remote github:cli/cli --json\\n    [{\\\"version\\\":\\\"2.62.0\\\",\\\"created_at\\\":\\\"2024-11-14T15:40:35Z\\\"},{\\\"version\\\":\\\"2.61.0\\\",\\\"created_at\\\":\\\"2024-10-23T19:22:15Z\\\"}]\\n\"\n    flag --all help=\"Show all installed plugins and versions\"\n    flag \"-J --json\" help=\"Output in JSON format (includes version metadata like created_at timestamps when available)\"\n    arg \"[TOOL@VERSION]\" help=\"Tool to get versions for\" required=#false\n    arg \"[PREFIX]\" help=\"The version prefix to use when querying the latest version\\nsame as the first argument after the \\\"@\\\"\" required=#false\n}\ncmd mcp help=\"[experimental] Run Model Context Protocol (MCP) server\" {\n    long_help \"[experimental] Run Model Context Protocol (MCP) server\\n\\nThis command starts an MCP server that exposes mise functionality\\nto AI assistants over stdin/stdout using JSON-RPC protocol.\\n\\nThe MCP server provides access to:\\n- Installed and available tools\\n- Task definitions and execution\\n- Environment variables\\n- Configuration information\\n- Task execution via the run_task tool\\n\\nResources available:\\n- mise://tools - List all tools (use ?include_inactive=true to include inactive tools)\\n- mise://tasks - List all tasks with their configurations\\n- mise://env - List all environment variables\\n- mise://config - Show configuration files and project root\\n\\nTools available:\\n- install_tool - Install a tool with an optional version (not yet implemented)\\n- run_task - Execute a mise task with optional arguments\\n\\nNote: This is primarily intended for integration with AI assistants like Claude,\\nCursor, or other tools that support the Model Context Protocol.\"\n    after_long_help \"Examples:\\n\\n    # Start the MCP server (typically used by AI assistant tools)\\n    $ mise mcp\\n\\n    # Example integration with Claude Desktop (add to claude_desktop_config.json):\\n    {\\n      \\\"mcpServers\\\": {\\n        \\\"mise\\\": {\\n          \\\"command\\\": \\\"mise\\\",\\n          \\\"args\\\": [\\\"mcp\\\"],\\n          \\\"env\\\": {\\n            \\\"MISE_EXPERIMENTAL\\\": \\\"1\\\"\\n          }\\n        }\\n      }\\n    }\\n\\n    # Interactive testing with JSON-RPC commands:\\n    $ echo '{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"id\\\":1,\\\"method\\\":\\\"initialize\\\",\\\"params\\\":{\\\"protocolVersion\\\":\\\"2024-11-05\\\",\\\"capabilities\\\":{},\\\"clientInfo\\\":{\\\"name\\\":\\\"test\\\",\\\"version\\\":\\\"1.0\\\"}}}' | mise mcp\\n\\n    # Resources you can query:\\n    - mise://tools - List active tools\\n    - mise://tools?include_inactive=true - List all installed tools\\n    - mise://tasks - List all tasks\\n    - mise://env - List environment variables\\n    - mise://config - Show configuration info\\n\\n    # Tools available:\\n    - install_tool - Install a tool (not yet implemented)\\n    - run_task - Execute a mise task with optional arguments\\n      Example: {\\\"task\\\": \\\"build\\\", \\\"args\\\": [\\\"--verbose\\\"]}\\n\"\n}\ncmd outdated help=\"Shows outdated tool versions\" {\n    long_help \"Shows outdated tool versions\\n\\nSee `mise upgrade` to upgrade these versions.\"\n    after_long_help \"Examples:\\n\\n    $ mise outdated\\n    Plugin  Requested  Current  Latest\\n    python  3.11       3.11.0   3.11.1\\n    node    20         20.0.0   20.1.0\\n\\n    $ mise outdated node\\n    Plugin  Requested  Current  Latest\\n    node    20         20.0.0   20.1.0\\n\\n    $ mise outdated --json\\n    {\\\"python\\\": {\\\"requested\\\": \\\"3.11\\\", \\\"current\\\": \\\"3.11.0\\\", \\\"latest\\\": \\\"3.11.1\\\"}, ...}\\n\\n    $ mise outdated --local\\n    Plugin  Requested  Current  Latest\\n    node    20         20.0.0   20.1.0\\n\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-l --bump\" help=\"Compares against the latest versions available, not what matches the current config\" {\n        long_help \"Compares against the latest versions available, not what matches the current config\\n\\nFor example, if you have `node = \\\"20\\\"` in your config by default `mise outdated` will only\\nshow other 20.x versions, not 21.x or 22.x versions.\\n\\nUsing this flag, if there are 21.x or newer versions it will display those instead of 20.x.\"\n    }\n    flag --local help=\"Only show outdated tools defined in local config files\" {\n        long_help \"Only show outdated tools defined in local config files\\n\\nThis will only show tools that are defined in project-local mise.toml and\\nwill skip tools defined in the global config (~/.config/mise/config.toml).\"\n    }\n    flag --no-header help=\"Don't show table header\"\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to show outdated versions for\\ne.g.: node@20 python@3.10\\nIf not specified, all tools in global and local configs will be shown\" required=#false var=#true\n}\ncmd plugins help=\"Manage plugins\" {\n    alias p\n    alias plugin plugin-list hide=#true\n    flag \"-a --all\" help=\"list all available remote plugins\" hide=#true {\n        long_help \"list all available remote plugins\\n\\nsame as `mise plugins ls-remote`\"\n    }\n    flag \"-c --core\" help=\"The built-in plugins only\\nNormally these are not shown\"\n    flag \"-u --urls\" help=\"Show the git url for each plugin\\ne.g.: https://github.com/mise-plugins/vfox-cmake.git\"\n    flag --refs help=\"Show the git refs for each plugin\\ne.g.: main 1234abc\" hide=#true\n    flag --user help=\"List installed plugins\" {\n        long_help \"List installed plugins\\n\\nThis is the default behavior but can be used with --core\\nto show core and user plugins\"\n    }\n    cmd install help=\"Install a plugin\" {\n        alias i a add\n        long_help \"Install a plugin\\n\\nnote that mise automatically can install plugins when you install a tool\\ne.g.: `mise install cmake@3.30` will autoinstall the cmake plugin\\n\\nThis behavior can be modified in ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    # install the poetry via shorthand\\n    $ mise plugins install poetry\\n\\n    # install the poetry plugin using a specific git url\\n    $ mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git\\n\\n    # install the poetry plugin using the git url only\\n    # (poetry is inferred from the url)\\n    $ mise plugins install https://github.com/mise-plugins/mise-poetry.git\\n\\n    # install the poetry plugin using a specific ref\\n    $ mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git#11d0c1e\\n\"\n        flag \"-a --all\" help=\"Install all missing plugins\\nThis will only install plugins that have matching shorthands.\\ni.e.: they don't need the full git repo url\"\n        flag \"-f --force\" help=\"Reinstall even if plugin exists\"\n        flag \"-j --jobs\" help=\"Number of jobs to run in parallel\" {\n            arg <JOBS>\n        }\n        flag \"-v --verbose\" help=\"Show installation output\" var=#true count=#true\n        arg \"[NEW_PLUGIN]\" help=\"The name of the plugin to install\\ne.g.: cmake, poetry\\nCan specify multiple plugins: `mise plugins install cmake poetry`\" required=#false\n        arg \"[GIT_URL]\" help=\"The git url of the plugin\" required=#false\n        arg \"[REST]…\" required=#false var=#true hide=#true\n    }\n    cmd link help=\"Symlinks a plugin into mise\" {\n        alias ln\n        long_help \"Symlinks a plugin into mise\\n\\nThis is used for developing a plugin.\"\n        after_long_help \"Examples:\\n\\n    # essentially just `ln -s ./vfox-cmake ~/.local/share/mise/plugins/cmake`\\n    $ mise plugins link cmake ./vfox-cmake\\n\\n    # infer plugin name as \\\"cmake\\\"\\n    $ mise plugins link ./vfox-cmake\\n\"\n        flag \"-f --force\" help=\"Overwrite existing plugin\"\n        arg <NAME> help=\"The name of the plugin\\ne.g.: cmake, poetry\"\n        arg \"[DIR]\" help=\"The local path to the plugin\\ne.g.: ./vfox-cmake\" required=#false\n    }\n    cmd ls help=\"List installed plugins\" {\n        alias list\n        long_help \"List installed plugins\\n\\nCan also show remotely available plugins to install.\"\n        after_long_help \"Examples:\\n\\n    $ mise plugins ls\\n    cmake\\n    poetry\\n\\n    $ mise plugins ls --urls\\n    cmake     https://github.com/mise-plugins/vfox-cmake.git\\n    poetry    https://github.com/mise-plugins/vfox-poetry.git\\n\"\n        flag \"-a --all\" help=\"List all available remote plugins\\nSame as `mise plugins ls-remote`\" hide=#true\n        flag \"-c --core\" help=\"The built-in plugins only\\nNormally these are not shown\" hide=#true\n        flag \"-o --outdated\" help=\"Show plugins with available updates\\nChecks the remote for newer versions and only displays plugins that are outdated\"\n        flag \"-u --urls\" help=\"Show the git url for each plugin\\ne.g.: https://github.com/mise-plugins/vfox-cmake.git\"\n        flag --refs help=\"Show the git refs for each plugin\\ne.g.: main 1234abc\" hide=#true\n        flag --user help=\"List installed plugins\" hide=#true\n    }\n    cmd ls-remote help=\"List all available remote plugins\" {\n        alias list-remote list-all\n        long_help \"\\nList all available remote plugins\\n\\nThe full list is here: https://github.com/jdx/mise/blob/main/registry/\\n\\nExamples:\\n\\n    $ mise plugins ls-remote\\n\"\n        flag \"-u --urls\" help=\"Show the git url for each plugin e.g.: https://github.com/mise-plugins/mise-poetry.git\"\n        flag --only-names help=\"Only show the name of each plugin by default it will show a \\\"*\\\" next to installed plugins\"\n    }\n    cmd uninstall help=\"Removes a plugin\" {\n        alias remove rm\n        after_long_help \"Examples:\\n\\n    $ mise plugins uninstall cmake\\n\"\n        flag \"-a --all\" help=\"Remove all plugins\"\n        flag \"-p --purge\" help=\"Also remove the plugin's installs, downloads, and cache\"\n        arg \"[PLUGIN]…\" help=\"Plugin(s) to remove\" required=#false var=#true\n    }\n    cmd update help=\"Updates a plugin to the latest version\" {\n        alias up upgrade\n        long_help \"Updates a plugin to the latest version\\n\\nnote: this updates the plugin itself, not the runtime versions\"\n        after_long_help \"Examples:\\n\\n    $ mise plugins update              # update all plugins\\n    $ mise plugins update cmake       # update only cmake\\n    $ mise plugins update cmake#beta  # specify a ref\\n\"\n        flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\nDefault: 4\" {\n            arg <JOBS>\n        }\n        arg \"[PLUGIN]…\" help=\"Plugin(s) to update\" required=#false var=#true\n    }\n}\ncmd prepare help=\"[experimental] Ensure project dependencies are ready\" {\n    alias prep\n    long_help \"[experimental] Ensure project dependencies are ready\\n\\nRuns all applicable prepare steps for the current project.\\nThis checks if dependency lockfiles are newer than installed outputs\\n(e.g., package-lock.json vs node_modules/) and runs install commands\\nif needed.\\n\\nProviders with `auto = true` are automatically invoked before `mise x` and `mise run`\\nunless skipped with the --no-prepare flag.\"\n    after_long_help \"Examples:\\n\\n    $ mise prepare              # Run all applicable prepare steps\\n    $ mise prepare npm          # Run only npm prepare\\n    $ mise prepare npm --explain # Show why npm is fresh or stale\\n    $ mise prepare --dry-run    # Show what would run without executing\\n    $ mise prepare --force      # Force run even if outputs are fresh\\n    $ mise prepare --list       # List available prepare providers\\n    $ mise prepare --skip npm   # Skip npm prepare\\n\\nConfiguration:\\n\\n    Configure prepare providers in mise.toml:\\n\\n    ```toml\\n    # Built-in npm provider (auto-detects lockfile)\\n    [prepare.npm]\\n    auto = true              # Auto-run before mise x/run\\n\\n    # Custom provider\\n    [prepare.codegen]\\n    auto = true\\n    sources = [\\\"schema/*.graphql\\\"]\\n    outputs = [\\\"src/generated/\\\"]\\n    run = \\\"npm run codegen\\\"\\n\\n    [prepare]\\n    disable = [\\\"npm\\\"]        # Disable specific providers at runtime\\n    ```\\n\"\n    flag --explain help=\"Show why a provider is fresh or stale (requires a provider argument)\"\n    flag \"-f --force\" help=\"Force run all prepare steps even if outputs are fresh\"\n    flag \"-n --dry-run\" help=\"Only check if prepare is needed, don't run commands\"\n    flag --list help=\"Show what prepare steps are available\"\n    flag --only help=\"Run specific prepare rule(s) only\" var=#true {\n        arg <ONLY>\n    }\n    flag --skip help=\"Skip specific prepare rule(s)\" var=#true {\n        arg <SKIP>\n    }\n    arg \"[PROVIDER]\" help=\"Provider to operate on (runs only this provider, or use with --explain)\" required=#false\n}\ncmd prune help=\"Delete unused versions of tools\" {\n    long_help \"Delete unused versions of tools\\n\\nmise tracks which config files have been used in ~/.local/state/mise/tracked-configs\\nVersions which are no longer the latest specified in any of those configs are deleted.\\nVersions installed only with environment variables `MISE_<PLUGIN>_VERSION` will be deleted,\\nas will versions only referenced on the command line `mise exec <PLUGIN>@<VERSION>`.\\n\\nYou can list prunable tools with `mise ls --prunable`\"\n    after_long_help \"Examples:\\n\\n    $ mise prune --dry-run\\n    rm -rf ~/.local/share/mise/versions/node/20.0.0\\n    rm -rf ~/.local/share/mise/versions/node/20.0.1\\n\"\n    flag \"-n --dry-run\" help=\"Do not actually delete anything\"\n    flag --configs help=\"Prune only tracked and trusted configuration links that point to non-existent configurations\"\n    flag --dry-run-code help=\"Like --dry-run but exits with code 1 if there are tools to prune\" {\n        long_help \"Like --dry-run but exits with code 1 if there are tools to prune\\n\\nThis is useful for scripts to check if tools need to be pruned.\"\n    }\n    flag --tools help=\"Prune only unused versions of tools\"\n    arg \"[INSTALLED_TOOL]…\" help=\"Prune only these tools\" required=#false var=#true\n}\ncmd registry help=\"List available tools to install\" {\n    long_help \"List available tools to install\\n\\nThis command lists the tools available in the registry as shorthand names.\\n\\nFor example, `poetry` is shorthand for `asdf:mise-plugins/mise-poetry`.\"\n    after_long_help \"Examples:\\n\\n    $ mise registry\\n    node    core:node\\n    poetry  asdf:mise-plugins/mise-poetry\\n    ubi     cargo:ubi-cli\\n\\n    $ mise registry poetry\\n    asdf:mise-plugins/mise-poetry\\n\"\n    flag \"-b --backend\" help=\"Show only tools for this backend\" {\n        arg <BACKEND>\n    }\n    flag --complete help=\"Print all tools with descriptions for shell completions\" hide=#true\n    flag --hide-aliased help=\"Hide aliased tools\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    arg \"[NAME]\" help=\"Show only the specified tool's full name\" required=#false\n}\ncmd render-help hide=#true help=\"internal command to generate markdown from help\"\ncmd reshim help=\"Creates new shims based on bin paths from currently installed tools.\" {\n    long_help \"Creates new shims based on bin paths from currently installed tools.\\n\\nThis creates new shims in ~/.local/share/mise/shims for CLIs that have been added.\\nmise will try to do this automatically for commands like `npm i -g` but there are\\nother ways to install things (like using yarn or pnpm for node) that mise does\\nnot know about and so it will be necessary to call this explicitly.\\n\\nIf you think mise should automatically call this for a particular command, please\\nopen an issue on the mise repo. You can also setup a shell function to reshim\\nautomatically (it's really fast so you don't need to worry about overhead):\\n\\n    npm() {\\n      command npm \\\"$@\\\"\\n      mise reshim\\n    }\\n\\nNote that this creates shims for _all_ installed tools, not just the ones that are\\ncurrently active in mise.toml.\"\n    after_long_help \"Examples:\\n\\n    $ mise reshim\\n    $ ~/.local/share/mise/shims/node -v\\n    v20.0.0\\n\"\n    flag \"-f --force\" help=\"Removes all shims before reshimming\"\n    arg \"[PLUGIN]\" required=#false hide=#true\n    arg \"[VERSION]\" required=#false hide=#true\n}\ncmd run restart_token=::: help=\"Run task(s)\" {\n    alias r\n    long_help \"Run task(s)\\n\\nThis command will run a task, or multiple tasks in parallel.\\nTasks may have dependencies on other tasks or on source files.\\nIf source is configured on a task, it will only run if the source\\nfiles have changed.\\n\\nTasks can be defined in mise.toml or as standalone scripts.\\nIn mise.toml, tasks take this form:\\n\\n    [tasks.build]\\n    run = \\\"npm run build\\\"\\n    sources = [\\\"src/**/*.ts\\\"]\\n    outputs = [\\\"dist/**/*.js\\\"]\\n\\nAlternatively, tasks can be defined as standalone scripts.\\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\\n`.config/mise/tasks`.\\nThe name of the script will be the name of the tasks.\\n\\n    $ cat .mise/tasks/build<<EOF\\n    #!/usr/bin/env bash\\n    npm run build\\n    EOF\\n    $ mise run build\"\n    after_long_help \"Examples:\\n\\n    # Runs the \\\"lint\\\" tasks. This needs to either be defined in mise.toml\\n    # or as a standalone script. See the project README for more information.\\n    $ mise run lint\\n\\n    # Forces the \\\"build\\\" tasks to run even if its sources are up-to-date.\\n    $ mise run --force build\\n\\n    # Run \\\"test\\\" with stdin/stdout/stderr all connected to the current terminal.\\n    # This forces `--jobs=1` to prevent interleaving of output.\\n    $ mise run --raw test\\n\\n    # Runs the \\\"lint\\\", \\\"test\\\", and \\\"check\\\" tasks in parallel.\\n    $ mise run lint ::: test ::: check\\n\\n    # Execute multiple tasks each with their own arguments.\\n    $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\\n\"\n    flag \"-c --continue-on-error\" help=\"Continue running tasks even if one fails\"\n    flag \"-C --cd\" help=\"Change to this directory before executing the command\" {\n        arg <CD>\n    }\n    flag \"-f --force\" help=\"Force the tasks to run even if outputs are up to date\"\n    flag \"-i --interleave\" help=\"Print directly to stdout/stderr instead of by line\\nDefaults to true if --jobs == 1\\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\" hide=#true\n    flag \"-j --jobs\" help=\"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\" {\n        arg <JOBS>\n    }\n    flag \"-n --dry-run\" help=\"Don't actually run the task(s), just print them in order of execution\"\n    flag \"-o --output\" help=\"Change how tasks information is output when running tasks\" {\n        long_help \"Change how tasks information is output when running tasks\\n\\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\\n- `interleave` - Print directly to stdout/stderr instead of by line\\n- `replacing` - Stdout is replaced each time, stderr is printed as is\\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\\n- `quiet` - Don't show extra output\\n- `silent` - Don't show any output including stdout and stderr from the task except for errors\"\n        arg <OUTPUT>\n    }\n    flag \"-p --prefix\" help=\"Print stdout/stderr by line, prefixed with the task's label\\nDefaults to true if --jobs > 1\\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\" hide=#true\n    flag \"-q --quiet\" help=\"Don't show extra output\"\n    flag \"-r --raw\" help=\"Read/write directly to stdin/stdout/stderr instead of by line\\nRedactions are not applied with this option\\nConfigure with `raw` config or `MISE_RAW` env var\"\n    flag \"-s --shell\" help=\"Shell to use to run toml tasks\" {\n        long_help \"Shell to use to run toml tasks\\n\\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\\nOr it can be overridden with the `shell` property on a task.\"\n        arg <SHELL>\n    }\n    flag \"-S --silent\" help=\"Don't show any output except for errors\"\n    flag \"-t --tool\" help=\"Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\" var=#true {\n        arg <TOOL@VERSION>\n    }\n    flag --fresh-env help=\"Bypass the environment cache and recompute the environment\"\n    flag --no-cache help=\"Do not use cache on remote tasks\"\n    flag --no-prepare help=\"Skip automatic dependency preparation\"\n    flag --no-timings help=\"Hides elapsed time after each task completes\" {\n        long_help \"Hides elapsed time after each task completes\\n\\nDefault to always hide with `MISE_TASK_TIMINGS=0`\"\n    }\n    flag --skip-deps help=\"Run only the specified tasks skipping all dependencies\"\n    flag --timeout help=\"Timeout for the task to complete\\ne.g.: 30s, 5m\" {\n        arg <TIMEOUT>\n    }\n    flag --timings help=\"Shows elapsed time after each task completes\" hide=#true {\n        long_help \"Shows elapsed time after each task completes\\n\\nDefault to always show with `MISE_TASK_TIMINGS=1`\"\n    }\n    mount run=\"mise tasks --usage\"\n}\ncmd search help=\"Search for tools in the registry\" {\n    long_help \"Search for tools in the registry\\n\\nThis command searches a tool in the registry.\\n\\nBy default, it will show all tools that fuzzy match the search term. For\\nnon-fuzzy matches, use the `--match-type` flag.\"\n    after_long_help \"Examples:\\n\\n    $ mise search jq\\n    Tool  Description\\n    jq    Command-line JSON processor. https://github.com/jqlang/jq\\n    jqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\\n    jiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\\n    gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\\n\\n    $ mise search --interactive\\n    Tool\\n    Search a tool\\n    ❯ jq    Command-line JSON processor. https://github.com/jqlang/jq\\n      jqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\\n      jiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\\n      gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\\n    /jq \\n    esc clear filter • enter confirm\\n\"\n    flag \"-i --interactive\" help=\"Show interactive search\"\n    flag \"-m --match-type\" help=\"Match type: equal, contains, or fuzzy\" default=fuzzy {\n        arg <MATCH_TYPE> {\n            choices equal contains fuzzy\n        }\n    }\n    flag --no-header help=\"Don't display headers\"\n    arg \"[NAME]\" help=\"The tool to search for\" required=#false\n}\ncmd self-update help=\"Updates mise itself.\" {\n    long_help \"Updates mise itself.\\n\\nUses the GitHub Releases API to find the latest release and binary.\\nBy default, this will also update any installed plugins.\\nUses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits.\\n\\nThis command is not available if mise is installed via a package manager.\"\n    flag \"-f --force\" help=\"Update even if already up to date\"\n    flag \"-y --yes\" help=\"Skip confirmation prompt\"\n    flag --no-plugins help=\"Disable auto-updating plugins\"\n    arg \"[VERSION]\" help=\"Update to a specific version\" required=#false\n}\ncmd set help=\"Set environment variables in mise.toml\" {\n    alias ev env-vars hide=#true\n    long_help \"Set environment variables in mise.toml\\n\\nBy default, this command modifies `mise.toml` in the current directory.\\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\\nthe lowest precedence file (`mise.toml`) will be used.\\nSee https://mise.jdx.dev/configuration.html#target-file-for-write-operations\\n\\nUse `-E <env>` to create/modify environment-specific config files like `mise.<env>.toml`.\"\n    after_long_help \"Examples:\\n\\n    $ mise set NODE_ENV=production\\n\\n    $ mise set NODE_ENV\\n    production\\n\\n    $ mise set -E staging NODE_ENV=staging\\n    # creates or modifies mise.staging.toml\\n\\n    $ mise set\\n    key       value       source\\n    NODE_ENV  production  ~/.config/mise/config.toml\\n\\n    $ mise set --prompt PASSWORD\\n    Enter value for PASSWORD: [hidden input]\\n\\n    Multiline Values (--stdin):\\n\\n    $ cat private.key | mise set --stdin MY_KEY\\n\\n    $ printf \\\"line1\\\\nline2\\\" | mise set --stdin MY_KEY\\n\\n    [experimental] Age Encryption:\\n\\n    $ mise set --age-encrypt API_KEY=secret\\n\\n    $ mise set --age-encrypt --prompt API_KEY\\n    Enter value for API_KEY: [hidden input]\\n\"\n    flag \"-E --env\" help=\"Create/modify an environment-specific config file like .mise.<env>.toml\" {\n        arg <ENV>\n    }\n    flag \"-g --global\" help=\"Set the environment variable in the global config file\"\n    flag --age-encrypt help=\"[experimental] Encrypt the value with age before storing\"\n    flag --age-key-file help=\"[experimental] Age identity file for encryption\" {\n        long_help \"[experimental] Age identity file for encryption\\n\\nDefaults to ~/.config/mise/age.txt if it exists\"\n        arg <PATH>\n    }\n    flag --age-recipient help=\"[experimental] Age recipient (x25519 public key) for encryption\" var=#true {\n        long_help \"[experimental] Age recipient (x25519 public key) for encryption\\n\\nCan be used multiple times. Requires --age-encrypt.\"\n        arg <RECIPIENT>\n    }\n    flag --age-ssh-recipient help=\"[experimental] SSH recipient (public key or path) for age encryption\" var=#true {\n        long_help \"[experimental] SSH recipient (public key or path) for age encryption\\n\\nCan be used multiple times. Requires --age-encrypt.\"\n        arg <PATH_OR_PUBKEY>\n    }\n    flag --complete help=\"Render completions\" hide=#true\n    flag --file help=\"The TOML file to update\" {\n        long_help \"The TOML file to update\\n\\nCan be a file path or directory. If a directory is provided, will create/use mise.toml in that directory.\\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`.\"\n        arg <FILE>\n    }\n    flag --no-redact help=\"Show raw values instead of redacting secrets\"\n    flag --prompt help=\"Prompt for environment variable values\"\n    flag \"--remove --rm --unset\" help=\"Remove the environment variable from config file\" var=#true hide=#true {\n        long_help \"Remove the environment variable from config file\\n\\nCan be used multiple times.\"\n        arg <ENV_KEY>\n    }\n    flag --stdin help=\"Read the value from stdin (for multiline input)\" {\n        long_help \"Read the value from stdin (for multiline input)\\n\\nWhen using --stdin, provide a single key without a value. The value will be read from stdin until EOF.\"\n    }\n    arg \"[ENV_VAR]…\" help=\"Environment variable(s) to set\\ne.g.: NODE_ENV=production\" required=#false var=#true\n}\ncmd settings help=\"Manage settings\" {\n    long_help \"Show current settings\\n\\nThis is the contents of ~/.config/mise/config.toml\\n\\nNote that aliases are also stored in this file\\nbut managed separately with `mise tool-alias`\"\n    after_long_help \"Examples:\\n    # list all settings\\n    $ mise settings\\n\\n    # get the value of the setting \\\"always_keep_download\\\"\\n    $ mise settings always_keep_download\\n\\n    # set the value of the setting \\\"always_keep_download\\\" to \\\"true\\\"\\n    $ mise settings always_keep_download=true\\n\\n    # set the value of the setting \\\"node.mirror_url\\\" to \\\"https://npm.taobao.org/mirrors/node\\\"\\n    $ mise settings node.mirror_url https://npm.taobao.org/mirrors/node\\n\"\n    flag \"-a --all\" help=\"List all settings\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag \"-l --local\" help=\"Use the local config file instead of the global one\" global=#true\n    flag \"-T --toml\" help=\"Output in TOML format\"\n    flag --complete help=\"Print all settings with descriptions for shell completions\" hide=#true\n    flag --json-extended help=\"Output in JSON format with sources\"\n    arg \"[SETTING]\" help=\"Name of setting\" required=#false\n    arg \"[VALUE]\" help=\"Setting value to set\" required=#false\n    cmd add help=\"Adds a setting to the configuration file\" {\n        long_help \"Adds a setting to the configuration file\\n\\nUsed with an array setting, this will append the value to the array.\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise settings add disable_hints python_multi\\n\"\n        flag \"-l --local\" help=\"Use the local config file instead of the global one\"\n        arg <SETTING> help=\"The setting to set\"\n        arg \"[VALUE]\" help=\"The value to set (optional if provided as KEY=VALUE)\" required=#false\n    }\n    cmd get help=\"Show a current setting\" {\n        long_help \"Show a current setting\\n\\nThis is the contents of a single entry in ~/.config/mise/config.toml\\n\\nNote that aliases are also stored in this file\\nbut managed separately with `mise tool-alias get`\"\n        after_long_help \"Examples:\\n\\n    $ mise settings get idiomatic_version_file\\n    true\\n\"\n        flag \"-l --local\" help=\"Use the local config file instead of the global one\"\n        arg <SETTING> help=\"The setting to show\"\n    }\n    cmd ls help=\"Show current settings\" {\n        alias list\n        long_help \"Show current settings\\n\\nThis is the contents of ~/.config/mise/config.toml\\n\\nNote that aliases are also stored in this file\\nbut managed separately with `mise tool-alias`\"\n        after_long_help \"Examples:\\n\\n    $ mise settings ls\\n    idiomatic_version_file = false\\n    ...\\n\\n    $ mise settings ls python\\n    default_packages_file = \\\"~/.default-python-packages\\\"\\n    ...\\n\"\n        flag \"-a --all\" help=\"List all settings\"\n        flag \"-J --json\" help=\"Output in JSON format\"\n        flag \"-l --local\" help=\"Use the local config file instead of the global one\" global=#true\n        flag \"-T --toml\" help=\"Output in TOML format\"\n        flag --complete help=\"Print all settings with descriptions for shell completions\" hide=#true\n        flag --json-extended help=\"Output in JSON format with sources\"\n        arg \"[SETTING]\" help=\"Name of setting\" required=#false\n    }\n    cmd set help=\"Add/update a setting\" {\n        alias create\n        long_help \"Add/update a setting\\n\\nThis modifies the contents of ~/.config/mise/config.toml by default.\\nWith `--local`, modifies the local config file instead.\\nSee https://mise.jdx.dev/configuration.html#target-file-for-write-operations\"\n        after_long_help \"Examples:\\n\\n    $ mise settings idiomatic_version_file=true\\n\"\n        flag \"-l --local\" help=\"Use the local config file instead of the global one\"\n        arg <SETTING> help=\"The setting to set\"\n        arg \"[VALUE]\" help=\"The value to set (optional if provided as KEY=VALUE)\" required=#false\n    }\n    cmd unset help=\"Clears a setting\" {\n        alias rm remove delete del\n        long_help \"Clears a setting\\n\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise settings unset idiomatic_version_file\\n\"\n        flag \"-l --local\" help=\"Use the local config file instead of the global one\"\n        arg <KEY> help=\"The setting to remove\"\n    }\n}\ncmd shell help=\"Sets a tool version for the current session.\" {\n    alias sh\n    long_help \"Sets a tool version for the current session.\\n\\nOnly works in a session where mise is already activated.\\n\\nThis works by setting environment variables for the current shell session\\nsuch as `MISE_NODE_VERSION=20` which is \\\"eval\\\"ed as a shell function created by `mise activate`.\"\n    after_long_help \"Examples:\\n\\n    $ mise shell node@20\\n    $ node -v\\n    v20.0.0\\n\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag \"-u --unset\" help=\"Removes a previously set version\"\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg <TOOL@VERSION>… help=\"Tool(s) to use\" var=#true\n}\ncmd shell-alias help=\"Manage shell aliases.\" {\n    flag --no-header help=\"Don't show table header\"\n    cmd get help=\"Show the command for a shell alias\" {\n        after_long_help \"Examples:\\n\\n    $ mise shell-alias get ll\\n    ls -la\\n\"\n        arg <shell_alias> help=\"The alias to show\"\n    }\n    cmd ls help=\"List shell aliases\" {\n        alias list\n        long_help \"List shell aliases\\n\\nShows the shell aliases that are set in the current directory.\\nThese are defined in `mise.toml` under the `[shell_alias]` section.\"\n        after_long_help \"Examples:\\n\\n    $ mise shell-alias ls\\n    alias    command\\n    ll       ls -la\\n    gs       git status\\n\"\n        flag --no-header help=\"Don't show table header\"\n    }\n    cmd set help=\"Add/update a shell alias\" {\n        alias add create\n        long_help \"Add/update a shell alias\\n\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise shell-alias set ll \\\"ls -la\\\"\\n    $ mise shell-alias set gs \\\"git status\\\"\\n\"\n        arg <shell_alias> help=\"The alias name\"\n        arg \"[COMMAND]\" help=\"The command to run (optional if provided as ALIAS=COMMAND)\" required=#false\n    }\n    cmd unset help=\"Removes a shell alias\" {\n        alias rm remove delete del\n        long_help \"Removes a shell alias\\n\\nThis modifies the contents of ~/.config/mise/config.toml\"\n        after_long_help \"Examples:\\n\\n    $ mise shell-alias unset ll\\n\"\n        arg <shell_alias> help=\"The alias to remove\"\n    }\n}\ncmd sync subcommand_required=#true help=\"Synchronize tools from other version managers with mise\" {\n    cmd node help=\"Symlinks all tool versions from an external tool into mise\" {\n        long_help \"Symlinks all tool versions from an external tool into mise\\n\\nFor example, use this to import all Homebrew node installs into mise\\n\\nThis won't overwrite any existing installs but will overwrite any existing symlinks\"\n        after_long_help \"Examples:\\n\\n    $ brew install node@18 node@20\\n    $ mise sync node --brew\\n    $ mise use -g node@18 - uses Homebrew-provided node\\n\"\n        flag --brew help=\"Get tool versions from Homebrew\"\n        flag --nodenv help=\"Get tool versions from nodenv\"\n        flag --nvm help=\"Get tool versions from nvm\"\n    }\n    cmd python help=\"Symlinks all tool versions from an external tool into mise\" {\n        long_help \"Symlinks all tool versions from an external tool into mise\\n\\nFor example, use this to import all pyenv installs into mise\\n\\nThis won't overwrite any existing installs but will overwrite any existing symlinks\"\n        after_long_help \"Examples:\\n\\n    $ pyenv install 3.11.0\\n    $ mise sync python --pyenv\\n    $ mise use -g python@3.11.0 - uses pyenv-provided python\\n    \\n    $ uv python install 3.11.0\\n    $ mise install python@3.10.0\\n    $ mise sync python --uv\\n    $ mise x python@3.11.0 -- python -V - uses uv-provided python\\n    $ uv run -p 3.10.0 -- python -V - uses mise-provided python\\n\"\n        flag --pyenv help=\"Get tool versions from pyenv\"\n        flag --uv help=\"Sync tool versions with uv (2-way sync)\"\n    }\n    cmd ruby help=\"Symlinks all ruby tool versions from an external tool into mise\" {\n        after_long_help \"Examples:\\n\\n    $ brew install ruby\\n    $ mise sync ruby --brew\\n    $ mise use -g ruby - Use the latest version of Ruby installed by Homebrew\\n\"\n        flag --brew help=\"Get tool versions from Homebrew\"\n    }\n}\ncmd tasks help=\"Manage tasks\" {\n    alias t\n    alias task hide=#true\n    after_long_help \"Examples:\\n\\n    $ mise tasks ls\\n\"\n    flag \"-g --global\" help=\"Only show global tasks\" global=#true\n    flag \"-J --json\" help=\"Output in JSON format\" global=#true\n    flag \"-l --local\" help=\"Only show non-global tasks\" global=#true\n    flag \"-x --extended\" help=\"Show all columns\" global=#true\n    flag --all help=\"Load all tasks from the entire monorepo, including sibling directories.\\nBy default, only tasks from the current directory hierarchy are loaded.\" global=#true\n    flag --complete help=\"Display tasks for usage completion\" hide=#true\n    flag --hidden help=\"Show hidden tasks\" global=#true\n    flag --no-header help=\"Do not print table header\" global=#true\n    flag --sort help=\"Sort by column. Default is name.\" global=#true {\n        arg <COLUMN> {\n            choices name alias description source\n        }\n    }\n    flag --sort-order help=\"Sort order. Default is asc.\" global=#true {\n        arg <SORT_ORDER> {\n            choices asc desc\n        }\n    }\n    flag --usage hide=#true global=#true\n    arg \"[TASK]\" help=\"Task name to get info of\" required=#false\n    cmd add help=\"Create a new task\" {\n        long_help \"Create a new task\\n\\nAdds a task to the local mise.toml file.\\nSee https://mise.jdx.dev/configuration.html#target-file-for-write-operations\"\n        after_long_help \"Examples:\\n\\n    $ mise tasks add pre-commit --depends \\\"test\\\" --depends \\\"render\\\" -- echo pre-commit\\n\"\n        flag \"-a --alias\" help=\"Other names for the task\" var=#true {\n            arg <ALIAS>\n        }\n        flag \"-d --depends\" help=\"Add dependencies to the task\" var=#true {\n            arg <DEPENDS>\n        }\n        flag \"-D --dir\" help=\"Run the task in a specific directory\" {\n            arg <DIR>\n        }\n        flag \"-f --file\" help=\"Create a file task instead of a toml task\"\n        flag \"-H --hide\" help=\"Hide the task from `mise tasks` and completions\"\n        flag \"-q --quiet\" help=\"Do not print the command before running\"\n        flag \"-r --raw\" help=\"Directly connect stdin/stdout/stderr\"\n        flag \"-s --sources\" help=\"Glob patterns of files this task uses as input\" var=#true {\n            arg <SOURCES>\n        }\n        flag \"-w --wait-for\" help=\"Wait for these tasks to complete if they are to run\" var=#true {\n            arg <WAIT_FOR>\n        }\n        flag --depends-post help=\"Dependencies to run after the task runs\" var=#true {\n            arg <DEPENDS_POST>\n        }\n        flag --description help=\"Description of the task\" {\n            arg <DESCRIPTION>\n        }\n        flag --outputs help=\"Glob patterns of files this task creates, to skip if they are not modified\" var=#true {\n            arg <OUTPUTS>\n        }\n        flag --run-windows help=\"Command to run on windows\" {\n            arg <RUN_WINDOWS>\n        }\n        flag --shell help=\"Run the task in a specific shell\" {\n            arg <SHELL>\n        }\n        flag --silent help=\"Do not print the command or its output\"\n        arg <TASK> help=\"Tasks name to add\"\n        arg \"[-- RUN]…\" required=#false var=#true\n    }\n    cmd deps help=\"Display a tree visualization of a dependency graph\" {\n        after_long_help \"Examples:\\n\\n    # Show dependencies for all tasks\\n    $ mise tasks deps\\n\\n    # Show dependencies for the \\\"lint\\\", \\\"test\\\" and \\\"check\\\" tasks\\n    $ mise tasks deps lint test check\\n\\n    # Show dependencies in DOT format\\n    $ mise tasks deps --dot\\n\"\n        flag --dot help=\"Display dependencies in DOT format\"\n        flag --hidden help=\"Show hidden tasks\"\n        arg \"[TASKS]…\" help=\"Tasks to show dependencies for\\nCan specify multiple tasks by separating with spaces\\ne.g.: mise tasks deps lint test check\" required=#false var=#true\n    }\n    cmd edit help=\"Edit a task with $EDITOR\" {\n        long_help \"Edit a task with $EDITOR\\n\\nThe task will be created as a standalone script if it does not already exist.\"\n        after_long_help \"Examples:\\n\\n    $ mise tasks edit build\\n    $ mise tasks edit test\\n\"\n        flag \"-p --path\" help=\"Display the path to the task instead of editing it\"\n        arg <TASK> help=\"Task to edit\"\n    }\n    cmd info help=\"Get information about a task\" {\n        after_long_help \"Examples:\\n\\n    $ mise tasks info\\n    Name: test\\n    Aliases: t\\n    Description: Test the application\\n    Source: ~/src/myproj/mise.toml\\n\\n    $ mise tasks info test --json\\n    {\\n      \\\"name\\\": \\\"test\\\",\\n      \\\"aliases\\\": \\\"t\\\",\\n      \\\"description\\\": \\\"Test the application\\\",\\n      \\\"source\\\": \\\"~/src/myproj/mise.toml\\\",\\n      \\\"depends\\\": [],\\n      \\\"env\\\": {},\\n      \\\"dir\\\": null,\\n      \\\"hide\\\": false,\\n      \\\"raw\\\": false,\\n      \\\"sources\\\": [],\\n      \\\"outputs\\\": [],\\n      \\\"run\\\": [\\n        \\\"echo \\\\\\\"testing!\\\\\\\"\\\"\\n      ],\\n      \\\"file\\\": null,\\n      \\\"usage_spec\\\": {}\\n    }\\n\"\n        flag \"-J --json\" help=\"Output in JSON format\"\n        arg <TASK> help=\"Name of the task to get information about\"\n    }\n    cmd ls help=\"List available tasks to execute\\nThese may be included from the config file or from the project's .mise/tasks directory\\nmise will merge all tasks from all parent directories into this list.\" {\n        long_help \"List available tasks to execute\\nThese may be included from the config file or from the project's .mise/tasks directory\\nmise will merge all tasks from all parent directories into this list.\\n\\nSo if you have global tasks in `~/.config/mise/tasks/*` and project-specific tasks in\\n~/myproject/.mise/tasks/*, then they'll both be available but the project-specific\\ntasks will override the global ones if they have the same name.\"\n        after_long_help \"Examples:\\n\\n    $ mise tasks ls\\n\"\n        flag \"-g --global\" help=\"Only show global tasks\" global=#true\n        flag \"-J --json\" help=\"Output in JSON format\" global=#true\n        flag \"-l --local\" help=\"Only show non-global tasks\" global=#true\n        flag \"-x --extended\" help=\"Show all columns\" global=#true\n        flag --all help=\"Load all tasks from the entire monorepo, including sibling directories.\\nBy default, only tasks from the current directory hierarchy are loaded.\" global=#true\n        flag --complete help=\"Display tasks for usage completion\" hide=#true\n        flag --hidden help=\"Show hidden tasks\" global=#true\n        flag --no-header help=\"Do not print table header\" global=#true\n        flag --sort help=\"Sort by column. Default is name.\" global=#true {\n            arg <COLUMN> {\n                choices name alias description source\n            }\n        }\n        flag --sort-order help=\"Sort order. Default is asc.\" global=#true {\n            arg <SORT_ORDER> {\n                choices asc desc\n            }\n        }\n        flag --usage hide=#true global=#true\n    }\n    cmd run restart_token=::: help=\"Run task(s)\" {\n        alias r\n        long_help \"Run task(s)\\n\\nThis command will run a task, or multiple tasks in parallel.\\nTasks may have dependencies on other tasks or on source files.\\nIf source is configured on a task, it will only run if the source\\nfiles have changed.\\n\\nTasks can be defined in mise.toml or as standalone scripts.\\nIn mise.toml, tasks take this form:\\n\\n    [tasks.build]\\n    run = \\\"npm run build\\\"\\n    sources = [\\\"src/**/*.ts\\\"]\\n    outputs = [\\\"dist/**/*.js\\\"]\\n\\nAlternatively, tasks can be defined as standalone scripts.\\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\\n`.config/mise/tasks`.\\nThe name of the script will be the name of the tasks.\\n\\n    $ cat .mise/tasks/build<<EOF\\n    #!/usr/bin/env bash\\n    npm run build\\n    EOF\\n    $ mise run build\"\n        after_long_help \"Examples:\\n\\n    # Runs the \\\"lint\\\" tasks. This needs to either be defined in mise.toml\\n    # or as a standalone script. See the project README for more information.\\n    $ mise run lint\\n\\n    # Forces the \\\"build\\\" tasks to run even if its sources are up-to-date.\\n    $ mise run --force build\\n\\n    # Run \\\"test\\\" with stdin/stdout/stderr all connected to the current terminal.\\n    # This forces `--jobs=1` to prevent interleaving of output.\\n    $ mise run --raw test\\n\\n    # Runs the \\\"lint\\\", \\\"test\\\", and \\\"check\\\" tasks in parallel.\\n    $ mise run lint ::: test ::: check\\n\\n    # Execute multiple tasks each with their own arguments.\\n    $ mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2\\n\"\n        flag \"-c --continue-on-error\" help=\"Continue running tasks even if one fails\"\n        flag \"-C --cd\" help=\"Change to this directory before executing the command\" {\n            arg <CD>\n        }\n        flag \"-f --force\" help=\"Force the tasks to run even if outputs are up to date\"\n        flag \"-i --interleave\" help=\"Print directly to stdout/stderr instead of by line\\nDefaults to true if --jobs == 1\\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\" hide=#true\n        flag \"-j --jobs\" help=\"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\" {\n            arg <JOBS>\n        }\n        flag \"-n --dry-run\" help=\"Don't actually run the task(s), just print them in order of execution\"\n        flag \"-o --output\" help=\"Change how tasks information is output when running tasks\" {\n            long_help \"Change how tasks information is output when running tasks\\n\\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\\n- `interleave` - Print directly to stdout/stderr instead of by line\\n- `replacing` - Stdout is replaced each time, stderr is printed as is\\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\\n- `quiet` - Don't show extra output\\n- `silent` - Don't show any output including stdout and stderr from the task except for errors\"\n            arg <OUTPUT>\n        }\n        flag \"-p --prefix\" help=\"Print stdout/stderr by line, prefixed with the task's label\\nDefaults to true if --jobs > 1\\nConfigure with `task.output` config or `MISE_TASK_OUTPUT` env var\" hide=#true\n        flag \"-q --quiet\" help=\"Don't show extra output\"\n        flag \"-r --raw\" help=\"Read/write directly to stdin/stdout/stderr instead of by line\\nRedactions are not applied with this option\\nConfigure with `raw` config or `MISE_RAW` env var\"\n        flag \"-s --shell\" help=\"Shell to use to run toml tasks\" {\n            long_help \"Shell to use to run toml tasks\\n\\nDefaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\\nCan also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\\nOr it can be overridden with the `shell` property on a task.\"\n            arg <SHELL>\n        }\n        flag \"-S --silent\" help=\"Don't show any output except for errors\"\n        flag \"-t --tool\" help=\"Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\" var=#true {\n            arg <TOOL@VERSION>\n        }\n        flag --fresh-env help=\"Bypass the environment cache and recompute the environment\"\n        flag --no-cache help=\"Do not use cache on remote tasks\"\n        flag --no-prepare help=\"Skip automatic dependency preparation\"\n        flag --no-timings help=\"Hides elapsed time after each task completes\" {\n            long_help \"Hides elapsed time after each task completes\\n\\nDefault to always hide with `MISE_TASK_TIMINGS=0`\"\n        }\n        flag --skip-deps help=\"Run only the specified tasks skipping all dependencies\"\n        flag --timeout help=\"Timeout for the task to complete\\ne.g.: 30s, 5m\" {\n            arg <TIMEOUT>\n        }\n        flag --timings help=\"Shows elapsed time after each task completes\" hide=#true {\n            long_help \"Shows elapsed time after each task completes\\n\\nDefault to always show with `MISE_TASK_TIMINGS=1`\"\n        }\n        arg \"[TASK]\" help=\"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\" required=#false default=default\n        arg \"[ARGS]…\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks\" required=#false var=#true\n        arg \"[-- ARGS_LAST]…\" help=\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks\" required=#false var=#true hide=#true\n        mount run=\"mise tasks --usage\"\n    }\n    cmd validate help=\"Validate tasks for common errors and issues\" {\n        after_long_help \"Examples:\\n\\n    # Validate all tasks\\n    $ mise tasks validate\\n\\n    # Validate specific tasks\\n    $ mise tasks validate build test\\n\\n    # Output results as JSON\\n    $ mise tasks validate --json\\n\\n    # Only show errors (skip warnings)\\n    $ mise tasks validate --errors-only\\n\\nValidation Checks:\\n\\nThe validate command performs the following checks:\\n\\n  • Circular Dependencies: Detects dependency cycles\\n  • Missing References: Finds references to non-existent tasks\\n  • Usage Spec Parsing: Validates #USAGE directives and specs\\n  • Timeout Format: Checks timeout values are valid durations\\n  • Alias Conflicts: Detects duplicate aliases across tasks\\n  • File Existence: Verifies file-based tasks exist\\n  • Directory Templates: Validates directory paths and templates\\n  • Shell Commands: Checks shell executables exist\\n  • Glob Patterns: Validates source and output patterns\\n  • Run Entries: Ensures tasks reference valid dependencies\\n\"\n        flag --errors-only help=\"Only show errors (skip warnings)\"\n        flag --json help=\"Output validation results in JSON format\"\n        arg \"[TASKS]…\" help=\"Tasks to validate\\nIf not specified, validates all tasks\" required=#false var=#true\n    }\n}\ncmd test-tool help=\"Test a tool installs and executes\" {\n    after_long_help \"Examples:\\n\\n    $ mise test-tool ripgrep\\n\"\n    flag \"-a --all\" help=\"Test every tool specified in registry/\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag --all-config help=\"Test all tools specified in config files\"\n    flag --include-non-defined help=\"Also test tools not defined in registry/, guessing how to test it\"\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg \"[TOOLS]…\" help=\"Tool(s) to test\" required=#false var=#true\n}\ncmd tool help=\"Gets information about a tool\" {\n    after_long_help \"Examples:\\n\\n    $ mise tool node\\n    Backend:            core\\n    Installed Versions: 20.0.0 22.0.0\\n    Active Version:     20.0.0\\n    Requested Version:  20\\n    Config Source:      ~/.config/mise/mise.toml\\n    Tool Options:       [none]\\n\"\n    flag \"-J --json\" help=\"Output in JSON format\"\n    flag --active help=\"Only show active versions\"\n    flag --backend help=\"Only show backend field\"\n    flag --config-source help=\"Only show config source\"\n    flag --description help=\"Only show description field\"\n    flag --installed help=\"Only show installed versions\"\n    flag --requested help=\"Only show requested versions\"\n    flag --tool-options help=\"Only show tool options\"\n    arg <TOOL> help=\"Tool name to get information about\"\n}\ncmd tool-stub help=\"Execute a tool stub\" {\n    long_help \"Execute a tool stub\\n\\nTool stubs are executable files containing TOML configuration that specify which tool to run and how to run it. They provide a convenient way to create portable, self-contained executables that automatically manage tool installation and execution.\\n\\nA tool stub consists of: - A shebang line: #!/usr/bin/env -S mise tool-stub - TOML configuration specifying the tool, version, and options - Optional comments describing the tool's purpose\\n\\nExample stub file: #!/usr/bin/env -S mise tool-stub # Node.js v20 development environment\\n\\ntool = \\\"node\\\" version = \\\"20.0.0\\\" bin = \\\"node\\\"\\n\\nThe stub will automatically install the specified tool version if missing and execute it with any arguments passed to the stub.\\n\\nFor more information, see: https://mise.jdx.dev/dev-tools/tool-stubs.html\"\n    arg <FILE> help=\"Path to the TOML tool stub file to execute\" help_long=\"Path to the TOML tool stub file to execute\\n\\nThe stub file must contain TOML configuration specifying the tool and version to run. At minimum, it should specify a 'version' field. Other common fields include 'tool', 'bin', and backend-specific options.\"\n    arg \"[ARGS]…\" help=\"Arguments to pass to the tool\" help_long=\"Arguments to pass to the tool\\n\\nAll arguments after the stub file path will be forwarded to the underlying tool. Use '--' to separate mise arguments from tool arguments if needed.\" required=#false double_dash=automatic var=#true\n}\ncmd trust help=\"Marks a config file as trusted\" {\n    long_help \"Marks a config file as trusted\\n\\nThis means mise will parse the file with potentially dangerous\\nfeatures enabled.\\n\\nThis includes:\\n- environment variables\\n- templates\\n- `path:` plugin versions\"\n    after_long_help \"Examples:\\n\\n    # trusts ~/some_dir/mise.toml\\n    $ mise trust ~/some_dir/mise.toml\\n\\n    # trusts mise.toml in the current or parent directory\\n    $ mise trust\\n\"\n    flag \"-a --all\" help=\"Trust all config files in the current directory and its parents\"\n    flag --ignore help=\"Do not trust this config and ignore it in the future\"\n    flag --show help=\"Show the trusted status of config files from the current directory and its parents.\\nDoes not trust or untrust any files.\"\n    flag --untrust help=\"No longer trust this config, will prompt in the future\"\n    arg \"[CONFIG_FILE]\" help=\"The config file to trust\" required=#false\n}\ncmd uninstall help=\"Removes installed tool versions\" {\n    long_help \"Removes installed tool versions\\n\\nThis only removes the installed version, it does not modify mise.toml.\"\n    after_long_help \"Examples:\\n\\n    # will uninstall specific version\\n    $ mise uninstall node@18.0.0\\n\\n    # will uninstall the current node version (if only one version is installed)\\n    $ mise uninstall node\\n\\n    # will uninstall all installed versions of node\\n    $ mise uninstall --all node@18.0.0 # will uninstall all node versions\\n\"\n    flag \"-a --all\" help=\"Delete all installed versions\"\n    flag \"-n --dry-run\" help=\"Do not actually delete anything\"\n    flag --dry-run-code help=\"Like --dry-run but exits with code 1 if there are tools to uninstall\" {\n        long_help \"Like --dry-run but exits with code 1 if there are tools to uninstall\\n\\nThis is useful for scripts to check if tools need to be uninstalled.\"\n    }\n    arg \"[INSTALLED_TOOL@VERSION]…\" help=\"Tool(s) to remove\" required=#false var=#true\n}\ncmd unset help=\"Remove environment variable(s) from the config file.\" {\n    long_help \"Remove environment variable(s) from the config file.\\n\\nBy default, this command modifies `mise.toml` in the current directory.\"\n    after_long_help \"Examples:\\n\\n    # Remove NODE_ENV from the current directory's config\\n    $ mise unset NODE_ENV\\n\\n    # Remove NODE_ENV from the global config\\n    $ mise unset NODE_ENV -g\\n\"\n    flag \"-f --file\" help=\"Specify a file to use instead of `mise.toml`\" {\n        arg <FILE>\n    }\n    flag \"-g --global\" help=\"Use the global config file\"\n    arg \"[ENV_KEY]…\" help=\"Environment variable(s) to remove\\ne.g.: NODE_ENV\" required=#false var=#true\n}\ncmd unuse help=\"Removes installed tool versions from mise.toml\" {\n    alias rm remove\n    long_help \"Removes installed tool versions from mise.toml\\n\\nBy default, this will use the `mise.toml` file that has the tool defined.\\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\\nthe lowest precedence file (`mise.toml`) will be used.\\nSee https://mise.jdx.dev/configuration.html#target-file-for-write-operations\\n\\nIn the following order:\\n  - If `--global` is set, it will use the global config file.\\n  - If `--path` is set, it will use the config file at the given path.\\n  - If `--env` is set, it will use `mise.<env>.toml`.\\n  - If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\\n  - If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\\n  - Otherwise just \\\"mise.toml\\\" or global config if cwd is home directory.\\n\\nWill also prune the installed version if no other configurations are using it.\"\n    after_long_help \"Examples:\\n\\n    # will uninstall specific version\\n    $ mise unuse node@18.0.0\\n\\n    # will uninstall specific version from global config\\n    $ mise unuse -g node@18.0.0\\n\\n    # will uninstall specific version from .mise.local.toml\\n    $ mise unuse --env local node@20\\n\\n    # will uninstall specific version from .mise.staging.toml\\n    $ mise unuse --env staging node@20\\n\"\n    flag \"-e --env\" help=\"Create/modify an environment-specific config file like .mise.<env>.toml\" {\n        arg <ENV>\n    }\n    flag \"-g --global\" help=\"Use the global config file (`~/.config/mise/config.toml`) instead of the local one\"\n    flag \"-p --path\" help=\"Specify a path to a config file or directory\" {\n        long_help \"Specify a path to a config file or directory\\n\\nIf a directory is specified, it will look for a config file in that directory following the rules above.\"\n        arg <PATH>\n    }\n    flag --no-prune help=\"Do not also prune the installed version\"\n    arg <INSTALLED_TOOL@VERSION>… help=\"Tool(s) to remove\" var=#true\n}\ncmd upgrade help=\"Upgrades outdated tools\" {\n    alias up\n    long_help \"Upgrades outdated tools\\n\\nBy default, this keeps the range specified in mise.toml. So if you have node@20 set, it will\\nupgrade to the latest 20.x.x version available. See the `--bump` flag to use the latest version\\nand bump the version in mise.toml.\\n\\nThis will update mise.lock if it is enabled, see https://mise.jdx.dev/configuration/settings.html#lockfile\"\n    after_long_help \"Examples:\\n\\n    # Upgrades node to the latest version matching the range in mise.toml\\n    $ mise upgrade node\\n\\n    # Upgrades node to the latest version and bumps the version in mise.toml\\n    $ mise upgrade node --bump\\n\\n    # Upgrades all tools to the latest versions\\n    $ mise upgrade\\n\\n    # Upgrades all tools to the latest versions and bumps the version in mise.toml\\n    $ mise upgrade --bump\\n\\n    # Just print what would be done, don't actually do it\\n    $ mise upgrade --dry-run\\n\\n    # Upgrades node and python to the latest versions\\n    $ mise upgrade node python\\n\\n    # Upgrade all tools except go\\n    $ mise upgrade --exclude go\\n\\n    # Show a multiselect menu to choose which tools to upgrade\\n    $ mise upgrade --interactive\\n\\n    # Only upgrade tools defined in local mise.toml, not global ones\\n    $ mise upgrade --local\\n\"\n    flag \"-i --interactive\" help=\"Display multiselect menu to choose which tools to upgrade\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag \"-l --bump\" help=\"Upgrades to the latest version available, bumping the version in mise.toml\" {\n        long_help \"Upgrades to the latest version available, bumping the version in mise.toml\\n\\nFor example, if you have `node = \\\"20.0.0\\\"` in your mise.toml but 22.1.0 is the latest available,\\nthis will install 22.1.0 and set `node = \\\"22.1.0\\\"` in your config.\\n\\nIt keeps the same precision as what was there before, so if you instead had `node = \\\"20\\\"`, it\\nwould change your config to `node = \\\"22\\\"`.\"\n    }\n    flag \"-n --dry-run\" help=\"Just print what would be done, don't actually do it\"\n    flag \"-x --exclude\" help=\"Tool(s) to exclude from upgrading\\ne.g.: go python\" var=#true {\n        arg <INSTALLED_TOOL>\n    }\n    flag --before help=\"Only upgrade to versions released before this date\" {\n        long_help \"Only upgrade to versions released before this date\\n\\nSupports absolute dates like \\\"2024-06-01\\\" and relative durations like \\\"90d\\\" or \\\"1y\\\".\\nThis can be useful for reproducibility or security purposes.\\n\\nThis only affects fuzzy version matches like \\\"20\\\" or \\\"latest\\\".\\nExplicitly pinned versions like \\\"22.5.0\\\" are not filtered.\"\n        arg <BEFORE>\n    }\n    flag --dry-run-code help=\"Like --dry-run but exits with code 1 if there are outdated tools\" {\n        long_help \"Like --dry-run but exits with code 1 if there are outdated tools\\n\\nThis is useful for scripts to check if tools need to be upgraded.\"\n    }\n    flag --local help=\"Only upgrade tools defined in local config files\" {\n        long_help \"Only upgrade tools defined in local config files\\n\\nThis will only upgrade tools that are defined in project-local mise.toml and\\nwill skip tools defined in the global config (~/.config/mise/config.toml).\"\n    }\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\"\n    arg \"[INSTALLED_TOOL@VERSION]…\" help=\"Tool(s) to upgrade\\ne.g.: node@20 python@3.10\\nIf not specified, all current tools will be upgraded\" required=#false var=#true\n}\ncmd usage hide=#true help=\"Generate a usage CLI spec\" {\n    long_help \"Generate a usage CLI spec\\n\\nSee https://usage.jdx.dev for more information on this specification.\"\n}\ncmd use help=\"Installs a tool and adds the version to mise.toml.\" {\n    alias u\n    long_help \"Installs a tool and adds the version to mise.toml.\\n\\nThis will install the tool version if it is not already installed.\\nBy default, this will use a `mise.toml` file in the current directory.\\nIf multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\\nthe lowest precedence file (`mise.toml`) will be used.\\nSee https://mise.jdx.dev/configuration.html#target-file-for-write-operations\\n\\nIn the following order:\\n  - If `--global` is set, it will use the global config file.\\n  - If `--path` is set, it will use the config file at the given path.\\n  - If `--env` is set, it will use `mise.<env>.toml`.\\n  - If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\\n  - If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\\n  - Otherwise just \\\"mise.toml\\\" or global config if cwd is home directory.\\n\\nUse the `--global` flag to use the global config file instead.\"\n    after_long_help \"Examples:\\n    \\n    # run with no arguments to use the interactive selector\\n    $ mise use\\n\\n    # set the current version of node to 20.x in mise.toml of current directory\\n    # will write the fuzzy version (e.g.: 20)\\n    $ mise use node@20\\n\\n    # set the current version of node to 20.x in ~/.config/mise/config.toml\\n    # will write the precise version (e.g.: 20.0.0)\\n    $ mise use -g --pin node@20\\n\\n    # sets .mise.local.toml (which is intended not to be committed to a project)\\n    $ mise use --env local node@20\\n\\n    # sets .mise.staging.toml (which is used if MISE_ENV=staging)\\n    $ mise use --env staging node@20\\n\"\n    flag \"-e --env\" help=\"Create/modify an environment-specific config file like .mise.<env>.toml\" {\n        arg <ENV>\n    }\n    flag \"-f --force\" help=\"Force reinstall even if already installed\"\n    flag \"-g --global\" help=\"Use the global config file (`~/.config/mise/config.toml`) instead of the local one\"\n    flag \"-j --jobs\" help=\"Number of jobs to run in parallel\\n[default: 4]\" {\n        arg <JOBS>\n    }\n    flag \"-n --dry-run\" help=\"Perform a dry run, showing what would be installed and modified without making changes\"\n    flag \"-p --path\" help=\"Specify a path to a config file or directory\" {\n        long_help \"Specify a path to a config file or directory\\n\\nIf a directory is specified, it will look for a config file in that directory following the rules above.\"\n        arg <PATH>\n    }\n    flag --before help=\"Only install versions released before this date\" {\n        long_help \"Only install versions released before this date\\n\\nSupports absolute dates like \\\"2024-06-01\\\" and relative durations like \\\"90d\\\" or \\\"1y\\\".\"\n        arg <BEFORE>\n    }\n    flag --dry-run-code help=\"Like --dry-run but exits with code 1 if there are changes to make\" {\n        long_help \"Like --dry-run but exits with code 1 if there are changes to make\\n\\nThis is useful for scripts to check if tools need to be added or removed.\"\n    }\n    flag --fuzzy help=\"Save fuzzy version to config file\" {\n        long_help \"Save fuzzy version to config file\\n\\ne.g.: `mise use --fuzzy node@20` will save 20 as the version\\nthis is the default behavior unless `MISE_PIN=1`\"\n    }\n    flag --pin help=\"Save exact version to config file\\ne.g.: `mise use --pin node@20` will save 20.0.0 as the version\\nSet `MISE_PIN=1` to make this the default behavior\" {\n        long_help \"Save exact version to config file\\ne.g.: `mise use --pin node@20` will save 20.0.0 as the version\\nSet `MISE_PIN=1` to make this the default behavior\\n\\nConsider using mise.lock as a better alternative to pinning in mise.toml:\\nhttps://mise.jdx.dev/configuration/settings.html#lockfile\"\n    }\n    flag --raw help=\"Directly pipe stdin/stdout/stderr from plugin to user Sets `--jobs=1`\"\n    flag --remove help=\"Remove the plugin(s) from config file\" var=#true {\n        arg <PLUGIN>\n    }\n    arg \"[TOOL@VERSION]…\" help=\"Tool(s) to add to config file\" help_long=\"Tool(s) to add to config file\\n\\ne.g.: node@20, cargo:ripgrep@latest npm:prettier@3\\nIf no version is specified, it will default to @latest\\n\\nTool options can be set with this syntax:\\n\\n    mise use ubi:BurntSushi/ripgrep[exe=rg]\" required=#false var=#true\n}\ncmd version help=\"Display the version of mise\" {\n    alias v\n    long_help \"Display the version of mise\\n\\nDisplays the version, os, architecture, and the date of the build.\\n\\nIf the version is out of date, it will display a warning.\"\n    after_long_help \"Examples:\\n\\n    $ mise version\\n    $ mise --version\\n    $ mise -v\\n    $ mise -V\\n\"\n    flag \"-J --json\" help=\"Print the version information in JSON format\"\n}\ncmd watch help=\"Run task(s) and watch for changes to rerun it\" {\n    alias w\n    long_help \"Run task(s) and watch for changes to rerun it\\n\\nThis command uses the `watchexec` tool to watch for changes to files and rerun the specified task(s).\\nIt must be installed for this command to work, but you can install it with `mise use -g watchexec@latest`.\\n\\nFor more advanced process management (daemon management, auto-restart, readiness checks,\\ncron scheduling), see mise's sister project: https://pitchfork.jdx.dev\"\n    after_long_help \"Examples:\\n\\n    $ mise watch build\\n    Runs the \\\"build\\\" tasks. Will re-run the tasks when any of its sources change.\\n    Uses \\\"sources\\\" from the tasks definition to determine which files to watch.\\n\\n    $ mise watch build --glob src/**/*.rs\\n    Runs the \\\"build\\\" tasks but specify the files to watch with a glob pattern.\\n    This overrides the \\\"sources\\\" from the tasks definition.\\n\\n    $ mise watch build --clear\\n    Extra arguments are passed to watchexec. See `watchexec --help` for details.\\n\\n    $ mise watch serve --watch src --exts rs --restart\\n    Starts an api server, watching for changes to \\\"*.rs\\\" files in \\\"./src\\\" and kills/restarts the server when they change.\\n\"\n    flag \"-t --task-flag\" help=\"Tasks to run\" var=#true hide=#true {\n        arg <TASK_FLAG>\n    }\n    flag \"-g --glob\" help=\"Files to watch\\nDefaults to sources from the task(s)\" var=#true hide=#true {\n        arg <GLOB>\n    }\n    flag --skip-deps help=\"Run only the specified tasks skipping all dependencies\"\n    flag \"-w --watch\" help=\"Watch a specific file or directory\" var=#true {\n        long_help \"Watch a specific file or directory\\n\\nBy default, Watchexec watches the current directory.\\n\\nWhen watching a single file, it's often better to watch the containing directory instead, and filter on the filename. Some editors may replace the file with a new one when saving, and some platforms may not detect that or further changes.\\n\\nUpon starting, Watchexec resolves a \\\"project origin\\\" from the watched paths. See the help for '--project-origin' for more information.\\n\\nThis option can be specified multiple times to watch multiple files or directories.\\n\\nThe special value '/dev/null', provided as the only path watched, will cause Watchexec to not watch any paths. Other event sources (like signals or key events) may still be used.\"\n        arg <PATH>\n    }\n    flag \"-W --watch-non-recursive\" help=\"Watch a specific directory, non-recursively\" var=#true {\n        long_help \"Watch a specific directory, non-recursively\\n\\nUnlike '-w', folders watched with this option are not recursed into.\\n\\nThis option can be specified multiple times to watch multiple directories non-recursively.\"\n        arg <PATH>\n    }\n    flag \"-F --watch-file\" help=\"Watch files and directories from a file\" {\n        long_help \"Watch files and directories from a file\\n\\nEach line in the file will be interpreted as if given to '-w'.\\n\\nFor more complex uses (like watching non-recursively), use the argfile capability: build a file containing command-line options and pass it to watchexec with `@path/to/argfile`.\\n\\nThe special value '-' will read from STDIN; this in incompatible with '--stdin-quit'.\"\n        arg <PATH>\n    }\n    flag \"-c --clear\" help=\"Clear screen before running command\" {\n        long_help \"Clear screen before running command\\n\\nIf this doesn't completely clear the screen, try '--clear=reset'.\"\n        arg <MODE> {\n            choices clear reset\n        }\n    }\n    flag \"-o --on-busy-update\" help=\"What to do when receiving events while the command is running\" default=do-nothing {\n        long_help \"What to do when receiving events while the command is running\\n\\nDefault is to 'do-nothing', which ignores events while the command is running, so that changes that occur due to the command are ignored, like compilation outputs. You can also use 'queue' which will run the command once again when the current run has finished if any events occur while it's running, or 'restart', which terminates the running command and starts a new one. Finally, there's 'signal', which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.\\n\\nThe signal can be specified with the '--signal' option.\"\n        arg <MODE> {\n            choices queue do-nothing restart signal\n        }\n    }\n    flag \"-r --restart\" help=\"Restart the process if it's still running\" {\n        long_help \"Restart the process if it's still running\\n\\nThis is a shorthand for '--on-busy-update=restart'.\"\n    }\n    flag \"-s --signal\" help=\"Send a signal to the process when it's still running\" {\n        long_help \"Send a signal to the process when it's still running\\n\\nSpecify a signal to send to the process when it's still running. This implies '--on-busy-update=signal'; otherwise the signal used when that mode is 'restart' is controlled by '--stop-signal'.\\n\\nSee the long documentation for '--stop-signal' for syntax.\\n\\nSignals are not supported on Windows at the moment, and will always be overridden to 'kill'. See '--stop-signal' for more on Windows \\\"signals\\\".\"\n        arg <SIGNAL>\n    }\n    flag --stop-signal help=\"Signal to send to stop the command\" {\n        long_help \"Signal to send to stop the command\\n\\nThis is used by 'restart' and 'signal' modes of '--on-busy-update' (unless '--signal' is provided). The restart behaviour is to send the signal, wait for the command to exit, and if it hasn't exited after some time (see '--timeout-stop'), forcefully terminate it.\\n\\nThe default on unix is \\\"SIGTERM\\\".\\n\\nInput is parsed as a full signal name (like \\\"SIGTERM\\\"), a short signal name (like \\\"TERM\\\"), or a signal number (like \\\"15\\\"). All input is case-insensitive.\\n\\nOn Windows this option is technically supported but only supports the \\\"KILL\\\" event, as Watchexec cannot yet deliver other events. Windows doesn't have signals as such; instead it has termination (here called \\\"KILL\\\" or \\\"STOP\\\") and \\\"CTRL+C\\\", \\\"CTRL+BREAK\\\", and \\\"CTRL+CLOSE\\\" events. For portability the unix signals \\\"SIGKILL\\\", \\\"SIGINT\\\", \\\"SIGTERM\\\", and \\\"SIGHUP\\\" are respectively mapped to these.\"\n        arg <SIGNAL>\n    }\n    flag --stop-timeout help=\"Time to wait for the command to exit gracefully\" default=\"10s\" {\n        long_help \"Time to wait for the command to exit gracefully\\n\\nThis is used by the 'restart' mode of '--on-busy-update'. After the graceful stop signal is sent, Watchexec will wait for the command to exit. If it hasn't exited after this time, it is forcefully terminated.\\n\\nTakes a unit-less value in seconds, or a time span value such as \\\"5min 20s\\\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\\n\\nThe default is 10 seconds. Set to 0 to immediately force-kill the command.\\n\\nThis has no practical effect on Windows as the command is always forcefully terminated; see '--stop-signal' for why.\"\n        arg <TIMEOUT>\n    }\n    flag --map-signal help=\"Translate signals from the OS to signals to send to the command\" var=#true {\n        long_help \"Translate signals from the OS to signals to send to the command\\n\\nTakes a pair of signal names, separated by a colon, such as \\\"TERM:INT\\\" to map SIGTERM to SIGINT. The first signal is the one received by watchexec, and the second is the one sent to the command. The second can be omitted to discard the first signal, such as \\\"TERM:\\\" to not do anything on SIGTERM.\\n\\nIf SIGINT or SIGTERM are mapped, then they no longer quit Watchexec. Besides making it hard to quit Watchexec itself, this is useful to send pass a Ctrl-C to the command without also terminating Watchexec and the underlying program with it, e.g. with \\\"INT:INT\\\".\\n\\nThis option can be specified multiple times to map multiple signals.\\n\\nSignal syntax is case-insensitive for short names (like \\\"TERM\\\", \\\"USR2\\\") and long names (like \\\"SIGKILL\\\", \\\"SIGHUP\\\"). Signal numbers are also supported (like \\\"15\\\", \\\"31\\\"). On Windows, the forms \\\"STOP\\\", \\\"CTRL+C\\\", and \\\"CTRL+BREAK\\\" are also supported to receive, but Watchexec cannot yet deliver other \\\"signals\\\" than a STOP.\"\n        arg <SIGNAL:SIGNAL>\n    }\n    flag \"-d --debounce\" help=\"Time to wait for new events before taking action\" default=\"50ms\" {\n        long_help \"Time to wait for new events before taking action\\n\\nWhen an event is received, Watchexec will wait for up to this amount of time before handling it (such as running the command). This is essential as what you might perceive as a single change may actually emit many events, and without this behaviour, Watchexec would run much too often. Additionally, it's not infrequent that file writes are not atomic, and each write may emit an event, so this is a good way to avoid running a command while a file is partially written.\\n\\nAn alternative use is to set a high value (like \\\"30min\\\" or longer), to save power or bandwidth on intensive tasks, like an ad-hoc backup script. In those use cases, note that every accumulated event will build up in memory.\\n\\nTakes a unit-less value in milliseconds, or a time span value such as \\\"5sec 20ms\\\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\\n\\nThe default is 50 milliseconds. Setting to 0 is highly discouraged.\"\n        arg <TIMEOUT>\n    }\n    flag --stdin-quit help=\"Exit when stdin closes\" {\n        long_help \"Exit when stdin closes\\n\\nThis watches the stdin file descriptor for EOF, and exits Watchexec gracefully when it is closed. This is used by some process managers to avoid leaving zombie processes around.\"\n    }\n    flag --no-vcs-ignore help=\"Don't load gitignores\" {\n        long_help \"Don't load gitignores\\n\\nAmong other VCS exclude files, like for Mercurial, Subversion, Bazaar, DARCS, Fossil. Note that Watchexec will detect which of these is in use, if any, and only load the relevant files. Both global (like '~/.gitignore') and local (like '.gitignore') files are considered.\\n\\nThis option is useful if you want to watch files that are ignored by Git.\"\n    }\n    flag --no-project-ignore help=\"Don't load project-local ignores\" {\n        long_help \"Don't load project-local ignores\\n\\nThis disables loading of project-local ignore files, like '.gitignore' or '.ignore' in the\\nwatched project. This is contrasted with '--no-vcs-ignore', which disables loading of Git\\nand other VCS ignore files, and with '--no-global-ignore', which disables loading of global\\nor user ignore files, like '~/.gitignore' or '~/.config/watchexec/ignore'.\\n\\nSupported project ignore files:\\n\\n  - Git: .gitignore at project root and child directories, .git/info/exclude, and the file pointed to by `core.excludesFile` in .git/config.\\n  - Mercurial: .hgignore at project root and child directories.\\n  - Bazaar: .bzrignore at project root.\\n  - Darcs: _darcs/prefs/boring\\n  - Fossil: .fossil-settings/ignore-glob\\n  - Ripgrep/Watchexec/generic: .ignore at project root and child directories.\\n\\nVCS ignore files (Git, Mercurial, Bazaar, Darcs, Fossil) are only used if the corresponding\\nVCS is discovered to be in use for the project/origin. For example, a .bzrignore in a Git\\nrepository will be discarded.\"\n    }\n    flag --no-global-ignore help=\"Don't load global ignores\" {\n        long_help \"Don't load global ignores\\n\\nThis disables loading of global or user ignore files, like '~/.gitignore',\\n'~/.config/watchexec/ignore', or '%APPDATA%\\\\Bazzar\\\\2.0\\\\ignore'. Contrast with\\n'--no-vcs-ignore' and '--no-project-ignore'.\\n\\nSupported global ignore files\\n\\n  - Git (if core.excludesFile is set): the file at that path\\n  - Git (otherwise): the first found of $XDG_CONFIG_HOME/git/ignore, %APPDATA%/.gitignore, %USERPROFILE%/.gitignore, $HOME/.config/git/ignore, $HOME/.gitignore.\\n  - Bazaar: the first found of %APPDATA%/Bazzar/2.0/ignore, $HOME/.bazaar/ignore.\\n  - Watchexec: the first found of $XDG_CONFIG_HOME/watchexec/ignore, %APPDATA%/watchexec/ignore, %USERPROFILE%/.watchexec/ignore, $HOME/.watchexec/ignore.\\n\\nLike for project files, Git and Bazaar global files will only be used for the corresponding\\nVCS as used in the project.\"\n    }\n    flag --no-default-ignore help=\"Don't use internal default ignores\" {\n        long_help \"Don't use internal default ignores\\n\\nWatchexec has a set of default ignore patterns, such as editor swap files, `*.pyc`, `*.pyo`, `.DS_Store`, `.bzr`, `_darcs`, `.fossil-settings`, `.git`, `.hg`, `.pijul`, `.svn`, and Watchexec log files.\"\n    }\n    flag --no-discover-ignore help=\"Don't discover ignore files at all\" {\n        long_help \"Don't discover ignore files at all\\n\\nThis is a shorthand for '--no-global-ignore', '--no-vcs-ignore', '--no-project-ignore', but even more efficient as it will skip all the ignore discovery mechanisms from the get go.\\n\\nNote that default ignores are still loaded, see '--no-default-ignore'.\"\n    }\n    flag --ignore-nothing help=\"Don't ignore anything at all\" {\n        long_help \"Don't ignore anything at all\\n\\nThis is a shorthand for '--no-discover-ignore', '--no-default-ignore'.\\n\\nNote that ignores explicitly loaded via other command line options, such as '--ignore' or '--ignore-file', will still be used.\"\n    }\n    flag \"-p --postpone\" help=\"Wait until first change before running command\" {\n        long_help \"Wait until first change before running command\\n\\nBy default, Watchexec will run the command once immediately. With this option, it will instead wait until an event is detected before running the command as normal.\"\n    }\n    flag --delay-run help=\"Sleep before running the command\" {\n        long_help \"Sleep before running the command\\n\\nThis option will cause Watchexec to sleep for the specified amount of time before running the command, after an event is detected. This is like using \\\"sleep 5 && command\\\" in a shell, but portable and slightly more efficient.\\n\\nTakes a unit-less value in seconds, or a time span value such as \\\"2min 5s\\\". Providing a unit-less value is deprecated and will warn; it will be an error in the future.\"\n        arg <DURATION>\n    }\n    flag --poll help=\"Poll for filesystem changes\" {\n        long_help \"Poll for filesystem changes\\n\\nBy default, and where available, Watchexec uses the operating system's native file system watching capabilities. This option disables that and instead uses a polling mechanism, which is less efficient but can work around issues with some file systems (like network shares) or edge cases.\\n\\nOptionally takes a unit-less value in milliseconds, or a time span value such as \\\"2s 500ms\\\", to use as the polling interval. If not specified, the default is 30 seconds. Providing a unit-less value is deprecated and will warn; it will be an error in the future.\\n\\nAliased as '--force-poll'.\"\n        arg <INTERVAL>\n    }\n    flag --shell help=\"Use a different shell\" {\n        long_help \"Use a different shell\\n\\nBy default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix-likes, and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec detects is the running shell.\\n\\nWith this option, you can override that and use a different shell, for example one with more features or one which has your custom aliases and functions.\\n\\nIf the value has spaces, it is parsed as a command line, and the first word used as the shell program, with the rest as arguments to the shell.\\n\\nThe command is run with the '-c' flag (except for 'cmd' on Windows, where it's '/C').\\n\\nThe special value 'none' can be used to disable shell use entirely. In that case, the command provided to Watchexec will be parsed, with the first word being the executable and the rest being the arguments, and executed directly. Note that this parsing is rudimentary, and may not work as expected in all cases.\\n\\nUsing 'none' is a little more efficient and can enable a stricter interpretation of the input, but it also means that you can't use shell features like globbing, redirection, control flow, logic, or pipes.\\n\\nExamples:\\n\\nUse without shell:\\n\\n$ watchexec -n -- zsh -x -o shwordsplit scr\\n\\nUse with powershell core:\\n\\n$ watchexec --shell=pwsh -- Test-Connection localhost\\n\\nUse with CMD.exe:\\n\\n$ watchexec --shell=cmd -- dir\\n\\nUse with a different unix shell:\\n\\n$ watchexec --shell=bash -- 'echo $BASH_VERSION'\\n\\nUse with a unix shell and options:\\n\\n$ watchexec --shell='zsh -x -o shwordsplit' -- scr\"\n        arg <SHELL>\n    }\n    flag -n help=\"Shorthand for '--shell=none'\"\n    flag --emit-events-to help=\"Configure event emission\" default=none {\n        long_help \"Configure event emission\\n\\nWatchexec can emit event information when running a command, which can be used by the child\\nprocess to target specific changed files.\\n\\nOne thing to take care with is assuming inherent behaviour where there is only chance.\\nNotably, it could appear as if the `RENAMED` variable contains both the original and the new\\npath being renamed. In previous versions, it would even appear on some platforms as if the\\noriginal always came before the new. However, none of this was true. It's impossible to\\nreliably and portably know which changed path is the old or new, \\\"half\\\" renames may appear\\n(only the original, only the new), \\\"unknown\\\" renames may appear (change was a rename, but\\nwhether it was the old or new isn't known), rename events might split across two debouncing\\nboundaries, and so on.\\n\\nThis option controls where that information is emitted. It defaults to 'none', which doesn't\\nemit event information at all. The other options are 'environment' (deprecated), 'stdio',\\n'file', 'json-stdio', and 'json-file'.\\n\\nThe 'stdio' and 'file' modes are text-based: 'stdio' writes absolute paths to the stdin of\\nthe command, one per line, each prefixed with `create:`, `remove:`, `rename:`, `modify:`,\\nor `other:`, then closes the handle; 'file' writes the same thing to a temporary file, and\\nits path is given with the $WATCHEXEC_EVENTS_FILE environment variable.\\n\\nThere are also two JSON modes, which are based on JSON objects and can represent the full\\nset of events Watchexec handles. Here's an example of a folder being created on Linux:\\n\\n```json\\n  {\\n    \\\"tags\\\": [\\n      {\\n        \\\"kind\\\": \\\"path\\\",\\n        \\\"absolute\\\": \\\"/home/user/your/new-folder\\\",\\n        \\\"filetype\\\": \\\"dir\\\"\\n      },\\n      {\\n        \\\"kind\\\": \\\"fs\\\",\\n        \\\"simple\\\": \\\"create\\\",\\n        \\\"full\\\": \\\"Create(Folder)\\\"\\n      },\\n      {\\n        \\\"kind\\\": \\\"source\\\",\\n        \\\"source\\\": \\\"filesystem\\\",\\n      }\\n    ],\\n    \\\"metadata\\\": {\\n      \\\"notify-backend\\\": \\\"inotify\\\"\\n    }\\n  }\\n```\\n\\nThe fields are as follows:\\n\\n  - `tags`, structured event data.\\n  - `tags[].kind`, which can be:\\n    * 'path', along with:\\n      + `absolute`, an absolute path.\\n      + `filetype`, a file type if known ('dir', 'file', 'symlink', 'other').\\n    * 'fs':\\n      + `simple`, the \\\"simple\\\" event type ('access', 'create', 'modify', 'remove', or 'other').\\n      + `full`, the \\\"full\\\" event type, which is too complex to fully describe here, but looks like 'General(Precise(Specific))'.\\n    * 'source', along with:\\n      + `source`, the source of the event ('filesystem', 'keyboard', 'mouse', 'os', 'time', 'internal').\\n    * 'keyboard', along with:\\n      + `keycode`. Currently only the value 'eof' is supported.\\n    * 'process', for events caused by processes:\\n      + `pid`, the process ID.\\n    * 'signal', for signals sent to Watchexec:\\n      + `signal`, the normalised signal name ('hangup', 'interrupt', 'quit', 'terminate', 'user1', 'user2').\\n    * 'completion', for when a command ends:\\n      + `disposition`, the exit disposition ('success', 'error', 'signal', 'stop', 'exception', 'continued').\\n      + `code`, the exit, signal, stop, or exception code.\\n  - `metadata`, additional information about the event.\\n\\nThe 'json-stdio' mode will emit JSON events to the standard input of the command, one per\\nline, then close stdin. The 'json-file' mode will create a temporary file, write the\\nevents to it, and provide the path to the file with the $WATCHEXEC_EVENTS_FILE\\nenvironment variable.\\n\\nFinally, the 'environment' mode was the default until 2.0. It sets environment variables\\nwith the paths of the affected files, for filesystem events:\\n\\n$WATCHEXEC_COMMON_PATH is set to the longest common path of all of the below variables,\\nand so should be prepended to each path to obtain the full/real path. Then:\\n\\n  - $WATCHEXEC_CREATED_PATH is set when files/folders were created\\n  - $WATCHEXEC_REMOVED_PATH is set when files/folders were removed\\n  - $WATCHEXEC_RENAMED_PATH is set when files/folders were renamed\\n  - $WATCHEXEC_WRITTEN_PATH is set when files/folders were modified\\n  - $WATCHEXEC_META_CHANGED_PATH is set when files/folders' metadata were modified\\n  - $WATCHEXEC_OTHERWISE_CHANGED_PATH is set for every other kind of pathed event\\n\\nMultiple paths are separated by the system path separator, ';' on Windows and ':' on unix.\\nWithin each variable, paths are deduplicated and sorted in binary order (i.e. neither\\nUnicode nor locale aware).\\n\\nThis is the legacy mode, is deprecated, and will be removed in the future. The environment\\nis a very restricted space, while also limited in what it can usefully represent. Large\\nnumbers of files will either cause the environment to be truncated, or may error or crash\\nthe process entirely. The $WATCHEXEC_COMMON_PATH is also unintuitive, as demonstrated by the\\nmultiple confused queries that have landed in my inbox over the years.\"\n        arg <MODE> {\n            choices environment stdio file json-stdio json-file none\n        }\n    }\n    flag --only-emit-events help=\"Only emit events to stdout, run no commands\" {\n        long_help \"Only emit events to stdout, run no commands.\\n\\nThis is a convenience option for using Watchexec as a file watcher, without running any commands. It is almost equivalent to using `cat` as the command, except that it will not spawn a new process for each event.\\n\\nThis option requires `--emit-events-to` to be set, and restricts the available modes to `stdio` and `json-stdio`, modifying their behaviour to write to stdout instead of the stdin of the command.\"\n    }\n    flag \"-E --env\" help=\"Add env vars to the command\" var=#true {\n        long_help \"Add env vars to the command\\n\\nThis is a convenience option for setting environment variables for the command, without setting them for the Watchexec process itself.\\n\\nUse key=value syntax. Multiple variables can be set by repeating the option.\"\n        arg \"<KEY=VALUE>\"\n    }\n    flag --wrap-process help=\"Configure how the process is wrapped\" default=group {\n        long_help \"Configure how the process is wrapped\\n\\nBy default, Watchexec will run the command in a process group in Unix, and in a Job Object in Windows.\\n\\nSome Unix programs prefer running in a session, while others do not work in a process group.\\n\\nUse 'group' to use a process group, 'session' to use a process session, and 'none' to run the command directly. On Windows, either of 'group' or 'session' will use a Job Object.\"\n        arg <MODE> {\n            choices group session none\n        }\n    }\n    flag \"-N --notify\" help=\"Alert when commands start and end\" {\n        long_help \"Alert when commands start and end\\n\\nWith this, Watchexec will emit a desktop notification when a command starts and ends, on supported platforms. On unsupported platforms, it may silently do nothing, or log a warning.\"\n    }\n    flag --color help=\"When to use terminal colours\" default=auto {\n        long_help \"When to use terminal colours\\n\\nSetting the environment variable `NO_COLOR` to any value is equivalent to `--color=never`.\"\n        arg <MODE> {\n            choices auto always never\n        }\n    }\n    flag --timings help=\"Print how long the command took to run\" {\n        long_help \"Print how long the command took to run\\n\\nThis may not be exactly accurate, as it includes some overhead from Watchexec itself. Use the `time` utility, high-precision timers, or benchmarking tools for more accurate results.\"\n    }\n    flag \"-q --quiet\" help=\"Don't print starting and stopping messages\" {\n        long_help \"Don't print starting and stopping messages\\n\\nBy default Watchexec will print a message when the command starts and stops. This option disables this behaviour, so only the command's output, warnings, and errors will be printed.\"\n    }\n    flag --bell help=\"Ring the terminal bell on command completion\"\n    flag --project-origin help=\"Set the project origin\" {\n        long_help \"Set the project origin\\n\\nWatchexec will attempt to discover the project's \\\"origin\\\" (or \\\"root\\\") by searching for a variety of markers, like files or directory patterns. It does its best but sometimes gets it it wrong, and you can override that with this option.\\n\\nThe project origin is used to determine the path of certain ignore files, which VCS is being used, the meaning of a leading '/' in filtering patterns, and maybe more in the future.\\n\\nWhen set, Watchexec will also not bother searching, which can be significantly faster.\"\n        arg <DIRECTORY>\n    }\n    flag --workdir help=\"Set the working directory\" {\n        long_help \"Set the working directory\\n\\nBy default, the working directory of the command is the working directory of Watchexec. You can change that with this option. Note that paths may be less intuitive to use with this.\"\n        arg <DIRECTORY>\n    }\n    flag \"-e --exts\" help=\"Filename extensions to filter to\" var=#true {\n        long_help \"Filename extensions to filter to\\n\\nThis is a quick filter to only emit events for files with the given extensions. Extensions can be given with or without the leading dot (e.g. 'js' or '.js'). Multiple extensions can be given by repeating the option or by separating them with commas.\"\n        arg <EXTENSIONS>\n    }\n    flag \"-f --filter\" help=\"Filename patterns to filter to\" var=#true {\n        long_help \"Filename patterns to filter to\\n\\nProvide a glob-like filter pattern, and only events for files matching the pattern will be emitted. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\"\n        arg <PATTERN>\n    }\n    flag --filter-file help=\"Files to load filters from\" var=#true {\n        long_help \"Files to load filters from\\n\\nProvide a path to a file containing filters, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '--filter' option.\\n\\nThis can also be used via the $WATCHEXEC_FILTER_FILES environment variable.\"\n        arg <PATH>\n    }\n    flag \"-J --filter-prog\" help=\"[experimental] Filter programs\" var=#true {\n        long_help \"[experimental] Filter programs.\\n\\n/!\\\\ This option is EXPERIMENTAL and may change and/or vanish without notice.\\n\\nProvide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in '--emit-events-to' and must return a boolean. Invalid programs will make watchexec fail to start; use '-v' to see program runtime errors.\\n\\nIn addition to the jaq stdlib, watchexec adds some custom filter definitions:\\n\\n- 'path | file_meta' returns file metadata or null if the file does not exist.\\n\\n- 'path | file_size' returns the size of the file at path, or null if it does not exist.\\n\\n- 'path | file_read(bytes)' returns a string with the first n bytes of the file at path. If the file is smaller than n bytes, the whole file is returned. There is no filter to read the whole file at once to encourage limiting the amount of data read and processed.\\n\\n- 'string | hash', and 'path | file_hash' return the hash of the string or file at path. No guarantee is made about the algorithm used: treat it as an opaque value.\\n\\n- 'any | kv_store(key)', 'kv_fetch(key)', and 'kv_clear' provide a simple key-value store. Data is kept in memory only, there is no persistence. Consistency is not guaranteed.\\n\\n- 'any | printout', 'any | printerr', and 'any | log(level)' will print or log any given value to stdout, stderr, or the log (levels = error, warn, info, debug, trace), and pass the value through (so '[1] | log(\\\"debug\\\") | .[]' will produce a '1' and log '[1]').\\n\\nAll filtering done with such programs, and especially those using kv or filesystem access, is much slower than the other filtering methods. If filtering is too slow, events will back up and stall watchexec. Take care when designing your filters.\\n\\nIf the argument to this option starts with an '@', the rest of the argument is taken to be the path to a file containing a jaq program.\\n\\nJaq programs are run in order, after all other filters, and short-circuit: if a filter (jaq or not) rejects an event, execution stops there, and no other filters are run. Additionally, they stop after outputting the first value, so you'll want to use 'any' or 'all' when iterating, otherwise only the first item will be processed, which can be quite confusing!\\n\\nFind user-contributed programs or submit your own useful ones at <https://github.com/watchexec/watchexec/discussions/592>.\\n\\n## Examples:\\n\\nRegexp ignore filter on paths:\\n\\n'all(.tags[] | select(.kind == \\\"path\\\"); .absolute | test(\\\"[.]test[.]js$\\\")) | not'\\n\\nPass any event that creates a file:\\n\\n'any(.tags[] | select(.kind == \\\"fs\\\"); .simple == \\\"create\\\")'\\n\\nPass events that touch executable files:\\n\\n'any(.tags[] | select(.kind == \\\"path\\\" && .filetype == \\\"file\\\"); .absolute | metadata | .executable)'\\n\\nIgnore files that start with shebangs:\\n\\n'any(.tags[] | select(.kind == \\\"path\\\" && .filetype == \\\"file\\\"); .absolute | read(2) == \\\"#!\\\") | not'\"\n        arg <EXPRESSION>\n    }\n    flag \"-i --ignore\" help=\"Filename patterns to filter out\" var=#true {\n        long_help \"Filename patterns to filter out\\n\\nProvide a glob-like filter pattern, and events for files matching the pattern will be excluded. Multiple patterns can be given by repeating the option. Events that are not from files (e.g. signals, keyboard events) will pass through untouched.\"\n        arg <PATTERN>\n    }\n    flag --ignore-file help=\"Files to load ignores from\" var=#true {\n        long_help \"Files to load ignores from\\n\\nProvide a path to a file containing ignores, one per line. Empty lines and lines starting with '#' are ignored. Uses the same pattern format as the '--ignore' option.\\n\\nThis can also be used via the $WATCHEXEC_IGNORE_FILES environment variable.\"\n        arg <PATH>\n    }\n    flag --fs-events help=\"Filesystem events to filter to\" var=#true default=create,remove,rename,modify,metadata {\n        long_help \"Filesystem events to filter to\\n\\nThis is a quick filter to only emit events for the given types of filesystem changes. Choose from 'access', 'create', 'remove', 'rename', 'modify', 'metadata'. Multiple types can be given by repeating the option or by separating them with commas. By default, this is all types except for 'access'.\\n\\nThis may apply filtering at the kernel level when possible, which can be more efficient, but may be more confusing when reading the logs.\"\n        arg <EVENTS> {\n            choices access create remove rename modify metadata\n        }\n    }\n    flag --no-meta help=\"Don't emit fs events for metadata changes\" {\n        long_help \"Don't emit fs events for metadata changes\\n\\nThis is a shorthand for '--fs-events create,remove,rename,modify'. Using it alongside the '--fs-events' option is non-sensical and not allowed.\"\n    }\n    flag --print-events help=\"Print events that trigger actions\" {\n        long_help \"Print events that trigger actions\\n\\nThis prints the events that triggered the action when handling it (after debouncing), in a human readable form. This is useful for debugging filters.\\n\\nUse '-vvv' instead when you need more diagnostic information.\"\n    }\n    flag --manual help=\"Show the manual page\" {\n        long_help \"Show the manual page\\n\\nThis shows the manual page for Watchexec, if the output is a terminal and the 'man' program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).\"\n    }\n    arg \"[TASK]\" help=\"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: `mise run task1 arg1 arg2 ::: task2 arg1 arg2`\" required=#false\n    arg \"[ARGS]…\" help=\"Task and arguments to run\" required=#false double_dash=automatic var=#true\n}\ncmd where help=\"Display the installation path for a tool\" {\n    long_help \"Display the installation path for a tool\\n\\nThe tool must be installed for this to work.\"\n    after_long_help \"Examples:\\n\\n    # Show the latest installed version of node\\n    # If it is is not installed, errors\\n    $ mise where node@20\\n    /home/jdx/.local/share/mise/installs/node/20.0.0\\n\\n    # Show the current, active install directory of node\\n    # Errors if node is not referenced in any .tool-version file\\n    $ mise where node\\n    /home/jdx/.local/share/mise/installs/node/20.0.0\\n\"\n    arg <TOOL@VERSION> help=\"Tool(s) to look up\\ne.g.: ruby@3\\nif \\\"@<PREFIX>\\\" is specified, it will show the latest installed version\\nthat matches the prefix\\notherwise, it will show the current, active installed version\"\n    arg \"[ASDF_VERSION]\" help=\"the version prefix to use when querying the latest version\\nsame as the first argument after the \\\"@\\\"\\nused for asdf compatibility\" required=#false hide=#true\n}\ncmd which help=\"Shows the path that a tool's bin points to.\" {\n    long_help \"Shows the path that a tool's bin points to.\\n\\nUse this to figure out what version of a tool is currently active.\"\n    after_long_help \"Examples:\\n\\n    $ mise which node\\n    /home/username/.local/share/mise/installs/node/20.0.0/bin/node\\n\\n    $ mise which node --plugin\\n    node\\n\\n    $ mise which node --version\\n    20.0.0\\n\"\n    flag \"-t --tool\" help=\"Use a specific tool@version\\ne.g.: `mise which npm --tool=node@20`\" {\n        arg <TOOL@VERSION>\n    }\n    flag --complete hide=#true\n    flag --plugin help=\"Show the plugin name instead of the path\"\n    flag --version help=\"Show the version instead of the path\"\n    arg \"[BIN_NAME]\" help=\"The bin to look up\" required=#false\n}\nsource_code_link_template #\"\"\"\n{%- set path = path | replace(from='-', to='_') -%}\n{%- if cmd.subcommands | length > 0 -%}\n{%- set path = path | split(pat=\"/\") | slice(end=1) | concat(with=\"mod.rs\") | join(sep=\"/\") -%}\n{%- else -%}\n{%- set path = path ~ \".rs\" -%}\n{%- endif -%}\nhttps://github.com/jdx/mise/blob/main/src/cli/{{path}}\n\"\"\"#\n\ncomplete \"alias\" run=\"mise alias ls {{words[PREV]}} | awk '{print $2}'\"\ncomplete \"config_file\" type=\"file\"\ncomplete \"new_plugin\" run=\"mise plugins --all\"\ncomplete \"installed_tool\" run=\"mise ls -i | awk '{print $1}' | uniq\"\ncomplete \"plugin\" run=\"mise plugins --core --user\"\ncomplete \"prefix\" run=\"mise ls-remote {{words[PREV]}}\"\ncomplete \"setting\" run=\"mise settings --complete\" descriptions=#true\ncomplete \"task\" run=\"mise tasks ls --complete\" descriptions=#true\ncomplete \"tool\" run=\"mise registry --complete\" descriptions=#true\ncomplete \"env_var\" run=#\"mise set --complete | awk '{print $1\"=\"}'\"#\ncomplete \"env_key\" run=\"mise set --complete\"\ncomplete \"backend\" run=\"mise backends\"\ncomplete \"bin_name\" run=\"mise which --complete\"\n\ncomplete \"tool@version\" run=#\"\"\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    versions=$(mise ls-remote $tool $prefix | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise registry | awk '{print $1}')\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"\"\"#\n\ncomplete \"installed_tool@version\" run=#\"\"\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    if [ ! -z \"$prefix\" ]; then\n      prefix=\"--prefix $prefix\"\n    fi\n    versions=$(mise ls --installed $tool $prefix | awk '{print $2}' | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise ls --installed | awk '{print $1}' | sed '1!G;h;$!d')\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"\"\"#\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mise\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"directories\": {\n    \"doc\": \"docs\",\n    \"man\": \"man\",\n    \"test\": \"tests\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"lint-fig\": \"eslint 'xtasks/fig/**/*.ts' && npx prettier --check 'xtasks/fig/**/*.ts' --parser typescript\",\n    \"lint-fig:fix\": \"eslint 'xtasks/fig/**/*.ts' --fix && npx prettier --write 'xtasks/fig/**/*.ts' --parser typescript\",\n    \"docs:dev\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:preview\": \"vitepress preview docs\"\n  },\n  \"author\": \"@jdx\",\n  \"resolutions\": {\n    \"esbuild\": \"0.21.5\"\n  },\n  \"devDependencies\": {\n    \"@fig/eslint-config-autocomplete\": \"^2.0.0\",\n    \"@tsconfig/node24\": \"^24.0.0\",\n    \"@types/markdown-it\": \"^14.1.2\",\n    \"@types/node\": \"^22.18.12\",\n    \"@withfig/autocomplete-tools\": \"^2.11.0\",\n    \"@withfig/autocomplete-types\": \"^1.31.0\",\n    \"eslint\": \"^8.57.1\",\n    \"js-toml\": \"^1.0.2\",\n    \"markdown-it\": \"^14.1.0\",\n    \"toml\": \"^3.0.0\",\n    \"tsx\": \"^4.20.6\",\n    \"typescript\": \"^5.9.3\",\n    \"vitepress\": \"1.6.4\",\n    \"vitepress-plugin-group-icons\": \"^1.6.5\",\n    \"vitepress-plugin-mermaid\": \"2.0.17\",\n    \"vitepress-plugin-tabs\": \"^0.7.3\"\n  }\n}\n"
  },
  {
    "path": "packaging/alpine/Dockerfile",
    "content": "FROM alpine:edge@sha256:9a341ff2287c54b86425cbee0141114d811ae69d88a36019087be6d896cef241\n\nRUN apk add --no-cache sudo build-base alpine-sdk bash direnv glab atools github-cli jq nodejs \\\n      && apk fix \\\n      && adduser -D packager \\\n      && addgroup packager abuild \\\n      && echo \"packager ALL=(ALL) NOPASSWD:ALL\" >> /etc/sudoers \\\n      && mkdir -p /__w && chown packager:packager /__w && chmod 777 /__w\n#USER packager\n#WORKDIR /home/packager\n\nHEALTHCHECK CMD abuild -v\n"
  },
  {
    "path": "packaging/alpine/README.md",
    "content": "To generate new release keys, first start the alpine docker container:\n\n```bash\ndocker run -it --rm -v $(pwd):/work/mise ghcr.io/jdx/mise:alpine\n```\n\nAnd inside the container:\n\n```bash\nsudo su - packager\nabuild-keygen -a -n\n```\n\nThen store them in GitHub secrets as `ALPINE_PRIV_KEY` and `ALPINE_PUB_KEY`.\nNote the name of the private key file, it will be something like `-5f2b2c4e.rsa`.\nSave that string as `ALPINE_KEY_ID` as another secret.\n\nAlso, the `ALPINE_GITLAB_TOKEN` needs to be rolled as well, use the [alpine gitlab portal](https://gitlab.alpinelinux.org/-/user_settings/personal_access_tokens)\nto generate a new token and store it in Github secrets as `ALPINE_GITLAB_TOKEN`.\n"
  },
  {
    "path": "packaging/copr/Dockerfile",
    "content": "FROM fedora:43@sha256:781b7642e8bf256e9cf75d2aa58d86f5cc695fd2df113517614e181a5eee9138\nLABEL maintainer=\"jdx\"\n\n# Install packaging dependencies\nRUN dnf update -y && \\\n    dnf install -y \\\n        rpm-build \\\n        rpmdevtools \\\n        python3-pip \\\n        git \\\n        rust \\\n        cargo \\\n        gcc \\\n        tar \\\n        gzip && \\\n    dnf clean all\n\n# Install copr-cli\nRUN pip3 install copr-cli\n\n# Add mise to PATH\nENV PATH=\"/root/.local/bin:${PATH}\"\n\n# Install mise and use it to install cargo-vendor\nRUN curl https://mise.run | sh\nRUN mise use -g cargo-binstall cargo:cargo-vendor\n\n# Set up RPM build environment\nRUN rpmdev-setuptree\n"
  },
  {
    "path": "packaging/copr/build-copr.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\n# Default values\nPACKAGE_NAME=\"${PACKAGE_NAME:-mise}\"\nCHROOTS=\"${CHROOTS:-fedora-43-aarch64 fedora-43-x86_64 fedora-42-aarch64 fedora-42-x86_64 epel-10-aarch64 epel-10-x86_64}\"\nBUILD_PROFILE=\"${BUILD_PROFILE:-release}\"\nMAINTAINER_NAME=\"${MAINTAINER_NAME:-mise Release Bot}\"\nMAINTAINER_EMAIL=\"${MAINTAINER_EMAIL:-noreply@mise.jdx.dev}\"\nCOPR_OWNER=\"${COPR_OWNER:-jdxcode}\"\nCOPR_PROJECT=\"${COPR_PROJECT:-mise}\"\nDRY_RUN=\"${DRY_RUN:-false}\"\n\n# Store the repository root directory\nREPO_ROOT=\"$(pwd)\"\n\n# Function to show usage\nusage() {\n\techo \"Usage: $0 [options]\"\n\techo \"\"\n\techo \"Options:\"\n\techo \"  -v, --version VERSION        Package version (required)\"\n\techo \"  -p, --profile PROFILE        Build profile (default: release)\"\n\techo \"  -c, --chroots CHROOTS        COPR chroots (default: fedora-43-aarch64 fedora-43-x86_64 fedora-42-aarch64 fedora-42-x86_64 epel-10-aarch64 epel-10-x86_64)\"\n\techo \"  -o, --owner OWNER            COPR owner (default: jdxcode)\"\n\techo \"  -j, --project PROJECT        COPR project (default: mise)\"\n\techo \"  -n, --name NAME              Package name (default: mise)\"\n\techo \"  -m, --maintainer-name NAME   Maintainer name (default: mise Release Bot)\"\n\techo \"  -e, --maintainer-email EMAIL Maintainer email (default: noreply@mise.jdx.dev)\"\n\techo \"  -d, --dry-run                Build SRPM only, don't submit to COPR\"\n\techo \"  -h, --help                   Show this help\"\n\techo \"\"\n\techo \"Environment variables:\"\n\techo \"  COPR_API_LOGIN               COPR API login (required for submission)\"\n\techo \"  COPR_API_TOKEN               COPR API token (required for submission)\"\n\techo \"\"\n\techo \"Example:\"\n\techo \"  $0 -v 2025.7.22 -p serious -d\"\n\texit 0\n}\n\n# Parse command line arguments\nwhile [[ $# -gt 0 ]]; do\n\tcase $1 in\n\t-v | --version)\n\t\tVERSION=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-p | --profile)\n\t\tBUILD_PROFILE=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-c | --chroots)\n\t\tCHROOTS=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-o | --owner)\n\t\tCOPR_OWNER=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-j | --project)\n\t\tCOPR_PROJECT=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-n | --name)\n\t\tPACKAGE_NAME=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-m | --maintainer-name)\n\t\tMAINTAINER_NAME=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-e | --maintainer-email)\n\t\tMAINTAINER_EMAIL=\"$2\"\n\t\tshift 2\n\t\t;;\n\t-d | --dry-run)\n\t\tDRY_RUN=\"true\"\n\t\tshift\n\t\t;;\n\t-h | --help)\n\t\tusage\n\t\t;;\n\t*)\n\t\techo \"Unknown option: $1\"\n\t\tusage\n\t\t;;\n\tesac\ndone\n\n# Check required parameters\nif [ -z \"${VERSION:-}\" ]; then\n\techo \"Error: VERSION is required\"\n\techo \"Use --version to specify the version or set VERSION environment variable\"\n\texit 1\nfi\n\necho \"=== COPR Build Configuration ===\"\necho \"Package Name: $PACKAGE_NAME\"\necho \"Version: $VERSION\"\necho \"Build Profile: $BUILD_PROFILE\"\necho \"Chroots: $CHROOTS\"\necho \"COPR Owner: $COPR_OWNER\"\necho \"COPR Project: $COPR_PROJECT\"\necho \"Maintainer: $MAINTAINER_NAME <$MAINTAINER_EMAIL>\"\necho \"Dry Run: $DRY_RUN\"\necho \"\"\n\n# Configure Git (needed for git archive)\ngit config --global user.name \"$MAINTAINER_NAME\"\ngit config --global user.email \"$MAINTAINER_EMAIL\"\ngit config --global --add safe.directory \"$REPO_ROOT\"\n\n# Set up COPR configuration if not in dry-run mode\nif [ \"$DRY_RUN\" != \"true\" ]; then\n\tif [ -z \"${COPR_API_LOGIN:-}\" ] || [ -z \"${COPR_API_TOKEN:-}\" ]; then\n\t\techo \"Error: COPR_API_LOGIN and COPR_API_TOKEN environment variables are required for submission\"\n\t\texit 1\n\tfi\n\n\tmkdir -p ~/.config\n\tcat >~/.config/copr <<EOF\n[copr-cli]\nlogin = $COPR_API_LOGIN\nusername = $COPR_OWNER\ntoken = $COPR_API_TOKEN\ncopr_url = https://copr.fedorainfracloud.org\nEOF\nfi\n\n# Create build directory structure\nBUILD_DIR=\"/tmp/rpm-build\"\nmkdir -p \"$BUILD_DIR\"/{BUILD,RPMS,SOURCES,SPECS,SRPMS}\n\n# Set up RPM build environment\necho \"%_topdir $BUILD_DIR\" >~/.rpmmacros\necho \"%_tmppath %{_topdir}/tmp\" >>~/.rpmmacros\n\ncd \"$BUILD_DIR\"\n\necho \"=== Creating Source Tarball ===\"\n# Create original source tarball\ngit -C \"$REPO_ROOT\" archive --format=tar --prefix=\"${PACKAGE_NAME}-${VERSION}/\" HEAD >\"SOURCES/${PACKAGE_NAME}-${VERSION}.tar\"\n\n# Compress the tarball\ngzip \"SOURCES/${PACKAGE_NAME}-${VERSION}.tar\"\n\necho \"=== Vendoring Rust Dependencies ===\"\n# Extract source for vendoring\ncd SOURCES\ntar -xzf \"${PACKAGE_NAME}-${VERSION}.tar.gz\"\ncd \"${PACKAGE_NAME}-${VERSION}\"\n\n# Vendor dependencies\nmkdir -p .cargo\ncat >.cargo/config.toml <<'EOF'\n[source.crates-io]\nreplace-with = \"vendored-sources\"\n\n[source.vendored-sources]\ndirectory = \"vendor\"\nEOF\n\ncargo vendor vendor/\ntar -czf \"../${PACKAGE_NAME}-vendor-${VERSION}.tar.gz\" vendor/ .cargo/\n\n# Clean up extracted source\ncd ../..\nrm -rf \"SOURCES/${PACKAGE_NAME}-${VERSION}\"\n\necho \"=== Creating RPM Spec File ===\"\n# Create spec file from template\ncat >\"SPECS/${PACKAGE_NAME}.spec\" <<'EOF'\n%global debug_package %{nil}\n%global _missing_build_ids_terminate_build 0\n\nName:           __PACKAGE_NAME__\nVersion:        __VERSION__\nRelease:        1%{?dist}\nSummary:        The front-end to your dev env\n\nLicense:        MIT\nURL:            https://mise.jdx.dev\nSource0:        https://github.com/jdx/mise/archive/v%{version}/mise-%{version}.tar.gz\nSource1:        mise-vendor-%{version}.tar.gz\n\nBuildRequires:  rust >= 1.85\nBuildRequires:  cargo\nBuildRequires:  gcc\nBuildRequires:  git\nBuildRequires:  openssl-devel\n\n%description\nmise is a development environment setup tool that manages runtime versions,\nenvironment variables, and tasks. It's a replacement for tools like nvm, rbenv,\npyenv, etc. and works with any language.\n\n%prep\n%autosetup -n %{name}-%{version}\n%setup -q -T -D -a 1\n\n%build\n# Set up vendored dependencies\nmkdir -p .cargo\ncp .cargo/config.toml .cargo/config.toml.bak 2>/dev/null || true\ncat > .cargo/config.toml << 'CARGO_EOF'\n[source.crates-io]\nreplace-with = \"vendored-sources\"\n\n[source.vendored-sources]\ndirectory = \"vendor\"\nCARGO_EOF\n\n# Build with specified profile\ncargo build --profile __BUILD_PROFILE__ --frozen --bin mise\n\n%install\nmkdir -p %{buildroot}%{_bindir}\ncp target/__BUILD_PROFILE__/mise %{buildroot}%{_bindir}/\n\n# Install man page if available\nmkdir -p %{buildroot}%{_mandir}/man1\ncp man/man1/mise.1 %{buildroot}%{_mandir}/man1/\n\n# Install shell completions\nmkdir -p %{buildroot}%{_datadir}/bash-completion/completions\ncp completions/mise.bash %{buildroot}%{_datadir}/bash-completion/completions/mise\n\nmkdir -p %{buildroot}%{_datadir}/zsh/site-functions\ncp completions/_mise %{buildroot}%{_datadir}/zsh/site-functions/\n\nmkdir -p %{buildroot}%{_datadir}/fish/vendor_completions.d\ncp completions/mise.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/\n\n# Disable self-update for package manager installations\nmkdir -p %{buildroot}%{_libdir}/mise\ncat > %{buildroot}%{_libdir}/mise/mise-self-update-instructions.toml <<'TOML'\nmessage = \"To update mise from COPR, run:\\n\\n  sudo dnf upgrade mise\\n\"\nTOML\n\n%files\n%license LICENSE\n%doc README.md\n%{_bindir}/mise\n%{_mandir}/man1/mise.1*\n%{_datadir}/bash-completion/completions/mise\n%{_datadir}/zsh/site-functions/_mise\n%{_datadir}/fish/vendor_completions.d/mise.fish\n%{_libdir}/mise/mise-self-update-instructions.toml\n\n%changelog\n* __CHANGELOG_DATE__ __MAINTAINER_NAME__ <__MAINTAINER_EMAIL__> - %{version}-1\n- New upstream release %{version}\nEOF\n\n# Replace placeholders in spec file\nCHANGELOG_DATE=$(date +'%a %b %d %Y')\nsed -i \"s/__PACKAGE_NAME__/${PACKAGE_NAME}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\nsed -i \"s/__VERSION__/${VERSION}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\nsed -i \"s/__BUILD_PROFILE__/${BUILD_PROFILE}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\nsed -i \"s/__CHANGELOG_DATE__/${CHANGELOG_DATE}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\nsed -i \"s/__MAINTAINER_NAME__/${MAINTAINER_NAME}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\nsed -i \"s/__MAINTAINER_EMAIL__/${MAINTAINER_EMAIL}/g\" \"SPECS/${PACKAGE_NAME}.spec\"\n\necho \"=== Building Source RPM ===\"\n# Build source RPM\nrpmbuild -bs \"SPECS/${PACKAGE_NAME}.spec\"\n\n# Copy SRPM to accessible location\nSRPM_FILE=$(find SRPMS -name \"*.src.rpm\" -type f | head -1)\nif [ -n \"$SRPM_FILE\" ]; then\n\tcp \"$SRPM_FILE\" \"$REPO_ROOT/\"\n\techo \"SRPM created: $REPO_ROOT/$(basename \"$SRPM_FILE\")\"\nelse\n\techo \"Error: No SRPM file found\"\n\texit 1\nfi\n\n# Submit to COPR if not in dry-run mode\nif [ \"$DRY_RUN\" != \"true\" ]; then\n\techo \"=== Submitting to COPR ===\"\n\techo \"Submitting $(basename \"$SRPM_FILE\") to COPR project $COPR_OWNER/$COPR_PROJECT\"\n\n\t# Submit build to COPR\n\t# Build the copr-cli command with multiple --chroot flags\n\tcopr_cmd=\"copr-cli build\"\n\t# Split CHROOTS into an array to ensure proper word splitting\n\tIFS=' ' read -ra chroot_array <<<\"$CHROOTS\"\n\tfor chroot in \"${chroot_array[@]}\"; do\n\t\tcopr_cmd=\"$copr_cmd --chroot $chroot\"\n\tdone\n\tcopr_cmd=\"$copr_cmd $COPR_OWNER/$COPR_PROJECT $SRPM_FILE\"\n\n\teval \"$copr_cmd\"\n\n\techo \"Build submitted successfully!\"\nelse\n\techo \"=== Dry Run Complete ===\"\n\techo \"SRPM built successfully but not submitted to COPR (dry-run mode)\"\nfi\n\n# Create artifacts directory\nmkdir -p \"$REPO_ROOT/artifacts\"\ncp \"$SRPM_FILE\" \"$REPO_ROOT/artifacts/\" 2>/dev/null || true\ncp \"SPECS/${PACKAGE_NAME}.spec\" \"$REPO_ROOT/artifacts/\" 2>/dev/null || true\n\necho \"=== Build Complete ===\"\necho \"Artifacts available in $REPO_ROOT/artifacts/\"\n"
  },
  {
    "path": "packaging/deb/Dockerfile",
    "content": "FROM ubuntu:24.04@sha256:353675e2a41babd526e2b837d7ec780c2a05bca0164f7ea5dbbd433d21d166fc\nLABEL maintainer=\"jdx\"\n\nRUN apt-get update \\\n    && apt-get install -y \\\n        build-essential \\\n        ruby \\\n    && apt-get clean \\\n    && rm -rf /var/lib/apt/lists/*\n\nRUN gem install fpm\n"
  },
  {
    "path": "packaging/deb/generate-release.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n# shellcheck disable=SC2044\n# shellcheck disable=SC2066\n# shellcheck disable=SC2086\n# shellcheck disable=SC2185\n\ndo_hash() {\n\tHASH_NAME=$1\n\tHASH_CMD=$2\n\techo \"${HASH_NAME}:\"\n\tfor f in $(find -type f); do\n\t\tf=$(echo $f | cut -c3-) # remove ./ prefix\n\t\tif [ \"$f\" = \"Release\" ]; then\n\t\t\tcontinue\n\t\tfi\n\t\techo \" $(${HASH_CMD} ${f} | cut -d\" \" -f1) $(wc -c $f)\"\n\tdone\n}\n\ncat <<EOF\nOrigin: mise repository\nLabel: mise\nSuite: stable\nCodename: stable\nVersion: 1.0\nArchitectures: amd64 arm64\nComponents: main\nDescription: https://github.com/jdx/mise\nDate: $(date -Ru)\nEOF\ndo_hash \"MD5Sum\" \"md5sum\"\ndo_hash \"SHA1\" \"sha1sum\"\ndo_hash \"SHA256\" \"sha256sum\"\n"
  },
  {
    "path": "packaging/mise/Dockerfile",
    "content": "# syntax=docker/dockerfile:1@sha256:4a43a54dd1fedceb30ba47e76cfcf2b47304f4161c0caeac2db1c61804ea3c91\nFROM rust@sha256:bed2d7f8140d73c26f16c298c91ae8487a09f40d3840c0d8d139537e1b51e148 AS builder\nLABEL maintainer=\"jdx\"\nLABEL org.opencontainers.image.source=https://github.com/jdx/mise\nLABEL org.opencontainers.image.description=\"mise is a tool for managing your development environment\"\nLABEL org.opencontainers.image.licenses=MIT\n\nWORKDIR /usr/src/mise\nCOPY . /usr/src/mise/\nRUN cargo build --release\n\nFROM rust@sha256:bed2d7f8140d73c26f16c298c91ae8487a09f40d3840c0d8d139537e1b51e148 AS runtime\n\nSHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\nENV MISE_DATA_DIR=\"/mise\"\nENV MISE_CONFIG_DIR=\"/mise\"\nENV MISE_CACHE_DIR=\"/mise/cache\"\nENV PATH=\"/mise/shims:$PATH\"\nENV MISE_CACHE_PRUNE_AGE=\"10y\"\n\nCOPY --from=builder /usr/src/mise/target/release/mise /usr/local/bin/mise\n\nRUN <<EOT\nset -euxo pipefail\n\napt-get update && apt-get install -y \\\n    jq                               \\\n    python3-full                     \\\n    python3-pip\nrm -rf /var/lib/apt/lists/* && apt-get clean\n\nmise use -g node@lts python@latest\n\nmise -v\nEOT\n\nWORKDIR /mise\nENTRYPOINT [\"mise\"]\nCMD [\"--help\"]\n"
  },
  {
    "path": "packaging/mise.run/shell.envsubst",
    "content": "#!/bin/sh\nset -eu\n\n#region logging setup\nif [ \"${MISE_DEBUG-}\" = \"true\" ] || [ \"${MISE_DEBUG-}\" = \"1\" ]; then\n  debug() {\n    echo \"$@\" >&2\n  }\nelse\n  debug() {\n    :\n  }\nfi\n\nif [ \"${MISE_QUIET-}\" = \"1\" ] || [ \"${MISE_QUIET-}\" = \"true\" ]; then\n  info() {\n    :\n  }\nelse\n  info() {\n    echo \"$@\" >&2\n  }\nfi\n\nerror() {\n  echo \"$@\" >&2\n  exit 1\n}\n#endregion\n\ninstall_mise() {\n  # Download and install mise using the main install script\n  info \"mise: downloading and installing mise...\"\n  \n  if [ -x \"$(command -v curl)\" ]; then\n    curl -fsSL https://mise.jdx.dev/install.sh | sh\n  elif [ -x \"$(command -v wget)\" ]; then\n    wget -qO- https://mise.jdx.dev/install.sh | sh\n  else\n    error \"mise install requires curl or wget but neither is installed. Aborting.\"\n  fi\n  \n  install_path=\"${MISE_INSTALL_PATH:-$HOME/.local/bin/mise}\"\n  \n  if [ ! -f \"$install_path\" ]; then\n    error \"mise installation failed\"\n  fi\n  \n  info \"mise: installed successfully to $install_path\"\n}\n\nsetup_${SHELL_NAME}_activation() {\n  install_path=\"${MISE_INSTALL_PATH:-$HOME/.local/bin/mise}\"\n  ${CONFIG_VAR_NAME}\n  \n  # Check if activation is already set up\n  if [ -f \"$${CONFIG_FILE_VAR}\" ] && grep -qF \"# added by https://mise.run/${SHELL_NAME}\" \"$${CONFIG_FILE_VAR}\"; then\n    info \"mise: ${SHELL_NAME} activation already configured in $${CONFIG_FILE_VAR}\"\n    return\n  fi\n  \n  # Add activation to ${SHELL_NAME} config\n  info \"mise: adding activation to $${CONFIG_FILE_VAR}\"\n  \n  ${CONFIG_SETUP_COMMANDS}\n  \n  # Add activation line\n  echo \"\" >> \"$${CONFIG_FILE_VAR}\"\n  ${ACTIVATION_COMMAND}\n  \n  info \"mise: activation added to $${CONFIG_FILE_VAR}\"\n  info \"mise: restart your shell or run '${SOURCE_COMMAND}' to activate mise\"\n  info \"mise: run 'mise doctor' to verify setup\"\n}\n\n# Main execution\ninstall_mise\nsetup_${SHELL_NAME}_activation\n\ninfo \"\"\ninfo \"mise: setup complete! 🎉\"\ninfo \"mise: ${FINAL_MESSAGE}\"\n"
  },
  {
    "path": "packaging/rpm/Dockerfile",
    "content": "FROM fedora:43@sha256:781b7642e8bf256e9cf75d2aa58d86f5cc695fd2df113517614e181a5eee9138\nLABEL maintainer=\"jdx\"\n\nRUN dnf install -y rpm-build rpm-sign ruby ruby-devel gcc \\\n      && gem install fpm \\\n      && dnf install -y createrepo \\\n      && dnf clean all\n"
  },
  {
    "path": "packaging/rpm/mise.repo",
    "content": "[mise-repo]\nname=mise repo\nbaseurl=https://mise.jdx.dev/rpm\nenabled=1\ngpgcheck=1\ngpgkey=https://mise.jdx.dev/gpg-key.pub\n"
  },
  {
    "path": "packaging/rpm/mise.spec",
    "content": "Summary: The front-end to your dev env\nName: mise\nVersion: 2026.3.9\nRelease: 1\nURL: https://github.com/jdx/mise/\nGroup: System\nLicense: MIT\nPackager: @jdx\nBuildRoot: /root/mise\n\n%description\nmise is a polyglot runtime manager\n\n%install\nmkdir -p %{buildroot}/usr/bin/\ncp /root/mise/target/release/mise %{buildroot}/usr/bin\ncp /root/mise/man/man1/mise.1 %{buildroot}/%{_mandir}/man1\n\n%files\n/usr/bin/mise\n%{_mandir}/man1/mise.1\n"
  },
  {
    "path": "packaging/rpm/rpmmacros",
    "content": "%_signature gpg\n%_gpg_name 8B81C9D17413A06D\n"
  },
  {
    "path": "packaging/snapcraft/mise-self-update-instructions.toml",
    "content": "message = \"To update mise snap package, run:\\n\\n  snap refresh\\n\\nNote that this command updates all the snap packages you installed.\\n\"\n"
  },
  {
    "path": "packaging/standalone/install.envsubst",
    "content": "#!/bin/sh\nset -eu\n\n#region logging setup\nif [ \"${MISE_DEBUG-}\" = \"true\" ] || [ \"${MISE_DEBUG-}\" = \"1\" ]; then\n  debug() {\n    echo \"$@\" >&2\n  }\nelse\n  debug() {\n    :\n  }\nfi\n\nif [ \"${MISE_QUIET-}\" = \"1\" ] || [ \"${MISE_QUIET-}\" = \"true\" ]; then\n  info() {\n    :\n  }\nelse\n  info() {\n    echo \"$@\" >&2\n  }\nfi\n\nerror() {\n  echo \"$@\" >&2\n  exit 1\n}\n#endregion\n\n#region environment setup\nget_os() {\n  os=\"$(uname -s)\"\n  if [ \"$os\" = Darwin ]; then\n    echo \"macos\"\n  elif [ \"$os\" = Linux ]; then\n    echo \"linux\"\n  else\n    error \"unsupported OS: $os\"\n  fi\n}\n\nget_arch() {\n  musl=\"\"\n  if type ldd >/dev/null 2>/dev/null; then\n    if [ \"${MISE_INSTALL_MUSL-}\" = \"1\" ] || [ \"${MISE_INSTALL_MUSL-}\" = \"true\" ]; then\n      musl=\"-musl\"\n    elif [ \"$(uname -o)\" = \"Android\" ]; then\n      # Android (Termux) always uses musl\n      musl=\"-musl\"\n    else\n      libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)\n      if [ -n \"$libc\" ]; then\n        musl=\"-musl\"\n      fi\n    fi\n  fi\n  arch=\"$(uname -m)\"\n  if [ \"$arch\" = x86_64 ]; then\n    echo \"x64$musl\"\n  elif [ \"$arch\" = aarch64 ] || [ \"$arch\" = arm64 ]; then\n    echo \"arm64$musl\"\n  elif [ \"$arch\" = armv7l ]; then\n    echo \"armv7$musl\"\n  else\n    error \"unsupported architecture: $arch\"\n  fi\n}\n\nget_ext() {\n  if [ -n \"${MISE_INSTALL_EXT:-}\" ]; then\n    echo \"$MISE_INSTALL_EXT\"\n  elif [ -n \"${MISE_VERSION:-}\" ] && echo \"$MISE_VERSION\" | grep -q '^v2024'; then\n    # 2024 versions don't have zstd tarballs\n    echo \"tar.gz\"\n  elif tar_supports_zstd; then\n    echo \"tar.zst\"\n  else\n    echo \"tar.gz\"\n  fi\n}\n\ntar_supports_zstd() {\n  if ! command -v zstd >/dev/null 2>&1; then\n    false\n  # tar is bsdtar\n  elif tar --version | grep -q 'bsdtar'; then\n    true\n  # tar version is >= 1.31\n  elif tar --version | grep -q '1\\.\\(3[1-9]\\|[4-9][0-9]\\)'; then\n    true\n  else\n    false\n  fi\n}\n\nshasum_bin() {\n  if command -v shasum >/dev/null 2>&1; then\n    echo \"shasum\"\n  elif command -v sha256sum >/dev/null 2>&1; then\n    echo \"sha256sum\"\n  else\n    error \"mise install requires shasum or sha256sum but neither is installed. Aborting.\"\n  fi\n}\n\nget_checksum() {\n  version=$1\n  os=$2\n  arch=$3\n  ext=$4\n  url=\"https://github.com/jdx/mise/releases/download/v${version}/SHASUMS256.txt\"\n  current_version=\"$MISE_CURRENT_VERSION\"\n  current_version=\"${current_version#v}\"\n\n  # For current version use static checksum otherwise\n  # use checksum from releases\n  if [ \"$version\" = \"$current_version\" ]; then\n    checksum_linux_x86_64=\"$MISE_CHECKSUM_LINUX_X86_64\"\n    checksum_linux_x86_64_musl=\"$MISE_CHECKSUM_LINUX_X86_64_MUSL\"\n    checksum_linux_arm64=\"$MISE_CHECKSUM_LINUX_ARM64\"\n    checksum_linux_arm64_musl=\"$MISE_CHECKSUM_LINUX_ARM64_MUSL\"\n    checksum_linux_armv7=\"$MISE_CHECKSUM_LINUX_ARMV7\"\n    checksum_linux_armv7_musl=\"$MISE_CHECKSUM_LINUX_ARMV7_MUSL\"\n    checksum_macos_x86_64=\"$MISE_CHECKSUM_MACOS_X86_64\"\n    checksum_macos_arm64=\"$MISE_CHECKSUM_MACOS_ARM64\"\n    checksum_linux_x86_64_zstd=\"$MISE_CHECKSUM_LINUX_X86_64_ZSTD\"\n    checksum_linux_x86_64_musl_zstd=\"$MISE_CHECKSUM_LINUX_X86_64_MUSL_ZSTD\"\n    checksum_linux_arm64_zstd=\"$MISE_CHECKSUM_LINUX_ARM64_ZSTD\"\n    checksum_linux_arm64_musl_zstd=\"$MISE_CHECKSUM_LINUX_ARM64_MUSL_ZSTD\"\n    checksum_linux_armv7_zstd=\"$MISE_CHECKSUM_LINUX_ARMV7_ZSTD\"\n    checksum_linux_armv7_musl_zstd=\"$MISE_CHECKSUM_LINUX_ARMV7_MUSL_ZSTD\"\n    checksum_macos_x86_64_zstd=\"$MISE_CHECKSUM_MACOS_X86_64_ZSTD\"\n    checksum_macos_arm64_zstd=\"$MISE_CHECKSUM_MACOS_ARM64_ZSTD\"\n\n    # TODO: refactor this, it's a bit messy\n    if [ \"$ext\" = \"tar.zst\" ]; then\n      if [ \"$os\" = \"linux\" ]; then\n        if [ \"$arch\" = \"x64\" ]; then\n          echo \"$checksum_linux_x86_64_zstd\"\n        elif [ \"$arch\" = \"x64-musl\" ]; then\n          echo \"$checksum_linux_x86_64_musl_zstd\"\n        elif [ \"$arch\" = \"arm64\" ]; then\n          echo \"$checksum_linux_arm64_zstd\"\n        elif [ \"$arch\" = \"arm64-musl\" ]; then\n          echo \"$checksum_linux_arm64_musl_zstd\"\n        elif [ \"$arch\" = \"armv7\" ]; then\n          echo \"$checksum_linux_armv7_zstd\"\n        elif [ \"$arch\" = \"armv7-musl\" ]; then\n          echo \"$checksum_linux_armv7_musl_zstd\"\n        else\n          warn \"no checksum for $os-$arch\"\n        fi\n      elif [ \"$os\" = \"macos\" ]; then\n        if [ \"$arch\" = \"x64\" ]; then\n          echo \"$checksum_macos_x86_64_zstd\"\n        elif [ \"$arch\" = \"arm64\" ]; then\n          echo \"$checksum_macos_arm64_zstd\"\n        else\n          warn \"no checksum for $os-$arch\"\n        fi\n      else\n        warn \"no checksum for $os-$arch\"\n      fi\n    else\n      if [ \"$os\" = \"linux\" ]; then\n        if [ \"$arch\" = \"x64\" ]; then\n          echo \"$checksum_linux_x86_64\"\n        elif [ \"$arch\" = \"x64-musl\" ]; then\n          echo \"$checksum_linux_x86_64_musl\"\n        elif [ \"$arch\" = \"arm64\" ]; then\n          echo \"$checksum_linux_arm64\"\n        elif [ \"$arch\" = \"arm64-musl\" ]; then\n          echo \"$checksum_linux_arm64_musl\"\n        elif [ \"$arch\" = \"armv7\" ]; then\n          echo \"$checksum_linux_armv7\"\n        elif [ \"$arch\" = \"armv7-musl\" ]; then\n          echo \"$checksum_linux_armv7_musl\"\n        else\n          warn \"no checksum for $os-$arch\"\n        fi\n      elif [ \"$os\" = \"macos\" ]; then\n        if [ \"$arch\" = \"x64\" ]; then\n          echo \"$checksum_macos_x86_64\"\n        elif [ \"$arch\" = \"arm64\" ]; then\n          echo \"$checksum_macos_arm64\"\n        else\n          warn \"no checksum for $os-$arch\"\n        fi\n      else\n        warn \"no checksum for $os-$arch\"\n      fi\n    fi\n  else\n    if command -v curl >/dev/null 2>&1; then\n      debug \">\" curl -fsSL \"$url\"\n      checksums=\"$(curl --compressed -fsSL \"$url\")\"\n    else\n      if command -v wget >/dev/null 2>&1; then\n        debug \">\" wget -qO - \"$url\"\n        checksums=\"$(wget -qO - \"$url\")\"\n      else\n        error \"mise standalone install specific version requires curl or wget but neither is installed. Aborting.\"\n      fi\n    fi\n    # TODO: verify with minisign or gpg if available\n\n    checksum=\"$(echo \"$checksums\" | grep \"$os-$arch.$ext\")\"\n    if ! echo \"$checksum\" | grep -Eq \"^([0-9a-f]{32}|[0-9a-f]{64})\"; then\n      warn \"no checksum for mise $version and $os-$arch\"\n    else\n      echo \"$checksum\"\n    fi\n  fi\n}\n\n#endregion\n\ndownload_file() {\n  url=\"$1\"\n  download_dir=\"$2\"\n  filename=\"$(basename \"$url\")\"\n  file=\"$download_dir/$filename\"\n\n  info \"mise: installing mise...\"\n\n  if command -v curl >/dev/null 2>&1; then\n    debug \">\" curl -#fLo \"$file\" \"$url\"\n    curl -#fLo \"$file\" \"$url\"\n  else\n    if command -v wget >/dev/null 2>&1; then\n      debug \">\" wget -qO \"$file\" \"$url\"\n      stderr=$(mktemp)\n      wget -O \"$file\" \"$url\" >\"$stderr\" 2>&1 || error \"wget failed: $(cat \"$stderr\")\"\n      rm \"$stderr\"\n    else\n      error \"mise standalone install requires curl or wget but neither is installed. Aborting.\"\n    fi\n  fi\n\n  echo \"$file\"\n}\n\ninstall_mise() {\n  version=\"${MISE_VERSION:-$MISE_CURRENT_VERSION}\"\n  version=\"${version#v}\"\n  current_version=\"$MISE_CURRENT_VERSION\"\n  current_version=\"${current_version#v}\"\n  os=\"${MISE_INSTALL_OS:-$(get_os)}\"\n  arch=\"${MISE_INSTALL_ARCH:-$(get_arch)}\"\n  ext=\"${MISE_INSTALL_EXT:-$(get_ext)}\"\n  install_path=\"${MISE_INSTALL_PATH:-$HOME/.local/bin/mise}\"\n  install_dir=\"$(dirname \"$install_path\")\"\n  install_from_github=\"${MISE_INSTALL_FROM_GITHUB:-}\"\n  if [ \"$version\" != \"$current_version\" ] || [ \"$install_from_github\" = \"1\" ] || [ \"$install_from_github\" = \"true\" ]; then\n    tarball_url=\"https://github.com/jdx/mise/releases/download/v${version}/mise-v${version}-${os}-${arch}.${ext}\"\n  elif [ -n \"${MISE_TARBALL_URL-}\" ]; then\n    tarball_url=\"$MISE_TARBALL_URL\"\n  else\n    tarball_url=\"https://mise.jdx.dev/v${version}/mise-v${version}-${os}-${arch}.${ext}\"\n  fi\n\n  download_dir=\"$(mktemp -d)\"\n  cache_file=$(download_file \"$tarball_url\" \"$download_dir\")\n  debug \"mise-setup: tarball=$cache_file\"\n\n  debug \"validating checksum\"\n  cd \"$(dirname \"$cache_file\")\" && get_checksum \"$version\" \"$os\" \"$arch\" \"$ext\" | \"$(shasum_bin)\" -c >/dev/null\n\n  # extract tarball\n  if [ -d \"$install_path\" ]; then\n    error \"MISE_INSTALL_PATH '$install_path' is a directory. Please set it to a file path, e.g. '$install_path/mise'.\"\n  fi\n  mkdir -p \"$install_dir\"\n  rm -f \"$install_path\"\n  extract_dir=\"$(mktemp -d)\"\n  cd \"$extract_dir\"\n  if [ \"$ext\" = \"tar.zst\" ] && ! tar_supports_zstd; then\n    zstd -d -c \"$cache_file\" | tar -xf -\n  else\n    tar -xf \"$cache_file\"\n  fi\n  mv mise/bin/mise \"$install_path\"\n\n  # cleanup\n  cd / # Move out of $extract_dir before removing it\n  rm -rf \"$download_dir\"\n  rm -rf \"$extract_dir\"\n\n  info \"mise: installed successfully to $install_path\"\n}\n\nafter_finish_help() {\n  case \"${SHELL:-}\" in\n  */zsh)\n    info \"mise: run the following to activate mise in your shell:\"\n    info \"echo \\\"eval \\\\\\\"\\\\\\$($install_path activate zsh)\\\\\\\"\\\" >> \\\"${ZDOTDIR-$HOME}/.zshrc\\\"\"\n    info \"\"\n    info \"mise: run \\`mise doctor\\` to verify this is set up correctly\"\n    ;;\n  */bash)\n    info \"mise: run the following to activate mise in your shell:\"\n    info \"echo \\\"eval \\\\\\\"\\\\\\$($install_path activate bash)\\\\\\\"\\\" >> ~/.bashrc\"\n    info \"\"\n    info \"mise: run \\`mise doctor\\` to verify this is set up correctly\"\n    ;;\n  */fish)\n    info \"mise: run the following to activate mise in your shell:\"\n    info \"echo \\\"$install_path activate fish | source\\\" >> ~/.config/fish/config.fish\"\n    info \"\"\n    info \"mise: run \\`mise doctor\\` to verify this is set up correctly\"\n    ;;\n  *)\n    info \"mise: run \\`$install_path --help\\` to get started\"\n    ;;\n  esac\n}\n\ninstall_mise\nif [ \"${MISE_INSTALL_HELP-}\" != 0 ]; then\n  after_finish_help\nfi\n"
  },
  {
    "path": "pitchfork.toml",
    "content": "[daemons.docs]\nrun = \"mise run docs\"\nauto = [\"stop\"]\n"
  },
  {
    "path": "registry/1password.toml",
    "content": "aliases = [\"1password-cli\", \"op\"]\nbackends = [\"vfox:mise-plugins/vfox-1password\", \"aqua:1password/cli\"]\ndescription = \"Password manager developed by AgileBits Inc\"\ntest = { cmd = \"op --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/aapt2.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-aapt2\"]\ndescription = \"Android Asset Packaging Tool (aapt)\"\ntest = { cmd = \"aapt2 version 2>&1\", expected = \"Android Asset Packaging Tool (aapt)\" } # version doesn't match\n"
  },
  {
    "path": "registry/act.toml",
    "content": "backends = [\"aqua:nektos/act\", \"asdf:gr1m0h/asdf-act\"]\ndescription = \"Run your GitHub Actions locally\"\ntest = { cmd = \"act --version\", expected = \"act version {{version}}\" }\n"
  },
  {
    "path": "registry/action-validator.toml",
    "content": "backends = [\n  \"aqua:mpalmer/action-validator\",\n  \"asdf:mpalmer/action-validator\",\n  \"cargo:action-validator\",\n]\ndescription = \"Tool to validate GitHub Action and Workflow YAML files\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"action-validator --version\", expected = \"action-validator {{version}}\" }\n"
  },
  {
    "path": "registry/actionlint.toml",
    "content": "backends = [\n  \"aqua:rhysd/actionlint\",\n  \"asdf:crazy-matt/asdf-actionlint\",\n  \"go:github.com/rhysd/actionlint/cmd/actionlint\",\n]\ndescription = \":octocat: Static checker for GitHub Actions workflow files\"\ntest = { cmd = \"actionlint --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/adr-tools.toml",
    "content": "backends = [\n  \"aqua:npryce/adr-tools\",\n  \"asdf:https://gitlab.com/td7x/asdf/adr-tools\",\n]\ndescription = \"Command-line tools for working with Architecture Decision Records\"\ntest = { cmd = \"adr help\", expected = \"adr help\" }\n"
  },
  {
    "path": "registry/ag.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-ag\", \"asdf:mise-plugins/mise-ag\"]\ndescription = \"The Silver Searcher: A code searching tool similar to ack, with a focus on speed\"\n# test = [\"ag --version\", \"ag version {{version}}\"] # requires libpcre\n"
  },
  {
    "path": "registry/age-plugin-yubikey.toml",
    "content": "backends = [\n  \"github:str4d/age-plugin-yubikey\",\n  \"asdf:joke/asdf-age-plugin-yubikey\",\n  \"cargo:age-plugin-yubikey\",\n]\ndescription = \"age-plugin-yubikey is a plugin for age clients like age and rage, which enables files to be encrypted to age identities stored on YubiKeys\"\ntest = { cmd = \"which age-plugin-yubikey\", expected = \"\" } # libpcsclite.so.1 is missing in CI\n"
  },
  {
    "path": "registry/age.toml",
    "content": "backends = [\"aqua:FiloSottile/age\", \"asdf:threkk/asdf-age\"]\ndescription = \"A simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability\"\ntest = { cmd = \"age --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/agebox.toml",
    "content": "backends = [\"aqua:slok/agebox\", \"asdf:slok/asdf-agebox\"]\ndescription = \"Age based repository file encryption gitops tool\"\ntest = { cmd = \"agebox --version 2>&1\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/aichat.toml",
    "content": "backends = [\"aqua:sigoden/aichat\"]\ndescription = \"Use GPT-4(V), Gemini, LocalAI, Ollama and other LLMs in the terminal\"\ntest = { cmd = \"aichat --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/air.toml",
    "content": "backends = [\"aqua:air-verse/air\", \"asdf:pdemagny/asdf-air\"]\ndescription = \"Live reload for Go apps\"\ntest = { cmd = \"air -v\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/aks-engine.toml",
    "content": "backends = [\"aqua:Azure/aks-engine\", \"asdf:robsonpeixoto/asdf-aks-engine\"]\ndescription = \"AKS Engine deploys and manages Kubernetes clusters in Azure\"\ntest = { cmd = \"aks-engine version\", expected = \"Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/allure.toml",
    "content": "backends = [\"github:allure-framework/allure2\", \"asdf:mise-plugins/mise-allure\"]\ndescription = \"Allure Report is a popular open source tool for visualizing the results of a test run\"\ntest = { cmd = \"allure --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/allurectl.toml",
    "content": "backends = [\"github:allure-framework/allurectl\"]\ndescription = \"allurectl is the command line wrapper of Allure TestOps' API allowing you to upload the test results in real time from a build job, and managing entities on Allure TestOps side (test cases, launches, projects)\"\ntest = { cmd = \"allurectl --version\", expected = \"allurectl version {{version}}\" }\n"
  },
  {
    "path": "registry/alp.toml",
    "content": "backends = [\"aqua:tkuchiki/alp\", \"asdf:asdf-community/asdf-alp\"]\ndescription = \"Access Log Profiler\"\ntest = { cmd = \"alp --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/amass.toml",
    "content": "backends = [\"github:owasp-amass/amass\", \"asdf:dhoeric/asdf-amass\"]\ndescription = \"In-depth attack surface mapping and asset discovery\"\ntest = { cmd = \"amass -version 2>&1\", expected = \"v\" } # version is wrong from the CLI\n"
  },
  {
    "path": "registry/amazon-ecr-credential-helper.toml",
    "content": "backends = [\n  \"aqua:awslabs/amazon-ecr-credential-helper\",\n  \"asdf:dex4er/asdf-amazon-ecr-credential-helper\",\n]\ndescription = \"Automatically gets credentials for Amazon ECR on docker push/docker pull\"\ntest = { cmd = \"docker-credential-ecr-login version\", expected = \"docker-credential-ecr-login (github.com/awslabs/amazon-ecr-credential-helper/ecr-login) {{version}}\" }\n"
  },
  {
    "path": "registry/amazon-ecs-cli.toml",
    "content": "aliases = [\"ecs-cli\"]\nbackends = [\"aqua:aws/amazon-ecs-cli\"]\ndescription = \"The Amazon ECS CLI enables users to run their applications on ECS/Fargate using the Docker Compose file format, quickly provision resources, push/pull images in ECR, and monitor running applications on ECS/Fargate.\"\ntest = { cmd = \"ecs-cli --version\", expected = \"ecs-cli version {{version}}\" }\n"
  },
  {
    "path": "registry/amp.toml",
    "content": "backends = [\"npm:@sourcegraph/amp\"]\ndescription = \"An agentic coding tool built by Sourcegraph\"\ntest = { cmd = \"amp --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/android-sdk.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-android-sdk\"]\ndepends = [\"java\"]\ndescription = \"Android Command-line tools\"\ntest = { cmd = \"sdkmanager --version\", expected = \".0\" }\n"
  },
  {
    "path": "registry/ansible-core.toml",
    "content": "aliases = [\"ansible-base\"]\nbackends = [\"pipx:ansible-core\"]\ndescription = \"ansible-core python package contains the core runtime and CLI tools, such as ansible and ansible-playbook\"\ntest = { cmd = \"ansible --version\", expected = \"ansible [core {{version}}]\" }\n"
  },
  {
    "path": "registry/ansible.toml",
    "content": "description = \"ansible python package contains the core runtime and CLI tools, such as ansible and ansible-playbook and extra modules, plugins, and roles\"\ntest = { cmd = \"ansible --version\", expected = \"ansible\" }\n\n[[backends]]\nfull = \"pipx:ansible\"\n\n[backends.options]\npipx_args = \"--include-deps\"\nuvx = false\n"
  },
  {
    "path": "registry/ant.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-ant\"]\ndescription = \"Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other\"\ntest = { cmd = \"ant -version\", expected = \"Apache Ant(TM) version {{version}}\" }\n"
  },
  {
    "path": "registry/apko.toml",
    "content": "backends = [\"aqua:chainguard-dev/apko\", \"asdf:omissis/asdf-apko\"]\ndescription = \"Build OCI images from APK packages directly without Dockerfile\"\ntest = { cmd = \"apko version\", expected = \"GitVersion:    v{{version}}\" }\n"
  },
  {
    "path": "registry/apollo-ios.toml",
    "content": "aliases = [\"apollo-ios-cli\"]\nbackends = [\"github:apollographql/apollo-ios\"]\ndescription = \"Apollo iOS Code Generation\"\nos = [\"macos\"]\n"
  },
  {
    "path": "registry/apollo-router.toml",
    "content": "backends = [\"github:apollographql/router\", \"asdf:safx/asdf-apollo-router\"]\ndescription = \"A configurable, high-performance routing runtime for Apollo Federation\"\ntest = { cmd = \"router --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/apollo-rover.toml",
    "content": "backends = [\"github:apollographql/rover\"]\ndescription = \"The CLI for Apollo GraphOS\"\ntest = { cmd = \"rover --version\", expected = \"Rover {{version}}\" }\n"
  },
  {
    "path": "registry/aqua.toml",
    "content": "backends = [\"github:aquaproj/aqua\"]\ndescription = \"Declarative CLI Version manager written in Go. Support Lazy Install, Registry, and continuous update with Renovate. CLI version is switched seamlessly\"\ntest = { cmd = \"aqua version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/arduino.toml",
    "content": "aliases = [\"arduino-cli\"]\nbackends = [\"aqua:arduino/arduino-cli\", \"asdf:egnor/asdf-arduino-cli\"]\ndescription = \"Arduino command line tool\"\ntest = { cmd = \"arduino-cli version\", expected = \"arduino-cli  Version: {{version}}\" }\n"
  },
  {
    "path": "registry/argc.toml",
    "content": "backends = [\"github:sigoden/argc\"]\ndescription = \"A Bash CLI framework, also a Bash command runner\"\ntest = { cmd = \"argc --argc-version\", expected = \"argc {{version}}\" }\n"
  },
  {
    "path": "registry/argo-rollouts.toml",
    "content": "backends = [\"aqua:argoproj/argo-rollouts\", \"asdf:abatilo/asdf-argo-rollouts\"]\ndescription = \"Progressive Delivery for Kubernetes\"\ntest = { cmd = \"kubectl-argo-rollouts version\", expected = \"kubectl-argo-rollouts: v{{version}}\" }\n"
  },
  {
    "path": "registry/argo.toml",
    "content": "backends = [\"aqua:argoproj/argo-workflows\", \"asdf:sudermanjr/asdf-argo\"]\ndescription = \"Argo Workflows CLI. Workflow engine for Kubernetes\"\ntest = { cmd = \"argo version\", expected = \"argo: v{{version}}\" }\n"
  },
  {
    "path": "registry/argocd.toml",
    "content": "backends = [\"aqua:argoproj/argo-cd\", \"asdf:beardix/asdf-argocd\"]\ndescription = \"Declarative continuous deployment for Kubernetes\"\ntest = { cmd = \"argocd version --client\", expected = \"argocd: v{{version}}\" }\n"
  },
  {
    "path": "registry/asciidoctorj.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-asciidoctorj\",\n  \"asdf:mise-plugins/mise-asciidoctorj\",\n]\ndescription = \"AsciidoctorJ is the official library for running Asciidoctor on the JVM. Using AsciidoctorJ, you can convert AsciiDoc content or analyze the structure of a parsed AsciiDoc document from Java and other JVM languages\"\ntest = { cmd = \"asciidoctorj --version\", expected = \"AsciidoctorJ {{version}}\" }\n"
  },
  {
    "path": "registry/assh.toml",
    "content": "backends = [\"github:moul/assh\", \"asdf:mise-plugins/mise-assh\"]\ndescription = \"make your ssh client smarter\"\ntest = { cmd = \"assh --version\", expected = \"assh version \" } # 2.16.0 reports version n/a\n"
  },
  {
    "path": "registry/ast-grep.toml",
    "content": "backends = [\n  \"aqua:ast-grep/ast-grep\",\n  \"cargo:ast-grep\",\n  \"npm:@ast-grep/cli\",\n  \"pipx:ast-grep-cli\",\n]\ndescription = \"A CLI tool for code structural search, lint and rewriting. Written in Rust\"\ntest = { cmd = \"sg --version\", expected = \"ast-grep {{version}}\" }\n"
  },
  {
    "path": "registry/astro.toml",
    "content": "description = \"CLI that makes it easy to create, test and deploy Airflow DAGs to Astronomer\"\ntest = { cmd = \"astro version\", expected = \"Astro CLI Version: {{version}}\" }\n\n[[backends]]\nfull = \"github:astronomer/astro-cli\"\n\n[backends.options]\nexe = \"astro\"\n"
  },
  {
    "path": "registry/atlas-community.toml",
    "content": "backends = [\"aqua:ariga/atlas/community\"]\ndescription = \"A modern tool for managing database schemas (Community Edition)\"\ntest = { cmd = \"atlas version\", expected = \"atlas community version v{{version}}\" }\n"
  },
  {
    "path": "registry/atlas.toml",
    "content": "backends = [\"aqua:ariga/atlas\", \"asdf:komi1230/asdf-atlas\"]\ndescription = \"A modern tool for managing database schemas\"\ntest = { cmd = \"atlas version\", expected = \"atlas version v{{version}}\" }\n"
  },
  {
    "path": "registry/atmos.toml",
    "content": "backends = [\"aqua:cloudposse/atmos\", \"asdf:cloudposse/asdf-atmos\"]\ndescription = \"Workflow automation tool for DevOps. Keep configuration DRY with hierarchical imports of configurations, inheritance, and WAY more. Native support for Terraform and Helmfile\"\nidiomatic_files = [\".atmos-version\"]\ntest = { cmd = \"atmos version\", expected = \"Atmos {{version}}\" }\n"
  },
  {
    "path": "registry/atuin.toml",
    "content": "backends = [\"aqua:atuinsh/atuin\", \"cargo:atuin\"]\ndescription = \"✨ Magical shell history\"\ntest = { cmd = \"atuin --version\", expected = \"atuin {{version}}\" }\n"
  },
  {
    "path": "registry/auto-doc.toml",
    "content": "backends = [\"github:tj-actions/auto-doc\", \"asdf:mise-plugins/mise-auto-doc\"]\ndescription = \"Github action that turns your reusable workflows and custom actions into easy to read markdown tables\"\ntest = { cmd = \"auto-doc --help\", expected = \"auto-doc [flags]\" }\n"
  },
  {
    "path": "registry/aws-amplify.toml",
    "content": "aliases = [\"amplify\"]\ndescription = \"The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development\"\n# test = [\"amplify --version\", \"{{version}}\"]  # hangs in CI\n\n[[backends]]\nfull = \"github:aws-amplify/amplify-cli\"\n\n[backends.options]\nrename_exe = \"amplify\"\n\n[[backends]]\nfull = \"asdf:LozanoMatheus/asdf-aws-amplify-cli\"\n"
  },
  {
    "path": "registry/aws-cli.toml",
    "content": "aliases = [\"aws\", \"awscli\"]\nbackends = [\n  { full = \"aqua:aws/aws-cli\", options = { symlink_bins = \"true\" } },\n  \"asdf:MetricMike/asdf-awscli\",\n]\ndescription = \"The AWS Command Line Interface (AWS CLI v2) is a unified tool that provides a consistent interface for interacting with all parts of Amazon Web Services\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"aws --version\", expected = \"aws-cli/{{version}}\" }\n"
  },
  {
    "path": "registry/aws-copilot.toml",
    "content": "backends = [\"aqua:aws/copilot-cli\", \"asdf:NeoHsu/asdf-copilot\"]\ndescription = \"The AWS Copilot CLI is a tool for developers to build, release and operate production ready containerized applications on AWS App Runner, Amazon ECS, and AWS Fargate\"\ntest = { cmd = \"copilot --version\", expected = \"copilot version: v{{version}}\" }\n"
  },
  {
    "path": "registry/aws-iam-authenticator.toml",
    "content": "backends = [\n  \"aqua:kubernetes-sigs/aws-iam-authenticator\",\n  \"asdf:zekker6/asdf-aws-iam-authenticator\",\n]\ndescription = \"A tool to use AWS IAM credentials to authenticate to a Kubernetes cluster\"\ntest = { cmd = \"aws-iam-authenticator version\", expected = '\"Version\":\"{{version}}\"' }\n"
  },
  {
    "path": "registry/aws-nuke.toml",
    "content": "backends = [\"aqua:ekristen/aws-nuke\", \"asdf:bersalazar/asdf-aws-nuke\"]\ndescription = \"Remove all the resources from an AWS account\"\ntest = { cmd = \"aws-nuke --version\", expected = \"aws-nuke version v{{version}}\" }\n"
  },
  {
    "path": "registry/aws-sam.toml",
    "content": "aliases = [\"aws-sam-cli\"]\nbackends = [\n  { full = \"aqua:aws/aws-sam-cli\", platforms = [\n    \"linux\",\n    \"macos\",\n  ], options = { symlink_bins = \"true\" } },\n  \"pipx:aws-sam-cli\",\n  \"asdf:mise-plugins/mise-pyapp\",\n]\ndescription = \"CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM\"\ntest = { cmd = \"sam --version\", expected = \"SAM CLI, version {{version}}\" }\n"
  },
  {
    "path": "registry/aws-sso.toml",
    "content": "backends = [\"aqua:synfinatic/aws-sso-cli\", \"asdf:adamcrews/asdf-aws-sso-cli\"]\ndescription = \"A powerful tool for using AWS Identity Center for the CLI and web console\"\ntest = { cmd = \"aws-sso version\", expected = \"AWS SSO CLI Version {{version}}\" }\n"
  },
  {
    "path": "registry/aws-vault.toml",
    "content": "backends = [\"aqua:ByteNess/aws-vault\"]\ndescription = \"A vault for securely storing and accessing AWS credentials in development environments\"\n# test = [\"aws-vault --version 2>&1\", \"v{{version}}\"] # TODO: re-enable after versions host update\n"
  },
  {
    "path": "registry/awscli-local.toml",
    "content": "backends = [\"pipx:awscli-local\"]\ndescription = \"This package provides the awslocal command, which is a thin wrapper around the aws command line interface for use with LocalStack\"\ntest = { cmd = \"awslocal --version\", expected = \"aws-cli/\" }\n"
  },
  {
    "path": "registry/awsebcli.toml",
    "content": "backends = [\"pipx:awsebcli\", \"asdf:mise-plugins/mise-pyapp\"]\ndescription = \"The AWS Elastic Beanstalk Command Line Interface (EB CLI) is a tool that helps you deploy and manage your Elastic Beanstalk applications and environments. It also provides integration with Git\"\ntest = { cmd = \"eb --version\", expected = \"EB CLI {{version}}\" }\n"
  },
  {
    "path": "registry/awsls.toml",
    "content": "backends = [\"github:jckuester/awsls\", \"asdf:chessmango/asdf-awsls\"]\ndescription = \"A list command for AWS resources\"\ntest = { cmd = \"awsls --version\", expected = \"version: {{version}}\" }\n"
  },
  {
    "path": "registry/awsrm.toml",
    "content": "backends = [\"github:jckuester/awsrm\", \"asdf:chessmango/asdf-awsrm\"]\ndescription = \"A remove command for AWS resources\"\ntest = { cmd = \"awsrm --version\", expected = \"version: {{version}}\" }\n"
  },
  {
    "path": "registry/awsweeper.toml",
    "content": "backends = [\"github:jckuester/awsweeper\", \"asdf:chessmango/asdf-awsweeper\"]\ndescription = \"A tool for cleaning your AWS account\"\ntest = { cmd = \"awsweeper --version\", expected = \"version: {{version}}\" }\n"
  },
  {
    "path": "registry/azure-functions-core-tools.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-azure-functions-core-tools\",\n  \"asdf:mise-plugins/mise-azure-functions-core-tools\",\n]\ndescription = \"Command line tools for Azure Functions\"\n"
  },
  {
    "path": "registry/azure-kubelogin.toml",
    "content": "backends = [\"aqua:Azure/kubelogin\", \"asdf:sechmann/asdf-kubelogin\"]\ndescription = \"A Kubernetes credential (exec) plugin implementing azure authentication\"\ntest = { cmd = \"kubelogin --version\", expected = \"git hash: v{{version}}\" }\n"
  },
  {
    "path": "registry/azure.toml",
    "content": "aliases = [\"azure-cli\"]\ndescription = \"azure-cli (az)\"\ntest = { cmd = \"az --version\", expected = \"azure-cli                         {{version}}\" }\n\n[[backends]]\nfull = \"pipx:azure-cli\"\n\n[backends.options]\nuvx_args = \"--prerelease=allow\"\n"
  },
  {
    "path": "registry/babashka.toml",
    "content": "description = \"Native, fast starting Clojure interpreter for scripting\"\ntest = { cmd = \"bb --version\", expected = \"babashka v{{version}}\" }\n\n[[backends]]\nfull = \"github:babashka/babashka\"\n\n[backends.options]\nexe = \"bb\"\n\n[[backends]]\nfull = \"asdf:pitch-io/asdf-babashka\"\n"
  },
  {
    "path": "registry/balena.toml",
    "content": "aliases = [\"balena-cli\"]\nbackends = [\"github:balena-io/balena-cli\", \"asdf:jaredallard/asdf-balena-cli\"]\ndescription = \"The balena CLI is a Command Line Interface for balenaCloud or openBalena\"\ntest = { cmd = \"balena --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/bashbot.toml",
    "content": "backends = [\"aqua:mathew-fleisch/bashbot\", \"asdf:mathew-fleisch/asdf-bashbot\"]\ndescription = \"A slack-bot written in golang for infrastructure/devops teams\"\ntest = { cmd = \"bashbot version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/bashly.toml",
    "content": "backends = [\"gem:bashly\", \"asdf:mise-plugins/mise-bashly\"]\ndepends = [\"ruby\"]\ndescription = \"Bashly is a command line application (written in Ruby) that lets you generate feature-rich bash command line tools\"\n# test = [\"bashly --version\", \"{{version}}\"]  # not working in CI\n"
  },
  {
    "path": "registry/bat-extras.toml",
    "content": "backends = [\"aqua:eth-p/bat-extras\", \"asdf:mise-plugins/mise-bat-extras\"]\ndescription = \"Bash scripts that integrate bat with various command line tools\"\ntest = { cmd = \"batman --version\", expected = \"batman {{version}}\" }\n"
  },
  {
    "path": "registry/bat.toml",
    "content": "backends = [\n  \"aqua:sharkdp/bat\",\n  \"cargo:bat\",\n  \"asdf:https://gitlab.com/wt0f/asdf-bat\",\n]\ndescription = \"A cat(1) clone with wings\"\ntest = { cmd = \"bat --version\", expected = \"bat {{version}}\" }\n"
  },
  {
    "path": "registry/bats.toml",
    "content": "backends = [\"aqua:bats-core/bats-core\", \"asdf:timgluz/asdf-bats\"]\ndescription = \"Bash Automated Testing System\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"bats -v\", expected = \"Bats\" }\n"
  },
  {
    "path": "registry/bazel-watcher.toml",
    "content": "backends = [\"aqua:bazelbuild/bazel-watcher\"]\ndescription = \"Tools for building Bazel targets when source files change\"\ntest = { cmd = \"ibazel version 2>&1\", expected = \"iBazel - Version v{{version}}\" }\n"
  },
  {
    "path": "registry/bazel.toml",
    "content": "backends = [\"aqua:bazelbuild/bazel\", \"asdf:rajatvig/asdf-bazel\"]\ndescription = \"a fast, scalable, multi-language and extensible build system\"\ntest = { cmd = \"bazel --version\", expected = \"bazel {{version}}\" }\n"
  },
  {
    "path": "registry/bazelisk.toml",
    "content": "backends = [\n  \"aqua:bazelbuild/bazelisk\",\n  \"npm:@bazel/bazelisk\",\n  \"asdf:josephtate/asdf-bazelisk\",\n]\ndescription = \"A user-friendly launcher for Bazel\"\ntest = { cmd = \"bazelisk --version\", expected = \"bazel\" } # shows bazel version, not bazelisk version\n"
  },
  {
    "path": "registry/bfs.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-bfs\", \"asdf:mise-plugins/mise-bfs\"]\ndescription = \"Breadth-first search for your files\"\ntest = { cmd = \"bfs --version\", expected = \"bfs {{version}}\" }\n"
  },
  {
    "path": "registry/bibtex-tidy.toml",
    "content": "backends = [\"npm:bibtex-tidy\"]\ndescription = \"Cleaner and Formatter for BibTeX files\"\ntest = { cmd = \"bibtex-tidy --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/binnacle.toml",
    "content": "backends = [\"aqua:Traackr/binnacle\", \"asdf:Traackr/asdf-binnacle\"]\ndescription = \"An opinionated tool to interact with Kubernetes' Helm\"\ntest = { cmd = \"binnacle --version\", expected = \"binnacle version {{version}}\" }\n"
  },
  {
    "path": "registry/biome.toml",
    "content": "backends = [\"aqua:biomejs/biome\", \"npm:@biomejs/biome\"]\ndescription = \"A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP\"\ntest = { cmd = \"biome --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/bitwarden-secrets-manager.toml",
    "content": "description = \"CLI for interacting with the Bitwarden Secrets Manager\"\ntest = { cmd = \"bws --version\", expected = \"bws {{version}}\" }\n\n[[backends]]\nfull = \"github:bitwarden/sdk\"\n\n[backends.options]\nversion_prefix = \"bws-v\"\n\n[[backends]]\nfull = \"asdf:asdf-community/asdf-bitwarden-secrets-manager\"\n"
  },
  {
    "path": "registry/bitwarden.toml",
    "content": "backends = [\"aqua:bitwarden/clients\", \"asdf:vixus0/asdf-bitwarden\"]\ndescription = \"Bitwarden CLI\"\ntest = { cmd = \"bw --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/black.toml",
    "content": "backends = [\"aqua:psf/black\"]\ndescription = \"The uncompromising Python code formatter\"\ntest = { cmd = \"black --version\", expected = \"black, {{version}}\" }\n"
  },
  {
    "path": "registry/blender.toml",
    "content": "backends = [\"aqua:blender/blender\"]\ndescription = \"Blender is a free and open-source 3D computer graphics software\"\ntest = { cmd = \"blender --version\", expected = \"Blender {{version}}\" }\n"
  },
  {
    "path": "registry/bob.toml",
    "content": "backends = [\"aqua:MordechaiHadad/bob\", \"cargo:bob-nvim\"]\ndescription = \"A version manager for neovim\"\ntest = { cmd = \"bob --version\", expected = \"bob-nvim {{version}}\" }\n"
  },
  {
    "path": "registry/boilerplate.toml",
    "content": "backends = [\"aqua:gruntwork-io/boilerplate\"]\ndescription = 'A tool for generating files and folders (\"boilerplate\") from a set of templates'\ntest = { cmd = \"boilerplate --version\", expected = \"boilerplate version v{{version}}\" }\n"
  },
  {
    "path": "registry/bombardier.toml",
    "content": "backends = [\"aqua:codesenberg/bombardier\", \"asdf:NeoHsu/asdf-bombardier\"]\ndescription = \"Fast cross-platform HTTP benchmarking tool written in Go\"\ntest = { cmd = \"bombardier --version 2>&1\", expected = \"bombardier version\" } # shows \"unspecified\"\n"
  },
  {
    "path": "registry/borg.toml",
    "content": "backends = [\"aqua:borgbackup/borg\", \"asdf:lwiechec/asdf-borg\"]\ndescription = \"Deduplicating archiver with compression and authenticated encryption\"\ntest = { cmd = \"borg --version\", expected = \"borg {{version}}\" }\n"
  },
  {
    "path": "registry/bosh-backup-and-restore.toml",
    "content": "aliases = [\"bbr\"]\ndescription = \"BOSH Backup and Restore is a CLI utility for orchestrating the backup and restore of BOSH deployments and BOSH directors\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"bosh-backup-and-restore version\", expected = \"bbr version {{version}}\" }\n\n[[backends]]\nfull = \"github:cloudfoundry-incubator/bosh-backup-and-restore\"\n\n[backends.options]\nasset_pattern = \"bbr-*-{darwin_os}-{amd64_arch}\"\nbin = \"bosh-backup-and-restore\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/tanzu-plug-in-for-asdf\"\n"
  },
  {
    "path": "registry/bosh.toml",
    "content": "backends = [\n  \"aqua:cloudfoundry/bosh-cli\",\n  \"asdf:mise-plugins/tanzu-plug-in-for-asdf\",\n]\ndescription = \"The bosh CLI is the command line tool used for interacting with all things BOSH, from deployment operations to software release management\"\ntest = { cmd = \"bosh --version\", expected = \"version {{version}}\" }\n"
  },
  {
    "path": "registry/bottom.toml",
    "content": "backends = [\n  \"aqua:ClementTsang/bottom\",\n  \"asdf:carbonteq/asdf-btm\",\n  \"cargo:bottom\",\n]\ndescription = \"Yet another cross-platform graphical process/system monitor\"\ntest = { cmd = \"btm --version\", expected = \"bottom {{version}}\" }\n"
  },
  {
    "path": "registry/boundary.toml",
    "content": "backends = [\"aqua:hashicorp/boundary\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"Boundary enables identity-based access management for dynamic infrastructure\"\ntest = { cmd = \"boundary version\", expected = \"Version Number:      {{version}}\" }\n"
  },
  {
    "path": "registry/bpkg.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-bpkg\", \"asdf:mise-plugins/mise-bpkg\"]\ndescription = \"Lightweight bash package manager\"\ntest = { cmd = \"bpkg --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/brig.toml",
    "content": "backends = [\"aqua:brigadecore/brigade\", \"asdf:Ibotta/asdf-brig\"]\ndescription = \"Brigade CLI. Event-driven scripting for Kubernetes\"\ntest = { cmd = \"brig version\", expected = \"Brigade client: version v{{version}}\" }\n"
  },
  {
    "path": "registry/btop.toml",
    "content": "backends = [\"aqua:aristocratos/btop\"]\ndescription = \"A monitor of resources\"\ntest = { cmd = '''btop --version | sed -e 's/\\x1b\\[[0-9;]*m//g'''', expected = \"btop version: {{version}}\" }\n"
  },
  {
    "path": "registry/btrace.toml",
    "content": "backends = [\"github:btraceio/btrace\", \"asdf:mise-plugins/mise-btrace\"]\ndescription = \"BTrace - a safe, dynamic tracing tool for the Java platform\"\ntest = { cmd = \"btrace --version\", expected = \"BTrace v.{{version}}\" }\n"
  },
  {
    "path": "registry/buck2.toml",
    "content": "description = \"A fast, hermetic, multi-language build system\"\n# test disabled: facebook replaces assets in-place on \"latest\" tag causing checksum race conditions\n# test = [\"buck2 --version\", \"buck2\"]\n\n[[backends]]\nfull = \"github:facebook/buck2\"\n\n[backends.options]\nbin = \"buck2\"\n"
  },
  {
    "path": "registry/buf.toml",
    "content": "backends = [\"aqua:bufbuild/buf\", \"asdf:truepay/asdf-buf\"]\ndescription = \"The best way of working with Protocol Buffers\"\ntest = { cmd = \"buf --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/buildifier.toml",
    "content": "backends = [\"aqua:bazelbuild/buildtools/buildifier\"]\ndescription = \"buildifier: For formatting BUILD, BUILD.bazel and BUCK files in a standard way\"\ntest = { cmd = \"buildifier --version\", expected = \"buildifier version: {{version}}\" }\n"
  },
  {
    "path": "registry/buildpack.toml",
    "content": "aliases = [\"pack\", \"buildpacks\"]\nbackends = [\"aqua:buildpacks/pack\", \"asdf:johnlayton/asdf-buildpack\"]\ndescription = \"CLI for building apps using Cloud Native Buildpacks\"\ntest = { cmd = \"pack --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/bun.toml",
    "content": "backends = [\"core:bun\"]\ndescription = \"Bun is a fast JavaScript all-in-one toolkit\"\ndetect = [\"bun.lock\", \"bun.lockb\", \"bunfig.toml\"]\ntest = { cmd = \"bun --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/cabal.toml",
    "content": "backends = [\"aqua:haskell/cabal/cabal-install\"]\ndescription = \"Cabal(haskell): Common Architecture for Building Applications and Libraries\"\ntest = { cmd = \"cabal --version\", expected = \"cabal-install version {{version}}\" }\n"
  },
  {
    "path": "registry/caddy.toml",
    "content": "backends = [\"aqua:caddyserver/caddy\", \"asdf:salasrod/asdf-caddy\"]\ndescription = \"Fast, multi-platform web server with automatic HTTPS\"\ntest = { cmd = \"caddy --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/calendarsync.toml",
    "content": "backends = [\"aqua:inovex/CalendarSync\", \"asdf:FeryET/asdf-calendarsync\"]\ndescription = \"Stateless CLI tool to sync calendars across different calendaring systems\"\ntest = { cmd = \"CalendarSync --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/calicoctl.toml",
    "content": "backends = [\n  \"aqua:projectcalico/calico/calicoctl\",\n  \"asdf:TheCubicleJockey/asdf-calicoctl\",\n]\ndescription = \"Cloud native networking and network security\"\ntest = { cmd = \"calicoctl version\", expected = \"Client Version:    v{{version}}\" }\n"
  },
  {
    "path": "registry/carapace.toml",
    "content": "backends = [\"aqua:carapace-sh/carapace-bin\"]\ndescription = \"A multi-shell completion binary\"\ntest = { cmd = \"carapace --version 2>&1\", expected = \"carapace-bin {{version}}\" }\n"
  },
  {
    "path": "registry/cargo-binstall.toml",
    "content": "backends = [\"aqua:cargo-bins/cargo-binstall\", \"cargo:cargo-binstall\"]\ndescription = \"Binary installation for rust projects\"\ntest = { cmd = \"cargo binstall -V\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/cargo-dist.toml",
    "content": "backends = [\n  \"aqua:axodotdev/cargo-dist\",\n  \"github:axodotdev/cargo-dist\",\n  \"cargo:cargo-dist\",\n]\ndescription = \"📦 shippable application packaging\"\ntest = { cmd = \"dist --version\", expected = \"cargo-dist {{version}}\" }\n"
  },
  {
    "path": "registry/cargo-insta.toml",
    "content": "backends = [\"aqua:mitsuhiko/insta\", \"cargo:insta\"]\ndescription = \"A snapshot testing library for rust\"\ntest = { cmd = \"cargo insta --version\", expected = \"cargo-insta {{version}}\" }\n"
  },
  {
    "path": "registry/cargo-make.toml",
    "content": "backends = [\n  \"aqua:sagiegurari/cargo-make\",\n  \"asdf:mise-plugins/asdf-cargo-make\",\n  \"cargo:cargo-make\",\n]\ndescription = \"Rust task runner and build tool\"\ntest = { cmd = \"makers --version\", expected = \"cargo-make {{version}}\" }\n"
  },
  {
    "path": "registry/carp.toml",
    "content": "description = \"Carp Language\"\ntest = { cmd = \"which carp\", expected = \"\" } # hangs in non-interactive shells\n\n[[backends]]\nfull = \"github:carp-lang/Carp\"\n\n[backends.options]\nexe = \"carp\"\n\n[[backends]]\nfull = \"asdf:susurri/asdf-carp\"\n"
  },
  {
    "path": "registry/carthage.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-carthage\",\n  \"asdf:mise-plugins/mise-carthage\",\n]\ndescription = \"A simple, decentralized dependency manager for Cocoa\"\nos = [\"macos\"]\n"
  },
  {
    "path": "registry/ccache.toml",
    "content": "backends = [\"github:ccache/ccache\", \"asdf:asdf-community/asdf-ccache\"]\ndescription = \"ccache – a fast compiler cache\"\ntest = { cmd = \"ccache --version\", expected = \"ccache version {{version}}\" }\n"
  },
  {
    "path": "registry/certstrap.toml",
    "content": "backends = [\"github:square/certstrap\", \"asdf:carnei-ro/asdf-certstrap\"]\ndescription = \"Tools to bootstrap CAs, certificate requests, and signed certificates\"\ntest = { cmd = \"certstrap --version\", expected = \"certstrap version {{version}}\" }\n"
  },
  {
    "path": "registry/cf.toml",
    "content": "backends = [\"github:cloudfoundry/cli\", \"asdf:mise-plugins/mise-cf\"]\ndescription = \"The official command line client for Cloud Foundry\"\ntest = { cmd = \"cf version\", expected = \"cf version {{version}}\" }\n"
  },
  {
    "path": "registry/cfn-lint.toml",
    "content": "backends = [\"pipx:cfn-lint\"]\ndescription = \"Checks CloudFormation templates for practices and behaviour that could potentially be improved\"\n# test = [\"cfn-lint --version\", \"cfn-lint {{version}}\"] # disabled: failing in CI\n"
  },
  {
    "path": "registry/cfssl.toml",
    "content": "backends = [\"aqua:cloudflare/cfssl/cfssl\", \"asdf:mathew-fleisch/asdf-cfssl\"]\ndescription = \"CFSSL: Cloudflare's PKI and TLS toolkit\"\n"
  },
  {
    "path": "registry/cfssljson.toml",
    "content": "backends = [\"aqua:cloudflare/cfssl/cfssljson\"]\ndescription = \"cfssljson: Takes the JSON output from Cloudflare's cfssl and multirootca programs and writes certificates, keys, CSRs, and bundles to disk.\"\ntest = { cmd = \"cfssljson -version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/chamber.toml",
    "content": "backends = [\"aqua:segmentio/chamber\", \"asdf:mintel/asdf-chamber\"]\ndescription = \"CLI for managing secrets\"\ntest = { cmd = \"chamber version\", expected = \"chamber v{{version}}\" }\n"
  },
  {
    "path": "registry/changie.toml",
    "content": "backends = [\"aqua:miniscruff/changie\", \"asdf:pdemagny/asdf-changie\"]\ndescription = \"Automated changelog tool for preparing releases with lots of customization options\"\ntest = { cmd = \"changie --version\", expected = \"changie version v{{version}}\" }\n"
  },
  {
    "path": "registry/cheat.toml",
    "content": "backends = [\"aqua:cheat/cheat\", \"asdf:jmoratilla/asdf-cheat-plugin\"]\ndescription = \"cheat allows you to create and view interactive cheatsheets on the command-line. It was designed to help remind *nix system administrators of options for commands that they use frequently, but not frequently enough to remember\"\n"
  },
  {
    "path": "registry/checkmake.toml",
    "content": "backends = [\"aqua:mrtazz/checkmake\"]\ndescription = \"experimental linter/analyzer for Makefiles\"\ntest = { cmd = \"checkmake --version\", expected = \"checkmake v{{version}}\" }\n"
  },
  {
    "path": "registry/checkov.toml",
    "content": "backends = [\"aqua:bridgecrewio/checkov\", \"asdf:bosmak/asdf-checkov\"]\ndescription = \"Prevent cloud misconfigurations and find vulnerabilities during build-time in infrastructure as code, container images and open source packages with Checkov by Bridgecrew\"\ntest = { cmd = \"checkov -v\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/chezmoi.toml",
    "content": "backends = [\"aqua:twpayne/chezmoi\", \"asdf:joke/asdf-chezmoi\"]\ndescription = \"Manage your dotfiles across multiple diverse machines, securely\"\ntest = { cmd = \"chezmoi --version\", expected = \"chezmoi version v{{version}}\" }\n"
  },
  {
    "path": "registry/chezscheme.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-chezscheme\",\n  \"asdf:mise-plugins/mise-chezscheme\",\n]\ndescription = \"Chez Scheme is both a programming language and an implementation of that language, with supporting tools and documentation\"\n"
  },
  {
    "path": "registry/chicken.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-chicken\"]\ndescription = \"CHICKEN is a compiler for the Scheme programming language\"\nos = [\"linux\", \"macos\", \"freebsd\", \"openbsd\"]\ntest = { cmd = \"csi -version\", expected = \"Version\" }\n"
  },
  {
    "path": "registry/chisel.toml",
    "content": "backends = [\n  \"aqua:jpillora/chisel\",\n  \"go:github.com/jpillora/chisel\",\n  \"asdf:lwiechec/asdf-chisel\",\n]\ndescription = \"A fast TCP/UDP tunnel over HTTP\"\ntest = { cmd = \"chisel --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/choose.toml",
    "content": "backends = [\n  \"aqua:theryangeary/choose\",\n  \"cargo:choose\",\n  \"asdf:carbonteq/asdf-choose\",\n]\ndescription = \"A human-friendly and fast alternative to cut (and sometimes awk)\"\ntest = { cmd = \"choose --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/chromedriver.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-chromedriver\",\n  \"asdf:mise-plugins/mise-chromedriver\",\n]\ndescription = \"ChromeDriver is a standalone server that implements the W3C WebDriver and WebDriver BiDi standards\"\ntest = { cmd = \"chromedriver --version\", expected = \"ChromeDriver {{version}}\" }\n"
  },
  {
    "path": "registry/cidr-merger.toml",
    "content": "backends = [\"github:zhanhb/cidr-merger\", \"asdf:ORCID/asdf-cidr-merger\"]\ndescription = \"A simple command line tool to merge ip/ip cidr/ip range, supports IPv4/IPv6\"\ntest = { cmd = \"cidr-merger --version 2>&1\", expected = \"cidr merger {{version}}\" }\n"
  },
  {
    "path": "registry/cidrchk.toml",
    "content": "backends = [\"github:mhausenblas/cidrchk\", \"asdf:ORCID/asdf-cidrchk\"]\ndescription = \"CLI tool for CIDR range operations (check, generate)\"\ntest = { cmd = \"cidrchk --version\", expected = \"{{version}},\" }\n"
  },
  {
    "path": "registry/cilium-cli.toml",
    "content": "backends = [\"aqua:cilium/cilium-cli\", \"asdf:carnei-ro/asdf-cilium-cli\"]\ndescription = \"CLI to install, manage & troubleshoot Kubernetes clusters running Cilium\"\ntest = { cmd = \"cilium version\", expected = \"cilium-cli: v{{version}}\" }\n"
  },
  {
    "path": "registry/cilium-hubble.toml",
    "content": "backends = [\"github:cilium/hubble\", \"asdf:NitriKx/asdf-cilium-hubble\"]\ndescription = \"Hubble - Network, Service & Security Observability for Kubernetes using eBPF\"\ntest = { cmd = \"hubble --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/circleci.toml",
    "content": "aliases = [\"circleci-cli\"]\nbackends = [\"aqua:CircleCI-Public/circleci-cli\", \"asdf:ucpr/asdf-circleci-cli\"]\ndescription = \"Use CircleCI from the command line\"\ntest = { cmd = \"circleci version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/clang-format.toml",
    "content": "backends = [\"conda:clang-format\", \"asdf:mise-plugins/mise-llvm\"]\ndescription = \"format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code\"\ntest = { cmd = \"clang-format --version\", expected = \"clang-format version\" }\n"
  },
  {
    "path": "registry/clang.toml",
    "content": "backends = [\n  \"conda:clang\",\n  \"asdf:mise-plugins/mise-llvm\",\n  \"vfox:mise-plugins/vfox-clang\",\n]\ndescription = \"Clang is an 'LLVM native' C/C++/Objective-C compiler, which aims to deliver amazingly fast compiles, extremely useful error and warning messages and to provide a platform for building great source level tools\"\n"
  },
  {
    "path": "registry/clarinet.toml",
    "content": "backends = [\"github:hirosystems/clarinet\", \"asdf:alexgo-io/asdf-clarinet\"]\ndescription = \"Write, test and deploy high-quality smart contracts to the Stacks blockchain and Bitcoin\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"clarinet --version\", expected = \"clarinet {{version}}\" }\n"
  },
  {
    "path": "registry/claude-powerline.toml",
    "content": "backends = [\"npm:@owloops/claude-powerline\"]\ndescription = \"Beautiful vim-style powerline statusline for Claude Code\"\ntest = { cmd = \"claude-powerline --help\", expected = \"claude-powerline [options]\" }\n"
  },
  {
    "path": "registry/claude-squad.toml",
    "content": "backends = [\"aqua:smtg-ai/claude-squad\"]\ndescription = \"Manage multiple AI agents like Claude Code, Aider, Codex, and Amp. 10x your productivity\"\ntest = { cmd = \"claude-squad version\", expected = \"\"\"\nclaude-squad version {{version}}\nhttps://github.com/smtg-ai/claude-squad/releases/tag/v{{version}}\"\"\" }\n"
  },
  {
    "path": "registry/claude.toml",
    "content": "aliases = [\"claude-code\"]\ndescription = \"Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows -- all through natural language commands\"\nos = [\"linux\", \"macos\", \"windows\"]\ntest = { cmd = \"claude --version\", expected = \"{{version}} (Claude Code)\" }\n\n[[backends]]\nfull = \"aqua:anthropics/claude-code\"\nplatforms = [\"linux\", \"macos\"]\n\n[[backends]]\nfull = \"http:claude\"\n\n[backends.options]\nbin = \"claude\"\n# NOTE: upstream `/stable` is often stale; prefer `/latest` for correct `mise latest claude`\n# See: https://github.com/jdx/mise/discussions/7329\nurl = 'https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/{{ version }}/{{ os(macos=\"darwin\") }}-{{ arch() }}/claude'\nversion_list_url = \"https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest\"\n\n[backends.options.platforms.windows-x64]\nbin = \"claude.exe\"\nurl = \"https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/{{ version }}/win32-x64/claude.exe\"\n\n[[backends]]\nfull = \"npm:@anthropic-ai/claude-code\"\n"
  },
  {
    "path": "registry/cli53.toml",
    "content": "backends = [\"aqua:barnybug/cli53\"]\ndescription = \"Command line tool for Amazon Route 53\"\ntest = { cmd = \"cli53 --version\", expected = \"cli53 version {{version}}\" }\n"
  },
  {
    "path": "registry/clickhouse.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-clickhouse\",\n  \"asdf:mise-plugins/mise-clickhouse\",\n]\ndescription = \"ClickHouse® is a high-performance, column-oriented SQL database management system (DBMS) for online analytical processing (OLAP)\"\ntest = { cmd = \"clickhouse --version\", expected = \"ClickHouse local version {{version | trim_end_matches(pat='-lts') | trim_end_matches(pat='-stable')}}\" }\n"
  },
  {
    "path": "registry/clj-kondo.toml",
    "content": "backends = [\"github:clj-kondo/clj-kondo\", \"asdf:rynkowsg/asdf-clj-kondo\"]\ndescription = \"Static analyzer and linter for Clojure code that sparks joy\"\ntest = { cmd = \"clj-kondo --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/cljstyle.toml",
    "content": "backends = [\"github:greglook/cljstyle\", \"asdf:abogoyavlensky/asdf-cljstyle\"]\ndescription = \"A tool for formatting Clojure code\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"cljstyle version\", expected = \"mvxcvi/cljstyle {{version}}\" }\n"
  },
  {
    "path": "registry/clojure.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-clojure\"]\ndescription = \"The Clojure Programming Language\"\n"
  },
  {
    "path": "registry/cloud-sql-proxy.toml",
    "content": "backends = [\n  \"aqua:GoogleCloudPlatform/cloud-sql-proxy\",\n  \"asdf:pbr0ck3r/asdf-cloud-sql-proxy\",\n]\ndescription = \"A utility for connecting securely to your Cloud SQL instances\"\n"
  },
  {
    "path": "registry/cloudflared.toml",
    "content": "backends = [\"aqua:cloudflare/cloudflared\", \"asdf:threkk/asdf-cloudflared\"]\ndescription = \"cloudflared connects your machine or user identity to Cloudflare's global network\"\ntest = { cmd = \"cloudflared -v\", expected = \"cloudflared version {{version}}\" }\n"
  },
  {
    "path": "registry/clusterawsadm.toml",
    "content": "description = \"clusterawsadm provides helpers for bootstrapping Kubernetes Cluster API Provider AWS\"\ntest = { cmd = \"cluster-api-provider-aws version\", expected = \"clusterawsadm version:\" }\n\n[[backends]]\nfull = \"github:kubernetes-sigs/cluster-api-provider-aws\"\n\n[backends.options]\nasset_pattern = \"clusterawsadm-{darwin_os}-{amd64_arch}\"\nbin = \"cluster-api-provider-aws\"\n\n[[backends]]\nfull = \"asdf:kahun/asdf-clusterawsadm\"\n"
  },
  {
    "path": "registry/clusterctl.toml",
    "content": "backends = [\n  \"aqua:kubernetes-sigs/cluster-api\",\n  \"asdf:pfnet-research/asdf-clusterctl\",\n]\ndescription = \"Home for Cluster API, a subproject of sig-cluster-lifecycle\"\ntest = { cmd = \"clusterctl version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/cmake.toml",
    "content": "backends = [\n  \"aqua:Kitware/CMake\",\n  \"asdf:mise-plugins/mise-cmake\",\n  \"vfox:mise-plugins/vfox-cmake\",\n]\ndescription = \"CMake is a tool to manage building of source code. Originally, CMake was designed as a generator for various dialects of Makefile, today CMake generates modern buildsystems such as Ninja as well as project files for IDEs such as Visual Studio and Xcode\"\ntest = { cmd = \"cmake --version\", expected = \"\"\"\ncmake version {{version}}\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\"\"\" }\n"
  },
  {
    "path": "registry/cmctl.toml",
    "content": "backends = [\"aqua:cert-manager/cmctl\", \"asdf:asdf-community/asdf-cmctl\"]\ndescription = \"the command line utility that makes cert-manager'ing easier\"\n"
  },
  {
    "path": "registry/cmdx.toml",
    "content": "backends = [\"aqua:suzuki-shunsuke/cmdx\"]\ndescription = \"Task runner. It provides useful help messages and supports interactive prompts and validation of arguments\"\ntest = { cmd = \"cmdx version\", expected = \"cmdx version {{version}}\" }\n"
  },
  {
    "path": "registry/cockroach.toml",
    "content": "backends = [\"aqua:cockroachdb/cockroach\", \"asdf:salasrod/asdf-cockroach\"]\ndescription = \"A distributed SQL database designed for speed, scale, and survival\"\ntest = { cmd = \"cockroach version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/cocoapods.toml",
    "content": "backends = [\"gem:cocoapods\"]\ndescription = \"CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects\"\nos = [\"macos\"]\ntest = { cmd = \"pod --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/cocogitto.toml",
    "content": "backends = [\"aqua:cocogitto/cocogitto\"]\ndescription = \"The Conventional Commits toolbox\"\ntest = { cmd = \"cog --version\", expected = \"cog {{version}}\" }\n"
  },
  {
    "path": "registry/code.toml",
    "content": "backends = [\"aqua:just-every/code\", \"npm:@just-every/code\"]\ndescription = \"Fast, effective, mind-blowing, coding CLI. Browser integration, multi-agents, theming, and reasoning control. Orchestrate agents from OpenAI, Claude, Gemini or any provider.\"\ntest = { cmd = \"code --version\", expected = \"code {{version}}\" }\n"
  },
  {
    "path": "registry/codebuff.toml",
    "content": "backends = [\"npm:codebuff\"]\ndescription = \"Codebuff is a CLI tool that writes code for you\"\n"
  },
  {
    "path": "registry/codefresh.toml",
    "content": "description = \"The Codefresh CLI provides a full and flexible interface to interact with Codefresh\"\n\n[[backends]]\nfull = \"github:codefresh-io/cli\"\n\n[backends.options]\nexe = \"codefresh\"\n\n[[backends]]\nfull = \"asdf:gurukulkarni/asdf-codefresh\"\n"
  },
  {
    "path": "registry/codeql.toml",
    "content": "description = \"CodeQL CLI\"\ntest = { cmd = \"codeql --version\", expected = \"CodeQL command-line toolchain release {{version}}\" }\n\n[[backends]]\nfull = \"github:github/codeql-cli-binaries\"\n\n[backends.options]\nbin_path = \"codeql\"\n\n[backends.options.platforms.macos-x64]\nasset_pattern = \"codeql-osx64.zip\"\n\n[backends.options.platforms.macos-arm64]\nasset_pattern = \"codeql-osx64.zip\"\n\n[backends.options.platforms.linux-x64]\nasset_pattern = \"codeql-linux64.zip\"\n\n[backends.options.platforms.windows-x64]\nasset_pattern = \"codeql-win64.zip\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-codeql\"\n"
  },
  {
    "path": "registry/coder.toml",
    "content": "backends = [\"aqua:coder/coder\", \"asdf:mise-plugins/asdf-coder\"]\ndescription = \"Provision remote development environments via Terraform\"\n"
  },
  {
    "path": "registry/codex.toml",
    "content": "backends = [\"aqua:openai/codex\", \"npm:@openai/codex\"]\ndescription = \"Lightweight coding agent that runs in your terminal\"\ntest = { cmd = \"codex --version\", expected = \"codex-cli {{version}}\" }\n"
  },
  {
    "path": "registry/colima.toml",
    "content": "backends = [\"aqua:abiosoft/colima\", \"asdf:CrouchingMuppet/asdf-colima\"]\ndescription = \"Container runtimes on macOS (and Linux) with minimal setup\"\ntest = { cmd = \"colima --version\", expected = \"colima version v{{version}}\" }\n"
  },
  {
    "path": "registry/committed.toml",
    "content": "backends = [\"aqua:crate-ci/committed\"]\ndescription = \"Nitpicking commit history since beabf39\"\n"
  },
  {
    "path": "registry/communique.toml",
    "content": "backends = [\"github:jdx/communique\"]\ndescription = \"Editorialized release notes powered by AI\"\ntest = { cmd = \"communique --version\", expected = \"communique {{version}}\" }\n"
  },
  {
    "path": "registry/conan.toml",
    "content": "backends = [\"pipx:conan\", \"asdf:mise-plugins/mise-pyapp\"]\ndescription = \"Decentralized, open-source (MIT), C/C++ package manager\"\ntest = { cmd = \"conan --version\", expected = \"Conan version {{version}}\" }\n"
  },
  {
    "path": "registry/concourse.toml",
    "content": "backends = [\n  \"aqua:concourse/concourse/concourse\",\n  \"asdf:mattysweeps/asdf-concourse\",\n]\ndescription = \"Concourse is a container-based automation system written in Go\"\n"
  },
  {
    "path": "registry/conduit.toml",
    "content": "backends = [\"github:ConduitIO/conduit\", \"asdf:gmcabrita/asdf-conduit\"]\ndescription = \"Conduit streams data between data stores. Kafka Connect replacement. No JVM required\"\ntest = { cmd = \"conduit --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/conform.toml",
    "content": "backends = [\"aqua:siderolabs/conform\", \"asdf:skyzyx/asdf-conform\"]\ndescription = \"Policy enforcement for your pipelines\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"conform version\", expected = \"conform version v{{version}}\" }\n"
  },
  {
    "path": "registry/conftest.toml",
    "content": "backends = [\"aqua:open-policy-agent/conftest\", \"asdf:looztra/asdf-conftest\"]\ndescription = \"Write tests against structured configuration data using the Open Policy Agent Rego query language\"\n"
  },
  {
    "path": "registry/consul.toml",
    "content": "backends = [\"aqua:hashicorp/consul\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure\"\n"
  },
  {
    "path": "registry/container-structure-test.toml",
    "content": "backends = [\n  \"aqua:GoogleContainerTools/container-structure-test\",\n  \"asdf:FeryET/asdf-container-structure-test\",\n]\ndescription = \"validate the structure of your container images\"\n"
  },
  {
    "path": "registry/container-use.toml",
    "content": "backends = [\"aqua:dagger/container-use\"]\ndescription = \"Development environments for coding agents. Enable multiple agents to work safely and independently with your preferred stack.\"\ntest = { cmd = \"container-use --version\", expected = \"container-use version {{version}}\" }\n"
  },
  {
    "path": "registry/container.toml",
    "content": "backends = [\"aqua:apple/container\"]\ndescription = \"A tool for creating and running Linux containers using lightweight virtual machines on a Mac.\"\nos = [\"macos\"]\ntest = { cmd = \"container --version\", expected = \"container CLI version {{version}}\" }\n"
  },
  {
    "path": "registry/cookiecutter.toml",
    "content": "backends = [\"pipx:cookiecutter\", \"asdf:shawon-crosen/asdf-cookiecutter\"]\ndescription = \"Create projects swiftly from cookiecutters (project templates) with this command-line utility. Ideal for generating Python package projects and more\"\n"
  },
  {
    "path": "registry/copier.toml",
    "content": "backends = [\"pipx:copier\", \"asdf:looztra/asdf-copier\"]\ndescription = \"A library and CLI app for rendering project templates\"\ntest = { cmd = \"copier --version\", expected = \"copier {{version}}\" }\n"
  },
  {
    "path": "registry/copper.toml",
    "content": "backends = [\"aqua:cloud66-oss/copper\", \"asdf:vladlosev/asdf-copper\"]\ndescription = \"A configuration file validator for Kubernetes\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"copper version\", expected = \"\" }\n"
  },
  {
    "path": "registry/coredns.toml",
    "content": "backends = [\"github:coredns/coredns\", \"asdf:s3than/asdf-coredns\"]\ndescription = \"CoreDNS: DNS and Service Discovery\"\ntest = { cmd = \"coredns --version\", expected = \"CoreDNS-{{version}}\" }\n"
  },
  {
    "path": "registry/coreutils.toml",
    "content": "backends = [\"aqua:uutils/coreutils\"]\ndescription = \"Cross-platform Rust rewrite of the GNU coreutils\"\ntest = { cmd = \"coreutils\", expected = \"coreutils {{version}}\" }\n"
  },
  {
    "path": "registry/cosign.toml",
    "content": "backends = [\"aqua:sigstore/cosign\", \"asdf:https://gitlab.com/wt0f/asdf-cosign\"]\ndescription = \"Code signing and transparency for containers and binaries\"\ntest = { cmd = \"cosign version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/coursier.toml",
    "content": "description = \"Pure Scala Artifact Fetching\"\n\n[[backends]]\nfull = \"github:coursier/coursier\"\n\n[backends.options]\nexe = \"cs\"\n\n[[backends]]\nfull = \"asdf:jiahuili430/asdf-coursier\"\n"
  },
  {
    "path": "registry/cowsay.toml",
    "content": "backends = [\"npm:cowsay\"]\ndescription = \"cowsay is a configurable talking cow, originally written in Perl by Tony Monroe\"\n"
  },
  {
    "path": "registry/cpz.toml",
    "content": "backends = [\"aqua:SUPERCILEX/fuc/cpz\"]\ndescription = \"A zippy alternative to cp, a tool to copy files and directories\"\ntest = { cmd = \"cpz --version\", expected = \"cpz {{version}}\" }\n"
  },
  {
    "path": "registry/crane.toml",
    "content": "backends = [\"aqua:google/go-containerregistry\", \"asdf:dmpe/asdf-crane\"]\ndescription = \"Go library and CLIs for working with container registries\"\ntest = { cmd = \"crane version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/credhub.toml",
    "content": "backends = [\n  \"aqua:cloudfoundry/credhub-cli\",\n  \"asdf:mise-plugins/tanzu-plug-in-for-asdf\",\n]\ndescription = \"CredHub CLI provides a command line interface to interact with CredHub servers\"\ntest = { cmd = \"credhub --version\", expected = \"CLI Version: {{version}}\" }\n"
  },
  {
    "path": "registry/crictl.toml",
    "content": "backends = [\n  \"aqua:kubernetes-sigs/cri-tools/crictl\",\n  \"asdf:FairwindsOps/asdf-crictl\",\n]\ndescription = \"crictl is a command-line interface for CRI-compatible container runtimes. You can use it to inspect and debug container runtimes and applications on a Kubernetes node\"\n"
  },
  {
    "path": "registry/croc.toml",
    "content": "backends = [\"aqua:schollz/croc\"]\ndescription = \"Easily and securely send things from one computer to another 🐊 📦\"\ntest = { cmd = \"croc --version\", expected = \"croc version v{{version}}\" }\n"
  },
  {
    "path": "registry/crossplane.toml",
    "content": "aliases = [\"crossplane-cli\"]\nbackends = [\"aqua:crossplane/crossplane\", \"asdf:joke/asdf-crossplane-cli\"]\ndescription = \"The Crossplane CLI extends kubectl with functionality to build, push, and install Crossplane packages\"\n"
  },
  {
    "path": "registry/crush.toml",
    "content": "backends = [\"aqua:charmbracelet/crush\"]\ndescription = \"The glamourous AI coding agent for your favourite terminal\"\ntest = { cmd = \"crush --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/crystal.toml",
    "content": "backends = [\n  \"github:crystal-lang/crystal\",\n  \"asdf:mise-plugins/mise-crystal\",\n  \"vfox:mise-plugins/vfox-crystal\",\n]\ndescription = \"Crystal: A language for humans and computers\"\n"
  },
  {
    "path": "registry/cspell.toml",
    "content": "backends = [\"npm:cspell\"]\ndescription = \"A Spell Checker for Code!\"\ntest = { cmd = \"cspell --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/ctlptl.toml",
    "content": "backends = [\"aqua:tilt-dev/ctlptl\", \"asdf:ezcater/asdf-ctlptl\"]\ndescription = \"Making local Kubernetes clusters fun and easy to set up\"\n"
  },
  {
    "path": "registry/ctop.toml",
    "content": "backends = [\"aqua:bcicen/ctop\", \"asdf:NeoHsu/asdf-ctop\"]\ndescription = \"Top-like interface for container metrics\"\ntest = { cmd = \"ctop -v\", expected = \"ctop version {{version}}\" }\n"
  },
  {
    "path": "registry/cue.toml",
    "content": "backends = [\"aqua:cue-lang/cue\", \"asdf:asdf-community/asdf-cue\"]\ndescription = \"The home of the CUE language! Validate and define text-based and dynamic configuration\"\n"
  },
  {
    "path": "registry/curlie.toml",
    "content": "backends = [\"aqua:rs/curlie\"]\ndescription = \"The power of curl, the ease of use of httpie\"\ntest = { cmd = \"curlie version\", expected = \"curlie {{version}}\" }\n"
  },
  {
    "path": "registry/cyclonedx.toml",
    "content": "backends = [\"aqua:CycloneDX/cyclonedx-cli\", \"asdf:xeedio/asdf-cyclonedx\"]\ndescription = \"CycloneDX CLI tool for SBOM analysis, merging, diffs and format conversions\"\n# TODO: re-enable test when aqua-registry is updated to use gnu instead of musl\n# test = [\"cyclonedx --version\", \"{{version}}\"]\n"
  },
  {
    "path": "registry/d2.toml",
    "content": "description = \"Modern diagram scripting language that turns text to diagrams\"\ntest = { cmd = \"d2 --version\", expected = \"v{{version}}\" }\n\n[[backends]]\nfull = \"aqua:terrastruct/d2\"\n\n[[backends]]\nfull = \"github:terrastruct/d2\"\n\n[backends.options]\nstrip_components = \"1\"\n"
  },
  {
    "path": "registry/dagger.toml",
    "content": "backends = [\"aqua:dagger/dagger\", \"asdf:virtualstaticvoid/asdf-dagger\"]\ndescription = \"A portable devkit for CI/CD pipelines\"\n"
  },
  {
    "path": "registry/dagu.toml",
    "content": "backends = [\"aqua:dagu-org/dagu\"]\ndescription = \"Yet another cron alternative with a Web UI, but with much more capabilities. It aims to solve greater problems\"\ntest = { cmd = \"dagu version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/danger-js.toml",
    "content": "backends = [\"npm:danger\"]\ndescription = \"Danger runs during your CI process, and gives teams the chance to automate common code review chores\"\n"
  },
  {
    "path": "registry/danger-swift.toml",
    "content": "backends = [\"spm:danger/swift\"]\ndescription = \"Stop saying 'you forgot to …' in code review\"\n"
  },
  {
    "path": "registry/dapr.toml",
    "content": "backends = [\"aqua:dapr/cli\", \"asdf:asdf-community/asdf-dapr-cli\"]\ndescription = \"Command-line tools for Dapr\"\ntest = { cmd = \"dapr --version\", expected = \"CLI version: {{version}}\" }\n"
  },
  {
    "path": "registry/dart.toml",
    "content": "description = \"An approachable, portable, and productive language for high-quality apps on any platform\"\n\n[[backends]]\nfull = \"http:dart\"\n\n[backends.options]\nurl = \"https://storage.googleapis.com/dart-archive/channels/stable/release/{{ version }}/sdk/dartsdk-{{ os() }}-{{ arch() }}-release.zip\"\nversion_expr = 'fromJSON(body).prefixes | filter({ # matches \"^channels/stable/release/(\\\\d+\\\\.\\\\d+\\\\.\\\\d+)/$\" }) | map({split(#, \"/\")[3]}) | sortVersions()'\nversion_list_url = \"https://storage.googleapis.com/storage/v1/b/dart-archive/o?prefix=channels/stable/release/&delimiter=/\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-dart\"\n\n[[backends]]\nfull = \"vfox:mise-plugins/vfox-dart\"\n"
  },
  {
    "path": "registry/dasel.toml",
    "content": "backends = [\"aqua:TomWright/dasel\", \"asdf:asdf-community/asdf-dasel\"]\ndescription = \"Select, put and delete data from JSON, TOML, YAML, XML and CSV files with a single tool. Supports conversion between formats and can be used as a Go package\"\n"
  },
  {
    "path": "registry/databricks-cli.toml",
    "content": "description = \"Databricks CLI\"\ntest = { cmd = \"databricks --version\", expected = \"Databricks CLI v{{version}}\" }\n\n[[backends]]\nfull = \"github:databricks/cli\"\n\n[backends.options]\nexe = \"databricks\"\n"
  },
  {
    "path": "registry/datree.toml",
    "content": "backends = [\"aqua:datreeio/datree\", \"asdf:lukeab/asdf-datree\"]\ndescription = \"Prevent Kubernetes misconfigurations from reaching production (again  )! From code to cloud, Datree provides an E2E policy enforcement solution to run automatic checks for rule violations. See our docs: https://hub.datree.io\"\n"
  },
  {
    "path": "registry/daytona.toml",
    "content": "description = \"Daytona is a Secure and Elastic Infrastructure for Running AI-Generated Code\"\ntest = { cmd = \"daytona version\", expected = \"Daytona CLI version v{{version}}\" }\n\n[[backends]]\nfull = \"github:daytonaio/daytona\"\n\n[backends.options]\nasset_pattern = \"daytona-{{ os(macos='darwin') }}-{{ arch(x64='amd64') }}{% if os() == 'windows' %}.exe{% endif %}\"\nbin = \"daytona\"\n\n[backends.options.platforms.windows-x64]\nbin = \"daytona.exe\"\n\n[backends.options.platforms.windows-arm64]\nbin = \"daytona.exe\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-daytona\"\n"
  },
  {
    "path": "registry/dbmate.toml",
    "content": "backends = [\"aqua:amacneil/dbmate\", \"asdf:juusujanar/asdf-dbmate\"]\ndescription = \"A lightweight, framework-agnostic database migration tool\"\n"
  },
  {
    "path": "registry/deck.toml",
    "content": "backends = [\"aqua:Kong/deck\", \"asdf:nutellinoit/asdf-deck\"]\ndescription = \"decK: Configuration management and drift detection for Kong\"\n"
  },
  {
    "path": "registry/delta.toml",
    "content": "backends = [\n  \"aqua:dandavison/delta\",\n  \"asdf:andweeb/asdf-delta\",\n  \"cargo:git-delta\",\n]\ndescription = \"A syntax-highlighting pager for git, diff, and grep output\"\ntest = { cmd = \"delta --version\", expected = \"delta {{version}}\" }\n"
  },
  {
    "path": "registry/deno.toml",
    "content": "backends = [\"core:deno\"]\ndescription = \"A modern runtime for JavaScript and TypeScript (Builtin plugin)\"\n"
  },
  {
    "path": "registry/depot.toml",
    "content": "description = \"Depot CLI, build your Docker images in the cloud\"\ntest = { cmd = \"depot --version\", expected = \"depot version {{version}}\" }\n\n[[backends]]\nfull = \"github:depot/cli\"\n\n[backends.options]\nexe = \"depot\"\n\n[[backends]]\nfull = \"asdf:depot/asdf-depot\"\n"
  },
  {
    "path": "registry/desk.toml",
    "content": "backends = [\"aqua:jamesob/desk\", \"asdf:endorama/asdf-desk\"]\ndescription = \"A lightweight workspace manager for the shell\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"desk version\", expected = \"desk {{version}}\" }\n"
  },
  {
    "path": "registry/devcontainer-cli.toml",
    "content": "backends = [\"npm:@devcontainers/cli\"]\ndescription = \"CLI for creating and configuring dev containers from devcontainer.json\"\ntest = { cmd = \"devcontainer --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/devspace.toml",
    "content": "backends = [\"aqua:devspace-sh/devspace\", \"asdf:NeoHsu/asdf-devspace\"]\ndescription = \"DevSpace - The Fastest Developer Tool for Kubernetes  Automate your deployment workflow with DevSpace and develop software directly inside Kubernetes\"\n"
  },
  {
    "path": "registry/dhall.toml",
    "content": "backends = [\"aqua:dhall-lang/dhall-haskell\", \"asdf:mise-plugins/mise-dhall\"]\ndescription = \"Maintainable configuration files (haskell)\"\ntest = { cmd = \"dhall --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/diffoci.toml",
    "content": "backends = [\"aqua:reproducible-containers/diffoci\"]\ndescription = \"diff for Docker and OCI container images\"\ntest = { cmd = \"diffoci --version\", expected = \"diffoci version v{{version}}\" }\n"
  },
  {
    "path": "registry/difftastic.toml",
    "content": "backends = [\n  \"aqua:Wilfred/difftastic\",\n  \"asdf:volf52/asdf-difftastic\",\n  \"cargo:difftastic\",\n]\ndescription = \"a structural diff that understands syntax\"\ntest = { cmd = \"difft --version\", expected = \"Difftastic {{version}}\" }\n"
  },
  {
    "path": "registry/direnv.toml",
    "content": "backends = [\"aqua:direnv/direnv\", \"asdf:asdf-community/asdf-direnv\"]\ndescription = \"unclutter your .profile\"\n"
  },
  {
    "path": "registry/dive.toml",
    "content": "backends = [\"aqua:wagoodman/dive\", \"asdf:looztra/asdf-dive\"]\ndescription = \"A tool for exploring each layer in a docker image\"\ntest = { cmd = \"dive --version\", expected = \"dive {{version}}\" }\n"
  },
  {
    "path": "registry/djinni.toml",
    "content": "description = \"Command-line tool that generates gluecode from a djinni-IDL file\"\ntest = { cmd = \"djinni --version\", expected = \"djinni generator version {{version}}\" }\n\n[[backends]]\nfull = \"github:cross-language-cpp/djinni-generator\"\n\n[backends.options]\nasset_pattern = \"djinni\"\nbin = \"djinni\"\n\n[[backends]]\nfull = \"asdf:cross-language-cpp/asdf-djinni\"\n"
  },
  {
    "path": "registry/docker-cli.toml",
    "content": "backends = [\"aqua:docker/cli\"]\ndescription = \"Docker CE CLI\"\ntest = { cmd = \"docker --version | awk '{print $3}' | tr -d ','\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/docker-compose.toml",
    "content": "backends = [\"aqua:docker/compose\"]\ndescription = \"Define and run multi-container applications with Docker\"\ntest = { cmd = \"docker-cli-plugin-docker-compose --version\", expected = \"Docker Compose version\" }\n"
  },
  {
    "path": "registry/docker-slim.toml",
    "content": "backends = [\"aqua:mintoolkit/mint\", \"asdf:xataz/asdf-docker-slim\"]\ndescription = \"minT(oolkit): Mint awesome, secure and production ready containers just the way you need them! Don't change anything in your container image and minify it by up to 30x (and for compiled languages even more) making it secure too! (free and open source)\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"slim --version\", expected = \"\" } # prints out weird version of mint or something\n"
  },
  {
    "path": "registry/dockle.toml",
    "content": "backends = [\"aqua:goodwithtech/dockle\", \"asdf:mathew-fleisch/asdf-dockle\"]\ndescription = \"Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start\"\n"
  },
  {
    "path": "registry/doctl.toml",
    "content": "backends = [\"aqua:digitalocean/doctl\", \"asdf:maristgeek/asdf-doctl\"]\ndescription = \"The official command line interface for the DigitalOcean API\"\ntest = { cmd = \"doctl version\", expected = \"doctl version {{version}}\" }\n"
  },
  {
    "path": "registry/docuum.toml",
    "content": "backends = [\n  \"aqua:stepchowfun/docuum\",\n  \"cargo:docuum\",\n  \"asdf:bradym/asdf-docuum\",\n]\ndescription = \"Docuum performs least recently used (LRU) eviction of Docker images\"\ntest = { cmd = \"docuum --version\", expected = \"Docuum {{version}}\" }\n"
  },
  {
    "path": "registry/doggo.toml",
    "content": "backends = [\"aqua:mr-karan/doggo\"]\ndescription = \":dog: Command-line DNS Client for Humans. Written in Golang\"\ntest = { cmd = \"doggo --version | awk '{print $1}'\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/dome.toml",
    "content": "description = \"DOME is a framework for making 2D games using the Wren programming language which can be played across platforms\"\nos = [\"linux\", \"macos\", \"windows\"]\n\n[[backends]]\nfull = \"github:domeengine/dome\"\n\n[backends.options.platforms.macos-x64]\nasset_pattern = \"dome-v{{ version }}-macosx-all.zip\"\nbin_path = \"dome-macosx-all\"\n\n[backends.options.platforms.macos-arm64]\nasset_pattern = \"dome-v{{ version }}-macosx-all.zip\"\nbin_path = \"dome-macosx-all\"\n\n[backends.options.platforms.linux-x64]\nasset_pattern = \"dome-v{{ version }}-linux-x64.zip\"\nbin_path = \"dome-linux-x64\"\n\n[backends.options.platforms.windows-x64]\nasset_pattern = \"dome-v{{ version }}-windows-x64.zip\"\nbin_path = \"dome-windows-x64\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-dome\"\n"
  },
  {
    "path": "registry/doppler.toml",
    "content": "description = \"The official CLI for interacting with your Doppler secrets and configuration\"\ntest = { cmd = \"doppler --version\", expected = \"v{{version}}\" }\n\n[[backends]]\nfull = \"github:DopplerHQ/cli\"\n\n[backends.options]\nexe = \"doppler\"\n\n[[backends]]\nfull = \"asdf:takutakahashi/asdf-doppler\"\n"
  },
  {
    "path": "registry/dotenv-linter.toml",
    "content": "backends = [\n  \"aqua:dotenv-linter/dotenv-linter\",\n  \"asdf:wesleimp/asdf-dotenv-linter\",\n  \"cargo:dotenv-linter\",\n]\ndescription = \"Lightning-fast linter for .env files. Written in Rust\"\ntest = { cmd = \"dotenv-linter --version\", expected = \"dotenv-linter {{version}}\" }\n"
  },
  {
    "path": "registry/dotenvx.toml",
    "content": "backends = [\"aqua:dotenvx/dotenvx\"]\ndescription = \"a secure dotenv–from the creator of `dotenv`\"\ntest = { cmd = \"dotenvx --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/dotnet-core.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-dotnet-core\"]\ndescription = \".Net Core\"\n"
  },
  {
    "path": "registry/dotnet.toml",
    "content": "backends = [\n  \"core:dotnet\",\n  \"vfox:mise-plugins/vfox-dotnet\",\n  \"asdf:mise-plugins/mise-dotnet\",\n]\ndescription = \".NET SDK\"\n"
  },
  {
    "path": "registry/dotslash.toml",
    "content": "backends = [\"github:facebook/dotslash\"]\ndescription = \"Simplified executable deployment\"\ntest = { cmd = \"dotslash --version\", expected = \"DotSlash\" }\n"
  },
  {
    "path": "registry/dprint.toml",
    "content": "backends = [\"aqua:dprint/dprint\", \"asdf:asdf-community/asdf-dprint\"]\ndescription = \"Pluggable and configurable code formatting platform written in Rust\"\n"
  },
  {
    "path": "registry/draft.toml",
    "content": "backends = [\"aqua:Azure/draft\", \"asdf:kristoflemmens/asdf-draft\"]\ndescription = \"A day 0 tool for getting your app on k8s fast\"\n"
  },
  {
    "path": "registry/driftctl.toml",
    "content": "backends = [\"aqua:snyk/driftctl\", \"asdf:nlamirault/asdf-driftctl\"]\ndescription = \"Detect, track and alert on infrastructure drift\"\n"
  },
  {
    "path": "registry/drone.toml",
    "content": "backends = [\"aqua:harness/drone-cli\", \"asdf:virtualstaticvoid/asdf-drone\"]\ndescription = \"Command Line Tools for Drone CI\"\ntest = { cmd = \"drone --version\", expected = \"drone version {{version}}\" }\n"
  },
  {
    "path": "registry/dt.toml",
    "content": "backends = [\"aqua:so-dang-cool/dt\", \"asdf:so-dang-cool/asdf-dt\"]\ndescription = \"dt - duct tape for your unix pipes\"\n"
  },
  {
    "path": "registry/dtm.toml",
    "content": "description = \"DevStream: the open-source DevOps toolchain manager (DTM)\"\n\n[[backends]]\nfull = \"github:devstream-io/devstream\"\n\n[backends.options]\nexe = \"dtm\"\n\n[[backends]]\nfull = \"asdf:zhenyuanlau/asdf-dtm\"\n"
  },
  {
    "path": "registry/dua.toml",
    "content": "backends = [\"aqua:Byron/dua-cli\", \"cargo:dua-cli\"]\ndescription = \"View disk space usage and delete unwanted data, fast\"\ntest = { cmd = \"dua --version\", expected = \"dua {{version}}\" }\n"
  },
  {
    "path": "registry/duckdb.toml",
    "content": "backends = [\"aqua:duckdb/duckdb\"]\ndescription = \"DuckDB is an analytical in-process SQL database management system\"\ntest = { cmd = \"duckdb --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/duf.toml",
    "content": "backends = [\"aqua:muesli/duf\", \"asdf:NeoHsu/asdf-duf\"]\ndescription = \"Disk Usage/Free Utility - a better 'df' alternative\"\n"
  },
  {
    "path": "registry/dust.toml",
    "content": "backends = [\"aqua:bootandy/dust\", \"asdf:looztra/asdf-dust\", \"cargo:du-dust\"]\ndescription = \"A more intuitive version of du in rust\"\ntest = { cmd = \"dust --version\", expected = \"Dust {{version}}\" }\n"
  },
  {
    "path": "registry/dvc.toml",
    "content": "backends = [\"pipx:dvc\"]\ndescription = \"Data Versioning and ML Experiments\"\ntest = { cmd = \"dvc version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/dyff.toml",
    "content": "backends = [\"aqua:homeport/dyff\", \"asdf:https://gitlab.com/wt0f/asdf-dyff\"]\ndescription = \"A diff tool for YAML files, and sometimes JSON\"\n"
  },
  {
    "path": "registry/dynatrace-monaco.toml",
    "content": "description = \"Monaco—This is the native Dynatrace Configuration as Code tool. Monaco is also the recommended tool for migrating from Dynatrace Managed to Dynatrace SaaS\"\n\n[[backends]]\nfull = \"github:Dynatrace/dynatrace-configuration-as-code\"\n\n[backends.options]\nexe = \"monaco\"\n\n[[backends]]\nfull = \"asdf:nsaputro/asdf-monaco\"\n"
  },
  {
    "path": "registry/e1s.toml",
    "content": "backends = [\"aqua:keidarcy/e1s\", \"asdf:tbobm/asdf-e1s\"]\ndescription = \"E1S - Easily Manage AWS ECS Resources in Terminal(~k9s for ECS)\"\n"
  },
  {
    "path": "registry/earthly.toml",
    "content": "backends = [\"aqua:earthly/earthly\", \"asdf:YR-ZR0/asdf-earthly\"]\ndescription = \"Repeatable builds\"\n"
  },
  {
    "path": "registry/ecspresso.toml",
    "content": "backends = [\"aqua:kayac/ecspresso\", \"asdf:kayac/asdf-ecspresso\"]\ndescription = \"ecspresso is a deployment tool for Amazon ECS\"\n"
  },
  {
    "path": "registry/edit.toml",
    "content": "backends = [\"aqua:microsoft/edit\"]\ndescription = \"We all edit\"\n# test = [\"edit --version\", \"edit version {{version}}\"] # exits 1 on CI\n"
  },
  {
    "path": "registry/editorconfig-checker.toml",
    "content": "backends = [\n  \"aqua:editorconfig-checker/editorconfig-checker\",\n  \"asdf:gabitchov/asdf-editorconfig-checker\",\n]\ndescription = \"A tool to verify that your files are in harmony with your .editorconfig\"\ntest = { cmd = \"ec --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/ejson.toml",
    "content": "backends = [\"aqua:Shopify/ejson\", \"asdf:cipherstash/asdf-ejson\"]\ndescription = \"EJSON is a small library to manage encrypted secrets using asymmetric encryption\"\n"
  },
  {
    "path": "registry/eksctl.toml",
    "content": "backends = [\"aqua:eksctl-io/eksctl\", \"asdf:elementalvoid/asdf-eksctl\"]\ndescription = \"The official CLI for Amazon EKS\"\n"
  },
  {
    "path": "registry/elasticsearch.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-elasticsearch\"]\ndescription = \"Elasticsearch is an open source, distributed search and analytics engine built for speed, scale, and AI applications\"\n"
  },
  {
    "path": "registry/elixir-ls.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-elixir-ls\"]\ndescription = \"A frontend-independent IDE 'smartness' server for Elixir. Implements the 'Language Server Protocol' standard and provides debugger support via the 'Debug Adapter Protocol'\"\n"
  },
  {
    "path": "registry/elixir.toml",
    "content": "backends = [\"core:elixir\"]\ndepends = [\"erlang\"]\ndescription = \"Elixir is a dynamic, functional language for building scalable and maintainable applications\"\n"
  },
  {
    "path": "registry/elm.toml",
    "content": "description = \"Compiler for Elm, a functional language for reliable webapps\"\ntest = { cmd = \"elm --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:elm/compiler\"\n\n[backends.options]\nbin = \"elm\"\n\n[[backends]]\nfull = \"asdf:asdf-community/asdf-elm\"\n"
  },
  {
    "path": "registry/emsdk.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-emsdk\"]\ndescription = \"Emscripten is a complete compiler toolchain to WebAssembly, using LLVM, with a special focus on speed, size, and the Web platform\"\n"
  },
  {
    "path": "registry/entireio-cli.toml",
    "content": "aliases = [\"entire\"]\nbackends = [\n  \"aqua:entireio/cli\",\n  \"github:entireio/cli\",\n  \"go:github.com/entireio/cli/cmd/entire\",\n]\ndescription = \"Entire is a new developer platform that hooks into your git workflow to capture AI agent sessions on every push, unifying your code with its context and reasoning.\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"entire version\", expected = \"Entire CLI {{version}}\" }\n"
  },
  {
    "path": "registry/envcli.toml",
    "content": "backends = [\"aqua:EnvCLI/EnvCLI\", \"asdf:zekker6/asdf-envcli\"]\ndescription = \"Don't install Node, Go, ... locally - use containers you define within your project. If you have a new machine / other contributors you just have to install docker and envcli to get started\"\ntest = { cmd = \"envcli --version\", expected = \"EnvCLI version {{version}}\" }\n"
  },
  {
    "path": "registry/envsubst.toml",
    "content": "backends = [\"aqua:a8m/envsubst\", \"asdf:dex4er/asdf-envsubst\"]\ndescription = \"Environment variables substitution for Go\"\n"
  },
  {
    "path": "registry/erlang.toml",
    "content": "backends = [\"core:erlang\"]\ndescription = \"erlang\"\n"
  },
  {
    "path": "registry/esc.toml",
    "content": "backends = [\"aqua:pulumi/esc\", \"asdf:fxsalazar/asdf-esc\"]\ndescription = \"Pulumi ESC is a centralized, secure service for environments, secrets, and configuration management, optimized for multi-cloud infrastructures and applications\"\ntest = { cmd = \"esc version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/esy.toml",
    "content": "backends = [\"npm:esy\"]\ndescription = \"Easy package management for native Reason, OCaml and more\"\ntest = { cmd = \"esy --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/etcd.toml",
    "content": "backends = [\n  \"aqua:etcd-io/etcd\",\n  \"asdf:particledecay/asdf-etcd\",\n  \"vfox:mise-plugins/vfox-etcd\",\n]\ndescription = \"Distributed reliable key-value store for the most critical data of a distributed system\"\ntest = { cmd = \"etcd --version\", expected = \"etcd Version: {{version}}\" }\n"
  },
  {
    "path": "registry/evans.toml",
    "content": "backends = [\"aqua:ktr0731/evans\", \"asdf:goki90210/asdf-evans\"]\ndescription = \"Evans: more expressive universal gRPC client\"\n"
  },
  {
    "path": "registry/eza.toml",
    "content": "backends = [\n  { full = \"aqua:eza-community/eza\", platforms = [\n    \"linux\",\n  ] },\n  \"asdf:mise-plugins/mise-eza\",\n  \"cargo:eza\",\n]\ndescription = \"A modern, maintained replacement for ls\"\ntest = { cmd = \"eza --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/fastfetch.toml",
    "content": "backends = [\"aqua:fastfetch-cli/fastfetch\"]\ndescription = \"An actively maintained, feature-rich and performance oriented, neofetch like system information tool\"\ntest = { cmd = \"fastfetch --version | awk '{print $1, $2}'\", expected = \"fastfetch {{version}}\" }\n"
  },
  {
    "path": "registry/fd.toml",
    "content": "backends = [\n  \"aqua:sharkdp/fd\",\n  \"asdf:https://gitlab.com/wt0f/asdf-fd\",\n  \"cargo:fd-find\",\n]\ndescription = \"A simple, fast and user-friendly alternative to 'find'\"\ntest = { cmd = \"fd --version\", expected = \"fd {{version}}\" }\n"
  },
  {
    "path": "registry/ffmpeg.toml",
    "content": "backends = [\"conda:ffmpeg\", \"asdf:mise-plugins/mise-ffmpeg\"]\ndescription = \"A complete, cross-platform solution to record, convert and stream audio and video\"\ntest = { cmd = \"ffmpeg -version 2>&1\", expected = \"ffmpeg version\" }\n"
  },
  {
    "path": "registry/figma-export.toml",
    "content": "description = \"Command line utility to export colors, typography, icons and images from Figma to Xcode / Android Studio project\"\nos = [\"macos\"]\ntest = { cmd = \"figma-export --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:RedMadRobot/figma-export\"\n\n[backends.options]\nbin_path = \"Release\"\n\n[[backends]]\nfull = \"asdf:younke/asdf-figma-export\"\n"
  },
  {
    "path": "registry/fillin.toml",
    "content": "backends = [\"aqua:itchyny/fillin\", \"asdf:ouest/asdf-fillin\"]\ndescription = \"fill-in your command and execute\"\n"
  },
  {
    "path": "registry/firebase.toml",
    "content": "backends = [\n  \"aqua:firebase/firebase-tools\",\n  \"npm:firebase-tools\",\n  \"asdf:jthegedus/asdf-firebase\",\n]\ndescription = \"The Firebase Command Line Tools\"\n# 15.2.0 doesn't work. ref: https://github.com/firebase/firebase-tools/issues/9715\n# test = [\"firebase --version\", \"{{version}}\"]\n"
  },
  {
    "path": "registry/fission.toml",
    "content": "backends = [\"aqua:fission/fission\", \"asdf:virtualstaticvoid/asdf-fission\"]\ndescription = \"Fast and Simple Serverless Functions for Kubernetes\"\n"
  },
  {
    "path": "registry/flamingo.toml",
    "content": "backends = [\"github:flux-subsystem-argo/flamingo\", \"asdf:log2/asdf-flamingo\"]\ndescription = \"Flux Subsystem for Argo\"\ntest = { cmd = \"flamingo -v\", expected = \"flamingo version {{version}}\" }\n"
  },
  {
    "path": "registry/flarectl.toml",
    "content": "description = \"A CLI application for interacting with a Cloudflare account. Powered by cloudflare-go\"\n# test = [\"flarectl --version\", \"flarectl version {{version}}\"] # flarectl removed since v4\n\n[[backends]]\nfull = \"github:cloudflare/cloudflare-go\"\n\n[backends.options]\nexe = \"flarectl\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/asdf-flarectl\"\n"
  },
  {
    "path": "registry/flatc.toml",
    "content": "description = \"The main compiler for FlatBuffers is called flatc and is used to convert schema definitions into generated code files for a variety of languages\"\ntest = { cmd = \"flatc --version\", expected = \"flatc version\" }\n\n[[backends]]\nfull = \"github:google/flatbuffers\"\n\n[backends.options]\nexe = \"flatc\"\n\n[[backends]]\nfull = \"asdf:TheOpenDictionary/asdf-flatc\"\n"
  },
  {
    "path": "registry/flutter.toml",
    "content": "description = \"Flutter is an open source framework for building beautiful, natively compiled, multi-platform applications from a single codebase\"\n\n[[backends]]\nfull = \"http:flutter\"\n\n[backends.options]\nversion_expr = 'fromJSON(body).releases | filter({ #.channel == \"stable\" }) | map({ #.version }) | sortVersions()'\nversion_list_url = \"https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json\"\n# Default URL for macos/windows (.zip archives)\n# arch() maps: x64 -> \"\" (no suffix), arm64 -> \"_arm64\"\nurl = 'https://storage.googleapis.com/flutter_infra_release/releases/stable/{{ os() }}/flutter_{{ os() }}{{ arch(x64=\"\", arm64=\"_arm64\") }}_{{ version | replace(from=\"-stable\", to=\"\") }}-stable.zip'\n\n# Linux uses .tar.xz instead of .zip\n[backends.options.platforms.linux-x64]\nurl = 'https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_{{ version | replace(from=\"-stable\", to=\"\") }}-stable.tar.xz'\n\n# Note: Flutter doesn't officially provide linux-arm64 builds, but use correct format if they add support\n[backends.options.platforms.linux-arm64]\nurl = 'https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_arm64_{{ version | replace(from=\"-stable\", to=\"\") }}-stable.tar.xz'\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-flutter\"\n\n[[backends]]\nfull = \"vfox:mise-plugins/vfox-flutter\"\n"
  },
  {
    "path": "registry/fluttergen.toml",
    "content": "description = \"The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"fluttergen --version\", expected = \"v{{version}}\" }\n\n[[backends]]\nfull = \"github:FlutterGen/flutter_gen\"\n\n[backends.options]\nexe = \"fluttergen\"\n\n[[backends]]\nfull = \"asdf:FlutterGen/asdf-fluttergen\"\n"
  },
  {
    "path": "registry/flux2.toml",
    "content": "backends = [\"aqua:fluxcd/flux2\", \"asdf:tablexi/asdf-flux2\"]\ndescription = \"Open and extensible continuous delivery solution for Kubernetes. Powered by GitOps Toolkit\"\ntest = { cmd = \"flux --version\", expected = \"flux version {{version}}\" }\n"
  },
  {
    "path": "registry/fly.toml",
    "content": "backends = [\n  \"aqua:concourse/concourse/fly\",\n  \"asdf:mise-plugins/tanzu-plug-in-for-asdf\",\n]\ndescription = \"fly cli for concourse ci\"\n"
  },
  {
    "path": "registry/flyctl.toml",
    "content": "backends = [\"aqua:superfly/flyctl\", \"asdf:chessmango/asdf-flyctl\"]\ndescription = \"Command line tools for fly.io services\"\n"
  },
  {
    "path": "registry/flyway.toml",
    "content": "description = \"Flyway by Redgate • Database Migrations Made Easy\"\ntest = { cmd = \"flyway --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:flyway/flyway\"\n\n[backends.options]\nversion_prefix = \"flyway-\"\n\n[backends.options.platforms.macos-arm64]\nasset_pattern = \"flyway-commandline-{{ version }}-macosx-arm64.tar.gz\"\nbin_path = \"flyway-{{ version }}\"\n\n[backends.options.platforms.macos-x64]\nasset_pattern = \"flyway-commandline-{{ version }}-macosx-x64.tar.gz\"\nbin_path = \"flyway-{{ version }}\"\n\n[backends.options.platforms.linux-x64]\nasset_pattern = \"flyway-commandline-{{ version }}-linux-x64.tar.gz\"\nbin_path = \"flyway-{{ version }}\"\n\n[backends.options.platforms.windows-x64]\nasset_pattern = \"flyway-commandline-{{ version }}-windows-x64.zip\"\nbin_path = \"flyway-{{ version }}\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-flyway\"\n"
  },
  {
    "path": "registry/fnox.toml",
    "content": "backends = [\"github:jdx/fnox\"]\ndescription = \"Fort Knox for your secrets\"\ntest = { cmd = \"fnox --version\", expected = \"fnox {{version}}\" }\n"
  },
  {
    "path": "registry/foundry.toml",
    "content": "backends = [\"aqua:foundry-rs/foundry\"]\ndescription = \"Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust\"\ntest = { cmd = \"forge -V\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/func-e.toml",
    "content": "backends = [\"github:tetratelabs/func-e\", \"asdf:mise-plugins/mise-func-e\"]\ndescription = \"func-e (pronounced funky) makes running Envoy® easy\"\ntest = { cmd = \"func-e --version\", expected = \"func-e version {{version}}\" }\n"
  },
  {
    "path": "registry/furyctl.toml",
    "content": "backends = [\"github:sighupio/furyctl\", \"asdf:sighupio/asdf-furyctl\"]\ndescription = \"furyctl is the SIGHUP Distribution cluster lifecycle manager\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"furyctl version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/fx.toml",
    "content": "backends = [\"aqua:antonmedv/fx\", \"asdf:https://gitlab.com/wt0f/asdf-fx\"]\ndescription = \"Command-line tool and terminal JSON viewer\"\n"
  },
  {
    "path": "registry/fzf.toml",
    "content": "backends = [\"aqua:junegunn/fzf\", \"asdf:kompiro/asdf-fzf\"]\ndescription = \":cherry_blossom: A command-line fuzzy finder\"\ntest = { cmd = \"fzf --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/gallery-dl.toml",
    "content": "backends = [\"pipx:gallery-dl\"]\ndescription = \"Command-line program to download image galleries and collections from several image hosting sites\"\n"
  },
  {
    "path": "registry/gam.toml",
    "content": "description = \"command line management for Google Workspace\"\n\n[[backends]]\nfull = \"github:GAM-team/GAM\"\n\n[backends.options]\nexe = \"gam\"\n\n[[backends]]\nfull = \"asdf:offbyone/asdf-gam\"\n"
  },
  {
    "path": "registry/gator.toml",
    "content": "backends = [\"aqua:open-policy-agent/gatekeeper\", \"asdf:MxNxPx/asdf-gator\"]\ndescription = \"Gatekeeper - Policy Controller for Kubernetes\"\ntest = { cmd = \"gator --version\", expected = \"gator version v{{version}}\" }\n"
  },
  {
    "path": "registry/gcc-arm-none-eabi.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-gcc-arm-none-eabi\"]\ndescription = \"Arm GNU Toolchain\"\n"
  },
  {
    "path": "registry/gcloud.toml",
    "content": "# no python dependency - gcloud bundles its own Python since v352.0.0\nbackends = [\"vfox:mise-plugins/vfox-gcloud\", \"asdf:mise-plugins/mise-gcloud\"]\ndescription = \"GCloud CLI (Google Cloud SDK)\"\ntest = { cmd = \"gcloud version\", expected = \"Google Cloud SDK {{version}}\" }\n"
  },
  {
    "path": "registry/gdu.toml",
    "content": "backends = [\"aqua:dundee/gdu\"]\ndescription = \"Fast disk usage analyzer with console interface written in Go\"\n"
  },
  {
    "path": "registry/gemini-cli.toml",
    "content": "aliases = [\"gemini\"]\nbackends = [\"npm:@google/gemini-cli\"]\ndescription = \"Gemini CLI, a command-line AI workflow tool that connects to your tools, understands your code and accelerates your workflows\"\ntest = { cmd = \"gemini --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/getenvoy.toml",
    "content": "backends = [\n  \"github:tetratelabs-attic/getenvoy\",\n  \"asdf:mise-plugins/mise-getenvoy\",\n]\ndescription = \"historical CLI of getenvoy\"\ntest = { cmd = \"getenvoy --version\", expected = \"getenvoy version {{version}}\" }\n"
  },
  {
    "path": "registry/ggshield.toml",
    "content": "backends = [\"aqua:GitGuardian/ggshield\", \"pipx:ggshield\"]\ndescription = \"Detect and validate 500+ types of hardcoded secrets with advanced checks. Use it as a pre-commit hook, GitHub Action, or CLI for proactive secret detection and security.\"\ntest = { cmd = \"ggshield --version\", expected = \"ggshield, version {{version}}\" }\n"
  },
  {
    "path": "registry/ghalint.toml",
    "content": "backends = [\"aqua:suzuki-shunsuke/ghalint\"]\ndescription = \"GitHub Actions linter\"\ntest = { cmd = \"ghalint version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/ghc.toml",
    "content": "backends = [\"conda:ghc\", \"asdf:mise-plugins/mise-ghcup\"]\ndescription = \"The Glorious Glasgow Haskell Compiler.\"\ntest = { cmd = \"ghc --version\", expected = \"The Glorious Glasgow Haskell Compilation System, version {{version}}\" }\n"
  },
  {
    "path": "registry/ghcup.toml",
    "content": "backends = [\"aqua:haskell/ghcup-hs\", \"asdf:mise-plugins/mise-ghcup\"]\ndescription = \"GHCup is an installer for the general purpose language Haskell\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"ghcup --version\", expected = \"The GHCup Haskell installer, version {{version}}\" }\n"
  },
  {
    "path": "registry/ghorg.toml",
    "content": "backends = [\"aqua:gabrie30/ghorg\", \"asdf:gbloquel/asdf-ghorg\"]\ndescription = \"Quickly clone an entire org/users repositories into one directory - Supports GitHub, GitLab, Bitbucket, and more\"\n"
  },
  {
    "path": "registry/ghq.toml",
    "content": "backends = [\"aqua:x-motemen/ghq\", \"asdf:kajisha/asdf-ghq\"]\ndescription = \"Remote repository management made easy\"\n"
  },
  {
    "path": "registry/ginkgo.toml",
    "content": "backends = [\n  \"go:github.com/onsi/ginkgo/v2/ginkgo\",\n  \"asdf:mise-plugins/mise-ginkgo\",\n]\ndescription = \"A Modern Testing Framework for Go\"\ntest = { cmd = \"ginkgo version\", expected = \"Ginkgo Version {{version}}\" }\n"
  },
  {
    "path": "registry/git-chglog.toml",
    "content": "backends = [\"aqua:git-chglog/git-chglog\", \"asdf:GoodwayGroup/asdf-git-chglog\"]\ndescription = \"CHANGELOG generator implemented in Go (Golang)\"\n"
  },
  {
    "path": "registry/git-cliff.toml",
    "content": "backends = [\"aqua:orhun/git-cliff\", \"asdf:jylenhof/asdf-git-cliff\"]\ndescription = \"A highly customizable Changelog Generator that follows Conventional Commit specifications\"\ntest = { cmd = \"git-cliff --version\", expected = \"git-cliff {{version}}\" }\n"
  },
  {
    "path": "registry/git-lfs.toml",
    "content": "backends = [\"aqua:git-lfs/git-lfs\"]\ndescription = \"Git extension for versioning large files\"\ntest = { cmd = \"git-lfs --version\", expected = \"git-lfs/{{version}}\" }\n"
  },
  {
    "path": "registry/gitconfig.toml",
    "content": "backends = [\"github:0ghny/gitconfig\", \"asdf:0ghny/asdf-gitconfig\"]\ndescription = \"Cli to manage multiple gitconfigs with ease\"\ntest = { cmd = \"gitconfig --version\", expected = \"gitconfig version {{version}}\" }\n"
  },
  {
    "path": "registry/github-cli.toml",
    "content": "aliases = [\"gh\"]\nbackends = [\"aqua:cli/cli\", \"asdf:bartlomiejdanek/asdf-github-cli\"]\ndescription = \"GitHub’s official command line tool\"\ntest = { cmd = \"gh --version\", expected = \"gh version {{version}}\" }\n"
  },
  {
    "path": "registry/github-markdown-toc.toml",
    "content": "backends = [\n  \"aqua:ekalinin/github-markdown-toc\",\n  \"asdf:skyzyx/asdf-github-markdown-toc\",\n]\ndescription = \"Easy TOC creation for GitHub README.md\"\ntest = { cmd = \"gh-md-toc --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/gitleaks.toml",
    "content": "backends = [\"aqua:gitleaks/gitleaks\", \"asdf:jmcvetta/asdf-gitleaks\"]\ndescription = \"Find secrets with Gitleaks\"\ntest = { cmd = \"gitleaks --version\", expected = \"gitleaks version {{version}}\" }\n"
  },
  {
    "path": "registry/gitsign.toml",
    "content": "backends = [\"aqua:sigstore/gitsign\", \"asdf:spencergilbert/asdf-gitsign\"]\ndescription = \"Keyless Git signing using Sigstore\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"gitsign --version\", expected = \"gitsign version v{{version}}\" }\n"
  },
  {
    "path": "registry/gitu.toml",
    "content": "backends = [\"aqua:altsem/gitu\", \"cargo:gitu\"]\ndescription = \"A TUI Git client inspired by Magit\"\n# test = [\"gitu --version\", \"gitu v{{version}}\"] # DISABLED: upstream bug - v0.40.0 binary reports as v0.39.0-21-g0d1141b\n"
  },
  {
    "path": "registry/gitui.toml",
    "content": "backends = [\"aqua:extrawurst/gitui\", \"asdf:looztra/asdf-gitui\", \"cargo:gitui\"]\ndescription = \"Blazing 💥 fast terminal-ui for git written in rust\"\n"
  },
  {
    "path": "registry/gitversion.toml",
    "content": "backends = [\"aqua:gittools/gitversion\"]\ndescription = \"From git log to SemVer in no time\"\n"
  },
  {
    "path": "registry/glab.toml",
    "content": "description = \"gitlab cli\"\ntest = { cmd = \"glab version\", expected = \"glab {{version}}\" }\n\n[[backends]]\nfull = \"gitlab:gitlab-org/cli\"\nplatforms = [\"linux\", \"macos\"]\n\n[backends.options]\nexe = \"glab\"\n\n[[backends]]\nfull = \"gitlab:gitlab-org/cli\"\nplatforms = [\"windows\"]\n\n[backends.options]\nexe = \"glab\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-glab\"\n"
  },
  {
    "path": "registry/gleam.toml",
    "content": "backends = [\"aqua:gleam-lang/gleam\", \"asdf:asdf-community/asdf-gleam\"]\ndescription = \"A friendly language for building type-safe, scalable systems\"\ntest = { cmd = \"gleam --version\", expected = \"gleam {{version}}\" }\n"
  },
  {
    "path": "registry/glen.toml",
    "content": "backends = [\"github:lingrino/glen\", \"asdf:bradym/asdf-glen\"]\ndescription = \"cli to export gitlab variables\"\ntest = { cmd = \"glen version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/glooctl.toml",
    "content": "backends = [\"github:solo-io/gloo\", \"asdf:halilkaya/asdf-glooctl\"]\ndescription = \"The Cloud-Native API Gateway and AI Gateway\"\n"
  },
  {
    "path": "registry/glow.toml",
    "content": "backends = [\"aqua:charmbracelet/glow\", \"asdf:mise-plugins/asdf-glow\"]\ndescription = \"Render markdown on the CLI, with pizzazz\"\n"
  },
  {
    "path": "registry/go-containerregistry.toml",
    "content": "backends = [\n  \"aqua:google/go-containerregistry\",\n  \"asdf:dex4er/asdf-go-containerregistry\",\n]\ndescription = \"Go library and CLIs for working with container registries\"\n"
  },
  {
    "path": "registry/go-getter.toml",
    "content": "backends = [\"aqua:hashicorp/go-getter\", \"asdf:mise-plugins/mise-go-getter\"]\ndescription = \"Package for downloading things from a string URL using a variety of protocols\"\ntest = { cmd = \"which go-getter\", expected = \"go-getter\" }\n"
  },
  {
    "path": "registry/go-jira.toml",
    "content": "backends = [\"aqua:go-jira/jira\", \"asdf:dguihal/asdf-go-jira\"]\ndescription = \"simple jira command line client in Go\"\n"
  },
  {
    "path": "registry/go-jsonnet.toml",
    "content": "backends = [\n  \"aqua:google/go-jsonnet\",\n  \"asdf:https://gitlab.com/craigfurman/asdf-go-jsonnet\",\n]\ndescription = \"This an implementation of Jsonnet in pure Go\"\n"
  },
  {
    "path": "registry/go-junit-report.toml",
    "content": "backends = [\n  \"aqua:jstemmer/go-junit-report\",\n  \"asdf:jwillker/asdf-go-junit-report\",\n]\ndescription = \"Convert Go test output to JUnit XML\"\ntest = { cmd = \"go-junit-report --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/go-sdk.toml",
    "content": "backends = [\"conda:go\", \"asdf:mise-plugins/mise-go-sdk\"]\ndescription = \"Install go sdk\"\ntest = { cmd = \"go version\", expected = \"go version\" }\n"
  },
  {
    "path": "registry/go-swagger.toml",
    "content": "backends = [\"aqua:go-swagger/go-swagger\", \"asdf:jfreeland/asdf-go-swagger\"]\ndescription = \"Swagger 2.0 implementation for go\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"swagger version\", expected = \"version: v{{version}}\" }\n"
  },
  {
    "path": "registry/go.toml",
    "content": "backends = [\"core:go\"]\ndescription = \"go lang (Builtin plugin)\"\ndetect = [\"go.mod\", \"go.sum\"]\n"
  },
  {
    "path": "registry/goconvey.toml",
    "content": "backends = [\n  \"go:github.com/smartystreets/goconvey\",\n  \"asdf:mise-plugins/mise-goconvey\",\n]\ndescription = \"Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go\"\n"
  },
  {
    "path": "registry/gocryptfs.toml",
    "content": "backends = [\"aqua:rfjakob/gocryptfs\"]\ndescription = \"Encrypted overlay filesystem written in Go\"\n"
  },
  {
    "path": "registry/godot.toml",
    "content": "backends = [\"aqua:godotengine/godot\"]\ndescription = \"Free and open source 2D and 3D game engine\"\n# Example of `godot --version`: 4.6.stable.official.89cea1439 (MAJOR.MINOR.stable.official.SHORT_COMMIT_HASH)\n# PATCH is sometimes present after MINOR.\ntest = { cmd = \"godot --version | awk -F'.stable' '{print $1}'\", expected = \"{{ version | split(pat='-') | first }}\" }\n"
  },
  {
    "path": "registry/gofumpt.toml",
    "content": "backends = [\"aqua:mvdan/gofumpt\", \"asdf:looztra/asdf-gofumpt\"]\ndescription = \"A stricter gofmt\"\ntest = { cmd = \"gofumpt --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/gojq.toml",
    "content": "backends = [\n  \"aqua:itchyny/gojq\",\n  \"asdf:jimmidyson/asdf-gojq\",\n  \"go:github.com/itchyny/gojq/cmd/gojq\",\n]\ndescription = \"Pure Go implementation of jq\"\ntest = { cmd = \"gojq --version\", expected = \"gojq {{version}}\" }\n"
  },
  {
    "path": "registry/gokey.toml",
    "content": "backends = [\"aqua:cloudflare/gokey\"]\ndescription = \"A simple vaultless password manager in Go\"\ntest = { cmd = \"gokey -p master -r realm -l 8\", expected = \"hJ2gXSy[\" }\n"
  },
  {
    "path": "registry/golangci-lint-langserver.toml",
    "content": "backends = [\n  \"aqua:nametake/golangci-lint-langserver\",\n  \"go:github.com/nametake/golangci-lint-langserver\",\n]\ndescription = \"golangci-lint language server\"\ntest = { cmd = \"which golangci-lint-langserver\", expected = \"golangci-lint-langserver\" }\n"
  },
  {
    "path": "registry/golangci-lint.toml",
    "content": "backends = [\"aqua:golangci/golangci-lint\", \"asdf:hypnoglow/asdf-golangci-lint\"]\ndescription = \"Fast linters Runner for Go\"\n"
  },
  {
    "path": "registry/golines.toml",
    "content": "backends = [\n  { full = \"aqua:segmentio/golines\", platforms = [\n    \"linux\",\n    \"macos\",\n  ] },\n  \"go:github.com/segmentio/golines\",\n]\ndescription = \"A golang formatter that fixes long lines\"\ntest = { cmd = \"golines --version\", expected = \"golines v{{version}}\" }\n"
  },
  {
    "path": "registry/gomigrate.toml",
    "content": "backends = [\"aqua:golang-migrate/migrate\", \"asdf:joschi/asdf-gomigrate\"]\ndescription = \"Database migrations. CLI and Golang library\"\ntest = { cmd = \"migrate --version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/gomplate.toml",
    "content": "backends = [\"aqua:hairyhenderson/gomplate\", \"asdf:sneakybeaky/asdf-gomplate\"]\ndescription = \"A flexible commandline tool for template rendering. Supports lots of local and remote datasources\"\n"
  },
  {
    "path": "registry/gopass.toml",
    "content": "backends = [\"aqua:gopasspw/gopass\", \"asdf:trallnag/asdf-gopass\"]\ndescription = \"The slightly more awesome standard unix password manager for teams\"\n"
  },
  {
    "path": "registry/goreleaser.toml",
    "content": "backends = [\"aqua:goreleaser/goreleaser\", \"asdf:kforsthoevel/asdf-goreleaser\"]\ndescription = \"Deliver Go binaries as fast and easily as possible\"\n"
  },
  {
    "path": "registry/goss.toml",
    "content": "backends = [\"aqua:goss-org/goss\", \"asdf:raimon49/asdf-goss\"]\ndescription = \"Quick and Easy server testing/validation\"\n"
  },
  {
    "path": "registry/gotestsum.toml",
    "content": "backends = [\"aqua:gotestyourself/gotestsum\", \"asdf:pmalek/mise-gotestsum\"]\ndescription = \"'go test' runner with output optimized for humans, JUnit XML for CI integration, and a summary of the test results\"\n"
  },
  {
    "path": "registry/gping.toml",
    "content": "backends = [\"aqua:orf/gping\", \"github:orf/gping\", \"cargo:gping\"]\ndescription = \"Ping, but with a graph\"\ntest = { cmd = \"gping --version\", expected = \"gping {{version}}\" }\n"
  },
  {
    "path": "registry/graalvm.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-graalvm\"]\ndescription = \"An advanced JDK with ahead-of-time Native Image compilation\"\n"
  },
  {
    "path": "registry/gradle.toml",
    "content": "backends = [\"aqua:gradle/gradle\", \"vfox:mise-plugins/vfox-gradle\"]\ndepends = [\"java\"]\ndescription = \"Gradle is the open source build system of choice for Java, Android, and Kotlin developers\"\ntest = { cmd = \"gradle -V\", expected = \"Gradle\" }\n"
  },
  {
    "path": "registry/grain.toml",
    "content": "description = \"The Grain compiler toolchain and CLI. Home of the modern web staple\"\ntest = { cmd = \"grain --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:grain-lang/grain\"\n\n[backends.options]\nversion_prefix = \"grain-v\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-grain\"\n"
  },
  {
    "path": "registry/granted.toml",
    "content": "backends = [\"aqua:common-fate/granted\", \"asdf:dex4er/asdf-granted\"]\ndescription = \"The easiest way to access AWS\"\n"
  },
  {
    "path": "registry/graphite.toml",
    "content": "description = \"Code review for the age of AI\"\ntest = { cmd = \"gt --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:withgraphite/homebrew-tap\"\n\n[backends.options]\nexe = \"gt\"\n\n[[backends]]\nfull = \"npm:@withgraphite/graphite-cli\"\n"
  },
  {
    "path": "registry/grex.toml",
    "content": "backends = [\"aqua:pemistahl/grex\", \"asdf:ouest/asdf-grex\", \"cargo:grex\"]\ndescription = \"A command-line tool and library for generating regular expressions from user-provided test cases\"\ntest = { cmd = \"grex --version\", expected = \"grex {{version}}\" }\n"
  },
  {
    "path": "registry/gron.toml",
    "content": "backends = [\"aqua:tomnomnom/gron\"]\ndescription = \"Make JSON greppable\"\ntest = { cmd = \"gron --version\", expected = \"gron version dev\" }\n"
  },
  {
    "path": "registry/groovy.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-groovy\", \"vfox:mise-plugins/vfox-groovy\"]\ndescription = \"A flexible and extensible Java-like language for the JVM\"\n"
  },
  {
    "path": "registry/grpc-health-probe.toml",
    "content": "backends = [\n  \"aqua:grpc-ecosystem/grpc-health-probe\",\n  \"asdf:zufardhiyaulhaq/asdf-grpc-health-probe\",\n]\ndescription = \"A command-line tool to perform health-checks for gRPC applications in Kubernetes and elsewhere\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"grpc_health_probe --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/grpcurl.toml",
    "content": "backends = [\"aqua:fullstorydev/grpcurl\", \"asdf:asdf-community/asdf-grpcurl\"]\ndescription = \"Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers\"\n"
  },
  {
    "path": "registry/grype.toml",
    "content": "backends = [\"aqua:anchore/grype\", \"asdf:poikilotherm/asdf-grype\"]\ndescription = \"A vulnerability scanner for container images and filesystems\"\ntest = { cmd = \"grype --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/gum.toml",
    "content": "backends = [\"aqua:charmbracelet/gum\", \"asdf:lwiechec/asdf-gum\"]\ndescription = \"A tool for glamorous shell scripts\"\n"
  },
  {
    "path": "registry/gup.toml",
    "content": "backends = [\"aqua:nao1215/gup\"]\ndescription = 'gup - Update binaries installed by \"go install\" with goroutines'\ntest = { cmd = \"gup version\", expected = \"gup version v{{version}}\" }\n"
  },
  {
    "path": "registry/gwvault.toml",
    "content": "backends = [\"aqua:GoodwayGroup/gwvault\", \"asdf:GoodwayGroup/asdf-gwvault\"]\ndescription = \"ansible-vault CLI reimplemented in go\"\n"
  },
  {
    "path": "registry/hadolint.toml",
    "content": "backends = [\"aqua:hadolint/hadolint\", \"asdf:devlincashman/asdf-hadolint\"]\ndescription = \"Dockerfile linter, validate inline bash, written in Haskell\"\ntest = { cmd = \"hadolint --version\", expected = \"Haskell Dockerfile Linter {{version}}\" }\n"
  },
  {
    "path": "registry/harper-cli.toml",
    "content": "backends = [\"aqua:Automattic/harper/harper-cli\"]\ndescription = \"harper-cli is a small, experimental frontend for Harper. It can be used in any situation where you might need to check a large number of files automatically (like in continuous integration)\"\n# harper-cli intentionally prints different version. See https://github.com/Automattic/harper/issues/557#issuecomment-2635037944\ntest = { cmd = \"harper-cli --version\", expected = \"harper-cli\" }\n"
  },
  {
    "path": "registry/harper-ls.toml",
    "content": "backends = [\"aqua:Automattic/harper/harper-ls\"]\ndescription = \"harper-ls is the Language Server Protocol frontend for Harper\"\ntest = { cmd = \"harper-ls --version\", expected = \"harper-ls {{version}}\" }\n"
  },
  {
    "path": "registry/has.toml",
    "content": "backends = [\"aqua:kdabir/has\", \"asdf:sylvainmetayer/asdf-has\"]\ndescription = \"checks presence of various command line tools and their versions on the path\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"has --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/hasura-cli.toml",
    "content": "backends = [\"aqua:hasura/graphql-engine\", \"asdf:gurukulkarni/asdf-hasura\"]\ndescription = \"Hasura GraphQL Engine CLI\"\n"
  },
  {
    "path": "registry/hatch.toml",
    "content": "backends = [\"pipx:hatch\"]\ndescription = \"Modern, extensible Python project management.\"\ntest = { cmd = \"hatch --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/haxe.toml",
    "content": "backends = [\"github:HaxeFoundation/haxe\", \"asdf:mise-plugins/mise-haxe\"]\ndescription = \"Haxe - The Cross-Platform Toolkit\"\ntest = { cmd = \"haxe --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/hcl2json.toml",
    "content": "backends = [\"aqua:tmccombs/hcl2json\", \"asdf:dex4er/asdf-hcl2json\"]\ndescription = \"Convert hcl2 to json\"\n"
  },
  {
    "path": "registry/hcloud.toml",
    "content": "backends = [\"aqua:hetznercloud/cli\", \"asdf:chessmango/asdf-hcloud\"]\ndescription = \"A command-line interface for Hetzner Cloud\"\n"
  },
  {
    "path": "registry/helix.toml",
    "content": "backends = [\"aqua:helix-editor/helix\"]\ndescription = \"A post-modern modal text editor\"\ntest = { cmd = \"hx --version\", expected = \"helix {{version}}\" }\n"
  },
  {
    "path": "registry/helm-cr.toml",
    "content": "backends = [\"aqua:helm/chart-releaser\", \"asdf:Antiarchitect/asdf-helm-cr\"]\ndescription = \"Hosting Helm Charts via GitHub Pages and Releases\"\n"
  },
  {
    "path": "registry/helm-ct.toml",
    "content": "backends = [\"aqua:helm/chart-testing\", \"asdf:tablexi/asdf-helm-ct\"]\ndescription = \"CLI tool for linting and testing Helm charts\"\n"
  },
  {
    "path": "registry/helm-diff.toml",
    "content": "description = \"A helm plugin that shows a diff explaining what a helm upgrade would change\"\ntest = { cmd = \"helm-diff version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:databus23/helm-diff\"\n\n[backends.options]\nbin = \"diff\"\nbin_path = \"diff/bin\"\nrename_exe = \"helm-diff\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-helm-diff\"\n"
  },
  {
    "path": "registry/helm-docs.toml",
    "content": "backends = [\"aqua:norwoodj/helm-docs\", \"asdf:sudermanjr/asdf-helm-docs\"]\ndescription = \"A tool for automatically generating markdown documentation for helm charts\"\n"
  },
  {
    "path": "registry/helm-ls.toml",
    "content": "backends = [\"aqua:mrjosh/helm-ls\"]\ndescription = \"Helm-ls is a helm language server protocol LSP implementation\"\ntest = { cmd = \"helm_ls version\", expected = \"Helm-ls version: master\" } # helm_ls version returns always \"master\" - https://github.com/mrjosh/helm-ls/issues/179\n"
  },
  {
    "path": "registry/helm.toml",
    "content": "backends = [\"aqua:helm/helm\", \"asdf:Antiarchitect/asdf-helm\"]\ndescription = \"The Kubernetes Package Manager\"\n"
  },
  {
    "path": "registry/helmfile.toml",
    "content": "backends = [\"aqua:helmfile/helmfile\", \"asdf:feniix/asdf-helmfile\"]\ndescription = \"Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases. Generate all-in-one manifests for use with ArgoCD\"\ntest = { cmd = \"helmfile --version\", expected = \"helmfile version {{version}}\" }\n"
  },
  {
    "path": "registry/helmsman.toml",
    "content": "backends = [\"github:Praqma/helmsman\", \"asdf:luisdavim/asdf-helmsman\"]\ndescription = \"Helmsman is a Helm Charts (k8s applications) as Code tool which allows you to automate the deployment/management of your Helm charts from version controlled code\"\n"
  },
  {
    "path": "registry/helmwave.toml",
    "content": "backends = [\"aqua:helmwave/helmwave\"]\ndescription = \"New  wave for @helm\"\ntest = { cmd = \"helmwave version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/heroku.toml",
    "content": "aliases = [\"heroku-cli\"]\nbackends = [\"npm:heroku\"]\ndescription = \"The Heroku Command Line Interface (CLI) is an essential part of using Heroku. With it, you can create and manage Heroku apps directly from the terminal\"\ntest = { cmd = \"heroku --version\", expected = \"heroku/{{version}}\" }\n"
  },
  {
    "path": "registry/hexyl.toml",
    "content": "backends = [\"aqua:sharkdp/hexyl\", \"cargo:hexyl\"]\ndescription = \"A command-line hex viewer\"\ntest = { cmd = \"hexyl --version\", expected = \"hexyl {{version}}\" }\n"
  },
  {
    "path": "registry/hishtory.toml",
    "content": "backends = [\"github:ddworken/hishtory\", \"asdf:asdf-community/asdf-hishtory\"]\ndescription = \"Your shell history: synced, queryable, and in context\"\n"
  },
  {
    "path": "registry/hivemind.toml",
    "content": "backends = [\"github:DarthSim/hivemind\", \"go:github.com/DarthSim/hivemind\"]\ndescription = \"Process manager for Procfile-based applications\"\ntest = { cmd = \"hivemind --version\", expected = \"Hivemind version {{version}}\" }\n"
  },
  {
    "path": "registry/hk.toml",
    "content": "backends = [\"aqua:jdx/hk\"]\ndescription = \"git hook and pre-commit lint manager\"\ntest = { cmd = \"hk --version\", expected = \"hk {{version}}\" }\n"
  },
  {
    "path": "registry/hledger-flow.toml",
    "content": "backends = [\"github:apauley/hledger-flow\", \"asdf:airtonix/asdf-hledger-flow\"]\ndescription = \"An hledger/ledger-cli workflow focusing on automated statement import and classification\"\n"
  },
  {
    "path": "registry/hledger.toml",
    "content": "backends = [\"github:simonmichael/hledger\", \"asdf:airtonix/asdf-hledger\"]\ndescription = \"Robust, fast, intuitive plain text accounting tool with CLI, TUI and web interfaces\"\n"
  },
  {
    "path": "registry/hostctl.toml",
    "content": "backends = [\"aqua:guumaster/hostctl\", \"asdf:svenluijten/asdf-hostctl\"]\ndescription = \"Your dev tool to manage /etc/hosts like a pro\"\n"
  },
  {
    "path": "registry/htmlq.toml",
    "content": "backends = [\"aqua:mgdm/htmlq\", \"cargo:htmlq\"]\ndescription = \"Like jq, but for HTML\"\ntest = { cmd = \"htmlq --version\", expected = \"htmlq {{version}}\" }\n"
  },
  {
    "path": "registry/httpie-go.toml",
    "content": "backends = [\"aqua:nojima/httpie-go\", \"asdf:abatilo/asdf-httpie-go\"]\ndescription = \"httpie-like HTTP client written in Go\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"ht --version 2>&1\", expected = \"httpie-go {{version}}\" }\n"
  },
  {
    "path": "registry/hub.toml",
    "content": "backends = [\"aqua:mislav/hub\", \"asdf:mise-plugins/asdf-hub\"]\ndescription = \"A command-line tool that makes git easier to use with GitHub\"\n"
  },
  {
    "path": "registry/hugo-extended.toml",
    "content": "backends = [\"aqua:gohugoio/hugo/hugo-extended\"]\ndescription = \"The world’s fastest framework for building websites\"\n"
  },
  {
    "path": "registry/hugo.toml",
    "content": "backends = [\n  \"aqua:gohugoio/hugo\",\n  \"asdf:NeoHsu/asdf-hugo\",\n  \"asdf:nklmilojevic/asdf-hugo\",\n]\ndescription = \"The world’s fastest framework for building websites\"\n"
  },
  {
    "path": "registry/hurl.toml",
    "content": "backends = [\n  \"aqua:Orange-OpenSource/hurl\",\n  \"asdf:raimon49/asdf-hurl\",\n  \"cargo:hurl\",\n]\ndescription = \"Hurl, run and test HTTP requests with plain text\"\n"
  },
  {
    "path": "registry/hwatch.toml",
    "content": "backends = [\"aqua:blacknon/hwatch\", \"asdf:chessmango/asdf-hwatch\"]\ndescription = \"A modern alternative to the watch command, records the differences in execution results and can check this differences at after\"\ntest = { cmd = \"hwatch --version\", expected = \"hwatch {{version}}\" }\n"
  },
  {
    "path": "registry/hygen.toml",
    "content": "backends = [\"github:jondot/hygen\", \"asdf:brentjanderson/asdf-hygen\"]\ndescription = \"The simple, fast, and scalable code generator that lives in your project\"\n"
  },
  {
    "path": "registry/hyperfine.toml",
    "content": "backends = [\n  \"aqua:sharkdp/hyperfine\",\n  \"asdf:volf52/asdf-hyperfine\",\n  \"cargo:hyperfine\",\n]\ndescription = \"A command-line benchmarking tool\"\n"
  },
  {
    "path": "registry/iam-policy-json-to-terraform.toml",
    "content": "backends = [\n  \"aqua:flosell/iam-policy-json-to-terraform\",\n  \"asdf:carlduevel/asdf-iam-policy-json-to-terraform\",\n]\ndescription = \"Small tool to convert an IAM Policy in JSON format into a Terraform aws_iam_policy_document\"\ntest = { cmd = \"iam-policy-json-to-terraform --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/iamlive.toml",
    "content": "backends = [\"aqua:iann0036/iamlive\", \"asdf:chessmango/asdf-iamlive\"]\ndescription = \"Generate an IAM policy from AWS calls using client-side monitoring (CSM) or embedded proxy\"\n"
  },
  {
    "path": "registry/imagemagick.toml",
    "content": "backends = [\"conda:imagemagick\", \"asdf:mise-plugins/mise-imagemagick\"]\ndescription = \"ImageMagick is a free, open-source software suite for creating, editing, converting, and displaying images. It supports 200+ formats and offers powerful command-line tools and APIs for automation, scripting, and integration across platforms\"\ntest = { cmd = \"magick --version 2>&1\", expected = \"ImageMagick\" }\n"
  },
  {
    "path": "registry/imgpkg.toml",
    "content": "backends = [\"aqua:carvel-dev/imgpkg\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = \"Store application configuration files in Docker/OCI registries\"\n"
  },
  {
    "path": "registry/infisical.toml",
    "content": "backends = [\"github:Infisical/cli\"]\ndescription = \"The open source secret management platform: Sync secrets across your team/infrastructure and prevent secret leaks\"\ntest = { cmd = \"infisical --version\", expected = \"infisical version {{version}}\" }\n"
  },
  {
    "path": "registry/infracost.toml",
    "content": "backends = [\"aqua:infracost/infracost\", \"asdf:dex4er/asdf-infracost\"]\ndescription = \"Cloud cost estimates for Terraform in pull requests. Love your cloud bill\"\n"
  },
  {
    "path": "registry/inlets.toml",
    "content": "backends = [\"aqua:inlets/inletsctl\", \"asdf:nlamirault/asdf-inlets\"]\ndescription = \"Create inlets servers on the top cloud platforms\"\n"
  },
  {
    "path": "registry/istioctl.toml",
    "content": "backends = [\"aqua:istio/istio/istioctl\", \"asdf:virtualstaticvoid/asdf-istioctl\"]\ndescription = \"Istio configuration command line utility for service operators to debug and diagnose their Istio mesh\"\ntest = { cmd = \"istioctl version --remote=false\", expected = \"client version: {{version}}\" }\n"
  },
  {
    "path": "registry/jaq.toml",
    "content": "backends = [\"aqua:01mf02/jaq\", \"cargo:jaq\"]\ndescription = \"A jq clone focussed on correctness, speed, and simplicity\"\ntest = { cmd = \"jaq --version\", expected = \"jaq {{version}}\" }\n"
  },
  {
    "path": "registry/java.toml",
    "content": "backends = [\"core:java\"]\ndescription = \"jdk java\"\n"
  },
  {
    "path": "registry/jbang.toml",
    "content": "backends = [\"asdf:mise-plugins/jbang-asdf\"]\ndescription = \"Lets Students, Educators and Professional Developers create, edit and run self-contained source-only Java programs with unprecedented ease\"\n"
  },
  {
    "path": "registry/jc.toml",
    "content": "backends = [\"aqua:kellyjonbrazil/jc\", \"pipx:jc\"]\ndescription = \"CLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts\"\ntest = { cmd = \"jc --version\", expected = \"jc version:  {{version}}\" }\n"
  },
  {
    "path": "registry/jd.toml",
    "content": "backends = [\"aqua:josephburnett/jd\", \"go:github.com/josephburnett/jd\"]\ndescription = \"JSON diff and patch\"\ntest = { cmd = \"jd --version\", expected = \"jd version {{version}}\" }\n"
  },
  {
    "path": "registry/jfrog-cli.toml",
    "content": "backends = [\"conda:jfrog-cli\", \"asdf:mise-plugins/mise-jfrog-cli\"]\ndescription = \"Frog CLI is a client that provides a simple interface that automates access to the JFrog products\"\ntest = { cmd = \"jf --version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/jib.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-jib\"]\ndescription = \"jib is a general-purpose command-line utility for building Docker or OCI container images from file system content as well as JAR files\"\ntest = { cmd = \"jib --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/jiq.toml",
    "content": "backends = [\"aqua:fiatjaf/jiq\", \"asdf:chessmango/asdf-jiq\"]\ndescription = \"jid on jq - interactive JSON query tool using jq expressions\"\n"
  },
  {
    "path": "registry/jj.toml",
    "content": "aliases = [\"jujutsu\"]\nbackends = [\"aqua:jj-vcs/jj\", \"cargo:jj-cli\"]\ndescription = \"A Git-compatible VCS that is both simple and powerful\"\n"
  },
  {
    "path": "registry/jjui.toml",
    "content": "aliases = [\"jujutsu-ui\"]\nbackends = [\"aqua:idursun/jjui\"]\ndescription = \"Jujutsu UI (jjui) is a Text User Interface (TUI) designed for interacting with the Jujutsu version control system\"\ntest = { cmd = \"jjui --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/jless.toml",
    "content": "backends = [\n  \"aqua:PaulJuliusMartinez/jless\",\n  \"asdf:jc00ke/asdf-jless\",\n  \"cargo:jless\",\n]\ndescription = \"jless is a command-line JSON viewer designed for reading, exploring, and searching through JSON data\"\n"
  },
  {
    "path": "registry/jmespath.toml",
    "content": "backends = [\"aqua:jmespath/jp\", \"asdf:skyzyx/asdf-jmespath\"]\ndescription = \"Command line interface to JMESPath - http://jmespath.org\"\ntest = { cmd = \"jp --version\", expected = \"jp version {{version}}\" }\n"
  },
  {
    "path": "registry/jnv.toml",
    "content": "backends = [\"aqua:ynqa/jnv\", \"asdf:raimon49/asdf-jnv\"]\ndescription = \"interactive JSON filter using jq\"\n"
  },
  {
    "path": "registry/jq.toml",
    "content": "backends = [\"aqua:jqlang/jq\", \"asdf:mise-plugins/asdf-jq\"]\ndescription = \"Command-line JSON processor\"\ntest = { cmd = \"jq --version\", expected = \"jq-{{version}}\" }\n"
  },
  {
    "path": "registry/jqp.toml",
    "content": "backends = [\"aqua:noahgorstein/jqp\", \"asdf:https://gitlab.com/wt0f/asdf-jqp\"]\ndescription = \"A TUI playground to experiment with jq\"\n"
  },
  {
    "path": "registry/jreleaser.toml",
    "content": "backends = [\"aqua:jreleaser/jreleaser\", \"asdf:joschi/asdf-jreleaser\"]\ndescription = \"Release projects quickly and easily with JReleaser\"\n"
  },
  {
    "path": "registry/json5.toml",
    "content": "backends = [\"npm:json5\"]\ndescription = \"JSON5 is an extension to the popular JSON file format that aims to be easier to write and maintain by hand (e.g. for config files). It is not intended to be used for machine-to-machine communication. (Keep using JSON or other file formats for that. 🙂)\"\ntest = { cmd = \"json5 --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/jsonnet-bundler.toml",
    "content": "aliases = [\"jb\"]\nbackends = [\"aqua:jsonnet-bundler/jsonnet-bundler\", \"asdf:beardix/asdf-jb\"]\ndescription = \"A jsonnet package manager\"\ntest = { cmd = \"jb --version 2>&1\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/jsonschema.toml",
    "content": "backends = [\"aqua:sourcemeta/jsonschema\"]\ndescription = \"The CLI for working with JSON Schema. Covers formatting, linting, testing, bundling, and more for both local development and CI/CD pipelines\"\ntest = { cmd = \"jsonschema version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/jules.toml",
    "content": "backends = [\"npm:@google/jules\"]\ndescription = \"Jules, the asynchronous coding agent from Google, in the terminal\"\ntest = { cmd = \"jules version\", expected = \"Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/julia.toml",
    "content": "description = \"The Julia Programming Language\"\ndetect = [\"Project.toml\", \"Manifest.toml\"]\ntest = { cmd = \"julia --version\", expected = \"julia version\" }\n\n[[backends]]\nfull = \"http:julia\"\n\n[backends.options]\nversion_expr = 'sortVersions(filter(keys(fromJSON(body)), { # matches \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+(-[0-9A-Za-z\\\\.-]+)?$\" }))'\nversion_list_url = \"https://julialang-s3.julialang.org/bin/versions.json\"\n\n[backends.options.platforms.macos-x64]\nurl = \"{% if version == \\\"nightly\\\" %}https://julialangnightlies-s3.julialang.org/bin/mac/x64/julia-latest-mac64.tar.gz{% else %}https://julialang-s3.julialang.org/bin/mac/x64/{{ version | split(pat='.') | slice(start=0, end=2) | join(sep='.') }}/julia-{{ version }}-mac64.tar.gz{% endif %}\"\n\n[backends.options.platforms.macos-arm64]\nurl = \"{% if version == \\\"nightly\\\" %}https://julialangnightlies-s3.julialang.org/bin/mac/aarch64/julia-latest-macaarch64.tar.gz{% else %}https://julialang-s3.julialang.org/bin/mac/aarch64/{{ version | split(pat='.') | slice(start=0, end=2) | join(sep='.') }}/julia-{{ version }}-macaarch64.tar.gz{% endif %}\"\n\n[backends.options.platforms.linux-x64]\nurl = \"{% if version == \\\"nightly\\\" %}https://julialangnightlies-s3.julialang.org/bin/linux/x64/julia-latest-linux64.tar.gz{% else %}https://julialang-s3.julialang.org/bin/linux/x64/{{ version | split(pat='.') | slice(start=0, end=2) | join(sep='.') }}/julia-{{ version }}-linux-x86_64.tar.gz{% endif %}\"\n\n[backends.options.platforms.linux-arm64]\nurl = \"{% if version == \\\"nightly\\\" %}https://julialangnightlies-s3.julialang.org/bin/linux/aarch64/julia-latest-linuxaarch64.tar.gz{% else %}https://julialang-s3.julialang.org/bin/linux/aarch64/{{ version | split(pat='.') | slice(start=0, end=2) | join(sep='.') }}/julia-{{ version }}-linux-aarch64.tar.gz{% endif %}\"\n\n[backends.options.platforms.windows-x64]\nformat = \"zip\"\nurl = \"{% if version == \\\"nightly\\\" %}https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.zip{% else %}https://julialang-s3.julialang.org/bin/winnt/x64/{{ version | split(pat='.') | slice(start=0, end=2) | join(sep='.') }}/julia-{{ version }}-win64.zip{% endif %}\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-julia\"\n"
  },
  {
    "path": "registry/just.toml",
    "content": "backends = [\"aqua:casey/just\", \"asdf:olofvndrhr/asdf-just\", \"cargo:just\"]\ndescription = \"Just a command runner\"\ntest = { cmd = \"just --version\", expected = \"just {{version}}\" }\n"
  },
  {
    "path": "registry/jwt.toml",
    "content": "backends = [\"aqua:mike-engel/jwt-cli\", \"cargo:jwt-cli\"]\ndescription = \"A super fast CLI tool to decode and encode JWTs built in Rust\"\ntest = { cmd = \"jwt --version\", expected = \"jwt {{version}}\" }\n"
  },
  {
    "path": "registry/jwtui.toml",
    "content": "description = \"A command line UI for decoding/encoding JSON Web Tokens\"\n\n[[backends]]\nfull = \"github:jwt-rs/jwt-ui\"\n\n[backends.options]\nexe = \"jwtui\"\n\n[[backends]]\nfull = \"cargo:jwt-ui\"\n"
  },
  {
    "path": "registry/jx.toml",
    "content": "backends = [\"aqua:jenkins-x/jx\", \"asdf:vbehar/asdf-jx\"]\ndescription = \"Jenkins X provides automated CI+CD for Kubernetes with Preview Environments on Pull Requests using Cloud Native pipelines from Tekton\"\n"
  },
  {
    "path": "registry/k0sctl.toml",
    "content": "backends = [\"aqua:k0sproject/k0sctl\", \"asdf:Its-Alex/asdf-plugin-k0sctl\"]\ndescription = \"A bootstrapping and management tool for k0s clusters\"\ntest = { cmd = \"k0sctl version\", expected = \"version: v{{version}}\" }\n"
  },
  {
    "path": "registry/k2tf.toml",
    "content": "backends = [\"aqua:sl1pm4t/k2tf\", \"asdf:carlduevel/asdf-k2tf\"]\ndescription = \"Kubernetes YAML to Terraform HCL converter\"\ntest = { cmd = \"k2tf --version\", expected = \"k2tf version: {{version}}\" }\n"
  },
  {
    "path": "registry/k3d.toml",
    "content": "backends = [\"aqua:k3d-io/k3d\", \"asdf:spencergilbert/asdf-k3d\"]\ndescription = \"Little helper to run CNCF's k3s in Docker\"\ntest = { cmd = \"k3d --version\", expected = \"k3d version v{{version}}\" }\n"
  },
  {
    "path": "registry/k3kcli.toml",
    "content": "description = \"K3k, Kubernetes in Kubernetes, is a tool that empowers you to create and manage isolated K3s clusters within your existing Kubernetes environment\"\ntest = { cmd = \"k3k --version\", expected = \"k3kcli version v{{version}}\" }\n\n[[backends]]\nfull = \"github:rancher/k3k\"\n\n[backends.options]\nasset_pattern = \"k3kcli-{darwin_os}-{amd64_arch}\"\nbin = \"k3k\"\nversion_prefix = \"v\"\n\n[[backends]]\nfull = \"asdf:xanmanning/asdf-k3kcli\"\n"
  },
  {
    "path": "registry/k3s.toml",
    "content": "backends = [\"aqua:k3s-io/k3s\", \"asdf:mise-plugins/mise-k3s\"]\ndescription = \"The certified Kubernetes distribution built for IoT & Edge computing\"\ntest = { cmd = \"k3s --version\", expected = \"k3s version v{{version}}\" }\n"
  },
  {
    "path": "registry/k3sup.toml",
    "content": "backends = [\"aqua:alexellis/k3sup\", \"asdf:cgroschupp/asdf-k3sup\"]\ndescription = \"bootstrap K3s over SSH in < 60s\"\n"
  },
  {
    "path": "registry/k6.toml",
    "content": "backends = [\"aqua:grafana/k6\", \"asdf:gr1m0h/asdf-k6\"]\ndescription = \"A modern load testing tool, using Go and JavaScript\"\ntest = { cmd = \"k6 --version\", expected = \"k6 v{{version}}\" }\n"
  },
  {
    "path": "registry/k9s.toml",
    "content": "backends = [\"aqua:derailed/k9s\", \"asdf:looztra/asdf-k9s\"]\ndescription = \"Kubernetes CLI To Manage Your Clusters In Style\"\n"
  },
  {
    "path": "registry/kafkactl.toml",
    "content": "backends = [\"aqua:deviceinsight/kafkactl\", \"asdf:anweber/asdf-kafkactl\"]\ndescription = \"Command Line Tool for managing Apache Kafka\"\n"
  },
  {
    "path": "registry/kapp.toml",
    "content": "backends = [\"aqua:carvel-dev/kapp\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = 'kapp is a simple deployment tool focused on the concept of \"Kubernetes application\" — a set of resources with the same label'\n"
  },
  {
    "path": "registry/kbld.toml",
    "content": "backends = [\"aqua:carvel-dev/kbld\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = \"kbld seamlessly incorporates image building and image pushing into your development and deployment workflows\"\n"
  },
  {
    "path": "registry/kcctl.toml",
    "content": "backends = [\"github:kcctl/kcctl\", \"asdf:joschi/asdf-kcctl\"]\ndescription = \"A modern and intuitive command line client for Kafka Connect\"\n"
  },
  {
    "path": "registry/kcl.toml",
    "content": "backends = [\"aqua:kcl-lang/cli\", \"asdf:mise-plugins/mise-kcl\"]\ndescription = \"The KCL Command Line Interface (CLI)\"\ntest = { cmd = \"kcl --version\", expected = \"kcl version {{version}}\" }\n"
  },
  {
    "path": "registry/kconf.toml",
    "content": "backends = [\"aqua:particledecay/kconf\", \"asdf:particledecay/asdf-kconf\"]\ndescription = \"Manage multiple kubeconfigs easily\"\n"
  },
  {
    "path": "registry/ki.toml",
    "content": "backends = [\"aqua:Kotlin/kotlin-interactive-shell\", \"asdf:comdotlinux/asdf-ki\"]\ndescription = \"Kotlin Language Interactive Shell\"\ntest = { cmd = \"ki --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/killport.toml",
    "content": "backends = [\"aqua:jkfran/killport\", \"cargo:killport\"]\ndescription = \"A command-line tool to easily kill processes running on a specified port\"\ntest = { cmd = \"killport --version\", expected = \"killport {{version}}\" }\n"
  },
  {
    "path": "registry/kind.toml",
    "content": "backends = [\"aqua:kubernetes-sigs/kind\", \"asdf:johnlayton/asdf-kind\"]\ndescription = \"Kubernetes IN Docker - local clusters for testing Kubernetes\"\ntest = { cmd = \"kind --version\", expected = \"kind version {{version}}\" }\n"
  },
  {
    "path": "registry/kiota.toml",
    "content": "backends = [\"aqua:microsoft/kiota\", \"asdf:asdf-community/asdf-kiota\"]\ndescription = \"OpenAPI based HTTP Client code generator\"\n"
  },
  {
    "path": "registry/kn.toml",
    "content": "backends = [\"aqua:knative/client\", \"asdf:joke/asdf-kn\"]\ndescription = \"Knative developer experience, docs, reference Knative CLI implementation\"\ntest = { cmd = \"kn version\", expected = \"Version:\" }\n"
  },
  {
    "path": "registry/ko.toml",
    "content": "backends = [\"aqua:ko-build/ko\", \"asdf:zasdaym/asdf-ko\"]\ndescription = \"Build and deploy Go applications on Kubernetes\"\ntest = { cmd = \"ko version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/koka.toml",
    "content": "backends = [\"github:koka-lang/koka\", \"asdf:susurri/asdf-koka\"]\ndescription = \"Koka language compiler and interpreter\"\n"
  },
  {
    "path": "registry/kompose.toml",
    "content": "backends = [\"aqua:kubernetes/kompose\", \"asdf:technikhil314/asdf-kompose\"]\ndescription = \"Go from Docker Compose to Kubernetes\"\ntest = { cmd = \"kompose version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/kopia.toml",
    "content": "backends = [\"aqua:kopia/kopia\", \"github:kopia/kopia\"]\ndescription = \"Kopia is a fast and secure open-source backup/restore tool that allows you to create encrypted snapshots of your data and save the snapshots to remote or cloud storage of your choice, to network-attached storage or server, or locally on your machine\"\ntest = { cmd = \"kopia --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/kops.toml",
    "content": "backends = [\"aqua:kubernetes/kops\", \"asdf:Antiarchitect/asdf-kops\"]\ndescription = \"Kubernetes Operations (kops) - Production Grade K8s Installation, Upgrades, and Management\"\n"
  },
  {
    "path": "registry/kotlin.toml",
    "content": "description = \"Kotlin is a modern but already mature programming language designed to make developers happier. It's concise, safe, interoperable with Java and other languages, and provides many ways to reuse code between multiple platforms for productive programming\"\n\n[[backends]]\nfull = \"github:JetBrains/kotlin\"\n\n[backends.options]\nasset_pattern = \"kotlin-compiler-*.zip\"\nbin_path = \"kotlinc/bin\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-kotlin\"\n\n[[backends]]\nfull = \"vfox:mise-plugins/vfox-kotlin\"\n"
  },
  {
    "path": "registry/kpack.toml",
    "content": "aliases = [\"kp\"]\ndescription = \"A command line interface for interacting with kpack\"\ntest = { cmd = \"kp version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:vmware-tanzu/kpack-cli\"\n\n[backends.options]\nexe = \"kp\"\n\n[[backends]]\nfull = \"asdf:asdf-community/asdf-kpack-cli\"\n"
  },
  {
    "path": "registry/kpt.toml",
    "content": "backends = [\"aqua:kptdev/kpt\", \"asdf:nlamirault/asdf-kpt\"]\ndescription = \"Automate Kubernetes Configuration Editing\"\nos = [\"linux\", \"macos\"]\n"
  },
  {
    "path": "registry/krab.toml",
    "content": "backends = [\"aqua:ohkrab/krab\", \"asdf:ohkrab/asdf-krab\"]\ndescription = \"Krab is a migration and automation tool for PostgreSQL based on HCL syntax\"\ntest = { cmd = \"krab --version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/krew.toml",
    "content": "backends = [\"aqua:kubernetes-sigs/krew\", \"asdf:bjw-s/asdf-krew\"]\ndescription = \"Find and install kubectl plugins\"\n"
  },
  {
    "path": "registry/kscript.toml",
    "content": "backends = [\"github:kscripting/kscript\", \"asdf:edgelevel/asdf-kscript\"]\ndepends = [\"kotlin\"]\ndescription = \"Scripting enhancements for Kotlin\"\ntest = { cmd = \"kscript --version 2>&1\", expected = \"Version   : {{version}}\" }\n"
  },
  {
    "path": "registry/ksops.toml",
    "content": "backends = [\"aqua:viaduct-ai/kustomize-sops\", \"asdf:janpieper/asdf-ksops\"]\ndescription = \"KSOPS - A Flexible Kustomize Plugin for SOPS Encrypted Resources\"\n"
  },
  {
    "path": "registry/ktlint.toml",
    "content": "backends = [\"aqua:pinterest/ktlint\", \"asdf:mise-plugins/mise-ktlint\"]\ndepends = [\"java\"]\ndescription = \"An anti-bikeshedding Kotlin linter with built-in formatter\"\n# test = [\"ktlint --version\", \"ktlint version {{version}}\"] # DISABLED: upstream bug - release 1.7.2 not found on GitHub\n"
  },
  {
    "path": "registry/kube-capacity.toml",
    "content": "backends = [\"aqua:robscott/kube-capacity\", \"asdf:looztra/asdf-kube-capacity\"]\ndescription = \"A simple CLI that provides an overview of the resource requests, limits, and utilization in a Kubernetes cluster\"\n"
  },
  {
    "path": "registry/kube-controller-tools.toml",
    "content": "description = \"Tools to use with the controller-runtime libraries\"\n\n[[backends]]\nfull = \"github:kubernetes-sigs/controller-tools\"\n\n[backends.options]\nexe = \"controller-gen\"\n\n[[backends]]\nfull = \"asdf:jimmidyson/asdf-kube-controller-tools\"\n"
  },
  {
    "path": "registry/kube-credential-cache.toml",
    "content": "backends = [\n  \"aqua:ryodocx/kube-credential-cache\",\n  \"asdf:ryodocx/kube-credential-cache\",\n]\ndescription = \"Accelerator cache for kubernetes access\"\n"
  },
  {
    "path": "registry/kube-linter.toml",
    "content": "backends = [\"aqua:stackrox/kube-linter\", \"asdf:devlincashman/asdf-kube-linter\"]\ndescription = \"KubeLinter is a static analysis tool that checks Kubernetes YAML files and Helm charts to ensure the applications represented in them adhere to best practices\"\n"
  },
  {
    "path": "registry/kube-score.toml",
    "content": "backends = [\"aqua:zegl/kube-score\", \"asdf:bageljp/asdf-kube-score\"]\ndescription = \"Kubernetes object analysis with recommendations for improved reliability and security. kube-score actively prevents downtime and bugs in your Kubernetes YAML and Charts. Static code analysis for Kubernetes\"\n"
  },
  {
    "path": "registry/kubebuilder.toml",
    "content": "backends = [\n  \"aqua:kubernetes-sigs/kubebuilder\",\n  \"asdf:virtualstaticvoid/asdf-kubebuilder\",\n]\ndescription = \"Kubebuilder - SDK for building Kubernetes APIs using CRDs\"\n"
  },
  {
    "path": "registry/kubecm.toml",
    "content": "backends = [\"aqua:sunny0826/kubecm\", \"asdf:samhvw8/asdf-kubecm\"]\ndescription = \"Manage your kubeconfig more easily\"\n"
  },
  {
    "path": "registry/kubecolor.toml",
    "content": "backends = [\"aqua:kubecolor/kubecolor\", \"asdf:dex4er/asdf-kubecolor\"]\ndepends = [\"kubectl\"]\ndescription = \"Colorize your kubectl output\"\ntest = { cmd = \"kubecolor --kubecolor-version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/kubeconform.toml",
    "content": "backends = [\"aqua:yannh/kubeconform\", \"asdf:lirlia/asdf-kubeconform\"]\ndescription = \"A FAST Kubernetes manifests validator, with support for Custom Resources\"\n"
  },
  {
    "path": "registry/kubectl-convert.toml",
    "content": "backends = [\n  \"aqua:kubernetes/kubernetes/kubectl-convert\",\n  \"asdf:iul1an/asdf-kubectl-convert\",\n]\ndescription = \"A plugin for Kubernetes command-line tool kubectl, which allows you to convert manifests between different API versions. This can be particularly helpful to migrate manifests to a non-deprecated api version with newer Kubernetes release\"\n"
  },
  {
    "path": "registry/kubectl-kots.toml",
    "content": "backends = [\"aqua:replicatedhq/kots\", \"asdf:ganta/asdf-kubectl-kots\"]\ndescription = \"KOTS provides the framework, tools and integrations that enable the delivery and management of 3rd-party Kubernetes applications, a.k.a. Kubernetes Off-The-Shelf (KOTS) Software\"\ntest = { cmd = \"kots version\", expected = \"Replicated KOTS {{version}}\" }\n"
  },
  {
    "path": "registry/kubectl-kuttl.toml",
    "content": "aliases = [\"kuttl\"]\nbackends = [\"aqua:kudobuilder/kuttl\", \"asdf:jimmidyson/asdf-kuttl\"]\ndescription = \"Kubernetes Test TooL (kuttl)\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"kubectl-kuttl --version\", expected = \"kubectl-kuttl version {{version}}\" }\n"
  },
  {
    "path": "registry/kubectl-rolesum.toml",
    "content": "aliases = [\"kubectl-bindrole\"]\nbackends = [\n  \"aqua:Ladicle/kubectl-rolesum\",\n  \"asdf:looztra/asdf-kubectl-bindrole\",\n]\ndescription = \"Summarize Kubernetes RBAC roles for the specified subjects\"\n"
  },
  {
    "path": "registry/kubectl.toml",
    "content": "backends = [\n  \"aqua:kubernetes/kubernetes/kubectl\",\n  \"asdf:asdf-community/asdf-kubectl\",\n]\ndescription = \"kubectl cli\"\ntest = { cmd = \"kubectl version --client\", expected = \"Client Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/kubectx.toml",
    "content": "backends = [\"aqua:ahmetb/kubectx\", \"asdf:https://gitlab.com/wt0f/asdf-kubectx\"]\ndescription = \"Faster way to switch between clusters and namespaces in kubectl\"\n"
  },
  {
    "path": "registry/kubefedctl.toml",
    "content": "backends = [\"aqua:kubernetes-retired/kubefed\", \"asdf:kvokka/asdf-kubefedctl\"]\ndescription = \"kubefedctl controls a Kubernetes Cluster Federation\"\ntest = { cmd = \"kubefedctl version\", expected = \"kubefedctl version:\" } # may not have version in output\n"
  },
  {
    "path": "registry/kubefirst.toml",
    "content": "backends = [\"github:konstructio/kubefirst\", \"asdf:Claywd/asdf-kubefirst\"]\ndescription = \"The Kubefirst CLI creates instant GitOps platforms that integrate some of the best tools in cloud native from scratch in minutes\"\n"
  },
  {
    "path": "registry/kubelogin.toml",
    "content": "backends = [\"aqua:int128/kubelogin\"]\ndescription = \"kubectl plugin for Kubernetes OpenID Connect authentication (kubectl oidc-login)\"\n"
  },
  {
    "path": "registry/kubemqctl.toml",
    "content": "backends = [\"aqua:kubemq-io/kubemqctl\", \"asdf:johnlayton/asdf-kubemqctl\"]\ndescription = \"Kubemqctl is a command line interface (CLI) for KubeMQ, Kubernetes Message Broker\"\n"
  },
  {
    "path": "registry/kubens.toml",
    "content": "backends = [\"aqua:ahmetb/kubectx/kubens\"]\ndescription = \"Faster way to switch between clusters and namespaces in kubectl\"\n"
  },
  {
    "path": "registry/kubent.toml",
    "content": "backends = [\n  \"aqua:doitintl/kube-no-trouble\",\n  \"asdf:virtualstaticvoid/asdf-kubent\",\n]\ndescription = \"Easily check your clusters for use of deprecated APIs\"\ntest = { cmd = \"kubent --version 2>&1\", expected = \"version {{version}}\" }\n"
  },
  {
    "path": "registry/kubeone.toml",
    "content": "backends = [\"aqua:kubermatic/kubeone\", \"aqua:kubermatic/kubeone\"]\ndescription = \"Kubermatic KubeOne automate cluster operations on all your cloud, on-prem, edge, and IoT environments\"\ntest = { cmd = \"kubeone version | jq -r '.kubeone.gitVersion'\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/kubergrunt.toml",
    "content": "backends = [\"aqua:gruntwork-io/kubergrunt\", \"asdf:NeoHsu/asdf-kubergrunt\"]\ndescription = \"Kubergrunt is a standalone go binary with a collection of commands to fill in the gaps between Terraform, Helm, and Kubectl. https://www.gruntwork.io\"\n"
  },
  {
    "path": "registry/kubeseal.toml",
    "content": "backends = [\n  \"aqua:bitnami-labs/sealed-secrets\",\n  \"asdf:stefansedich/asdf-kubeseal\",\n]\ndescription = \"A Kubernetes controller and tool for one-way encrypted Secrets\"\ntest = { cmd = \"kubeseal --version\", expected = \"kubeseal version: {{version}}\" }\n"
  },
  {
    "path": "registry/kubesec.toml",
    "content": "backends = [\"aqua:controlplaneio/kubesec\", \"asdf:vitalis/asdf-kubesec\"]\ndescription = \"Security risk analysis for Kubernetes resources\"\n"
  },
  {
    "path": "registry/kubeshark.toml",
    "content": "backends = [\"aqua:kubeshark/kubeshark\", \"asdf:carnei-ro/asdf-kubeshark\"]\ndescription = \"The API traffic analyzer for Kubernetes providing real-time K8s protocol-level visibility, capturing and monitoring all traffic and payloads going in, out and across containers, pods, nodes and clusters. Inspired by Wireshark, purposely built for Kubernetes\"\n"
  },
  {
    "path": "registry/kubespy.toml",
    "content": "backends = [\"aqua:pulumi/kubespy\", \"asdf:jfreeland/asdf-kubespy\"]\ndescription = \"Tools for observing Kubernetes resources in real time, powered by Pulumi\"\n"
  },
  {
    "path": "registry/kubeswitch.toml",
    "content": "backends = [\"aqua:danielfoehrKn/kubeswitch\", \"github:danielfoehrKn/kubeswitch\"]\ndescription = \"The kubectx for operators\"\ntest = { cmd = \"switcher --version\", expected = \"switcher version v{{version}}\" }\n"
  },
  {
    "path": "registry/kubeval.toml",
    "content": "backends = [\"aqua:instrumenta/kubeval\", \"asdf:stefansedich/asdf-kubeval\"]\ndescription = \"Validate your Kubernetes configuration files, supports multiple Kubernetes versions\"\n"
  },
  {
    "path": "registry/kubevela.toml",
    "content": "backends = [\"aqua:kubevela/kubevela\", \"asdf:gustavclausen/asdf-kubevela\"]\ndescription = \"The Modern Application Platform\"\ntest = { cmd = \"vela version\", expected = \"CLI Version: {{version}}\" }\n"
  },
  {
    "path": "registry/kubie.toml",
    "content": "backends = [\"aqua:sbstp/kubie\", \"asdf:johnhamelink/asdf-kubie\"]\ndescription = \"A more powerful alternative to kubectx and kubens\"\n"
  },
  {
    "path": "registry/kustomize.toml",
    "content": "backends = [\"aqua:kubernetes-sigs/kustomize\", \"asdf:Banno/asdf-kustomize\"]\ndescription = \"Customization of kubernetes YAML configurations\"\ntest = { cmd = \"kustomize version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/kwokctl.toml",
    "content": "backends = [\"aqua:kubernetes-sigs/kwok/kwokctl\"]\ndescription = \"kwokctl is a CLI tool designed to streamline the creation and management of clusters, with nodes simulated by kwok\"\ntest = { cmd = \"kwokctl --version\", expected = \"kwok version v{{version}}\" }\n"
  },
  {
    "path": "registry/kwt.toml",
    "content": "backends = [\"aqua:carvel-dev/kwt\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = \"Kubernetes Workstation Tools CLI\"\n"
  },
  {
    "path": "registry/kyverno.toml",
    "content": "backends = [\n  \"aqua:kyverno/kyverno\",\n  \"asdf:https://github.com/hobaen/asdf-kyverno-cli.git\",\n]\ndescription = \"Cloud Native Policy Management\"\n"
  },
  {
    "path": "registry/lab.toml",
    "content": "backends = [\"aqua:zaquestion/lab\", \"asdf:particledecay/asdf-lab\"]\ndescription = \"Lab wraps Git or Hub, making it simple to clone, fork, and interact with repositories on GitLab\"\n"
  },
  {
    "path": "registry/lane.toml",
    "content": "backends = [\"github:CodeReaper/lane\", \"asdf:CodeReaper/asdf-lane\"]\ndescription = \"lane is a task automation helper\"\n"
  },
  {
    "path": "registry/lazydocker.toml",
    "content": "backends = [\"aqua:jesseduffield/lazydocker\"]\ndescription = \"The lazier way to manage everything docker\"\ntest = { cmd = \"lazydocker --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/lazygit.toml",
    "content": "backends = [\"aqua:jesseduffield/lazygit\", \"asdf:nklmilojevic/asdf-lazygit\"]\ndescription = \"simple terminal UI for git commands\"\n"
  },
  {
    "path": "registry/lazyjournal.toml",
    "content": "backends = [\"aqua:Lifailon/lazyjournal\"]\ndescription = \"TUI for journalctl, file system logs, as well Docker and Podman containers for quick viewing and filtering with fuzzy find, regex support (like fzf and grep) and coloring the output, written in Go with the gocui library\"\ntest = { cmd = \"lazyjournal --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/lazyssh.toml",
    "content": "backends = [\"aqua:Adembc/lazyssh\"]\ndescription = \"A terminal-based SSH manager inspired by lazydocker and k9s - Written in go\"\ntest = { cmd = \"lazyssh --help\", expected = \"lazyssh [flags]\" }\n"
  },
  {
    "path": "registry/lefthook.toml",
    "content": "backends = [\n  \"aqua:evilmartians/lefthook\",\n  \"npm:lefthook\",\n  \"asdf:jtzero/asdf-lefthook\",\n  \"go:github.com/evilmartians/lefthook\",\n]\ndescription = \"Fast and powerful Git hooks manager for any type of projects\"\ntest = { cmd = \"lefthook version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/leiningen.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-leiningen\", \"asdf:mise-plugins/mise-lein\"]\ndescription = \"for automating Clojure projects without setting your hair on fire\"\n"
  },
  {
    "path": "registry/levant.toml",
    "content": "backends = [\"aqua:hashicorp/levant\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"An open source templating and deployment tool for HashiCorp Nomad jobs\"\n"
  },
  {
    "path": "registry/libsql-server.toml",
    "content": "description = \"server mode of libSQL, which is a fork of SQLite that is both Open Source, and Open Contributions\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"sqld --version\", expected = \"sqld sqld {{version}}\" }\n\n[[backends]]\nfull = \"github:tursodatabase/libsql\"\n\n[backends.options]\nversion_prefix = \"libsql-server-v\"\n\n[[backends]]\nfull = \"asdf:jonasb/asdf-libsql-server\"\n"
  },
  {
    "path": "registry/license-plist.toml",
    "content": "backends = [\"aqua:mono0926/LicensePlist\", \"asdf:MacPaw/asdf-license-plist\"]\ndescription = \"A license list generator of all your dependencies for iOS applications\"\nos = [\"macos\"]\ntest = { cmd = \"license-plist --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/lima.toml",
    "content": "backends = [\"aqua:lima-vm/lima\", \"asdf:CrouchingMuppet/asdf-lima\"]\ndescription = \"Linux virtual machines, with a focus on running containers\"\ntest = { cmd = \"lima --version\", expected = \"limactl version {{version}}\" }\n"
  },
  {
    "path": "registry/linkerd.toml",
    "content": "backends = [\"aqua:linkerd/linkerd2\", \"asdf:kforsthoevel/asdf-linkerd\"]\ndescription = \"Ultralight, security-first service mesh for Kubernetes. Main repo for Linkerd 2.x\"\n"
  },
  {
    "path": "registry/liqoctl.toml",
    "content": "backends = [\"aqua:liqotech/liqo\", \"asdf:pdemagny/asdf-liqoctl\"]\ndescription = \"Enable dynamic and seamless Kubernetes multi-cluster topologies\"\n"
  },
  {
    "path": "registry/liquibase.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-liquibase\"]\ndescription = \"Liquibase helps millions of developers track, version, and deploy database schema changes\"\n"
  },
  {
    "path": "registry/litestream.toml",
    "content": "backends = [\"aqua:benbjohnson/litestream\", \"asdf:threkk/asdf-litestream\"]\ndescription = \"Streaming replication for SQLite\"\n"
  },
  {
    "path": "registry/lnav.toml",
    "content": "backends = [\"aqua:tstack/lnav\"]\ndescription = \"Log file navigator\"\ntest = { cmd = \"lnav --version\", expected = \"lnav {{version}}\" }\n"
  },
  {
    "path": "registry/localstack.toml",
    "content": "description = \"The LocalStack CLI packaged using pyinstaller\"\ntest = { cmd = \"localstack --version\", expected = \"LocalStack CLI {{version}}\" }\n\n[[backends]]\nfull = \"github:localstack/localstack-cli\"\n\n[backends.options]\nexe = \"localstack\"\n"
  },
  {
    "path": "registry/loki-logcli.toml",
    "content": "backends = [\"aqua:grafana/loki/logcli\", \"asdf:comdotlinux/asdf-loki-logcli\"]\ndescription = \"LogCLI is a command-line tool for querying and exploring logs in Grafana Loki\"\n"
  },
  {
    "path": "registry/ls-lint.toml",
    "content": "backends = [\n  \"aqua:loeffel-io/ls-lint\",\n  \"npm:@ls-lint/ls-lint\",\n  \"asdf:Ameausoone/asdf-ls-lint\",\n]\ndescription = \"An extremely fast directory and filename linter - Bring some structure to your project filesystem\"\ntest = { cmd = \"ls-lint --version\", expected = \"ls-lint v{{version}}\" }\n"
  },
  {
    "path": "registry/lsd.toml",
    "content": "backends = [\"aqua:lsd-rs/lsd\", \"asdf:mise-plugins/asdf-lsd\", \"cargo:lsd\"]\ndescription = \"The next gen ls command\"\n"
  },
  {
    "path": "registry/lua-language-server.toml",
    "content": "backends = [\n  \"aqua:LuaLS/lua-language-server\",\n  \"asdf:bellini666/asdf-lua-language-server\",\n]\ndescription = \"A language server that offers Lua language support - programmed in Lua\"\n"
  },
  {
    "path": "registry/lua.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-lua\", \"asdf:mise-plugins/mise-lua\"]\ndescription = \"Lua language\"\n"
  },
  {
    "path": "registry/luajit.toml",
    "content": "backends = [\"conda:luajit\", \"asdf:mise-plugins/mise-luaJIT\"]\ndescription = \"a Just-In-Time Compiler for Lua\"\ntest = { cmd = \"luajit -v 2>&1\", expected = \"LuaJIT\" }\n"
  },
  {
    "path": "registry/luau.toml",
    "content": "backends = [\"aqua:luau-lang/luau\"]\ndescription = \"A fast, small, safe, gradually typed embeddable scripting language derived from Lua\"\ntest = { cmd = \"echo 'print(_VERSION)' | luau\", expected = \"Luau\" }\n"
  },
  {
    "path": "registry/lychee.toml",
    "content": "backends = [\"aqua:lycheeverse/lychee\", \"cargo:lychee\"]\ndescription = \"Fast, async, stream-based link checker written in Rust. Finds broken URLs and mail addresses inside Markdown, HTML, reStructuredText, websites and more\"\ntest = { cmd = \"lychee --version\", expected = \"lychee {{version}}\" }\n"
  },
  {
    "path": "registry/maestro.toml",
    "content": "backends = [\"github:mobile-dev-inc/maestro\", \"asdf:dotanuki-labs/asdf-maestro\"]\ndescription = \"Painless E2E Automation for Mobile and Web\"\n"
  },
  {
    "path": "registry/mage.toml",
    "content": "backends = [\"aqua:magefile/mage\", \"asdf:mathew-fleisch/asdf-mage\"]\ndescription = \"a Make/rake-like dev tool using Go\"\n"
  },
  {
    "path": "registry/magika.toml",
    "content": "backends = [\"cargo:magika-cli\"]\ndescription = \"Fast and accurate AI powered file content types detection\"\ntest = { cmd = \"magika --version\", expected = \"magika {{version | trim_start_matches(pat='v')}}\" }\n"
  },
  {
    "path": "registry/mago.toml",
    "content": "backends = [\"aqua:carthage-software/mago\"]\ndescription = \"A blazing fast linter, formatter, and static analyzer for PHP, written in Rust\"\ntest = { cmd = \"mago --version\", expected = \"mago {{version}}\" }\n"
  },
  {
    "path": "registry/make.toml",
    "content": "backends = [\"conda:make\", \"asdf:mise-plugins/mise-make\"]\ndescription = \"GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files\"\n"
  },
  {
    "path": "registry/mani.toml",
    "content": "backends = [\"aqua:alajmo/mani\", \"asdf:anweber/asdf-mani\"]\ndescription = \"CLI tool to help you manage repositories\"\ntest = { cmd = \"mani --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/mark.toml",
    "content": "backends = [\"github:kovetskiy/mark\", \"asdf:jfreeland/asdf-mark\"]\ndescription = \"Sync your markdown files with Confluence pages\"\n"
  },
  {
    "path": "registry/markdownlint-cli2.toml",
    "content": "backends = [\n  \"npm:markdownlint-cli2\",\n  \"asdf:paulo-ferraz-oliveira/asdf-markdownlint-cli2\",\n]\ndescription = \"A fast, flexible, configuration-based command-line interface for linting Markdown/CommonMark files with the markdownlint library\"\ntest = { cmd = \"markdownlint-cli2 --version\", expected = \"markdownlint-cli2 v{{version}}\" }\n"
  },
  {
    "path": "registry/marksman.toml",
    "content": "backends = [\"aqua:artempyanykh/marksman\"]\ndescription = \"Write Markdown with code assist and intelligence in the comfort of your favourite editor\"\ntest = { cmd = \"marksman --version\", expected = \"\" }\n"
  },
  {
    "path": "registry/marp-cli.toml",
    "content": "backends = [\"aqua:marp-team/marp-cli\", \"asdf:xataz/asdf-marp-cli\"]\ndescription = \"A CLI interface for Marp and Marpit based converters\"\n"
  },
  {
    "path": "registry/mas.toml",
    "content": "backends = [\"aqua:mas-cli/mas\"]\ndescription = \"Mac App Store command-line interface\"\nos = [\"macos\"]\ntest = { cmd = \"mas --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/mask.toml",
    "content": "backends = [\"aqua:jacobdeichert/mask\", \"asdf:aaaaninja/asdf-mask\"]\ndescription = \"A CLI task runner defined by a simple markdown file\"\ntest = { cmd = \"mask --version\", expected = \"mask {{version}}\" }\n"
  },
  {
    "path": "registry/maven.toml",
    "content": "backends = [\n  \"aqua:apache/maven\",\n  \"asdf:mise-plugins/mise-maven\",\n  \"vfox:mise-plugins/vfox-maven\",\n]\ndescription = \"Apache Maven core\"\ntest = { cmd = \"mvn --version\", expected = \"Apache Maven {{version}}\" }\n"
  },
  {
    "path": "registry/mc.toml",
    "content": "backends = [\"aqua:minio/mc\", \"asdf:mise-plugins/mise-mc\"]\ndescription = \"Unix like utilities for object store (minio)\"\n"
  },
  {
    "path": "registry/mdbook-linkcheck.toml",
    "content": "description = \"A backend for `mdbook` which will check your links for you\"\ntest = { cmd = \"mdbook-linkcheck --version\", expected = \"mdbook-linkcheck {{version}}\" }\n\n[[backends]]\nfull = \"github:Michael-F-Bryan/mdbook-linkcheck\"\n\n[backends.options]\nbin = \"mdbook-linkcheck\"\n\n[[backends]]\nfull = \"cargo:mdbook-linkcheck\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-mdbook-linkcheck\"\n"
  },
  {
    "path": "registry/mdbook.toml",
    "content": "backends = [\n  \"aqua:rust-lang/mdBook\",\n  \"asdf:cipherstash/asdf-mdbook\",\n  \"cargo:mdbook\",\n]\ndescription = \"Create book from markdown files. Like Gitbook but implemented in Rust\"\ntest = { cmd = \"mdbook --version\", expected = \"mdbook v{{version}}\" }\n"
  },
  {
    "path": "registry/melange.toml",
    "content": "backends = [\"aqua:chainguard-dev/melange\", \"asdf:omissis/asdf-melange\"]\ndescription = \"build APKs from source code\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"melange version\", expected = \"GitVersion:    v{{version}}\" }\n"
  },
  {
    "path": "registry/melt.toml",
    "content": "backends = [\"github:charmbracelet/melt\", \"asdf:chessmango/asdf-melt\"]\ndescription = \"Backup and restore Ed25519 SSH keys with seed words 🫠\"\n"
  },
  {
    "path": "registry/mermaid-ascii.toml",
    "content": "backends = [\n  \"aqua:AlexanderGrooff/mermaid-ascii\",\n  \"github:AlexanderGrooff/mermaid-ascii\",\n]\ndescription = \"Render Mermaid graphs inside your terminal\"\ntest = { cmd = \"which mermaid-ascii\", expected = \"mermaid-ascii\" }\n"
  },
  {
    "path": "registry/meson.toml",
    "content": "backends = [\"pipx:meson\", \"asdf:mise-plugins/mise-meson\"]\ndescription = \"Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible\"\n"
  },
  {
    "path": "registry/micromamba.toml",
    "content": "backends = [\"github:mamba-org/micromamba-releases\"]\ndescription = \"Lightweight conda-compatible package manager\"\ntest = { cmd = \"micromamba --version\", expected = \"{{ version | split(pat='-') | first }}\" }\n"
  },
  {
    "path": "registry/micronaut.toml",
    "content": "description = \"A modern, JVM-based, full-stack framework for building modular, easily testable microservice and serverless applications\"\n\n[[backends]]\nfull = \"github:micronaut-projects/micronaut-starter\"\n\n[backends.options]\nexe = \"mn\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-micronaut\"\n"
  },
  {
    "path": "registry/miller.toml",
    "content": "backends = [\"aqua:johnkerl/miller\"]\ndescription = \"Miller is like awk, sed, cut, join, and sort for name-indexed data such as CSV, TSV, and tabular JSON\"\ntest = { cmd = \"mlr version\", expected = \"mlr version {{version}}\" }\n"
  },
  {
    "path": "registry/mimirtool.toml",
    "content": "backends = [\n  \"aqua:grafana/mimir/mimirtool\",\n  \"asdf:asdf-community/asdf-mimirtool\",\n]\ndescription = \"Mimirtool is a command-line tool that operators and tenants can use to execute a number of common tasks that involve Grafana Mimir or Grafana Cloud Metrics\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"mimirtool version\", expected = \"Mimirtool, version {{version}}\" }\n"
  },
  {
    "path": "registry/minify.toml",
    "content": "backends = [\"aqua:tdewolff/minify\", \"asdf:axilleas/asdf-minify\"]\ndescription = \"Go minifiers for web formats\"\n"
  },
  {
    "path": "registry/minikube.toml",
    "content": "backends = [\"aqua:kubernetes/minikube\", \"asdf:alvarobp/asdf-minikube\"]\ndescription = \"Run Kubernetes locally\"\n"
  },
  {
    "path": "registry/minio.toml",
    "content": "backends = [\"conda:minio-server\", \"asdf:mise-plugins/mise-minio\"]\ndescription = \"MinIO AIStor is a high-performance S3-compatible object store licensed under the MinIO Commercial License\"\ntest = { cmd = \"minio --version 2>&1\", expected = \"minio\" }\n"
  },
  {
    "path": "registry/minishift.toml",
    "content": "backends = [\"aqua:minishift/minishift\", \"asdf:sqtran/asdf-minishift\"]\ndescription = \"Run OpenShift 3.x locally\"\n"
  },
  {
    "path": "registry/minisign.toml",
    "content": "backends = [\"aqua:jedisct1/minisign\"]\ndescription = \"A dead simple tool to sign files and verify digital signatures\"\n"
  },
  {
    "path": "registry/mint.toml",
    "content": "backends = [\"github:mint-lang/mint\", \"asdf:mint-lang/asdf-mint\"]\ndescription = \"🍃 A refreshing programming language for the front-end web\"\n"
  },
  {
    "path": "registry/mirrord.toml",
    "content": "backends = [\"aqua:metalbear-co/mirrord\", \"asdf:metalbear-co/asdf-mirrord\"]\ndescription = \"Connect your local process and your cloud environment, and run local code in cloud conditions\"\n# test = [\"mirrord --version\", \"mirrord {{version}}\"]\n"
  },
  {
    "path": "registry/mitmproxy.toml",
    "content": "backends = [\"pipx:mitmproxy\", \"asdf:mise-plugins/mise-mitmproxy\"]\ndescription = \"mitmproxy is a free and open source interactive HTTPS proxy\"\n"
  },
  {
    "path": "registry/mkcert.toml",
    "content": "backends = [\"aqua:FiloSottile/mkcert\", \"asdf:salasrod/asdf-mkcert\"]\ndescription = \"A simple zero-config tool to make locally trusted development certificates with any names you'd like\"\ntest = { cmd = \"mkcert --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/mockery.toml",
    "content": "backends = [\"aqua:vektra/mockery\", \"asdf:cabify/asdf-mockery\"]\ndescription = \"A mock code autogenerator for Go\"\n"
  },
  {
    "path": "registry/mockolo.toml",
    "content": "backends = [\"github:uber/mockolo\", \"asdf:mise-plugins/mise-mockolo\"]\ndescription = \"Efficient Mock Generator for Swift\"\ntest = { cmd = \"mockolo --help\", expected = \"Show help information\" }\n"
  },
  {
    "path": "registry/mold.toml",
    "content": "backends = [\"aqua:rui314/mold\"]\ndescription = \"Mold: A Modern Linker\"\ntest = { cmd = \"mold --version\", expected = \"mold {{version}}\" }\n"
  },
  {
    "path": "registry/mongodb.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-mongodb\", \"vfox:echocat/vfox-mongod\"]\ndescription = \"MongoDB\"\n"
  },
  {
    "path": "registry/mongosh.toml",
    "content": "backends = [\"github:mongodb-js/mongosh\", \"asdf:itspngu/asdf-mongosh\"]\ndescription = \"The MongoDB Shell\"\n"
  },
  {
    "path": "registry/mprocs.toml",
    "content": "backends = [\"aqua:pvolok/mprocs\"]\ndescription = \"Run multiple commands in parallel\"\ntest = { cmd = \"mprocs --version\", expected = \"mprocs {{version}}\" }\n"
  },
  {
    "path": "registry/mssqldef.toml",
    "content": "backends = [\"aqua:sqldef/sqldef/mssqldef\"]\ndescription = \"Idempotent schema management for MsSQL and more\"\n"
  },
  {
    "path": "registry/mutagen.toml",
    "content": "backends = [\"aqua:mutagen-io/mutagen\", \"github:mutagen-io/mutagen\"]\ndescription = \"Fast file synchronization and network forwarding for remote development\"\ntest = { cmd = \"mutagen version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/mvnd.toml",
    "content": "backends = [\"aqua:apache/maven-mvnd\", \"asdf:joschi/asdf-mvnd\"]\ndescription = \"Apache Maven Daemon\"\n"
  },
  {
    "path": "registry/mysql.toml",
    "content": "backends = [\"conda:mysql\", \"asdf:mise-plugins/mise-mysql\"]\ndescription = \"MySQL Database\"\ntest = { cmd = \"mysql --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/mysqldef.toml",
    "content": "backends = [\"aqua:sqldef/sqldef/mysqldef\"]\ndescription = \"Idempotent schema management for MySQL and more\"\n"
  },
  {
    "path": "registry/nancy.toml",
    "content": "backends = [\"aqua:sonatype-nexus-community/nancy\", \"asdf:iilyak/asdf-nancy\"]\ndescription = \"A tool to check for vulnerabilities in your Golang dependencies, powered by Sonatype OSS Index\"\n"
  },
  {
    "path": "registry/navi.toml",
    "content": "backends = [\"aqua:denisidoro/navi\", \"cargo:navi\"]\ndescription = \"An interactive cheatsheet tool for the command-line\"\ntest = { cmd = \"navi --version\", expected = \"navi {{version}}\" }\n"
  },
  {
    "path": "registry/neko.toml",
    "content": "backends = [\"github:HaxeFoundation/neko\", \"asdf:asdf-community/asdf-neko\"]\ndescription = \"The Neko Virtual Machine\"\n"
  },
  {
    "path": "registry/nelm.toml",
    "content": "backends = [\"aqua:werf/nelm\"]\ndescription = \"Nelm is a Helm 4 alternative - it is a Kubernetes deployment tool that manages Helm Charts and deploys them to Kubernetes\"\n"
  },
  {
    "path": "registry/neonctl.toml",
    "content": "backends = [\"aqua:neondatabase/neonctl\"]\ndescription = \"Neon CLI tool. The Neon CLI is a command-line interface that lets you manage Neon Serverless Postgres directly from the terminal\"\ntest = { cmd = \"neonctl --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/neovim.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-neovim\", \"aqua:neovim/neovim\"]\ndescription = \"Vim-fork focused on extensibility and usability\"\n"
  },
  {
    "path": "registry/nerdctl.toml",
    "content": "backends = [\"aqua:containerd/nerdctl\", \"asdf:dmpe/asdf-nerdctl\"]\ndescription = \"contaiNERD CTL - Docker-compatible CLI for containerd, with support for Compose, Rootless, eStargz, OCIcrypt, IPFS, \"\ntest = { cmd = \"nerdctl --version\", expected = \"nerdctl version {{version}}\" }\n"
  },
  {
    "path": "registry/newrelic.toml",
    "content": "aliases = [\"newrelic-cli\"]\nbackends = [\"aqua:newrelic/newrelic-cli\", \"asdf:NeoHsu/asdf-newrelic-cli\"]\ndescription = \"The New Relic Command Line Interface\"\ntest = { cmd = \"newrelic --version\", expected = \"newrelic version {{version}}\" }\n"
  },
  {
    "path": "registry/nfpm.toml",
    "content": "backends = [\"aqua:goreleaser/nfpm\", \"asdf:ORCID/asdf-nfpm\"]\ndescription = \"nFPM is Not FPM - a simple deb, rpm and apk packager written in Go\"\ntest = { cmd = \"nfpm --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/ni.toml",
    "content": "backends = [\"npm:@antfu/ni\"]\ndescription = \"ni - use the right package manager\"\ntest = { cmd = \"ni --version\", expected = \"@antfu/ni  \\u001B[36mv{{version}}\\u001B[39m\" }\n"
  },
  {
    "path": "registry/ninja.toml",
    "content": "backends = [\"aqua:ninja-build/ninja\", \"asdf:asdf-community/asdf-ninja\"]\ndescription = \"a small build system with a focus on speed\"\n"
  },
  {
    "path": "registry/node.toml",
    "content": "backends = [\"core:node\"]\ndescription = \"Node.js® is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts (Builtin plugin)\"\ndetect = [\"package.json\", \".nvmrc\", \".node-version\"]\n"
  },
  {
    "path": "registry/nomad-pack.toml",
    "content": "description = \"Nomad Pack is a templating and packaging tool used with HashiCorp Nomad\"\ntest = { cmd = \"nomad-pack version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"http:nomad-pack\"\n\n[backends.options]\nurl = 'https://releases.hashicorp.com/nomad-pack/{{ version }}/nomad-pack_{{ version }}_{{ os(macos=\"darwin\") }}_{{ arch(x64=\"amd64\") }}.zip'\nversion_expr = 'fromJSON(body).versions | keys() | sortVersions()'\nversion_list_url = \"https://releases.hashicorp.com/nomad-pack/index.json\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-hashicorp\"\n"
  },
  {
    "path": "registry/nomad.toml",
    "content": "backends = [\"aqua:hashicorp/nomad\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"Nomad is an easy-to-use, flexible, and performant workload orchestrator that can deploy a mix of microservice, batch, containerized, and non-containerized applications. Nomad is easy to operate and scale and has native Consul and Vault integrations\"\n"
  },
  {
    "path": "registry/notation.toml",
    "content": "backends = [\"aqua:notaryproject/notation\", \"asdf:bodgit/asdf-notation\"]\ndescription = \"A CLI tool to sign and verify artifacts\"\n"
  },
  {
    "path": "registry/nova.toml",
    "content": "backends = [\"aqua:FairwindsOps/nova\", \"asdf:elementalvoid/asdf-nova\"]\ndescription = \"Find outdated or deprecated Helm charts running in your cluster\"\n"
  },
  {
    "path": "registry/npm.toml",
    "content": "backends = [\"npm:npm\"]\ndescription = \"the package manager for JavaScript\"\nidiomatic_files = [\"package.json\"]\noverrides = [\"node\"]\ntest = { cmd = \"npm --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/nsc.toml",
    "content": "backends = [\"github:nats-io/nsc\", \"asdf:dex4er/asdf-nsc\"]\ndescription = \"Tool for creating nkey/jwt based configurations\"\n"
  },
  {
    "path": "registry/numbat.toml",
    "content": "backends = [\"aqua:sharkdp/numbat\", \"cargo:numbat-cli\"]\ndescription = \"A statically typed programming language for scientific computations with first class support for physical dimensions and units\"\ntest = { cmd = \"numbat --version\", expected = \"numbat {{version}}\" }\n"
  },
  {
    "path": "registry/oapi-codegen.toml",
    "content": "backends = [\n  \"go:github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen\",\n  \"asdf:dylanrayboss/asdf-oapi-codegen\",\n]\ndescription = \"oapi-codegen is a command-line tool and library to convert OpenAPI specifications to Go code, be it server-side implementations, API clients, or simply HTTP models\"\n"
  },
  {
    "path": "registry/oauth2c.toml",
    "content": "backends = [\"aqua:cloudentity/oauth2c\"]\ndescription = \"User-friendly OAuth2 CLI\"\ntest = { cmd = \"oauth2c version 2>&1\", expected = \"oauth2c version {{version}}\" }\n"
  },
  {
    "path": "registry/oc.toml",
    "content": "backends = [\"conda:openshift-cli\", \"asdf:mise-plugins/mise-oc\"]\ndescription = \"OpenShift Client CLI (oc)\"\ntest = { cmd = \"oc version --client 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/oci.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-oci\"]\ndescription = \"Oracle Cloud Infrastructure CLI\"\n"
  },
  {
    "path": "registry/octosql.toml",
    "content": "backends = [\"github:cube2222/octosql\"]\ndescription = \"OctoSQL is a query tool that allows you to join, analyse and transform data from multiple databases and file formats using SQL\"\ntest = { cmd = \"octosql --version\", expected = \"octosql version {{version}}\" }\n"
  },
  {
    "path": "registry/odin.toml",
    "content": "description = \"Odin Programming Language\"\n\n[[backends]]\nfull = \"github:odin-lang/Odin\"\n\n[backends.options]\nexe = \"odin\"\n\n[[backends]]\nfull = \"asdf:jtakakura/asdf-odin\"\n"
  },
  {
    "path": "registry/odo.toml",
    "content": "backends = [\"aqua:redhat-developer/odo\", \"asdf:rm3l/asdf-odo\"]\ndescription = \"A fast, and iterative CLI tool for container-based application development\"\n"
  },
  {
    "path": "registry/oh-my-posh.toml",
    "content": "backends = [\"aqua:JanDeDobbeleer/oh-my-posh\"]\ndescription = \"The most customizable and fastest prompt engine for any shell\"\ntest = { cmd = \"oh-my-posh version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/oha.toml",
    "content": "backends = [\"aqua:hatoo/oha\", \"github:hatoo/oha\"]\ndescription = \"Ohayou(おはよう), HTTP load generator, inspired by rakyll/hey with tui animation\"\ntest = { cmd = \"oha --version\", expected = \"oha {{version}}\" }\n"
  },
  {
    "path": "registry/okta-aws.toml",
    "content": "aliases = [\"okta-aws-cli\"]\nbackends = [\n  \"aqua:okta/okta-aws-cli\",\n  \"asdf:bennythejudge/asdf-plugin-okta-aws-cli\",\n]\ndescription = \"A CLI for having Okta as the IdP for AWS CLI operations\"\n"
  },
  {
    "path": "registry/okteto.toml",
    "content": "backends = [\"aqua:okteto/okteto\", \"asdf:BradenM/asdf-okteto\"]\ndescription = \"Develop your applications directly in your Kubernetes Cluster\"\n"
  },
  {
    "path": "registry/ollama.toml",
    "content": "backends = [\"aqua:ollama/ollama\", \"asdf:virtualstaticvoid/asdf-ollama\"]\ndescription = \"Get up and running with Llama 3.1, Mistral, Gemma 2, and other large language models\"\n"
  },
  {
    "path": "registry/om.toml",
    "content": "backends = [\"aqua:pivotal-cf/om\", \"asdf:mise-plugins/tanzu-plug-in-for-asdf\"]\ndescription = \"General command line utility for working with VMware Tanzu Operations Manager\"\ntest = { cmd = \"om version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/omnictl.toml",
    "content": "backends = [\"aqua:siderolabs/omni/omnictl\"]\ndescription = \"CLI for Omni - SideroLabs' Kubernetes management platform for bare metal deployments\"\ntest = { cmd = \"omnictl --version\", expected = \"omnictl version v{{version}}\" }\n"
  },
  {
    "path": "registry/onyx.toml",
    "content": "backends = [\"github:onyx-lang/onyx\", \"asdf:jtakakura/asdf-onyx\"]\ndescription = \"The compiler and developer toolchain for Onyx\"\n"
  },
  {
    "path": "registry/opa.toml",
    "content": "backends = [\"aqua:open-policy-agent/opa\", \"asdf:tochukwuvictor/asdf-opa\"]\ndescription = \"Open Policy Agent (OPA) is an open source, general-purpose policy engine\"\n"
  },
  {
    "path": "registry/opam.toml",
    "content": "description = \"(ocaml) opam is a source-based package manager. It supports multiple simultaneous compiler installations, flexible package constraints, and a Git-friendly development workflow\"\ntest = { cmd = \"opam --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:ocaml/opam\"\n\n[backends.options]\nasset_pattern = \"opam-*-{gnu_arch}-{os}\"\n\n[[backends]]\nfull = \"asdf:asdf-community/asdf-opam\"\n"
  },
  {
    "path": "registry/openbao.toml",
    "content": "description = \"OpenBao exists to provide a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys\"\n\n[[backends]]\nfull = \"github:openbao/openbao\"\n\n[backends.options]\nexe = \"bao\"\n"
  },
  {
    "path": "registry/opencode.toml",
    "content": "backends = [\"aqua:anomalyco/opencode\"]\ndescription = \"AI coding agent, built for the terminal\"\ntest = { cmd = \"opencode --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/openfaas-cli.toml",
    "content": "backends = [\"aqua:openfaas/faas-cli\", \"asdf:zekker6/asdf-faas-cli\"]\ndescription = \"Official CLI for OpenFaaS\"\n"
  },
  {
    "path": "registry/opengrep.toml",
    "content": "backends = [\"aqua:opengrep/opengrep\"]\ndescription = \"Static code analysis engine to find security issues in code\"\ntest = { cmd = \"opengrep --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/opensearch-cli.toml",
    "content": "backends = [\n  \"github:opensearch-project/opensearch-cli\",\n  \"asdf:mise-plugins/mise-opensearch-cli\",\n]\ndescription = \"A full-featured command line interface (CLI) for OpenSearch\"\ntest = { cmd = \"opensearch-cli --version\", expected = \"opensearch-cli version {{version}}\" }\n"
  },
  {
    "path": "registry/openshift-install.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-openshift-install\"]\ndescription = \"Install an OpenShift 4.x cluster\"\n"
  },
  {
    "path": "registry/opentofu.toml",
    "content": "backends = [\"aqua:opentofu/opentofu\", \"asdf:virtualroot/asdf-opentofu\"]\ndescription = \"OpenTofu lets you declaratively manage your cloud infrastructure\"\nidiomatic_files = [\".opentofu-version\"]\ntest = { cmd = \"tofu --version\", expected = \"OpenTofu v{{version}}\" }\n"
  },
  {
    "path": "registry/operator-sdk.toml",
    "content": "backends = [\n  \"aqua:operator-framework/operator-sdk\",\n  \"asdf:Medium/asdf-operator-sdk\",\n]\ndescription = \"SDK for building Kubernetes applications. Provides high level APIs, useful abstractions, and project scaffolding\"\n"
  },
  {
    "path": "registry/opsgenie-lamp.toml",
    "content": "description = \"OpsGenie Lamp with Go SDK\"\ntest = { cmd = \"opsgenie-lamp --version\", expected = \"lamp version \" } # 3.1.4 reports 3.2.0\n\n[[backends]]\nfull = \"github:opsgenie/opsgenie-lamp\"\n\n[backends.options]\nbin = \"opsgenie-lamp\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-opsgenie-lamp\"\n"
  },
  {
    "path": "registry/oras.toml",
    "content": "backends = [\"aqua:oras-project/oras\", \"asdf:bodgit/asdf-oras\"]\ndescription = \"ORAS CLI\"\n"
  },
  {
    "path": "registry/ormolu.toml",
    "content": "backends = [\"github:tweag/ormolu\"]\ndescription = \"A formatter for Haskell source code\"\ntest = { cmd = \"ormolu --version\", expected = \"ormolu {{version}}\" }\n"
  },
  {
    "path": "registry/orval.toml",
    "content": "backends = [\"npm:orval\"]\ndescription = \"Generate type-safe TypeScript clients from OpenAPI specifications provided by https://orval.dev\"\ntest = { cmd = \"orval --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/osv-scanner.toml",
    "content": "backends = [\"aqua:google/osv-scanner\"]\ndescription = \"Vulnerability scanner written in Go which uses the data provided by https://osv.dev\"\ntest = { cmd = \"osv-scanner --version\", expected = \"osv-scanner version: {{version}}\" }\n"
  },
  {
    "path": "registry/overmind.toml",
    "content": "backends = [\"github:DarthSim/overmind\", \"go:github.com/DarthSim/overmind/v2\"]\ndescription = \"Process manager for Procfile-based applications and tmux\"\n"
  },
  {
    "path": "registry/oxfmt.toml",
    "content": "backends = [\"npm:oxfmt\"]\ndescription = \"This is the formatter for oxc.\"\ntest = { cmd = \"oxfmt --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/oxipng.toml",
    "content": "backends = [\"aqua:oxipng/oxipng\", \"cargo:oxipng\"]\ndescription = \"Oxipng is a multithreaded lossless PNG/APNG compression optimizer\"\ntest = { cmd = \"oxipng --version\", expected = \"oxipng {{version}}\" }\n"
  },
  {
    "path": "registry/oxker.toml",
    "content": "backends = [\"aqua:mrjackwills/oxker\", \"cargo:oxker\"]\ndescription = \"A simple tui to view & control docker containers\"\ntest = { cmd = \"oxker --version\", expected = \"oxker {{version}}\" }\n"
  },
  {
    "path": "registry/oxlint.toml",
    "content": "# aqua cannot support oxlint 1.17.0 or later.\n# See https://github.com/oxc-project/oxc/discussions/14452#discussioncomment-14631344\nbackends = [\"npm:oxlint\", \"aqua:oxc-project/oxc/oxlint\"]\ndescription = \"This is the linter for oxc.\"\ntest = { cmd = \"oxlint --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/pachctl.toml",
    "content": "backends = [\"aqua:pachyderm/pachyderm\", \"asdf:abatilo/asdf-pachctl\"]\ndescription = \"Data-Centric Pipelines and Data Versioning\"\ntest = { cmd = \"pachctl help\", expected = \"\" } # version subcommand fails with invalid configuration\n"
  },
  {
    "path": "registry/packer.toml",
    "content": "backends = [\"aqua:hashicorp/packer\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"Packer is a tool for creating identical machine images for multiple platforms from a single source configuration\"\nidiomatic_files = [\".packer-version\"]\ntest = { cmd = \"packer --version\", expected = \"Packer v{{version}}\" }\n"
  },
  {
    "path": "registry/pandoc.toml",
    "content": "backends = [\"github:jgm/pandoc\", \"asdf:Fbrisset/asdf-pandoc\"]\ndescription = \"Universal markup converter\"\n"
  },
  {
    "path": "registry/patat.toml",
    "content": "backends = [\"github:jaspervdj/patat\", \"asdf:airtonix/asdf-patat\"]\ndescription = \"Terminal-based presentations using Pandoc\"\n"
  },
  {
    "path": "registry/pdm.toml",
    "content": "backends = [\"pipx:pdm\", \"asdf:1oglop1/asdf-pdm\"]\ndescription = \"A modern Python package and dependency manager supporting the latest PEP standards\"\ntest = { cmd = \"pdm --version\", expected = \"PDM, version {{version}}\" }\n"
  },
  {
    "path": "registry/peco.toml",
    "content": "backends = [\"aqua:peco/peco\", \"asdf:asdf-community/asdf-peco\"]\ndescription = \"Simplistic interactive filtering tool\"\n"
  },
  {
    "path": "registry/periphery.toml",
    "content": "backends = [\"aqua:peripheryapp/periphery\", \"asdf:mise-plugins/mise-periphery\"]\ndescription = \"A tool to identify unused code in Swift projects\"\n"
  },
  {
    "path": "registry/perl.toml",
    "content": "backends = [\"aqua:skaji/relocatable-perl\", \"asdf:ouest/asdf-perl\"]\ndescription = \"self-contained, portable perl binaries\"\n"
  },
  {
    "path": "registry/php.toml",
    "content": "backends = [\"asdf:mise-plugins/asdf-php\", \"vfox:mise-plugins/vfox-php\"]\ndescription = \"popular general-purpose scripting language that is especially suited to web development. Fast, flexible and pragmatic, PHP powers everything from your blog to the most popular websites in the world\"\n"
  },
  {
    "path": "registry/pi.toml",
    "content": "backends = [\"github:badlogic/pi-mono\", \"npm:@mariozechner/pi-coding-agent\"]\ndescription = \"Pi is a minimal terminal coding harness\"\ntest = { cmd = \"pi --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/pinact.toml",
    "content": "backends = [\"aqua:suzuki-shunsuke/pinact\"]\ndescription = \"pinact is a CLI to edit GitHub Workflow and Composite action files and pin versions of Actions and Reusable Workflows. pinact can also update their versions and verify version annotations\"\ntest = { cmd = \"pinact version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/pint.toml",
    "content": "backends = [\"aqua:cloudflare/pint\", \"asdf:sam-burrell/asdf-pint\"]\ndescription = \"Prometheus rule linter/validator\"\n"
  },
  {
    "path": "registry/pipectl.toml",
    "content": "backends = [\"aqua:pipe-cd/pipecd/pipectl\", \"asdf:pipe-cd/asdf-pipectl\"]\ndescription = \"The One CD for All {applications, platforms, operations}\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"pipectl version\", expected = \"Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/pipenv.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-pipenv\", \"pipx:pipenv\"]\ndepends = [\"python\"]\ndescription = \"Python Development Workflow for Humans\"\ntest = { cmd = \"pipenv --version\", expected = \"pipenv, version {{version}}\" }\n"
  },
  {
    "path": "registry/pipx.toml",
    "content": "backends = [\"aqua:pypa/pipx\", \"asdf:mise-plugins/mise-pipx\"]\ndepends = [\"python\"]\ntest = { cmd = \"pipx --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/pitchfork.toml",
    "content": "backends = [\"aqua:jdx/pitchfork\"]\ndescription = \"Daemons with DX\"\ntest = { cmd = \"pitchfork --version\", expected = \"pitchfork {{version}}\" }\n"
  },
  {
    "path": "registry/pivnet.toml",
    "content": "backends = [\n  \"aqua:pivotal-cf/pivnet-cli\",\n  \"asdf:mise-plugins/tanzu-plug-in-for-asdf\",\n]\ndescription = \"CLI to interact with Tanzu Network API V2 interface\"\ntest = { cmd = \"pivnet version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/pixi.toml",
    "content": "backends = [\"github:prefix-dev/pixi\"]\ndescription = \"Package management made easy\"\ntest = { cmd = \"pixi -V\", expected = \"pixi {{version}}\" }\n"
  },
  {
    "path": "registry/pkl.toml",
    "content": "backends = [\"aqua:apple/pkl\", \"asdf:mise-plugins/asdf-pkl\"]\ndescription = \"A configuration as code language with rich validation and tooling\"\ntest = { cmd = \"pkl --version\", expected = \"Pkl {{version}}\" }\n"
  },
  {
    "path": "registry/please.toml",
    "content": "backends = [\"aqua:thought-machine/please\", \"asdf:asdf-community/asdf-please\"]\ndescription = \"High-performance extensible build system for reproducible multi-language builds\"\n"
  },
  {
    "path": "registry/pluto.toml",
    "content": "backends = [\"aqua:FairwindsOps/pluto\", \"asdf:FairwindsOps/asdf-pluto\"]\ndescription = \"A cli tool to help discover deprecated apiVersions in Kubernetes\"\ntest = { cmd = \"pluto version\", expected = \"Version:{{version}}\" }\n"
  },
  {
    "path": "registry/pnpm.toml",
    "content": "backends = [\"aqua:pnpm/pnpm\", \"npm:pnpm\"]\ndescription = \"Fast, disk space efficient package manager\"\ndetect = [\"pnpm-lock.yaml\", \"pnpm-workspace.yaml\"]\nidiomatic_files = [\"package.json\"]\ntest = { cmd = \"pnpm --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/podman-tui.toml",
    "content": "backends = [\"github:containers/podman-tui\"]\ndescription = \"Podman Terminal UI\"\ntest = { cmd = \"podman-tui version\", expected = \"podman-tui v{{version}}\" }\n"
  },
  {
    "path": "registry/podman.toml",
    "content": "description = \"Podman: A tool for managing OCI containers and pods\"\n\n[[backends]]\nfull = \"github:containers/podman\"\n\n[[backends]]\nfull = \"asdf:tvon/asdf-podman\"\n"
  },
  {
    "path": "registry/poetry.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-poetry\", \"pipx:poetry\"]\ndescription = \"Python packaging and dependency management made easy\"\ndetect = [\"poetry.lock\"]\ntest = { cmd = \"poetry --version\", expected = \"Poetry (version {{version}})\" }\n"
  },
  {
    "path": "registry/polaris.toml",
    "content": "backends = [\"aqua:FairwindsOps/polaris\", \"asdf:particledecay/asdf-polaris\"]\ndescription = \"Validation of best practices in your Kubernetes clusters\"\n"
  },
  {
    "path": "registry/popeye.toml",
    "content": "backends = [\"aqua:derailed/popeye\", \"asdf:nlamirault/asdf-popeye\"]\ndescription = \"A Kubernetes cluster resource sanitizer\"\n"
  },
  {
    "path": "registry/porter.toml",
    "content": "description = \"CNAB bundle authoring and management tool\"\ntest = { cmd = \"porter version\", expected = \"porter v{{version}}\" }\n\n[[backends]]\nfull = \"github:getporter/porter\"\n\n[backends.options]\nasset_pattern = \"porter-{{ os(macos='darwin') }}-{{ arch(x64='amd64') }}{% if os() == 'windows' %}.exe{% endif %}\"\nbin = \"porter\"\n\n[backends.options.platforms.windows-x64]\nbin = \"porter.exe\"\n\n[backends.options.platforms.windows-arm64]\nbin = \"porter.exe\"\n"
  },
  {
    "path": "registry/portless.toml",
    "content": "backends = [\"npm:portless\"]\ndescription = \"Replace port numbers with stable, named .localhost URLs. For humans and agents.\"\ntest = { cmd = \"portless --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/postgres.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-postgres\",\n  \"asdf:mise-plugins/mise-postgres\",\n]\ndescription = \"PostgreSQL is a powerful, open source object-relational database system with over 35 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance\"\n"
  },
  {
    "path": "registry/powerline-go.toml",
    "content": "backends = [\"aqua:justjanne/powerline-go\", \"asdf:dex4er/asdf-powerline-go\"]\ndescription = \"A beautiful and useful low-latency prompt for your shell, written in go\"\n"
  },
  {
    "path": "registry/powerpipe.toml",
    "content": "backends = [\"aqua:turbot/powerpipe\", \"asdf:jc00ke/asdf-powerpipe\"]\ndescription = \"Powerpipe: Dashboards for DevOps. Visualize cloud configurations. Assess security posture against a massive library of benchmarks. Build custom dashboards with code\"\n"
  },
  {
    "path": "registry/powershell-core.toml",
    "content": "aliases = [\"powershell\"]\nbackends = [\n  \"aqua:PowerShell/PowerShell\",\n  \"asdf:daveneeley/asdf-powershell-core\",\n]\ndescription = \"PowerShell for every system\"\ntest = { cmd = \"pwsh --version\", expected = \"PowerShell {{version}}\" }\n"
  },
  {
    "path": "registry/pre-commit.toml",
    "content": "backends = [\n  \"aqua:pre-commit/pre-commit\",\n  \"asdf:jonathanmorley/asdf-pre-commit\",\n  \"pipx:pre-commit\",\n]\ndescription = \"A framework for managing and maintaining multi-language pre-commit hooks\"\ntest = { cmd = \"pre-commit --version\", expected = \"pre-commit {{version}}\" }\n"
  },
  {
    "path": "registry/prek.toml",
    "content": "backends = [\"aqua:j178/prek\"]\ntest = { cmd = \"prek --version\", expected = \"prek {{version}}\" }\n"
  },
  {
    "path": "registry/prettier.toml",
    "content": "backends = [\"npm:prettier\"]\ndescription = \"Prettier is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary\"\ntest = { cmd = \"prettier --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/process-compose.toml",
    "content": "backends = [\"github:F1bonacc1/process-compose\"]\ndescription = \"Process Compose is a simple and flexible scheduler and orchestrator to manage non-containerized applications.\"\ntest = { cmd = \"process-compose version --short\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/promtool.toml",
    "content": "backends = [\"aqua:prometheus/prometheus\", \"asdf:asdf-community/asdf-promtool\"]\ndescription = \"The Prometheus monitoring system and time series database\"\ntest = { cmd = \"promtool --version\", expected = \"promtool, version {{version}}\" }\n"
  },
  {
    "path": "registry/protoc-gen-connect-go.toml",
    "content": "backends = [\n  \"go:connectrpc.com/connect/cmd/protoc-gen-connect-go\",\n  \"asdf:dylanrayboss/asdf-protoc-gen-connect-go\",\n]\ndescription = \"The Go implementation of Connect: Protobuf RPC that works\"\n"
  },
  {
    "path": "registry/protoc-gen-go-grpc.toml",
    "content": "backends = [\n  \"aqua:grpc/grpc-go/protoc-gen-go-grpc\",\n  \"asdf:pbr0ck3r/asdf-protoc-gen-go-grpc\",\n]\ndescription = \"This tool generates Go language bindings of services in protobuf definition files for gRPC\"\ntest = { cmd = \"protoc-gen-go-grpc --version\", expected = \"protoc-gen-go-grpc {{version}}\" }\n"
  },
  {
    "path": "registry/protoc-gen-go.toml",
    "content": "backends = [\n  \"aqua:protocolbuffers/protobuf-go/protoc-gen-go\",\n  \"asdf:pbr0ck3r/asdf-protoc-gen-go\",\n]\ndescription = \"protoc-gen-go is a plugin for the Google protocol buffer compiler to generate Go code\"\n"
  },
  {
    "path": "registry/protoc-gen-js.toml",
    "content": "description = \"This directory contains the JavaScript Protocol Buffers runtime library\"\n\n[[backends]]\nfull = \"github:protocolbuffers/protobuf-javascript\"\n\n[backends.options]\nexe = \"protoc-gen-js\"\n\n[[backends]]\nfull = \"asdf:pbr0ck3r/asdf-protoc-gen-js\"\n"
  },
  {
    "path": "registry/protoc-gen-validate.toml",
    "content": "backends = [\n  \"aqua:bufbuild/protoc-gen-validate\",\n  \"go:github.com/envoyproxy/protoc-gen-validate\",\n]\ndescription = \"Protocol Buffer Validation - Being replaced by github.com/bufbuild/protovalidate\"\ntest = { cmd = \"which protoc-gen-validate\", expected = \"protoc-gen-validate\" }\n"
  },
  {
    "path": "registry/protoc.toml",
    "content": "aliases = [\"protobuf\"]\nbackends = [\n  \"aqua:protocolbuffers/protobuf/protoc\",\n  \"asdf:paxosglobal/asdf-protoc\",\n]\ndescription = \"Protocol Buffers Compiler - Google's data interchange format\"\n"
  },
  {
    "path": "registry/protolint.toml",
    "content": "backends = [\"aqua:yoheimuta/protolint\", \"asdf:spencergilbert/asdf-protolint\"]\ndescription = \"A pluggable linter and fixer to enforce Protocol Buffer style and conventions\"\n"
  },
  {
    "path": "registry/psc-package.toml",
    "content": "backends = [\"github:purescript/psc-package\", \"asdf:nsaunders/asdf-psc-package\"]\ndescription = \"A package manager for PureScript based on package sets\"\n"
  },
  {
    "path": "registry/psqldef.toml",
    "content": "backends = [\"aqua:sqldef/sqldef/psqldef\"]\ndescription = \"Idempotent schema management for PostgreSQL\"\n"
  },
  {
    "path": "registry/pulumi.toml",
    "content": "backends = [\"aqua:pulumi/pulumi\", \"asdf:canha/asdf-pulumi\"]\ndescription = \"Pulumi - Infrastructure as Code in any programming language\"\ntest = { cmd = \"pulumi version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/purerl.toml",
    "content": "backends = [\"github:purerl/purerl\", \"asdf:GoNZooo/asdf-purerl\"]\ndescription = \"Erlang backend for the PureScript compiler\"\n"
  },
  {
    "path": "registry/purescript.toml",
    "content": "description = \"A strongly-typed language that compiles to JavaScript\"\n\n[[backends]]\nfull = \"github:purescript/purescript\"\n\n[backends.options]\nexe = \"purs\"\n\n[[backends]]\nfull = \"asdf:jrrom/asdf-purescript\"\n"
  },
  {
    "path": "registry/purty.toml",
    "content": "backends = [\"npm:purty\"]\ndescription = \"PureScript pretty-printer\"\ntest = { cmd = \"purty version\", expected = \"Purty version: {{version}}\" }\n"
  },
  {
    "path": "registry/python.toml",
    "content": "backends = [\"core:python\"]\ndescription = \"python language\"\ndetect = [\"pyproject.toml\", \".python-version\", \"setup.py\", \"requirements.txt\"]\n"
  },
  {
    "path": "registry/qdns.toml",
    "content": "backends = [\"github:natesales/q\", \"asdf:moritz-makandra/asdf-plugin-qdns\"]\ndescription = \"A tiny command line DNS client with support for UDP, TCP, DoT, DoH, DoQ and ODoH\"\n"
  },
  {
    "path": "registry/qsv.toml",
    "content": "backends = [\"github:dathere/qsv\", \"asdf:vjda/asdf-qsv\"]\ndescription = \"Blazing-fast Data-Wrangling toolkit\"\ntest = { cmd = \"qsv --version\", expected = \"qsv {{version}}\" }\n"
  },
  {
    "path": "registry/quarkus.toml",
    "content": "backends = [\"github:quarkusio/quarkus\", \"asdf:mise-plugins/mise-quarkus\"]\ndescription = \"The quarkus command lets you create projects, manage extensions and do essential build and development tasks using the underlying project build tool\"\n"
  },
  {
    "path": "registry/quicktype.toml",
    "content": "backends = [\"npm:quicktype\"]\ndescription = \"Generate types and converters from JSON, Schema, and GraphQL provided by https://quicktype.io\"\ntest = { cmd = \"quicktype --version\", expected = \"quicktype version {{version}}\" }\n"
  },
  {
    "path": "registry/railway.toml",
    "content": "description = \"Railway CLI\"\ntest = { cmd = \"railway --version\", expected = \"railway {{version}}\" }\n\n[[backends]]\nfull = \"github:railwayapp/cli\"\n\n[backends.options]\nexe = \"railway\"\n\n[[backends]]\nfull = \"cargo:railwayapp\"\n"
  },
  {
    "path": "registry/rancher.toml",
    "content": "backends = [\"aqua:rancher/cli\", \"asdf:abinet/asdf-rancher\"]\ndescription = \"Rancher CLI\"\ntest = { cmd = \"rancher --version\", expected = \"rancher version v{{version}}\" }\n"
  },
  {
    "path": "registry/rbac-lookup.toml",
    "content": "backends = [\"aqua:FairwindsOps/rbac-lookup\", \"asdf:looztra/asdf-rbac-lookup\"]\ndescription = \"Easily find roles and cluster roles attached to any user, service account, or group name in your Kubernetes cluster\"\n"
  },
  {
    "path": "registry/rclone.toml",
    "content": "backends = [\"aqua:rclone/rclone\", \"asdf:johnlayton/asdf-rclone\"]\ndescription = '\"rsync for cloud storage\" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Yandex Files'\ntest = { cmd = \"rclone version\", expected = \"rclone v{{version}}\" }\n"
  },
  {
    "path": "registry/rebar.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-rebar\"]\ndepends = [\"erlang\"]\ndescription = \"Erlang build tool that makes it easy to compile and test Erlang applications and releases\"\n"
  },
  {
    "path": "registry/reckoner.toml",
    "content": "backends = [\"github:FairwindsOps/reckoner\", \"asdf:FairwindsOps/asdf-reckoner\"]\ndescription = \"Declaratively install and manage multiple Helm chart releases\"\n"
  },
  {
    "path": "registry/redis.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-redis\", \"asdf:mise-plugins/mise-redis\"]\ndescription = \"Cache & in-memory datastore\"\n"
  },
  {
    "path": "registry/redo.toml",
    "content": "backends = [\"aqua:barthr/redo\", \"asdf:chessmango/asdf-redo\"]\ndescription = \"Redo is the ultimate tool to create reusable functions from your history in an interactive way\"\ntest = { cmd = \"which redo\", expected = \"redo\" }\n"
  },
  {
    "path": "registry/redpanda-connect.toml",
    "content": "aliases = [\"benthos\"]\nbackends = [\"aqua:redpanda-data/connect\", \"asdf:benthosdev/benthos-asdf\"]\ndescription = \"Fancy stream processing made operationally mundane\"\ntest = { cmd = \"redpanda-connect --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/reg.toml",
    "content": "backends = [\"aqua:genuinetools/reg\", \"asdf:looztra/asdf-reg\"]\ndescription = \"Docker registry v2 command line client and repo listing generator with security checks\"\n"
  },
  {
    "path": "registry/regal.toml",
    "content": "backends = [\"aqua:open-policy-agent/regal\", \"asdf:mise-plugins/mise-regal\"]\ndescription = \"Regal is a linter and language server for Rego, with the goal of making your Rego magnificent\"\n"
  },
  {
    "path": "registry/regctl.toml",
    "content": "backends = [\"aqua:regclient/regclient/regctl\", \"asdf:ORCID/asdf-regctl\"]\ndescription = \"Docker and OCI Registry Client in Go and tooling using those libraries\"\n"
  },
  {
    "path": "registry/regsync.toml",
    "content": "backends = [\"aqua:regclient/regclient/regsync\", \"asdf:rsrchboy/asdf-regsync\"]\ndescription = \"regsync is a registry synchronization utility used to update mirrors of OCI compatible container registries\"\n"
  },
  {
    "path": "registry/release-plz.toml",
    "content": "backends = [\n  \"aqua:release-plz/release-plz\",\n  \"github:release-plz/release-plz\",\n  \"cargo:release-plz\",\n]\ndescription = \"Publish Rust crates from CI with a Release PR.\"\ntest = { cmd = \"release-plz --version\", expected = \"release-plz {{version}}\" }\n"
  },
  {
    "path": "registry/restic.toml",
    "content": "backends = [\"aqua:restic/restic\", \"asdf:xataz/asdf-restic\"]\ndescription = \"Fast, secure, efficient backup program\"\ntest = { cmd = \"restic version\", expected = \"restic {{version}}\" }\n"
  },
  {
    "path": "registry/restish.toml",
    "content": "backends = [\"aqua:rest-sh/restish\", \"go:github.com/danielgtaylor/restish\"]\ndescription = \"Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in\"\ntest = { cmd = \"restish --version\", expected = \"restish version {{version}}\" }\n"
  },
  {
    "path": "registry/resvg.toml",
    "content": "backends = [\"aqua:linebender/resvg\", \"cargo:resvg\"]\ndescription = \"An SVG rendering library.\"\ntest = { cmd = \"resvg --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/revive.toml",
    "content": "backends = [\"aqua:mgechev/revive\", \"asdf:bjw-s/asdf-revive\"]\ndescription = \"~6x faster, stricter, configurable, extensible, and beautiful drop-in replacement for golint\"\n"
  },
  {
    "path": "registry/richgo.toml",
    "content": "backends = [\"aqua:kyoh86/richgo\", \"asdf:paxosglobal/asdf-richgo\"]\ndescription = \"Enrich `go test` outputs with text decorations\"\n"
  },
  {
    "path": "registry/ripgrep-all.toml",
    "content": "backends = [\"aqua:phiresky/ripgrep-all\", \"cargo:ripgrep_all\"]\ndescription = \"rga: ripgrep, but also search in PDFs, E-Books, Office documents, zip, tar.gz, etc\"\ntest = { cmd = \"rga --version\", expected = \"ripgrep-all {{version}}\" }\n"
  },
  {
    "path": "registry/ripgrep.toml",
    "content": "aliases = [\"rg\"]\nbackends = [\n  \"aqua:BurntSushi/ripgrep\",\n  \"asdf:https://gitlab.com/wt0f/asdf-ripgrep\",\n  \"cargo:ripgrep\",\n]\ndescription = \"ripgrep recursively searches directories for a regex pattern while respecting your gitignore\"\ntest = { cmd = \"rg --version\", expected = \"ripgrep {{version}}\" }\n"
  },
  {
    "path": "registry/ripsecrets.toml",
    "content": "backends = [\n  \"aqua:sirwart/ripsecrets\",\n  \"asdf:https://github.com/boris-smidt-klarrio/asdf-ripsecrets\",\n]\ndescription = \"A command-line tool to prevent committing secret keys into your source code\"\ntest = { cmd = \"ripsecrets --version\", expected = \"ripsecrets {{version}}\" }\n"
  },
  {
    "path": "registry/rke.toml",
    "content": "backends = [\"aqua:rancher/rke\", \"asdf:particledecay/asdf-rke\"]\ndescription = \"Rancher Kubernetes Engine (RKE), an extremely simple, lightning fast Kubernetes distribution that runs entirely within containers\"\n"
  },
  {
    "path": "registry/rmz.toml",
    "content": "backends = [\"aqua:SUPERCILEX/fuc/rmz\"]\ndescription = \"A zippy alternative to rm, a tool to remove files and directories\"\ntest = { cmd = \"rmz --version\", expected = \"rmz {{version}}\" }\n"
  },
  {
    "path": "registry/rpk.toml",
    "content": "backends = [\"aqua:redpanda-data/redpanda\"]\ndescription = \"Redpanda CLI and toolbox\"\ntest = { cmd = \"rpk --version\", expected = \"rpk version (Redpanda CLI): v{{version}}\" }\n"
  },
  {
    "path": "registry/ruby.toml",
    "content": "backends = [\"core:ruby\"]\ndescription = \"Ruby language\"\ndetect = [\"Gemfile\", \".ruby-version\", \"Rakefile\"]\n"
  },
  {
    "path": "registry/ruff.toml",
    "content": "backends = [\"aqua:astral-sh/ruff\", \"asdf:simhem/asdf-ruff\"]\ndescription = \"An extremely fast Python linter and code formatter, written in Rust\"\ntest = { cmd = \"ruff --version\", expected = \"ruff {{version}}\" }\n"
  },
  {
    "path": "registry/rumdl.toml",
    "content": "backends = [\"github:rvben/rumdl\"]\ndescription = \"Markdown Linter and Formatter written in Rust\"\ntest = { cmd = \"rumdl --version\", expected = \"rumdl {{version}}\" }\n"
  },
  {
    "path": "registry/rust-analyzer.toml",
    "content": "backends = [\"aqua:rust-lang/rust-analyzer\", \"asdf:Xyven1/asdf-rust-analyzer\"]\ndescription = \"A Rust compiler front-end for IDEs\"\n"
  },
  {
    "path": "registry/rust.toml",
    "content": "backends = [\"core:rust\", \"asdf:code-lever/asdf-rust\"]\ndescription = \"Rust language\"\n"
  },
  {
    "path": "registry/rustic.toml",
    "content": "backends = [\"aqua:rustic-rs/rustic\", \"cargo:rustic-rs\"]\ndescription = \"rustic - fast, encrypted, and deduplicated backups powered by Rust\"\ntest = { cmd = \"rustic --version\", expected = \"rustic v{{version}}\" }\n"
  },
  {
    "path": "registry/rye.toml",
    "content": "backends = [\"aqua:astral-sh/rye\", \"asdf:Azuki-bar/asdf-rye\", \"cargo:rye\"]\ndescription = \"a Hassle-Free Python Experience\"\n"
  },
  {
    "path": "registry/s5cmd.toml",
    "content": "backends = [\"aqua:peak/s5cmd\"]\ndescription = \"Parallel S3 and local filesystem execution tool\"\ntest = { cmd = \"s5cmd version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/saml2aws.toml",
    "content": "backends = [\"aqua:Versent/saml2aws\", \"asdf:elementalvoid/asdf-saml2aws\"]\ndescription = \"CLI tool which enables you to login and retrieve AWS temporary credentials using a SAML IDP\"\n"
  },
  {
    "path": "registry/sampler.toml",
    "content": "backends = [\"aqua:sqshq/sampler\"]\ndescription = \"Tool for shell commands execution, visualization and alerting. Configured with a simple YAML file\"\ntest = { cmd = \"sampler --version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/sbt.toml",
    "content": "backends = [\"conda:sbt\", \"asdf:mise-plugins/mise-sbt\"]\ndepends = [\"java\"]\ndescription = \"sbt, the interactive build tool\"\ntest = { cmd = \"sbt --version 2>&1\", expected = \"sbt\" }\n"
  },
  {
    "path": "registry/scala-cli.toml",
    "content": "backends = [\"github:VirtusLab/scala-cli\", \"asdf:mise-plugins/mise-scala-cli\"]\ndescription = \"Scala CLI is a command-line tool to interact with the Scala language. It lets you compile, run, test, and package your Scala code (and more!)\"\n"
  },
  {
    "path": "registry/scala.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-scala\", \"vfox:mise-plugins/vfox-scala\"]\ndescription = \"Scala language\"\n"
  },
  {
    "path": "registry/scaleway.toml",
    "content": "aliases = [\"scaleway-cli\"]\nbackends = [\n  \"aqua:scaleway/scaleway-cli\",\n  \"asdf:albarralnunez/asdf-plugin-scaleway-cli\",\n]\ndescription = \"Command Line Interface for Scaleway\"\n"
  },
  {
    "path": "registry/scalingo-cli.toml",
    "content": "backends = [\"aqua:Scalingo/cli\", \"asdf:brandon-welsch/asdf-scalingo-cli\"]\ndescription = \"Command Line client for Scalingo PaaS\"\n"
  },
  {
    "path": "registry/scarb.toml",
    "content": "backends = [\"github:software-mansion/scarb\", \"asdf:software-mansion/asdf-scarb\"]\ndescription = \"The Cairo package manager\"\n"
  },
  {
    "path": "registry/sccache.toml",
    "content": "backends = [\n  \"aqua:mozilla/sccache\",\n  \"asdf:emersonmx/asdf-sccache\",\n  \"cargo:sccache\",\n]\ndescription = \"sccache is ccache with cloud storage\"\ntest = { cmd = \"sccache --version\", expected = \"sccache {{version}}\" }\n"
  },
  {
    "path": "registry/schemacrawler.toml",
    "content": "description = \"Free database schema discovery and comprehension tool\"\n#test = [\"schemacrawler.sh --version\", \"SchemaCrawler {{version}}\"]\n\n[[backends]]\nfull = \"github:schemacrawler/SchemaCrawler\"\n\n[backends.options]\nexe = \"schemacrawler.sh\"\n"
  },
  {
    "path": "registry/scie-pants.toml",
    "content": "backends = [\"github:pantsbuild/scie-pants\", \"asdf:robzr/asdf-scie-pants\"]\ndescription = \"Protects your Pants from the elements\"\n"
  },
  {
    "path": "registry/scooter.toml",
    "content": "backends = [\"aqua:thomasschafer/scooter\", \"cargo:scooter\"]\ndescription = \"Interactive find-and-replace in the terminal\"\ntest = { cmd = \"scooter --version\", expected = \"scooter {{version}}\" }\n"
  },
  {
    "path": "registry/scorecard.toml",
    "content": "backends = [\"aqua:ossf/scorecard\"]\ndescription = \"OpenSSF Scorecard - Security health metrics for Open Source\"\ntest = { cmd = \"scorecard version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/sd.toml",
    "content": "backends = [\"aqua:chmln/sd\", \"cargo:sd\"]\ndescription = \"Intuitive find & replace CLI (sed alternative)\"\n# test = { cmd = \"sd --version\", expected = \"sd {{version}}\" } # upstream bug: v1.1.0 reports \"sd 1.0.0\"\n"
  },
  {
    "path": "registry/semgrep.toml",
    "content": "backends = [\"pipx:semgrep\", \"asdf:mise-plugins/mise-semgrep\"]\ndescription = \"Lightweight static analysis for many languages. Find bug variants with patterns that look like source code.\"\ntest = { cmd = \"semgrep --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/semver.toml",
    "content": "backends = [\n  \"aqua:fsaintjacques/semver-tool\",\n  \"vfox:mise-plugins/vfox-semver\",\n  \"asdf:mathew-fleisch/asdf-semver\",\n]\ndescription = \"semver bash implementation\"\ntest = { cmd = \"semver --version\", expected = \"semver: {{version}}\" }\n"
  },
  {
    "path": "registry/sentinel.toml",
    "content": "description = \"Sentinel is a policy as code tool that lets you control what users of HashiCorp products are allowed to do. It enforces policies proactively, preventing end users from deploying changes that are not allowed\"\ntest = { cmd = \"sentinel version\", expected = \"Sentinel v{{version}}\" }\n\n[[backends]]\nfull = \"http:sentinel\"\n\n[backends.options]\nurl = 'https://releases.hashicorp.com/sentinel/{{ version }}/sentinel_{{ version }}_{{ os(macos=\"darwin\") }}_{{ arch(x64=\"amd64\") }}.zip'\nversion_expr = 'fromJSON(body).versions | keys() | sortVersions()'\nversion_list_url = \"https://releases.hashicorp.com/sentinel/index.json\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-hashicorp\"\n"
  },
  {
    "path": "registry/sentry.toml",
    "content": "aliases = [\"sentry-cli\"]\nbackends = [\"aqua:getsentry/sentry-cli\"]\ndescription = \"A command line utility to work with Sentry\"\ntest = { cmd = \"sentry-cli --version\", expected = \"sentry-cli {{version}}\" }\n"
  },
  {
    "path": "registry/serverless.toml",
    "content": "backends = [\"npm:serverless\", \"asdf:mise-plugins/mise-serverless\"]\ndescription = \"Serverless Framework\"\n"
  },
  {
    "path": "registry/setup-envtest.toml",
    "content": "backends = [\n  \"aqua:kubernetes-sigs/controller-runtime/setup-envtest\",\n  \"asdf:mise-plugins/mise-setup-envtest\",\n]\ndescription = \"This is a small tool that manages binaries for envtest. It can be used to download new binaries, list currently installed and available ones, and clean up versions\"\n"
  },
  {
    "path": "registry/shell2http.toml",
    "content": "backends = [\"aqua:msoap/shell2http\", \"asdf:ORCID/asdf-shell2http\"]\ndescription = \"Executing shell commands via HTTP server\"\n"
  },
  {
    "path": "registry/shellcheck.toml",
    "content": "backends = [\"aqua:koalaman/shellcheck\", \"asdf:luizm/asdf-shellcheck\"]\ndescription = \"ShellCheck, a static analysis tool for shell scripts\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"shellcheck --version\", expected = \"version: {{version}}\" }\n"
  },
  {
    "path": "registry/shellspec.toml",
    "content": "backends = [\"aqua:shellspec/shellspec\", \"asdf:poikilotherm/asdf-shellspec\"]\ndescription = \"A full-featured BDD unit testing framework for bash, ksh, zsh, dash and all POSIX shells\"\n"
  },
  {
    "path": "registry/shfmt.toml",
    "content": "backends = [\n  \"aqua:mvdan/sh\",\n  \"asdf:luizm/asdf-shfmt\",\n  \"go:mvdan.cc/sh/v3/cmd/shfmt\",\n]\ndescription = \"A shell parser, formatter, and interpreter with bash support; includes shfmt\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"shfmt --version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/signadot.toml",
    "content": "description = \"Command-line interface for Signadot\"\ntest = { cmd = \"signadot --version\", expected = \"signadot version v{{version}}\" }\n\n[[backends]]\nfull = \"github:signadot/cli\"\n\n[backends.options]\nexe = \"signadot\"\n"
  },
  {
    "path": "registry/sinker.toml",
    "content": "backends = [\"aqua:plexsystems/sinker\", \"asdf:elementalvoid/asdf-sinker\"]\ndescription = \"A tool to sync images from one container registry to another\"\n"
  },
  {
    "path": "registry/skaffold.toml",
    "content": "backends = [\n  \"aqua:GoogleContainerTools/skaffold\",\n  \"asdf:nklmilojevic/asdf-skaffold\",\n]\ndescription = \"Easy and Repeatable Kubernetes Development\"\n"
  },
  {
    "path": "registry/skate.toml",
    "content": "backends = [\"aqua:charmbracelet/skate\", \"asdf:chessmango/asdf-skate\"]\ndescription = \"A personal key value store\"\n"
  },
  {
    "path": "registry/skeema.toml",
    "content": "backends = [\"aqua:skeema/skeema\"]\ndescription = \"Declarative pure-SQL schema management for MySQL and MariaDB (Community Edition)\"\ntest = { cmd = \"skeema version | awk -F, '{print $1}'\", expected = \"skeema version {{version}}-community\" }\n"
  },
  {
    "path": "registry/sloth.toml",
    "content": "backends = [\"aqua:slok/sloth\", \"asdf:slok/asdf-sloth\"]\ndescription = \"Easy and simple Prometheus SLO (service level objectives) generator\"\n"
  },
  {
    "path": "registry/slsa-verifier.toml",
    "content": "backends = [\n  \"aqua:slsa-framework/slsa-verifier\",\n  \"github:slsa-framework/slsa-verifier\",\n  \"go:github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier\",\n]\ndescription = \"Verify provenance from SLSA compliant builders\"\ntest = { cmd = \"slsa-verifier version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/smithy.toml",
    "content": "backends = [\"aqua:smithy-lang/smithy\", \"asdf:mise-plugins/mise-smithy\"]\ndescription = \"Smithy is a language for defining services and SDKs\"\ntest = { cmd = \"smithy --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/snyk.toml",
    "content": "backends = [\"aqua:snyk/cli\", \"github:snyk/cli\", \"asdf:nirfuchs/asdf-snyk\"]\ndescription = \"Snyk CLI scans and monitors your projects for security vulnerabilities\"\n"
  },
  {
    "path": "registry/soft-serve.toml",
    "content": "description = \"The mighty, self-hostable Git server for the command line\"\n\n[[backends]]\nfull = \"github:charmbracelet/soft-serve\"\n\n[backends.options]\nexe = \"soft\"\n\n[[backends]]\nfull = \"asdf:chessmango/asdf-soft-serve\"\n"
  },
  {
    "path": "registry/solidity.toml",
    "content": "description = \"Solidity, the Smart Contract Programming Language\"\n\n[[backends]]\nfull = \"github:ethereum/solidity\"\n\n[backends.options]\nexe = \"solc\"\n\n[[backends]]\nfull = \"asdf:diegodorado/asdf-solidity\"\n"
  },
  {
    "path": "registry/sonar-scanner-cli.toml",
    "content": "backends = [\n  \"aqua:SonarSource/sonar-scanner-cli\",\n  \"asdf:virtualstaticvoid/asdf-sonarscanner\",\n]\ndescription = \"Scanner CLI for SonarQube (Server, Cloud)\"\ntest = { cmd = \"sonar-scanner --version\", expected = \"SonarScanner CLI {{version}}\" }\n"
  },
  {
    "path": "registry/sonobuoy.toml",
    "content": "backends = [\"github:vmware-tanzu/sonobuoy\", \"asdf:Nick-Triller/asdf-sonobuoy\"]\ndescription = \"Sonobuoy is a diagnostic tool that makes it easier to understand the state of a Kubernetes cluster by running a set of Kubernetes conformance tests and other plugins in an accessible and non-destructive manner\"\n"
  },
  {
    "path": "registry/sops.toml",
    "content": "backends = [\"aqua:getsops/sops\", \"asdf:mise-plugins/mise-sops\"]\ndescription = \"Simple and flexible tool for managing secrets\"\n"
  },
  {
    "path": "registry/sopstool.toml",
    "content": "backends = [\"aqua:ibotta/sopstool\", \"asdf:elementalvoid/asdf-sopstool\"]\ndescription = \"SOPS multi-file wrapper\"\n"
  },
  {
    "path": "registry/soracom.toml",
    "content": "backends = [\"github:soracom/soracom-cli\", \"asdf:gr1m0h/asdf-soracom\"]\ndescription = \"Provides `soracom` command, a command line tool for calling SORACOM APIs\"\n"
  },
  {
    "path": "registry/sourcery.toml",
    "content": "description = \"Meta-programming for Swift, stop writing boilerplate code\"\n\n[[backends]]\nfull = \"github:krzysztofzablocki/Sourcery\"\n\n[backends.options]\nexe = \"bin/sourcery\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-sourcery\"\n"
  },
  {
    "path": "registry/spacectl.toml",
    "content": "backends = [\"aqua:spacelift-io/spacectl\", \"asdf:bodgit/asdf-spacectl\"]\ndescription = \"Spacelift client and CLI\"\n"
  },
  {
    "path": "registry/spago.toml",
    "content": "backends = [\"github:purescript/spago\", \"asdf:jrrom/asdf-spago\"]\ndescription = \"🍝 PureScript package manager and build tool\"\n"
  },
  {
    "path": "registry/spark.toml",
    "content": "backends = [\"aqua:apache/spark\", \"asdf:mise-plugins/mise-spark\"]\ndepends = [\"java\"]\ndescription = \"Apache Spark - A unified analytics engine for large-scale data processing\"\n"
  },
  {
    "path": "registry/specstory.toml",
    "content": "backends = [\"aqua:specstoryai/getspecstory\"]\ndescription = \"You don’t write prompts. You author intent. Enhance your AI development workflow with SpecStory\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"specstory --version\", expected = \"{{version}} (SpecStory)\" }\n"
  },
  {
    "path": "registry/spectral.toml",
    "content": "backends = [\"aqua:stoplightio/spectral\", \"asdf:vbyrd/asdf-spectral\"]\ndescription = \"A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI (v3.1, v3.0, and v2.0), Arazzo v1.0, as well as AsyncAPI v2.x\"\n"
  },
  {
    "path": "registry/spin.toml",
    "content": "backends = [\"aqua:spinnaker/spin\", \"asdf:pavloos/asdf-spin\"]\ndescription = \"Spinnaker CLI\"\n"
  },
  {
    "path": "registry/spring-boot.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-spring-boot\"]\ndescription = \"Spring Boot CLI\"\n"
  },
  {
    "path": "registry/spruce.toml",
    "content": "backends = [\"aqua:geofffranks/spruce\", \"asdf:woneill/asdf-spruce\"]\ndescription = \"Standalone, daemon-less, unprivileged Dockerfile and OCI compatible container image builder\"\n"
  },
  {
    "path": "registry/sqlc.toml",
    "content": "backends = [\"github:sqlc-dev/sqlc\"]\ndescription = \"Generate type-safe code from SQL\"\ntest = { cmd = \"sqlc version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/sqlite.toml",
    "content": "backends = [\"conda:sqlite\", \"asdf:mise-plugins/mise-sqlite\"]\ndescription = \"SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. SQLite is the most used database engine in the world\"\n"
  },
  {
    "path": "registry/sqlite3def.toml",
    "content": "backends = [\"aqua:sqldef/sqldef/sqlite3def\"]\ndescription = \"The easiest idempotent SQLite3 Server schema management by SQL\"\n"
  },
  {
    "path": "registry/sshi.toml",
    "content": "backends = [\"aqua:aakso/ssh-inscribe/sshi\"]\ndescription = \"SSH CA Client/Server\"\ntest = { cmd = \"sshi version\", expected = \"local: {{version}}\" }\n"
  },
  {
    "path": "registry/sshuttle.toml",
    "content": "backends = [\"pipx:sshuttle\", \"asdf:mise-plugins/mise-sshuttle\"]\ndescription = \"sshuttle: where transparent proxy meets VPN meets ssh\"\n"
  },
  {
    "path": "registry/sst.toml",
    "content": "backends = [\"github:sst/sst\"]\ndescription = \"Build full-stack apps on your own infrastructure\"\ntest = { cmd = \"sst version\", expected = \"sst {{version}}\" }\n"
  },
  {
    "path": "registry/stack.toml",
    "content": "backends = [\"aqua:commercialhaskell/stack\", \"asdf:mise-plugins/mise-ghcup\"]\ndescription = \"The Haskell Tool Stack\"\ntest = { cmd = \"stack --version\", expected = \"Version {{version}}\" }\n"
  },
  {
    "path": "registry/starboard.toml",
    "content": "backends = [\n  \"aqua:aquasecurity/starboard\",\n  \"asdf:zufardhiyaulhaq/asdf-starboard\",\n]\ndescription = \"Kubernetes-native security toolkit\"\n"
  },
  {
    "path": "registry/starknet-foundry-sncast.toml",
    "content": "description = \"All-in-one tool for interacting with Starknet smart contracts, sending transactions and getting chain data\"\n\n[[backends]]\nfull = \"github:foundry-rs/starknet-foundry\"\n\n[backends.options]\nexe = \"sncast\"\n"
  },
  {
    "path": "registry/starknet-foundry.toml",
    "content": "description = \"Starknet testing framework (like Truffle, Hardhat and DappTools but for Starknet)\"\n\n[[backends]]\nfull = \"github:foundry-rs/starknet-foundry\"\n\n[backends.options]\nexe = \"snforge\"\n"
  },
  {
    "path": "registry/starship.toml",
    "content": "backends = [\n  \"aqua:starship/starship\",\n  \"asdf:gr1m0h/asdf-starship\",\n  \"cargo:starship\",\n]\ndescription = \"The minimal, blazing-fast, and infinitely customizable prompt for any shell\"\ntest = { cmd = \"starship --version\", expected = \"starship {{version}}\" }\n"
  },
  {
    "path": "registry/staticcheck.toml",
    "content": "backends = [\n  \"aqua:dominikh/go-tools/staticcheck\",\n  \"asdf:pbr0ck3r/asdf-staticcheck\",\n  \"go:honnef.co/go/tools/cmd/staticcheck\",\n]\ndescription = \"Staticcheck - The advanced Go linter\"\ntest = { cmd = \"staticcheck --version\", expected = \"staticcheck {{version}}\" }\n"
  },
  {
    "path": "registry/steampipe.toml",
    "content": "backends = [\"aqua:turbot/steampipe\", \"asdf:carnei-ro/asdf-steampipe\"]\ndescription = \"Use SQL to instantly query your cloud services (AWS, Azure, GCP and more). Open source CLI. No DB required\"\ntest = { cmd = \"steampipe --version\", expected = \"Steampipe v{{version}}\" }\n"
  },
  {
    "path": "registry/step.toml",
    "content": "backends = [\"aqua:smallstep/cli\", \"asdf:log2/asdf-step\"]\ndescription = \"A zero trust swiss army knife for working with X509, OAuth, JWT, OATH OTP, etc\"\n"
  },
  {
    "path": "registry/stern.toml",
    "content": "backends = [\"aqua:stern/stern\", \"asdf:looztra/asdf-stern\"]\ndescription = \"⎈ Multi pod and container log tailing for Kubernetes -- Friendly fork of https://github.com/wercker/stern\"\n"
  },
  {
    "path": "registry/stripe.toml",
    "content": "aliases = [\"stripe-cli\"]\nbackends = [\"aqua:stripe/stripe-cli\", \"asdf:offbyone/asdf-stripe\"]\ndescription = \"A command-line tool for Stripe\"\n"
  },
  {
    "path": "registry/stylua.toml",
    "content": "backends = [\n  \"aqua:JohnnyMorganz/StyLua\",\n  \"asdf:jc00ke/asdf-stylua\",\n  \"cargo:stylua\",\n]\ndescription = \"A Lua code formatter\"\ntest = { cmd = \"stylua --version\", expected = \"stylua {{version}}\" }\n"
  },
  {
    "path": "registry/sui.toml",
    "content": "backends = [\"github:MystenLabs/sui\", \"asdf:placeholder-soft/asdf-sui\"]\ndescription = \"ui, a next-generation smart contract platform with high throughput, low latency, and an asset-oriented programming model powered by the Move programming language\"\n"
  },
  {
    "path": "registry/supabase.toml",
    "content": "backends = [\"aqua:supabase/cli\"]\ndescription = \"Supabase CLI. Manage postgres migrations, run Supabase locally, deploy edge functions. Postgres backups. Generating types from your database schema\"\ntest = { cmd = \"supabase --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/superfile.toml",
    "content": "backends = [\"aqua:yorukot/superfile\"]\ndescription = \"Pretty fancy and modern terminal file manager\"\ntest = { cmd = \"spf --version\", expected = \"superfile version v{{version}}\" }\n"
  },
  {
    "path": "registry/superhtml.toml",
    "content": "backends = [\"github:kristoff-it/superhtml\"]\ndescription = \"HTML Validator, Formatter, LSP, and Templating Language Library\"\ntest = { cmd = \"superhtml version 2>&1\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/sver.toml",
    "content": "backends = [\"aqua:mitoma/sver\", \"asdf:robzr/asdf-sver\"]\ndescription = \"Version generator based on source code\"\n"
  },
  {
    "path": "registry/svu.toml",
    "content": "backends = [\"aqua:caarlos0/svu\", \"asdf:asdf-community/asdf-svu\"]\ndescription = \"semantic version utility\"\n"
  },
  {
    "path": "registry/swag.toml",
    "content": "backends = [\"aqua:swaggo/swag\", \"asdf:behoof4mind/asdf-swag\"]\ndescription = \"Automatically generate RESTful API documentation with Swagger 2.0 for Go\"\n"
  },
  {
    "path": "registry/swift-package-list.toml",
    "content": "backends = [\n  \"github:FelixHerrmann/swift-package-list\",\n  \"spm:FelixHerrmann/swift-package-list\",\n  \"asdf:mise-plugins/mise-swift-package-list\",\n]\ndescription = \"A command-line tool to get all used Swift Package dependencies\"\n"
  },
  {
    "path": "registry/swift.toml",
    "content": "backends = [\"core:swift\"]\ndescription = \"Swift Lang (Core)\"\nos = [\"linux\", \"macos\"]\n"
  },
  {
    "path": "registry/swiftformat.toml",
    "content": "description = \"A command-line tool and Xcode Extension for formatting Swift code\"\ntest = { cmd = \"swiftformat --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:nicklockwood/SwiftFormat\"\n\n[backends.options]\nno_app = true\nrename_exe = \"swiftformat\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-swiftformat\"\n"
  },
  {
    "path": "registry/swiftgen.toml",
    "content": "description = \"The Swift code generator for your assets, storyboards, Localizable.strings, … — Get rid of all String-based APIs!\"\n\n[[backends]]\nfull = \"github:SwiftGen/SwiftGen\"\n\n[backends.options]\nexe = \"swiftgen/bin/swiftgen\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-swiftgen\"\n"
  },
  {
    "path": "registry/swiftlint.toml",
    "content": "backends = [\"aqua:realm/SwiftLint\", \"asdf:mise-plugins/mise-swiftlint\"]\ndescription = \"A tool to enforce Swift style and conventions\"\ntest = { cmd = \"swiftlint --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/syft.toml",
    "content": "backends = [\"aqua:anchore/syft\", \"asdf:davidgp1701/asdf-syft\"]\ndescription = \"CLI tool and library for generating a Software Bill of Materials from container images and filesystems\"\n"
  },
  {
    "path": "registry/tailpipe.toml",
    "content": "backends = [\"aqua:turbot/tailpipe\"]\ndescription = \"select * from logs! Tailpipe is an open source SIEM for instant log insights, powered by DuckDB. Analyze millions of events in seconds, right from your terminal\"\ntest = { cmd = \"tailpipe --version\", expected = \"Tailpipe v{{version}}\" }\n"
  },
  {
    "path": "registry/talhelper.toml",
    "content": "backends = [\"aqua:budimanjojo/talhelper\", \"asdf:bjw-s/asdf-talhelper\"]\ndescription = \"A tool to help creating Talos kubernetes cluster\"\n"
  },
  {
    "path": "registry/talosctl.toml",
    "content": "aliases = [\"talos\"]\nbackends = [\"aqua:siderolabs/talos\"]\ndescription = \"Talos is a modern OS for Kubernetes. talosctl is a CLI for out-of-band management of Kubernetes nodes created by Talos\"\ntest = { cmd = \"talosctl version --client --short\", expected = \"Talos v{{version}}\" }\n"
  },
  {
    "path": "registry/tanka.toml",
    "content": "backends = [\"aqua:grafana/tanka\", \"asdf:trotttrotttrott/asdf-tanka\"]\ndescription = \"Flexible, reusable and concise configuration for Kubernetes\"\n"
  },
  {
    "path": "registry/tanzu.toml",
    "content": "description = \"The Tanzu Core CLI project provides the core functionality of the Tanzu CLI. The CLI is based on a plugin architecture where CLI command functionality can be delivered through independently developed plugin binaries\"\ntest = { cmd = \"tanzu version\", expected = \"version: v{{version}}\" }\n\n[[backends]]\nfull = \"github:vmware-tanzu/tanzu-cli\"\n\n[backends.options]\nrename_exe = \"tanzu\"\n"
  },
  {
    "path": "registry/taplo.toml",
    "content": "backends = [\"aqua:tamasfe/taplo\", \"cargo:taplo-cli\"]\ndescription = \"A TOML toolkit written in Rust\"\ntest = { cmd = \"taplo --version\", expected = \"taplo {{version}}\" }\n"
  },
  {
    "path": "registry/task.toml",
    "content": "backends = [\"aqua:go-task/task\", \"asdf:particledecay/asdf-task\"]\ndescription = \"A task runner / simpler Make alternative written in Go\"\ntest = { cmd = \"task --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/tbls.toml",
    "content": "backends = [\"aqua:k1LoW/tbls\"]\ndescription = \"A CI-Friendly tool to document a database written in Go\"\ntest = { cmd = \"tbls version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/tctl.toml",
    "content": "backends = [\"aqua:temporalio/tctl\", \"asdf:eko/asdf-tctl\"]\ndescription = \"Temporal CLI\"\n"
  },
  {
    "path": "registry/tekton.toml",
    "content": "aliases = [\"tekton-cli\"]\nbackends = [\"aqua:tektoncd/cli\", \"asdf:johnhamelink/asdf-tekton-cli\"]\ndescription = \"A CLI for interacting with Tekton\"\n"
  },
  {
    "path": "registry/teleport-community.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-teleport-community\"]\ndescription = \"Teleport provides connectivity, authentication, access controls and audit for infrastructure (community version)\"\n"
  },
  {
    "path": "registry/teleport-ent.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-teleport-ent\"]\ndescription = \"Teleport provides connectivity, authentication, access controls and audit for infrastructure (Enterprise version)\"\n"
  },
  {
    "path": "registry/telepresence.toml",
    "content": "backends = [\n  \"aqua:telepresenceio/telepresence\",\n  \"asdf:pirackr/asdf-telepresence\",\n]\ndescription = \"Local development against a remote Kubernetes or OpenShift cluster\"\n"
  },
  {
    "path": "registry/television.toml",
    "content": "backends = [\"aqua:alexpasmantier/television\"]\ndescription = \"The revolution will (not) be televised\"\ntest = { cmd = \"tv --version\", expected = \"television {{version}}\" }\n"
  },
  {
    "path": "registry/teller.toml",
    "content": "backends = [\"aqua:tellerops/teller\", \"asdf:pdemagny/asdf-teller\"]\ndescription = \"Cloud native secrets management for developers - never leave your command line for secrets\"\n"
  },
  {
    "path": "registry/temporal.toml",
    "content": "backends = [\"aqua:temporalio/temporal\", \"asdf:asdf-community/asdf-temporal\"]\ndescription = \"Temporal service and CLI\"\n"
  },
  {
    "path": "registry/terradozer.toml",
    "content": "backends = [\"github:chenrui333/terradozer\"]\ndescription = \"Terraform destroy without configuration files\"\nos = [\"linux\", \"macos\"]\n"
  },
  {
    "path": "registry/terraform-docs.toml",
    "content": "backends = [\n  \"aqua:terraform-docs/terraform-docs\",\n  \"asdf:looztra/asdf-terraform-docs\",\n]\ndescription = \"Generate documentation from Terraform modules in various output formats\"\n"
  },
  {
    "path": "registry/terraform-ls.toml",
    "content": "backends = [\"aqua:hashicorp/terraform-ls\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"Terraform Language Server\"\n"
  },
  {
    "path": "registry/terraform-lsp.toml",
    "content": "backends = [\n  \"aqua:juliosueiras/terraform-lsp\",\n  \"asdf:bartlomiejdanek/asdf-terraform-lsp\",\n]\ndescription = \"Language Server Protocol for Terraform\"\n"
  },
  {
    "path": "registry/terraform-validator.toml",
    "content": "backends = [\n  \"aqua:thazelart/terraform-validator\",\n  \"asdf:looztra/asdf-terraform-validator\",\n]\ndescription = \"A norms and conventions validator for Terraform\"\n"
  },
  {
    "path": "registry/terraform.toml",
    "content": "backends = [\n  \"aqua:hashicorp/terraform\",\n  \"asdf:mise-plugins/mise-hashicorp\",\n  \"vfox:mise-plugins/vfox-terraform\",\n]\ndescription = \"Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned\"\nidiomatic_files = [\".terraform-version\"]\ntest = { cmd = \"terraform version\", expected = \"Terraform v{{version}}\" }\n"
  },
  {
    "path": "registry/terraformer.toml",
    "content": "backends = [\n  \"aqua:GoogleCloudPlatform/terraformer\",\n  \"asdf:gr1m0h/asdf-terraformer\",\n]\ndescription = \"CLI tool to generate terraform files from existing infrastructure (reverse Terraform). Infrastructure to Code\"\n"
  },
  {
    "path": "registry/terragrunt.toml",
    "content": "backends = [\"aqua:gruntwork-io/terragrunt\", \"asdf:gruntwork-io/asdf-terragrunt\"]\ndescription = \"Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules\"\nidiomatic_files = [\".terragrunt-version\"]\ntest = { cmd = \"terragrunt --version\", expected = \"terragrunt version v{{version}}\" }\n"
  },
  {
    "path": "registry/terramate.toml",
    "content": "backends = [\"aqua:terramate-io/terramate\", \"asdf:martinlindner/asdf-terramate\"]\ndescription = \"Open-source Infrastructure as Code (IaC) orchestration platform: GitOps workflows, orchestration, code generation, observability, drift detection, asset management, policies, Slack notifications, and more. Integrates with Terraform, OpenTofu, Terragrunt, Kubernetes, GitHub Actions, GitLab CI/CD, BitBucket Pipelines, and any other CI/CD platform\"\nidiomatic_files = [\".terramate-version\"]\n"
  },
  {
    "path": "registry/terrascan.toml",
    "content": "backends = [\"aqua:tenable/terrascan\", \"asdf:hpdobrica/asdf-terrascan\"]\ndescription = \"Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure\"\n"
  },
  {
    "path": "registry/tf-summarize.toml",
    "content": "backends = [\"aqua:dineshba/tf-summarize\", \"asdf:adamcrews/asdf-tf-summarize\"]\ndescription = \"A command-line utility to print the summary of the terraform plan\"\n"
  },
  {
    "path": "registry/tfc-agent.toml",
    "content": "description = \"HCP Terraform Agents allow HCP Terraform to communicate with isolated, private, or on-premises infrastructure\"\nos = [\"linux\"]\n\n[[backends]]\nfull = \"http:tfc-agent\"\n\n[backends.options]\nurl = 'https://releases.hashicorp.com/tfc-agent/{{ version }}/tfc-agent_{{ version }}_linux_{{ arch(x64=\"amd64\") }}.zip'\nversion_expr = 'fromJSON(body).versions | keys() | sortVersions()'\nversion_list_url = \"https://releases.hashicorp.com/tfc-agent/index.json\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-hashicorp\"\n"
  },
  {
    "path": "registry/tfctl.toml",
    "content": "backends = [\"aqua:flux-iac/tofu-controller/tfctl\", \"asdf:deas/asdf-tfctl\"]\ndescription = \"A GitOps OpenTofu and Terraform controller for Flux\"\n"
  },
  {
    "path": "registry/tfenv.toml",
    "content": "backends = [\"aqua:tfutils/tfenv\", \"asdf:carlduevel/asdf-tfenv\"]\ndescription = \"Terraform version manager\"\n"
  },
  {
    "path": "registry/tflint.toml",
    "content": "backends = [\"aqua:terraform-linters/tflint\", \"asdf:skyzyx/asdf-tflint\"]\ndescription = \"A Pluggable Terraform Linter\"\ntest = { cmd = \"tflint --version\", expected = \"TFLint version {{version}}\" }\n"
  },
  {
    "path": "registry/tfmigrate.toml",
    "content": "backends = [\"aqua:minamijoyo/tfmigrate\", \"asdf:dex4er/asdf-tfmigrate\"]\ndescription = \"A Terraform / OpenTofu state migration tool for GitOps\"\n"
  },
  {
    "path": "registry/tfnotify.toml",
    "content": "backends = [\"aqua:mercari/tfnotify\", \"asdf:jnavarrof/asdf-tfnotify\"]\ndescription = \"A CLI command to parse Terraform execution result and notify it to GitHub\"\n"
  },
  {
    "path": "registry/tfsec.toml",
    "content": "backends = [\"aqua:aquasecurity/tfsec\", \"asdf:woneill/asdf-tfsec\"]\ndescription = \"Security scanner for your Terraform code\"\n"
  },
  {
    "path": "registry/tfstate-lookup.toml",
    "content": "backends = [\n  \"aqua:fujiwara/tfstate-lookup\",\n  \"asdf:carnei-ro/asdf-tfstate-lookup\",\n]\ndescription = \"Lookup resource attributes in tfstate\"\n"
  },
  {
    "path": "registry/tfswitch.toml",
    "content": "description = \"A command line tool to switch between different versions of terraform (install with homebrew and more)\"\n\n[[backends]]\nfull = \"github:warrensbox/terraform-switcher\"\n\n[backends.options]\nexe = \"tfswitch\"\n\n[[backends]]\nfull = \"asdf:iul1an/asdf-tfswitch\"\n"
  },
  {
    "path": "registry/tfupdate.toml",
    "content": "backends = [\"aqua:minamijoyo/tfupdate\", \"asdf:yuokada/asdf-tfupdate\"]\ndescription = \"Update version constraints in your Terraform configurations\"\n"
  },
  {
    "path": "registry/tigerbeetle.toml",
    "content": "backends = [\"github:tigerbeetle/tigerbeetle\"]\ndescription = \"The financial transactions database designed for mission critical safety and performance.\"\ntest = { cmd = \"tigerbeetle version\", expected = \"TigerBeetle version {{version}}\" }\n"
  },
  {
    "path": "registry/tilt.toml",
    "content": "backends = [\"aqua:tilt-dev/tilt\", \"asdf:eaceaser/asdf-tilt\"]\ndescription = \"Define your dev environment as code. For microservice apps on Kubernetes\"\n"
  },
  {
    "path": "registry/timoni.toml",
    "content": "backends = [\"aqua:stefanprodan/timoni\", \"asdf:Smana/asdf-timoni\"]\ndescription = \"Timoni is a package manager for Kubernetes, powered by CUE and inspired by Helm\"\n"
  },
  {
    "path": "registry/tiny.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-tiny\"]\ndescription = \"rtx-tiny is mostly a fake plugin to check mise in CI\"\n"
  },
  {
    "path": "registry/tinygo.toml",
    "content": "backends = [\"aqua:tinygo-org/tinygo\"]\ndescription = \"Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM\"\ntest = { cmd = \"tinygo version\", expected = \"tinygo version {{version}}\" }\n"
  },
  {
    "path": "registry/tinymist.toml",
    "content": "backends = [\"aqua:Myriad-Dreamin/tinymist\", \"cargo:tinymist\"]\ndescription = \"Tinymist is an integrated language service for Typst.\"\n# 0.14.4 doesn't print version\n# expected was: \"Build Git Describe:  v{{version}}\"\ntest = { cmd = \"tinymist --version\", expected = \"\" }\n"
  },
  {
    "path": "registry/tinytex.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-tinytex\"]\ndescription = \"A lightweight, cross-platform, portable, and easy-to-maintain LaTeX distribution based on TeX Live\"\n"
  },
  {
    "path": "registry/tirith.toml",
    "content": "backends = [\"github:sheeki03/tirith\", \"cargo:tirith\"]\ndescription = \"Terminal security - catches homograph attacks, pipe-to-shell, ANSI injection\"\ntest = { cmd = \"tirith --version\", expected = \"tirith {{version}}\" }\n"
  },
  {
    "path": "registry/titan.toml",
    "content": "backends = [\"github:titan-data/titan\", \"asdf:gabitchov/asdf-titan\"]\ndescription = \"Titan is an open source project for developers to manage their data like code\"\n"
  },
  {
    "path": "registry/tlrc.toml",
    "content": "backends = [\"aqua:tldr-pages/tlrc\", \"cargo:tlrc\"]\ndescription = \"A tldr client written in Rust\"\ntest = { cmd = \"tldr --version\", expected = \"tlrc v{{version}}\" }\n"
  },
  {
    "path": "registry/tmux.toml",
    "content": "backends = [\"aqua:tmux/tmux-builds\", \"asdf:mise-plugins/mise-tmux\"]\ndescription = \"tmux is a terminal multiplexer. It lets you switch easily between several programs in one terminal, detach them (they keep running in the background) and reattach them to a different terminal\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"tmux -V\", expected = \"tmux {{version}}\" }\n"
  },
  {
    "path": "registry/tokei.toml",
    "content": "backends = [\n  # v13.0.0 doesn't have binaries\n  \"cargo:tokei\",\n  \"aqua:XAMPPRocky/tokei\",\n  \"asdf:gasuketsu/asdf-tokei\",\n]\ndescription = \"Count your code, quickly\"\ntest = { cmd = \"tokei --version\", expected = \"tokei {{version}}\" }\n"
  },
  {
    "path": "registry/tombi.toml",
    "content": "backends = [\"aqua:tombi-toml/tombi\"]\ndescription = \"TOML Formatter / Linter / Language Server\"\ntest = { cmd = \"tombi --version\", expected = \"tombi {{version}}\" }\n"
  },
  {
    "path": "registry/tomcat.toml",
    "content": "backends = [\"aqua:apache/tomcat\", \"asdf:mise-plugins/mise-tomcat\"]\ndescription = \"The Apache Tomcat® software is an open source implementation of the Jakarta Servlet, Jakarta Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the Jakarta EE platform\"\n"
  },
  {
    "path": "registry/tonnage.toml",
    "content": "backends = [\"github:elementalvoid/tonnage\", \"asdf:elementalvoid/asdf-tonnage\"]\ndescription = \"Tonnage is a small utility to summarize the resource capacity and allocation of a Kubernetes cluster\"\n"
  },
  {
    "path": "registry/topgrade.toml",
    "content": "backends = [\n  \"aqua:topgrade-rs/topgrade\",\n  \"github:topgrade-rs/topgrade\",\n  \"cargo:topgrade\",\n]\ndescription = \"Upgrade all the things\"\ntest = { cmd = \"topgrade --version\", expected = \"topgrade {{version}}\" }\n"
  },
  {
    "path": "registry/traefik.toml",
    "content": "backends = [\"github:traefik/traefik\", \"asdf:Dabolus/asdf-traefik\"]\ndescription = \"The Cloud Native Application Proxy\"\n"
  },
  {
    "path": "registry/transifex.toml",
    "content": "description = \"The Transifex command-line client\"\n\n[[backends]]\nfull = \"github:transifex/cli\"\n\n[backends.options]\nexe = \"tx\"\n\n[[backends]]\nfull = \"asdf:ORCID/asdf-transifex\"\n"
  },
  {
    "path": "registry/trdsql.toml",
    "content": "backends = [\"aqua:noborus/trdsql\", \"asdf:johnlayton/asdf-trdsql\"]\ndescription = \"CLI tool that can execute SQL queries on CSV, LTSV, JSON and TBLN. Can output to various formats\"\n"
  },
  {
    "path": "registry/tree-sitter.toml",
    "content": "backends = [\"aqua:tree-sitter/tree-sitter\", \"asdf:ivanvc/asdf-tree-sitter\"]\ndescription = \"An incremental parsing system for programming tools\"\n"
  },
  {
    "path": "registry/tridentctl.toml",
    "content": "backends = [\n  \"aqua:NetApp/trident/tridentctl\",\n  \"asdf:asdf-community/asdf-tridentctl\",\n]\ndepends = [\"kubectl\"]\ndescription = \"Storage orchestrator for containers\"\nos = [\"linux\", \"macos\"]\ntest = { cmd = \"tridentctl version --client\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/trivy.toml",
    "content": "backends = [\"aqua:aquasecurity/trivy\", \"asdf:zufardhiyaulhaq/asdf-trivy\"]\ndescription = \"Find vulnerabilities, misconfigurations, secrets, SBOM in containers, Kubernetes, code repositories, clouds and more\"\n"
  },
  {
    "path": "registry/trufflehog.toml",
    "content": "backends = [\n  \"aqua:trufflesecurity/trufflehog\",\n  \"github:trufflesecurity/trufflehog\",\n]\ntest = { cmd = \"trufflehog --version\", expected = \"trufflehog {{version}}\" }\n"
  },
  {
    "path": "registry/trunk.toml",
    "content": "backends = [\"npm:@trunkio/launcher\"]\ndescription = \"Trunk is a comprehensive code quality tool that runs linters, formatters, and security scanners to help maintain high-quality codebases (https://trunk.io)\"\ntest = { cmd = \"trunk --help\", expected = \"trunk [flags] [subcommand]\" } # --version can't be used because we know the launcher version, but we get the binary version\n"
  },
  {
    "path": "registry/trzsz-ssh.toml",
    "content": "aliases = [\"tssh\"]\nbackends = [\"aqua:trzsz/trzsz-ssh\", \"go:github.com/trzsz/trzsz-ssh/cmd/tssh\"]\ndescription = \"trzsz-ssh ( tssh ) is an ssh client designed as a drop-in replacement for the openssh client. It aims to provide complete compatibility with openssh, mirroring all its features, while also offering additional useful features. Such as login prompt, batch login, remember password, automated interaction, trzsz, zmodem(rz/sz), udp mode like mosh, etc.\"\ntest = { cmd = \"tssh --version 2>&1\", expected = \"trzsz ssh {{version}}\" }\n"
  },
  {
    "path": "registry/tsuru.toml",
    "content": "description = \"tsuru-client is a tsuru command line tool for application developers\"\n\n[[backends]]\nfull = \"github:tsuru/tsuru-client\"\n\n[backends.options]\nexe = \"tsuru\"\n\n[[backends]]\nfull = \"asdf:virtualstaticvoid/asdf-tsuru\"\n"
  },
  {
    "path": "registry/ttyd.toml",
    "content": "backends = [\"aqua:tsl0922/ttyd\", \"asdf:ivanvc/asdf-ttyd\"]\ndescription = \"Share your terminal over the web\"\n"
  },
  {
    "path": "registry/tuist.toml",
    "content": "backends = [\"aqua:tuist/tuist\", \"asdf:mise-plugins/mise-tuist\"]\ndescription = \"A toolchain to generate Xcode projects from Swift packages\"\nos = [\"macos\", \"linux\"]\ntest = { cmd = \"tuist version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/turbo.toml",
    "content": "backends = [\"npm:turbo\"]\ndescription = \"Turborepo is a high-performance build system for JavaScript and TypeScript codebases.\"\ntest = { cmd = \"turbo --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/tusd.toml",
    "content": "backends = [\"github:tus/tusd\"]\ndescription = \"Reference server implementation in Go of tus: the open protocol for resumable file uploads\"\ntest = { cmd = \"tusd --version | head -n1\", expected = \"Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/ty.toml",
    "content": "backends = [\"aqua:astral-sh/ty\", \"github:astral-sh/ty\"]\ndescription = \"An extremely fast Python type checker and language server, written in Rust\"\ntest = { cmd = \"ty --version\", expected = \"ty {{version}}\" }\n"
  },
  {
    "path": "registry/typos.toml",
    "content": "backends = [\n  \"aqua:crate-ci/typos\",\n  \"asdf:aschiavon91/asdf-typos\",\n  \"cargo:typos-cli\",\n]\ndescription = \"Source code spell checker\"\ntest = { cmd = \"typos --version\", expected = \"typos-cli {{version}}\" }\n"
  },
  {
    "path": "registry/typst.toml",
    "content": "backends = [\n  \"aqua:typst/typst\",\n  \"github:typst/typst\",\n  \"asdf:stephane-klein/asdf-typst\",\n  \"cargo:typst-cli\",\n]\ndescription = \"A new markup-based typesetting system that is powerful and easy to learn\"\ntest = { cmd = \"typst --version\", expected = \"typst {{version}}\" }\n"
  },
  {
    "path": "registry/typstyle.toml",
    "content": "backends = [\"aqua:Enter-tainer/typstyle\", \"cargo:typstyle\"]\ndescription = \"Beautiful and reliable typst code formatter\"\ntest = { cmd = \"typstyle --version | grep 'Version:' | awk '{print $2}'\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/uaa.toml",
    "content": "aliases = [\"uaa-cli\"]\nbackends = [\n  \"aqua:cloudfoundry/uaa-cli\",\n  \"asdf:mise-plugins/tanzu-plug-in-for-asdf\",\n]\ndescription = \"CLI for UAA written in Go\"\ntest = { cmd = \"uaa version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/ubi.toml",
    "content": "backends = [\"aqua:houseabsolute/ubi\"]\ndescription = \"The Universal Binary Installer\"\ntest = { cmd = \"ubi --version\", expected = \"ubi {{version}}\" }\n"
  },
  {
    "path": "registry/unison.toml",
    "content": "backends = [\"github:unisonweb/unison\", \"asdf:susurri/asdf-unison\"]\ndescription = \"A friendly programming language from the future\"\n"
  },
  {
    "path": "registry/upctl.toml",
    "content": "backends = [\"aqua:UpCloudLtd/upcloud-cli\"]\ndescription = \"UpCloud command line client (upctl)\"\ntest = { cmd = \"upctl version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/updatecli.toml",
    "content": "backends = [\"aqua:updatecli/updatecli\", \"asdf:updatecli/asdf-updatecli\"]\ndescription = \"A Declarative Dependency Management tool\"\n"
  },
  {
    "path": "registry/upt.toml",
    "content": "backends = [\"github:sigoden/upt\", \"asdf:ORCID/asdf-upt\"]\ndescription = \"Universal Package-management Tool for any OS\"\n"
  },
  {
    "path": "registry/upx.toml",
    "content": "backends = [\"aqua:upx/upx\", \"asdf:jimmidyson/asdf-upx\"]\ndescription = \"UPX - the Ultimate Packer for eXecutables\"\n"
  },
  {
    "path": "registry/usage.toml",
    "content": "backends = [\n  { full = \"aqua:jdx/usage\", platforms = [\n    \"linux\",\n    \"macos\",\n  ] },\n  { full = \"asdf:mise-plugins/mise-usage\", platforms = [\n    \"linux\",\n    \"macos\",\n  ] },\n  \"cargo:usage-cli\",\n]\ndescription = \"A specification for CLIs\"\nos = [\"linux\", \"macos\", \"freebsd\"]\ntest = { cmd = \"usage --version\", expected = \"usage-cli {{version}}\" }\n"
  },
  {
    "path": "registry/usql.toml",
    "content": "backends = [\"aqua:xo/usql\", \"asdf:itspngu/asdf-usql\"]\ndescription = \"Universal command-line interface for SQL databases\"\n"
  },
  {
    "path": "registry/uv.toml",
    "content": "backends = [\"aqua:astral-sh/uv\", \"asdf:asdf-community/asdf-uv\", \"pipx:uv\"]\ndescription = \"An extremely fast Python package installer and resolver, written in Rust\"\ndetect = [\"uv.lock\"]\ntest = { cmd = \"uv --version\", expected = \"uv {{version}}\" }\n"
  },
  {
    "path": "registry/v.toml",
    "content": "backends = [\"asdf:mise-plugins/mise-v\"]\ndescription = \"V - https://vlang.io\"\n"
  },
  {
    "path": "registry/vacuum.toml",
    "content": "backends = [\"aqua:daveshanley/vacuum\"]\ndescription = \"vacuum is the worlds fastest OpenAPI 3, OpenAPI 2 / Swagger linter and quality analysis tool. Built in go, it tears through API specs faster than you can think. vacuum is compatible with Spectral rulesets and generates compatible reports\"\ntest = { cmd = \"vacuum version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/vale.toml",
    "content": "backends = [\"aqua:errata-ai/vale\", \"asdf:pdemagny/asdf-vale\"]\ndescription = \":pencil: A markup-aware linter for prose built with speed and extensibility in mind\"\n"
  },
  {
    "path": "registry/vals.toml",
    "content": "backends = [\"aqua:helmfile/vals\", \"asdf:dex4er/asdf-vals\"]\ndescription = \"Helm-like configuration values loader with support for various sources\"\n"
  },
  {
    "path": "registry/vault.toml",
    "content": "backends = [\"aqua:hashicorp/vault\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"A tool for secrets management, encryption as a service, and privileged access management\"\ntest = { cmd = \"vault version\", expected = \"Vault v{{version}}\" }\n"
  },
  {
    "path": "registry/vcluster.toml",
    "content": "backends = [\n  \"aqua:loft-sh/vcluster\",\n  \"asdf:https://gitlab.com/wt0f/asdf-vcluster\",\n]\ndescription = \"vCluster - Create fully functional virtual Kubernetes clusters - Each vcluster runs inside a namespace of the underlying k8s cluster. It's cheaper than creating separate full-blown clusters and it offers better multi-tenancy and isolation than regular namespaces\"\n"
  },
  {
    "path": "registry/velad.toml",
    "content": "backends = [\"github:kubevela/velad\", \"asdf:mise-plugins/mise-velad\"]\ndescription = \"Lightweight KubeVela that runs as Daemon in single node with high availability\"\ntest = { cmd = \"velad version\", expected = \"Version: v{{version}}\" }\n"
  },
  {
    "path": "registry/velero.toml",
    "content": "backends = [\"aqua:vmware-tanzu/velero\", \"asdf:looztra/asdf-velero\"]\ndescription = \"Backup and migrate Kubernetes applications and their persistent volumes\"\n"
  },
  {
    "path": "registry/vendir.toml",
    "content": "backends = [\"aqua:carvel-dev/vendir\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = \"Easy way to vendor portions of git repos, github releases, helm charts, docker image contents, etc. declaratively\"\n"
  },
  {
    "path": "registry/venom.toml",
    "content": "backends = [\"aqua:ovh/venom\", \"asdf:aabouzaid/asdf-venom\"]\ndescription = \"Manage and run your integration tests with efficiency - Venom run executors (script, HTTP Request, web, imap, etc... ) and assertions\"\n"
  },
  {
    "path": "registry/vercel.toml",
    "content": "backends = [\"npm:vercel\"]\ndescription = \"Build and deploy on the Vercel cloud\"\ntest = { cmd = \"vc --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/vespa-cli.toml",
    "content": "backends = [\"github:vespa-engine/vespa\"]\ndescription = \"The command-line tool for Vespa.ai.\"\ntest = { cmd = \"vespa version\", expected = \"Vespa CLI version {{version}}\" }\n"
  },
  {
    "path": "registry/vfox.toml",
    "content": "backends = [\"aqua:version-fox/vfox\"]\ndescription = \"A cross-platform and extendable version manager with support for Java, Node.js, Flutter, .Net & more\"\ntest = { cmd = \"vfox --version\", expected = \"vfox version {{version}}\" }\n"
  },
  {
    "path": "registry/vhs.toml",
    "content": "backends = [\"aqua:charmbracelet/vhs\", \"asdf:chessmango/asdf-vhs\"]\ndescription = \"Your CLI home video recorder\"\n"
  },
  {
    "path": "registry/victoria-metrics.toml",
    "content": "backends = [\"aqua:VictoriaMetrics/VictoriaMetrics/victoria-metrics\"]\ndescription = \"VictoriaMetrics: fast, cost-effective monitoring solution and time series database\"\n"
  },
  {
    "path": "registry/viddy.toml",
    "content": "backends = [\"aqua:sachaos/viddy\", \"asdf:ryodocx/asdf-viddy\"]\ndescription = \"A modern watch command. Time machine and pager etc\"\n"
  },
  {
    "path": "registry/vim.toml",
    "content": "backends = [\"conda:vim\", \"asdf:mise-plugins/mise-vim\"]\ndescription = \"Vim is an advanced text editor that seeks to provide the power of the de-facto Unix editor 'Vi', with a more complete feature set. It's useful whether you're already using vi or using a different editor\"\n"
  },
  {
    "path": "registry/viteplus.toml",
    "content": "aliases = [\"vp\"]\nbackends = [\"npm:vite-plus\"]\ndescription = \"The Unified Toolchain for the Web\"\ntest = { cmd = \"vp --version\", expected = \"vp v{{version}}\" }\n"
  },
  {
    "path": "registry/vivid.toml",
    "content": "backends = [\"aqua:sharkdp/vivid\", \"cargo:vivid\"]\ndescription = \"A themeable LS_COLORS generator with a rich filetype datebase\"\ntest = { cmd = \"vivid --version\", expected = \"vivid {{version}}\" }\n"
  },
  {
    "path": "registry/vlang.toml",
    "content": "backends = [\"vfox:mise-plugins/vfox-vlang\"]\ndescription = \"The V Programming Language. Simple, fast, safe, compiled. For developing maintainable software\"\n"
  },
  {
    "path": "registry/vultr.toml",
    "content": "aliases = [\"vultr-cli\"]\nbackends = [\"github:vultr/vultr-cli\", \"asdf:ikuradon/asdf-vultr-cli\"]\ndescription = \"Official command line tool for Vultr services\"\ntest = { cmd = \"vultr-cli version\", expected = \"Vultr-CLI v{{version}}\" }\n"
  },
  {
    "path": "registry/wait-for-gh-rate-limit.toml",
    "content": "backends = [\"github:jdx/wait-for-gh-rate-limit\"]\ndescription = \"CLI to wait for github rate limits to reset if they are expired\"\n"
  },
  {
    "path": "registry/wash.toml",
    "content": "backends = [\"aqua:wasmCloud/wasmCloud/wash\"]\ndescription = \"wasmCloud Shell (wash)\"\ntest = { cmd = \"wash --version | head -n1 | awk '{print $2}'\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/wasm4.toml",
    "content": "backends = [\"aqua:aduros/wasm4\", \"asdf:jtakakura/asdf-wasm4\"]\ndescription = \"Build retro games using WebAssembly for a fantasy console\"\ntest = { cmd = \"w4 --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/wasmer.toml",
    "content": "backends = [\"aqua:wasmerio/wasmer\", \"asdf:tachyonicbytes/asdf-wasmer\"]\ndescription = \"The leading WebAssembly Runtime supporting WASI and Emscripten\"\n"
  },
  {
    "path": "registry/wasmtime.toml",
    "content": "backends = [\n  \"aqua:bytecodealliance/wasmtime\",\n  \"asdf:tachyonicbytes/asdf-wasmtime\",\n]\ndescription = \"A lightweight WebAssembly runtime that is fast, secure, and standards-compliant\"\n"
  },
  {
    "path": "registry/watchexec.toml",
    "content": "backends = [\"aqua:watchexec/watchexec\", \"cargo:watchexec-cli\"]\ndescription = \"Executes commands in response to file modifications\"\ntest = { cmd = \"watchexec --version\", expected = \"watchexec {{version}}\" }\n"
  },
  {
    "path": "registry/waypoint.toml",
    "content": "backends = [\"aqua:hashicorp/waypoint\", \"asdf:mise-plugins/mise-hashicorp\"]\ndescription = \"A tool to build, deploy, and release any application on any platform\"\n"
  },
  {
    "path": "registry/weave-gitops.toml",
    "content": "description = \"Command line utility for managing Kubernetes applications via GitOps\"\n\n[[backends]]\nfull = \"github:weaveworks/weave-gitops\"\n\n[backends.options]\nexe = \"gitops\"\n\n[[backends]]\nfull = \"asdf:deas/asdf-weave-gitops\"\n"
  },
  {
    "path": "registry/websocat.toml",
    "content": "backends = [\n  \"aqua:vi/websocat\",\n  \"asdf:bdellegrazie/asdf-websocat\",\n  \"cargo:websocat\",\n]\ndescription = \"Command-line client for WebSockets, like netcat (or curl) for ws:// with advanced socat-like functions\"\n"
  },
  {
    "path": "registry/werf.toml",
    "content": "backends = [\"aqua:werf/werf\"]\ndescription = \"A solution for implementing efficient and consistent software delivery to Kubernetes facilitating best practices\"\ntest = { cmd = \"werf version\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/workmux.toml",
    "content": "backends = [\"github:raine/workmux\", \"cargo:workmux\"]\ndescription = \"git worktrees + tmux windows for zero-friction parallel dev\"\ntest = { cmd = \"workmux --version\", expected = \"workmux {{version}}\" }\n"
  },
  {
    "path": "registry/wrangler.toml",
    "content": "backends = [\"npm:wrangler\"]\ndescription = \"A command line tool for building Cloudflare Workers\"\ntest = { cmd = \"wrangler --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/wren.toml",
    "content": "aliases = [\"wren-cli\"]\nbackends = [\"aqua:wren-lang/wren-cli\", \"asdf:jtakakura/asdf-wren-cli\"]\ndescription = \"A command line tool for the Wren programming language\"\ntest = { cmd = \"wren_cli --version\", expected = \"wren {{version}}\" }\n"
  },
  {
    "path": "registry/wtfutil.toml",
    "content": "backends = [\"aqua:wtfutil/wtf\", \"asdf:NeoHsu/asdf-wtfutil\"]\ndescription = \"WTF is the personal information dashboard for your terminal\"\ntest = { cmd = \"wtfutil --version\", expected = \"WTF v{{version}}\" }\n"
  },
  {
    "path": "registry/xc.toml",
    "content": "backends = [\"aqua:joerdav/xc\", \"asdf:airtonix/asdf-xc\"]\ndescription = \"Markdown defined task runner\"\n"
  },
  {
    "path": "registry/xcbeautify.toml",
    "content": "backends = [\"aqua:cpisciotta/xcbeautify\", \"asdf:mise-plugins/asdf-xcbeautify\"]\ndescription = \"A little beautifier tool for xcodebuild\"\ntest = { cmd = \"which xcbeautify\", expected = \"xcbeautify\" }\n"
  },
  {
    "path": "registry/xchtmlreport.toml",
    "content": "backends = [\"github:XCTestHTMLReport/XCTestHTMLReport\"]\ndescription = \"Xcode-like HTML report for Unit and UI Tests\"\nos = [\"macos\"]\ntest = { cmd = \"xchtmlreport --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/xcodegen.toml",
    "content": "backends = [\"github:yonaskolb/XcodeGen\"]\ndescription = \"A Swift command line tool for generating your Xcode project\"\nos = [\"macos\"]\ntest = { cmd = \"xcodegen --version\", expected = \"Version: {{version}}\" }\n"
  },
  {
    "path": "registry/xcodes.toml",
    "content": "backends = [\"aqua:XcodesOrg/xcodes\"]\ndescription = \"The best command-line tool to install and switch between multiple versions of Xcode\"\nos = [\"macos\"]\ntest = { cmd = \"xcodes version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/xcresultparser.toml",
    "content": "backends = [\"github:a7ex/xcresultparser\"]\ndescription = \"Parse the binary xcresult bundle from Xcode builds and testruns\"\nos = [\"macos\"]\ntest = { cmd = \"xcresultparser --help\", expected = \"OVERVIEW: xcresultparser\" }\n"
  },
  {
    "path": "registry/xcsift.toml",
    "content": "backends = [\"github:ldomaradzki/xcsift\"]\ndescription = \"Swift tool to parse and format xcodebuild output for coding agents\"\nos = [\"macos\"]\ntest = { cmd = \"xcsift --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/xh.toml",
    "content": "backends = [\"aqua:ducaale/xh\", \"asdf:NeoHsu/asdf-xh\", \"cargo:xh\"]\ndescription = \"Friendly and fast tool for sending HTTP requests\"\ntest = { cmd = \"xh -V\", expected = \"xh {{version}}\" }\n"
  },
  {
    "path": "registry/xxh.toml",
    "content": "backends = [\"pipx:xxh-xxh\"]\ndescription = \"🚀 Bring your favorite shell wherever you go through the ssh. Xonsh shell, fish, zsh, osquery and so on.\"\ntest = { cmd = \"xxh --version\", expected = \"xxh/{{version}}\" }\n"
  },
  {
    "path": "registry/yamlfmt.toml",
    "content": "backends = [\n  \"aqua:google/yamlfmt\",\n  \"asdf:mise-plugins/asdf-yamlfmt\",\n  \"go:github.com/google/yamlfmt/cmd/yamlfmt\",\n]\ndescription = \"An extensible command line tool or library to format yaml files\"\ntest = { cmd = \"yamlfmt --version\", expected = \"yamlfmt {{version}}\" }\n"
  },
  {
    "path": "registry/yamllint.toml",
    "content": "backends = [\"pipx:yamllint\", \"asdf:ericcornelissen/asdf-yamllint\"]\ndescription = \"A linter for YAML files\"\ntest = { cmd = \"yamllint --version\", expected = \"yamllint {{version}}\" }\n"
  },
  {
    "path": "registry/yamlscript.toml",
    "content": "backends = [\"aqua:yaml/yamlscript\", \"asdf:mise-plugins/mise-yamlscript\"]\ndescription = \"YS — YAML Done Wisely\"\ntest = { cmd = \"ys --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/yarn.toml",
    "content": "backends = [\n  \"vfox:mise-plugins/vfox-yarn\",\n  \"asdf:mise-plugins/mise-yarn\",\n  \"aqua:yarnpkg/berry\",\n  \"npm:@yarnpkg/cli-dist\",\n]\ndescription = \"Yarn is a package manager that doubles down as project manager. Whether you work on simple projects or industry monorepos, whether you're an open source developer or an enterprise user, Yarn has your back\"\ndetect = [\"yarn.lock\", \".yarnrc.yml\"]\nidiomatic_files = [\"package.json\"]\ntest = { cmd = \"yarn --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/yazi.toml",
    "content": "backends = [\"aqua:sxyazi/yazi\", \"cargo:yazi-fm\"]\ndescription = \"Blazing fast terminal file manager written in Rust, based on async I/O\"\ntest = { cmd = \"yazi --version\", expected = \"Yazi {{version}}\" }\n"
  },
  {
    "path": "registry/yj.toml",
    "content": "backends = [\"aqua:sclevine/yj\", \"asdf:ryodocx/asdf-yj\"]\ndescription = \"CLI - Convert between YAML, TOML, JSON, and HCL. Preserves map order\"\ntest = { cmd = \"yj -v\", expected = \"v{{version}}\" }\n"
  },
  {
    "path": "registry/yor.toml",
    "content": "backends = [\"aqua:bridgecrewio/yor\", \"asdf:ordinaryexperts/asdf-yor\"]\ndescription = \"Extensible auto-tagger for your IaC files. The ultimate way to link entities in the cloud back to the codified resource which created it\"\ntest = { cmd = \"yor --version\", expected = \"yor version {{version}}\" }\n"
  },
  {
    "path": "registry/youtube-dl.toml",
    "content": "backends = [\"aqua:ytdl-org/ytdl-nightly\", \"asdf:mise-plugins/mise-youtube-dl\"]\ndescription = \"Command-line program to download videos from YouTube.com and other video sites\"\ntest = { cmd = \"youtube-dl --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/yq.toml",
    "content": "backends = [\n  \"aqua:mikefarah/yq\",\n  \"asdf:sudermanjr/asdf-yq\",\n  \"go:github.com/mikefarah/yq/v4\",\n]\ndescription = \"yq is a portable command-line YAML processor\"\ntest = { cmd = \"yq --version\", expected = \"version v{{version}}\" }\n"
  },
  {
    "path": "registry/yt-dlp.toml",
    "content": "description = \"A feature-rich command-line audio/video downloader\"\ntest = { cmd = \"yt-dlp --version\", expected = \"{{version}}\" }\n\n[[backends]]\nfull = \"github:yt-dlp/yt-dlp\"\n\n[backends.options]\nrename_exe = \"yt-dlp\"\n\n[[backends]]\nfull = \"asdf:duhow/asdf-yt-dlp\"\n"
  },
  {
    "path": "registry/ytt.toml",
    "content": "backends = [\"aqua:carvel-dev/ytt\", \"asdf:vmware-tanzu/asdf-carvel\"]\ndescription = \"YAML templating tool that works on YAML structure instead of text\"\ntest = { cmd = \"ytt --version\", expected = \"ytt version {{version}}\" }\n"
  },
  {
    "path": "registry/zarf.toml",
    "content": "backends = [\"aqua:zarf-dev/zarf\"]\ndescription = \"The Airgap Native Packager Manager for Kubernetes\"\ntest = { cmd = \"zarf version\", expected = \"v{{version | trim_start_matches(pat='v')}}\" }\n"
  },
  {
    "path": "registry/zbctl.toml",
    "content": "backends = [\"npm:zbctl\"]\ndescription = \"zbctl is a command line interface designed to create and read resources inside zeebe broker.\"\ntest = { cmd = \"zbctl version\", expected = \"zbctl {{version}}\" }\n"
  },
  {
    "path": "registry/zellij.toml",
    "content": "backends = [\n  \"aqua:zellij-org/zellij\",\n  \"asdf:chessmango/asdf-zellij\",\n  \"cargo:zellij\",\n]\ndescription = \"A terminal workspace with batteries included\"\ntest = { cmd = \"zellij --version\", expected = \"zellij {{version}}\" }\n"
  },
  {
    "path": "registry/zephyr.toml",
    "content": "backends = [\"aqua:MaybeJustJames/zephyr\", \"asdf:nsaunders/asdf-zephyr\"]\ndescription = \"Tree shaking breeze for PureScript CoreFn AST\"\ntest = { cmd = \"zephyr --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/zig.toml",
    "content": "backends = [\"core:zig\"]\ndescription = \"Zig is a general-purpose programming language and toolchain for maintaining robust, optimal and reusable software\"\n"
  },
  {
    "path": "registry/zigmod.toml",
    "content": "backends = [\n  \"aqua:nektro/zigmod\",\n  \"github:nektro/zigmod\",\n  \"asdf:mise-plugins/asdf-zigmod\",\n]\ndescription = \"A package manager for the Zig programming language\"\ntest = { cmd = \"zigmod version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/zizmor.toml",
    "content": "backends = [\"aqua:zizmorcore/zizmor\", \"cargo:zizmor\"]\ndescription = \"Static analysis for GitHub Actions\"\ntest = { cmd = \"zizmor --version\", expected = \"zizmor {{version}}\" }\n"
  },
  {
    "path": "registry/zls.toml",
    "content": "backends = [\"aqua:zigtools/zls\"]\ndescription = \"A Zig language server supporting Zig developers with features like autocomplete and goto definition\"\ntest = { cmd = \"zls --version\", expected = \"{{version}}\" }\n"
  },
  {
    "path": "registry/zola.toml",
    "content": "backends = [\"aqua:getzola/zola\", \"asdf:salasrod/asdf-zola\"]\ndescription = \"A fast static site generator in a single binary with everything built-in. https://www.getzola.org\"\ntest = { cmd = \"zola --version\", expected = \"zola {{version}}\" }\n"
  },
  {
    "path": "registry/zoxide.toml",
    "content": "backends = [\"aqua:ajeetdsouza/zoxide\", \"cargo:zoxide\"]\ndescription = \"A smarter cd command. Supports all major shells\"\ntest = { cmd = \"zoxide --version\", expected = \"zoxide {{version}}\" }\n"
  },
  {
    "path": "registry/zprint.toml",
    "content": "description = \"Executables, uberjar, and library to beautifully format Clojure and Clojurescript source code and s-expressions\"\ntest = { cmd = \"zprint --version 2>&1\", expected = \"zprint-{{version}}\" }\n\n[[backends]]\nfull = \"aqua:kkinnear/zprint\"\n\n[[backends]]\nfull = \"github:kkinnear/zprint\"\n\n[backends.options]\nbin = \"zprint\"\n\n[backends.options.platforms.macos-arm64]\nasset_pattern = \"zprintma-{{ version }}\"\n\n[backends.options.platforms.macos-x64]\nasset_pattern = \"zprintm-{{ version }}\"\n\n[backends.options.platforms.linux-x64]\nasset_pattern = \"zprintl-{{ version }}\"\n\n[[backends]]\nfull = \"asdf:mise-plugins/mise-zprint\"\n"
  },
  {
    "path": "schema/mise-registry-tool.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://mise.jdx.dev/schema/mise-registry-tool.json\",\n  \"title\": \"mise registry tool schema\",\n  \"description\": \"Schema for individual tool files in the mise registry\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"aliases\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\",\n        \"pattern\": \"^[a-zA-Z0-9_.-]+$\"\n      },\n      \"description\": \"Alternative names for the tool\"\n    },\n    \"backends\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"oneOf\": [\n          {\n            \"type\": \"string\",\n            \"pattern\": \"^(aqua|asdf|cargo|conda|core|dotnet|gem|github|gitlab|go|http|npm|pipx|spm|ubi|vfox):.+$\",\n            \"description\": \"Backend specification as a string (e.g., 'aqua:owner/repo')\"\n          },\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"full\": {\n                \"type\": \"string\",\n                \"pattern\": \"^(aqua|asdf|cargo|conda|core|dotnet|gem|github|gitlab|go|http|npm|pipx|spm|ubi|vfox):.+$\",\n                \"description\": \"Full backend specification\"\n              },\n              \"platforms\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"type\": \"string\",\n                  \"enum\": [\"freebsd\", \"linux\", \"macos\", \"openbsd\", \"windows\"]\n                },\n                \"description\": \"Operating systems this backend supports\"\n              },\n              \"options\": {\n                \"type\": \"object\",\n                \"description\": \"Backend-specific options\",\n                \"properties\": {\n                  \"platforms\": {\n                    \"type\": \"object\",\n                    \"description\": \"Platform-specific options (e.g., macos-arm64, linux-x64)\",\n                    \"propertyNames\": {\n                      \"pattern\": \"^(linux|macos|windows)-(x64|arm64|armv7)$\"\n                    },\n                    \"additionalProperties\": {\n                      \"type\": \"object\",\n                      \"description\": \"Platform-specific configuration\",\n                      \"additionalProperties\": {\n                        \"type\": [\"string\", \"boolean\"]\n                      }\n                    }\n                  }\n                },\n                \"additionalProperties\": {\n                  \"type\": [\"string\", \"boolean\"]\n                }\n              }\n            },\n            \"required\": [\"full\"],\n            \"additionalProperties\": false\n          }\n        ]\n      },\n      \"description\": \"List of backends that can install this tool\",\n      \"minItems\": 1\n    },\n    \"depends\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\",\n        \"pattern\": \"^[a-zA-Z0-9_.-]+$\"\n      },\n      \"description\": \"Other tools this tool depends on\"\n    },\n    \"description\": {\n      \"type\": \"string\",\n      \"description\": \"A brief description of the tool\"\n    },\n    \"detect\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Files that indicate this tool should be suggested during config generation\"\n    },\n    \"idiomatic_files\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Files that indicate this tool should be used in a project\"\n    },\n    \"os\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\",\n        \"enum\": [\"freebsd\", \"linux\", \"macos\", \"openbsd\", \"windows\"]\n      },\n      \"description\": \"Operating systems this tool supports (empty means all)\"\n    },\n    \"overrides\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\",\n        \"pattern\": \"^[a-zA-Z0-9_.-]+$\"\n      },\n      \"description\": \"List of tool IDs that this tool overrides\"\n    },\n    \"test\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"cmd\": {\n          \"type\": \"string\",\n          \"description\": \"Command to run to test the tool installation\"\n        },\n        \"expected\": {\n          \"type\": \"string\",\n          \"description\": \"Expected substring in the command output\"\n        }\n      },\n      \"required\": [\"cmd\", \"expected\"],\n      \"additionalProperties\": false,\n      \"description\": \"Command to test the tool installation\"\n    }\n  },\n  \"required\": [\"backends\"],\n  \"additionalProperties\": false\n}\n"
  },
  {
    "path": "schema/mise-settings.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"$id\": \"https://mise.jdx.dev/schema/mise-settings.json\",\n  \"title\": \"Mise Settings Schema\",\n  \"description\": \"JSON schema for mise settings.toml configuration file\",\n  \"type\": \"object\",\n  \"patternProperties\": {\n    \"^[a-zA-Z0-9_]+$\": {\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/definitions/setting\"\n        },\n        {\n          \"type\": \"object\",\n          \"patternProperties\": {\n            \"^[a-zA-Z0-9_]+$\": {\n              \"$ref\": \"#/definitions/setting\"\n            }\n          },\n          \"additionalProperties\": false\n        }\n      ]\n    }\n  },\n  \"additionalProperties\": false,\n  \"definitions\": {\n    \"setting\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"aliases\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"Alternative names for this setting\"\n        },\n        \"default\": {\n          \"description\": \"Default value for this setting\"\n        },\n        \"default_docs\": {\n          \"type\": \"string\",\n          \"description\": \"Documentation for the default value shown in docs\"\n        },\n        \"deprecated\": {\n          \"type\": \"string\",\n          \"description\": \"Deprecation message if this setting is deprecated\"\n        },\n        \"deprecated_warn_at\": {\n          \"type\": \"string\",\n          \"description\": \"Mise version at which the deprecation warning starts showing (e.g. \\\"2026.8.0\\\")\"\n        },\n        \"deprecated_remove_at\": {\n          \"type\": \"string\",\n          \"description\": \"Mise version at which the deprecated code should be removed (triggers debug_assert, e.g. \\\"2027.2.0\\\")\"\n        },\n        \"description\": {\n          \"type\": \"string\",\n          \"description\": \"Brief description of what this setting does\"\n        },\n        \"deserialize_with\": {\n          \"type\": \"string\",\n          \"description\": \"Custom deserialization function to use\"\n        },\n        \"docs\": {\n          \"type\": \"string\",\n          \"description\": \"Detailed documentation for this setting\"\n        },\n        \"enum\": {\n          \"type\": \"array\",\n          \"description\": \"List of allowed values for this setting\",\n          \"items\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"boolean\"\n              },\n              {\n                \"type\": \"integer\"\n              },\n              {\n                \"type\": \"object\",\n                \"properties\": {\n                  \"value\": {\n                    \"oneOf\": [\n                      { \"type\": \"string\" },\n                      { \"type\": \"boolean\" },\n                      { \"type\": \"integer\" }\n                    ],\n                    \"description\": \"The enum value\"\n                  },\n                  \"description\": {\n                    \"type\": \"string\",\n                    \"description\": \"Description of this enum value\"\n                  }\n                },\n                \"required\": [\"value\"],\n                \"additionalProperties\": false\n              }\n            ]\n          }\n        },\n        \"env\": {\n          \"type\": \"string\",\n          \"description\": \"Environment variable name that can set this setting\"\n        },\n        \"hide\": {\n          \"type\": \"boolean\",\n          \"description\": \"Whether to hide this setting from documentation\"\n        },\n        \"optional\": {\n          \"type\": \"boolean\",\n          \"description\": \"Whether this setting is optional\"\n        },\n        \"parse_env\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"bool_string\",\n            \"list_by_comma\",\n            \"list_by_colon\",\n            \"set_by_comma\",\n            \"parse_url_replacements\"\n          ],\n          \"description\": \"How to parse the environment variable value\"\n        },\n        \"rc\": {\n          \"type\": \"boolean\",\n          \"description\": \"Whether this setting can be set in .miserc.toml for early initialization\"\n        },\n        \"rust_type\": {\n          \"type\": \"string\",\n          \"description\": \"Rust type used internally for this setting\"\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"Bool\",\n            \"String\",\n            \"Integer\",\n            \"Path\",\n            \"Url\",\n            \"Duration\",\n            \"ListString\",\n            \"ListPath\",\n            \"SetString\",\n            \"IndexMap<String, String>\",\n            \"BoolOrString\"\n          ],\n          \"description\": \"Type of this setting\"\n        }\n      },\n      \"required\": [\"description\"],\n      \"additionalProperties\": false\n    }\n  }\n}\n"
  },
  {
    "path": "schema/mise-task.json",
    "content": "{\n  \"$id\": \"https://mise.jdx.dev/schema/mise-task.json\",\n  \"$schema\": \"https://json-schema.org/draft/2019-09/schema#\",\n  \"title\": \"mise-task-schema\",\n  \"type\": \"object\",\n  \"$defs\": {\n    \"task_dependency_item\": {\n      \"description\": \"task name and args\",\n      \"oneOf\": [\n        {\n          \"type\": \"string\"\n        },\n        {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"task\": {\n              \"type\": \"string\"\n            },\n            \"args\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"env\": {\n              \"type\": \"object\",\n              \"additionalProperties\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\"task\"],\n          \"additionalProperties\": false\n        }\n      ]\n    },\n    \"task\": {\n      \"oneOf\": [\n        {\n          \"description\": \"script to run\",\n          \"type\": \"string\"\n        },\n        {\n          \"description\": \"script to run\",\n          \"items\": {\n            \"description\": \"script to run\",\n            \"type\": \"string\"\n          },\n          \"type\": \"array\"\n        },\n        {\n          \"properties\": {\n            \"alias\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"alias for this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"alias for this task\",\n                  \"items\": {\n                    \"description\": \"alias for this task\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"confirm\": {\n              \"description\": \"confirmation message before running this task\",\n              \"type\": \"string\"\n            },\n            \"depends\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to run before this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to run before this task\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  }\n                }\n              ]\n            },\n            \"depends_post\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to run after this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to run after this task\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  }\n                }\n              ]\n            },\n            \"wait_for\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to wait for completion first\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to wait for completion first\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"description\": {\n              \"description\": \"description of task\",\n              \"type\": \"string\"\n            },\n            \"dir\": {\n              \"default\": \"{{ config_root }}\",\n              \"description\": \"directory to run script in, default is the project's base directory\",\n              \"type\": \"string\"\n            },\n            \"env\": {\n              \"$ref\": \"#/$defs/env\"\n            },\n            \"vars\": {\n              \"$ref\": \"#/$defs/vars\"\n            },\n            \"tools\": {\n              \"description\": \"tools to install/activate before running this task\",\n              \"additionalProperties\": {\n                \"oneOf\": [\n                  {\n                    \"description\": \"version of the tool to install\",\n                    \"type\": \"string\"\n                  },\n                  {\n                    \"properties\": {\n                      \"version\": {\n                        \"description\": \"version of the tool to install\",\n                        \"type\": \"string\"\n                      },\n                      \"os\": {\n                        \"oneOf\": [\n                          {\n                            \"description\": \"operating system to install on\",\n                            \"type\": \"array\"\n                          },\n                          {\n                            \"description\": \"option to pass to tool\",\n                            \"type\": \"string\"\n                          },\n                          {\n                            \"description\": \"option to pass to tool\",\n                            \"type\": \"boolean\"\n                          }\n                        ]\n                      }\n                    },\n                    \"required\": [\"version\"],\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                      \"oneOf\": [\n                        {\n                          \"type\": \"string\"\n                        }\n                      ]\n                    }\n                  }\n                ]\n              },\n              \"type\": \"object\"\n            },\n            \"hide\": {\n              \"default\": false,\n              \"description\": \"do not display this task\",\n              \"type\": \"boolean\"\n            },\n            \"outputs\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"files created by this task\",\n                  \"items\": {\n                    \"description\": \"glob pattern or path to files created by this task\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                },\n                {\n                  \"description\": \"glob pattern or path to files created by this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"additionalProperties\": false,\n                  \"properties\": {\n                    \"auto\": {\n                      \"description\": \"automatically touch an internal tracked file instead of specifying outputs\",\n                      \"enum\": [true],\n                      \"type\": \"boolean\"\n                    }\n                  },\n                  \"required\": [\"auto\"],\n                  \"type\": \"object\"\n                }\n              ]\n            },\n            \"quiet\": {\n              \"default\": false,\n              \"description\": \"do not display mise information for this task\",\n              \"type\": \"boolean\"\n            },\n            \"silent\": {\n              \"default\": false,\n              \"description\": \"suppress all output for this task\",\n              \"oneOf\": [\n                {\n                  \"type\": \"boolean\"\n                },\n                {\n                  \"enum\": [\"stdout\", \"stderr\"],\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"interactive\": {\n              \"default\": false,\n              \"description\": \"mark task as interactive, acquiring exclusive terminal access while allowing other non-interactive tasks to run in parallel\",\n              \"type\": \"boolean\"\n            },\n            \"raw\": {\n              \"default\": false,\n              \"description\": \"directly connect task to stdin/stdout/stderr\",\n              \"type\": \"boolean\"\n            },\n            \"run\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/task_run_entry\"\n                },\n                {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_run_entry\"\n                  }\n                }\n              ]\n            },\n            \"run_windows\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/task_run_entry\"\n                },\n                {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_run_entry\"\n                  }\n                }\n              ]\n            },\n            \"file\": {\n              \"description\": \"Execute an external script\",\n              \"type\": \"string\"\n            },\n            \"sources\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"files that this task depends on\",\n                  \"items\": {\n                    \"description\": \"glob pattern or path to files that this task depends on\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                },\n                {\n                  \"description\": \"glob pattern or path to files that this task depends on\",\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"shell\": {\n              \"description\": \"specify a shell command to run the script with\",\n              \"type\": \"string\"\n            },\n            \"usage\": {\n              \"description\": \"Specify usage (https://usage.jdx.dev/) specs for the task\",\n              \"type\": \"string\"\n            },\n            \"timeout\": {\n              \"description\": \"timeout for this task\",\n              \"type\": \"string\"\n            },\n            \"extends\": {\n              \"description\": \"name of the task template to extend\",\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\"\n        }\n      ]\n    },\n    \"env\": {\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"value\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"string\"\n                  },\n                  {\n                    \"type\": \"number\"\n                  },\n                  {\n                    \"type\": \"boolean\"\n                  }\n                ]\n              },\n              \"tools\": {\n                \"type\": \"boolean\",\n                \"description\": \"load tools before resolving\"\n              },\n              \"redact\": {\n                \"type\": \"boolean\",\n                \"description\": \"redact the value from logs\"\n              },\n              \"required\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"boolean\",\n                    \"description\": \"require this environment variable to be defined before mise runs or in a later config file\"\n                  },\n                  {\n                    \"type\": \"string\",\n                    \"description\": \"require this environment variable with user help text on how to set it\"\n                  }\n                ],\n                \"description\": \"require this environment variable to be defined before mise runs or in a later config file. Cannot be used with empty string values or value=false. Can be a boolean or a help string.\"\n              }\n            },\n            \"additionalProperties\": false\n          },\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"age\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"string\",\n                    \"description\": \"[experimental] age-encrypted value (simplified format)\"\n                  },\n                  {\n                    \"type\": \"object\",\n                    \"properties\": {\n                      \"value\": {\n                        \"type\": \"string\",\n                        \"description\": \"[experimental] age-encrypted value\"\n                      },\n                      \"format\": {\n                        \"type\": \"string\",\n                        \"enum\": [\"raw\", \"zstd\"],\n                        \"description\": \"[experimental] compression format for the encrypted value\"\n                      }\n                    },\n                    \"required\": [\"value\"],\n                    \"additionalProperties\": false,\n                    \"description\": \"[experimental] age-encrypted value (complex format)\"\n                  }\n                ]\n              }\n            },\n            \"required\": [\"age\"],\n            \"additionalProperties\": false,\n            \"description\": \"[experimental] age-encrypted environment variable\"\n          },\n          {\n            \"type\": \"string\"\n          },\n          {\n            \"type\": \"number\"\n          },\n          {\n            \"type\": \"boolean\"\n          }\n        ]\n      },\n      \"description\": \"environment variables\",\n      \"properties\": {\n        \"_\": {\n          \"description\": \"environment modules\",\n          \"additionalProperties\": true,\n          \"properties\": {\n            \"file\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/env_directive\"\n                },\n                {\n                  \"description\": \"dotenv file to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"dotenv files to load\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"dotenv file to load\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"$ref\": \"#/$defs/env_directive\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"path\": {\n              \"oneOf\": [\n                {\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"path\": {\n                      \"oneOf\": [\n                        {\n                          \"type\": \"string\"\n                        },\n                        {\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      ]\n                    },\n                    \"paths\": {\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"type\": \"string\"\n                      }\n                    },\n                    \"tools\": {\n                      \"type\": \"boolean\",\n                      \"description\": \"load tools before resolving\"\n                    }\n                  },\n                  \"oneOf\": [\n                    {\n                      \"type\": \"object\",\n                      \"properties\": {\n                        \"path\": {\n                          \"oneOf\": [\n                            {\n                              \"type\": \"string\"\n                            },\n                            {\n                              \"type\": \"array\",\n                              \"items\": {\n                                \"type\": \"string\"\n                              }\n                            }\n                          ]\n                        }\n                      },\n                      \"required\": [\"path\"]\n                    },\n                    {\n                      \"type\": \"object\",\n                      \"properties\": {\n                        \"paths\": {\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      },\n                      \"required\": [\"paths\"]\n                    }\n                  ]\n                },\n                {\n                  \"description\": \"PATH entry to add\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"PATH entries to add\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"PATH entry to add\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"path\": {\n                            \"oneOf\": [\n                              {\n                                \"type\": \"string\"\n                              },\n                              {\n                                \"type\": \"array\",\n                                \"items\": {\n                                  \"type\": \"string\"\n                                }\n                              }\n                            ]\n                          },\n                          \"tools\": {\n                            \"type\": \"boolean\",\n                            \"description\": \"load tools before resolving\"\n                          }\n                        }\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"python\": {\n              \"description\": \"python environment\",\n              \"properties\": {\n                \"venv\": {\n                  \"oneOf\": [\n                    {\n                      \"description\": \"path to python virtual environment to use\",\n                      \"type\": \"string\"\n                    },\n                    {\n                      \"description\": \"virtualenv options\",\n                      \"properties\": {\n                        \"create\": {\n                          \"default\": false,\n                          \"description\": \"create a new virtual environment if one does not exist\",\n                          \"type\": \"boolean\"\n                        },\n                        \"path\": {\n                          \"description\": \"path to python virtual environment to use\",\n                          \"type\": \"string\"\n                        },\n                        \"python\": {\n                          \"description\": \"python version to use\",\n                          \"type\": \"string\"\n                        },\n                        \"python_create_args\": {\n                          \"description\": \"additional arguments to pass to python when creating a virtual environment\",\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"uv_create_args\": {\n                          \"description\": \"additional arguments to pass to uv when creating a virtual environment\",\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      },\n                      \"required\": [\"path\"],\n                      \"type\": \"object\"\n                    }\n                  ]\n                }\n              },\n              \"type\": \"object\"\n            },\n            \"source\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/env_directive\"\n                },\n                {\n                  \"description\": \"bash script to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"bash scripts to load\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"bash script to load\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"$ref\": \"#/$defs/env_directive\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            }\n          },\n          \"type\": \"object\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"env_directive\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"path\": {\n          \"oneOf\": [\n            {\n              \"type\": \"string\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          ]\n        },\n        \"paths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"tools\": {\n          \"type\": \"boolean\",\n          \"description\": \"load tools before resolving\"\n        },\n        \"redact\": {\n          \"type\": \"boolean\",\n          \"description\": \"redact the value from logs\"\n        },\n        \"required\": {\n          \"oneOf\": [\n            {\n              \"type\": \"boolean\",\n              \"description\": \"require this environment variable to be defined before mise runs or in a later config file\"\n            },\n            {\n              \"type\": \"string\",\n              \"description\": \"require this environment variable with user help text on how to set it\"\n            }\n          ],\n          \"description\": \"require this environment variable to be defined before mise runs or in a later config file. Cannot be used with empty string values or value=false. Can be a boolean or a help string.\"\n        }\n      },\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"path\": {\n              \"$ref\": \"#/$defs/env_directive/properties/path\"\n            }\n          },\n          \"required\": [\"path\"]\n        },\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"paths\": {\n              \"$ref\": \"#/$defs/env_directive/properties/paths\"\n            }\n          },\n          \"required\": [\"paths\"]\n        }\n      ]\n    },\n    \"task_run_entry\": {\n      \"oneOf\": [\n        {\n          \"description\": \"script to run\",\n          \"type\": \"string\"\n        },\n        {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"task\": {\n              \"description\": \"single task name (with optional args) to run\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"task\"]\n        },\n        {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"tasks\": {\n              \"description\": \"parallel task group to run\",\n              \"items\": {\n                \"description\": \"task name and args\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            }\n          },\n          \"required\": [\"tasks\"]\n        }\n      ]\n    },\n    \"task_template\": {\n      \"description\": \"task template that can be extended by tasks\",\n      \"properties\": {\n        \"alias\": {\n          \"oneOf\": [\n            {\n              \"description\": \"alias for this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"alias for this task\",\n              \"items\": {\n                \"description\": \"alias for this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"confirm\": {\n          \"description\": \"confirmation message before running this task\",\n          \"type\": \"string\"\n        },\n        \"depends\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"depends_post\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"wait_for\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"description\": {\n          \"description\": \"description of task\",\n          \"type\": \"string\"\n        },\n        \"dir\": {\n          \"default\": \"{{ config_root }}\",\n          \"description\": \"directory to run script in, default is the project's base directory\",\n          \"type\": \"string\"\n        },\n        \"env\": {\n          \"$ref\": \"#/$defs/env\"\n        },\n        \"vars\": {\n          \"$ref\": \"#/$defs/vars\"\n        },\n        \"tools\": {\n          \"description\": \"tools to install/activate before running this task\",\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"description\": \"version of the tool to install\",\n                \"type\": \"string\"\n              },\n              {\n                \"properties\": {\n                  \"version\": {\n                    \"description\": \"version of the tool to install\",\n                    \"type\": \"string\"\n                  },\n                  \"os\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"operating system to install on\",\n                        \"type\": \"array\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"boolean\"\n                      }\n                    ]\n                  }\n                },\n                \"required\": [\"version\"],\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                  \"oneOf\": [\n                    {\n                      \"type\": \"string\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          \"type\": \"object\"\n        },\n        \"hide\": {\n          \"default\": false,\n          \"description\": \"do not display this task\",\n          \"type\": \"boolean\"\n        },\n        \"outputs\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files created by this task\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files created by this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files created by this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"auto\": {\n                  \"description\": \"automatically touch an internal tracked file instead of specifying outputs\",\n                  \"enum\": [true],\n                  \"type\": \"boolean\"\n                }\n              },\n              \"required\": [\"auto\"],\n              \"type\": \"object\"\n            }\n          ]\n        },\n        \"quiet\": {\n          \"default\": false,\n          \"description\": \"do not display mise information for this task\",\n          \"type\": \"boolean\"\n        },\n        \"silent\": {\n          \"default\": false,\n          \"description\": \"suppress all output for this task\",\n          \"oneOf\": [\n            {\n              \"type\": \"boolean\"\n            },\n            {\n              \"enum\": [\"stdout\", \"stderr\"],\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"interactive\": {\n          \"default\": false,\n          \"description\": \"mark task as interactive, acquiring exclusive terminal access while allowing other non-interactive tasks to run in parallel\",\n          \"type\": \"boolean\"\n        },\n        \"raw\": {\n          \"default\": false,\n          \"description\": \"directly connect task to stdin/stdout/stderr\",\n          \"type\": \"boolean\"\n        },\n        \"run\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"run_windows\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"file\": {\n          \"description\": \"Execute an external script\",\n          \"type\": \"string\"\n        },\n        \"sources\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files that this task depends on\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files that this task depends on\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files that this task depends on\",\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"shell\": {\n          \"description\": \"specify a shell command to run the script with\",\n          \"type\": \"string\"\n        },\n        \"usage\": {\n          \"description\": \"Specify usage (https://usage.jdx.dev/) specs for the task\",\n          \"type\": \"string\"\n        },\n        \"timeout\": {\n          \"description\": \"timeout for this task\",\n          \"type\": \"string\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"vars\": {\n      \"description\": \"variables to set\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"_\": {\n          \"description\": \"vars modules\",\n          \"additionalProperties\": true,\n          \"properties\": {\n            \"file\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"dotenv file to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"dotenv files to load\",\n                  \"items\": {\n                    \"description\": \"dotenv file to load\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"source\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"bash script to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"bash scripts to load\",\n                  \"items\": {\n                    \"description\": \"bash script to load\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            }\n          },\n          \"type\": \"object\"\n        }\n      },\n      \"additionalProperties\": {\n        \"description\": \"value of variable\",\n        \"type\": \"string\"\n      }\n    }\n  },\n  \"description\": \"Config file for included mise tasks (https://mise.jdx.dev/tasks/#task-configuration)\",\n  \"additionalProperties\": {\n    \"$ref\": \"#/$defs/task\"\n  }\n}\n"
  },
  {
    "path": "schema/mise.json",
    "content": "{\n  \"$id\": \"https://mise.jdx.dev/schema/mise.json\",\n  \"$schema\": \"https://json-schema.org/draft/2019-09/schema#\",\n  \"title\": \"mise\",\n  \"type\": \"object\",\n  \"$defs\": {\n    \"task_dependency_item\": {\n      \"description\": \"task name and args\",\n      \"oneOf\": [\n        {\n          \"type\": \"string\"\n        },\n        {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"task\": {\n              \"type\": \"string\"\n            },\n            \"args\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"env\": {\n              \"type\": \"object\",\n              \"additionalProperties\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\"task\"],\n          \"additionalProperties\": false\n        }\n      ]\n    },\n    \"env_directive\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"path\": {\n          \"oneOf\": [\n            {\n              \"type\": \"string\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          ]\n        },\n        \"paths\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"tools\": {\n          \"type\": \"boolean\",\n          \"description\": \"load tools before resolving\"\n        },\n        \"redact\": {\n          \"type\": \"boolean\",\n          \"description\": \"redact the value from logs\"\n        },\n        \"required\": {\n          \"oneOf\": [\n            {\n              \"type\": \"boolean\",\n              \"description\": \"require this environment variable to be defined before mise runs or in a later config file\"\n            },\n            {\n              \"type\": \"string\",\n              \"description\": \"require this environment variable with user help text on how to set it\"\n            }\n          ],\n          \"description\": \"require this environment variable to be defined before mise runs or in a later config file. Cannot be used with empty string values or value=false. Can be a boolean or a help string.\"\n        }\n      },\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"path\": {\n              \"$ref\": \"#/$defs/env_directive/properties/path\"\n            }\n          },\n          \"required\": [\"path\"]\n        },\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"paths\": {\n              \"$ref\": \"#/$defs/env_directive/properties/paths\"\n            }\n          },\n          \"required\": [\"paths\"]\n        }\n      ]\n    },\n    \"env\": {\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"value\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"string\"\n                  },\n                  {\n                    \"type\": \"number\"\n                  },\n                  {\n                    \"type\": \"boolean\"\n                  }\n                ]\n              },\n              \"tools\": {\n                \"type\": \"boolean\",\n                \"description\": \"load tools before resolving\"\n              },\n              \"redact\": {\n                \"type\": \"boolean\",\n                \"description\": \"redact the value from logs\"\n              },\n              \"required\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"boolean\",\n                    \"description\": \"require this environment variable to be defined before mise runs or in a later config file\"\n                  },\n                  {\n                    \"type\": \"string\",\n                    \"description\": \"require this environment variable with user help text on how to set it\"\n                  }\n                ],\n                \"description\": \"require this environment variable to be defined before mise runs or in a later config file. Cannot be used with empty string values or value=false. Can be a boolean or a help string.\"\n              }\n            },\n            \"additionalProperties\": false\n          },\n          {\n            \"type\": \"object\",\n            \"properties\": {\n              \"age\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"string\",\n                    \"description\": \"[experimental] age-encrypted value (simplified format)\"\n                  },\n                  {\n                    \"type\": \"object\",\n                    \"properties\": {\n                      \"value\": {\n                        \"type\": \"string\",\n                        \"description\": \"[experimental] age-encrypted value\"\n                      },\n                      \"format\": {\n                        \"type\": \"string\",\n                        \"enum\": [\"raw\", \"zstd\"],\n                        \"description\": \"[experimental] compression format for the encrypted value\"\n                      }\n                    },\n                    \"required\": [\"value\"],\n                    \"additionalProperties\": false,\n                    \"description\": \"[experimental] age-encrypted value (complex format)\"\n                  }\n                ]\n              }\n            },\n            \"required\": [\"age\"],\n            \"additionalProperties\": false,\n            \"description\": \"[experimental] age-encrypted environment variable\"\n          },\n          {\n            \"type\": \"string\"\n          },\n          {\n            \"type\": \"number\"\n          },\n          {\n            \"type\": \"boolean\"\n          }\n        ]\n      },\n      \"description\": \"environment variables\",\n      \"properties\": {\n        \"_\": {\n          \"description\": \"environment modules\",\n          \"additionalProperties\": true,\n          \"properties\": {\n            \"file\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/env_directive\"\n                },\n                {\n                  \"description\": \"dotenv file to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"dotenv files to load\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"dotenv file to load\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"$ref\": \"#/$defs/env_directive\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"path\": {\n              \"oneOf\": [\n                {\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"path\": {\n                      \"oneOf\": [\n                        {\n                          \"type\": \"string\"\n                        },\n                        {\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      ]\n                    },\n                    \"paths\": {\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"type\": \"string\"\n                      }\n                    },\n                    \"tools\": {\n                      \"type\": \"boolean\",\n                      \"description\": \"load tools before resolving\"\n                    }\n                  },\n                  \"oneOf\": [\n                    {\n                      \"type\": \"object\",\n                      \"properties\": {\n                        \"path\": {\n                          \"oneOf\": [\n                            {\n                              \"type\": \"string\"\n                            },\n                            {\n                              \"type\": \"array\",\n                              \"items\": {\n                                \"type\": \"string\"\n                              }\n                            }\n                          ]\n                        }\n                      },\n                      \"required\": [\"path\"]\n                    },\n                    {\n                      \"type\": \"object\",\n                      \"properties\": {\n                        \"paths\": {\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      },\n                      \"required\": [\"paths\"]\n                    }\n                  ]\n                },\n                {\n                  \"description\": \"PATH entry to add\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"PATH entries to add\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"PATH entry to add\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"path\": {\n                            \"oneOf\": [\n                              {\n                                \"type\": \"string\"\n                              },\n                              {\n                                \"type\": \"array\",\n                                \"items\": {\n                                  \"type\": \"string\"\n                                }\n                              }\n                            ]\n                          },\n                          \"tools\": {\n                            \"type\": \"boolean\",\n                            \"description\": \"load tools before resolving\"\n                          }\n                        }\n                      }\n                    ]\n                  }\n                }\n              ]\n            },\n            \"python\": {\n              \"description\": \"python environment\",\n              \"properties\": {\n                \"venv\": {\n                  \"oneOf\": [\n                    {\n                      \"description\": \"path to python virtual environment to use\",\n                      \"type\": \"string\"\n                    },\n                    {\n                      \"description\": \"virtualenv options\",\n                      \"properties\": {\n                        \"create\": {\n                          \"default\": false,\n                          \"description\": \"create a new virtual environment if one does not exist\",\n                          \"type\": \"boolean\"\n                        },\n                        \"path\": {\n                          \"description\": \"path to python virtual environment to use\",\n                          \"type\": \"string\"\n                        },\n                        \"python\": {\n                          \"description\": \"python version to use\",\n                          \"type\": \"string\"\n                        },\n                        \"python_create_args\": {\n                          \"description\": \"additional arguments to pass to python when creating a virtual environment\",\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"uv_create_args\": {\n                          \"description\": \"additional arguments to pass to uv when creating a virtual environment\",\n                          \"type\": \"array\",\n                          \"items\": {\n                            \"type\": \"string\"\n                          }\n                        }\n                      },\n                      \"required\": [\"path\"],\n                      \"type\": \"object\"\n                    }\n                  ]\n                }\n              },\n              \"type\": \"object\"\n            },\n            \"source\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/env_directive\"\n                },\n                {\n                  \"description\": \"bash script to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"bash scripts to load\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"bash script to load\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"$ref\": \"#/$defs/env_directive\"\n                      }\n                    ]\n                  }\n                }\n              ]\n            }\n          },\n          \"type\": \"object\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"settings\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"activate_aggressive\": {\n          \"description\": \"Pushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after activation to take precedence.\",\n          \"type\": \"boolean\"\n        },\n        \"age\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"identity_files\": {\n              \"description\": \"[experimental] List of age identity files to use for decryption.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"key_file\": {\n              \"description\": \"[experimental] Path to the age private key file to use for encryption/decryption.\",\n              \"type\": \"string\"\n            },\n            \"ssh_identity_files\": {\n              \"description\": \"[experimental] List of SSH identity files to use for age decryption.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"strict\": {\n              \"default\": true,\n              \"description\": \"If true, fail when age decryption fails (including when age is not available, the key is missing, or the key is invalid). If false, skip decryption and continue in these cases.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"all_compile\": {\n          \"description\": \"do not use precompiled binaries for any tool\",\n          \"type\": \"boolean\"\n        },\n        \"always_keep_download\": {\n          \"description\": \"should mise keep downloaded files after installation\",\n          \"type\": \"boolean\"\n        },\n        \"always_keep_install\": {\n          \"description\": \"should mise keep install files after installation even if the installation fails\",\n          \"type\": \"boolean\"\n        },\n        \"aqua\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"baked_registry\": {\n              \"default\": true,\n              \"description\": \"Use baked-in aqua registry.\",\n              \"type\": \"boolean\"\n            },\n            \"cosign\": {\n              \"default\": true,\n              \"description\": \"Use cosign to verify aqua tool signatures.\",\n              \"type\": \"boolean\"\n            },\n            \"cosign_extra_args\": {\n              \"description\": \"Extra arguments to pass to cosign when verifying aqua tool signatures.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"github_attestations\": {\n              \"default\": true,\n              \"description\": \"Enable GitHub Artifact Attestations verification for aqua tools.\",\n              \"type\": \"boolean\"\n            },\n            \"minisign\": {\n              \"default\": true,\n              \"description\": \"Use minisign to verify aqua tool signatures.\",\n              \"type\": \"boolean\"\n            },\n            \"registry_url\": {\n              \"description\": \"URL to fetch aqua registry from.\",\n              \"type\": \"string\"\n            },\n            \"slsa\": {\n              \"default\": true,\n              \"description\": \"Use SLSA to verify aqua tool signatures.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"arch\": {\n          \"description\": \"Architecture to use for precompiled binaries.\",\n          \"type\": \"string\"\n        },\n        \"asdf\": {\n          \"description\": \"use asdf as a default plugin backend\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"asdf_compat\": {\n          \"description\": \"set to true to ensure .tool-versions will be compatible with asdf\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"auto_install\": {\n          \"default\": true,\n          \"description\": \"Automatically install missing tools when running `mise x`, `mise run`, or as part of the 'not found' handler.\",\n          \"type\": \"boolean\"\n        },\n        \"auto_install_disable_tools\": {\n          \"description\": \"List of tools to skip automatically installing when running `mise x`, `mise run`, or as part of the 'not found' handler.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"cache_prune_age\": {\n          \"default\": \"30d\",\n          \"description\": \"Delete files in cache that have not been accessed in this duration\",\n          \"type\": \"string\"\n        },\n        \"cargo\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"binstall\": {\n              \"default\": true,\n              \"description\": \"Use cargo-binstall instead of cargo install if available\",\n              \"type\": \"boolean\"\n            },\n            \"binstall_only\": {\n              \"default\": false,\n              \"description\": \"Only use cargo-binstall for installation, fail if not available.\",\n              \"type\": \"boolean\"\n            },\n            \"registry_name\": {\n              \"description\": \"Name of the cargo registry to use.\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"cargo_binstall\": {\n          \"description\": \"Use cargo-binstall instead of cargo install if available\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"cd\": {\n          \"description\": \"Path to change to after launching mise\",\n          \"type\": \"string\"\n        },\n        \"ceiling_paths\": {\n          \"default\": [],\n          \"description\": \"Directories where mise stops searching for config files.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"ci\": {\n          \"default\": \"false\",\n          \"description\": \"Set to true if running in a CI environment\",\n          \"type\": \"boolean\"\n        },\n        \"color\": {\n          \"default\": true,\n          \"description\": \"Use color in mise terminal output\",\n          \"type\": \"boolean\"\n        },\n        \"color_theme\": {\n          \"default\": \"default\",\n          \"description\": \"Theme for interactive prompts (default/charm, base16, catppuccin, dracula)\",\n          \"type\": \"string\",\n          \"enum\": [\"default\", \"charm\", \"base16\", \"catppuccin\", \"dracula\"]\n        },\n        \"conda\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"channel\": {\n              \"default\": \"conda-forge\",\n              \"description\": \"Default channel for conda packages.\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"debug\": {\n          \"description\": \"Sets log level to debug\",\n          \"type\": \"boolean\"\n        },\n        \"default_config_filename\": {\n          \"default\": \"mise.toml\",\n          \"description\": \"The default config filename read. `mise use` and other commands that create new config files will use this value. This must be an env var.\",\n          \"type\": \"string\"\n        },\n        \"default_tool_versions_filename\": {\n          \"default\": \".tool-versions\",\n          \"description\": \"The default .tool-versions filename read. This will not ignore .tool-versions—use override_tool_versions_filename for that. This must be an env var.\",\n          \"type\": \"string\"\n        },\n        \"disable_backends\": {\n          \"default\": [],\n          \"description\": \"Backends to disable such as `asdf` or `pipx`\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"disable_default_registry\": {\n          \"description\": \"Disable the default mapping of short tool names like `php` -> `asdf:mise-plugins/asdf-php`. This parameter disables only for the backends `vfox` and `asdf`.\",\n          \"type\": \"boolean\"\n        },\n        \"disable_default_shorthands\": {\n          \"description\": \"Disables built-in shorthands to asdf/vfox plugins\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"disable_hints\": {\n          \"default\": [],\n          \"description\": \"Turns off helpful hints when using different mise features\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"disable_tools\": {\n          \"default\": [],\n          \"description\": \"Tools defined in mise.toml that should be ignored\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"dotnet\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"cli_telemetry_optout\": {\n              \"description\": \"Set DOTNET_CLI_TELEMETRY_OPTOUT to opt out of .NET CLI telemetry.\",\n              \"type\": \"boolean\"\n            },\n            \"dotnet_root\": {\n              \"description\": \"Path to the shared .NET SDK root directory.\",\n              \"type\": \"string\"\n            },\n            \"isolated\": {\n              \"default\": false,\n              \"description\": \"Install each .NET SDK version in its own isolated directory.\",\n              \"type\": \"boolean\"\n            },\n            \"package_flags\": {\n              \"default\": [],\n              \"description\": \"Extends dotnet search and install abilities.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"registry_url\": {\n              \"default\": \"https://api.nuget.org/v3/index.json\",\n              \"description\": \"URL to fetch dotnet tools from.\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"enable_tools\": {\n          \"default\": [],\n          \"description\": \"Tools defined in mise.toml that should be used - all other tools are ignored\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"env\": {\n          \"default\": [],\n          \"description\": \"Env to use for mise.<MISE_ENV>.toml files.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"env_cache\": {\n          \"default\": false,\n          \"description\": \"[experimental] Enable environment caching for nested mise invocations\",\n          \"type\": \"boolean\"\n        },\n        \"env_cache_ttl\": {\n          \"default\": \"1h\",\n          \"description\": \"TTL for cached environments\",\n          \"type\": \"string\"\n        },\n        \"env_file\": {\n          \"description\": \"Path to a file containing environment variables to automatically load.\",\n          \"type\": \"string\"\n        },\n        \"env_shell_expand\": {\n          \"description\": \"Enable shell-style variable expansion in env values (e.g., $FOO, ${BAR:-default})\",\n          \"type\": \"boolean\"\n        },\n        \"erlang\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"compile\": {\n              \"description\": \"If true, compile erlang from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"exec_auto_install\": {\n          \"default\": true,\n          \"description\": \"Automatically install missing tools when running `mise x`.\",\n          \"type\": \"boolean\"\n        },\n        \"experimental\": {\n          \"description\": \"Enable experimental mise features which are incomplete or unstable—breakings changes may occur\",\n          \"type\": \"boolean\"\n        },\n        \"fetch_remote_versions_cache\": {\n          \"default\": \"1h\",\n          \"description\": \"How long to cache remote versions for tools.\",\n          \"type\": \"string\"\n        },\n        \"fetch_remote_versions_timeout\": {\n          \"default\": \"20s\",\n          \"description\": \"Timeout in seconds for HTTP requests to fetch new tool versions in mise.\",\n          \"type\": \"string\"\n        },\n        \"github\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"github_attestations\": {\n              \"default\": true,\n              \"description\": \"Enable GitHub Artifact Attestations verification for github backend tools.\",\n              \"type\": \"boolean\"\n            },\n            \"slsa\": {\n              \"default\": true,\n              \"description\": \"Enable SLSA provenance verification for github backend tools.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"github_attestations\": {\n          \"default\": true,\n          \"description\": \"Enable GitHub Artifact Attestations verification for supported tools.\",\n          \"type\": \"boolean\"\n        },\n        \"gix\": {\n          \"default\": true,\n          \"description\": \"Use gix for git operations, set to false to shell out to git.\",\n          \"type\": \"boolean\"\n        },\n        \"global_config_file\": {\n          \"description\": \"Path to the global mise config file. Default is `~/.config/mise/config.toml`. This must be an env var.\",\n          \"type\": \"string\"\n        },\n        \"global_config_root\": {\n          \"description\": \"Path which is used as `{{config_root}}` for the global config file. Default is `$HOME`. This must be an env var.\",\n          \"type\": \"string\"\n        },\n        \"go_default_packages_file\": {\n          \"default\": \"~/.default-go-packages\",\n          \"description\": \"Path to a file containing default go packages to install when installing go\",\n          \"type\": \"string\"\n        },\n        \"go_download_mirror\": {\n          \"default\": \"https://dl.google.com/go\",\n          \"description\": \"Mirror to download go sdk tarballs from.\",\n          \"type\": \"string\"\n        },\n        \"go_repo\": {\n          \"default\": \"https://github.com/golang/go\",\n          \"description\": \"URL to fetch go from.\",\n          \"type\": \"string\"\n        },\n        \"go_set_gobin\": {\n          \"description\": \"Changes where `go install` installs binaries to.\",\n          \"type\": \"boolean\"\n        },\n        \"go_set_gopath\": {\n          \"description\": \"[deprecated] Set to true to set GOPATH=~/.local/share/mise/installs/go/.../packages.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"go_set_goroot\": {\n          \"default\": true,\n          \"description\": \"Sets GOROOT=~/.local/share/mise/installs/go/.../.\",\n          \"type\": \"boolean\"\n        },\n        \"go_skip_checksum\": {\n          \"description\": \"Set to true to skip checksum verification when downloading go sdk tarballs.\",\n          \"type\": \"boolean\"\n        },\n        \"gpg_verify\": {\n          \"description\": \"Use gpg to verify all tool signatures.\",\n          \"type\": \"boolean\"\n        },\n        \"hook_env\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"cache_ttl\": {\n              \"default\": \"0s\",\n              \"description\": \"Cache hook-env directory checks for this duration. Useful for slow filesystems like NFS.\",\n              \"type\": \"string\"\n            },\n            \"chpwd_only\": {\n              \"default\": false,\n              \"description\": \"Only run hook-env checks on directory change, not on every prompt.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"http_retries\": {\n          \"default\": 0,\n          \"description\": \"Number of retries for HTTP requests in mise.\",\n          \"type\": \"number\"\n        },\n        \"http_timeout\": {\n          \"default\": \"30s\",\n          \"description\": \"Timeout in seconds for all HTTP requests in mise.\",\n          \"type\": \"string\"\n        },\n        \"idiomatic_version_file\": {\n          \"description\": \"Set to false to disable the idiomatic version files such as .node-version, .ruby-version, etc.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"idiomatic_version_file_disable_tools\": {\n          \"default\": [],\n          \"description\": \"Specific tools to disable idiomatic version files for.\",\n          \"type\": \"array\",\n          \"deprecated\": true,\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"idiomatic_version_file_enable_tools\": {\n          \"default\": [],\n          \"description\": \"Specific tools to enable idiomatic version files for like .node-version, .ruby-version, etc.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"ignored_config_paths\": {\n          \"default\": [],\n          \"description\": \"This is a list of config paths that mise will ignore.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"install_before\": {\n          \"description\": \"Only install versions released before this date\",\n          \"type\": \"string\"\n        },\n        \"java\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"shorthand_vendor\": {\n              \"default\": \"openjdk\",\n              \"description\": \"Shorthand for Java. Used when installing Java without a vendor prefix.\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"jobs\": {\n          \"default\": 8,\n          \"description\": \"How many jobs to run concurrently such as tool installs.\",\n          \"type\": \"number\"\n        },\n        \"legacy_version_file\": {\n          \"default\": true,\n          \"description\": \"Set to false to disable the idiomatic version files such as .node-version, .ruby-version, etc.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"legacy_version_file_disable_tools\": {\n          \"default\": [],\n          \"description\": \"Specific tools to disable idiomatic version files for.\",\n          \"type\": \"array\",\n          \"deprecated\": true,\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"libgit2\": {\n          \"default\": true,\n          \"description\": \"Use libgit2 for git operations, set to false to shell out to git.\",\n          \"type\": \"boolean\"\n        },\n        \"locked\": {\n          \"default\": false,\n          \"description\": \"Require lockfile URLs to be present during installation.\",\n          \"type\": \"boolean\"\n        },\n        \"lockfile\": {\n          \"description\": \"Create and read lockfiles for tool versions.\",\n          \"type\": \"boolean\"\n        },\n        \"log_level\": {\n          \"default\": \"info\",\n          \"description\": \"Show more/less output.\",\n          \"type\": \"string\",\n          \"enum\": [\"trace\", \"debug\", \"info\", \"warn\", \"error\"]\n        },\n        \"netrc\": {\n          \"default\": true,\n          \"description\": \"Use a netrc file for HTTP Basic authentication.\",\n          \"type\": \"boolean\"\n        },\n        \"netrc_file\": {\n          \"description\": \"Path to the netrc file to use for HTTP Basic authentication.\",\n          \"type\": \"string\"\n        },\n        \"no_env\": {\n          \"description\": \"Do not load environment variables from config files.\",\n          \"type\": \"boolean\"\n        },\n        \"no_hooks\": {\n          \"description\": \"Do not execute hooks from config files.\",\n          \"type\": \"boolean\"\n        },\n        \"node\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"cflags\": {\n              \"description\": \"Additional CFLAGS options (e.g., to override -O3).\",\n              \"type\": \"string\"\n            },\n            \"compile\": {\n              \"description\": \"Compile node from source.\",\n              \"type\": \"boolean\"\n            },\n            \"concurrency\": {\n              \"description\": \"How many jobs should be used in compilation.\",\n              \"type\": \"number\"\n            },\n            \"configure_opts\": {\n              \"description\": \"Additional ./configure options.\",\n              \"type\": \"string\"\n            },\n            \"corepack\": {\n              \"description\": \"Installs the default corepack shims after installing any node version.\",\n              \"type\": \"boolean\"\n            },\n            \"default_packages_file\": {\n              \"description\": \"Path to a file containing default npm packages to install.\",\n              \"type\": \"string\"\n            },\n            \"flavor\": {\n              \"description\": \"Install a specific node flavor like glibc-217 or musl. Use with unofficial node build repo.\",\n              \"type\": \"string\"\n            },\n            \"gpg_verify\": {\n              \"description\": \"Use gpg to verify node tool signatures.\",\n              \"type\": \"boolean\"\n            },\n            \"make\": {\n              \"description\": \"Make command to use.\",\n              \"type\": \"string\"\n            },\n            \"make_install_opts\": {\n              \"description\": \"Additional make install options.\",\n              \"type\": \"string\"\n            },\n            \"make_opts\": {\n              \"description\": \"Additional make options.\",\n              \"type\": \"string\"\n            },\n            \"mirror_url\": {\n              \"description\": \"Mirror to download node tarballs from.\",\n              \"type\": \"string\"\n            },\n            \"ninja\": {\n              \"description\": \"Use ninja instead of make to compile node.\",\n              \"type\": \"boolean\"\n            },\n            \"nodenv_root\": {\n              \"default\": \"~/.nodenv\",\n              \"description\": \"Directory for nodenv.\",\n              \"type\": \"string\"\n            },\n            \"nvm_dir\": {\n              \"default\": \"~/.nvm\",\n              \"description\": \"Directory for nvm.\",\n              \"type\": \"string\"\n            },\n            \"verify\": {\n              \"default\": true,\n              \"description\": \"Verify the downloaded assets using GPG.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"not_found_auto_install\": {\n          \"default\": true,\n          \"description\": \"Set to false to disable the \\\"command not found\\\" handler to autoinstall missing tool versions.\",\n          \"type\": \"boolean\"\n        },\n        \"npm\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"bun\": {\n              \"description\": \"Use bun instead of npm if bun is installed and on PATH.\",\n              \"type\": \"boolean\",\n              \"deprecated\": true\n            },\n            \"package_manager\": {\n              \"default\": \"npm\",\n              \"description\": \"Package manager to use for installing npm packages.\",\n              \"type\": \"string\",\n              \"enum\": [\"npm\", \"bun\", \"pnpm\"]\n            }\n          }\n        },\n        \"offline\": {\n          \"description\": \"Disable all HTTP requests. Tools will only use locally cached data.\",\n          \"type\": \"boolean\"\n        },\n        \"os\": {\n          \"description\": \"OS to use for precompiled binaries.\",\n          \"type\": \"string\"\n        },\n        \"override_config_filenames\": {\n          \"default\": [],\n          \"description\": \"If set, mise will ignore default config files like `mise.toml` and use these filenames instead.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"override_tool_versions_filenames\": {\n          \"default\": [],\n          \"description\": \"If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"paranoid\": {\n          \"description\": \"Enables extra-secure behavior.\",\n          \"type\": \"boolean\"\n        },\n        \"pin\": {\n          \"description\": \"Default to pinning versions when running `mise use` in mise.toml files.\",\n          \"type\": \"boolean\"\n        },\n        \"pipx\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"registry_url\": {\n              \"default\": \"https://pypi.org/pypi/{}/json\",\n              \"description\": \"URL to use for pipx registry.\",\n              \"type\": \"string\"\n            },\n            \"uvx\": {\n              \"description\": \"Use uvx instead of pipx if uv is installed and on PATH.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"pipx_uvx\": {\n          \"description\": \"Use uvx instead of pipx if uv is installed and on PATH.\",\n          \"type\": \"boolean\"\n        },\n        \"plugin_autoupdate_last_check_duration\": {\n          \"default\": \"7d\",\n          \"description\": \"How long to wait before updating plugins automatically (note this isn't currently implemented).\",\n          \"type\": \"string\"\n        },\n        \"prefer_offline\": {\n          \"description\": \"Prefer locally cached data over remote fetches when possible.\",\n          \"type\": \"boolean\"\n        },\n        \"profile\": {\n          \"description\": \"Profile to use for mise.${MISE_PROFILE}.toml files.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"compile\": {\n              \"description\": \"If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\",\n              \"type\": \"boolean\"\n            },\n            \"default_packages_file\": {\n              \"description\": \"Path to a file containing default python packages to install when installing a python version.\",\n              \"type\": \"string\"\n            },\n            \"patch_url\": {\n              \"description\": \"URL to fetch python patches from to pass to python-build.\",\n              \"type\": \"string\"\n            },\n            \"patches_directory\": {\n              \"description\": \"Directory to fetch python patches from.\",\n              \"type\": \"string\"\n            },\n            \"precompiled_arch\": {\n              \"description\": \"Specify the architecture to use for precompiled binaries.\",\n              \"type\": \"string\"\n            },\n            \"precompiled_flavor\": {\n              \"description\": \"Specify the flavor to use for precompiled binaries.\",\n              \"type\": \"string\"\n            },\n            \"precompiled_os\": {\n              \"description\": \"Specify the OS to use for precompiled binaries.\",\n              \"type\": \"string\"\n            },\n            \"pyenv_repo\": {\n              \"default\": \"https://github.com/pyenv/pyenv.git\",\n              \"description\": \"URL to fetch pyenv from for compiling python with python-build.\",\n              \"type\": \"string\"\n            },\n            \"uv_venv_auto\": {\n              \"default\": false,\n              \"description\": \"Integrate with uv to manage project venvs when uv.lock is present.\",\n              \"type\": [\"boolean\", \"string\"],\n              \"enum\": [false, \"source\", \"create|source\", true]\n            },\n            \"uv_venv_create_args\": {\n              \"description\": \"Arguments to pass to uv when creating a venv.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"venv_create_args\": {\n              \"description\": \"Arguments to pass to python when creating a venv. (not used for uv venv creation)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"venv_stdlib\": {\n              \"description\": \"Prefer to use venv from Python's standard library.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"python_compile\": {\n          \"description\": \"If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"python_default_packages_file\": {\n          \"description\": \"Path to a file containing default python packages to install when installing python.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_patch_url\": {\n          \"description\": \"URL to fetch python patches from.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_patches_directory\": {\n          \"description\": \"Directory to fetch python patches from.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_precompiled_arch\": {\n          \"description\": \"Specify the architecture to use for precompiled binaries.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_precompiled_os\": {\n          \"description\": \"Specify the OS to use for precompiled binaries.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_pyenv_repo\": {\n          \"description\": \"URL to fetch pyenv from for compiling python.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"python_venv_stdlib\": {\n          \"description\": \"Prefer to use venv from Python's standard library.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"quiet\": {\n          \"description\": \"Suppress all output except errors.\",\n          \"type\": \"boolean\"\n        },\n        \"raw\": {\n          \"description\": \"Connect stdin/stdout/stderr to child processes.\",\n          \"type\": \"boolean\"\n        },\n        \"ruby\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"apply_patches\": {\n              \"description\": \"A list of patch files or URLs to apply to ruby source.\",\n              \"type\": \"string\"\n            },\n            \"compile\": {\n              \"description\": \"Set to true to compile ruby from source, false to use precompiled binaries.\",\n              \"type\": \"boolean\"\n            },\n            \"default_packages_file\": {\n              \"default\": \"~/.default-gems\",\n              \"description\": \"Path to a file containing default ruby gems to install when installing ruby.\",\n              \"type\": \"string\"\n            },\n            \"github_attestations\": {\n              \"description\": \"Enable GitHub Artifact Attestations verification for precompiled Ruby binaries.\",\n              \"type\": \"boolean\"\n            },\n            \"precompiled_arch\": {\n              \"description\": \"Override architecture identifier for precompiled Ruby binaries.\",\n              \"type\": \"string\"\n            },\n            \"precompiled_os\": {\n              \"description\": \"Override OS identifier for precompiled Ruby binaries.\",\n              \"type\": \"string\"\n            },\n            \"precompiled_url\": {\n              \"default\": \"jdx/ruby\",\n              \"description\": \"URL template or GitHub repo for precompiled Ruby binaries.\",\n              \"type\": \"string\"\n            },\n            \"ruby_build_opts\": {\n              \"description\": \"Options to pass to ruby-build.\",\n              \"type\": \"string\"\n            },\n            \"ruby_build_repo\": {\n              \"default\": \"https://github.com/rbenv/ruby-build.git\",\n              \"description\": \"The URL used to fetch ruby-build. This accepts either a Git repository or a ZIP archive.\",\n              \"type\": \"string\"\n            },\n            \"ruby_install\": {\n              \"description\": \"Use ruby-install instead of ruby-build.\",\n              \"type\": \"boolean\"\n            },\n            \"ruby_install_opts\": {\n              \"description\": \"Options to pass to ruby-install.\",\n              \"type\": \"string\"\n            },\n            \"ruby_install_repo\": {\n              \"default\": \"https://github.com/postmodern/ruby-install.git\",\n              \"description\": \"The URL used to fetch ruby-install. This accepts either a Git repository or a ZIP archive.\",\n              \"type\": \"string\"\n            },\n            \"verbose_install\": {\n              \"description\": \"Set to true to enable verbose output during ruby installation.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"rust\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"cargo_home\": {\n              \"description\": \"Path to the cargo home directory. Defaults to `~/.cargo` or `%USERPROFILE%\\\\.cargo`\",\n              \"type\": \"string\"\n            },\n            \"default_host\": {\n              \"description\": \"Default host triple to pass to `rustup init` via `--default-host`.\",\n              \"type\": \"string\"\n            },\n            \"rustup_home\": {\n              \"description\": \"Path to the rustup home directory. Defaults to `~/.rustup` or `%USERPROFILE%\\\\.rustup`\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"shared_install_dirs\": {\n          \"description\": \"[experimental] Additional read-only directories to search for installed tool versions.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"shorthands_file\": {\n          \"description\": \"Path to a file containing custom tool shorthands.\",\n          \"type\": \"string\"\n        },\n        \"silent\": {\n          \"description\": \"Suppress all `mise run|watch` output except errors—including what tasks output.\",\n          \"type\": \"boolean\"\n        },\n        \"slsa\": {\n          \"default\": true,\n          \"description\": \"Enable SLSA provenance verification globally.\",\n          \"type\": \"boolean\"\n        },\n        \"sops\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"age_key\": {\n              \"description\": \"The age private key to use for sops secret decryption. Takes precedence over standard SOPS_AGE_KEY environment variable.\",\n              \"type\": \"string\"\n            },\n            \"age_key_file\": {\n              \"description\": \"Path to the age private key file for sops secret decryption. Takes precedence over standard SOPS_AGE_KEY_FILE environment variable.\",\n              \"type\": \"string\"\n            },\n            \"age_recipients\": {\n              \"description\": \"The age public keys to use for sops secret encryption.\",\n              \"type\": \"string\"\n            },\n            \"rops\": {\n              \"default\": true,\n              \"description\": \"Use rops to decrypt sops files. Disable to shell out to `sops` which will slow down mise but sops may offer features not available in rops.\",\n              \"type\": \"boolean\"\n            },\n            \"strict\": {\n              \"default\": true,\n              \"description\": \"If true, fail when sops decryption fails (including when sops is not available, the key is missing, or the key is invalid). If false, skip decryption and continue in these cases.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"status\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"missing_tools\": {\n              \"default\": \"if_other_versions_installed\",\n              \"description\": \"Show a warning if tools are not installed when entering a directory with a mise.toml file.\",\n              \"type\": \"string\"\n            },\n            \"show_env\": {\n              \"description\": \"Show configured env vars when entering a directory with a mise.toml file.\",\n              \"type\": \"boolean\"\n            },\n            \"show_prepare_stale\": {\n              \"default\": true,\n              \"description\": \"Show warning when prepare providers have stale dependencies.\",\n              \"type\": \"boolean\"\n            },\n            \"show_tools\": {\n              \"description\": \"Show configured tools when entering a directory with a mise.toml file.\",\n              \"type\": \"boolean\"\n            },\n            \"truncate\": {\n              \"default\": true,\n              \"description\": \"Truncate status messages.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"swift\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"gpg_verify\": {\n              \"description\": \"Use gpg to verify swift tool signatures.\",\n              \"type\": \"boolean\"\n            },\n            \"platform\": {\n              \"description\": \"Override the platform to use for precompiled binaries.\",\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"system_config_file\": {\n          \"description\": \"Path to the system mise config file. Default is `/etc/mise/config.toml`. This must be an env var.\",\n          \"type\": \"string\"\n        },\n        \"task\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"disable_paths\": {\n              \"default\": [],\n              \"description\": \"Paths that mise will not look for tasks in.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"disable_spec_from_run_scripts\": {\n              \"default\": false,\n              \"description\": \"Opt out of parsing task run scripts to infer the usage spec (arguments and flags). When enabled, mise will derive the usage spec only from the `usage` field, ignoring any `arg()`, `option()`, or `flag()` templates used in run scripts. This can restore previous behavior and avoid the extra template pass over run scripts when collecting specs.\",\n              \"type\": \"boolean\"\n            },\n            \"monorepo_depth\": {\n              \"default\": 5,\n              \"description\": \"Maximum depth to search for task files in monorepo subdirectories.\",\n              \"type\": \"number\"\n            },\n            \"monorepo_exclude_dirs\": {\n              \"default\": [],\n              \"description\": \"Directory patterns to exclude when discovering monorepo subdirectories.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"monorepo_respect_gitignore\": {\n              \"default\": true,\n              \"description\": \"Whether to respect .gitignore files when discovering monorepo subdirectories.\",\n              \"type\": \"boolean\"\n            },\n            \"output\": {\n              \"description\": \"Change output style when executing tasks.\",\n              \"type\": \"string\",\n              \"enum\": [\n                \"prefix\",\n                \"interleave\",\n                \"keep-order\",\n                \"replacing\",\n                \"timed\",\n                \"quiet\",\n                \"silent\"\n              ]\n            },\n            \"remote_no_cache\": {\n              \"description\": \"Mise will always fetch the latest tasks from the remote, by default the cache is used.\",\n              \"type\": \"boolean\"\n            },\n            \"run_auto_install\": {\n              \"default\": true,\n              \"description\": \"Automatically install missing tools when executing tasks.\",\n              \"type\": \"boolean\"\n            },\n            \"show_full_cmd\": {\n              \"description\": \"Disable truncation of command lines in task execution output. When true, the full command line will be shown.\",\n              \"type\": \"boolean\"\n            },\n            \"skip\": {\n              \"default\": [],\n              \"description\": \"Tasks to skip when running `mise run`.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"skip_depends\": {\n              \"description\": \"Run only specified tasks skipping all dependencies.\",\n              \"type\": \"boolean\"\n            },\n            \"source_freshness_equal_mtime_is_fresh\": {\n              \"default\": false,\n              \"description\": \"When source mtime equals output mtime, consider sources fresh (use <=). Default false uses strict < comparison.\",\n              \"type\": \"boolean\"\n            },\n            \"source_freshness_hash_contents\": {\n              \"default\": false,\n              \"description\": \"Use content hashing (blake3) instead of metadata for source freshness. More accurate but slower.\",\n              \"type\": \"boolean\"\n            },\n            \"timeout\": {\n              \"description\": \"Default timeout for tasks. Can be overridden by individual tasks.\",\n              \"type\": \"string\"\n            },\n            \"timings\": {\n              \"description\": \"Show completion message with elapsed time for each task on `mise run`. Default shows when output type is `prefix`.\",\n              \"type\": \"boolean\"\n            }\n          }\n        },\n        \"task_disable_paths\": {\n          \"description\": \"Paths that mise will not look for tasks in.\",\n          \"type\": \"array\",\n          \"deprecated\": true,\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"task_output\": {\n          \"description\": \"Change output style when executing tasks.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"task_remote_no_cache\": {\n          \"description\": \"Mise will always fetch the latest tasks from the remote, by default the cache is used.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"task_run_auto_install\": {\n          \"description\": \"Automatically install missing tools when executing tasks.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"task_show_full_cmd\": {\n          \"description\": \"Disable truncation of command lines in task execution output. When true, the full command line will be shown.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"task_skip\": {\n          \"description\": \"Tasks to skip when running `mise run`.\",\n          \"type\": \"array\",\n          \"deprecated\": true,\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"task_skip_depends\": {\n          \"description\": \"Run only specified tasks skipping all dependencies.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"task_timeout\": {\n          \"description\": \"Default timeout for tasks. Can be overridden by individual tasks.\",\n          \"type\": \"string\",\n          \"deprecated\": true\n        },\n        \"task_timings\": {\n          \"description\": \"Show completion message with elapsed time for each task on `mise run`. Default shows when output type is `prefix`.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"terminal_progress\": {\n          \"default\": true,\n          \"description\": \"Enable terminal progress indicators (OSC 9;4) for compatible terminals.\",\n          \"type\": \"boolean\"\n        },\n        \"trace\": {\n          \"description\": \"Sets log level to trace\",\n          \"type\": \"boolean\"\n        },\n        \"trusted_config_paths\": {\n          \"default\": [],\n          \"description\": \"This is a list of config paths that mise will automatically mark as trusted.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"unix_default_file_shell_args\": {\n          \"default\": \"sh\",\n          \"description\": \"Default shell arguments for Unix to be used for file commands. For example, `sh` for sh.\",\n          \"type\": \"string\"\n        },\n        \"unix_default_inline_shell_args\": {\n          \"default\": \"sh -c -o errexit\",\n          \"description\": \"Default shell arguments for Unix to be used for inline commands. For example, `sh -c` for sh.\",\n          \"type\": \"string\"\n        },\n        \"url_replacements\": {\n          \"description\": \"Map of URL patterns to replacement URLs applied to all requests.\",\n          \"type\": \"object\",\n          \"additionalProperties\": {\n            \"type\": \"string\"\n          }\n        },\n        \"use_file_shell_for_executable_tasks\": {\n          \"default\": false,\n          \"description\": \"Determines whether to use a specified shell for executing tasks in the tasks directory. When set to true, the shell defined in the file will be used, or the default shell specified by `windows_default_file_shell_args` or `unix_default_file_shell_args` will be applied. If set to false, tasks will be executed directly as programs.\",\n          \"type\": \"boolean\"\n        },\n        \"use_versions_host\": {\n          \"default\": true,\n          \"description\": \"Set to false to disable using the mise-versions API as a quick way for mise to query for new versions.\",\n          \"type\": \"boolean\"\n        },\n        \"use_versions_host_track\": {\n          \"default\": true,\n          \"description\": \"Send anonymous download statistics when installing tools.\",\n          \"type\": \"boolean\"\n        },\n        \"verbose\": {\n          \"description\": \"Shows more verbose output such as installation logs when installing tools.\",\n          \"type\": \"boolean\"\n        },\n        \"vfox\": {\n          \"description\": \"Use vfox as a default plugin backend instead of asdf.\",\n          \"type\": \"boolean\",\n          \"deprecated\": true\n        },\n        \"windows_default_file_shell_args\": {\n          \"default\": \"cmd /c\",\n          \"description\": \"Default shell arguments for Windows to be used for file commands. For example, `cmd /c` for cmd.exe.\",\n          \"type\": \"string\"\n        },\n        \"windows_default_inline_shell_args\": {\n          \"default\": \"cmd /c\",\n          \"description\": \"Default shell arguments for Windows to be used for inline commands. For example, `cmd /c` for cmd.exe.\",\n          \"type\": \"string\"\n        },\n        \"windows_executable_extensions\": {\n          \"default\": [\"exe\", \"bat\", \"cmd\", \"com\", \"ps1\", \"vbs\"],\n          \"description\": \"List of executable extensions for Windows. For example, `exe` for .exe files, `bat` for .bat files, and so on.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"windows_shim_mode\": {\n          \"default\": \"exe\",\n          \"description\": \"Shim file mode for Windows. Options: `exe`, `file`, `hardlink`, `symlink`.\",\n          \"type\": \"string\"\n        },\n        \"yes\": {\n          \"description\": \"This will automatically answer yes or no to prompts. This is useful for scripting.\",\n          \"type\": \"boolean\"\n        },\n        \"zig\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"use_community_mirrors\": {\n              \"default\": true,\n              \"description\": \"Download Zig from community-maintained mirrors\",\n              \"type\": \"boolean\"\n            }\n          }\n        }\n      }\n    },\n    \"task_run_entry\": {\n      \"oneOf\": [\n        {\n          \"description\": \"script to run\",\n          \"type\": \"string\"\n        },\n        {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"task\": {\n              \"description\": \"single task name (with optional args) to run\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"task\"]\n        },\n        {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"tasks\": {\n              \"description\": \"parallel task group to run\",\n              \"items\": {\n                \"description\": \"task name and args\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            }\n          },\n          \"required\": [\"tasks\"]\n        }\n      ]\n    },\n    \"task\": {\n      \"oneOf\": [\n        {\n          \"description\": \"script to run\",\n          \"type\": \"string\"\n        },\n        {\n          \"description\": \"script to run\",\n          \"items\": {\n            \"description\": \"script to run\",\n            \"type\": \"string\"\n          },\n          \"type\": \"array\"\n        },\n        {\n          \"properties\": {\n            \"alias\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"alias for this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"alias for this task\",\n                  \"items\": {\n                    \"description\": \"alias for this task\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"confirm\": {\n              \"description\": \"confirmation message before running this task\",\n              \"type\": \"string\"\n            },\n            \"depends\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to run before this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to run before this task\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  }\n                }\n              ]\n            },\n            \"depends_post\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to run after this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to run after this task\",\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  }\n                }\n              ]\n            },\n            \"wait_for\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"task with args to wait for completion first\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"task with args to wait for completion first\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_dependency_item\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"description\": {\n              \"description\": \"description of task\",\n              \"type\": \"string\"\n            },\n            \"dir\": {\n              \"default\": \"{{ config_root }}\",\n              \"description\": \"directory to run script in, default is the project's base directory\",\n              \"type\": \"string\"\n            },\n            \"env\": {\n              \"$ref\": \"#/$defs/env\"\n            },\n            \"vars\": {\n              \"$ref\": \"#/$defs/vars\"\n            },\n            \"tools\": {\n              \"description\": \"tools to install/activate before running this task\",\n              \"additionalProperties\": {\n                \"oneOf\": [\n                  {\n                    \"description\": \"version of the tool to install\",\n                    \"type\": \"string\"\n                  },\n                  {\n                    \"properties\": {\n                      \"version\": {\n                        \"description\": \"version of the tool to install\",\n                        \"type\": \"string\"\n                      },\n                      \"os\": {\n                        \"oneOf\": [\n                          {\n                            \"description\": \"operating system to install on\",\n                            \"type\": \"array\"\n                          },\n                          {\n                            \"description\": \"option to pass to tool\",\n                            \"type\": \"string\"\n                          },\n                          {\n                            \"description\": \"option to pass to tool\",\n                            \"type\": \"boolean\"\n                          }\n                        ]\n                      }\n                    },\n                    \"required\": [\"version\"],\n                    \"type\": \"object\",\n                    \"additionalProperties\": {\n                      \"oneOf\": [\n                        {\n                          \"type\": \"string\"\n                        }\n                      ]\n                    }\n                  }\n                ]\n              },\n              \"type\": \"object\"\n            },\n            \"hide\": {\n              \"default\": false,\n              \"description\": \"do not display this task\",\n              \"type\": \"boolean\"\n            },\n            \"outputs\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"files created by this task\",\n                  \"items\": {\n                    \"description\": \"glob pattern or path to files created by this task\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                },\n                {\n                  \"description\": \"glob pattern or path to files created by this task\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"additionalProperties\": false,\n                  \"properties\": {\n                    \"auto\": {\n                      \"description\": \"automatically touch an internal tracked file instead of specifying outputs\",\n                      \"enum\": [true],\n                      \"type\": \"boolean\"\n                    }\n                  },\n                  \"required\": [\"auto\"],\n                  \"type\": \"object\"\n                }\n              ]\n            },\n            \"quiet\": {\n              \"default\": false,\n              \"description\": \"do not display mise information for this task\",\n              \"type\": \"boolean\"\n            },\n            \"silent\": {\n              \"default\": false,\n              \"description\": \"suppress all output for this task\",\n              \"oneOf\": [\n                {\n                  \"type\": \"boolean\"\n                },\n                {\n                  \"enum\": [\"stdout\", \"stderr\"],\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"interactive\": {\n              \"default\": false,\n              \"description\": \"mark task as interactive, acquiring exclusive terminal access while allowing other non-interactive tasks to run in parallel\",\n              \"type\": \"boolean\"\n            },\n            \"raw\": {\n              \"default\": false,\n              \"description\": \"directly connect task to stdin/stdout/stderr\",\n              \"type\": \"boolean\"\n            },\n            \"run\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/task_run_entry\"\n                },\n                {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_run_entry\"\n                  }\n                }\n              ]\n            },\n            \"run_windows\": {\n              \"oneOf\": [\n                {\n                  \"$ref\": \"#/$defs/task_run_entry\"\n                },\n                {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"$ref\": \"#/$defs/task_run_entry\"\n                  }\n                }\n              ]\n            },\n            \"file\": {\n              \"description\": \"Execute an external script\",\n              \"type\": \"string\"\n            },\n            \"sources\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"files that this task depends on\",\n                  \"items\": {\n                    \"description\": \"glob pattern or path to files that this task depends on\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                },\n                {\n                  \"description\": \"glob pattern or path to files that this task depends on\",\n                  \"type\": \"string\"\n                }\n              ]\n            },\n            \"shell\": {\n              \"description\": \"specify a shell command to run the script with\",\n              \"type\": \"string\"\n            },\n            \"usage\": {\n              \"description\": \"Specify usage (https://usage.jdx.dev/) specs for the task\",\n              \"type\": \"string\"\n            },\n            \"timeout\": {\n              \"description\": \"timeout for this task\",\n              \"type\": \"string\"\n            },\n            \"extends\": {\n              \"description\": \"name of the task template to extend\",\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\"\n        }\n      ]\n    },\n    \"vars\": {\n      \"description\": \"variables to set\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"_\": {\n          \"description\": \"vars modules\",\n          \"additionalProperties\": true,\n          \"properties\": {\n            \"file\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"dotenv file to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"dotenv files to load\",\n                  \"items\": {\n                    \"description\": \"dotenv file to load\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            },\n            \"source\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"bash script to load\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"bash scripts to load\",\n                  \"items\": {\n                    \"description\": \"bash script to load\",\n                    \"type\": \"string\"\n                  },\n                  \"type\": \"array\"\n                }\n              ]\n            }\n          },\n          \"type\": \"object\"\n        }\n      },\n      \"additionalProperties\": {\n        \"description\": \"value of variable\",\n        \"type\": \"string\"\n      }\n    },\n    \"task_config\": {\n      \"description\": \"configuration for task execution/management\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"dir\": {\n          \"description\": \"default directory to run tasks in defined in this file\",\n          \"type\": \"string\"\n        },\n        \"includes\": {\n          \"description\": \"files/directories to include searching for tasks. Can be local paths or git repository URLs using git:: prefix (e.g., git::https://github.com/org/repo.git//path?ref=branch)\",\n          \"items\": {\n            \"description\": \"file/directory root to include in task execution. Supports local paths and git URLs (git::https://github.com/org/repo.git//path?ref=branch)\",\n            \"type\": \"string\"\n          },\n          \"type\": \"array\"\n        }\n      }\n    },\n    \"experimental_monorepo_root\": {\n      \"description\": \"Marks this config as a monorepo root, enabling target path syntax for tasks. Requires MISE_EXPERIMENTAL=1. When enabled, tasks can be referenced with paths like //projects/frontend:build\",\n      \"type\": \"boolean\"\n    },\n    \"monorepo\": {\n      \"description\": \"Configuration for monorepo task discovery\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"config_roots\": {\n          \"description\": \"Explicit list of config root paths for monorepo task discovery. Supports single-level glob patterns (*). When set, skips filesystem walking for better performance.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    },\n    \"tool\": {\n      \"oneOf\": [\n        {\n          \"description\": \"version of the tool to install\",\n          \"type\": \"string\"\n        },\n        {\n          \"properties\": {\n            \"version\": {\n              \"description\": \"version of the tool to install\",\n              \"type\": \"string\"\n            },\n            \"os\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"operating system to install on\",\n                  \"type\": \"array\"\n                },\n                {\n                  \"description\": \"option to pass to tool\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"description\": \"option to pass to tool\",\n                  \"type\": \"boolean\"\n                }\n              ]\n            },\n            \"install_env\": {\n              \"type\": \"object\",\n              \"additionalProperties\": {\n                \"oneOf\": [\n                  {\n                    \"type\": \"string\"\n                  },\n                  {\n                    \"type\": \"number\"\n                  },\n                  {\n                    \"type\": \"boolean\"\n                  }\n                ]\n              },\n              \"description\": \"environment variables during tool installation\"\n            },\n            \"postinstall\": {\n              \"description\": \"command to run after tool installation\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"version\"],\n          \"type\": \"object\",\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"type\": \"number\"\n              },\n              {\n                \"type\": \"boolean\"\n              },\n              {\n                \"type\": \"object\",\n                \"additionalProperties\": true\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"hooks\": {\n      \"description\": \"hooks to run\",\n      \"type\": \"object\",\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"description\": \"script to run\",\n            \"type\": \"string\"\n          },\n          {\n            \"additionalProperties\": false,\n            \"properties\": {\n              \"script\": {\n                \"description\": \"script to run\",\n                \"type\": \"string\"\n              },\n              \"shell\": {\n                \"description\": \"specify the shell to run the script inside of\",\n                \"type\": \"string\"\n              }\n            },\n            \"type\": \"object\"\n          },\n          {\n            \"additionalProperties\": false,\n            \"properties\": {\n              \"task\": {\n                \"description\": \"mise task to run\",\n                \"type\": \"string\"\n              }\n            },\n            \"required\": [\"task\"],\n            \"type\": \"object\"\n          },\n          {\n            \"description\": \"scripts/tasks to run\",\n            \"items\": {\n              \"oneOf\": [\n                {\n                  \"description\": \"script to run\",\n                  \"type\": \"string\"\n                },\n                {\n                  \"additionalProperties\": false,\n                  \"properties\": {\n                    \"script\": {\n                      \"description\": \"script to run\",\n                      \"type\": \"string\"\n                    },\n                    \"shell\": {\n                      \"description\": \"specify the shell to run the script inside of\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"type\": \"object\"\n                },\n                {\n                  \"additionalProperties\": false,\n                  \"properties\": {\n                    \"task\": {\n                      \"description\": \"mise task to run\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\"task\"],\n                  \"type\": \"object\"\n                }\n              ]\n            },\n            \"type\": \"array\"\n          }\n        ]\n      }\n    },\n    \"watch_files\": {\n      \"description\": \"files to watch for changes\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"description\": \"file to watch for changes\",\n        \"additionalProperties\": false,\n        \"properties\": {\n          \"run\": {\n            \"type\": \"string\",\n            \"description\": \"script to run when file changes\"\n          },\n          \"task\": {\n            \"type\": \"string\",\n            \"description\": \"mise task to run when file changes\"\n          },\n          \"patterns\": {\n            \"type\": \"array\",\n            \"description\": \"patterns to watch for\",\n            \"items\": {\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"oneOf\": [\n          {\n            \"required\": [\"run\"]\n          },\n          {\n            \"required\": [\"task\"]\n          }\n        ]\n      }\n    },\n    \"prepare_provider\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"auto\": {\n          \"type\": \"boolean\",\n          \"default\": false,\n          \"description\": \"Auto-run before `mise x` and `mise run`\"\n        },\n        \"sources\": {\n          \"oneOf\": [\n            {\n              \"type\": \"string\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          ],\n          \"description\": \"Files/patterns to check for changes\"\n        },\n        \"outputs\": {\n          \"oneOf\": [\n            {\n              \"type\": \"string\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          ],\n          \"description\": \"Files/directories that should be newer than sources\"\n        },\n        \"run\": {\n          \"type\": \"string\",\n          \"description\": \"Command to run when stale\"\n        },\n        \"env\": {\n          \"type\": \"object\",\n          \"additionalProperties\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"Environment variables to set\"\n        },\n        \"dir\": {\n          \"type\": \"string\",\n          \"description\": \"Working directory for the command\"\n        },\n        \"description\": {\n          \"type\": \"string\",\n          \"description\": \"Description shown in output\"\n        },\n        \"depends\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"Other prepare providers that must complete before this one runs\"\n        },\n        \"timeout\": {\n          \"type\": \"string\",\n          \"description\": \"Timeout for the run command (e.g., \\\"30s\\\", \\\"5m\\\", \\\"1h\\\")\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"description\": \"Prepare provider configuration\"\n    },\n    \"task_props\": {\n      \"description\": \"common task properties\",\n      \"properties\": {\n        \"alias\": {\n          \"oneOf\": [\n            {\n              \"description\": \"alias for this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"alias for this task\",\n              \"items\": {\n                \"description\": \"alias for this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"confirm\": {\n          \"description\": \"confirmation message before running this task\",\n          \"type\": \"string\"\n        },\n        \"depends\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"depends_post\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"wait_for\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"description\": {\n          \"description\": \"description of task\",\n          \"type\": \"string\"\n        },\n        \"dir\": {\n          \"default\": \"{{ config_root }}\",\n          \"description\": \"directory to run script in, default is the project's base directory\",\n          \"type\": \"string\"\n        },\n        \"env\": {\n          \"$ref\": \"#/$defs/env\"\n        },\n        \"vars\": {\n          \"$ref\": \"#/$defs/vars\"\n        },\n        \"tools\": {\n          \"description\": \"tools to install/activate before running this task\",\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"description\": \"version of the tool to install\",\n                \"type\": \"string\"\n              },\n              {\n                \"properties\": {\n                  \"version\": {\n                    \"description\": \"version of the tool to install\",\n                    \"type\": \"string\"\n                  },\n                  \"os\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"operating system to install on\",\n                        \"type\": \"array\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"boolean\"\n                      }\n                    ]\n                  }\n                },\n                \"required\": [\"version\"],\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                  \"oneOf\": [\n                    {\n                      \"type\": \"string\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          \"type\": \"object\"\n        },\n        \"hide\": {\n          \"default\": false,\n          \"description\": \"do not display this task\",\n          \"type\": \"boolean\"\n        },\n        \"outputs\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files created by this task\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files created by this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files created by this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"auto\": {\n                  \"description\": \"automatically touch an internal tracked file instead of specifying outputs\",\n                  \"enum\": [true],\n                  \"type\": \"boolean\"\n                }\n              },\n              \"required\": [\"auto\"],\n              \"type\": \"object\"\n            }\n          ]\n        },\n        \"quiet\": {\n          \"default\": false,\n          \"description\": \"do not display mise information for this task\",\n          \"type\": \"boolean\"\n        },\n        \"silent\": {\n          \"default\": false,\n          \"description\": \"suppress all output for this task\",\n          \"oneOf\": [\n            {\n              \"type\": \"boolean\"\n            },\n            {\n              \"enum\": [\"stdout\", \"stderr\"],\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"interactive\": {\n          \"default\": false,\n          \"description\": \"mark task as interactive, acquiring exclusive terminal access while allowing other non-interactive tasks to run in parallel\",\n          \"type\": \"boolean\"\n        },\n        \"raw\": {\n          \"default\": false,\n          \"description\": \"directly connect task to stdin/stdout/stderr\",\n          \"type\": \"boolean\"\n        },\n        \"run\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"run_windows\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"file\": {\n          \"description\": \"Execute an external script\",\n          \"type\": \"string\"\n        },\n        \"sources\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files that this task depends on\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files that this task depends on\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files that this task depends on\",\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"shell\": {\n          \"description\": \"specify a shell command to run the script with\",\n          \"type\": \"string\"\n        },\n        \"usage\": {\n          \"description\": \"Specify usage (https://usage.jdx.dev/) specs for the task\",\n          \"type\": \"string\"\n        },\n        \"timeout\": {\n          \"description\": \"timeout for this task\",\n          \"type\": \"string\"\n        }\n      },\n      \"type\": \"object\"\n    },\n    \"task_template\": {\n      \"description\": \"task template that can be extended by tasks\",\n      \"properties\": {\n        \"alias\": {\n          \"oneOf\": [\n            {\n              \"description\": \"alias for this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"alias for this task\",\n              \"items\": {\n                \"description\": \"alias for this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"confirm\": {\n          \"description\": \"confirmation message before running this task\",\n          \"type\": \"string\"\n        },\n        \"depends\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run before this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"depends_post\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to run after this task\",\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              }\n            }\n          ]\n        },\n        \"wait_for\": {\n          \"oneOf\": [\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"type\": \"string\"\n            },\n            {\n              \"description\": \"task with args to wait for completion first\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_dependency_item\"\n              },\n              \"type\": \"array\"\n            }\n          ]\n        },\n        \"description\": {\n          \"description\": \"description of task\",\n          \"type\": \"string\"\n        },\n        \"dir\": {\n          \"default\": \"{{ config_root }}\",\n          \"description\": \"directory to run script in, default is the project's base directory\",\n          \"type\": \"string\"\n        },\n        \"env\": {\n          \"$ref\": \"#/$defs/env\"\n        },\n        \"vars\": {\n          \"$ref\": \"#/$defs/vars\"\n        },\n        \"tools\": {\n          \"description\": \"tools to install/activate before running this task\",\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"description\": \"version of the tool to install\",\n                \"type\": \"string\"\n              },\n              {\n                \"properties\": {\n                  \"version\": {\n                    \"description\": \"version of the tool to install\",\n                    \"type\": \"string\"\n                  },\n                  \"os\": {\n                    \"oneOf\": [\n                      {\n                        \"description\": \"operating system to install on\",\n                        \"type\": \"array\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"string\"\n                      },\n                      {\n                        \"description\": \"option to pass to tool\",\n                        \"type\": \"boolean\"\n                      }\n                    ]\n                  }\n                },\n                \"required\": [\"version\"],\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                  \"oneOf\": [\n                    {\n                      \"type\": \"string\"\n                    }\n                  ]\n                }\n              }\n            ]\n          },\n          \"type\": \"object\"\n        },\n        \"hide\": {\n          \"default\": false,\n          \"description\": \"do not display this task\",\n          \"type\": \"boolean\"\n        },\n        \"outputs\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files created by this task\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files created by this task\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files created by this task\",\n              \"type\": \"string\"\n            },\n            {\n              \"additionalProperties\": false,\n              \"properties\": {\n                \"auto\": {\n                  \"description\": \"automatically touch an internal tracked file instead of specifying outputs\",\n                  \"enum\": [true],\n                  \"type\": \"boolean\"\n                }\n              },\n              \"required\": [\"auto\"],\n              \"type\": \"object\"\n            }\n          ]\n        },\n        \"quiet\": {\n          \"default\": false,\n          \"description\": \"do not display mise information for this task\",\n          \"type\": \"boolean\"\n        },\n        \"silent\": {\n          \"default\": false,\n          \"description\": \"suppress all output for this task\",\n          \"oneOf\": [\n            {\n              \"type\": \"boolean\"\n            },\n            {\n              \"enum\": [\"stdout\", \"stderr\"],\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"interactive\": {\n          \"default\": false,\n          \"description\": \"mark task as interactive, acquiring exclusive terminal access while allowing other non-interactive tasks to run in parallel\",\n          \"type\": \"boolean\"\n        },\n        \"raw\": {\n          \"default\": false,\n          \"description\": \"directly connect task to stdin/stdout/stderr\",\n          \"type\": \"boolean\"\n        },\n        \"run\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"run_windows\": {\n          \"oneOf\": [\n            {\n              \"$ref\": \"#/$defs/task_run_entry\"\n            },\n            {\n              \"type\": \"array\",\n              \"items\": {\n                \"$ref\": \"#/$defs/task_run_entry\"\n              }\n            }\n          ]\n        },\n        \"file\": {\n          \"description\": \"Execute an external script\",\n          \"type\": \"string\"\n        },\n        \"sources\": {\n          \"oneOf\": [\n            {\n              \"description\": \"files that this task depends on\",\n              \"items\": {\n                \"description\": \"glob pattern or path to files that this task depends on\",\n                \"type\": \"string\"\n              },\n              \"type\": \"array\"\n            },\n            {\n              \"description\": \"glob pattern or path to files that this task depends on\",\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"shell\": {\n          \"description\": \"specify a shell command to run the script with\",\n          \"type\": \"string\"\n        },\n        \"usage\": {\n          \"description\": \"Specify usage (https://usage.jdx.dev/) specs for the task\",\n          \"type\": \"string\"\n        },\n        \"timeout\": {\n          \"description\": \"timeout for this task\",\n          \"type\": \"string\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"description\": \"config file for mise version manager (mise.toml)\",\n  \"properties\": {\n    \"alias\": {\n      \"deprecated\": true,\n      \"description\": \"custom shorthands\",\n      \"type\": \"object\",\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"description\": \"where the alias goes\",\n            \"type\": \"string\"\n          },\n          {\n            \"description\": \"tool to set aliases for\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n              \"description\": \"version alias points to\",\n              \"type\": \"string\"\n            }\n          }\n        ]\n      }\n    },\n    \"tool_alias\": {\n      \"description\": \"Tool version aliases\",\n      \"type\": \"object\",\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"description\": \"where the alias goes\",\n            \"type\": \"string\"\n          },\n          {\n            \"description\": \"tool to set aliases for\",\n            \"type\": \"object\",\n            \"additionalProperties\": {\n              \"description\": \"version alias points to\",\n              \"type\": \"string\"\n            }\n          }\n        ]\n      }\n    },\n    \"shell_alias\": {\n      \"description\": \"shell aliases\",\n      \"type\": \"object\",\n      \"additionalProperties\": {\n        \"description\": \"command to run\",\n        \"type\": \"string\"\n      }\n    },\n    \"env\": {\n      \"description\": \"environment variables to set\",\n      \"oneOf\": [\n        {\n          \"$ref\": \"#/$defs/env\"\n        },\n        {\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/$defs/env\"\n          }\n        }\n      ]\n    },\n    \"experimental_monorepo_root\": {\n      \"description\": \"marks this config as a monorepo root for task path syntax\",\n      \"$ref\": \"#/$defs/experimental_monorepo_root\"\n    },\n    \"monorepo\": {\n      \"description\": \"configuration for monorepo task discovery\",\n      \"$ref\": \"#/$defs/monorepo\"\n    },\n    \"min_version\": {\n      \"description\": \"minimum version of mise required to use this config\",\n      \"oneOf\": [\n        {\n          \"pattern\": \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\",\n          \"type\": \"string\"\n        },\n        {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"properties\": {\n            \"hard\": {\n              \"description\": \"error if current mise is lower than this version\",\n              \"type\": \"string\",\n              \"pattern\": \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\"\n            },\n            \"soft\": {\n              \"description\": \"warn if current mise is lower than this version\",\n              \"type\": \"string\",\n              \"pattern\": \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\"\n            }\n          }\n        }\n      ]\n    },\n    \"redactions\": {\n      \"description\": \"env or vars keys to redact from logs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"plugins\": {\n      \"additionalProperties\": {\n        \"description\": \"url to plugin repository\",\n        \"type\": \"string\"\n      },\n      \"description\": \"plugins to use\",\n      \"type\": \"object\"\n    },\n    \"prepare\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"disable\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"description\": \"Disable specific prepare providers\"\n        },\n        \"npm\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"yarn\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"pnpm\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"bun\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"go\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"pip\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"poetry\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"uv\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"bundler\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        },\n        \"composer\": {\n          \"$ref\": \"#/$defs/prepare_provider\"\n        }\n      },\n      \"additionalProperties\": {\n        \"$ref\": \"#/$defs/prepare_provider\"\n      },\n      \"description\": \"configure prepare providers\"\n    },\n    \"settings\": {\n      \"$ref\": \"#/$defs/settings\",\n      \"description\": \"mise settings\",\n      \"type\": \"object\"\n    },\n    \"task_config\": {\n      \"description\": \"configuration for task execution and management\",\n      \"$ref\": \"#/$defs/task_config\"\n    },\n    \"tasks\": {\n      \"additionalProperties\": {\n        \"$ref\": \"#/$defs/task\"\n      },\n      \"description\": \"task runner tasks\",\n      \"type\": \"object\"\n    },\n    \"task_templates\": {\n      \"description\": \"task templates that can be extended by tasks via extends\",\n      \"additionalProperties\": {\n        \"$ref\": \"#/$defs/task_template\"\n      },\n      \"type\": \"object\"\n    },\n    \"tools\": {\n      \"additionalProperties\": {\n        \"oneOf\": [\n          {\n            \"items\": {\n              \"$ref\": \"#/$defs/tool\"\n            },\n            \"type\": \"array\"\n          },\n          {\n            \"$ref\": \"#/$defs/tool\"\n          }\n        ]\n      },\n      \"description\": \"dev tools to use\",\n      \"type\": \"object\"\n    },\n    \"hooks\": {\n      \"description\": \"hooks to run on events like cd, enter, leave\",\n      \"$ref\": \"#/$defs/hooks\"\n    },\n    \"vars\": {\n      \"description\": \"variables to set for use in config templates\",\n      \"$ref\": \"#/$defs/vars\"\n    },\n    \"watch_files\": {\n      \"description\": \"files to watch for changes and run scripts when modified\",\n      \"$ref\": \"#/$defs/watch_files\"\n    },\n    \"_\": {\n      \"type\": \"object\",\n      \"additionalProperties\": true\n    }\n  }\n}\n"
  },
  {
    "path": "schema/mise.plugin.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://mise.jdx.dev/schema/mise.plugin.json\",\n  \"title\": \"mise-plugin\",\n  \"description\": \"config file for a mise plugin\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"list-aliases\": {\n      \"description\": \"configuration for bin/list-aliases script\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"data\": {\n          \"description\": \"list of aliases to add\",\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"list-legacy-filenames\": {\n      \"description\": \"configuration for bin/list-legacy-filenames script\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"data\": {\n          \"description\": \"list of idiomatic filenames to check for\",\n          \"type\": \"string\"\n        }\n      }\n    },\n    \"list-bin-paths\": {\n      \"description\": \"configuration for bin/list-bin-paths script\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"cache-key\": {\n          \"description\": \"cache the results of bin/exec-env separately based on these values\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    },\n    \"exec-env\": {\n      \"description\": \"configuration for bin/exec-env script\",\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"cache-key\": {\n          \"description\": \"cache the results of bin/exec-env separately based on these values\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "schema/miserc.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"mise rc config\",\n  \"description\": \"Early initialization settings for mise. These settings are loaded before the main config files.\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"ceiling_paths\": {\n      \"default\": [],\n      \"description\": \"Directories where mise stops searching for config files.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"env\": {\n      \"default\": [],\n      \"description\": \"Env to use for mise.<MISE_ENV>.toml files.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"ignored_config_paths\": {\n      \"default\": [],\n      \"description\": \"This is a list of config paths that mise will ignore.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"override_config_filenames\": {\n      \"default\": [],\n      \"description\": \"If set, mise will ignore default config files like `mise.toml` and use these filenames instead.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"override_tool_versions_filenames\": {\n      \"default\": [],\n      \"description\": \"If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/build-deb.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nMISE_VERSION=$(./scripts/get-version.sh)\n\nmkdir -p mise/lib\ncat >mise/lib/mise-self-update-instructions.toml <<'TOML'\nmessage = \"To update mise from the APT repository, run:\\n\\n  sudo apt update && sudo apt install --only-upgrade mise\\n\"\nTOML\n\ntar -xvJf \"dist/mise-$MISE_VERSION-linux-x64.tar.xz\"\nfpm -s dir -t deb \\\n\t--name mise \\\n\t--license MIT \\\n\t--version \"${MISE_VERSION#v*}\" \\\n\t--architecture amd64 \\\n\t--description \"The front-end to your dev env\" \\\n\t--url \"https://github.com/jdx/mise\" \\\n\t--maintainer \"Jeff Dickey @jdx\" \\\n\tmise/bin/mise=/usr/bin/mise \\\n\tmise/lib/mise-self-update-instructions.toml=/usr/lib/mise/mise-self-update-instructions.toml \\\n\tmise/man/man1/mise.1=/usr/share/man/man1/mise.1\n\ntar -xvJf \"dist/mise-$MISE_VERSION-linux-arm64.tar.xz\"\nfpm -s dir -t deb \\\n\t--name mise \\\n\t--license MIT \\\n\t--version \"${MISE_VERSION#v*}\" \\\n\t--architecture arm64 \\\n\t--description \"The front-end to your dev env\" \\\n\t--url \"https://github.com/jdx/mise\" \\\n\t--maintainer \"Jeff Dickey @jdx\" \\\n\tmise/bin/mise=/usr/bin/mise \\\n\tmise/lib/mise-self-update-instructions.toml=/usr/lib/mise/mise-self-update-instructions.toml \\\n\tmise/man/man1/mise.1=/usr/share/man/man1/mise.1\n\nmkdir -p dist/deb/pool/main\ncp -v ./*.deb dist/deb/pool/main\nmkdir -p dist/deb/dists/stable/main/binary-amd64\nmkdir -p dist/deb/dists/stable/main/binary-arm64\ncd dist/deb\ndpkg-scanpackages --arch amd64 pool/ >dists/stable/main/binary-amd64/Packages\ndpkg-scanpackages --arch arm64 pool/ >dists/stable/main/binary-arm64/Packages\ngzip -9c <dists/stable/main/binary-amd64/Packages >dists/stable/main/binary-amd64/Packages.gz\ngzip -9c <dists/stable/main/binary-arm64/Packages >dists/stable/main/binary-arm64/Packages.gz\ncd ../..\n\ncd dist/deb/dists/stable\n\"$GITHUB_WORKSPACE/packaging/deb/generate-release.sh\" >Release\ngpg -u 8B81C9D17413A06D -abs <Release >Release.gpg\ngpg -u 8B81C9D17413A06D -abs --clearsign <Release >InRelease\ncd \"$GITHUB_WORKSPACE\"\n"
  },
  {
    "path": "scripts/build-rpm.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nMISE_VERSION=$(./scripts/get-version.sh)\n\nmkdir -p mise/lib\ncat >mise/lib/mise-self-update-instructions.toml <<'TOML'\nmessage = \"To update mise from the RPM repository, run:\\n\\n  sudo dnf upgrade mise\\n\"\nTOML\n\ntar -xvJf \"dist/mise-$MISE_VERSION-linux-x64.tar.xz\"\nfpm -s dir -t rpm \\\n\t--name mise \\\n\t--license MIT \\\n\t--version \"${MISE_VERSION#v*}\" \\\n\t--architecture x86_64 \\\n\t--description \"The front-end to your dev env\" \\\n\t--url \"https://github.com/jdx/mise\" \\\n\t--maintainer \"Jeff Dickey @jdx\" \\\n\tmise/bin/mise=/usr/bin/mise \\\n\tmise/lib/mise-self-update-instructions.toml=/usr/lib/mise/mise-self-update-instructions.toml \\\n\tmise/man/man1/mise.1=/usr/share/man/man1/mise.1\n\ntar -xvJf \"dist/mise-$MISE_VERSION-linux-arm64.tar.xz\"\nfpm -s dir -t rpm \\\n\t--name mise \\\n\t--license MIT \\\n\t--version \"${MISE_VERSION#v*}\" \\\n\t--architecture aarch64 \\\n\t--description \"The front-end to your dev env\" \\\n\t--url \"https://github.com/jdx/mise\" \\\n\t--maintainer \"Jeff Dickey @jdx\" \\\n\tmise/bin/mise=/usr/bin/mise \\\n\tmise/lib/mise-self-update-instructions.toml=/usr/lib/mise/mise-self-update-instructions.toml \\\n\tmise/man/man1/mise.1=/usr/share/man/man1/mise.1\n\ncat <<EOF >~/.rpmmacros\n%_signature gpg\n%_gpg_name 8B81C9D17413A06D\nEOF\n\nmkdir -p dist/rpmrepo/packages\ncp -v packaging/rpm/mise.repo dist/rpmrepo\ncp -v ./*.rpm dist/rpmrepo/packages\nrpm --addsign dist/rpmrepo/packages/*.rpm\ncreaterepo dist/rpmrepo\ngpg --batch --yes --detach-sign --armor dist/rpmrepo/repodata/repomd.xml\n"
  },
  {
    "path": "scripts/build-tarball.ps1",
    "content": "Set-StrictMode -Version Latest\n#Set-PSDebug -Trace 1\n\n$Target = $args[0]\n$Version = ./scripts/get-version.ps1\n$BaseName = \"mise-v$Version-$Env:OS-$Env:ARCH\"\n\n# TODO: use \"serious\" feature\ncargo build --release --features rustls-native-roots,openssl/vendored --target \"$Target\"\ncargo build --release -p mise-shim --target \"$Target\"\nmkdir -p dist/mise/bin\ncp \"target/$Target/release/mise.exe\" dist/mise/bin/mise.exe\ncp \"target/$Target/release/mise-shim.exe\" dist/mise/bin/mise-shim.exe\ncp README.md dist/mise/README.md\ncp LICENSE dist/mise/LICENSE\nSet-Location dist\n7z a -tzip \"$BaseName.zip\" mise\nSet-Location ..\n7z l \"dist/$BaseName.zip\"\n"
  },
  {
    "path": "scripts/build-tarball.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nerror() {\n\techo \"$@\" >&2\n\texit 1\n}\n\nRUST_TRIPLE=${1:-$(rustc -vV | grep ^host: | cut -d ' ' -f2)}\n#region os/arch\nget_os() {\n\tcase \"$RUST_TRIPLE\" in\n\t*-apple-darwin*)\n\t\techo \"macos\"\n\t\t;;\n\t*-windows-*)\n\t\techo \"windows\"\n\t\t;;\n\t*-linux-*)\n\t\techo \"linux\"\n\t\t;;\n\t*)\n\t\terror \"unsupported OS: $RUST_TRIPLE\"\n\t\t;;\n\tesac\n}\n\nget_arch() {\n\tcase \"$RUST_TRIPLE\" in\n\taarch64-*)\n\t\techo \"arm64\"\n\t\t;;\n\tarm*)\n\t\techo \"armv7\"\n\t\t;;\n\tx86_64-*)\n\t\techo \"x64\"\n\t\t;;\n\tuniversal2-*)\n\t\techo \"universal\"\n\t\t;;\n\t*)\n\t\terror \"unsupported arch: $RUST_TRIPLE\"\n\t\t;;\n\tesac\n}\nget_suffix() {\n\tcase \"$RUST_TRIPLE\" in\n\t*-musl | *-musleabi | *-musleabihf)\n\t\techo \"-musl\"\n\t\t;;\n\t*)\n\t\techo \"\"\n\t\t;;\n\tesac\n}\n#endregion\n\nset -x\nos=$(get_os)\narch=$(get_arch)\nsuffix=$(get_suffix)\nversion=$(./scripts/get-version.sh)\nbasename=mise-$version-$os-$arch$suffix\n\ncase \"$os-$arch\" in\nlinux-arm*)\n\t# don't use sccache\n\tunset RUSTC_WRAPPER\n\t;;\nesac\n\nfeatures=\"rustls-native-roots,self_update,vfox/vendored-lua,openssl/vendored\"\nif [[ $os == \"linux\" ]] && [[ $arch == \"armv7\" ]]; then\n\tfeatures=\"$features,aws-lc-rs\"\nfi\n\nif [[ $os == \"linux\" ]]; then\n\tcross build --profile=serious --target \"$RUST_TRIPLE\" --no-default-features --features \"$features\"\nelse\n\tcargo build --profile=serious --target \"$RUST_TRIPLE\" --no-default-features --features \"$features\"\nfi\n\n# Check glibc compatibility for x86_64-unknown-linux-gnu (Amazon Linux 2 requirement: glibc <= 2.26)\nif [[ $RUST_TRIPLE == \"x86_64-unknown-linux-gnu\" ]]; then\n\techo \"Checking glibc compatibility for Amazon Linux 2...\"\n\t# Use CARGO_TARGET_DIR if set, otherwise default to target\n\ttarget_dir=\"${CARGO_TARGET_DIR:-target}\"\n\tbinary_path=\"$target_dir/$RUST_TRIPLE/serious/mise\"\n\tif [[ -f $binary_path ]]; then\n\t\tmax_glibc=$(objdump -p \"$binary_path\" | grep 'GLIBC_' | sed 's/.*GLIBC_//' | sort -V | tail -1)\n\t\techo \"Maximum glibc version required: $max_glibc\"\n\n\t\t# Amazon Linux 2 has glibc 2.26, so we check if our binary requires <= 2.26\n\t\tif printf '%s\\n' \"$max_glibc\" \"2.26\" | sort -V -C; then\n\t\t\techo \"✅ Binary is compatible with Amazon Linux 2 (glibc $max_glibc <= 2.26)\"\n\t\telse\n\t\t\techo \"❌ Binary requires glibc $max_glibc, which is newer than Amazon Linux 2's glibc 2.26\"\n\t\t\techo \"This binary will NOT work on Amazon Linux 2\"\n\t\t\texit 1\n\t\tfi\n\telse\n\t\techo \"Warning: Binary not found at $binary_path, skipping glibc check\"\n\tfi\nfi\nmkdir -p dist/mise/bin\nmkdir -p dist/mise/man/man1\nmkdir -p dist/mise/share/fish/vendor_conf.d\n# Use CARGO_TARGET_DIR if set, otherwise default to target\ntarget_dir=\"${CARGO_TARGET_DIR:-target}\"\ncp \"$target_dir/$RUST_TRIPLE/serious/mise\"* dist/mise/bin\ncp README.md dist/mise/README.md\ncp LICENSE dist/mise/LICENSE\n\nif [[ $os != \"windows\" ]]; then\n\tcp {,dist/mise/}man/man1/mise.1\n\tcp {,dist/mise/}share/fish/vendor_conf.d/mise-activate.fish\nfi\n\ncd dist\n\nif [[ $os == \"macos\" ]]; then\n\tcodesign -f --prefix dev.jdx. -s \"Developer ID Application: Jeffrey Dickey (4993Y37DX6)\" mise/bin/mise\nfi\n\nif [[ $os == \"windows\" ]]; then\n\tzip -r \"$basename.zip\" mise\n\tls -oh \"$basename.zip\"\nelse\n\tXZ_OPT=-9 tar -acf \"$basename.tar.xz\" mise\n\ttar -cf - mise | gzip -9 >\"$basename.tar.gz\"\n\tZSTD_NBTHREADS=0 ZSTD_CLEVEL=19 tar -acf \"$basename.tar.zst\" mise\n\tls -oh \"$basename.tar.\"*\nfi\n"
  },
  {
    "path": "scripts/deploy-worker.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nif [ -z \"${CLOUDFLARE_API_TOKEN:-}\" ]; then\n\techo \"Error: CLOUDFLARE_API_TOKEN environment variable is required\"\n\texit 1\nfi\n\nACCOUNT_ID=\"6e243906ff257b965bcae8025c2fc344\"\nWORKER_NAME=\"mise-run\"\n\necho \"Deploying updated worker code for mise.run to worker: $WORKER_NAME\"\n\nif [[ $DRY_RUN != 1 ]]; then\n\t# Upload the worker script\n\tresponse=$(curl -s -X PUT \"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$WORKER_NAME/content\" \\\n\t\t-H \"Authorization: Bearer $CLOUDFLARE_API_TOKEN\" \\\n\t\t-H \"Content-Type: application/javascript\" \\\n\t\t--data-binary @cloudflare/workers/mise-run.js)\n\n\tif echo \"$response\" | jq -e '.success == true' >/dev/null; then\n\t\techo \"✅ Worker deployed successfully!\"\n\telse\n\t\techo \"❌ Worker deployment failed:\"\n\t\techo \"$response\" | jq .\n\t\texit 1\n\tfi\nfi\n\n# Show current routes\necho \"\"\necho \"Current worker routes:\"\ncurl -s -X GET \"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/workers/scripts/$WORKER_NAME/routes\" \\\n\t-H \"Authorization: Bearer $CLOUDFLARE_API_TOKEN\" \\\n\t-H \"Content-Type: application/json\" | jq -r '.result[]?.pattern // \"No routes found\"'\n"
  },
  {
    "path": "scripts/dotslash_comparison.sh",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\necho \"🚀 Node.js Performance Comparison: Direct vs mise vs DotSlash\"\necho \"==============================================================\"\n\ncargo b --profile=release\n\n# Create temporary directory for the test\nTEMP_DIR=$(mktemp -d)\necho \"📁 Working in temporary directory: $TEMP_DIR\"\ncp target/release/mise \"$TEMP_DIR\"\ncd \"$TEMP_DIR\"\nPATH=\"$TEMP_DIR:$PATH\"\n\n# Set up mise config for dependencies\ncat >.mise.toml <<'EOF'\n[tools]\nhyperfine = \"latest\"\n\"ubi:facebook/dotslash\" = \"latest\"\nnode = \"20.0.0\"\nEOF\n\necho \"📦 Installing dependencies...\"\nmise install\n\n# Add tools to PATH\nPATH=\"$(mise where hyperfine)/bin:$PATH\"\nPATH=\"$(mise where ubi:facebook/dotslash):$PATH\"\nPATH=\"$(mise where node)/bin:$PATH\"\n\n# Verify installations\necho \"🔍 Verifying installations...\"\necho \"  Node.js: $(node --version)\"\necho \"  DotSlash: $(dotslash --version 2>/dev/null || echo \"Failed\")\"\necho \"  Hyperfine: $(hyperfine --version | head -1)\"\n\n# Create test directory\nmkdir -p bin\n\n# Get direct node path\nDIRECT_NODE_PATH=\"$(which node)\"\necho \"🎯 Direct Node.js path: $DIRECT_NODE_PATH\"\n\n# Create mise tool stub\ncat >bin/node-mise <<'EOF'\n#!/usr/bin/env -S mise tool-stub\nversion = \"20.0.0\"\ntool = \"node\"\nbin = \"node\"\nEOF\nchmod +x bin/node-mise\n\n# Test mise tool stub works\necho \"📋 Testing mise tool stub...\"\n./bin/node-mise --version\n\n# Create DotSlash shim\ncat >bin/node-dotslash <<'EOF'\n#!/usr/bin/env dotslash\n\n{\n  \"name\": \"node-v20.0.0\",\n  \"platforms\": {\n    \"linux-x86_64\": {\n      \"size\": 45952734,\n      \"hash\": \"blake3\",\n      \"digest\": \"39fcc8b488ae4877b99ddf40603e9808bb73885742b48401f136f16304615c83\",\n      \"format\": \"tar.gz\",\n      \"path\": \"node-v20.0.0-linux-x64/bin/node\",\n      \"providers\": [\n        {\n          \"url\": \"https://nodejs.org/dist/v20.0.0/node-v20.0.0-linux-x64.tar.gz\"\n        }\n      ]\n    },\n\t\"macos-aarch64\": {\n\t\t\"size\": 41339150,\n\t\t\"hash\": \"blake3\",\n\t\t\"digest\": \"1373835099da2743cc18f136e54bc5c08d91f5234ec2f313336d7b940d815c4b\",\n\t\t\"format\": \"tar.gz\",\n\t\t\"path\": \"node-v20.0.0-darwin-arm64/bin/node\",\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"url\": \"https://nodejs.org/dist/v20.0.0/node-v20.0.0-darwin-arm64.tar.gz\"\n\t\t\t}\n\t\t]\n\t}\n  }\n}\nEOF\nchmod +x bin/node-dotslash\n\n# Test DotSlash shim works\necho \"📋 Testing DotSlash shim...\"\n./bin/node-dotslash --version\n\necho \"\"\necho \"⚡ Running Performance Benchmark...\"\n\n# Run the performance comparison\nhyperfine \\\n\t--warmup 5 \\\n\t--min-runs 20 \\\n\t--export-markdown results.md \\\n\t--export-json results.json \\\n\t--command-name \"Direct Node.js\" \"$DIRECT_NODE_PATH --version\" \\\n\t--command-name \"Mise Shim\" \"./bin/node-mise --version\" \\\n\t--command-name \"DotSlash Shim\" \"./bin/node-dotslash --version\"\n\necho \"\"\necho \"📈 Results:\"\ncat results.md\n\n# Calculate overhead if jq and bc are available\nif command -v jq &>/dev/null && command -v bc &>/dev/null; then\n\techo \"\"\n\techo \"📊 Overhead Analysis:\"\n\n\tdirect_time=$(jq -r '.results[0].mean' results.json)\n\tmise_time=$(jq -r '.results[1].mean' results.json)\n\tdotslash_time=$(jq -r '.results[2].mean' results.json)\n\n\tmise_overhead=$(echo \"scale=1; ($mise_time - $direct_time) / $direct_time * 100\" | bc)\n\tdotslash_overhead=$(echo \"scale=1; ($dotslash_time - $direct_time) / $direct_time * 100\" | bc)\n\n\techo \"  Direct Node.js:     ${direct_time}s (baseline)\"\n\techo \"  Mise overhead:      +${mise_overhead}%\"\n\techo \"  DotSlash overhead:  +${dotslash_overhead}%\"\n\n\t# File sizes\n\techo \"\"\n\techo \"📝 File Sizes:\"\n\techo \"  Direct Node.js:     $(du -h \"$DIRECT_NODE_PATH\" | cut -f1)\"\n\techo \"  Mise shim:          $(du -h bin/node-mise | cut -f1)\"\n\techo \"  DotSlash shim:      $(du -h bin/node-dotslash | cut -f1)\"\nfi\n\necho \"\"\necho \"✅ Performance comparison complete!\"\necho \"🗂️  Test files are in: $TEMP_DIR\"\necho \"🧹 To clean up: rm -rf $TEMP_DIR\"\n"
  },
  {
    "path": "scripts/gen-aqua-changelog.sh",
    "content": "#!/usr/bin/env bash\n# Generate aqua-registry changelog section\n# Usage: gen-aqua-changelog.sh <old_packages> <new_packages> <heading_level>\nset -euo pipefail\n\nOLD_PKGS=\"$1\"\nNEW_PKGS=\"$2\"\nHEADING_LEVEL=\"${3:-###}\" # Default to ### for CHANGELOG.md sections\n\nif [[ -z $OLD_PKGS ]]; then\n\texit 0\nfi\n\n# Find new packages (in new but not in old)\nNEW_PACKAGES=\"$(comm -13 <(echo \"$OLD_PKGS\") <(echo \"$NEW_PKGS\"))\"\n\n# Find updated packages (in both old and new)\n# For updated, check which files actually changed\nCOMMON_PKGS=\"$(comm -12 <(echo \"$OLD_PKGS\") <(echo \"$NEW_PKGS\"))\"\nUPDATED_PACKAGES=\"\"\nwhile IFS= read -r pkg; do\n\tif [[ -n $pkg ]]; then\n\t\tif git diff --quiet HEAD -- \"crates/aqua-registry/aqua-registry/pkgs/$pkg/registry.yaml\" 2>/dev/null; then\n\t\t\t: # No changes\n\t\telse\n\t\t\tUPDATED_PACKAGES+=\"$pkg\"$'\\n'\n\t\tfi\n\tfi\ndone <<<\"$COMMON_PKGS\"\n\nNEW_COUNT=$(echo \"$NEW_PACKAGES\" | grep -c . || true)\nif [[ -z $NEW_COUNT ]] || [[ $NEW_COUNT -eq 0 ]]; then\n\tNEW_COUNT=0\nfi\n\nUPDATED_COUNT=$(echo \"$UPDATED_PACKAGES\" | grep -c . || true)\nif [[ -z $UPDATED_COUNT ]] || [[ $UPDATED_COUNT -eq 0 ]]; then\n\tUPDATED_COUNT=0\nfi\n\n# If no changes, exit\nif [[ $NEW_COUNT -eq 0 ]] && [[ $UPDATED_COUNT -eq 0 ]]; then\n\texit 0\nfi\n\n# Build markdown output\necho \"$HEADING_LEVEL 📦 Aqua Registry Updates\"\necho \"\"\n\nif [[ $NEW_COUNT -gt 0 ]]; then\n\techo \"#### New Packages ($NEW_COUNT)\"\n\techo \"\"\n\twhile IFS= read -r pkg; do\n\t\tif [[ -n $pkg ]]; then\n\t\t\techo \"- [\\`$pkg\\`](https://github.com/$pkg)\"\n\t\tfi\n\tdone <<<\"$NEW_PACKAGES\"\n\techo \"\"\nfi\n\nif [[ $UPDATED_COUNT -gt 0 ]]; then\n\techo \"#### Updated Packages ($UPDATED_COUNT)\"\n\techo \"\"\n\twhile IFS= read -r pkg; do\n\t\tif [[ -n $pkg ]]; then\n\t\t\techo \"- [\\`$pkg\\`](https://github.com/$pkg)\"\n\t\tfi\n\tdone <<<\"$UPDATED_PACKAGES\"\n\techo \"\"\nfi\n"
  },
  {
    "path": "scripts/get-latest-version.sh",
    "content": "#!/bin/sh\nset -eu\n\ngh release view -R jdx/mise --json tagName | jq -r '.tagName'\n"
  },
  {
    "path": "scripts/get-version.ps1",
    "content": "$Version = (Get-Content -Path Cargo.toml | Select-String -Pattern '^version = \"(.*)\"' | ForEach-Object { $_.Matches.Groups[1].Value })\nWrite-Output $Version\n"
  },
  {
    "path": "scripts/get-version.sh",
    "content": "#!/bin/sh\nset -eu\n\necho \"v$(grep '^version =' Cargo.toml | head -n1 | cut -d '\"' -f 2)\"\n"
  },
  {
    "path": "scripts/publish-r2.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nexport AWS_REGION=auto\nexport AWS_DEFAULT_OUTPUT=json\nexport AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com\nexport AWS_ACCESS_KEY_ID=$CLOUDFLARE_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY=$CLOUDFLARE_SECRET_ACCESS_KEY\nexport AWS_S3_BUCKET=mise\n\n./scripts/publish-s3.sh\n"
  },
  {
    "path": "scripts/publish-release.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\n# This script runs after the GitHub release is successfully created\n# It updates the VERSION file and publishes to R2\n\nBASE_DIR=\"$(pwd)\"\nMISE_VERSION=$(./scripts/get-version.sh)\nRELEASE_DIR=releases\nexport BASE_DIR MISE_VERSION RELEASE_DIR\n\necho \"::group::Create VERSION file\"\npushd \"$RELEASE_DIR\"\necho \"$MISE_VERSION\" | tr -d 'v' >VERSION\npopd\n\nif [[ ${DRY_RUN:-0} != 1 ]]; then\n\techo \"::group::Publish r2\"\n\t./scripts/publish-r2.sh\nfi\n"
  },
  {
    "path": "scripts/publish-s3.sh",
    "content": "#!/usr/bin/env -S mise x aws-cli@2.22.35 -- bash\nset -euxo pipefail\n\n#cache_hour=\"max-age=3600,s-maxage=3600,public,immutable\"\ncache_day=\"max-age=86400,s-maxage=86400,public,immutable\"\ncache_week=\"max-age=604800,s-maxage=604800,public,immutable\"\n\n# Configure AWS CLI to use retry mode with exponential backoff\nexport AWS_RETRY_MODE=adaptive\nexport AWS_MAX_ATTEMPTS=10\n\n# Upload versioned tarballs to mise-v{version}/ directory\naws s3 cp \"$RELEASE_DIR/$MISE_VERSION\" \"s3://$AWS_S3_BUCKET/$MISE_VERSION/\" --cache-control \"$cache_week\" --no-progress --recursive --include \"*.tar.gz\" --include \"*.tar.xz\" --include \"*.tar.zst\" --include \"*.zip\" --include \"SHASUMS*\"\n\nwhich -a aws\naws --version\n\n# Upload mise-latest-* binaries (excluding archives to avoid conflicts)\n# Note: --exclude must come before --include for proper filtering\naws s3 cp \"$RELEASE_DIR\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress --recursive --exclude \"*\" --include \"mise-latest-*\" --exclude \"*.tar.gz\" --exclude \"*.tar.xz\" --exclude \"*.tar.zst\" --exclude \"*.zip\"\n\n# Upload SHASUMS files\naws s3 cp \"$RELEASE_DIR\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress --content-type \"text/plain\" --recursive --exclude \"*\" --include \"SHASUMS*\"\n\n# Upload individual files sequentially to avoid rate limiting\naws s3 cp \"$RELEASE_DIR/VERSION\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress --content-type \"text/plain\"\naws s3 cp \"$RELEASE_DIR/install.sh\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress --content-type \"text/plain\"\naws s3 cp \"$RELEASE_DIR/install.sh.sig\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress\naws s3 cp \"$RELEASE_DIR/install.sh.minisig\" \"s3://$AWS_S3_BUCKET/\" --cache-control \"$cache_day\" --no-progress\naws s3 cp \"./schema/mise.json\" \"s3://$AWS_S3_BUCKET/schema/mise.json\" --cache-control \"$cache_day\" --no-progress --content-type \"application/json\"\naws s3 cp \"./schema/mise.plugin.json\" \"s3://$AWS_S3_BUCKET/schema/mise.plugin.json\" --cache-control \"$cache_day\" --no-progress --content-type \"application/json\"\naws s3 cp \"./schema/mise-task.json\" \"s3://$AWS_S3_BUCKET/schema/mise-task.json\" --cache-control \"$cache_day\" --no-progress --content-type \"application/json\"\n\n# Upload shell-specific mise.run scripts\naws s3 cp artifacts/mise.run/zsh \"s3://$AWS_S3_BUCKET/mise.run/zsh\" --cache-control \"$cache_week\" --no-progress --content-type \"text/plain\"\naws s3 cp artifacts/mise.run/bash \"s3://$AWS_S3_BUCKET/mise.run/bash\" --cache-control \"$cache_week\" --no-progress --content-type \"text/plain\"\naws s3 cp artifacts/mise.run/fish \"s3://$AWS_S3_BUCKET/mise.run/fish\" --cache-control \"$cache_week\" --no-progress --content-type \"text/plain\"\n\naws s3 cp artifacts/rpm/mise.repo \"s3://$AWS_S3_BUCKET/rpm/\" --cache-control \"$cache_day\" --no-progress\naws s3 cp artifacts/rpm/packages/ \"s3://$AWS_S3_BUCKET/rpm/packages/\" --cache-control \"$cache_week\" --no-progress --recursive\naws s3 cp artifacts/rpm/repodata/ \"s3://$AWS_S3_BUCKET/rpm/repodata/\" --cache-control \"$cache_day\" --no-progress --recursive --exclude \"*\" --include \"repomd.xml*\"\naws s3 cp artifacts/rpm/repodata/ \"s3://$AWS_S3_BUCKET/rpm/repodata/\" --cache-control \"$cache_week\" --no-progress --recursive --exclude \"repomd.xml*\"\n\naws s3 cp artifacts/deb/pool/ \"s3://$AWS_S3_BUCKET/deb/pool/\" --cache-control \"$cache_week\" --no-progress --recursive\naws s3 cp artifacts/deb/dists/ \"s3://$AWS_S3_BUCKET/deb/dists/\" --cache-control \"$cache_day\" --no-progress --no-progress --recursive\n\n# delete ancient CLIs\n# since=`date --date '-3 years' +%F 2>/dev/null`\n# aws s3api list-objects-v2 --bucket \"$AWS_S3_BUCKET\" --query 'Contents[?LastModified < `'\"$since\"'`]' | jq -r '.[].Key' | grep \"^(deb|rpm)\\/\"\n\nexport CLOUDFLARE_ACCOUNT_ID=6e243906ff257b965bcae8025c2fc344\n\n# jdx.dev\ncurl --fail-with-body -X POST \"https://api.cloudflare.com/client/v4/zones/90dfd7997bdcfa8579c52d8ee8dd4cd1/purge_cache\" \\\n\t-H \"Authorization: Bearer $CLOUDFLARE_API_TOKEN\" \\\n\t-H \"Content-Type: application/json\" \\\n\t--data '{ \"purge_everything\": true }'\n\n# mise.run\ncurl --fail-with-body -X POST \"https://api.cloudflare.com/client/v4/zones/782fc08181b7bbd26c529a00df52a277/purge_cache\" \\\n\t-H \"Authorization: Bearer $CLOUDFLARE_API_TOKEN\" \\\n\t-H \"Content-Type: application/json\" \\\n\t--data '{ \"purge_everything\": true }'\n"
  },
  {
    "path": "scripts/query-top-plugins.fish",
    "content": "#!/usr/bin/env fish\n\n# Print out list of asdf plugins sorted by number of stars. Full list is\n# persisted to stargazer_count.txt\n\nif test -n (type -t gh)\nelse\n    echo \"GitHub CLI Missing! Aborting!\"\n    exit 1\nend\n\n\nif test -d /tmp/asdf-plugins\n    set current_dir (pwd)\n    cd /tmp/asdf-plugins\n    git pull /tmp/asdf-plugins\n    cd $current_dir\nelse\n    git clone --depth=1 git@github.com:mise-plugins/registry.git /tmp/asdf-plugins\nend\n\nif test -e stargazer_count.txt\n    rm -rf stargazer_count.txt\nend\n\n\nfor i in /tmp/asdf-plugins/plugins/*\n    cat $i | \\\n        string split -f2 '=' | \\\n        string trim | \\\n        xargs -I '{}' gh repo view '{}' --json stargazerCount,name,owner | \\\n        jq -r \"[.stargazerCount,\\\"$(basename $i)\\\",\\\"$(string split '=' -f2 (cat $i))\\\"]|@tsv\" >> stargazer_count.txt &\nend\n\necho \"$(cat stargazer_count.txt)\" | sort -nr | uniq >stargazer_count.txt\nhead -n 50 stargazer_count.txt\n"
  },
  {
    "path": "scripts/release-alpine.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nMISE_VERSION=$(./scripts/get-latest-version.sh)\n\nexport GITLAB_HOST=gitlab.alpinelinux.org\nexport GITLAB_TOKEN=\"$ALPINE_GITLAB_TOKEN\"\n\nsudo chown -R packager:packager /github/home\nmkdir -p /github/home/.abuild\necho \"$ALPINE_PUB_KEY\" | sudo tee \"/etc/apk/keys/$ALPINE_KEY_ID.pub\"\necho \"$ALPINE_PUB_KEY\" >\"/github/home/.abuild/$ALPINE_KEY_ID.pub\"\necho \"$ALPINE_PRIV_KEY\" >\"/github/home/.abuild/$ALPINE_KEY_ID\"\necho \"PACKAGER_PRIVKEY=\\\"/github/home/.abuild/$ALPINE_KEY_ID\\\"\" >>/github/home/.abuild/abuild.conf\n\ngit config --global user.name \"Jeff Dickey\"\ngit config --global user.email 6271-jdxcode@users.gitlab.alpinelinux.org\n\ngit clone https://gitlab.alpinelinux.org/alpine/aports.git/ /home/packager/aports\ncd /home/packager/aports\ngit config --local core.hooksPath .githooks\ngit remote add jdxcode \"https://jdxcode:$GITLAB_TOKEN@gitlab.alpinelinux.org/jdxcode/aports.git/\"\ngit checkout -mb mise\ncd community/mise\n\nsed -i \"s/pkgver=.*/pkgver=${MISE_VERSION#v}/\" APKBUILD\n\nabuild checksum\ncat /github/home/.abuild/abuild.conf\nabuild -r\n#apkbuild-lint APKBUILD fails due to: SC:[AL57]:./APKBUILD:7:invalid arch '!loongarch64'\n\ngit add APKBUILD\n\nif git diff --cached --exit-code; then\n\techo \"No changes to commit\"\n\texit 0\nfi\ngit commit -m \"community/mise: upgrade to ${MISE_VERSION#v}\"\n\nif [ \"$DRY_RUN\" == 0 ]; then\n\tgit push jdxcode -f\nfi\n\nopen_mr=\"$(glab mr list -R alpine/aports --author=@me)\"\nif [[ $open_mr != \"Showing\"* ]]; then\n\tif [ \"$DRY_RUN\" == 0 ]; then\n\t\tDEBUG=1 glab mr create --fill --yes -H jdxcode/aports -R alpine/aports\n\tfi\nfi\n#git show\n"
  },
  {
    "path": "scripts/release-npm.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nerror() {\n\techo \"$@\" >&2\n\texit 1\n}\n\nmkdir -p \"$RELEASE_DIR/npm\"\n\ndist_tag_from_version() {\n\tIFS=\"-\" read -r -a version_split <<<\"$1\"\n\tIFS=\".\" read -r -a version_split <<<\"${version_split[1]:-latest}\"\n\techo \"${version_split[0]}\"\n}\ndist_tag=\"$(dist_tag_from_version \"$MISE_VERSION\")\"\n\nplatforms=(\n\tlinux-x64\n\tlinux-arm64\n\tlinux-armv7\n\tmacos-x64\n\tmacos-arm64\n)\nfor platform in \"${platforms[@]}\"; do\n\t# shellcheck disable=SC2206\n\tplatform_split=(${platform//-/ })\n\tos=\"${platform_split[0]}\"\n\tarch=\"${platform_split[1]}\"\n\n\tif [[ $os == \"macos\" ]]; then\n\t\tos=\"darwin\"\n\tfi\n\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\" \"$RELEASE_DIR/mise-latest-$platform.tar.gz\"\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.xz\" \"$RELEASE_DIR/mise-latest-$platform.tar.xz\"\n\ttar -xzvf \"$RELEASE_DIR/mise-latest-$platform.tar.gz\" -C \"$RELEASE_DIR\"\n\trm -rf \"$RELEASE_DIR/npm\"\n\tmv \"$RELEASE_DIR/mise\" \"$RELEASE_DIR/npm\"\n\tcat <<EOF >\"$RELEASE_DIR/npm/package.json\"\n{\n  \"name\": \"$NPM_PREFIX-$os-$arch\",\n  \"version\": \"$MISE_VERSION\",\n  \"description\": \"polyglot runtime manager\",\n  \"bin\": {\n    \"mise\": \"bin/mise\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/jdx/mise\"\n  },\n  \"files\": [\n    \"bin\",\n    \"README.md\"\n  ],\n  \"license\": \"MIT\",\n  \"os\": \"$os\",\n  \"cpu\": \"$arch\"\n}\nEOF\n\tpushd \"$RELEASE_DIR/npm\"\n\ttree || true\n\tif [ \"${DRY_RUN:-1}\" != \"0\" ]; then\n\t\techo DRY_RUN\n\t\techo npm publish --access public --tag \"$dist_tag\" --provenance\n\t\techo DRY_RUN\n\telse\n\t\tif ! npm publish --access public --tag \"$dist_tag\" --provenance 2>&1 | tee /tmp/npm-publish.log; then\n\t\t\tif grep -q \"You cannot publish over the previously published versions\" /tmp/npm-publish.log; then\n\t\t\t\techo \"Version already published, skipping...\"\n\t\t\telse\n\t\t\t\tcat /tmp/npm-publish.log\n\t\t\t\texit 1\n\t\t\tfi\n\t\tfi\n\tfi\n\tpopd\ndone\n\ncat <<EOF >\"$RELEASE_DIR/npm/installArchSpecificPackage.js\"\nvar spawn = require('child_process').spawn;\nvar path = require('path');\nvar fs = require('fs');\n\nfunction installArchSpecificPackage(version) {\n\n    process.env.npm_config_global = 'false';\n\n    var platform = process.platform == 'win32' ? 'windows' : process.platform;\n    var arch = platform == 'windows' && process.arch == 'ia32' ? 'x86' : process.arch;\n\n    var cp = spawn(platform == 'windows' ? 'npm.cmd' : 'npm', ['install', '--no-save', ['$NPM_PREFIX', platform, arch].join('-') + '@' + version], {\n        stdio: 'inherit',\n        shell: true\n    });\n\n    cp.on('close', function(code) {\n        var pkgJson = require.resolve(['$NPM_PREFIX', platform, arch].join('-') + '/package.json');\n        var subpkg = JSON.parse(fs.readFileSync(pkgJson, 'utf8'));\n        var executable = subpkg.bin.mise;\n        var bin = path.resolve(path.dirname(pkgJson), executable);\n\n        try {\n            fs.mkdirSync(path.resolve(process.cwd(), 'bin'));\n        } catch (e) {\n            if (e.code != 'EEXIST') {\n                throw e;\n            }\n        }\n\n        linkSync(bin, path.resolve(process.cwd(), executable));\n\n        if (platform == 'windows') {\n            var pkg = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), 'package.json')));\n            fs.writeFileSync(path.resolve(process.cwd(), 'bin/mise'), 'This file intentionally left blank');\n            pkg.bin.mise = 'bin/mise.exe';\n            fs.writeFileSync(path.resolve(process.cwd(), 'package.json'), JSON.stringify(pkg, null, 2));\n        }\n\n        return process.exit(code);\n\n    });\n}\n\nfunction linkSync(src, dest) {\n    try {\n        fs.unlinkSync(dest);\n    } catch (e) {\n        if (e.code != 'ENOENT') {\n            throw e;\n        }\n    }\n    return fs.linkSync(src, dest);\n}\n\nconst pjson = require('./package.json')\ninstallArchSpecificPackage(pjson.version)\nEOF\n\ncat <<EOF >\"$RELEASE_DIR/npm/package.json\"\n{\n  \"name\": \"$NPM_PREFIX\",\n  \"description\": \"polyglot runtime manager\",\n  \"version\": \"$MISE_VERSION\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/jdx/mise\"\n  },\n  \"files\": [\n    \"installArchSpecificPackage.js\",\n    \"README.md\"\n  ],\n  \"scripts\": {\n    \"prepack\": \"rm -rf bin\",\n    \"preinstall\": \"node installArchSpecificPackage.js\"\n  },\n  \"bin\": {\n    \"mise\": \"./bin/mise\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=5.0.0\"\n  }\n}\nEOF\npushd \"$RELEASE_DIR/npm\"\nif [ \"${DRY_RUN:-1}\" != \"0\" ]; then\n\techo DRY_RUN\n\techo npm publish --access public --tag \"$dist_tag\" --provenance\n\techo DRY_RUN\nelse\n\tif ! npm publish --access public --tag \"$dist_tag\" --provenance 2>&1 | tee /tmp/npm-publish.log; then\n\t\tif grep -q \"You cannot publish over the previously published versions\" /tmp/npm-publish.log; then\n\t\t\techo \"Version already published, skipping...\"\n\t\telse\n\t\t\tcat /tmp/npm-publish.log\n\t\t\texit 1\n\t\tfi\n\tfi\nfi\npopd\n"
  },
  {
    "path": "scripts/release.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\necho \"::group::Setup\"\ngit config --global user.name mise-en-dev\ngit config --global user.email 123107610+mise-en-dev@users.noreply.github.com\n\nBASE_DIR=\"$(pwd)\"\nMISE_VERSION=$(./scripts/get-version.sh)\nRELEASE_DIR=releases\nexport BASE_DIR MISE_VERSION RELEASE_DIR\nrm -rf \"${RELEASE_DIR:?}/$MISE_VERSION\"\nmkdir -p \"$RELEASE_DIR/$MISE_VERSION\"\n\necho \"::group::Build\"\nplatforms=(\n\tlinux-x64\n\tlinux-x64-musl\n\tlinux-arm64\n\tlinux-arm64-musl\n\tlinux-armv7\n\tlinux-armv7-musl\n\tmacos-x64\n\tmacos-arm64\n)\nfor platform in \"${platforms[@]}\"; do\n\tcp artifacts/*/\"mise-$MISE_VERSION-$platform.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\"\n\tcp artifacts/*/\"mise-$MISE_VERSION-$platform.tar.xz\" \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.xz\"\n\tcp artifacts/*/\"mise-$MISE_VERSION-$platform.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.zst\"\n\tzipsign sign tar \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\" ~/.zipsign/mise.priv\n\tzipsign verify tar \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\" \"$BASE_DIR/zipsign.pub\"\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\" \"$RELEASE_DIR/mise-latest-$platform.tar.gz\"\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.xz\" \"$RELEASE_DIR/mise-latest-$platform.tar.xz\"\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.zst\" \"$RELEASE_DIR/mise-latest-$platform.tar.zst\"\n\ttar -xvzf \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.tar.gz\"\n\tcp -v mise/bin/mise \"$RELEASE_DIR/mise-latest-$platform\"\n\tcp -v mise/bin/mise \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform\"\ndone\n\nwindows_platforms=(\n\twindows-arm64\n\twindows-x64\n)\nfor platform in \"${windows_platforms[@]}\"; do\n\tcp artifacts/*/\"mise-$MISE_VERSION-$platform.zip\" \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.zip\"\n\tzipsign sign zip \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.zip\" ~/.zipsign/mise.priv\n\tzipsign verify zip \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.zip\" \"$BASE_DIR/zipsign.pub\"\n\tcp \"$RELEASE_DIR/$MISE_VERSION/mise-$MISE_VERSION-$platform.zip\" \"$RELEASE_DIR/mise-latest-$platform.zip\"\ndone\n\necho \"::group::Checksums\"\npushd \"$RELEASE_DIR\"\ncp mise-latest-linux-x64 mise-latest-linux-amd64\ncp mise-latest-macos-x64 mise-latest-macos-amd64\nsha256sum ./mise-latest-* >SHASUMS256.txt\nsha512sum ./mise-latest-* >SHASUMS512.txt\ngpg --clearsign -u 8B81C9D17413A06D <SHASUMS256.txt >SHASUMS256.asc\ngpg --clearsign -u 8B81C9D17413A06D <SHASUMS512.txt >SHASUMS512.asc\nminisign -WSs \"$BASE_DIR/minisign.key\" -p \"$BASE_DIR/minisign.pub\" -m SHASUMS256.txt SHASUMS512.txt </dev/zero\npopd\n\npushd \"$RELEASE_DIR/$MISE_VERSION\"\nsha256sum ./* >SHASUMS256.txt\nsha512sum ./* >SHASUMS512.txt\ngpg --clearsign -u 8B81C9D17413A06D <SHASUMS256.txt >SHASUMS256.asc\ngpg --clearsign -u 8B81C9D17413A06D <SHASUMS512.txt >SHASUMS512.asc\nminisign -WSs \"$BASE_DIR/minisign.key\" -p \"$BASE_DIR/minisign.pub\" -m SHASUMS256.txt SHASUMS512.txt </dev/zero\npopd\n\necho \"::group::install.sh\"\n./scripts/render-install.sh >\"$RELEASE_DIR\"/install.sh\nchmod +x \"$RELEASE_DIR\"/install.sh\nshellcheck \"$RELEASE_DIR\"/install.sh\ngpg -u 8B81C9D17413A06D --output \"$RELEASE_DIR\"/install.sh.sig --sign \"$RELEASE_DIR\"/install.sh\nminisign -WSs \"$BASE_DIR/minisign.key\" -p \"$BASE_DIR/minisign.pub\" -m \"$RELEASE_DIR\"/install.sh </dev/zero\ncp \"$RELEASE_DIR\"/{install.sh,install.sh.sig,install.sh.minisig} \"$RELEASE_DIR/$MISE_VERSION\"\n\necho \"::group::mise.run scripts\"\n./scripts/render-mise-run.sh\n\necho \"::group::Sign source tarball\"\nTMP_FILE=\"$(mktemp)\"\ncurl -L -o \"$TMP_FILE\" \"https://github.com/jdx/mise/archive/refs/tags/$MISE_VERSION.tar.gz\"\ngpg --detach-sign -u 8B81C9D17413A06D <\"$TMP_FILE\" >\"$RELEASE_DIR/$MISE_VERSION/$MISE_VERSION.tar.gz.sig\"\nrm \"$TMP_FILE\"\n\n# Publishing is now done after GitHub release is created\n"
  },
  {
    "path": "scripts/render-install.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\n# shellcheck disable=SC2016\nMISE_CURRENT_VERSION=$MISE_VERSION \\\n\tMISE_CHECKSUM_LINUX_X86_64=$(grep \"mise-v.*linux-x64.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_X86_64_MUSL=$(grep \"mise-v.*linux-x64-musl.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARM64=$(grep \"mise-v.*linux-arm64.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARM64_MUSL=$(grep \"mise-v.*linux-arm64-musl.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARMV7=$(grep \"mise-v.*linux-armv7.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARMV7_MUSL=$(grep \"mise-v.*linux-armv7-musl.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_MACOS_X86_64=$(grep \"mise-v.*macos-x64.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_MACOS_ARM64=$(grep \"mise-v.*macos-arm64.tar.gz\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_X86_64_ZSTD=$(grep \"mise-v.*linux-x64.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_X86_64_MUSL_ZSTD=$(grep \"mise-v.*linux-x64-musl.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARM64_ZSTD=$(grep \"mise-v.*linux-arm64.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARM64_MUSL_ZSTD=$(grep \"mise-v.*linux-arm64-musl.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARMV7_ZSTD=$(grep \"mise-v.*linux-armv7.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_LINUX_ARMV7_MUSL_ZSTD=$(grep \"mise-v.*linux-armv7-musl.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_MACOS_X86_64_ZSTD=$(grep \"mise-v.*macos-x64.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tMISE_CHECKSUM_MACOS_ARM64_ZSTD=$(grep \"mise-v.*macos-arm64.tar.zst\" \"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\") \\\n\tenvsubst '$MISE_CURRENT_VERSION,$MISE_CHECKSUM_LINUX_X86_64,$MISE_CHECKSUM_LINUX_X86_64_MUSL,$MISE_CHECKSUM_LINUX_ARM64,$MISE_CHECKSUM_LINUX_ARM64_MUSL,$MISE_CHECKSUM_LINUX_ARMV6,$MISE_CHECKSUM_LINUX_ARMV6_MUSL,$MISE_CHECKSUM_LINUX_ARMV7,$MISE_CHECKSUM_LINUX_ARMV7_MUSL,$MISE_CHECKSUM_MACOS_X86_64,$MISE_CHECKSUM_MACOS_ARM64,$MISE_CHECKSUM_LINUX_X86_64_ZSTD,$MISE_CHECKSUM_LINUX_X86_64_MUSL_ZSTD,$MISE_CHECKSUM_LINUX_ARM64_ZSTD,$MISE_CHECKSUM_LINUX_ARM64_MUSL_ZSTD,$MISE_CHECKSUM_LINUX_ARMV7_ZSTD,$MISE_CHECKSUM_LINUX_ARMV7_MUSL_ZSTD,$MISE_CHECKSUM_MACOS_X86_64_ZSTD,$MISE_CHECKSUM_MACOS_ARM64_ZSTD' \\\n\t<\"$BASE_DIR/packaging/standalone/install.envsubst\"\n"
  },
  {
    "path": "scripts/render-mise-run.sh",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2016\nset -euxo pipefail\n\nBASE_DIR=\"$(pwd)\"\n\n# Create the mise.run directory in releases\nmkdir -p \"artifacts/mise.run\"\n\n# Function to generate shell-specific script\ngenerate_shell_script() {\n\tlocal shell_name=\"$1\"\n\tlocal config_var_name=\"$2\"\n\tlocal config_file_var=\"$3\"\n\tlocal config_setup_commands=\"$4\"\n\tlocal activation_command=\"$5\"\n\tlocal source_command=\"$6\"\n\tlocal final_message=\"$7\"\n\n\techo \"Generating $shell_name script...\"\n\n\t# Export variables for envsubst\n\texport SHELL_NAME=\"$shell_name\"\n\texport CONFIG_VAR_NAME=\"$config_var_name\"\n\texport CONFIG_FILE_VAR=\"$config_file_var\"\n\texport CONFIG_SETUP_COMMANDS=\"$config_setup_commands\"\n\texport ACTIVATION_COMMAND=\"$activation_command\"\n\texport SOURCE_COMMAND=\"$source_command\"\n\texport FINAL_MESSAGE=\"$final_message\"\n\n\t# Generate script from template\n\tenvsubst '$SHELL_NAME,$CONFIG_VAR_NAME,$CONFIG_FILE_VAR,$CONFIG_SETUP_COMMANDS,$ACTIVATION_COMMAND,$SOURCE_COMMAND,$FINAL_MESSAGE' <\"$BASE_DIR/packaging/mise.run/shell.envsubst\" >\"artifacts/mise.run/$shell_name\"\n\n\t# Make executable\n\tchmod +x \"artifacts/mise.run/$shell_name\"\n\n\t# Validate with shellcheck\n\tshellcheck \"artifacts/mise.run/$shell_name\"\n}\n\n# Generate zsh script\ngenerate_shell_script \"zsh\" \\\n\t'zshrc=\"${ZDOTDIR-$HOME}/.zshrc\"' \\\n\t\"zshrc\" \\\n\t'if [ ! -f \"$zshrc\" ]; then\n    touch \"$zshrc\"\n  fi' \\\n\t'echo \"eval \\\"\\$($install_path activate zsh)\\\" # added by https://mise.run/zsh\" >> \"$zshrc\"' \\\n\t'source $zshrc' \\\n\t\"restart your shell or run 'source \\${ZDOTDIR-\\$HOME}/.zshrc' to start using mise\"\n\n# Generate bash script\ngenerate_shell_script \"bash\" \\\n\t'bashrc=\"$HOME/.bashrc\"' \\\n\t\"bashrc\" \\\n\t'if [ ! -f \"$bashrc\" ]; then\n    touch \"$bashrc\"\n  fi' \\\n\t'echo \"eval \\\"\\$($install_path activate bash)\\\" # added by https://mise.run/bash\" >> \"$bashrc\"' \\\n\t\"source ~/.bashrc\" \\\n\t\"restart your shell or run 'source ~/.bashrc' to start using mise\"\n\n# Generate fish script\ngenerate_shell_script \"fish\" \\\n\t'fish_config_dir=\"$HOME/.config/fish\"\n  fish_config=\"$fish_config_dir/config.fish\"' \\\n\t\"fish_config\" \\\n\t'if [ ! -d \"$fish_config_dir\" ]; then\n    mkdir -p \"$fish_config_dir\"\n  fi\n  if [ ! -f \"$fish_config\" ]; then\n    touch \"$fish_config\"\n  fi' \\\n\t'echo \"$install_path activate fish | source # added by https://mise.run/fish\" >> \"$fish_config\"' \\\n\t\"source ~/.config/fish/config.fish\" \\\n\t\"restart your fish shell or run 'source ~/.config/fish/config.fish' to start using mise\"\n\necho \"Shell scripts generated successfully in artifacts/mise.run/\"\n"
  },
  {
    "path": "scripts/setup-zipsign.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nif [ -z \"$ZIPSIGN\" ]; then\n\techo \"ZIPSIGN is not defined\"\n\texit 0\nfi\n\nif ! command -v zipsign >/dev/null 2>&1; then\n\tcargo install zipsign\nfi\n\nmkdir -p ~/.zipsign\necho \"$ZIPSIGN\" | base64 -d >~/.zipsign/mise.priv\n"
  },
  {
    "path": "scripts/test-standalone.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nBASE_DIR=\"$(pwd)\"\nRELEASE_DIR=\"$(pwd)/tmp\"\nMISE_VERSION=\"v$(curl -fsSL https://mise.jdx.dev/VERSION)\"\nexport BASE_DIR RELEASE_DIR MISE_VERSION\n\nmkdir -p \"$RELEASE_DIR/$MISE_VERSION\"\ncurl -fsSL \"https://mise.jdx.dev/$MISE_VERSION/SHASUMS256.txt\" >\"$RELEASE_DIR/$MISE_VERSION/SHASUMS256.txt\"\n./scripts/render-install.sh >tmp/install.sh\nchmod +x tmp/install.sh\nmise x shellcheck -- shellcheck tmp/install.sh\n\n./tmp/install.sh\nif [[ ! \"$(\"$HOME/.local/bin/mise\" -v)\" =~ ^${MISE_VERSION//v/} ]]; then\n\techo \"mise version mismatch\"\n\texit 1\nfi\nrm -rf \"$RELEASE_DIR\"\n"
  },
  {
    "path": "scripts/update-redirect.sh",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\nCURRENT_VERSION=\"${1}\"\necho \"Current version: $CURRENT_VERSION\"\n\n# Cloudflare API endpoint for updating redirect rules\nZONE_ID=\"90dfd7997bdcfa8579c52d8ee8dd4cd1\" # jdx.dev zone ID\n\n# Use the correct ruleset ID and rule ID from the API response\nRULESET_ID=\"f929f651a2824bfcac1cca11bbd3cf73\"\nRULE_ID=\"ba099b251b5647d7833d319a3f5e0416\"\necho \"Using ruleset ID: $RULESET_ID\"\necho \"Using rule ID: $RULE_ID\"\n\n# Update the redirect rule with the new version\necho \"Updating redirect rule with version $CURRENT_VERSION...\"\n\ncurl --fail-with-body -X PATCH \"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$RULESET_ID/rules/$RULE_ID\" \\\n\t-H \"Authorization: Bearer $CLOUDFLARE_API_TOKEN\" \\\n\t-H \"Content-Type: application/json\" \\\n\t--data @- <<EOF\n{\n  \"expression\": \"(http.host eq \\\"mise.jdx.dev\\\" and starts_with(http.request.uri.path, \\\"/mise-latest-\\\"))\",\n  \"action\": \"redirect\",\n  \"action_parameters\": {\n    \"from_value\": {\n      \"preserve_query_string\": false,\n      \"status_code\": 302,\n      \"target_url\": {\n        \"expression\": \"concat(\\\"https://github.com/jdx/mise/releases/download/${CURRENT_VERSION}/\\\", wildcard_replace(http.request.uri.path, \\\"/mise-latest-*\\\", \\\"mise-${CURRENT_VERSION}-\\${1}\\\"))\"\n      }\n    }\n  },\n  \"description\": \"Redirect mise-latest-* to current version\",\n  \"enabled\": false,\n  \"ref\": \"ba099b251b5647d7833d319a3f5e0416\"\n}\nEOF\n\necho \"Redirect rule updated successfully!\"\n"
  },
  {
    "path": "settings.toml",
    "content": "# This file generates code and documentation for settings in mise\n# When this file is updated, run `mise run render` to update generated files\n[activate_aggressive]\ndescription = \"Pushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after activation to take precedence.\"\ndocs = \"\"\"\nPushes tools' bin-paths to the front of PATH instead of allowing modifications of PATH after activation to take precedence. For example, if you have the following in your `mise.toml`:\n\n```toml\n[tools]\nnode = '20'\npython = '3.12'\n```\n\nBut you also have this in your `~/.zshrc`:\n\n```sh\neval \"$(mise activate zsh)\"\nPATH=\"/some/other/python:$PATH\"\n```\n\nWhat will happen is `/some/other/python` will be used instead of the python installed by mise. This\nmeans\nyou typically want to put `mise activate` at the end of your shell config so nothing overrides it.\n\nIf you want to always use the mise versions of tools despite what is in your shell config, set this\nto `true`.\nIn that case, using this example again, `/some/other/python` will be after mise's python in PATH.\n\"\"\"\nenv = \"MISE_ACTIVATE_AGGRESSIVE\"\ntype = \"Bool\"\n\n[age.identity_files]\ndescription = \"[experimental] List of age identity files to use for decryption.\"\nenv = \"MISE_AGE_IDENTITY_FILES\"\noptional = true\nrust_type = \"Vec<PathBuf>\"\ntype = \"ListPath\"\n\n[age.key_file]\ndefault_docs = \"~/.config/mise/age.txt\"\ndescription = \"[experimental] Path to the age private key file to use for encryption/decryption.\"\nenv = \"MISE_AGE_KEY_FILE\"\noptional = true\ntype = \"Path\"\n\n[age.ssh_identity_files]\ndescription = \"[experimental] List of SSH identity files to use for age decryption.\"\nenv = \"MISE_AGE_SSH_IDENTITY_FILES\"\noptional = true\nrust_type = \"Vec<PathBuf>\"\ntype = \"ListPath\"\n\n[age.strict]\ndefault = true\ndescription = \"If true, fail when age decryption fails (including when age is not available, the key is missing, or the key is invalid). If false, skip decryption and continue in these cases.\"\nenv = \"MISE_AGE_STRICT\"\ntype = \"Bool\"\n\n[all_compile]\ndescription = \"do not use precompiled binaries for any tool\"\ndocs = \"\"\"\nDefault: false unless running NixOS or Alpine (let me know if others should be added)\n\nDo not use precompiled binaries for all languages. Useful if running on a Linux distribution\nlike Alpine that does not use glibc and therefore likely won't be able to run precompiled binaries.\n\nNote that this needs to be setup for each language. File a ticket if you notice a language that is\nnot\nworking with this config.\n\"\"\"\nenv = \"MISE_ALL_COMPILE\"\ntype = \"Bool\"\n\n[always_keep_download]\ndescription = \"should mise keep downloaded files after installation\"\nenv = \"MISE_ALWAYS_KEEP_DOWNLOAD\"\ntype = \"Bool\"\n\n[always_keep_install]\ndescription = \"should mise keep install files after installation even if the installation fails\"\nenv = \"MISE_ALWAYS_KEEP_INSTALL\"\ntype = \"Bool\"\n\n[aqua.baked_registry]\ndefault = true\ndescription = \"Use baked-in aqua registry.\"\nenv = \"MISE_AQUA_BAKED_REGISTRY\"\ntype = \"Bool\"\n\n[aqua.cosign]\ndefault = true\ndescription = \"Use cosign to verify aqua tool signatures.\"\nenv = \"MISE_AQUA_COSIGN\"\ntype = \"Bool\"\n\n[aqua.cosign_extra_args]\ndescription = \"Extra arguments to pass to cosign when verifying aqua tool signatures.\"\nenv = \"MISE_AQUA_COSIGN_EXTRA_ARGS\"\noptional = true\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[aqua.github_attestations]\ndefault = true\ndescription = \"Enable GitHub Artifact Attestations verification for aqua tools.\"\ndocs = \"\"\"\nEnable/disable GitHub Artifact Attestations verification for aqua tools.\nWhen enabled, mise will verify the authenticity and integrity of downloaded tools\nusing GitHub's artifact attestation system.\n\"\"\"\nenv = \"MISE_AQUA_GITHUB_ATTESTATIONS\"\ntype = \"Bool\"\n\n[aqua.minisign]\ndefault = true\ndescription = \"Use minisign to verify aqua tool signatures.\"\nenv = \"MISE_AQUA_MINISIGN\"\ntype = \"Bool\"\n\n[aqua.registry_url]\ndescription = \"URL to fetch aqua registry from.\"\ndocs = \"\"\"\nURL to fetch aqua registry from. This is used to install tools from the aqua registry.\n\nIf this is set, the baked-in aqua registry is not used.\n\nBy default, the official aqua registry is used: https://github.com/aquaproj/aqua-registry\n\"\"\"\nenv = \"MISE_AQUA_REGISTRY_URL\"\noptional = true\ntype = \"Url\"\n\n[aqua.slsa]\ndefault = true\ndescription = \"Use SLSA to verify aqua tool signatures.\"\nenv = \"MISE_AQUA_SLSA\"\ntype = \"Bool\"\n\n[arch]\ndefault_docs = '\"x86_64\" | \"aarch64\" | \"arm\" | \"loongarch64\" | \"riscv64\"'\ndescription = \"Architecture to use for precompiled binaries.\"\ndocs = \"\"\"\nArchitecture to use for precompiled binaries. This is used to determine which precompiled binaries\nto download. If unset, mise will use the system's architecture.\n\"\"\"\nenv = \"MISE_ARCH\"\noptional = true\ntype = \"String\"\n\n[asdf]\ndeprecated = \"Use disable_backends instead.\"\ndescription = \"use asdf as a default plugin backend\"\ndocs = \"\"\"\nUse asdf as a default plugin backend. This means running something like `mise use cmake` will\ndefault to using an asdf plugin for cmake.\n\"\"\"\nenv = \"MISE_ASDF\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[asdf_compat]\ndeprecated = \"no longer supported\"\ndescription = \"set to true to ensure .tool-versions will be compatible with asdf\"\ndocs = \"\"\"\nOnly output `.tool-versions` files in `mise local|global` which will be usable by asdf.\nThis disables mise functionality that would otherwise make these files incompatible with asdf such\nas non-pinned versions.\n\nThis will also change the default global tool config to be `~/.tool-versions` instead\nof `~/.config/mise/config.toml`.\n\"\"\"\nenv = \"MISE_ASDF_COMPAT\"\nhide = true\ntype = \"Bool\"\n\n[auto_install]\ndefault = true\ndescription = \"Automatically install missing tools when running `mise x`, `mise run`, or as part of the 'not found' handler.\"\nenv = \"MISE_AUTO_INSTALL\"\ntype = \"Bool\"\n\n[auto_install_disable_tools]\ndescription = \"List of tools to skip automatically installing when running `mise x`, `mise run`, or as part of the 'not found' handler.\"\nenv = \"MISE_AUTO_INSTALL_DISABLE_TOOLS\"\noptional = true\nparse_env = \"list_by_comma\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[cache_prune_age]\ndefault = \"30d\"\ndescription = \"Delete files in cache that have not been accessed in this duration\"\ndocs = \"\"\"\nThe age of the cache before it is considered stale. mise will occasionally delete cache files which\nhave not been accessed in this amount of time.\n\nSet to `0s` to keep cache files indefinitely.\n\"\"\"\nenv = \"MISE_CACHE_PRUNE_AGE\"\ntype = \"Duration\"\n\n[cargo.binstall]\ndefault = true\ndescription = \"Use cargo-binstall instead of cargo install if available\"\ndocs = \"\"\"\nIf true, mise will use `cargo binstall` instead of `cargo install` if\n[`cargo-binstall`](https://crates.io/crates/cargo-binstall) is installed and on PATH.\nThis makes installing CLIs with cargo _much_ faster by downloading precompiled binaries.\n\nYou can install it with mise:\n\n```sh\nmise use -g cargo-binstall\n```\n\"\"\"\nenv = \"MISE_CARGO_BINSTALL\"\ntype = \"Bool\"\n\n[cargo.binstall_only]\ndefault = false\ndescription = \"Only use cargo-binstall for installation, fail if not available.\"\nenv = \"MISE_CARGO_BINSTALL_ONLY\"\ntype = \"Bool\"\n\n[cargo.registry_name]\ndescription = \"Name of the cargo registry to use.\"\ndocs = \"\"\"\nPackages are installed from the official cargo registry.\n\nYou can set this to a different registry name if you have a custom feed or want to use a different source.\n\nPlease follow the [cargo alternative registries documentation](https://doc.rust-lang.org/cargo/reference/registries.html#using-an-alternate-registry) to configure your registry.\n\"\"\"\nenv = \"MISE_CARGO_REGISTRY_NAME\"\noptional = true\ntype = \"String\"\n\n[cargo_binstall]\ndeprecated = \"Use cargo.binstall instead.\"\ndescription = \"Use cargo-binstall instead of cargo install if available\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[cd]\ndescription = \"Path to change to after launching mise\"\nenv = \"MISE_CD\"\nhide = true\noptional = true\ntype = \"Path\"\n\n[ceiling_paths]\ndefault = []\ndescription = \"Directories where mise stops searching for config files.\"\ndocs = \"\"\"\nDirectories where mise stops searching for config files. By default, mise\nwill search from the current directory up to the root of the filesystem.\n\nSetting this to a list of directories will stop the search when one of\nthose directories is reached. Config files **in** the ceiling directory\nitself are excluded—only directories below it are searched. For example,\nif `MISE_CEILING_PATHS=\"/home/user\"`, then `/home/user/mise.toml` is\n**not** loaded, but `/home/user/projects/myapp/mise.toml` is.\n\nThis follows the same semantics as Git's `GIT_CEILING_DIRECTORIES`.\n\nThis is an early-init setting: it must be set in `.miserc.toml`, environment\nvariables, or CLI flags. Setting it in `mise.toml` will have no effect because\nconfig file discovery has already occurred by the time `mise.toml` is read.\n\"\"\"\nenv = \"MISE_CEILING_PATHS\"\nparse_env = \"list_by_colon\"\nrc = true\nrust_type = \"BTreeSet<PathBuf>\"\ntype = \"ListPath\"\n\n[ci]\ndefault = \"false\"\ndescription = \"Set to true if running in a CI environment\"\ndeserialize_with = \"bool_string\"\nenv = \"CI\"\nhide = true\ntype = \"Bool\"\n\n[color]\ndefault = true\ndescription = \"Use color in mise terminal output\"\nenv = \"MISE_COLOR\"\ntype = \"Bool\"\n\n[color_theme]\ndefault = \"default\"\ndescription = \"Theme for interactive prompts (default/charm, base16, catppuccin, dracula)\"\ndocs = \"\"\"\nSets the color theme for interactive prompts like `mise run` task selection.\nAvailable themes:\n\n- `default` or `charm` - Default theme, works well on dark terminals\n- `base16` - Base16 theme, works well on light terminals\n- `catppuccin` - Catppuccin theme\n- `dracula` - Dracula theme\n\nIf you're using a light terminal and the default theme is hard to read,\ntry setting this to `base16`.\n\"\"\"\nenum = [\"default\", \"charm\", \"base16\", \"catppuccin\", \"dracula\"]\nenv = \"MISE_COLOR_THEME\"\ntype = \"String\"\n\n[conda.channel]\ndefault = \"conda-forge\"\ndescription = \"Default channel for conda packages.\"\ndocs = \"\"\"\nDefault conda channel when installing packages with the conda backend.\nOverride per-package with `conda:package[channel=bioconda]`.\n\nThe most common channels are:\n- `conda-forge` - Community-maintained packages (default)\n- `bioconda` - Bioinformatics packages\n- `nvidia` - NVIDIA CUDA packages\n\"\"\"\nenv = \"MISE_CONDA_CHANNEL\"\ntype = \"String\"\n\n[debug]\ndescription = \"Sets log level to debug\"\nenv = \"MISE_DEBUG\"\nhide = true\ntype = \"Bool\"\n\n[default_config_filename]\ndefault = \"mise.toml\"\ndescription = \"The default config filename read. `mise use` and other commands that create new config files will use this value. This must be an env var.\"\nenv = \"MISE_DEFAULT_CONFIG_FILENAME\"\ntype = \"String\"\n\n[default_tool_versions_filename]\ndefault = \".tool-versions\"\ndescription = \"The default .tool-versions filename read. This will not ignore .tool-versions—use override_tool_versions_filename for that. This must be an env var.\"\nenv = \"MISE_DEFAULT_TOOL_VERSIONS_FILENAME\"\ntype = \"String\"\n\n[disable_backends]\ndefault = []\ndescription = \"Backends to disable such as `asdf` or `pipx`\"\nenv = \"MISE_DISABLE_BACKENDS\"\nparse_env = \"list_by_comma\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[disable_default_registry]\ndescription = \"Disable the default mapping of short tool names like `php` -> `asdf:mise-plugins/asdf-php`. This parameter disables only for the backends `vfox` and `asdf`.\"\nenv = \"MISE_DISABLE_DEFAULT_REGISTRY\"\ntype = \"Bool\"\n\n[disable_default_shorthands]\ndeprecated = \"Replaced with `disable_default_registry`\"\ndescription = \"Disables built-in shorthands to asdf/vfox plugins\"\ndocs = \"\"\"\nDisables the shorthand aliases for installing plugins. You will have to specify full URLs when\ninstalling plugins, e.g.: `mise plugin install node https://github.com/asdf-vm/asdf-node.git`\n\"\"\"\nenv = \"MISE_DISABLE_DEFAULT_SHORTHANDS\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[disable_hints]\ndefault = []\ndescription = \"Turns off helpful hints when using different mise features\"\nenv = \"MISE_DISABLE_HINTS\"\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[disable_tools]\ndefault = []\ndescription = \"Tools defined in mise.toml that should be ignored\"\nenv = \"MISE_DISABLE_TOOLS\"\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[dotnet.cli_telemetry_optout]\ndescription = \"Set DOTNET_CLI_TELEMETRY_OPTOUT to opt out of .NET CLI telemetry.\"\ndocs = \"\"\"\nWhen set to true, the `DOTNET_CLI_TELEMETRY_OPTOUT` environment variable is set to `1`,\ndisabling .NET CLI telemetry. When set to false, it is set to `0`.\n\nWhen unset (default), mise does not set the variable and .NET uses its own default behavior.\n\"\"\"\nenv = \"MISE_DOTNET_CLI_TELEMETRY_OPTOUT\"\noptional = true\ntype = \"Bool\"\n\n[dotnet.dotnet_root]\ndescription = \"Path to the shared .NET SDK root directory.\"\ndocs = \"\"\"\nAll .NET SDK versions are installed side-by-side under this directory, matching .NET's native multi-version model.\n\nBy default, mise uses `~/.local/share/mise/dotnet-root`. Set this to override the location.\n\"\"\"\nenv = \"MISE_DOTNET_ROOT\"\noptional = true\ntype = \"Path\"\n\n[dotnet.isolated]\ndefault = false\ndescription = \"Install each .NET SDK version in its own isolated directory.\"\ndocs = \"\"\"\nWhen true, each SDK version is installed in its own directory under mise's installs path,\nlike most other tools. `dotnet --list-sdks` will only show the active version.\n\nWhen false (default), all SDK versions share a single `DOTNET_ROOT` directory and\n`dotnet --list-sdks` shows all installed versions, matching .NET's native side-by-side model.\n\"\"\"\nenv = \"MISE_DOTNET_ISOLATED\"\ntype = \"Bool\"\n\n[dotnet.package_flags]\ndefault = []\ndescription = \"Extends dotnet search and install abilities.\"\ndocs = \"\"\"\nThis is a list of flags to extend the search and install abilities of dotnet tools.\n\nHere are the available flags:\n\n- 'prerelease' : include prerelease versions in search and install\n\"\"\"\nenv = \"MISE_DOTNET_PACKAGE_FLAGS\"\nparse_env = \"list_by_comma\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[dotnet.registry_url]\ndefault = \"https://api.nuget.org/v3/index.json\"\ndescription = \"URL to fetch dotnet tools from.\"\ndocs = \"\"\"\nURL to fetch dotnet tools from. This is used when installing dotnet tools.\n\nBy default, mise will use the [nuget](https://api.nuget.org/v3/index.json) API to fetch.\n\nHowever, you can set this to a different URL if you have a custom feed or want to use a different source.\n\"\"\"\nenv = \"MISE_DOTNET_REGISTRY_URL\"\ntype = \"Url\"\n\n[enable_tools]\ndefault = []\ndescription = \"Tools defined in mise.toml that should be used - all other tools are ignored\"\nenv = \"MISE_ENABLE_TOOLS\"\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[env]\ndefault = []\ndescription = \"Env to use for mise.<MISE_ENV>.toml files.\"\ndocs = \"\"\"\nEnables profile-specific config files such as `.mise.development.toml`.\nUse this for different env vars or different tool versions in\ndevelopment/staging/production environments. See\n[Configuration Environments](/configuration/environments.html) for more on how\nto use this feature.\n\nMultiple envs can be set by separating them with a comma, e.g. `MISE_ENV=ci,test`.\nThey will be read in order, with the last one taking precedence.\n\nThis is an early-init setting: it must be set in `.miserc.toml`, environment\nvariables, or CLI flags (`-E`/`--env`). Setting it in `mise.toml` will have no\neffect because `MISE_ENV` determines which config files to load.\n\"\"\"\nenv = \"MISE_ENV\"\nparse_env = \"list_by_comma\"\nrc = true\ntype = \"ListString\"\n\n[env_cache]\ndefault = false\ndescription = \"[experimental] Enable environment caching for nested mise invocations\"\ndocs = \"\"\"\nWhen enabled, mise will cache the computed environment (env vars and PATH) to disk.\nThis dramatically speeds up nested mise invocations (e.g., `mise x -- mise env`).\n\nThe cache is encrypted using a session-scoped key (`__MISE_ENV_CACHE_KEY`) that is\ngenerated when you run `mise activate` or `mise exec`. This means:\n- Cache files are encrypted and unreadable by other processes\n- When your shell session ends, the key is lost\n- Old cache files become unreadable and will be regenerated\n\nCache invalidation happens when:\n- Any config file changes (mise.toml, .tool-versions, etc.)\n- Tool versions change\n- Settings change\n- mise version changes\n- TTL expires (configurable via `env_cache_ttl`)\n- Any watched files change (from modules or _.source directives)\n\nModules (vfox plugins) can declare themselves cacheable by returning\n`{cacheable = true, watch_files = [...], env = [...]}` from their mise_env hook.\nModules that don't declare cacheability are treated as dynamic and will be\nre-executed on each cache hit.\n\nDirectives can opt out of caching by setting `cacheable = false`:\n```toml\n[env]\nTIMESTAMP = { value = \"{{ now() }}\", cacheable = false }\n_.source = { file = \"dynamic.sh\", cacheable = false }\n```\n\"\"\"\nenv = \"MISE_ENV_CACHE\"\ntype = \"Bool\"\n\n[env_cache_ttl]\ndefault = \"1h\"\ndescription = \"TTL for cached environments\"\ndocs = \"\"\"\nHow long cached environments remain valid before being regenerated.\nAccepts duration strings like \"1h\", \"30m\", \"1d\".\n\nEven with a valid TTL, caches are still invalidated when config files,\ntool versions, settings, or watched files change.\n\"\"\"\nenv = \"MISE_ENV_CACHE_TTL\"\ntype = \"Duration\"\n\n[env_file]\ndescription = \"Path to a file containing environment variables to automatically load.\"\nenv = \"MISE_ENV_FILE\"\noptional = true\ntype = \"Path\"\n\n[env_shell_expand]\ndescription = \"Enable shell-style variable expansion in env values (e.g., $FOO, ${BAR:-default})\"\ndocs = \"\"\"\nControls shell-style variable expansion in `mise.toml` `[env]` values:\n\n```toml\n[env]\nFOO = \"hello\"\nBAR = \"$FOO-world\"        # \"hello-world\"\nBAZ = \"${FOO}_suffix\"     # \"hello_suffix\"\nQUX = \"${UNDEF:-fallback}\" # \"fallback\"\n```\n\n- `true` — enable shell expansion\n- `false` — disable shell expansion (no warning)\n- unset — disable shell expansion but warn if `$` is detected in env values\n  (shell expansion will become the default in a future release)\n\nExpansion happens after Tera template rendering, so both syntaxes can be mixed.\nUndefined variables are left unexpanded (e.g., `$MISSING` stays as `$MISSING`).\n\"\"\"\nenv = \"MISE_ENV_SHELL_EXPAND\"\noptional = true\ntype = \"Bool\"\n\n[erlang.compile]\ndescription = \"If true, compile erlang from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\"\nenv = \"MISE_ERLANG_COMPILE\"\noptional = true\ntype = \"Bool\"\n\n[exec_auto_install]\ndefault = true\ndescription = \"Automatically install missing tools when running `mise x`.\"\nenv = \"MISE_EXEC_AUTO_INSTALL\"\ntype = \"Bool\"\n\n[experimental]\ndescription = \"Enable experimental mise features which are incomplete or unstable—breakings changes may occur\"\ndocs = \"\"\"\nEnables experimental features. I generally will publish new features under\nthis config which needs to be enabled to use them. While a feature is marked\nas \"experimental\" its behavior may change or even disappear in any release.\n\nThe idea is experimental features can be iterated on this way so we can get\nthe behavior right, but once that label goes away you shouldn't expect things\nto change without a proper deprecation—and even then it's unlikely.\n\nAlso, I very often will use experimental as a beta flag as well. New\nfunctionality that I want to test with a smaller subset of users I will often\npush out under experimental mode even if it's not related to an experimental\nfeature.\n\nIf you'd like to help me out, consider enabling it even if you don't have\na particular feature you'd like to try. Also, if something isn't working\nright, try disabling it if you can.\n\"\"\"\nenv = \"MISE_EXPERIMENTAL\"\ntype = \"Bool\"\n\n[fetch_remote_versions_cache]\ndefault = \"1h\"\ndescription = \"How long to cache remote versions for tools.\"\ndocs = \"\"\"\nduration that remote version cache is kept for\n\"fast\" commands (represented by PREFER_STALE), these are always\ncached. For \"slow\" commands like `mise ls-remote` or `mise install`:\n- if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that\n- if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY\n\"\"\"\nenv = \"MISE_FETCH_REMOTE_VERSIONS_CACHE\"\ntype = \"Duration\"\n\n[fetch_remote_versions_timeout]\naliases = [\"fetch_remote_version_timeout\"]\ndefault = \"20s\"\ndescription = \"Timeout in seconds for HTTP requests to fetch new tool versions in mise.\"\nenv = \"MISE_FETCH_REMOTE_VERSIONS_TIMEOUT\"\ntype = \"Duration\"\n\n[github.github_attestations]\ndefault = true\ndescription = \"Enable GitHub Artifact Attestations verification for github backend tools.\"\ndocs = \"\"\"\nEnable/disable GitHub Artifact Attestations verification for github backend tools.\nWhen enabled, mise will verify the authenticity and integrity of downloaded tools\nusing GitHub's artifact attestation system.\n\"\"\"\nenv = \"MISE_GITHUB_GITHUB_ATTESTATIONS\"\ntype = \"Bool\"\n\n[github.slsa]\ndefault = true\ndescription = \"Enable SLSA provenance verification for github backend tools.\"\ndocs = \"\"\"\nEnable/disable SLSA provenance verification for github backend tools.\nWhen enabled, mise will verify the supply-chain integrity of downloaded tools\nusing SLSA provenance attestations.\n\"\"\"\nenv = \"MISE_GITHUB_SLSA\"\ntype = \"Bool\"\n\n[github_attestations]\ndefault = true\ndescription = \"Enable GitHub Artifact Attestations verification for supported tools.\"\ndocs = \"\"\"\nEnable/disable GitHub Artifact Attestations verification globally.\nWhen enabled, mise will verify the authenticity and integrity of downloaded tools\nusing GitHub's artifact attestation system for tools that support it (e.g., Ruby precompiled binaries).\n\"\"\"\nenv = \"MISE_GITHUB_ATTESTATIONS\"\ntype = \"Bool\"\n\n[gix]\ndefault = true\ndescription = \"Use gix for git operations, set to false to shell out to git.\"\ndocs = \"\"\"\nUse gix for git operations. This is generally faster but may not be as compatible if the\nsystem's gix is not the same version as the one used by mise.\n\"\"\"\nenv = \"MISE_GIX\"\nhide = true\ntype = \"Bool\"\n\n[global_config_file]\ndescription = \"Path to the global mise config file. Default is `~/.config/mise/config.toml`. This must be an env var.\"\nenv = \"MISE_GLOBAL_CONFIG_FILE\"\noptional = true\ntype = \"Path\"\n\n[global_config_root]\ndescription = \"Path which is used as `{{config_root}}` for the global config file. Default is `$HOME`. This must be an env var.\"\nenv = \"MISE_GLOBAL_CONFIG_ROOT\"\noptional = true\ntype = \"Path\"\n\n[go_default_packages_file]\ndefault = \"~/.default-go-packages\"\ndescription = \"Path to a file containing default go packages to install when installing go\"\nenv = \"MISE_GO_DEFAULT_PACKAGES_FILE\"\ntype = \"Path\"\n\n[go_download_mirror]\ndefault = \"https://dl.google.com/go\"\ndescription = \"Mirror to download go sdk tarballs from.\"\nenv = \"MISE_GO_DOWNLOAD_MIRROR\"\ntype = \"String\"\n\n[go_repo]\ndefault = \"https://github.com/golang/go\"\ndescription = \"URL to fetch go from.\"\nenv = \"MISE_GO_REPO\"\ntype = \"Url\"\n\n[go_set_gobin]\ndescription = \"Changes where `go install` installs binaries to.\"\ndocs = \"\"\"\nDefaults to `~/.local/share/mise/installs/go/.../bin`.\nSet to `true` to override GOBIN if previously set.\nSet to `false` to not set GOBIN (default is `${GOPATH:-$HOME/go}/bin`).\n\"\"\"\nenv = \"MISE_GO_SET_GOBIN\"\noptional = true\ntype = \"Bool\"\n\n[go_set_gopath]\ndeprecated = \"Use env._go.set_goroot instead.\"\ndescription = \"[deprecated] Set to true to set GOPATH=~/.local/share/mise/installs/go/.../packages.\"\nenv = \"MISE_GO_SET_GOPATH\"\ntype = \"Bool\"\n\n[go_set_goroot]\ndefault = true\ndescription = \"Sets GOROOT=~/.local/share/mise/installs/go/.../.\"\nenv = \"MISE_GO_SET_GOROOT\"\ntype = \"Bool\"\n\n[go_skip_checksum]\ndescription = \"Set to true to skip checksum verification when downloading go sdk tarballs.\"\nenv = \"MISE_GO_SKIP_CHECKSUM\"\ntype = \"Bool\"\n\n[gpg_verify]\ndescription = \"Use gpg to verify all tool signatures.\"\nenv = \"MISE_GPG_VERIFY\"\noptional = true\ntype = \"Bool\"\n\n[hook_env.cache_ttl]\ndefault = \"0s\"\ndescription = \"Cache hook-env directory checks for this duration. Useful for slow filesystems like NFS.\"\ndocs = \"\"\"\nOn slow filesystems (like NFS with cold cache), mise's hook-env can be slow due to\nmultiple filesystem stat operations. Setting this to a positive value (e.g., \"5s\")\nwill cache the results of directory traversal and only re-check after the TTL expires.\n\nWhen set to \"0s\" (default), no caching is performed and every hook-env call will\ncheck the filesystem for changes. This is the safest option but slowest on NFS.\n\nNote: When caching is enabled, newly created config files may not be detected until\nthe TTL expires. Use `mise hook-env --force` to bypass the cache.\n\"\"\"\nenv = \"MISE_HOOK_ENV_CACHE_TTL\"\ntype = \"Duration\"\n\n[hook_env.chpwd_only]\ndefault = false\ndescription = \"Only run hook-env checks on directory change, not on every prompt.\"\ndocs = \"\"\"\nWhen enabled, mise will only perform full config file checks when the directory changes\n(chpwd), not on every shell prompt (precmd). This significantly reduces filesystem\noperations on slow filesystems like NFS.\n\nWith this enabled, changes to config files will not be detected until you change\ndirectories. Use `mise hook-env --force` to manually trigger a full update.\n\nThis setting is useful when:\n- You're working on an NFS filesystem with slow stat operations\n- Config files rarely change during a session\n- You want the fastest possible shell prompt response time\n\"\"\"\nenv = \"MISE_HOOK_ENV_CHPWD_ONLY\"\ntype = \"Bool\"\n\n[http_retries]\ndefault = 0\ndescription = \"Number of retries for HTTP requests in mise.\"\ndocs = \"\"\"\nUses an exponential backoff strategy. The duration is calculated by taking the base (10ms) to the n-th power.\n\"\"\"\nenv = \"MISE_HTTP_RETRIES\"\ntype = \"Integer\"\n\n[http_timeout]\ndefault = \"30s\"\ndescription = \"Timeout in seconds for all HTTP requests in mise.\"\nenv = \"MISE_HTTP_TIMEOUT\"\ntype = \"Duration\"\n\n[idiomatic_version_file]\ndeprecated = \"This has been replaced with the idiomatic_version_file_enable_tools setting.\"\ndescription = \"Set to false to disable the idiomatic version files such as .node-version, .ruby-version, etc.\"\ndocs = \"\"\"\nPlugins can read the versions files used by other version managers (if enabled by the plugin)\nfor example, `.nvmrc` in the case of node's nvm. See [idiomatic version files](/configuration.html#idiomatic-version-files)\nfor more\ninformation.\n\nSet to \"false\" to disable idiomatic version file parsing.\n\"\"\"\nenv = \"MISE_IDIOMATIC_VERSION_FILE\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[idiomatic_version_file_disable_tools]\ndefault = []\ndeprecated = \"This has been replaced with the idiomatic_version_file_enable_tools setting.\"\ndescription = \"Specific tools to disable idiomatic version files for.\"\nenv = \"MISE_IDIOMATIC_VERSION_FILE_DISABLE_TOOLS\"\nhide = true\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[idiomatic_version_file_enable_tools]\ndefault = []\ndescription = \"Specific tools to enable idiomatic version files for like .node-version, .ruby-version, etc.\"\ndocs = \"\"\"\nBy default, idiomatic version files are disabled. You can enable them for specific tools with this setting.\n\nFor example, to enable idiomatic version files for node and python:\n\n    mise settings add idiomatic_version_file_enable_tools node\n    mise settings add idiomatic_version_file_enable_tools python\n\nSee [Idiomatic Version Files](/configuration.html#idiomatic-version-files) for more information.\n\"\"\"\nenv = \"MISE_IDIOMATIC_VERSION_FILE_ENABLE_TOOLS\"\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[ignored_config_paths]\ndefault = []\ndescription = \"This is a list of config paths that mise will ignore.\"\ndocs = \"\"\"\nThis is a list of config paths that mise will ignore.\n\nThis is an early-init setting: it must be set in `.miserc.toml`, environment\nvariables, or CLI flags. Setting it in `mise.toml` will have no effect because\nconfig file discovery has already occurred by the time `mise.toml` is read.\n\"\"\"\nenv = \"MISE_IGNORED_CONFIG_PATHS\"\nparse_env = \"list_by_colon\"\nrc = true\nrust_type = \"BTreeSet<PathBuf>\"\ntype = \"ListPath\"\n\n[install_before]\ndescription = \"Only install versions released before this date\"\ndocs = \"\"\"\nFilter tool versions by release date. Supports:\n\n- Absolute dates: `2024-06-01`, `2024-06-01T12:00:00Z`\n- Relative durations: `90d` (90 days ago), `1y` (1 year ago), `6m` (6 months ago)\n\nThis is useful for reproducible builds or security purposes where you want to ensure\nyou're only installing versions that existed before a certain point in time.\n\nOnly affects backends that provide release timestamps (aqua, cargo, npm, pipx, and some core plugins).\nVersions without timestamps are included by default.\n\n**Behavior**: This filter only applies when resolving fuzzy version requests like `node@20` or `latest`.\nExplicitly pinned versions like `node@22.5.0` are not filtered, allowing you to selectively\nuse newer versions for specific tools while keeping others behind the cutoff date.\n\nCan be overridden with the `--before` CLI flag.\n\"\"\"\nenv = \"MISE_INSTALL_BEFORE\"\noptional = true\ntype = \"String\"\n\n[java.shorthand_vendor]\ndefault = \"openjdk\"\ndescription = \"Shorthand for Java. Used when installing Java without a vendor prefix.\"\nenv = \"MISE_JAVA_SHORTHAND_VENDOR\"\ntype = \"String\"\n\n[jobs]\ndefault = 8\ndescription = \"How many jobs to run concurrently such as tool installs.\"\nenv = \"MISE_JOBS\"\nrust_type = \"usize\"\ntype = \"Integer\"\n\n[legacy_version_file]\ndefault = true\ndeprecated = \"Use idiomatic_version_file instead.\"\ndescription = \"Set to false to disable the idiomatic version files such as .node-version, .ruby-version, etc.\"\nenv = \"MISE_LEGACY_VERSION_FILE\"\nhide = true\ntype = \"Bool\"\n\n[legacy_version_file_disable_tools]\ndefault = []\ndeprecated = \"Use idiomatic_version_file_disable_tools instead.\"\ndescription = \"Specific tools to disable idiomatic version files for.\"\nenv = \"MISE_LEGACY_VERSION_FILE_DISABLE_TOOLS\"\nhide = true\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[libgit2]\ndefault = true\ndescription = \"Use libgit2 for git operations, set to false to shell out to git.\"\ndocs = \"\"\"\nUse libgit2 for git operations. This is generally faster but may not be as compatible if the\nsystem's libgit2 is not the same version as the one used by mise.\n\"\"\"\nenv = \"MISE_LIBGIT2\"\nhide = true\ntype = \"Bool\"\n\n[locked]\ndefault = false\ndescription = \"Require lockfile URLs to be present during installation.\"\ndocs = \"\"\"\n\n> [!NOTE]\n> This setting requires [lockfile](#lockfile) to be enabled.\n\nWhen enabled, `mise install` will fail if tools don't have pre-resolved URLs in the lockfile\nfor the current platform. This prevents API calls to GitHub, aqua registry, etc. and ensures\nreproducible installations.\n\nThis is useful in CI/CD environments where you want to:\n- Avoid GitHub API rate limits\n- Ensure deterministic builds using pre-resolved URLs\n- Fail fast if the lockfile is incomplete\n\nTo generate lockfile URLs, run:\n\n```sh\nmise lock\n```\n\nEquivalent to passing `--locked` to `mise install`.\n\"\"\"\nenv = \"MISE_LOCKED\"\ntype = \"Bool\"\n\n[lockfile]\ndescription = \"Create and read lockfiles for tool versions.\"\ndocs = \"\"\"\nRead/update lockfiles for tool versions. This is useful when you'd like to have loose versions in mise.toml like this:\n\n```toml\n[tools]\nnode = \"22\"\ngh = \"latest\"\n```\n\nBut you'd like the versions installed to be consistent within a project. When this is enabled, mise will update mise.lock\nfiles next to mise.toml files containing pinned versions. When installing tools, mise will reference this lockfile if it exists and this setting is enabled to resolve versions.\n\nThe lockfiles are not created automatically. To generate them, run the following (assuming the config file is `mise.toml`):\n\n```sh\ntouch mise.lock && mise install\n```\n\nThe lockfile is named the same as the config file but with `.lock` instead of `.toml` as the extension, e.g.:\n\n- `mise.toml` -> `mise.lock`\n- `mise.local.toml` -> `mise.local.lock`\n- `.config/mise.toml` -> `.config/mise.lock`\n\nWhen set to `true`, lockfiles are read and written. When set to `false`, lockfiles are explicitly disabled—this\nwill cause an error if `locked = true` is also set, since locked mode requires reading lockfiles.\nWhen unset (the default), lockfiles are enabled (same as `true`) but there is no conflict with `locked` mode.\n\"\"\"\nenv = \"MISE_LOCKFILE\"\noptional = true\ntype = \"Bool\"\n\n[log_level]\ndefault = \"info\"\ndescription = \"Show more/less output.\"\nenum = [\"trace\", \"debug\", \"info\", \"warn\", \"error\"]\nenv = \"MISE_LOG_LEVEL\"\nhide = true\ntype = \"String\"\n\n[netrc]\ndefault = true\ndescription = \"Use a netrc file for HTTP Basic authentication.\"\ndocs = \"\"\"\nWhen enabled, mise will read credentials from the netrc file and apply\nHTTP Basic authentication for matching hosts. This is useful for accessing\nprivate artifact repositories like Artifactory or Nexus.\n\nOn Unix/macOS, the default path is `~/.netrc`.\nOn Windows, mise looks for `%USERPROFILE%\\\\_netrc` first, then falls back to `%USERPROFILE%\\\\.netrc`.\n\nThe netrc file format is:\n\n```\nmachine artifactory.example.com\n  login myuser\n  password mytoken\n```\n\nYou can also specify a custom netrc file path using the `netrc_file` setting.\n\"\"\"\nenv = \"MISE_NETRC\"\ntype = \"Bool\"\n\n[netrc_file]\ndescription = \"Path to the netrc file to use for HTTP Basic authentication.\"\ndocs = \"\"\"\nOverride the default netrc file path. This is useful if you want to use a\ndifferent netrc file for mise or if your netrc file is in a non-standard location.\n\"\"\"\nenv = \"MISE_NETRC_FILE\"\noptional = true\ntype = \"Path\"\n\n[no_env]\ndescription = \"Do not load environment variables from config files.\"\nenv = \"MISE_NO_ENV\"\noptional = true\ntype = \"Bool\"\n\n[no_hooks]\ndescription = \"Do not execute hooks from config files.\"\nenv = \"MISE_NO_HOOKS\"\noptional = true\ntype = \"Bool\"\n\n[node.cflags]\ndescription = \"Additional CFLAGS options (e.g., to override -O3).\"\nenv = \"MISE_NODE_CFLAGS\"\noptional = true\ntype = \"String\"\n\n[node.compile]\ndescription = \"Compile node from source.\"\nenv = \"MISE_NODE_COMPILE\"\noptional = true\ntype = \"Bool\"\n\n[node.concurrency]\ndefault_docs = \"Number of physical CPUs (unless ninja is enabled)\"\ndescription = \"How many jobs should be used in compilation.\"\ndocs = \"\"\"\nNumber of parallel jobs for node compilation. Defaults to the number of physical CPU cores when using make. When ninja is enabled, this defaults to unset (ninja handles concurrency automatically).\n\"\"\"\nenv = \"MISE_NODE_CONCURRENCY\"\noptional = true\ntype = \"Integer\"\n\n[node.configure_opts]\ndescription = \"Additional ./configure options.\"\nenv = \"MISE_NODE_CONFIGURE_OPTS\"\noptional = true\ntype = \"String\"\n\n[node.corepack]\ndescription = \"Installs the default corepack shims after installing any node version.\"\nenv = \"MISE_NODE_COREPACK\"\ntype = \"Bool\"\n\n[node.default_packages_file]\ndefault_docs = \"~/.default-npm-packages\"\ndescription = \"Path to a file containing default npm packages to install.\"\ndocs = \"\"\"\nPath to a file containing packages to install with npm after installing a new Node.js version.\nDefaults to `~/.default-npm-packages`. Also checks `~/.default-nodejs-packages` and `~/.default-node-packages` for backwards compatibility.\n\nFormat: one package per line, with optional version specifier:\n```\nlodash\ntypescript@latest\n@types/node@^20\n```\n\"\"\"\nenv = \"MISE_NODE_DEFAULT_PACKAGES_FILE\"\noptional = true\ntype = \"Path\"\n\n[node.flavor]\ndescription = \"Install a specific node flavor like glibc-217 or musl. Use with unofficial node build repo.\"\nenv = \"MISE_NODE_FLAVOR\"\noptional = true\ntype = \"String\"\n\n[node.gpg_verify]\ndescription = \"Use gpg to verify node tool signatures.\"\nenv = \"MISE_NODE_GPG_VERIFY\"\noptional = true\ntype = \"Bool\"\n\n[node.make]\ndescription = \"Make command to use.\"\nenv = \"MISE_NODE_MAKE\"\noptional = true\ntype = \"String\"\n\n[node.make_install_opts]\ndescription = \"Additional make install options.\"\nenv = \"MISE_NODE_MAKE_INSTALL_OPTS\"\noptional = true\ntype = \"String\"\n\n[node.make_opts]\ndescription = \"Additional make options.\"\nenv = \"MISE_NODE_MAKE_OPTS\"\noptional = true\ntype = \"String\"\n\n[node.mirror_url]\ndescription = \"Mirror to download node tarballs from.\"\nenv = \"MISE_NODE_MIRROR_URL\"\noptional = true\ntype = \"Url\"\n\n[node.ninja]\ndefault_docs = \"Auto-detected: true if ninja is on PATH\"\ndescription = \"Use ninja instead of make to compile node.\"\ndocs = \"\"\"\nIf true, use ninja build system instead of make for faster compilation.\nDefaults to true if `ninja` is found on PATH, false otherwise.\n\nNinja is generally faster than make for incremental builds.\n\"\"\"\nenv = \"MISE_NODE_NINJA\"\noptional = true\ntype = \"Bool\"\n\n[node.nodenv_root]\ndefault = \"~/.nodenv\"\ndescription = \"Directory for nodenv.\"\nenv = \"NODENV_ROOT\"\ntype = \"Path\"\n\n[node.nvm_dir]\ndefault = \"~/.nvm\"\ndescription = \"Directory for nvm.\"\nenv = \"NVM_DIR\"\ntype = \"Path\"\n\n[node.verify]\ndefault = true\ndescription = \"Verify the downloaded assets using GPG.\"\nenv = \"MISE_NODE_VERIFY\"\ntype = \"Bool\"\n\n[not_found_auto_install]\ndefault = true\ndescription = \"Set to false to disable the \\\"command not found\\\" handler to autoinstall missing tool versions.\"\ndocs = \"\"\"\nSet to false to disable the \"command not found\" handler to autoinstall missing tool versions.\nDisable this if experiencing strange behavior in your shell when a command is not found.\n\n**Important limitation**: This handler only installs missing versions of tools that already have\nat least one version installed. mise cannot determine which tool provides a binary without having\nthe tool installed first, so it cannot auto-install completely new tools.\n\nThis also runs in shims if the terminal is interactive.\n\"\"\"\nenv = \"MISE_NOT_FOUND_AUTO_INSTALL\"\ntype = \"Bool\"\n\n[npm.bun]\ndeprecated = \"Use npm.package_manager instead.\"\ndescription = \"Use bun instead of npm if bun is installed and on PATH.\"\ndocs = \"\"\"\nIf true, mise will use `bun` instead of `npm` if\n[`bun`](https://bun.sh/) is installed and on PATH.\nThis makes installing CLIs faster by using `bun` as the package manager.\n\nYou can install it with mise:\n\n```sh\nmise use -g bun\n```\n\"\"\"\nenv = \"MISE_NPM_BUN\"\nhide = true\ntype = \"Bool\"\n\n[npm.package_manager]\ndefault = \"npm\"\ndescription = \"Package manager to use for installing npm packages.\"\ndocs = \"\"\"\nPackage manager to use for installing npm packages.\n\"\"\"\nenum = [\"npm\", \"bun\", \"pnpm\"]\nenv = \"MISE_NPM_PACKAGE_MANAGER\"\nrust_type = \"NpmPackageManager\"\ntype = \"String\"\n\n[offline]\ndescription = \"Disable all HTTP requests. Tools will only use locally cached data.\"\ndocs = \"\"\"\nWhen enabled, mise will never make HTTP requests. This is useful for air-gapped environments,\nVPN issues, or when you want to ensure mise only uses locally cached data.\n\nNote: Commands like `hook-env`, `activate`, `exec`, `env`, and shims already avoid most network\nrequests via the `prefer_offline` behavior. Set `offline = true` to completely block all\nHTTP requests for commands like `mise install` or `mise ls-remote` as well.\n\nCan also be set with the `--offline` CLI flag.\n\"\"\"\nenv = \"MISE_OFFLINE\"\ntype = \"Bool\"\n\n[os]\ndefault_docs = '\"linux\" | \"macos\" | \"windows\"'\ndescription = \"OS to use for precompiled binaries.\"\nenv = \"MISE_OS\"\noptional = true\ntype = \"String\"\n\n[override_config_filenames]\ndefault = []\ndescription = \"If set, mise will ignore default config files like `mise.toml` and use these filenames instead.\"\ndocs = \"\"\"\nIf set, mise will ignore default config files like `mise.toml` and use these\nfilenames instead.\n\nThis is an early-init setting: it must be set in `.miserc.toml`, environment\nvariables, or CLI flags. Setting it in `mise.toml` will have no effect because\nconfig file discovery has already occurred by the time `mise.toml` is read.\n\"\"\"\nenv = \"MISE_OVERRIDE_CONFIG_FILENAMES\"\nparse_env = \"list_by_colon\"\nrc = true\ntype = \"ListString\"\n\n[override_tool_versions_filenames]\ndefault = []\ndescription = \"If set, mise will ignore .tool-versions files and use these filenames instead. Can be set to `none` to disable .tool-versions.\"\ndocs = \"\"\"\nIf set, mise will ignore .tool-versions files and use these filenames instead.\nCan be set to `none` to disable .tool-versions entirely.\n\nThis is an early-init setting: it must be set in `.miserc.toml`, environment\nvariables, or CLI flags. Setting it in `mise.toml` will have no effect because\nconfig file discovery has already occurred by the time `mise.toml` is read.\n\"\"\"\nenv = \"MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES\"\nparse_env = \"list_by_colon\"\nrc = true\ntype = \"ListString\"\n\n[paranoid]\ndescription = \"Enables extra-secure behavior.\"\ndocs = \"\"\"\nEnables extra-secure behavior. See [Paranoid](/paranoid.html).\n\"\"\"\nenv = \"MISE_PARANOID\"\ntype = \"Bool\"\n\n[pin]\ndescription = \"Default to pinning versions when running `mise use` in mise.toml files.\"\ndocs = \"\"\"\nThis sets `--pin` by default when running `mise use` in mise.toml files. This can be overridden by\npassing `--fuzzy` on the command line.\n\"\"\"\nenv = \"MISE_PIN\"\ntype = \"Bool\"\n\n[pipx.registry_url]\ndefault = \"https://pypi.org/pypi/{}/json\"\ndescription = \"URL to use for pipx registry.\"\ndocs = \"\"\"\nURL to use for pipx registry.\n\nThis is used to fetch the latest version of a package from the pypi registry.\n\nThe default is `https://pypi.org/pypi/{}/json` which is the JSON endpoint for the pypi\nregistry.\n\nYou can also use the HTML endpoint by setting this to `https://pypi.org/simple/{}/`.\n\"\"\"\nenv = \"MISE_PIPX_REGISTRY_URL\"\ntype = \"String\"\n\n[pipx.uvx]\ndefault_docs = \"true\"\ndescription = \"Use uvx instead of pipx if uv is installed and on PATH.\"\ndocs = \"\"\"\nIf true, mise will use `uvx` instead of `pipx` if\n[`uv`](https://docs.astral.sh/uv/) is installed and on PATH.\nThis makes installing CLIs _much_ faster by using `uv` as the package manager.\n\nYou can install it with mise:\n\n```sh\nmise use -g uv\n```\n\"\"\"\nenv = \"MISE_PIPX_UVX\"\noptional = true\ntype = \"Bool\"\n\n[pipx_uvx]\ndescription = \"Use uvx instead of pipx if uv is installed and on PATH.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[plugin_autoupdate_last_check_duration]\ndefault = \"7d\"\ndescription = \"How long to wait before updating plugins automatically (note this isn't currently implemented).\"\nenv = \"MISE_PLUGIN_AUTOUPDATE_LAST_CHECK_DURATION\"\ntype = \"String\"\n\n[prefer_offline]\ndescription = \"Prefer locally cached data over remote fetches when possible.\"\ndocs = \"\"\"\nWhen enabled, mise will prefer locally cached data and avoid remote version fetching when\npossible. Unlike `offline`, this still allows network requests as a fallback.\n\nThis is automatically enabled for fast commands like `hook-env`, `activate`, `exec`, `env`,\n`ls`, `current`, `where`, and shims.\n\"\"\"\nenv = \"MISE_PREFER_OFFLINE\"\ntype = \"Bool\"\n\n[profile]\ndeprecated = \"Use MISE_ENV_FILE instead.\"\ndescription = \"Profile to use for mise.${MISE_PROFILE}.toml files.\"\nenv = \"MISE_PROFILE\"\nhide = true\noptional = true\ntype = \"String\"\n\n[python.compile]\ndescription = \"If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\"\ndocs = \"\"\"\n* Values:\n  * `true` - always compile with python-build instead of downloading [precompiled binaries](/lang/python.html#precompiled-python-binaries).\n  * `false` - always download precompiled binaries.\n  * [undefined] - use precompiled binary if one is available for the current platform, compile otherwise.\n\"\"\"\nenv = \"MISE_PYTHON_COMPILE\"\noptional = true\ntype = \"Bool\"\n\n[python.default_packages_file]\ndescription = \"Path to a file containing default python packages to install when installing a python version.\"\nenv = \"MISE_PYTHON_DEFAULT_PACKAGES_FILE\"\noptional = true\ntype = \"Path\"\n\n[python.patch_url]\ndescription = \"URL to fetch python patches from to pass to python-build.\"\nenv = \"MISE_PYTHON_PATCH_URL\"\noptional = true\ntype = \"Url\"\n\n[python.patches_directory]\ndescription = \"Directory to fetch python patches from.\"\nenv = \"MISE_PYTHON_PATCHES_DIRECTORY\"\noptional = true\ntype = \"Path\"\n\n[python.precompiled_arch]\ndefault_docs = '\"apple-darwin\" | \"unknown-linux-gnu\" | \"unknown-linux-musl\"'\ndescription = \"Specify the architecture to use for precompiled binaries.\"\nenv = \"MISE_PYTHON_PRECOMPILED_ARCH\"\noptional = true\ntype = \"String\"\n\n[python.precompiled_flavor]\ndefault_docs = \"install_only_stripped\"\ndescription = \"Specify the flavor to use for precompiled binaries.\"\ndocs = \"\"\"\nSpecify the flavor to use for precompiled binaries.\n\nOptions are available here: <https://gregoryszorc.com/docs/python-build-standalone/main/running.html>\n\"\"\"\nenv = \"MISE_PYTHON_PRECOMPILED_FLAVOR\"\noptional = true\ntype = \"String\"\n\n[python.precompiled_os]\ndefault_docs = '\"x86_64_v3\" | \"aarch64\"'\ndescription = \"Specify the OS to use for precompiled binaries.\"\ndocs = \"\"\"\nSpecify the architecture to use for precompiled binaries. If on an old CPU, you may want to set this to \"x86_64\" for the most compatible binaries. See https://gregoryszorc.com/docs/python-build-standalone/main/running.html for more information.\n\"\"\"\nenv = \"MISE_PYTHON_PRECOMPILED_OS\"\noptional = true\ntype = \"String\"\n\n[python.pyenv_repo]\ndefault = \"https://github.com/pyenv/pyenv.git\"\ndescription = \"URL to fetch pyenv from for compiling python with python-build.\"\nenv = \"MISE_PYENV_REPO\"\ntype = \"String\"\n\n[python.uv_venv_auto]\ndefault = false\ndescription = \"Integrate with uv to manage project venvs when uv.lock is present.\"\ndocs = \"\"\"\nControls how mise handles uv project venvs when a uv.lock file is present.\n\nThe legacy `true` value (will be deprecated in a future release) is treated like \"create|source\", with one difference:\nWhen using this, mise also exports `UV_PYTHON` to force uv to use the python version managed by mise.\n\"\"\"\nenum = [\n  { value = false, description = \"disable uv venv integration\" },\n  { value = \"source\", description = \"only source an existing `.venv`\" },\n  { value = \"create|source\", description = \"create the venv if missing and source it\" },\n  { value = true, description = \"(create|source) with UV_PYTHON export (legacy)\" },\n]\nenv = \"MISE_PYTHON_UV_VENV_AUTO\"\nrust_type = \"PythonUvVenvAuto\"\ntype = \"BoolOrString\"\n\n[python.uv_venv_create_args]\ndescription = \"Arguments to pass to uv when creating a venv.\"\nenv = \"MISE_PYTHON_UV_VENV_CREATE_ARGS\"\noptional = true\nparse_env = \"list_by_colon\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[python.venv_create_args]\ndescription = \"Arguments to pass to python when creating a venv. (not used for uv venv creation)\"\nenv = \"MISE_PYTHON_VENV_CREATE_ARGS\"\noptional = true\nparse_env = \"list_by_colon\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[python.venv_stdlib]\ndescription = \"Prefer to use venv from Python's standard library.\"\nenv = \"MISE_VENV_STDLIB\"\ntype = \"Bool\"\n\n[python_compile]\ndeprecated = \"Use python.compile instead.\"\ndescription = \"If true, compile python from source. If false, use precompiled binaries. If not set, use precompiled binaries if available.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[python_default_packages_file]\ndeprecated = \"Use python.default_packages_file instead.\"\ndescription = \"Path to a file containing default python packages to install when installing python.\"\nhide = true\noptional = true\ntype = \"Path\"\n\n[python_patch_url]\ndeprecated = \"Use python.patch_url instead.\"\ndescription = \"URL to fetch python patches from.\"\nhide = true\noptional = true\ntype = \"String\"\n\n[python_patches_directory]\ndeprecated = \"Use python.patch_url instead.\"\ndescription = \"Directory to fetch python patches from.\"\nhide = true\noptional = true\ntype = \"Path\"\n\n[python_precompiled_arch]\ndeprecated = \"Use python.precompiled_arch instead.\"\ndescription = \"Specify the architecture to use for precompiled binaries.\"\nhide = true\noptional = true\ntype = \"String\"\n\n[python_precompiled_os]\ndeprecated = \"Use python.precompiled_os instead.\"\ndescription = \"Specify the OS to use for precompiled binaries.\"\nhide = true\noptional = true\ntype = \"String\"\n\n[python_pyenv_repo]\ndeprecated = \"Use python.pyenv_repo instead.\"\ndescription = \"URL to fetch pyenv from for compiling python.\"\nhide = true\noptional = true\ntype = \"String\"\n\n[python_venv_stdlib]\ndeprecated = \"Use python.venv_stdlib instead.\"\ndescription = \"Prefer to use venv from Python's standard library.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[quiet]\ndescription = \"Suppress all output except errors.\"\nenv = \"MISE_QUIET\"\ntype = \"Bool\"\n\n[raw]\ndescription = \"Connect stdin/stdout/stderr to child processes.\"\nenv = \"MISE_RAW\"\ntype = \"Bool\"\n\n[ruby.apply_patches]\ndescription = \"A list of patch files or URLs to apply to ruby source.\"\nenv = \"MISE_RUBY_APPLY_PATCHES\"\noptional = true\ntype = \"String\"\n\n[ruby.compile]\ndescription = \"Set to true to compile ruby from source, false to use precompiled binaries.\"\ndocs = \"\"\"\nControls whether Ruby is compiled from source or downloaded as precompiled binaries.\n\n- If `false`: Try precompiled binaries first, fall back to compiling if unavailable\n- If `true`: Always compile from source using ruby-build\n- If unset: Defaults to compiling from source (will change to precompiled in 2026.8.0). Note: if `experimental = true`, precompiled binaries are used when unset.\n\"\"\"\nenv = \"MISE_RUBY_COMPILE\"\noptional = true\ntype = \"Bool\"\n\n[ruby.default_packages_file]\ndefault = \"~/.default-gems\"\ndescription = \"Path to a file containing default ruby gems to install when installing ruby.\"\nenv = \"MISE_RUBY_DEFAULT_PACKAGES_FILE\"\ntype = \"String\"\n\n[ruby.github_attestations]\ndescription = \"Enable GitHub Artifact Attestations verification for precompiled Ruby binaries.\"\ndocs = \"\"\"\nOverride the global `github_attestations` setting for Ruby precompiled binaries.\nWhen enabled, mise will verify the authenticity of precompiled Ruby binaries from jdx/ruby.\n\nDefaults to the global `github_attestations` setting if not specified.\n\"\"\"\nenv = \"MISE_RUBY_GITHUB_ATTESTATIONS\"\noptional = true\ntype = \"Bool\"\n\n[ruby.precompiled_arch]\ndescription = \"Override architecture identifier for precompiled Ruby binaries.\"\nenv = \"MISE_RUBY_PRECOMPILED_ARCH\"\noptional = true\ntype = \"String\"\n\n[ruby.precompiled_os]\ndescription = \"Override OS identifier for precompiled Ruby binaries.\"\nenv = \"MISE_RUBY_PRECOMPILED_OS\"\noptional = true\ntype = \"String\"\n\n[ruby.precompiled_url]\ndefault = \"jdx/ruby\"\ndescription = \"URL template or GitHub repo for precompiled Ruby binaries.\"\ndocs = \"\"\"\nCan be either:\n- A GitHub repo shorthand: `\"jdx/ruby\"` or `\"yourorg/ruby\"`\n- A full URL template with variables: `{version}`, `{platform}`, `{os}`, `{arch}`\n\nExamples:\n```toml\n[settings.ruby]\n# Use a different GitHub repo\nprecompiled_url = \"yourorg/ruby\"\n\n# Or use a custom URL template\nprecompiled_url = \"https://my-mirror.example.com/ruby-{version}.{platform}.tar.gz\"\n```\n\"\"\"\nenv = \"MISE_RUBY_PRECOMPILED_URL\"\ntype = \"String\"\n\n[ruby.ruby_build_opts]\ndescription = \"Options to pass to ruby-build.\"\nenv = \"MISE_RUBY_BUILD_OPTS\"\noptional = true\ntype = \"String\"\n\n[ruby.ruby_build_repo]\ndefault = \"https://github.com/rbenv/ruby-build.git\"\ndescription = \"The URL used to fetch ruby-build. This accepts either a Git repository or a ZIP archive.\"\nenv = \"MISE_RUBY_BUILD_REPO\"\ntype = \"String\"\n\n[ruby.ruby_install]\ndescription = \"Use ruby-install instead of ruby-build.\"\nenv = \"MISE_RUBY_INSTALL\"\ntype = \"Bool\"\n\n[ruby.ruby_install_opts]\ndescription = \"Options to pass to ruby-install.\"\nenv = \"MISE_RUBY_INSTALL_OPTS\"\noptional = true\ntype = \"String\"\n\n[ruby.ruby_install_repo]\ndefault = \"https://github.com/postmodern/ruby-install.git\"\ndescription = \"The URL used to fetch ruby-install. This accepts either a Git repository or a ZIP archive.\"\nenv = \"MISE_RUBY_INSTALL_REPO\"\ntype = \"String\"\n\n[ruby.verbose_install]\ndescription = \"Set to true to enable verbose output during ruby installation.\"\nenv = \"MISE_RUBY_VERBOSE_INSTALL\"\noptional = true\ntype = \"Bool\"\n\n[rust.cargo_home]\ndescription = \"Path to the cargo home directory. Defaults to `~/.cargo` or `%USERPROFILE%\\\\.cargo`\"\nenv = \"MISE_CARGO_HOME\"\noptional = true\ntype = \"Path\"\n\n[rust.default_host]\ndescription = \"Default host triple to pass to `rustup init` via `--default-host`.\"\nenv = \"MISE_RUST_DEFAULT_HOST\"\noptional = true\ntype = \"String\"\n\n[rust.rustup_home]\ndescription = \"Path to the rustup home directory. Defaults to `~/.rustup` or `%USERPROFILE%\\\\.rustup`\"\nenv = \"MISE_RUSTUP_HOME\"\noptional = true\ntype = \"Path\"\n\n[shared_install_dirs]\ndescription = \"[experimental] Additional read-only directories to search for installed tool versions.\"\ndocs = \"\"\"\nA list of additional directories to search for installed tool versions. These directories\nare checked after the primary install directory (`~/.local/share/mise/installs`) when\nlooking for installed tools. They are read-only—mise will never install tools into these\ndirectories.\n\nThe system directory `/usr/local/share/mise/installs` (or `MISE_SYSTEM_DATA_DIR/installs`) is\nalways checked automatically when it exists—you do not need to add it here. To populate it,\nrun: `mise install --system node@20`\n\nThis is useful for shared environments like Docker containers or bastion hosts where a\nbase set of tools is pre-installed in a shared location, and users can install additional\ntools in their own directory.\n\nPaths are colon-separated when using the environment variable.\n\"\"\"\nenv = \"MISE_SHARED_INSTALL_DIRS\"\noptional = true\nparse_env = \"list_by_colon\"\nrust_type = \"Vec<PathBuf>\"\ntype = \"ListPath\"\n\n[shorthands_file]\ndescription = \"Path to a file containing custom tool shorthands.\"\ndocs = \"\"\"\nUse a custom file for the shorthand aliases. This is useful if you want to share plugins within\nan organization.\n\nShorthands make it so when a user runs something like `mise install elixir` mise will\nautomatically install the [asdf-elixir](https://github.com/asdf-vm/asdf-elixir) plugin. By\ndefault, it uses the shorthands in\n[`registry/`](https://github.com/jdx/mise/blob/main/registry/).\n\nThe file should be in this toml format:\n\n```toml\nelixir = \"https://github.com/my-org/mise-elixir.git\"\nnode = \"https://github.com/my-org/mise-node.git\"\n```\n\n\"\"\"\nenv = \"MISE_SHORTHANDS_FILE\"\noptional = true\ntype = \"Path\"\n\n[silent]\ndescription = \"Suppress all `mise run|watch` output except errors—including what tasks output.\"\nenv = \"MISE_SILENT\"\ntype = \"Bool\"\n\n[slsa]\ndefault = true\ndescription = \"Enable SLSA provenance verification globally.\"\ndocs = \"\"\"\nEnable/disable SLSA provenance verification globally for all backends that support it.\nWhen enabled, mise will verify the supply-chain integrity of downloaded tools\nusing SLSA provenance attestations.\n\"\"\"\nenv = \"MISE_SLSA\"\ntype = \"Bool\"\n\n[sops.age_key]\ndescription = \"The age private key to use for sops secret decryption. Takes precedence over standard SOPS_AGE_KEY environment variable.\"\nenv = \"MISE_SOPS_AGE_KEY\"\noptional = true\ntype = \"String\"\n\n[sops.age_key_file]\ndefault_docs = \"~/.config/mise/age.txt\"\ndescription = \"Path to the age private key file for sops secret decryption. Takes precedence over standard SOPS_AGE_KEY_FILE environment variable.\"\nenv = \"MISE_SOPS_AGE_KEY_FILE\"\noptional = true\ntype = \"Path\"\n\n[sops.age_recipients]\ndescription = \"The age public keys to use for sops secret encryption.\"\nenv = \"MISE_SOPS_AGE_RECIPIENTS\"\noptional = true\ntype = \"String\"\n\n[sops.rops]\ndefault = true\ndescription = \"Use rops to decrypt sops files. Disable to shell out to `sops` which will slow down mise but sops may offer features not available in rops.\"\nenv = \"MISE_SOPS_ROPS\"\ntype = \"Bool\"\n\n[sops.strict]\ndefault = true\ndescription = \"If true, fail when sops decryption fails (including when sops is not available, the key is missing, or the key is invalid). If false, skip decryption and continue in these cases.\"\nenv = \"MISE_SOPS_STRICT\"\ntype = \"Bool\"\n\n[status.missing_tools]\ndefault = \"if_other_versions_installed\"\ndescription = \"Show a warning if tools are not installed when entering a directory with a mise.toml file.\"\ndocs = \"\"\"\n| Choice                                  | Description                                                                |\n|-----------------------------------------|----------------------------------------------------------------------------|\n| `if_other_versions_installed` [default] | Show the warning only when the tool has at least 1 other version installed |\n| `always`                                | Always show the warning                                                    |\n| `never`                                 | Never show the warning                                                     |\n\nShow a warning if tools are not installed when entering a directory with a `mise.toml` file.\n\nDisable tools with [`disable_tools`](#disable_tools).\n\"\"\"\nenv = \"MISE_STATUS_MESSAGE_MISSING_TOOLS\"\ntype = \"String\"\n\n[status.show_env]\ndescription = \"Show configured env vars when entering a directory with a mise.toml file.\"\nenv = \"MISE_STATUS_MESSAGE_SHOW_ENV\"\ntype = \"Bool\"\n\n[status.show_prepare_stale]\ndefault = true\ndescription = \"Show warning when prepare providers have stale dependencies.\"\nenv = \"MISE_STATUS_SHOW_PREPARE_STALE\"\ntype = \"Bool\"\n\n[status.show_tools]\ndescription = \"Show configured tools when entering a directory with a mise.toml file.\"\nenv = \"MISE_STATUS_MESSAGE_SHOW_TOOLS\"\ntype = \"Bool\"\n\n[status.truncate]\ndefault = true\ndescription = \"Truncate status messages.\"\nenv = \"MISE_STATUS_MESSAGE_TRUNCATE\"\ntype = \"Bool\"\n\n[swift.gpg_verify]\ndescription = \"Use gpg to verify swift tool signatures.\"\nenv = \"MISE_SWIFT_GPG_VERIFY\"\noptional = true\ntype = \"Bool\"\n\n[swift.platform]\ndefault_docs = '\"osx\" | \"windows10\" | \"ubuntu20.04\" | \"ubuntu22.04\" | \"ubuntu24.04\" | \"amazonlinux2\" | \"ubi9\" | \"fedora39\"'\ndescription = \"Override the platform to use for precompiled binaries.\"\nenv = \"MISE_SWIFT_PLATFORM\"\noptional = true\ntype = \"String\"\n\n[system_config_file]\ndescription = \"Path to the system mise config file. Default is `/etc/mise/config.toml`. This must be an env var.\"\nenv = \"MISE_SYSTEM_CONFIG_FILE\"\noptional = true\ntype = \"Path\"\n\n[task.disable_paths]\ndefault = []\ndescription = \"Paths that mise will not look for tasks in.\"\nenv = \"MISE_TASK_DISABLE_PATHS\"\nparse_env = \"list_by_colon\"\nrust_type = \"BTreeSet<PathBuf>\"\ntype = \"ListPath\"\n\n[task.disable_spec_from_run_scripts]\ndefault = false\ndescription = \"Opt out of parsing task run scripts to infer the usage spec (arguments and flags). When enabled, mise will derive the usage spec only from the `usage` field, ignoring any `arg()`, `option()`, or `flag()` templates used in run scripts. This can restore previous behavior and avoid the extra template pass over run scripts when collecting specs.\"\ndocs = \"\"\"\nWhen enabled, `arg()`, `option()`, and `flag()` Tera functions in run scripts will not contribute\nto the task's usage spec—only the explicit `usage` field is used.\n\nThis is useful for:\n- Skipping the extra template pass over run scripts (performance)\n- Avoiding two-pass parsing quirks where template functions return empty strings during spec collection\n- Early opt-out before Tera template arguments are removed in 2026.11.0\n\"\"\"\nenv = \"MISE_TASK_DISABLE_SPEC_FROM_RUN_SCRIPTS\"\ntype = \"Bool\"\n\n[task.monorepo_depth]\ndefault = 5\ndescription = \"Maximum depth to search for task files in monorepo subdirectories.\"\ndocs = \"\"\"\nWhen using monorepo mode (experimental_monorepo_root = true), this controls how deep\nmise will search for task files in subdirectories.\n\n**Depth levels:**\n- 1 = immediate children only (monorepo_root/projects/)\n- 2 = grandchildren (monorepo_root/projects/frontend/)\n- 5 = default (5 levels deep)\n\n**Performance tip:** Reduce this value if you have a very large monorepo and notice\nslow task discovery. For example, if your projects are all at `projects/*`, set to 2.\n\n**Example:**\n```toml\n[settings]\ntask.monorepo_depth = 3  # Only search 3 levels deep\n```\n\nOr via environment variable:\n```bash\nexport MISE_TASK_MONOREPO_DEPTH=3\n```\n\"\"\"\nenv = \"MISE_TASK_MONOREPO_DEPTH\"\ntype = \"Integer\"\n\n[task.monorepo_exclude_dirs]\ndefault = []\ndescription = \"Directory patterns to exclude when discovering monorepo subdirectories.\"\ndocs = \"\"\"\nIf empty (default), uses default exclusions: node_modules, target, dist, build.\nIf you specify any patterns, ONLY those patterns will be excluded (defaults are NOT included).\nFor example, setting to [\".temp\", \"vendor\"] will exclude only those two directories.\n\"\"\"\nenv = \"MISE_TASK_MONOREPO_EXCLUDE_DIRS\"\nparse_env = \"list_by_comma\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[task.monorepo_respect_gitignore]\ndefault = true\ndescription = \"Whether to respect .gitignore files when discovering monorepo subdirectories.\"\ndocs = \"\"\"\nWhen enabled, mise will skip directories that are ignored by .gitignore files\nwhen discovering tasks in a monorepo.\n\"\"\"\nenv = \"MISE_TASK_MONOREPO_RESPECT_GITIGNORE\"\ntype = \"Bool\"\n\n[task.output]\ndescription = \"Change output style when executing tasks.\"\ndocs = \"\"\"\nChange output style when executing tasks. This controls the output of `mise run`.\n\"\"\"\nenum = [\n  { value = \"prefix\", description = \"(default if jobs > 1) print by line with the prefix of the task name\" },\n  { value = \"interleave\", description = \"(default if jobs == 1 or all tasks run sequentially) print output as it comes in\" },\n  { value = \"keep-order\", description = \"stream one task's output live while buffering others, printing in definition order as tasks complete\" },\n  { value = \"replacing\", description = \"replace stdout each time a line is printed-this uses similar logic as `mise install`\" },\n  { value = \"timed\", description = \"only show stdout lines that take longer than 1s to complete\" },\n  { value = \"quiet\", description = \"print only stdout/stderr from tasks and nothing from mise\" },\n  { value = \"silent\", description = \"print nothing from tasks or mise\" },\n]\nenv = \"MISE_TASK_OUTPUT\"\noptional = true\nrust_type = \"crate::task::TaskOutput\"\ntype = \"String\"\n\n[task.remote_no_cache]\ndescription = \"Mise will always fetch the latest tasks from the remote, by default the cache is used.\"\nenv = \"MISE_TASK_REMOTE_NO_CACHE\"\noptional = true\ntype = \"Bool\"\n\n[task.run_auto_install]\ndefault = true\ndescription = \"Automatically install missing tools when executing tasks.\"\nenv = \"MISE_TASK_RUN_AUTO_INSTALL\"\ntype = \"Bool\"\n\n[task.show_full_cmd]\ndescription = \"Disable truncation of command lines in task execution output. When true, the full command line will be shown.\"\nenv = \"MISE_TASK_SHOW_CMD_NO_TRUNC\"\ntype = \"Bool\"\n\n[task.skip]\ndefault = []\ndescription = \"Tasks to skip when running `mise run`.\"\nenv = \"MISE_TASK_SKIP\"\nparse_env = \"set_by_comma\"\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[task.skip_depends]\ndescription = \"Run only specified tasks skipping all dependencies.\"\nenv = \"MISE_TASK_SKIP_DEPENDS\"\ntype = \"Bool\"\n\n[task.source_freshness_equal_mtime_is_fresh]\ndefault = false\ndescription = \"When source mtime equals output mtime, consider sources fresh (use <=). Default false uses strict < comparison.\"\nenv = \"MISE_TASK_SOURCE_FRESHNESS_EQUAL_MTIME_IS_FRESH\"\ntype = \"Bool\"\n\n[task.source_freshness_hash_contents]\ndefault = false\ndescription = \"Use content hashing (blake3) instead of metadata for source freshness. More accurate but slower.\"\nenv = \"MISE_TASK_SOURCE_FRESHNESS_HASH_CONTENTS\"\ntype = \"Bool\"\n\n[task.timeout]\ndescription = \"Default timeout for tasks. Can be overridden by individual tasks.\"\nenv = \"MISE_TASK_TIMEOUT\"\noptional = true\ntype = \"Duration\"\n\n[task.timings]\ndescription = \"Show completion message with elapsed time for each task on `mise run`. Default shows when output type is `prefix`.\"\nenv = \"MISE_TASK_TIMINGS\"\noptional = true\ntype = \"Bool\"\n\n[task_disable_paths]\ndeprecated = \"Use task.disable_paths instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Paths that mise will not look for tasks in.\"\nhide = true\noptional = true\nrust_type = \"BTreeSet<PathBuf>\"\ntype = \"ListPath\"\n\n[task_output]\ndeprecated = \"Use task.output instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Change output style when executing tasks.\"\nhide = true\noptional = true\nrust_type = \"crate::task::TaskOutput\"\ntype = \"String\"\n\n[task_remote_no_cache]\ndeprecated = \"Use task.remote_no_cache instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Mise will always fetch the latest tasks from the remote, by default the cache is used.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[task_run_auto_install]\ndeprecated = \"Use task.run_auto_install instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Automatically install missing tools when executing tasks.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[task_show_full_cmd]\ndeprecated = \"Use task.show_full_cmd instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Disable truncation of command lines in task execution output. When true, the full command line will be shown.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[task_skip]\ndeprecated = \"Use task.skip instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Tasks to skip when running `mise run`.\"\nhide = true\noptional = true\nrust_type = \"BTreeSet<String>\"\ntype = \"SetString\"\n\n[task_skip_depends]\ndeprecated = \"Use task.skip_depends instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Run only specified tasks skipping all dependencies.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[task_timeout]\ndeprecated = \"Use task.timeout instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Default timeout for tasks. Can be overridden by individual tasks.\"\nhide = true\noptional = true\ntype = \"Duration\"\n\n[task_timings]\ndeprecated = \"Use task.timings instead.\"\ndeprecated_remove_at = \"2027.2.0\"\ndeprecated_warn_at = \"2026.8.0\"\ndescription = \"Show completion message with elapsed time for each task on `mise run`. Default shows when output type is `prefix`.\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[terminal_progress]\ndefault = true\ndescription = \"Enable terminal progress indicators (OSC 9;4) for compatible terminals.\"\ndocs = \"\"\"\nEnable terminal progress indicators using OSC 9;4 escape sequences. This provides\nnative progress bars in the terminal window chrome for terminals that support it,\nincluding Ghostty, iTerm2, VS Code's integrated terminal, Windows Terminal, and VTE-based\nterminals (GNOME Terminal, Ptyxis, etc.).\n\nWhen enabled, mise will send progress updates to the terminal during operations like\ntool installations. The progress bar appears in the terminal's window UI, separate\nfrom the text output.\n\nmise automatically detects whether your terminal supports OSC 9;4 and will only send\nthese sequences if supported. Terminals like Alacritty, WezTerm, and kitty\ndo not support OSC 9;4 and will not receive these sequences.\n\nSet to false to disable this feature if you prefer not to see these indicators.\n\"\"\"\nenv = \"MISE_TERMINAL_PROGRESS\"\ntype = \"Bool\"\n\n[trace]\ndescription = \"Sets log level to trace\"\nenv = \"MISE_TRACE\"\nhide = true\ntype = \"Bool\"\n\n[trusted_config_paths]\ndefault = []\ndescription = \"This is a list of config paths that mise will automatically mark as trusted.\"\nenv = \"MISE_TRUSTED_CONFIG_PATHS\"\nparse_env = \"list_by_colon\"\nrust_type = \"BTreeSet<PathBuf>\"\ntype = \"ListPath\"\n\n[unix_default_file_shell_args]\ndefault = \"sh\"\ndescription = \"Default shell arguments for Unix to be used for file commands. For example, `sh` for sh.\"\nenv = \"MISE_UNIX_DEFAULT_FILE_SHELL_ARGS\"\ntype = \"String\"\n\n[unix_default_inline_shell_args]\ndefault = \"sh -c -o errexit\"\ndescription = \"Default shell arguments for Unix to be used for inline commands. For example, `sh -c` for sh.\"\nenv = \"MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS\"\ntype = \"String\"\n\n[url_replacements]\ndescription = \"Map of URL patterns to replacement URLs applied to all requests.\"\ndocs = '''\nMap of URL patterns to replacement URLs. This feature supports both simple hostname replacements\nand advanced regex-based URL transformations for download mirroring and custom registries.\n\nSee [URL Replacements](/url-replacements.html) for more information.\n'''\nenv = \"MISE_URL_REPLACEMENTS\"\noptional = true\nparse_env = \"parse_url_replacements\"\ntype = \"IndexMap<String, String>\"\n\n[use_file_shell_for_executable_tasks]\ndefault = false\ndescription = \"Determines whether to use a specified shell for executing tasks in the tasks directory. When set to true, the shell defined in the file will be used, or the default shell specified by `windows_default_file_shell_args` or `unix_default_file_shell_args` will be applied. If set to false, tasks will be executed directly as programs.\"\nenv = \"MISE_USE_FILE_SHELL_FOR_EXECUTABLE_TASKS\"\ntype = \"Bool\"\n\n[use_versions_host]\ndefault = true\ndescription = \"Set to false to disable using the mise-versions API as a quick way for mise to query for new versions.\"\ndocs = \"\"\"\nSet to \"false\" to disable using [mise-versions](https://mise-versions.jdx.dev) as\na quick way for mise to query for new versions. This host regularly grabs all the\nlatest versions of core and community plugins. It's faster than running a plugin's\n`list-all` command and gets around GitHub rate limiting problems when using it.\n\nmise-versions itself also struggles with rate limits but you can help it to fetch more frequently by authenticating\nwith its [GitHub app](https://github.com/apps/mise-versions). It does not require any permissions since it simply\nfetches public repository information.\n\nSee [Troubleshooting](/troubleshooting.html#new-version-of-a-tool-is-not-available) for more information.\n\"\"\"\nenv = \"MISE_USE_VERSIONS_HOST\"\ntype = \"Bool\"\n\n[use_versions_host_track]\ndefault = true\ndescription = \"Send anonymous download statistics when installing tools.\"\ndocs = \"\"\"\nWhen enabled, mise sends anonymous download statistics to mise-versions.jdx.dev after\nsuccessfully installing a tool. This helps show tool popularity on [mise-versions.jdx.dev](https://mise-versions.jdx.dev).\n\nData collected:\n- Tool name and version\n- OS and architecture (from User-Agent)\n- Hashed IP address (for daily deduplication, not stored raw)\n\nThis is automatically disabled if `use_versions_host` is set to false.\nSet to false to opt-out of anonymous statistics collection.\n\"\"\"\nenv = \"MISE_USE_VERSIONS_HOST_TRACK\"\ntype = \"Bool\"\n\n[verbose]\ndescription = \"Shows more verbose output such as installation logs when installing tools.\"\nenv = \"MISE_VERBOSE\"\ntype = \"Bool\"\n\n[vfox]\ndeprecated = \"Use disable_backends instead.\"\ndescription = \"Use vfox as a default plugin backend instead of asdf.\"\ndocs = \"\"\"\nUse vfox as a default plugin backend. This means running something like `mise use cmake` will\ndefault to using a vfox plugin for cmake.\n\"\"\"\nenv = \"MISE_VFOX\"\nhide = true\noptional = true\ntype = \"Bool\"\n\n[windows_default_file_shell_args]\ndefault = \"cmd /c\"\ndescription = \"Default shell arguments for Windows to be used for file commands. For example, `cmd /c` for cmd.exe.\"\nenv = \"MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS\"\ntype = \"String\"\n\n[windows_default_inline_shell_args]\ndefault = \"cmd /c\"\ndescription = \"Default shell arguments for Windows to be used for inline commands. For example, `cmd /c` for cmd.exe.\"\nenv = \"MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS\"\ntype = \"String\"\n\n[windows_executable_extensions]\ndefault = [\"exe\", \"bat\", \"cmd\", \"com\", \"ps1\", \"vbs\"]\ndescription = \"List of executable extensions for Windows. For example, `exe` for .exe files, `bat` for .bat files, and so on.\"\nenv = \"MISE_WINDOWS_EXECUTABLE_EXTENSIONS\"\nparse_env = \"list_by_comma\"\nrust_type = \"Vec<String>\"\ntype = \"ListString\"\n\n[windows_shim_mode]\ndefault = \"exe\"\ndescription = \"Shim file mode for Windows. Options: `exe`, `file`, `hardlink`, `symlink`.\"\ndocs = \"\"\"\n* values:\n  * `exe`: Copies a native executable shim (`mise-shim.exe`) as `<tool>.exe`. Recommended. Works with all shells, package managers, and `where.exe`. Requires `mise-shim.exe` alongside `mise.exe`.\n  * `file`: Creates a `.cmd` batch file shim and an extensionless bash script for Git Bash/Cygwin.\n  * `hardlink`: Uses Windows NTFS Hardlink, required on same filesystems. Need run `mise reshim --force` after upgrade mise.\n  * `symlink`: Uses Windows NTFS SymbolicLink. Requires Windows Vista or later with admin privileges or enabling \"Developer Mode\" in Windows 10/11.\n\"\"\"\nenv = \"MISE_WINDOWS_SHIM_MODE\"\ntype = \"String\"\n\n[yes]\ndescription = \"This will automatically answer yes or no to prompts. This is useful for scripting.\"\nenv = \"MISE_YES\"\ntype = \"Bool\"\n\n[zig.use_community_mirrors]\ndefault = true\ndescription = \"Download Zig from community-maintained mirrors\"\ndocs = \"\"\"\nThis setting allows mise to fetch Zig from one of many community-maintained mirrors.\n\nThe ziglang.org website does not offer any uptime or speed guarantees, and it\nrecommends to use the mirrors. The mirror list is cached and allows the installs\nto succeed even if the main server is unavailable.\n\nThe downloaded tarballs are always verified against Zig Software Foundation's public\nkey, so there is no risk of third-party modifications. Read more on [ziglang.org](https://ziglang.org/download/community-mirrors/).\n\nIf you don't have the mirror list cached locally, you can place the newline-separated\nserver list inside `mise cache path`, folder `zig` as `community-mirrors.txt`.\n\"\"\"\nenv = \"MISE_ZIG_USE_COMMUNITY_MIRRORS\"\ntype = \"Bool\"\n"
  },
  {
    "path": "share/fish/vendor_conf.d/mise-activate.fish",
    "content": "if [ \"$MISE_FISH_AUTO_ACTIVATE\" != \"0\" ]\n  mise activate fish | source\nend\n"
  },
  {
    "path": "snapcraft.yaml",
    "content": "# To test this snap package on your local Linux machine,\n# Install snapcraft (`snap install snapcraft --classic`) and\n# run the following commands:\n#\n# ```shell\n# snapcraft pack\n# snap install ./mise_20xx.xx.x_amd64.snap --dangerous --classic\n# ```\n\nname: mise\ntitle: mise-en-place\nversion: \"2026.3.9\"\nsummary: The front-end to your dev env\ndescription: |\n  mise-en-place is a command line tool to manage your development environment.\n\n  - Like asdf (or nvm or pyenv but for any language) it manages [dev tools](https://mise.jdx.dev/dev-tools/) like node, python, cmake, terraform, and [hundreds more](https://mise.jdx.dev/registry.html).\n  - Like direnv it manages [environment variables](https://mise.jdx.dev/environments/) for different project directories.\n  - Like make it manages [tasks](https://mise.jdx.dev/tasks/) used to build and test projects.\n\n  See the [documentation](https://mise.jdx.dev/getting-started.html) to learn more.\n\nlicense: MIT\nwebsite: https://mise.jdx.dev\nsource-code: https://github.com/jdx/mise.git\nissues: https://github.com/jdx/mise/discussions\ncontact:\n  - https://github.com/jdx/mise/discussions\n  - https://phanective.org\ndonation:\n  - https://github.com/sponsors/jdx\n\ngrade: devel\nconfinement: classic\n\nplatforms:\n  amd64:\n  arm64:\n  armhf:\n\nbase: core24\n\nparts:\n  mise:\n    source: \".\"\n    source-type: local\n\n    plugin: rust\n    rust-channel: stable\n\n    build-packages:\n      - libssl-dev\n    build-attributes:\n      - enable-patchelf\n\n  update-instructions:\n    plugin: dump\n    source: ./packaging/snapcraft\n    source-type: local\n    organize:\n      \"mise-self-update-instructions.toml\": lib/\n    stage:\n      - lib/\n\napps:\n  mise:\n    command: bin/mise\n"
  },
  {
    "path": "src/agecrypt.rs",
    "content": "use std::io::{BufReader, Read, Write};\nuse std::path::{Path, PathBuf};\n\nuse age::ssh;\nuse age::{Decryptor, Encryptor, Identity, IdentityFile, Recipient};\nuse base64::Engine;\nuse eyre::{Result, WrapErr, eyre};\nuse indexmap::IndexSet;\n\nuse crate::config::Settings;\nuse crate::config::env_directive::{AgeFormat, EnvDirective, EnvDirectiveOptions};\nuse crate::file::{self, replace_path};\nuse crate::{dirs, env};\n\nconst ZSTD_COMPRESSION_LEVEL: i32 = 3;\nconst COMPRESSION_THRESHOLD: usize = 1024; // 1KB\n\npub async fn create_age_directive(\n    key: String,\n    value: &str,\n    recipients: &[Box<dyn Recipient + Send>],\n) -> Result<EnvDirective> {\n    if recipients.is_empty() {\n        return Err(eyre!(\n            \"[experimental] No age recipients provided for encryption\"\n        ));\n    }\n\n    let encryptor =\n        match Encryptor::with_recipients(recipients.iter().map(|r| r.as_ref() as &dyn Recipient)) {\n            Ok(encryptor) => encryptor,\n            Err(e) => return Err(eyre!(\"[experimental] Failed to create encryptor: {}\", e)),\n        };\n\n    let mut encrypted = Vec::new();\n    let mut writer = encryptor.wrap_output(&mut encrypted)?;\n    writer.write_all(value.as_bytes())?;\n    writer.finish()?;\n\n    // Determine format based on size and compression\n    let (encoded, format) = if encrypted.len() > COMPRESSION_THRESHOLD {\n        let compressed = zstd::encode_all(&encrypted[..], ZSTD_COMPRESSION_LEVEL)?;\n        let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(&compressed);\n        (encoded, Some(AgeFormat::Zstd))\n    } else {\n        let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(&encrypted);\n        (encoded, None) // Use None for raw format (default)\n    };\n\n    Ok(EnvDirective::Age {\n        key,\n        value: encoded,\n        format,\n        options: EnvDirectiveOptions::default(),\n    })\n}\n\npub async fn decrypt_age_directive(directive: &EnvDirective) -> Result<String> {\n    Settings::get().ensure_experimental(\"age encryption\")?;\n    match directive {\n        EnvDirective::Age { value, format, .. } => {\n            let decoded = base64::engine::general_purpose::STANDARD_NO_PAD\n                .decode(value)\n                .wrap_err(\"[experimental] Failed to decode base64\")?;\n\n            let ciphertext = match format {\n                Some(AgeFormat::Zstd) => zstd::decode_all(&decoded[..])\n                    .wrap_err(\"[experimental] Failed to decompress zstd\")?,\n                Some(AgeFormat::Raw) | None => decoded,\n            };\n\n            let identities = load_all_identities().await?;\n            if identities.is_empty() {\n                return Err(eyre!(\n                    \"[experimental] No age identities found for decryption\"\n                ));\n            }\n\n            let decryptor = Decryptor::new(&ciphertext[..])?;\n            let mut decrypted = Vec::new();\n\n            let identity_refs: Vec<&dyn Identity> = identities\n                .iter()\n                .map(|i| i.as_ref() as &dyn Identity)\n                .collect();\n\n            match decryptor.decrypt(identity_refs.into_iter()) {\n                Ok(mut reader) => {\n                    reader.read_to_end(&mut decrypted)?;\n                }\n                Err(e) => {\n                    return Err(eyre!(\"[experimental] Failed to decrypt: {}\", e));\n                }\n            }\n\n            String::from_utf8(decrypted)\n                .wrap_err(\"[experimental] Decrypted value is not valid UTF-8\")\n        }\n        _ => Err(eyre!(\"[experimental] Not an Age directive\")),\n    }\n}\n\npub async fn load_recipients_from_defaults() -> Result<Vec<Box<dyn Recipient + Send>>> {\n    let mut recipients: IndexSet<String> = IndexSet::new();\n\n    // Try to load from age key file\n    if let Some(key_file) = get_default_key_file().await\n        && key_file.exists()\n    {\n        let content = file::read_to_string(&key_file)?;\n        // For age keys, we need to parse them as x25519 identities to get public keys\n        for line in content.lines() {\n            let line = line.trim();\n            if line.starts_with(\"AGE-SECRET-KEY-\")\n                && let Ok(identity) = line.parse::<age::x25519::Identity>()\n            {\n                recipients.insert(identity.to_public().to_string());\n            }\n        }\n    }\n\n    // Try to load from SSH private keys\n    let ssh_key_paths = get_default_ssh_key_paths();\n    for path in ssh_key_paths {\n        if path.exists()\n            && let Ok(recipient) = load_ssh_recipient_from_private_key(&path).await\n        {\n            recipients.insert(recipient);\n        }\n    }\n\n    let mut parsed_recipients: Vec<Box<dyn Recipient + Send>> = Vec::new();\n    for recipient_str in recipients {\n        if let Some(recipient) = parse_recipient(&recipient_str)? {\n            parsed_recipients.push(recipient);\n        }\n    }\n\n    if parsed_recipients.is_empty() {\n        return Err(eyre!(\n            \"[experimental] No age recipients found. Provide --age-recipient, --age-ssh-recipient, or configure settings.age.key_file\"\n        ));\n    }\n\n    Ok(parsed_recipients)\n}\n\npub async fn load_recipients_from_key_file(path: &Path) -> Result<Vec<Box<dyn Recipient + Send>>> {\n    let mut recipients: Vec<Box<dyn Recipient + Send>> = Vec::new();\n\n    if !path.exists() {\n        return Err(eyre!(\n            \"[experimental] Age key file not found: {}\",\n            path.display()\n        ));\n    }\n\n    let content = file::read_to_string(path)?;\n\n    // Parse age x25519 identities and convert to recipients\n    for line in content.lines() {\n        let line = line.trim();\n        if line.starts_with(\"AGE-SECRET-KEY-\")\n            && let Ok(identity) = line.parse::<age::x25519::Identity>()\n        {\n            let public_key = identity.to_public();\n            recipients.push(Box::new(public_key));\n        }\n    }\n\n    if recipients.is_empty() {\n        return Err(eyre!(\n            \"[experimental] No valid age identities found in {}\",\n            path.display()\n        ));\n    }\n\n    Ok(recipients)\n}\n\npub fn parse_recipient(recipient_str: &str) -> Result<Option<Box<dyn Recipient + Send>>> {\n    let trimmed = recipient_str.trim();\n\n    if trimmed.starts_with(\"age1\") {\n        match trimmed.parse::<age::x25519::Recipient>() {\n            Ok(r) => Ok(Some(Box::new(r))),\n            Err(e) => Err(eyre!(\"[experimental] Invalid age recipient: {}\", e)),\n        }\n    } else if trimmed.starts_with(\"ssh-\") {\n        // SSH recipient parsing - the age crate will validate it\n        match trimmed.parse::<ssh::Recipient>() {\n            Ok(r) => Ok(Some(Box::new(r))),\n            Err(e) => Err(eyre!(\"[experimental] Invalid SSH recipient: {:?}\", e)),\n        }\n    } else {\n        Ok(None)\n    }\n}\n\npub async fn load_ssh_recipient_from_path(path: &Path) -> Result<Box<dyn Recipient + Send>> {\n    let content = file::read_to_string(path)?;\n    let trimmed = content.trim();\n\n    // Check if it's a public key\n    if trimmed.starts_with(\"ssh-\") {\n        match trimmed.parse::<ssh::Recipient>() {\n            Ok(r) => return Ok(Box::new(r)),\n            Err(e) => {\n                return Err(eyre!(\n                    \"[experimental] Invalid SSH public key at {}: {:?}\",\n                    path.display(),\n                    e\n                ));\n            }\n        }\n    }\n\n    // Try to load as private key and derive public\n    if path.extension().and_then(|s| s.to_str()) == Some(\"pub\") {\n        Err(eyre!(\n            \"[experimental] Invalid SSH public key at {}\",\n            path.display()\n        ))\n    } else {\n        load_ssh_recipient_from_private_key(path)\n            .await\n            .and_then(|s| {\n                parse_recipient(&s)?\n                    .ok_or_else(|| eyre!(\"[experimental] Failed to parse SSH recipient\"))\n            })\n    }\n}\n\nasync fn load_ssh_recipient_from_private_key(path: &Path) -> Result<String> {\n    // For SSH keys, we can't easily derive the public key from the private key using the age crate\n    // So we'll try to read the corresponding .pub file\n    let pub_path = path.with_extension(\"pub\");\n    if pub_path.exists() {\n        let content = file::read_to_string(&pub_path)?;\n        let trimmed = content.trim();\n        if trimmed.starts_with(\"ssh-\") {\n            return Ok(trimmed.to_string());\n        }\n    }\n\n    Err(eyre!(\n        \"[experimental] Could not find public key for SSH private key at {}. Expected {}.pub\",\n        path.display(),\n        path.display()\n    ))\n}\n\nasync fn load_all_identities() -> Result<Vec<Box<dyn Identity>>> {\n    // Get identity files first\n    let identity_files = get_all_identity_files().await;\n    let ssh_identity_files = get_all_ssh_identity_files();\n\n    // Now process identities without holding them across await points\n    let mut identities: Vec<Box<dyn Identity>> = Vec::new();\n\n    // Check MISE_AGE_KEY environment variable\n    if let Ok(age_key) = env::var(\"MISE_AGE_KEY\")\n        && !age_key.is_empty()\n    {\n        // First try to parse as a raw age secret key\n        for line in age_key.lines() {\n            let line = line.trim();\n            if line.starts_with(\"AGE-SECRET-KEY-\")\n                && let Ok(identity) = line.parse::<age::x25519::Identity>()\n            {\n                identities.push(Box::new(identity));\n            }\n        }\n\n        // If no keys were found, try parsing as an identity file\n        if identities.is_empty()\n            && let Ok(identity_file) = IdentityFile::from_buffer(age_key.as_bytes())\n            && let Ok(mut file_identities) = identity_file.into_identities()\n        {\n            identities.append(&mut file_identities);\n        }\n    }\n\n    // Load from identity files\n    for path in identity_files {\n        if path.exists() {\n            match file::read_to_string(&path) {\n                Ok(content) => {\n                    if let Ok(identity_file) = IdentityFile::from_buffer(content.as_bytes())\n                        && let Ok(mut file_identities) = identity_file.into_identities()\n                    {\n                        identities.append(&mut file_identities);\n                    }\n                }\n                Err(e) => {\n                    debug!(\n                        \"[experimental] Failed to read identity file {:?}: {}\",\n                        path, e\n                    );\n                }\n            }\n        }\n    }\n\n    // Load SSH identities\n    for path in ssh_identity_files {\n        if path.exists() {\n            match std::fs::File::open(&path) {\n                Ok(file) => {\n                    let mut reader = BufReader::new(file);\n                    match ssh::Identity::from_buffer(&mut reader, Some(path.display().to_string()))\n                    {\n                        Ok(identity) => {\n                            identities.push(Box::new(identity));\n                        }\n                        Err(e) => {\n                            debug!(\n                                \"[experimental] Failed to parse SSH identity from {:?}: {}\",\n                                path, e\n                            );\n                        }\n                    }\n                }\n                Err(e) => {\n                    debug!(\n                        \"[experimental] Failed to read SSH identity file {:?}: {}\",\n                        path, e\n                    );\n                }\n            }\n        }\n    }\n\n    Ok(identities)\n}\n\nasync fn get_default_key_file() -> Option<PathBuf> {\n    Settings::get()\n        .age\n        .key_file\n        .clone()\n        .map(replace_path)\n        .or_else(|| {\n            let default_path = dirs::CONFIG.join(\"age.txt\");\n            if default_path.exists() {\n                Some(default_path)\n            } else {\n                None\n            }\n        })\n}\n\nasync fn get_all_identity_files() -> Vec<PathBuf> {\n    let mut files = Vec::new();\n\n    if let Some(ref identity_files) = Settings::get().age.identity_files {\n        for path in identity_files {\n            // Apply path expansion for tilde and environment variables\n            files.push(replace_path(path.clone()));\n        }\n    }\n\n    if let Some(key_file) = Settings::get().age.key_file.clone() {\n        files.push(replace_path(key_file));\n    }\n\n    let default_age_txt = dirs::CONFIG.join(\"age.txt\");\n    if default_age_txt.exists() && !files.contains(&default_age_txt) {\n        files.push(default_age_txt);\n    }\n\n    files\n}\n\nfn get_all_ssh_identity_files() -> Vec<PathBuf> {\n    let mut files = Vec::new();\n\n    if let Some(ref ssh_identity_files) = Settings::get().age.ssh_identity_files {\n        for path in ssh_identity_files {\n            // Apply path expansion for tilde and environment variables\n            files.push(replace_path(path.clone()));\n        }\n    }\n\n    files.extend(get_default_ssh_key_paths());\n    files\n}\n\nfn get_default_ssh_key_paths() -> Vec<PathBuf> {\n    let mut paths = Vec::new();\n    let home = &*dirs::HOME;\n    let ssh_dir = home.join(\".ssh\");\n    paths.push(ssh_dir.join(\"id_ed25519\"));\n    paths.push(ssh_dir.join(\"id_rsa\"));\n    paths\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[tokio::test]\n    async fn test_age_x25519_round_trip_small() -> Result<()> {\n        let key = age::x25519::Identity::generate();\n        let recipient = key.to_public();\n\n        // Small value should not be compressed\n        let plaintext = \"secret value\";\n        let recipients: Vec<Box<dyn Recipient + Send>> = vec![Box::new(recipient)];\n        let directive =\n            create_age_directive(\"TEST_VAR\".to_string(), plaintext, &recipients).await?;\n\n        if let crate::config::env_directive::EnvDirective::Age { value, format, .. } = directive {\n            // Small value should not be compressed (format should be None/Raw)\n            assert!(\n                format.is_none()\n                    || matches!(format, Some(crate::config::env_directive::AgeFormat::Raw))\n            );\n\n            use age::secrecy::ExposeSecret;\n            env::set_var(\"MISE_AGE_KEY\", key.to_string().expose_secret());\n            let decrypted =\n                decrypt_age_directive(&crate::config::env_directive::EnvDirective::Age {\n                    key: \"TEST_VAR\".to_string(),\n                    value,\n                    format,\n                    options: Default::default(),\n                })\n                .await?;\n            env::remove_var(\"MISE_AGE_KEY\");\n\n            assert_eq!(decrypted, plaintext);\n        } else {\n            panic!(\"Expected Age directive\");\n        }\n        Ok(())\n    }\n\n    #[tokio::test]\n    async fn test_age_x25519_round_trip_large() -> Result<()> {\n        let key = age::x25519::Identity::generate();\n        let recipient = key.to_public();\n\n        // Large value should be compressed (>1KB)\n        let plaintext = \"x\".repeat(2000);\n        let recipients: Vec<Box<dyn Recipient + Send>> = vec![Box::new(recipient)];\n        let directive =\n            create_age_directive(\"TEST_VAR\".to_string(), &plaintext, &recipients).await?;\n\n        if let crate::config::env_directive::EnvDirective::Age { value, format, .. } = directive {\n            // Large value should be compressed\n            assert_eq!(format, Some(crate::config::env_directive::AgeFormat::Zstd));\n\n            use age::secrecy::ExposeSecret;\n            env::set_var(\"MISE_AGE_KEY\", key.to_string().expose_secret());\n            let decrypted =\n                decrypt_age_directive(&crate::config::env_directive::EnvDirective::Age {\n                    key: \"TEST_VAR\".to_string(),\n                    value,\n                    format,\n                    options: Default::default(),\n                })\n                .await?;\n            env::remove_var(\"MISE_AGE_KEY\");\n\n            assert_eq!(decrypted, plaintext);\n        } else {\n            panic!(\"Expected Age directive\");\n        }\n        Ok(())\n    }\n\n    #[test]\n    fn test_parse_recipient() -> Result<()> {\n        let age_recipient = \"age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p\";\n        let parsed = parse_recipient(age_recipient)?;\n        assert!(parsed.is_some());\n\n        // Note: The SSH recipient parser in the age crate is strict about format\n        // This is a valid format example\n        let ssh_recipient =\n            \"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmkfJ8VZq4m5k7tJVts7+nR01fbRvLHLgeQCF6FWYr5\";\n        let parsed = parse_recipient(ssh_recipient)?;\n        assert!(parsed.is_some());\n\n        let invalid = \"invalid_recipient\";\n        let parsed = parse_recipient(invalid)?;\n        assert!(parsed.is_none());\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/aqua/aqua_registry_wrapper.rs",
    "content": "use crate::backend::aqua::{arch, os};\nuse crate::config::Settings;\nuse crate::git::{CloneOptions, Git};\nuse crate::{dirs, duration::WEEKLY, file};\nuse aqua_registry::{AquaRegistry, AquaRegistryConfig};\nuse eyre::Result;\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::sync::LazyLock as Lazy;\nuse tokio::sync::Mutex;\n\nstatic AQUA_REGISTRY_PATH: Lazy<PathBuf> = Lazy::new(|| dirs::CACHE.join(\"aqua-registry\"));\nstatic AQUA_DEFAULT_REGISTRY_URL: &str = \"https://github.com/aquaproj/aqua-registry\";\n\npub static AQUA_REGISTRY: Lazy<MiseAquaRegistry> = Lazy::new(|| {\n    MiseAquaRegistry::standard().unwrap_or_else(|err| {\n        warn!(\"failed to initialize aqua registry: {err:?}\");\n        MiseAquaRegistry::default()\n    })\n});\n\n/// Wrapper around the aqua-registry crate that provides mise-specific functionality\n#[derive(Debug)]\npub struct MiseAquaRegistry {\n    inner: AquaRegistry,\n    #[allow(dead_code)]\n    path: PathBuf,\n    #[allow(dead_code)]\n    repo_exists: bool,\n}\n\nimpl Default for MiseAquaRegistry {\n    fn default() -> Self {\n        let config = AquaRegistryConfig::default();\n        let inner = AquaRegistry::new(config.clone());\n        Self {\n            inner,\n            path: config.cache_dir,\n            repo_exists: false,\n        }\n    }\n}\n\nimpl MiseAquaRegistry {\n    pub fn standard() -> Result<Self> {\n        let path = AQUA_REGISTRY_PATH.clone();\n        let repo = Git::new(&path);\n        let settings = Settings::get();\n        let registry_url =\n            settings\n                .aqua\n                .registry_url\n                .as_deref()\n                .or(if settings.aqua.baked_registry {\n                    None\n                } else {\n                    Some(AQUA_DEFAULT_REGISTRY_URL)\n                });\n\n        if let Some(registry_url) = registry_url {\n            if repo.exists() {\n                fetch_latest_repo(&repo)?;\n            } else {\n                info!(\"cloning aqua registry from {registry_url} to {path:?}\");\n                repo.clone(registry_url, CloneOptions::default())?;\n            }\n        }\n\n        let config = AquaRegistryConfig {\n            cache_dir: path.clone(),\n            registry_url: registry_url.map(|s| s.to_string()),\n            use_baked_registry: settings.aqua.baked_registry,\n            prefer_offline: settings.prefer_offline(),\n        };\n\n        let inner = AquaRegistry::new(config);\n\n        Ok(Self {\n            inner,\n            path,\n            repo_exists: repo.exists(),\n        })\n    }\n\n    pub async fn package(&self, id: &str) -> Result<AquaPackage> {\n        static CACHE: Lazy<Mutex<HashMap<String, AquaPackage>>> =\n            Lazy::new(|| Mutex::new(HashMap::new()));\n\n        if let Some(pkg) = CACHE.lock().await.get(id) {\n            return Ok(pkg.clone());\n        }\n\n        let pkg = self.inner.package(id).await?;\n        CACHE.lock().await.insert(id.to_string(), pkg.clone());\n        Ok(pkg)\n    }\n\n    pub async fn package_with_version(&self, id: &str, versions: &[&str]) -> Result<AquaPackage> {\n        let pkg = self.package(id).await?;\n        Ok(pkg.with_version(versions, os(), arch()))\n    }\n}\n\nfn fetch_latest_repo(repo: &Git) -> Result<()> {\n    if file::modified_duration(&repo.dir)? < WEEKLY {\n        return Ok(());\n    }\n\n    if Settings::get().prefer_offline() {\n        trace!(\"skipping aqua registry update due to prefer-offline mode\");\n        return Ok(());\n    }\n\n    info!(\"updating aqua registry repo\");\n    repo.update(None)?;\n    Ok(())\n}\n\nstruct AquaSuggestionsCache {\n    name_to_ids: HashMap<&'static str, Vec<&'static str>>,\n    names: Vec<&'static str>,\n}\n\nstatic AQUA_SUGGESTIONS_CACHE: Lazy<AquaSuggestionsCache> = Lazy::new(|| {\n    let ids = aqua_registry::package_ids();\n    let mut name_to_ids: HashMap<&'static str, Vec<&'static str>> = HashMap::new();\n    for id in ids {\n        if let Some((_, name)) = id.rsplit_once('/') {\n            name_to_ids.entry(name).or_default().push(id);\n        }\n    }\n    let names = name_to_ids.keys().copied().collect();\n    AquaSuggestionsCache { name_to_ids, names }\n});\n\n/// Search aqua packages by tool name, returning \"owner/name\" IDs\n/// where the name part is similar to the query.\npub fn aqua_suggest(query: &str) -> Vec<String> {\n    let cache = &*AQUA_SUGGESTIONS_CACHE;\n\n    // Use a higher threshold (0.8) to avoid noisy suggestions\n    let similar_names = xx::suggest::similar_n_with_threshold(query, &cache.names, 5, 0.8);\n\n    // Map back to full IDs\n    let mut results = Vec::new();\n    for matched_name in &similar_names {\n        if let Some(full_ids) = cache.name_to_ids.get(matched_name.as_str()) {\n            for full_id in full_ids {\n                results.push(full_id.to_string());\n                if results.len() >= 5 {\n                    return results;\n                }\n            }\n        }\n    }\n    results\n}\n\n// Re-export types and static for compatibility\npub use aqua_registry::{\n    AquaChecksum, AquaChecksumType, AquaMinisignType, AquaPackage, AquaPackageType,\n};\n"
  },
  {
    "path": "src/aqua/mod.rs",
    "content": "pub(crate) mod aqua_registry_wrapper;\n"
  },
  {
    "path": "src/assets/bash_zsh_support/LICENSE",
    "content": "GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "src/assets/bash_zsh_support/README.md",
    "content": "# bash_zsh_support\n\nsupport Zsh function hooks for Bash\n"
  },
  {
    "path": "src/assets/bash_zsh_support/chpwd/README.md",
    "content": "# Bash support for Zsh like chpwd hook\n\nImplemented based on the description from\n<http://zsh.sourceforge.net/Doc/Release/Functions.html#Hook-Functions>\n\n## Usage\n\n1. load `function.sh` and `load.sh`, eg:\n\n        source chpwd/functions.sh\n        source chpwd/load.sh\n\n2. add the hook - replace `_hook_name` with your function name:\n\n        export -a chpwd_functions                              # define hooks as an shell array\n        [[ \" ${chpwd_functions[*]} \" == *\" _hook_name \"* ]] || # prevent double addition\n        chpwd_functions+=(_hook_name)                          # finally add it to the list\n"
  },
  {
    "path": "src/assets/bash_zsh_support/chpwd/function.sh",
    "content": "# shellcheck shell=bash\nexport -a chpwd_functions\nfunction __zsh_like_cd()\n{\n  \\typeset __zsh_like_cd_hook\n  if\n    builtin \"$@\"\n  then\n    for __zsh_like_cd_hook in chpwd \"${chpwd_functions[@]}\"\n    do\n      if \\typeset -f \"$__zsh_like_cd_hook\" >/dev/null 2>&1\n      then \"$__zsh_like_cd_hook\" || break # finish on first failed hook\n      fi\n    done\n    true\n  else\n    return $?\n  fi\n}\n"
  },
  {
    "path": "src/assets/bash_zsh_support/chpwd/load.sh",
    "content": "# shellcheck shell=bash\n[[ -n \"${ZSH_VERSION:-}\" ]] ||\n{\n  function cd()    { __zsh_like_cd cd    \"$@\" ; }\n  function popd()  { __zsh_like_cd popd  \"$@\" ; }\n  function pushd() { __zsh_like_cd pushd \"$@\" ; }\n}\n"
  },
  {
    "path": "src/assets/gpg/node.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFq44CwBCADNRnp3EGOqifmbqOgRb64hkObYdNAClPy/aQfxyWvrZBuVw8OF\nDhtziM8M8g986wALaE/nCMufVLrWLVFr4hDHrKr9weaX8vdrPVgvbk/wLfokumnT\nied2EXUYv4i1+PFPLnBEfb/FhG/x11mSStIra74JIw7C3uLbBdZfU5SBI9SRjFEg\nIMHnnTVrXsoZCf+MBUU5nN+tEuOk5s2bnb8rZOsDfdkMLblLbk7j9OvU4OfJ9cLa\ntNk0wsvrXmOkxAkr0NNwaotb6xqQwXML1obiBkLl3cZ8c9PnvxWnEau8jItvO/+n\nVOgSIvCQd/obAZzAYWPKrYwLp5iEwejB66XLABEBAAG0IEJldGggR3JpZ2dzIDxi\nZ3JpZ2dzQHJlZGhhdC5jb20+iQFXBBMBCABBAhsDBQsJCAcCBhUKCQgLAgQWAgMB\nAh4BAheAAhkBFiEETtd49TnjY0x3nIfG1wYoSKGrAFwFAmBePXEFCQln0lUACgkQ\n1wYoSKGrAFyFMwf/dwvX7pOhVOhaXUwc0jhzslRnoVCNPcdHJvTXRWl/sdMEcgZN\nI074o7hWBhEy1q9hveBA0d+xNUW7akcHSgzj3hU3PqKqtX6X8x3Z/vymlBCX3Bmn\nEwydEvMK1GVLct3StgLQDw4iq9vueIHUV43H3U5Qpr1RuO4qrQiFZAD12RL+aAT/\nGno6pDqOOb1GrxZJQ859hsWXh1cnoI1r6AS/ztnkPAofXISe4XxABNh2dLZXEBSo\nyXMvc7LSLsJoT8sGdRtjMirDRuUN6D1lnOqe1kcE0efv22igBRpVlOF9rgAi90Go\nb5qSfnTysC/306lmAWlj0Rgl2OBEEl/1fzRV1okBVwQTAQgAQQIbAwUJBaPvfgUL\nCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBE7XePU542NMd5yHxtcGKEihqwBcBQJf\ndgz6AhkBAAoJENcGKEihqwBcl28H/RS5pGfdPEsR0UeB9F2t7W08m6e8f3nBdmmx\ntEC6qowZkv+LpSxApBpb9E2iig7uv+5yenkwqdCZRoFhtmYdhHGAoez0bLMLsUSA\nlLdmaj7U41QntdB27fRhB3VXdbvXmMugi7nKw9gOLjepdetWGA52S9uHvc3PlZmI\nsY0FUR7JKIDCbkMHQUMnKj0+zj8giuaYGapzBUI0ZWUbxyem/l5xZ+U6ufbpU7Sk\nXWjFd097OXoQzw7OiEdVRBZEZj1QIW4vXQlWBZDwKXAB+Oobz7/muJIVPDN6w1ik\nZf62zHWzTpLz+VDMDKtDNtnGqNV5/089+oonG/x6dfzhdIIs9uGJAVQEEwEIAD4W\nIQRO13j1OeNjTHech8bXBihIoasAXAUCX3YM4AIbAwUJBaPvfgULCQgHAgYVCgkI\nCwIEFgIDAQIeAQIXgAAKCRDXBihIoasAXIZJB/9QBWKhLUV8El+bE7XplkwgnLWv\n4eTvR5dGDLNo5sYXQxS5y6NG0/mSC8biez6tUFfnqY1lp8uKz1E8BZlcbRUBe1bx\nCTDCr7psIig9IqKOYbMNpAcrnVG2wv+TZz9Sb9PJxgT2Pqwek9KiMPTJk6V3fWau\nGKRsl11ur5tpx0SiJwk21iv1YVHL6Vz6/E4/3XMEq5QpdjLroCBqFBKbKgDHQUYa\n6G/h8YU+WkdncVi331WX2ukX88Z47b5nagXN5FHEHMA44qWyqKJbts5LHsI+hbUK\n4zT+yNxSd0jmEuGi8kYvzz7IXGBcED7CCY2ZG5wlCVa1O3L9FqHK0EJFkOjItCdC\nZXRoIEdyaWdncyA8QmV0aGFueS5HcmlnZ3NAdWsuaWJtLmNvbT6JAVQEEwEIAD4C\nGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQRO13j1OeNjTHech8bXBihIoasA\nXAUCYF49cQUJCWfSVQAKCRDXBihIoasAXGIyB/9TCYA8fJYElS0S5OvYjA38l+3k\n2D22ckRrRTO1UvWMSltBA4PWNtKZ9j2/uQVDFWzgxio9n8tJs0b+9U7mKKKovubo\nlYD4tMzsBaEKESd+tOgwraAPqkwT6jQt49R/NspoQaZ1ubIYvYK00mPerGHX4wIQ\nw/9u9douLqTw6Q38J34sxJA2pJ3Rz4OAvPef3MsBd+5PE1OHXgSi9/+MvPzDBGw5\no+N6qm/AyW06v6c0RrhKX4i8POcycLkMdcLgZXLhQacj40a+PP5AeVogjjwMFzkc\nbGJUcMuqJHkf5d8G0SdrVwEOcEfDQmAGpvWtS5JqwZfU9x+J/UdBB70rQ+WeiQFU\nBBMBCAA+FiEETtd49TnjY0x3nIfG1wYoSKGrAFwFAlq44CwCGwMFCQPCZwAFCwkI\nBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ1wYoSKGrAFz3hgf/RfSAI0EfcPPo7t+3\nLvJ6EENvOY/+UJAF5kTLExKdmwT/nx9got9vi8QJ+rHX6RxzGa0tLlzTUOegDZft\nVGQ/aanpOpStIc6TxSPkKqNZrt/ICceDhTl0101dafaIAChY5TIz8KDUsEOmWOO7\nbO6Nk+/IlttM7X6BDC0vHOH09bsn7APQ19fUL0PLIOvjiTkI+knecSnXagVn7Qyg\ne5FLgpSbHgz/MLlt9hSX0Zz9nClI4S313bLsKufvyh1QzK9VnQZFnAp70r3Rw00t\n5LsHdh8Me8h/VqpDQYWyOGlTDREustxvOlN+cRnlsZsCOX8m1gwTTVAPtgYz7GZd\n1p65uokBVAQTAQgAPgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAUJBaPvfhYh\nBE7XePU542NMd5yHxtcGKEihqwBcBQJfdgz6AAoJENcGKEihqwBcRxIIAKTG7199\nXR/SHE4zY+FNu9AZZnModHa+1sVdpq1u11cQgjV33xeU4kK0hqQyUv+CcPfPGpFk\nODmIWTsz90PhO6x568Va3SXYtJrXJW6DXIADpxobgYEvxMraxReViuUuMnl+Dl4L\np6qdXQBGLAvyBuZ8Ebq79Os8pMMXccF/KQh1tpNlJzeP6xqWkvLGwFQR05nTtIlp\nOdAc13wlfgojWrDI18lIRYObZ8NBdnfCFf2JcaPXmkEzskNbGG86VJr0YNXo7P0H\n1+8CqxOhucOE/Fkc2pbbUqXcympkaC2OqB/vvrvOqSKOwQOFaCv7cZZ5YV5z20uq\nJavJh6hEwAgZCVCJAVcEEwEIAEECGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AF\nCQWj734WIQRO13j1OeNjTHech8bXBihIoasAXAUCX3YM4AIZAQAKCRDXBihIoasA\nXCr6CADMzDvi2isS7AiwvbDz/y/wtiy0HbOeT/BH1g/ZpArmx2ML1lgxBlD5+uro\nNAYLgWhub3ofV5uOadma65y5uHDzKpdsold1K7zJNlewCjVyEYg6v7wikSY7E16O\nyQRlDN+pSdoNU7N2aAmCOTLul1jRBhMflyjZWjT8NiWCN9ie9THfFtRNT6sPinx8\nb6k9z8arby9rdOHJysMyGBcjCsL6/TTUqwC/ZSBz9yM3nFt7LvWHNS14bNCwoPx1\npOYa3cCRfmnd4LtbXvQ60y81f6MgNepIHi5nJ9YeJy8cY9oANtZggK3Nw4Lv1WU/\n/lixbTsDLcB8qe9AWPlH4Mhka9/ZiQFUBBMBCAA+AhsDBQsJCAcCBhUKCQgLAgQW\nAgMBAh4BAheAFiEETtd49TnjY0x3nIfG1wYoSKGrAFwFAl57nCoFCQWj734ACgkQ\n1wYoSKGrAFxoUQf7BS5G4leywWU0tTeh8sT1dcfjXpF6LT4Xp5Z8dKPlC4ZZ2VWo\n2YjRwggwmhXT+01dfV97k5/cge+a1QuI/ItajjhaeeI+Lgw/PfeS1UwaHk/r+5z/\nR1jvGB+/yXtSgI5aQmwxw2T67o/PlLx/qPkyw3iqMdhuT4zrRHGm9c3nmZyGm573\nc2myvOSHmgceTyscIxRB5187Xtm5A+ur+NEBCwF8QwYqsznz4B6mTc0zkBxxfzJa\nIsrJNgCT5eD62+JjJCKlg3uGOJ18JvrWEJsigIjlgF8JMvVO/qcYsMoDNPdLxeP7\nbK1NTfzbIeVyPYIoDdhWHXzNT96Q7YWqQssbEokBVAQTAQgAPgIbAwULCQgHAgYV\nCgkICwIEFgIDAQIeAQIXgBYhBE7XePU542NMd5yHxtcGKEihqwBcBQJee35/BQkF\no9HTAAoJENcGKEihqwBcYzsH/j1Bodb0le0jwRly3K81UASvCuPzQP4o+7jbMC0s\nyfAZIgqTdaKq3H0o6TFg16ByyBQCywXTQ28q5rMUMpzS5rBThdDD/88lmMAwQb0G\nO+cpDWUrtOrfzsPX9ifVp/IAlOlOvyRNx4KXFca+LUegkuSU+HFSbihjebTfHbEb\ndSPma7CIyDY/zVnwprOmysOcIItx5MW6xc/lY62CrcHk2ivM9ZRt492zY0M6Alqj\nkprLes3oH8HswhdLRdDT2IfFO+0zwZflBIn0bepKkXzSzNBeZ0JjY7tDfV4w84vM\nVsJ53MG1b71WEALhiTMWj0zzQeSzqLMJVOt79olDtHEWote5AQ0EWrjgLAEIAML0\ngaAcTl01H3mhCZkbL+yRpknAiUNXFe56bSkpxZFP43X3N8i63NF9iLYzcjgicTHv\nrF5hZQXrjqMPPotqR1jye34qfp3pZ/3pqrTqcGgRTZ0z3aMr+G+eNSIhd5ZlGgXN\n5U4PAddehK7mst9tJbc3+xvC/sb0jc0nut7D40jaKMkoQjb1MGlmZ1NmunuyJ4yM\nsI6jbq2Qm72duML1GC12i0FU+GfUdk+8NU+GR6j4lr/QPi+X4O0RPfdpzXm8cQ6w\nkCzrKP6a4LQ06qSG26iwue3V+H4WjWCluapsZ+RADUdB5+DCHboPu5jS2iecHVxA\n2byPQLuOyW4p4igSkXcAEQEAAYkBPAQYAQgAJgIbDBYhBE7XePU542NMd5yHxtcG\nKEihqwBcBQJgXj1xBQkJZ9JVAAoJENcGKEihqwBc/9UIAJRkCDOgNLX+mbpo+29p\njoU+KZj5IE1R9XggKjZJeAMOZtSCMt4QNQLYDBP6fnuSVEt0L6t9CCwbQgrtgknv\nvq1urynIp8MQvMMRaN++uC+7v/oTO/Sxlq8w08HCX0+SmA+upSECMv+pehaZD8pT\nP45AVubs4hVZf1O68/4RMzOI7IDF6sJTl8GSW8fWbOeOa0XR3l46JF9MJzWKozMF\nDDimlWvZOxxUwM2eWPVrP0dqN26r/i2EGgyY18AGL/SUBIpzp9sMnh2qDX+2Jat7\nCGGhgXlIlvNNx29Ru5eTE0k4BVuq1ZM+rgQTTQis3x5tTICxog+joxMGVWfC5s2r\nMH8=\n=H626\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFWujE4BEAC8YwRvCMbhE0CV0F7U3Swr96hLPerVWEVmFoVshq9acXc8x+NL\na4BjGBt+GBZR2E6cRw4kEbIHmNj/XEE2fF4MG/L149feRxMwk8SuakQbcbvopSmZ\ncVc+IqLTYcZ36nJH1Vvij4gREL2BnPGHZKSJ2RxMtoc75t1Mgdx3D1MmOPHrBmCB\njN9xCvMBx24Fv5QHCXoL5ObOyZbJ+J4Et+nR2e5tL5ixWXA99Vomy6mAkYIinlNc\n/BqvV7E5eWh21a2aHCD0j0msmVkQ9dZA+wmsh226P7YwOkjSOCU5einfd4t2AoJt\nlg2YBSmDd99UYx852Y2BibRBgh8FoTmx9vjDdw8t1CGv//9ApFTUeVYe6Nzw2dZB\nVuVXvWkAOAiunrizk8ZGA0kHJwJ3ls+LBiYxRd24JidDyHs2UfLYvp8tolQFby/f\nNdlHuWVzd/rsEJBlpU64VDvibWpXIQL5qhnqitdpRmHMQToxrMy9oFW/a+bdc7Xn\ncZalUDG+chsjYM0LLRNZdsZ6mvYA+MQWJ5r69oKFPIkKzmkhUrf+AAoSPWIL/Q+j\nnPJDIClMtybBaWLgKe08f6xgqIMTGCxMulTiqNaTHXY7NMEhhkRQ368/WLV1LT6/\nPyPVfuISiYuCuwAjldotc1ijyg/PJuPKSzH7Wbf2nNaHHYRSYAPD3adekwARAQAB\ntB9Db2xpbiBJaHJpZyA8Y2ppaHJpZ0BnbWFpbC5jb20+iQI9BBMBCgAnBQJVroxO\nAhsDBQkHhh+ABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEHQ0OQvb6bnFcs4P\n/A3qsO4+/boj+nJcrUJlG0vkWf4GQS3gPLZWUYbsEf/o1Dr9TWImkpKu+hC+a+x9\n6pNrmXNvZd8j6rV9vDqiYeOO5rnS2ZjmSElJM5inqEFwZoT+sG5YxeHdpRBF8m5x\n/WGYdvr9OQQUN+xwC5lT/hCjqXs5SNsRcfty+jhA+f1cbpbTUU1OyaRJ/xC+mkLI\n7e05ugXAWGI/kNAWSVxJdgWZ9CNckGbOPXKKip6DNXyS8B0sgpDo5TYFDkTK11Sa\n4oBjz/HePpx4ev1TyK8sbe8H/icBz4aSnHNaGlff8ypR6baU/De22mj6bLbA1kq7\n6/1OJhpt//T+Z3c9p+KRt1sX3mJYg15xYP6BJbSZGWe+8Mxg+F4hc/DgDH3z9IfL\nfI0IvR1U8ikZZGqbtpa2jsQz3Ip2xaYgnZ1sbHQj/Q1/aCWegxDR97YvsY9Esiv0\nPpnnNazhaVQWiGODcUDVb9jY9dOAahmgYCXUNL2I1DbSqw/fbT5ECMejVvyDT7lH\nyJDuc3SLaaxgMMEMgWbKpnDPiKnXjUDp/MILLivFMl5XGsUqdcTMBYkX+LeMtgLC\nYPipiRieKmLL+bJdEEVFZA/8Zwf++DURSO+ahQ+Tr1epWfA20GdWGReYN0wY8sCg\nGWnXVBb0wXjnSQ0CFgLX/SO8WFtFGMP/8PQhCNYNNggGuQINBFWujE4BEADGIQDE\nIcsQ4ykBhRxShY7pRUQ2SEEmHn76edTXa6cOt8hkOAl2ZVVkmbYy0nIZVgCZvS9J\np3bYlq1LhKFQHeFYdbFwD1LNbSnPPyW6XEL+IXVEIQDDeq5DrlojYcVfwEHThgfS\nu5f/D9iARNdIxHCrJ7Vet3Gq5cezRddE4uPPpHXjJkjJT60qswtp74RzWW2mhn85\nBQpbS+xA15n5W/IJ6ujYrrfpg9JyLl3fdx22iOGW4QZqwoOkuGr+18g0rEunuLE4\nGBqRqIfpfx4ujHn/eHC6QjgCUfsl7iF7mLwzZGwarzx9i47ASHpTbgBkyFOpu1Nn\n5aHMRpOuocnz2ZjyQINrbO6yODyHdhD0MwMsE50nPgw147TYaUSw9GL9mVqJfT6k\ntzlV4fKmMzD1KV9N4lXyB5GxiRAwHXvMZzLWwzNVNXndPNtAGb+vCNZvoHTuMfKZ\nHxjJE5O8+5KoQrx1ULXLW58WoKswPgZDZjvzB98oyooBYBY35WlBFJKDrkBac5Dn\nO3H9sFgqxVMx3MuT8/ySfX12RpZK06AO7Zz1YqWZQNFpXOiO6MbyGVZGwoaOS4gh\nJYCKolb39Fw/64M6lisBK5sL7GcgBlmBswaG4TtZqTe9B8Ubj2hFoCceJY/EpZtZ\nL98JvPY25MixC9nX2oJA7zJAcCyjxjNHp8th/QARAQABiQIlBBgBCgAPBQJVroxO\nAhsMBQkHhh+AAAoJEHQ0OQvb6bnFAicP/ijpdJQC650vD9+wxIgP8k9ay5CTvvI2\nVPYdlJrunCerY9jYAncnpvdNpopQ0p1F4nt5/W6EdD4Nj9pPb5ipSA/xh/8+TeX2\nsHU2Ul0JPsRwTFodl5rTfeovIfgUcL7r69notQLLK+CmHxJAWKCjmkwOwENPLU2+\nOqOo98DpoVpLWN6aF9LGY2WvNei+TP39pjUVQKS72tkv2elpGXS7TZqR1xnBMvDk\ncOG6HgiJl7opn+Hg1jwy8M3rwyvNFcN3k07J8BqmWqM5IV6j4xvWSjCpOfrGIKWi\nJUWSHCOFH5RgXaYs6AQia4iK6xGHork16vtMOeFbXW0+vWZd0/h93edeO6NkGxgn\nJ7Ngm9uWZzn0qL+HfpQA3v3LyqaFdpGzmTycRzaTKSrHX81rp4IZtO4n99PZL3lW\nG7AsuyGNI6zdnrdLdmXEDGdRWbdwDOxVRrIsvFb62dpW6UbAwa9ohy4G1rAwwkCh\nwR7NJhOSPMkbEeXCqyqAgl9pzHLV3LJMq93tzstVBxO6frcTQ+wAeXWsQA4az45l\n3X8O2c1wbhgNcGpaOz4AZLeeKb4uyMPLXrGTLHsGkeAnsHlPHoFst2w77waFzv7Q\nzTbeFyQlqZoK409fCdxzre1KxNOoox38cH79ffsjinQf1Q5zUIdR2QCnVNhbHMj4\nmMJZL+1dR71q\n=sm/t\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFtYnJsBCACdDOWJYl/Zd38Mt6kg3j+ooN7sl1bR+SBPEv4yS+lK0cLenv3F\nM+cYZEy152H8542OpJpASvQQ+N4TSHcoqDauSR1oQYKkHOj3k+U7wgODlkh5LioO\n9Z+WyMuawMcaK6daN323OdiEt5uALLP2/60BC6As9Sl6KO7BSz2nWjEqtb4daGps\nxzyjuBgzl4A3Ct9PpBEuft4L6TVhLv8bQOTJIkjM3q4iDX312elbtZxs+4wCsVpa\nsY0OaA6UVLSxQChpaXdpQiHEn0Obv+C213nm+BLpwNUjnzkxzEvsM35Bb/fY5Jyv\nNfNyKfXp+795b3z+cTokJUhb4M+rtG1vw7gBABEBAAG0KERhbmllbGxlIEFkYW1z\nIDxhZGFtemRhbmllbGxlQGdtYWlsLmNvbT6JAVQEEwEIAD4CGwMFCwkIBwIGFQoJ\nCAsCBBYCAwECHgECF4AWIQQcBQiZM0JEqK915TeS72Ydhnud+gUCX2ogXwUJBJVm\n9QAKCRCS72Ydhnud+uZIB/4nxi3IG5AebPp1aBm9jc021FXFLBjiBi7C0KJKoj/l\nij9XEnGxULiAeon2TnH9mAIqr8sEvyK80M24gQACGL7HQeEPo36+mj9yXXHc/6wo\n7gQq9omkEqoGJeMKrNCFTXv8yBUXMMku7oaVwmvszIsAKSq0lxERlTM1HTay5tk6\nH1k5Ekq6koDypi7uaJwDOATHZldmSaeA8tyeXZh29Q4nCNCJ5aRi01ZaA2tq/19q\nXv/zCjdjT+XrdLI+8bJuIFYDZgF3E074KdX2cOkFDOE3XZVTDUDSMD4cAVpVtqWk\n2wllId62awCAFVzqM7frlg2GFyQFVjhJ/x0U6u5700H0tClkYW5pZWxsZWFkYW1z\nIDxkYW5pZWxsZS5hZGFtc0BoZXJva3UuY29tPokBVAQTAQgAPgIbAwULCQgHAgYV\nCgkICwIEFgIDAQIeAQIXgBYhBBwFCJkzQkSor3XlN5LvZh2Ge536BQJfaiBgBQkE\nlWb1AAoJEJLvZh2Ge536JMsH/jq0ZP88g2rHC1PKpJMaNqYrSsGEkQomMXJiWQv7\nTVjggJBoMuWCZoGC9kE99PNX1tYyJZbokCy+aw6TnUvNm9JDgPgdTkxllUNh6bfw\nGi8CaKhHQuI/y1YymuQ75cuIrgMxV4y0VR8O5TYHm7ZHuXgLEpKDQSX0cfewaMIA\noe+73QWz64qRQXaz7i9p+L+l1UMsjxU1Rwlj4I9RH2Q5t5EZSDj+Ljsg1lNpnspT\nuo7YtjuHJahz8w2/EN0J9N0x9SD82jFZB1OUzWcSxPDAZcmPxhl8yuXZedSjd12+\nRtzWYUrM/2I49WImTvCrpdXDMetSsDnK1+5vsinuugAEQvG5AQ0EW1icmwEIALl3\nD4Qh6l2M+7zGjtf0FO3y48ud/QcWpcy0q6GIRZDd0lrn41UJhLEyLMBV9VWzsagO\npASTR8oETMbDrjMFrL7GpqgCRYbrTwJcpXNsCXV9LwMg+EMO7ulCKZlQ7ZecVdJY\nJceB0eu3MBm7QMgD1JoTiEUE0QMrLxnodPcghVAZXyMdvWqKv5vEYK38nYSGyfai\nhA65nHvphI6e9ZYAU8mkVn+qLsSBiFs32jDgfl7PnBf2h5yTfu/qTAMk0JhI50ql\nTSrRVb4LYL9VJEcVlZ0+VHU7IbHZHBfZVEEAn5TcYzc4gkhRlHnZYwZYXxWyhdb1\nSWp7kl2L/jBVkNhbpJMAEQEAAYkBNgQYAQgAIBYhBBwFCJkzQkSor3XlN5LvZh2G\ne536BQJbWJybAhsMAAoJEJLvZh2Ge536xW4H/3UB4DnR5p/BcXeMufo8zEcpfDsV\n51KRtcAPq5bmjQJWQ8uYeorQslUPFufw4+1tv4dwmKP0Zx7t0G5DJI9BzclMV4ot\nWCrANP71Z6g52VeKmUAY5nSBzg6cjo5vzkpv/4MhbsyTyUxkrZSxsDoCoQURJyEe\n+SJItRY9+9HFKdW5ercag1nln9tRVWeCfEgiCxfg4xiUu+ngkgU9Ps1YCCgEl0+P\nDpOCw22UTW2cf5wZTr6THRHeuuAZUAxJXWCJ9WacTkJu7irCfNc1BebbINd+O3se\nHiCpJpIGZQQfnMzE+CsMSu3u2gwUnWHBVHzof7wbgs94u+xEgNBjQ6QkbbY=\n=ZsQu\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFZypZgBEADeIdm42LaylSWw5CosOAte2m6S9DgAGEBrg/yHSFTZWz341EZr\nlq1fghIC9nHh09wVlJNOOo3orB9tYoJ3LArB0MQb7Ha7dcnfn98O1od0T4QTlEro\nEeJaOfuElLD+5b9HVYqhdRtMIFiUTfSTbEXbQcvZhaLf3M8aI1G+poPRYNVRx30p\nX9PM5N8DDmW8Q/xYg3T1uHuYUmd6HlzBiESNE2WWcJoxoKuQR2Lk4Wkt+qYnxdHH\n0vYIsk9mN0yDySpPEv+kzrAU/UuZ9Ve0GhlLsVLL3yHFUjLQOx1gV/ofrV/v0vcW\nM3+rRovU1cFPUUv75mzA/TJ8aseAbboAY84RyF0b4jQLOmiTHWdDMSZwDVR05r82\nJqynI0GGfXRgztNpnnebiYk5QLAqvUzzdfRMyrU0SSl6VDCXUQAEz3CyODwJ8GGk\n6PaTQ9/9vmt3OY4leEEf3SrSwH+l4E8Z59gCvAUx/ao1pIacPdCd/kdx1mPVcwxT\njiPDMp8sIeBSdLt9Lo8jt5m/92nKoH9SnE6L4snJVvB21mfwRxRj1cWmeZ1+BAC7\n+5WfcJRM6xhr7XXeEmZO+QQYjLzKS1t+zIsv1modQMl/f2ciSi1RTO82mIEaCfRB\nXVEpewsRV+nikjsAJ9FOV+kr4NAUIg6zg9QRiHtTulm3P/c7iRKFnbdehQARAQAB\ntB1FdmFuIEx1Y2FzIDxldmFubHVjYXNAbWUuY29tPokCPQQTAQoAJwUCVnKlmAIb\nAwUJB4YfgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRC2O1NaTCBsqYJuD/9V\nd0yTYaSYj1BWDusB8GowhVsiPiHFO+b7LPcNO60mPOU8emJCyIDR7MZTzGuiHPaz\nxV4zYgK1IEZ1a24M483i+53Bquej7nqch3AGVlKA9okPFNTsJOt0QkbuPTGztU++\nZSfiUnNpY7hMA0f5rZVoHg1BIOSv9jzt/Ej4PPRKoiMB7f0wSeQkYyXojq1ilcZD\nYIuk9il6dxD8mLgc5HoJcCLIhuBUhqDlEMH/1yODqoonDJMUShJqOZE+1Xp6zJ6w\nBeMC+IGGefp8UyIvumtT89l2JrS5j+6DLPRC7IKoo9ZcdKwdX/erX4vfee2uorDL\n/u64oN1otYEeZdz571rq+YipTlyqA+4kvmzxl6Vsz0hbVOskttLOTrjQkZ+wu64d\n4VpczomevsqZcETrIwy+0lngkOxsQdh085kO/Xgh/abRjDkWd7bxWkdMavmfY0oe\naHi1/NWWiBZn8PM3EFhNINVgCjLdfwD+gHJ4SFZCXWmVcxIelo9kZ0Zwh66LViDh\nHAfE2e/pr+tQ37hW5Sj3LgYUlTKkFL4iSlcib6EKL7BNmmRtmDDpdn6Qk5CZXj3T\nIqjGnpwUygcNxms1vv2ZtHqr2dPmnVJT8kzrQhQHaE3yTLyeTjrwPnFA304BOaEm\nkdCbAVV9Qk6UfGV7Hf2rJ0QI6TzpLotVN2QclYG62IkCQAQTAQoAKgIbAwUJB4Yf\ngAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCVnKmHgIZAQAKCRC2O1NaTCBsqck9\nEACqOdwRtnf/X2vqdsOxisPjxvtfb4jFC1j09rsWcXmOoVRFxphriX7Y+Ea1+pwA\nSeMHR6UP1gLpbISMVKoBxDp0n916sTxH5KPeq5o9xcieRAoNubzxQdEArwCkd545\nLv4K1SlYTNWUZxECHCkHEcpUA3JBOYzd1vkJTS73Box02zOrDX2FTX0Naf2pduNH\nFsQ2b7p1Wj3XIEN0YDvHSmWCKdqlQRfxYL+7qakd1170ILqmPZpjItU+jLkL7d7W\nXNgI8Ej/30OBygNntdgUZieB40Ogzuvye20lCHjATF22bbD7gyc1etAIZCgtCFiL\nCoprJTO0wCky3wesjRTEnz5n8Vlz/XWLllCEOu6b3iWJVKgHUUP7AP3EUITT54sB\nuDEnHE782zhbaYGjcPJQCWg0hKTEdHnzQai0CagSElwrm+ez2kK/O1R6QDdo9P/x\nxrphl6PoJ7nHjgvgV8kuoH/OllN3E4SZ4TOEU0a909QBKmoikySTtlL/ur54+4v7\npLnKFoT21JD5So+JUeh6iXJHDId2yez4CgZGh6StsSZsbDJ6dxput+STMyoDOZuW\nuOjBHx3Zi3tSMkOzPaSGfvVj3SPognuGd4tPU9rGCB9ftMW/19zs4Tz8G0j78lom\nPXygUiKKZ6q6BI0n9pN45Dn2l1UGF9RN+FZdANkCww12QLQhRXZhbiBMdWNhcyA8\nZXZhbmx1Y2FzQGtleWJhc2UuaW8+iQI9BBMBCgAnBQJWcqYVAhsDBQkHhh+ABQsJ\nCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJELY7U1pMIGypAdIP/RnIwmVyCHRDFn6i\nJlRkIn+VDfn6NiVloru2VFEaJlGnSZuXaYk++LvQLb21SJCJPU1CU/PDmAOBSVKW\nq2xCog9WVDdUZLN34ggqGBJWQFMYFmlTFrYmDHrSO7FPxi4/Ul/8UmvPIOV+gkLM\nJLp4+4aEXh2dD1lOvWPX2tVxaUeMp28tpL6F1RHEHUzF7hv+Ek1oTfWPIDIl65W8\np3vVUOG+VJi3iFSy/V3/R/xbI+6x4qrLQPiBlxQQ8nXaXaqRz7CzY0xuRh9Xq7XG\n5tpiVHgvLr6frZFBQiCnx2ULDLpFC8F+5mEZQUppa69u0O/EbSf2pVdI6KXqFNnQ\nNuHfP+ueXwQkAZOjQNIH1Hi4CHJhG4iH1TA9FLjggv/OriMmeiYz3aOhU9vDXEvd\nvMqZSViG03LBzESz2LGfRBjuyU7PjFMKeRN8BiyXrHE8wXVp0n4Z6lhfCVAo1cVG\nieU5a+hSnC9XWQ12UlfkEwE/7c2FDQBpw2UCui70PQTYumWO2dP067+HH7ojCyUi\n94tGQWzJLObz+f2y0TIWYYGgyBie2XaYrkO71rl/vyxgXQV8zMvWkqSOpugzW/dW\nyRPQGE6aS462NgIkWedujrl0VZqAG2vfuEbiCWX+SOEWA99RZgGvIWjIkKseBEsl\nQvRCLMOOi9K/H0BqeMjnLf5Hu74BuQINBFZypZgBEAC6T1PynefGCGgjhjIefXBg\nSx9d3X5UcnF4+JuMG67tEau1bXBAucvbD/FZAOc4sCX1K/yH+CsvvTam3CiV8IkJ\nGBgIj4VkWlNbi/zQvgw1+bzOYRVth57xh58SHUNHIpl7ccFLMOhmCjUfAak6xC/P\nVf0XtK132Zj+uET8Ek99tCZfpxaZuRmRkctIdSnl35AjmV4Wb+l4Rs7SVfxH8JsD\npu8PIF8rsGU1JNTVcujGaiT3GB5vJjzO2QnrC2s3PE2TDgn9jDCs/i/U4NgcrA4B\nJh8QdH4IIul/U8lGeQcZJb5/iu8ygBqj+ZylpLtHolC61XrFJtTb2X2mILOwOqry\nHLuizuSkZOpTG21hgdQ4FnspnF6yFvOXuHD1RWNgU7jesASYBGxpHRy/owzwevSx\nqvcxnv39P4R1BMmg9R6hx6nfQK60iwIm1XB1U6XFbl9mpIgrifo4rebsGaiXg1DR\nhblOe7qICqvOMz7DdkFCpCzNSbBn/3LZnDlP4fyu7/+y60SU55lLwp5PmC2uJklB\n9LYHRKvULK3Kx5VkXftYxy7DktHJTpJpU/M1drQFDYISkiQUOHKhMYndr4fwNAgS\nE1uQ7ym3fUF4EX3Fouwh1W18GL62PkcV2i5VkE+Bev07dBonunntzpHRqZulsp9N\n0Pi/3n6s7tMx8oR89oe8ewARAQABiQIlBBgBCgAPBQJWcqWYAhsMBQkHhh+AAAoJ\nELY7U1pMIGypmoAP/2GV4IZ/V2lt/SEY54Q51YhRaQHGT++cvemkfCIQLJ+nWOSD\nFJZUaZiwNF7sC3U0crXMJ87Ais5LxE5EIFqqjKn/cbTZX4a9Jd7uNooZQvGzT825\nzr98MH8Go9PZdodcSwwtLf6C/gPa2VYI6X7wpdfBS1RaUB9SW+PX0R/rQR6uWVyU\nnT17xk9tvHzFyauxBAm0UWd96C3I4zvHujrH3If7Qol+fWBDMZZ7lMjId+f3Ix+e\ny39lsaSVZXiRP2GmyjpPilJ2tONe1Bj96MfEev0owl3Uz5LJrhTy99zQdfUNVLgX\nluvslK/WzppNmOXX+u3Xw4c3p3QL9qtyXay9tv2rsi19HULpPE5FkZulscbDrbUI\nEcyAc1CTq0S0wJvVvnPNtUIiOkiLGNlTIZpVp6e3vi165Bm4Kx7KwxELyuE07pJJ\nv6PbHjfbD4UTGGPBxGa39y/h72nh0hv73Ev4HDDRAwgQhALhHsL1eXyc6kMMxLXh\nNR3W/AdBq2BDID1qj4g15FqBnVmcOLJ79AAbszQ+2Sh08PmPGw08D0iAGsqvOsmW\nW+4+S206EIfKl43eLd/PME1ot+FAOepT9CXkQxaAs+ZH7rKmlx8mmowujwX0Cb1j\npkatHhJZAsqY8KUjSXqFfVjPHglxLyP/8ywgi/MBlwSnTTtbHyKmqDyts1PP\n=CMP0\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFf3hmYBEAC6YQyQighf1meU1gG8OyjlfRp7KMJJHmxtBjtH5fWtM8IWCdmZ\nnCoUgNbJHIYD2Fn3h/ijX4/S/492mbymadmW24D7mYde/OBuAQCmffjypBCUS5Gh\nZmZF0tu9Dg4cn5Zx+mchnt330m7T6cUreWR1/CiBXINJWQ6ISuwO8MDW/OSKJNyr\nRdrf4Hq73PDBkSkHK3awXVHyHfypeJP44fqBWbG+j437xWJFEqnVSIhMlk5y+qS7\nToZTmjybq0A88tfMZztSuUv6CApGVbS/zxSpyYrFbSW1vZK9glrZ2qJsWZYCBlt6\n17W1P5nWYIpP6T2NLOmx6Hk9okQL+TVrfOGsBkdMBI/KBlV9SlxQFlwIPSj24a7f\nUjpjP82Bx8sdErUM/DREnr7epLU88jdLxazWywI+yh+rEfE4A+9oxpcmxwJtpzP7\n2sVloWhaVLjWDbaSJ+ALvkFr9PmOa27nxnRYt77D5AMWttnjyoWvS8fJ5Bcm+N7t\nbrVBORqk61WCJDmuK9ghCgQ/YnC1e7PGEhxUVYfJEU+m+NIAPcOE0lv3nHSTAunf\npIzHwI9TTkd9Kj4rHzxtQW+tmToeGO0ghnBj6p741rzMYdVHER5isvD36Vij3bW0\nf+qJItIbcDpwiPMBUOIPB5saZzn7toXNMo+fmYAN44pXk38ImnZM5F0ljQARAQAB\ntCVHaWJzb24gRmFobmVzdG9jayA8Z2liZmFobkBnbWFpbC5jb20+iQI5BBMBCAAj\nBQJX94ZmAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQsB+7koIcWHqx\nWQ/+MrqkpR3a5vtTz53p+pgU/1XARr8/PISTILA969FZZ4naXPyUpYICVnVMgs4s\nFu7X8D5I0tSUmVDD1zQH35+d8Sgxd52AgrHg1gXa8Dyc3NPamG1yD5rVB/+QdhE8\n34klvs/lG/YZrASQ1VrRH6xVmdBAnGEP19jJ2xSQGKidzs3o0Sj3OZ8gMlWRYJxm\ny+nnhuuKGZWb6U+cQXP8bMTzf4Rxhgmi66snmL3ffffa8YGg/hMiW2m0bXy9/n9j\nAZXjihzGDingPYv6Vh2rO8lPW+woVWX/S/59no1Q7mCW7JEMx+vD8kueT/OYvhDg\nXCylqSkiDzkaTQzu9HRTIt0ODSIc0gV1r6rFpKoBluoJF4PRXbtwYiM+9hHT/lFm\nh4RXrL4Kvbt1kOwThCWQEiR2oDd8O3v4Rg/mNdHjXaSUnHmTDagZEw7QLuIAlQCA\nQK/PIN7q0CVpza/A35rlWcuk95Rx5TYctPfgT3VzDXtqwsttxzSseeDNxSUX6zR2\nMqAMg8PLSIN4sxSQ5DwDoFjGezDt0SFz+f1sZLOX1ZQ6vqSeGK4S3M0tm86MaND3\nF8Ie1o1g/TxrZHVaSYdLXhpkExOE0TW2pve0EhBDLjDc6ntE/kvSnMpoou6xGA1Q\np/BrtqINBOq166uZrmCjuuz+nulkor/T3RbzdkxTDZbscFK5Ag0EV/eGZgEQAKfK\nOW/wNpyORAWl6tXxllhFFfCEHZQy8GZ5lgo+egaHLNXNrMHLG5sOB5Rw0TISEt7R\nxWJ6b1zMJIb2WyhvG5AqQA0Z8E+oL6psKEogkEWkrh67Nj23BnmDQlY5rjzLx/Mj\n9lViWhscnq7RJDUXK62nbtDnZGIbWstqaWdRFAxhv3p7JvDArjTEdNQbZPwyTqcm\npiU7BnXxbAxtJjU32Dg9RFWdmK4zuRqIViATstPF8MWD8Dz/xBdNo0oAWyd4VwNs\nLHNjqMy8/4j2QNTpNDyqcBr32aCavU3JMxlBh1bhAY6jKEJuzDFWAtL6NV9uh3vE\nbKlNSW8v1zgSUtCy5mD+/kU6RAYSXInFDa5f9Taf/DVUfFNAOC8Bwg0/8nLUjDGZ\nvs0Pk+k9caV7ckMf6DTRknHOa1+PO+uqv+izWH105LUlRK9ZD6bgPG6x3p09M19Q\nuZ05/Q08f11lb59I1QJ64kdOz1S45VtlEfC+6bsCrECWf6Fk6cvIFb35zEblAy3Z\nsZLSMk/MkZbRlAFh65APm+z4Y90Rj+ZlqtBYGnTgWh7BPpcoWfLHceHHRV42vbQ3\nlYNzUPYgopKtA3AN1kEck/GOPFqXOHheDCokTpxLnSCjaLcHUEvckMMiC4BjC7KM\nn9WQgnq3FjljNKRld8VhkXLvCH9wxZjxC/ntRUJfABEBAAGJAh8EGAEIAAkFAlf3\nhmYCGwwACgkQsB+7koIcWHq2PRAAkbTAM5NwMd6BU72Yuhy3pq+v6bbIKaaqvV3L\nDfRdABA67AWmECu5BzLXl+FeKCEDsa0J2WX9f6fteAha74c2Kt+UMX6GjHVeMF9c\nhvsBf7obbpggRwAYTDJ1gGZn0+km4gMZ8vBXJoFt0n/jkHii3EwD+fbRDolBUxN/\nTmEj51Q8UXVkBwDCbqca7bHa84aOYWY5SzfmrI92FObcM7R6+6ZNomczyjcOGQS4\n649TSouC8uuiloicjhZ+T0ubXsRfbAmMOfZHnRv5GgW8c+Dv+cUmML1u8xhQDl/3\nC3oaaA8IYZsJiESZvOW6w34715XTvGUGYvBlnSg+FnZ0V1VEMkZ7bsdm0bHol5E3\nzfzU6xWD64Gb2JjX5THUkCqj9T9K40KR2m31kemkqs47Q0inX49PR11rNzW76VZy\nwTiLyJ4ILTwlO5VmniMjNK6rwoJfKUVVlidPwgrLk0O9RYoD3fYn77uAyHYI/kAC\nDhqZBK3vruEQGml878yEYQ7RC87Fae1GBjs2ekw9TN+X5p6rvP48uCP4zkNB/+gi\nga9LX8s48pbof8mesx0fLmBAqcHllhuE9T4WxlL6uRsAfpzgx0dQIPapOHnx6tfO\nwzSUzZBpKVw/+hPrbFbpoRzpjDSAe0XePuiTcVbGZIQtjsAgJsK6t+mGHppWTri/\nKoZmFSI=\n=Fwcs\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFRgAMsBEAC1SlN8Db9p/+pQcrlXM0xtbVDOZksBQynOzUV+Y/NBTmeBnYMo\ngh+gTau0Iv7UlDanKlB8pQubo1Gwp6ToLB6pcoh+Zuy6BRB1yHYtNFhrb33QZ5Qu\nQjtnM1qRhIuZI74StyJvfvfg5xG+Z15rvGalIhJ95s3574t6sFnnkdAx3FnHZS93\n2Bv9Dg7FsgKB7BAANa0rTbe0PS2NdzMRtelvomUnT97Z7Ik7NLNYddu+9LRXUqQw\nsxt0bFL4nhGti/+XHGodtiYgtxiRg1qV2XbWdzVJB0KA1MMSlFj56xzvydLZbaAM\nggUm1WE9rUas8klqx+tff8u0zJzoQjD3SZ1HWpmmtujYGiCQ8X9V4dZONBtu7xTA\nspoh9rm+re+paR0/W0GWBzQJMBQgmPrs6M5NN1eNofNvbWkW5XhtMZ1ebBoqKm0P\nZ+xjVmvJIq53oy3GaakRdom2SMeHWaFoSz7hHYzoYy+ZwSD2nJbAlewWt8Fa+HGz\nDw0HS3MOnktYaU/vuLPfa1FQo8xdCLT1tidbgsQMmh3bx6p9y8e4xrKWEkSpenk7\n1BDGP9B5FdDUOBhyJ8xMKLQOigKzeU246P3Mv37allDn870yB340BU7yuGfUhBPa\nt4mV4MFjFZQq2l+1sdI/AU7v+bC4IXjgy4Sr0wO+WU0o+mt0SBGxxhHQAwARAQAB\ntCFKYW1lcyBNIFNuZWxsIDxqYXNuZWxsQGdtYWlsLmNvbT6JAjcEEwEKACEFAlcG\nbYgCGy8FCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQyX7HoH7eP8HWmxAAl+gW\n/nticpxR5GnUjxmYEws7lprXoXAYg6c1YUwAZ/bmzNaSm64qrrME8B1x72UrkcfZ\nATgecEau41pifCsn1WsPlDIzOhGO9TVfkcaBScQK69SmifZk19VQ4e2TuPUL83sy\nYGCgoxWh1wuGadZxP4ldud5QYEDbSNSk21CF/Uwpzn8sws/D0ZqN452KWFds9Ql6\n497HoauzIE15M/JxKeslbnT+00Y/DOyKb67R1uV+nuyX1cxWlyWbLyHbQDyGG2U9\ntIOcC1hodx2CFzv+hT0NwUjSeq/TiuWPZ+mtO3YMGh282RfK1y2p46bfmnopf/QG\nyKglU26yxb7RnrljbnSS6CxqpokSnMmGtOunnwb1YJ7qMCNJvtWjTMPE0hqyW8wc\nhT2o4KLavx9MSUyZw2Azpz9zlmTn2E2jwi4eNFdaIDCMzoU8pXpIXLinX0/ss7aV\nq5YMO/N0A9H+Z+05GIQyDYPdcZrESbcn4uieIujYWk/ZiVjfW1JB3ws6mDZFo5es\n8yJkU9tgbU8oTSvQSIB8ibY0InXTv51AltlDdpb4Sm6B+hKZYptAR5cxEpsshX1M\n5fEicvaeCxdagF6blErbqjWjo4GEZrSqyg9lNsYYhfF2TaiPFMNC+Ztgu8iY3L+Z\nI8EZA5Wcnpg5f+CL/Lka81Pyjca3tj9fAHntsry0IkphbWVzIE0gU25lbGwgPGph\nc25lbGxAdXMuaWJtLmNvbT6JAjcEEwEKACEFAlcGbboCGy8FCwkIBwMFFQoJCAsF\nFgIDAQACHgECF4AACgkQyX7HoH7eP8F0yQ//UD98e/HG/Ntj3jCrTBzmFPRj0+T/\nc6/sdDoCHYPvQZR/glK4zlvAs1GmXh3eLG85W8RuYDfqyhaPsmby8nAw2rBAS7ZA\nn1AWhWJc7UcHHI1Ti6Jd1KJopJxq37jx0Nb1HRo3vc4zD59KVEojXDOrZT2jyfBc\n2k1/R5wHz0+argv20um2Ptb5TyqWIhIVae2PlS9vyzZaKXMFl8Hpu5a3P7TxGi6Y\n88wI9i2NvdYKaNPRMNAzfbNJiDroGWuIZr2MeREfHwls72e9uxUAEp2JNkdrK4RA\nyxJQdPHV9YRyvzCUuCckqzOqn6fjPANLD27RFLYjyggL9RE3XZtBBvVOD2XgxiiX\nWickJaAmScw+7FPyVX2oTtMrJlO8Ma0TJHFSJ5l0BXNloD2tLA1Etvo3UEqaqS6e\nQkn+Qynjh9vU67nvdXhaD4hVt/bSZwi2UqoR1rBQ2IDzq9kVXYvG9DiElrpBo8j7\ngLdxvGhp+Oyl2WTe8/lH4OZLVG+rxqh+t/sSZ6voRqfg/fKG6Wb8ZDa5cRhgYJRp\n1nEta9hse8bWChkYXLScxep+ncsPh1gJStEgXBt8QO+4c93gBHJW0oRTvytj+y/9\nebIyo7WVHylczMpR/k4iTBDo0dkwib3LODR01Tqsooz7MI38GKguEMfFcDpRQwtq\ntonrAexO6AaDMcu0J2tleWJhc2UuaW8vamFzbmVsbCA8amFzbmVsbEBrZXliYXNl\nLmlvPokCHAQQAQgABgUCVGAW3QAKCRDJfsegft4/wVwiD/9w2HqKu2gmmgUiZwPT\nwgPlwIWKscnoyM96LUMEOfoUwc0p8uk0xikbGWkiYUh92eNW5MknrcF71TJnd9d2\nHRkt1l7Km7gGqdQi/OOxGLNU5l5fs1DGY6+owoNzF4htMosVJ300tJXQKYlwO6zK\n07RNjfiVaUU8CMj0N62gzR62vy7a2SI+x1u0vSRU2FUED8GZsVTVsr3Zos7Fk1zm\nbyv+ejiAq1UBnnf1kenKidtcaTz7AJFF//P3Pb58xjur+tYpPh2gHNOw2p2ANdUH\nY/HQdtkpvRT/jiDTUIunOfPjSrVJEWaVfzNHjocmV0uYJfSTuBomtCXdqLAHWcl/\nrWDYO/20MAL3Bvy357zxbhyLhvWiusxSvZYsNKEpDU4na+jH5TpiDUi3ulE5MUEj\n9Vyh4p3n0Knse7Rd0pKvPpV3FklDVlv9pOjpb/TrAq4f5/LfBmq+HUryqBiOlII5\nECbP/RZoreH82LJO3a6wbnOM8gzhf7BKBToiZIEZrNsnpjBCY2X6m/LESO4geEEq\nb22xzxvD8iiZRgIpc6xwjVpBZi+BcGgeOHxr732M93cbUAtdv8DUjBz3fL/sdx44\nnKN8byJ0vSutHhEn05AjAJECykV5L5SGhJhtVCGv/FHnYqeZnE/HoPWTUI76MBrB\nCQYst9L2LRBvHkFXaFbpdngGE4kCHAQQAQgABgUCVGBVwQAKCRDJfsegft4/wYAw\nEAClrLnJnhMnDjMnJPeid+Yb/a5yUbi5LIcXKEeikExznyKogMljF7xCl/gtUZys\nK1GncI5B/1AoDJG/a/6OsTgbIR9RvZosKMJj0m0JNp660ZzzyDY4o1CCNn+mBrZA\ndsEnYxE7Hrc7K9S4fi8QLJRUVstaPeh9HrARB0thzQInaU63B9ZjX1DluPWRKTZh\nbpyd4NcU6cJjapu6l0UkHH4YzRsXgVJCvCkcB3XI6KjkycZbbCuv4GJkiEKUDCFt\nlhaf3jOT+TVD0aErrJ/SDIUsH7hOLjgriJ2ElpE0fdNF7zBs7FjPTaVEneIeBwZJ\nBobM9+cf50P8XVVTs5DzM/28XIEMEjFyoHRn5ghirdGGuIz2VBmMdpm5O0SWmk1e\nts/23YMEh1ZUA+8QgBU9WV4VejQxgHDHfgho4YifXNopHLgSgZa8pL5hk+yWey+d\nWm7QxZBaIsTYjS5CuCjeSZYI+2L1BxuF4PVlaENGEMbzCbLUr7jyDj8Mbd8mxWla\ndxJCyQ3IGuGZMwTyGUjuhTceW8kBFfwUUEsWlsRJ+JvcbbOKr7BlNOlPy4g8doLK\n8S10+2GSQudncj1MQbxYrePSoeEy0e9stGKRwM/gcfLyWJFNPI+z59rkKAdigbkT\nXiYaohWROWRL3YfzJar+jUtycGbXaN9TJr8zFv0dlDZAJIkCHAQQAQgABgUCVUTm\ntgAKCRDJfsegft4/wf8YD/9ISAWK7cJtKiTH9JfMgelUinWiVGyKu5SsvA/eyvIp\n2ZufUXfTCQ6C37Kui1XVZUchtGW+iDX29q1+8uZl6qunezXLGUMe/PCQCCc4y6sy\nWXfKLmUMgIt/ffJmOLh6UG/ituiJULHrhiN6X+vRmnkcYyBWAVIP+xh3RojTdtvb\nNHQf8TI6bIeqEt/h+qSoYXhT+lUGKqvnvDZGwtqS3pAGdJpLSaN3FpgTJRF7RLhC\nt1NC/zy3r1CrcikTmYMOXRq7dGhDSNkIHXjVvEbc2Fcefc74ThU3GwCiGeSjyvmc\nCh+mt5Xwsh+ReOPJKSushWQ8hceTbEK3P/ytXmzQ7jssGlLE11F8nYDK+yq6XnD5\n+sHXdOdc5EvZHmWU5RyZetlHBwvnBAOST9I+dOzLqVcJgCB45bN7BRl8FrXKFEL7\nPTufzqvdqG/a8J1MtC30IuSbi90NtJbmMt60jLmA6YHruO+YgB8zjugIV0yLbcjv\nZ+a3ligRd9xS0zMhCz4EoMNXTBnwLNHdLWwLFe2z9n6jpGaZKxYM2n+vSbJacv+P\nLjaYQwGCjwj2eWt5Pdui9DubL0Cnyr5phEIhxtkPpStFosfBE9uICdbhruEzOeha\nfadMfk4wfHja6lzjy8Qp5qkEEjqdeKRXFSjgFoMSZ5yf3wni0pWvwlLNYT8XoyQn\n8IkCHwQQAQoACQUCVwZtqwIZAQAKCRDJfsegft4/wYlgEACCVatD5VtbCWrvk5mF\nGXeqLFdEwwJxCzy6r8CR8xNX9lihxo7NTS7TXvKozVFl9nclpqLVcsBkB15hD1rf\ntZbDonGUSjPtT0zs7YlfqJTVHH8MKtg4lRiHru65bD5t6/ygBoBHxGsgcVtKsSpp\nLICzpbrv+LEsflK+P0EA/D9LRpGE6cKH4gASn41TqrjxkI4NiUZlFvoheNmT/Jo/\nyt88fn1gh79P3i/g8uk9ZSHxiRzXousL/hcYi/yjqJmQTzhVTEXFIV3I4zqpkroH\ntPidLLuI3mX91xuQrLnf8cO6BEYoC6R2qnMMpBq0Ys2QUYogLzdYwgQczVKFVwZ6\nP23XpNpZmP0/lGwj/WnaMuAoW3BAtwKjJc/MCMkd97fKZdXx9u9UscfU4Vy5rHvf\nBXOsQ7BqygQQ0mLRVDJE0JyUXsHs4eheM9pyf3ZxxYcLk7rvcOy48k4jpJAfxwMC\nsWQuajEh7Rp2bewVGOJpb8pIV+oTP1Q15dAEmEDRSA42uc4rzUMnLq8+59AEGB9P\nPRvDEy+6fceOQ2KzGitvzFw11aKyS7fzHfXFWR+L8ahF99S7iKdF7nAyebQeupSM\nHQW500DDhEGZj+pjtqOPUNuqDZG5gEBQDJnKzGefH/WrHq191pEtTLi1rU6XssHw\nY7/4FdyFGC3bXgquNSZU1G2/QIkCLQQTAQoAFwUCVGAAywIbLwMLCQcDFQoIAh4B\nAheAAAoJEMl+x6B+3j/BW0IP/2R9HNKSifGjTwZ4MYZcbFXfLSnXLaz8AVQQwIdn\n0diQkevICzhbZ7VbcxvgODMjn7ZwaI/gGcPWklVUp4cSyttxAfWRKqEPOr63jblp\nTaSzxAAjnFEa1CJTb3T6d2hvwCd+R2W6Vht3O8lRkOa7YyXVfLnakbeWGDhm2IDT\nHQNXpeuZPHnIcoLpaAsVhpm0EQ8+3Q53sFjZus0h1xh5v7Wfnrxjf/jzQ2MJTGvb\nFxRy/eti62yVAHEYLbw6ud1qZB1vJ9TNjcdnhfEn7gtuXHLMUrAQ3v5HoVBdAmZf\nm6C8S5Ko2kh0PCtfgGYxXIHPeQo34YipRDpe8y5CZ81WbWB8CgTfPnjglWEY3GpN\nA0r0PI0JDd4cVJO2HZQ9qNk9hvKnpOQxbcwzsOt4bZyGkqWGJOKSwMqsFh7HaQfA\nWHnPGz7PRulCR6mOTTPI2LQVbp0zBWfQM1HnsZw1dV99DrGKLiiRigwJuoCc+YxZ\nmx6odKaoBzFe2qqeq/HTnykkhIGEwUHxKDfdXhOwaj6d10gx7Eh2d1puNPMHNNMO\n6y7drNnX5FeTrI1vFNAZst8yhxUGVXLZvjr+PkZDloe3NUxTUdSe75VV9QC0w1nl\nFsBKWTfu92bWcJo+pHsk4q05xqHObq6tcXhdmfBPsuQaTD8imCZNA5W2bDim4Ou2\n9p9uuQENBFRgAMsBCAC43agotjWP18xhtfMOydJEMFsc5bZ1OzRMNAuAd/3FbLuz\n8HSNgB2ff/kRIBj5bjtFLwC348Q8lYIsbNtA8WblumYPuMTPqxpvglUUCnFSmum1\nptCZE3L5aHWRzvDa0cC6tIP5xGJu2gn+mjwUbXhCNKJ/zdloRyuOulLuYjsUjNvq\nY/2y0aKic9qpvUR3JQjdHqiCqs/e/pLfe/j07gKVb9SfN5t9PShmD8hw1yVR8Cbg\nX2Z7xlh2g3f0Ue25QcFZ/5K/DN0Kfb7W0uB620tSupmoLk2kma6qF6fTIfI4CQ4T\nnsd3v5CdM8+zGq0pI9CLSXsiQktIjFdEwltdCVk5ABEBAAGJA0QEGAEKAA8FAlRg\nAMsFCQ8JnAACGwIBKQkQyX7HoH7eP8HAXSAEGQEKAAYFAlRgAMsACgkQc0GxXAcI\nd6yPxwgAmgnZzvl9tYAKrDQ1Vl/c/XDV7FfGNT1rUl6ECGAM2cq3aF9PabjPJqRt\nmYPwrTUYHTfz879WZqX8u4lhD37oSAu20HzmppJzs6t6ZXv8NvEoSyadEteW+pZE\nFrNt+UyYt4iOq+5IKKdyyUMHC4mK+KS1eNsX40b1SFioxy9L06UEicW6oTpfwUTy\nkPva2iMJdldz3z2Vspr3pYQET4qv8YWyftPiusHc27UucDm8v6UssO2EaYmngQC4\nbufkThi4UORgeJaunHJ203oKJe3l5viyuse48KG6+ZE8cOCOz3URW0OGYDV5aJnP\nzWy+gsQG/amJ1y78Hd3JAa8n+zhZBpEID/9gUms98iXNGDhDi4iL2pa4J+vK/sPO\nZXG0TEYkMNI/youAWQRhCoMeB8hK/borFLSnuzQVZ8nPau3YKjbA/8JF01RAaJ5L\njE6uKpV5INav8/B3gUAEAZJXIcFg3OWAxgj3XjkSXlfzSaMNDWXQrrR6Edpj+U0S\nMH231rgz6E7AN/TRaLP90csTeRoxb39sGqEdIc++3kZSnvXIpOs6/7BtKpfolAjY\nRXu7IRbaU8+hA5YV1+5wRokJaPebaYJChljwux/NCybARIL4S9jUXHO/aImOCUrb\nBiIPDrF4oXyY7Lj44rtaKBSRaLdtpadZLR1aeazwpAoyuicXcRrlsH2NMowAE8KD\nOfZ4Dpv9qf0NdHkeRKR9hjmjmKXO7e7dksReyqc7wyUpKnVlekI3KTG9kVszjBWH\n6957DH2khGBWqjnGNwTVeYx8PHQ00IOSDA+NSa5uUkjXKP89ArAhk0C74/Ekdchj\n+//vz0MbzxI4txfvQxzRFXnIDJTvSx5ZY/gR0+B/ZpiptvmLn6fQvAZ28h9lt6fn\nCdQVcLEvYkJbRa7qL2e2Vib40Ell6HxaT9k+OAx3f3IBbkDVXG9750gn+Hjlm4+a\n3b1YjS0gumgN31ttSFKUJbsOZNL3M/IdBQAndCoeTrfYzJecpWVnt4OTu6sjpy2n\ncMp4ZM/mOzLMX7kBDQRUYADLAQgAy35fTSDmKmu14u1wBr6l7fSp8wjgTAuHTMGe\n0pZs7PxtUEZI5fOBszDpoze8Dw6xw4H25AkMk9+tUiGObMs7M19hBGdxNaeM+W/X\n4ySUEB3X1v7o92058+uwFcipiaBZfGhOtnq/wcTH699Apkr16cScSwsMb88jCoE6\nDRCYKIzf+lEGSRbYLv8hGw/F0hPgrX67X4llDgR9CjTofZ5OKzkGZnp/KsrpiIV6\nSXYw+p6J3XC2UrqVJw7lwFvXulRPwYQhj2aX8JGAkyI9xZNUSZUXhpWq2VKV4TI0\nunXXSKlbcwevdSc+WmhHyHT57euWlhLdGSfa9ja7pWdFU6gcfwARAQABiQNEBBgB\nCgAPBQJUYADLBQkPCZwAAhsMASkJEMl+x6B+3j/BwF0gBBkBCgAGBQJUYADLAAoJ\nEIl1uothAMaxNn8H/3b34X3lSzD6vD+IoCkYRrATG16KRC55G/T8uWCai3iD1Wbn\nYfhewAK7hkgPsO3N8XGhoVReMk3ZFe9GWGbDZESwegbL4/MO6/V1cPMc5Xr8bWWh\n62rrH7VDyNA0UH/9NZNKogPf5DA9GYNUox8B60YPCKBljXThx6rf4t0VMyO5HW6U\nu7YSRmKORbSnwoj5zBY3yzjZP2lRfFmOelWpx90HhwRh6pBulIAo3oQWfOFolSku\njW/E30nXxXlvo9c0cYHbEzPNYQ5VgUchkE+FHRUuKDkbofgze90uDB+RogpkjwUJ\nOajV99F4e6VIXmy3+LLgz9MTE58OsblUPeA4Sk4poQ/+I3EtcXZdRKt5McxipEfQ\n/hCxQRElduZ0Y8qqhB8ZccvcIkSCpp1APIxzM+mpOGCBS30n2TxCGzaqgRqydbPj\nzSgZ5RDVRLPPCV5yh/9IN4qaecii6Pq9RHFY3T2UU0JARjOdpQ18jsFl2Umx4BIz\ntNgyuoGH2YpytkLw+80PZGBV9oYLHGDs69bc6zyOPaHc69qXB6Gihn/9vQwsuTY6\nRVVTxxuwZTNwAOcAz7arHSTv7dQaDSALLcbA0qrLRfJCq0H/VUYUMDZyOasHI61e\nCNeDMGmQ1K2rv6glcVoG00y6m+Os6OqVeLRGVBERLRkctbXv7wRQFo+43/ZJxDu2\n8aYR4F1jjyUbEsdvfst8a1/Nhr6vnJwid7Gg3TjVYzOHxBqUblHoRjP0LDd+G/Fk\npWc9pQRSn0cxvSTwoN1UPo9kmr0QqfLOV/kNrwlh0YElr2ArNVRmn5BUyhmWxn8w\n1C07HQJe1LnTkgln65V/+kt2tze4WfMt6OGYo5mcxGiPtgcBSsJEU1IU99dKz1od\nGuyYaS3LXdYyGTKWNrxto1CEkGQArS4Ei+CrTbeb6GAXEn8GDhzfpw09JT2c3Ab5\n12rlNNGXvvSUwk0NjUwuYv7HxNBCjrQQAhoPEZlzZ60wv+uRLNWQUr01VwLxzaD2\nntI6COSRy17o3GzXm9d4V70=\n=h9up\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF5MceABEADFVslAVcrIyj7pcWEPeYgnr+psd6CNKlqOslf0+WUFSf0RVl45\nuTckfS/D46llZRGbnOOixtM0v0fK60iSjLfWOTQJWAF8BIHaCEb3nAafZcFGnRb/\nLYwBYHakhtlvQFprEp7R+ja3e5+m4N3x7Rr/WEG57g+PXigsH2oGOZxgjRbaoAw8\nQovG3ngU1/4Zo6p+7spTtPQ2eyhuE3qd039zJ4mKysJWqdZUsByNPfFITKVtbj5m\nhtZPTKwYw4+gAV1aWy8AaEVpRJxGciZFQxp3ZqNgNBLFcgs3IWN9MPXapqS4A1U8\nqLZ9VeWhgFtNvf5Sxb5l/cGoH99u3nJCrn8EHiMsDU4qnrEzszxcOdLiERwtgzhH\n4wvddZdAz0dqonD/PMhOvhbrANx2Z58pq+mgw9BAQuwpsFsgiJj40NSdr3Uy7Hfm\nvDA3WmOPu9eRE6zt6RXcP70Hh4/VFr97T+v6oNVERy8KtGQaMTGtc2tFnqV4sdOX\nXsgZvmdghvQjkVUwwCEBZjNyrb0v1iEHvLjLi3Nli70Ue/HMQQGU4ICznC3rgZ4o\nPNW4fPD4QFtDMz+xh5mIrKNA4TiOGwhtZxrEvpZmU3EmzB+fYuKvfCkOlemV0/WG\nCvH2Va6ejJk/y0tn19eBR3G5O+9r+172MPaKOxlgmSHWi4o45JUrV4VAZwARAQAB\ntCxKdWFuIEpvc8OpIEFyYm9sZWRhIDxzb3lqdWFuYXJib2xAZ21haWwuY29tPokC\nTgQTAQoAOBYhBGH8aB37kqB58Whed5c/KVWU7EaJBQJeTHHgAhsDBQsJCAcCBhUK\nCQgLAgQWAgMBAh4BAheAAAoJEJc/KVWU7EaJ3LUQAJ88l5DP+nccBt+Z8VWUPJpj\nosA3FO7VFSHnPqzPAFe8PNhllyYnhguaaFJZQGzhjE7KP84hLHINBQ6rSyYjOE9p\n4YwC8JjKiF3cNVA8sV87kYG9yh3ogBDO4RKLc5Fqj7dXneFxKapips3yC3iTjORU\nPCYphlPT5D+qoshEIyYvxU9Iovapl7uNwLSmxoFb93vp+7KY9ooCufErXig+x7Ci\nmy0NcrG9JEjQCdyTECcXeetB6LCqCNUdAsXf5yw1jf5rtdHOAFdLt5v2lbfmqwJO\nv274Knk7sHTWfTnB16SUVpvh8XST8pCgPa9U2yZiWOFQ14hV5pvg8c5cYtSbjpE3\nfecm2DquZg9LtKs8PafQGg0fHbQCcTmUF4L8JYW9T4bIzFZt/bF2FmUlE3ka7brz\nDRE/cTlqI8eaIGRr38UqoDuQZ9kgDgcA/n63jciVL/TkJ246eViPjuSUtkI6DCpn\n/IVked4/1yMsqgzT9k+QAMdLLMlVvNfHzbrnRyyh4UkH4MAnjuafpBkTgoMsDKcT\nwE7CcG65WIOcQdYB5oFNYkJqqrbsvw1N+fLiDmN6aYrP8sYJoPlr7LUVFCgJSLUF\nh2k/dZyp+Lj23p7ls1BWe63jvb29KRzo2bew/URVdFaiYj1XadvuQSLhQo6Pv0Uv\n8W5Pba/pFEVFK5YT/SEBuQINBF5MceABEAC3+dGa/TP26+L3RKpmu8Wei6SDkgbE\nfYQkxbd2KNVLPVSAyDP3XGgcsgYze+RyGGZwCEMgSpcS11N8Bci6Z5bs2OQ9Q0o+\njuO8jNbPvBqq/5q8gupMrnXYmvIt79f+ZXKSfm5fJSemRotLBnHZDGRLLF6QzObt\noi+QFfqWHPa7mBM+pjFIBt7fJjqQDreLHuQZ8rYdez1FrnNOr3gvmOyFaxsgjcQ+\n6RPpVvtkxRyVBi/Hjc4GLEj5sGzjzsMeFSZ52O0QXHTOxodZzcn/sbw143RJk4AG\nxzxCkNTa306ZYXKteTqmPT/b/tg0baR5pt0xmnfRbijxiyYFsSW7vmR4+fc4h1zU\nUCiPpp6BweD1QMyJCWOds3OBwm91z0qesOxfIZ5X1jUM2iQ7/ZYJ/I9sWPEoVMDl\nCR1ez7ihdhxeeUJRvjlMzdn8QTp0qUY7hcJRCrl60GwsXtotcxDMJ5VDU0/yQoJ0\nYa2DIXbCbgkAXQA+hvZ9z+C8G/Qa6cAuHuKGcaeb29HpXJU8upLsyjAGhXJUzj2s\nZX06NA8pc+DX1E03kd8/iVLzkkOqWTQY4SZcaQPafmcDlw2LMVGwTu0IwzFY34rX\n2O5xcGiTBLNSUJBld/+NPF33VQHnwKqnO7q9zEyruxGNNS2/PpjIvli628msWZj6\nXXeyyKQVQSFYwwARAQABiQI2BBgBCgAgFiEEYfxoHfuSoHnxaF53lz8pVZTsRokF\nAl5MceACGwwACgkQlz8pVZTsRol+AQ//eYQZMhPVz1mADAp5t+jYQ5sGUdhJsV5T\nI4EEwPGA6nyjjbnuCR4nfDc5teSVSI+24qvzfgkKTRjWojLWFsN2JSBsNZVzHEwj\nNS6lEkFuwAnOE2QjG6yKXoRLZvHiCw35Ep0Fs6fSVtiqedX5FcjURw1wx6PHyiHF\n8rUDBPnzuD/EQwqcLSXo3pWZr+sqYAu87G7bgJJqu+bm5g1MTrtAJw4/x6TrKrW2\nfMmNDSvdgaHiRx9adY33W4nmr+ShjxN2OVrAo5TsjO5kANOmKySDlfjpPoDAWJ2T\nY7acqfYGXFgCTKdTjMFdURveB1qIezR0P6Eo+mvtDMnaUCaw4mR1r9Es4QxYasof\nsyh0BkkoL6F1mTr2aP0S0b+WAcJ4SI4BUY1J6fBDccxUZtl3/h7jKLy7mGlG3WnP\npp45cZ9SHr4GErp3z8hu4HbaIVoAxurkiFX2Wd6QmkTcpRM1NKftkEZLW6pzrD0w\nI24uLT/RC+8e8xwGqvcPc5HZ5POrQJLknW+xnSDoAQNcjwcyD3oX9nH3dfPAV6LP\n5jZl07WrRfbElwmr/v/gKVVgaxrK3laZ/U3OYe/qGz/ntMvPPhkoezpP4hgNyTTj\n17mQo2WRyoHgK6bivtU7j8ZSmByctDvyWsfknnNFKvKZDW555O01TDNpChkpvzoY\n+SMSBsOPDf0=\n=i++9\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFM7JpoBEACmf7uB5P5QJ8X38ARQn+dr+/O+6/wzkKzUcoFvRArwZTcpdEO/\n0C12kNSpK2UkVMh4sorYwA8W0yv3spZJWU3TiIfCVryxqZaAWEIU+dwsQ0P6EAUy\nthjdQEs81bG6aN0dUqE26fWjGL/mU7BPtAwfzg6lty2cwZJP5zaNCl/PjRUeTKC2\noNas3M5dWoOqWq6HLPqnTEPHPlZ/mhkOfLOnJA6r669sQcml5R+Lhwd8wdJp+ANi\nDLW661MmaiA4VqjEXwsXKK0KISWftEgd9WGBsHH8rn4KdKj9u6EtnDlA3vaPmADZ\nmf7RVSMRoMkdiswFqEIMQuhTVbqS69vyhtByQs1fhriYrPy3OMeSMjJ/zNDCnHTB\nuKxoNHgMcznVu1tjz+ggso7Whd0IiXEaHXhF5ASWnJJa+xLxXQRQV2X1RXEK0bAy\nSX5B+NmxJRVY+ixpO5TVhQhzzzL9Ivz4z0odlvt5VJJIHHFIAWkgXRNAo0wgDzfe\n+jHOE7nz9uzYsqDBV25Zo22oMZURTBN87WZ1TFpDiORvvjR8QXJIBIUvMHAhG/Zl\nEkVopoNaznUOplnr/ToDpA1RDrdxeUAQ1i99EeBtXRREFgByFvETnVCkX/pvQA1y\nFrhGFgqCYBpN4IK0UcUx1MuwPBrfZxbL/cy+FhmJqutB6ufaJzatMQHu5QARAQAB\ntClrZXliYXNlLmlvL2Zpc2hyb2NrIDxmaXNocm9ja0BrZXliYXNlLmlvPokCPQQT\nAQoAJwIbLwUJEswDAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCVwQhpwAKCRAJ\n/kRzTreZDi0BD/kBw2x4mRU5CTcJsft/llfVXiWpxl0o3HDP8gP5UteD3A+YnN65\ntLbSN8WvBZs3j2ch9e4UAUe3msGEq1jRKya9zg3fj/K4F8tj1a951HUD/oyIAnGy\n4hoHBWk7WJwIgVzVc2R60sVSss8RAh0ALZ5GqyMzJlU6ZvfOZ8HEhFHY/O3KhUcE\nuCyAQ5nvKvtJSPljEdEGhtfMDv+9P+458Nbz/CeEJ+lvXbdRk0waU5yMPjxeedmE\nUMuFflkj1XIozqef/PrHSAw/oNdU7SS6aDLCbajSUvFwmpdCzjaje56FxnNeQVPW\nPC54RL7O2hv+0dQhDnke+Yn1p7lCKyo++cYPekzx4cMyisroaHNlGH+IYTIA2mYW\nOmK2diwInuwkJ3ofblmZ/Srvd1DFgdNX/y8lZw669LHL2RuYNE+9IesKGLn94SKF\nKJJmv3HJOLL3K79fYEPlAIMOz28Wy99qGl+U0oS4eo9dzulDasGGWw7JZ7sqdkyc\nu9kzNJtREgmaheQSmV76wb70cCJA+TovmOxCQbk/WQrt6z8kzaEX8SigHDVd5UpE\nMd9rbnLtyGMGEt7cIvcu/7gtH1PFEMOMAwE4vdb6urfPpxTAX7mQuGZJRvM7Umxf\nxtufVqbErkLKaxYHtyigVKCBHXt83RAuYu1P07/ODjdYhKE8mpQ53zw46IkCPQQT\nAQoAJwUCUzsmmgIbLwUJEswDAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRAJ\n/kRzTreZDoJsD/4vYyw9IchMrrJiWiKNuk1u8JTeIHNa5ONwFOFl65Wq9pwm1t8H\neTKubKmTwqpjoRsV3QlT9GNW10rp0kJ5hlmlkcaPx/q4VmDksCAhp3NyQI0p0h53\nYBzwZKssNahoryPdsYIU+1jwJ/2gQx/1YENC7gz3iUXgxXNChQqZ8Qapf3gVUufw\n9uS2MjYRWmXAmSSLTc4nj3SX4RnZpfTaAvdgD9qh0zulIK5jySpcQzliBLPCE8Ap\nWafWOY1p0mNcYUGD36GtjPO1mwyUWfVzK4VMhrqnaAA3bJ0iCiK/kqNkDjN3T7EP\nxaurZCvbUwZU9p/cB4JrnLk7k959uxpBSBeTac9f057BjPFsyLAZnzmlIfA1XLq4\nVtKL5qvnay1deRYpZXFeK4QDASymKro9+QY6MV2l9/TSoynu/jYIeIFGVXkD3kLU\nKtI2eKxHduseT49Ax9yZMzmqYUI0uCtSJvX2eRC/pifPQDChkpjDQBp4ryLfOAlH\neouLE9mtWMVJKvBykCaYK5zzJFqbF6atPsZ6/+Nwgur52pRFI6yrE+t06BzkBkcS\nu0SwW1IqAVctLViiq97o6VvYj3nxC0/EXn8OTyFx13nW/HKa9I5m5UO+wzNJl15Y\n0Lk48RPVWmpBwPkcAWMtGc3TDCik3FF3BziSYGdtkUwPtO0TuXOzS5Ats4kCQAQT\nAQoAKgIbLwUJEswDAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCVwQhdgIZAQAK\nCRAJ/kRzTreZDgATD/9g3/UVBAhCgKMZ1ELw6XZItFExCb4I3UFQ6J87XaRsO5Gq\nrh+yi0AcWnCFNCdyg6+Q2utEcii9SJxroGy0SLf4jGy5/hDT7CBjhwCTZiAV7woc\nFBhcxpkkSsWRvdtQyZiPPao7RWytJ0st5uQFKTwJo91A/iVxhnOUCMZoTmS3D3GP\nWBr9KEAOdbpIsnIMvLOLme0rk/lWJPcDANxKA5TG4ep8CY2os/Xrp5ajBdmgduUY\nuksbVyzSQ4bk8xCUlWUEzpNOvMAUetu9WOYAuivfgz6gUHlV6CqxcwhXxpmjAJIi\ntuVhX8KiSSr3o5FjYtBcBLZQSjnNyswht61ftBWLv+K8zS+Y/RELjGSLLvnaws++\nv4QOI/7Fjs9cKsETH9Nfe/xKp0VVxz5wyGvYeVmwhkyhW1Wl7YdGz9BF4AmdSMRb\nGYeyY7VUlB2A0n2XOtZ6Xs17IYNSShJPX+FyFuD6FaY6yClhTCdCC7BOxkAPzJVt\noCuAqRDAMR/BLl0D1xBwNMidaSnaVXzt+QoamHVQSKf6DZAG2KfocFHuOP0ybFje\nwEVYqB/SSvhB3n/kLJGZdO/enECzVvSObcZDqUkO3EmxBeEhGghkv4B1bRaPMQhI\nVQbdhJQR3kOGOweGW7+tnsjOOJnCU08T9kqGf3cMhTFBGyejwPB0nAy2xWS++LQu\nSmVyZW1pYWggU2Vua3BpZWwgPGZpc2hyb2NrMTIzQHJvY2tldG1haWwuY29tPokC\nPQQTAQoAJwUCVwQhagIbLwUJEswDAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAK\nCRAJ/kRzTreZDjI5D/oC9tol8Gz+AeFlUUnI+RRY09JZt/+Zz/DIPkWC+txOumS3\nFR++get7PJXtLuyBrVKY/FOA1+hCcdIoSakTqaN3GawSo9DmFM/MlAxZOAZ74aqU\n5gAogWlQTUpUB3UzE+D0fo9wblqczosLYT42ILQ3ew5udYbCWIO5LhSVg2D3Zz/g\nasFpLB8e+U0i4hVs1F5hUWgLyxVCMbvvf36bXSExygDgZCUQCJwHfzXAIiQYwxU2\nI6qs7Uk+sb+XCYLQ0qUdTXfncOQPsvnH3Ddb5t6a2YKSm4+ReNKvZA6hORhyQd4B\nDIfTxfkj3T3rnZGnyz1O7UOcesqP/Njch9Vb85jyfUuXwSuTVr4bNliL7Z1Ptw4g\nmw1/ptZVQyc7rLgQCSr0eEJLvgk9jnIzjaTab9PTMDq6NO+X4Cpha7bLDnsQz6fN\npNvKqwNeB47kR9yNAH+CnxoVN3C+AxNRgdJ4m0EozxqedenokLVNmE2VA6zjTX6r\njSGygFZh7FvPiQl0tzMZ+EoVr+Pqxt23FTCgAoYtG5vv1PJRYiBJgd3fjmuQhVeP\nN6QKH28j2wuuubfa0vYoSyQyOuvOKpyvhZi2DsboT09VOFi/RP/tPVaZ2n6y/r6x\n1zTYS3/1frifg76iO+OI+nd8wZcZe0XuZzhle4947Is3NDwMk30MtUjr3Pta/4kC\nQAQTAQoAKgIbLwUJEswDAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCVwQhpwIZ\nAQAKCRAJ/kRzTreZDjdwD/9kXy21TxUzWjZLTUUQcztwHV/ReVr78k7iEj9cj108\noq63U8s6/5mM3Pf4Y9wpdGlxpobUzKssNkZBuF78v0s/F5Q8Q2+/uh/g5zaybwD2\nrKQi9DbfMUDSqp3yWkM6Vjh/QTLjtg2wUmHHR4G1ra4+1kVSRzK75DG/mcRUAaFx\nhitamEcvwD6mC1hAO4sGoZZHxfYS7KisatEEBZJ/49wuL4q+Rl9g+bBOgzEzsG5P\n1o20eQewpbC63LCTo0UEv1Ue2wH5ks+Um0Gixjg7IaVpptNnFQUmBaxct6yOXNV1\nrET1MlTIHleF3rdyKjyHhdlfn1AGuKQGfyrptQ/tvsMNOLOQpS8SAww80LTTLOdU\ncrKeHvuddotz5RR04aczncnnE1LieK83ZZBWm/sRfhoFm93tkW1ju3LqrK3jDSiW\nW9QeqiwYKcypIHYVMod6Fr5uVQhsMcq5iP34LTwn4VeluTK2aJ/SieAY2nOmKrq3\nxCTSTWPe+ze6Xuvmw6QjCFUwMyOU7NIIXLYnELzDjUz6rRJEPLQaRoJSeQMXcnka\ngtUhYpy8HEbfgYwda4DANPyatvxO87THSnFgx73V99+IExGjWZ5VnB3FYdLxKEAE\nAiq7JZ37x5LcWxb5A0wti6UmrI1pHpTm21X8c6qRmttakFfWXw59baXRv738+hU8\nQ7kCDQRTOyaaARAAvG+PmIRpCu8qls1lzJN6CR1jfMGFPBpG1EZ+do4NcrmEuHCT\nh/Qt0/4igDLFGBiIyCQ9/OBUF/lf7ziRFqN9mztC+OCx4ULWUsTtu2aZuHaeIxlS\ntL0Eze8NKL/BL3u9PJ0SvvbhztEvGOv+hMdYgRH1PuLPLzizIOo1vg+a31P8vzuo\nhW2QyVlw61S5hDOclYkDUfPxKQ+u0/fvMAUXBAccGus3ns4d2PaeBjqiuSS8MfCw\n66/5j34DqS5avJfsiR0h1c+WaCS8GPExOPiviO1qrTXLhJw6kh6zqHIoSMBcnGOU\nafU2vj5I0D7LMpjHwCEIWgceOUmRsE8m6eBge49qENdXVGELQgVfvHgfFEEKKORK\nHGX7khLxVPZL3ZhQreEPLXm73hpvjB7uBUBKMaaZYOHothfPdUd/JXRt1ZQ24zCS\ndqGpJ7x1rIJWWVo9EM7Qq0wtvu3g6tvLPf8yoOBcQ7Bvi3BYYOKpAAZEGad7N971\npMVjeVYJvLb1595nImwbdO42YUT4wV0oxyUTtx2MSRr1ptvviXNQrkCo74Q0dCM0\nw/lwR2IOGo5mHKSLBlxkBjTh01n6Iv9ACWGAqpwJvtZKlB7Lm9gzXHFM2WPPJ9y0\nnpRDGS2IjtUvshrW7XtiwjtM5iEBeCTslhZHzpgBDv0PUGHUy9+OHtx9LlUAEQEA\nAYkERAQYAQoADwUCUzsmmgIbLgUJEswDAAIpCRAJ/kRzTreZDsFdIAQZAQoABgUC\nUzsmmgAKCRBF9e69gT2ujoIzD/9ZXbiKvsx2DBFgX3QXjrMWT1XPc7dv1x4IW25b\n7CWq0OG5WrDIgJCbuUfp57tg7C+YFLz5jnpK5Ht8uvyKHtkgbS0tIuNaSrDm6X5q\nCxeRhtyQKKjoKSnK+Fj4GeSo/hWQ3jJ0CCDxQNF13A66Yg/yD27apa01f9GLaEUI\niEjbXL6XgLnQAwCcETkxHBWPlm1XT7P1OEjLoosWRWUi722rax55u9R4ucy3mT7Y\n3DDIbhnJ5fBgUg/4xc9F2iXyJqrYmR5x9Zz45CnF1e2nwWSUSdHQlcjPbiWZrCKh\nODglw3Mk0wmWP1fgNJg8TXHx2ZdtNIK3SAJoVGe+DHEaTwL8o9Hy3Zrd1ye+DWhe\nK6KEYmzn/+ZMFjaEkk4Sm6cX3Zha83z7wUtT+jLRinyf2wquwVGdcJw8MUkNhv19\nVPbFtm+VziV+fbiOimcuKsq6eF1jUiXSosOKh6stc/+h+J5P00C0OSy+Ku7w9BZ3\naTe3iugyGWKHpAtQAt4l07ChUyKodPboaSMXiI+XP5co0KZt7FghKC7Bn1ttJDj7\n0IgbqNuuiDwhaHhGYBxw90RpgdXO3+wbtg7B2OUmBmLzTJVNWI7vqMzIvaJy0ZCw\nShNSCYT1FZk0k/AsOixe5Gbhhi7o8DCoAZC1nM+xHYr04613NlPs52bqVk8c5TO+\notNgD7UNEACQdyGa+slpdHMLVrdubatBVJarH3Wd0vUH3Ba5Ir9NjSEpiijRoQef\nbH1wSUV0/AtQY2LwOzhufFGK5xNrOVPoPTbKXN1fUwCktsaEGDrv2Rpr/TiYuqOs\nAE26UefK7yvKab9nEVbBPq6IQRl8pSEqmxbKD9zBbpI6+2WLMW+PnJPWz5f2g3Px\ndtFpfeVeq0o22+L6sdGHH8QuQq/6od7fSB1tvHxzPXsuw7MvULRoGnqh2f336DzM\nohBbfs2riI+Ik667uOF4RrLNRfDVRb5PiDcTAuHGaDtJjUpBlrG9WNZlwjo9k3Wh\nUWFPha4ZKiRIGvTh+C4wJmJeR51u41OlQjEF4MJTgZiGWZSnTKbv942FvXQpKz5D\ngt6NaGDcxEXOj5ohP8VWlLZel8H8ncoljNEcT2y+SU3C8o3q0xzv6jTlZR/pi15E\nxkZ4mf7VQdPkLwUrwp10HMRt8pxCBjTnvEBwMVLyq1fo5z3czv3LiWW8RBYtTBZ/\nsFv2xRcarfdVeGY5r7ZKRhlkJj6L8x96Xik7D5b9G5SiIEi6XX3ZOIaiV4mDfDaV\nFuIInPdrU0Bg1jqBWQZDqjEvfRHYIDQpd3Ahxbv56J02tl6s29gMT5dYRFE7OhaJ\n0CCphsH66qcPvWImsyQ3OdVJ7AU3fuFRFVIgQwoohTpKKCIGTJ8u1g==\n=NfOh\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFcGZx4BEACa92SjEniMQIBdb0btnZRu8vzOGNe+ndzXIWPyu2h+p0xZ/2JN\nMDQW5hc8USoV4/rTssdqDOqcu3AkmLtZi14IaRJ1TQP6Zb05I8MOEm58WXXn7fSF\nYJwhD3LDrAdAHAs896QvsFG7X3Rw18+j7RpK/MPIXZDA5GS3QPfrB67q/J3vvJyQ\neNz9jSlnMpkNO3KQYvUuU1KqeBpMXZtJi52B6FQY7y3H27MgjmJ2EEX9f1uNaxUw\n0SzHCJhKXFjAoeKIwrE/MwcbSks2Ax8lHMlLAgaio77nfdvrEtHbXUIbOGlY7gT/\nPzwav9ofCE3thvfTAzcScIENgmRuun2PEItxAO2ysqzpnj8cbdknF+ZVQohpGV1d\n2ECyYLcwQLWiJd+UR/rr0IJ8KvJI0dMxZxul055JF4UqU0O98BsRABi5GiIg6zgn\nPZm2Tr6Um90rPjKcVgJ3DgxeGkeYjvfxEj4pX4muZkouJdi4BGnvUB/pkKFaf9pl\nyx/hioMMF4tywify74+avPseZDaXRJSxqz+uXEy8VApN263oIiJAWiXWwPunTaWP\nnMBoAZcJm+2im7NwB8x3jxUfK9M8GcsOOUT+grpe0OguLwH1vhYSaLg9rlpjMBdb\n3xF6X7N6/h8PaHGUatHrvht+0V6NchmtdTVnJzOXOsI6rBBFc6ON2Yz7RQARAQAB\ntC9NaWNoYcOrbCBaYXNzbyAoVGFyZ29zKSA8dGFyZ29zQHByb3Rvbm1haWwuY29t\nPokCVQQTAQgAPwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AWIQSPzKE/7x0M\nLpEAjgl3D3qaWuFWAAUCaTgfOQUJJP27GwAKCRB3D3qaWuFWAOH+D/4lJ0ldFrsm\npt/w04XNgwRajkv1LniHMmzAss1TerrgrWALMh8A8rhxkAxYekcAYghGQEXomtNO\nj2hBe95DmQLhFob7INy6uaoRXcLPdHYm7K7zkKjOpMD7Hqni+ozmU53zrI/Myj+A\nE3kFP199JnL8Bj2fnJLHVTsdTxSERuUkLuVmMHjjqKRrbmSn7x9uysXhF6yFD/Wt\nML8A1pFbTn04VO+pLNK8mxoH+TJ1g4N8Zi8B0qzvCTBTkNhPrKztNlQWmRuvWiZ3\n7GADTGdanNbuiM9sUt/vY4cz5lRDZybO8Xk1MXFJ6ISrjZWPMbt6fF40HTqj9d+c\n0BpWJKulOUWh8Bcna4HFv/EKODoVteSshDnixqNgkOXhooM87TnBh/1hivLLVj5j\nKk54VQ44P/f88IOs+TaUCxPgj6+ww6+dWpxyM5S925Gu6EbVDUnkjPWPQHfcVUih\nKnA1pTLkqnA1DyJikiyBDXeGpPtyqibIHFnLS+DcHwc/dhnXUMfzOETUf2VnwkmD\nxBoQmIf8g6o3ggmhIAIzcB5MxI7RBteLnM8D80P3X1eeRPwIJaRC0zL9WIuUtuON\ngCr/SXMkyBBQCxluMVVC2U+xH2Y4QnGXIkjZJzhx/XdOCg2MFe48S8bxT4HU24Tn\nMmshf7gzMKuWs29Fr1NNXc6okhP8RrL2ybkCDQRXBmceARAAysxKPzZLnWG+QZUr\naQHUoYndRG5Y0toYHvCk9mUm98+aRvxUyG9VwRTkQzWv2e2yL1kX+Gs36c47XZNo\nOeOwfkDtv7QXDVp/7h2LSFLaXYg+We0EXdNAm5yjJRq7dEIziJgJQOcL9VC6jjWa\nfk578uMZOyQWdcAmcuzT9aAzdz1nbqVK3gBOj1pDSIK4OxiI5bgsLN2SE8vreaFQ\nqXEatBw5Aik5tU00Suv/B7T8oYi27/JZt7f9+m4cSAlrChyRasF9ALyotQBpQarj\ncWuYevc6cmLsh4d5p15tDlRChu9uwHAZ1mZzruZK8vgeWgdsIZ1oyDR907u8kqOh\nUBC5f7VDkw8tWdokhAraNGYs4SRYCR28myxVSTBl2j1/uWXOxBXNjojMql17bMJs\nbli+ajCNBJGuOhgB/m75DT2Mt6rcuDE2lc4yQzih7C7f46caEy8k9kmHMDLYNtOc\nJmTmQ3dkaOTdKTcRE1EzyWdRLEWeXvDO2X5oZT0wYygppJxPEaLU+ChWrU9hLdpd\ne+fsSyQMqguX30hLhXz+HDsQqJF3LfQs7tCH6nDx5UqrVNIEizBnuS/DolXmgDOd\noczZUgeGtS1gWU0jfDX1KEdoeSQJz87hcA4FesDryeQpiyTAdwe9JlMI86K4ceGw\nksXl9LeVNJn84CgcfPKuIy2+sGMAEQEAAYkCPAQYAQgAJgIbDBYhBI/MoT/vHQwu\nkQCOCXcPeppa4VYABQJpOB9kBQkUEuvGAAoJEHcPeppa4VYAXckP/322cQ3GTB9x\nPGndr7kbQrEE5z8fhatMVk9YlamujoWYRQzXWjmhK5wHuUIQur3sGspuAGLPSUfn\nLK1r6qPGp719vSS0MVco4ME/qR98txo47/Mjc8uBjwWpbODf0AjEjwBN5jauXdi0\nw4hu68+QfbffAqIu6libBfitjHrNT7/DnwTLhDvlHpLqkKgQutvJ1Sf1GBQ9iDbo\nIu6hd+7QAzvW50FZE887gwOBha6F01EJLxqy1cwmQkT1QHCiLPHv/N9oIX2uYsQD\nUtW+yuRkG06E5at0fYrQNLksQMmsVU8MTxNMYJk7Ac9gTn9den71uQzt2QxaYBhA\nQLkAMUweFzBPlNU3IDirpYsz8+0TT0jsAIgNGJ/r09pDpgyDsnyuwVqBDLj7zWU3\nCaNfn6Es6/Z57fjnd8OD5iC0J/2ykURnhz1RHL8SSikOmkLaZQps4SfpF7PnuGHm\nry4fNFZrt0YeiOLyucBAbHMi02UpGd51yRvFJ9EK63JR5/orjsH1vw7gI1In93zs\n23SWnx8JL5l1uGlkJ/PN8LJJI751FeezE88wD0aOG3C+sMvuZJdahOHlGDEm7xKR\nBA+da9/uNqbKAfMzX3K3eto9RoeBQeLqgYouT85gHmZLeD7kYxI9NnU9pxeeELmF\nreo3MNn8Ye0sXg12rQIxV/isDIk6zg6GuDMEaSAoCRYJKwYBBAHaRw8BAQdAq/Y6\n0uQAJXs+LO3yhZJtKRbow22NHbOKOsY/BMFFnOuJArMEGAEIACYCGwIWIQSPzKE/\n7x0MLpEAjgl3D3qaWuFWAAUCaTgfZAUJAfkq2wCBdiAEGRYKAB0WIQSGyNdGQuZ4\nRvjhIChNqoDR5ze8nwUCaSAoCQAKCRBNqoDR5ze8nxryAP9IiA8ZTV6GQ/kpwLJq\n+87o+HZTojSYtN/ZfDQrPuHHFAD/dkGOXiutQcEM1YKDTTTSVQcdFhPFLChIGtoh\nExpmYgQJEHcPeppa4VYAp54P/1Dk/wLnuCB7XjNeIEA9UdU1w6M+cpWuzSlaLkjf\ngL95r89/SG3n670qNh54mTz0Uod7QV9BijoxNopbz2daPNJwf+WYlxk3pmCngXwu\nck8efXwgl6C1NrnZiJBvtQO6qXabmqTs59PumLjoR0i43knw8iaYQYdnuKBFJ6K6\n5xpMoYJAzj1nxHAESPhcbTe+nRPnGrfVwQ2qvK7iSL6eU80emHOWsxPaFo6SA9no\nDvzWmSwZ6jmFJo43lasrkLW8QH+8OdsORc7nBm1J7hXk24KAIHOrxBm5Icpc89XF\nxCJNI8fEP/WZJNfEx61m25XWIDuPz4mTgCaBHvrp+6bvXuVC8QiEFhqYGPpklN8G\n/cYG9OyDPOyTSPjfoUPYQwNap+SPxzqYIg/is9lqeIsMEV7Sbg8FLGlhP52sxnxR\ntrA7kZMfXFphCC42PMojJEBq/nlmXC79G64Q3kbmmDZ5kbzmYBtoPSEou17MGGCi\nwicnOtUO/XHct5/Wfkq2z5jYuj5Wbe5DNBV/eWp43uMpxNjkmfj+SdJtpI9MJ5B2\nUwJ09JwwPNF5B1RasQnXDLImINEoLOxixNddwk+2hZn5p7YwbZ02MznDaWVuiX86\nVpZxqzy2y5PDphbf/Rbx4ePeziYIsa0PRyjrS6fPu5QUV/EBK2V6nibMHsGuSfin\nR/5R\n=+ahi\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFaVjpQBEADt/ZC4FsskPNkAgLq240K+CjPJzq/0cuEyABJeAVeYWJFUJRcb\nzNHBVzr85vW0pEKJUGyTyVxGV1P9VzkqaL5RRiupViwC5lf48P78fCMgEa2z4LIt\nnlIiWnJ1UlDeTvLc1DiLCxWgsYTRRj+x70/sL6EmH7laE1C/5RlnkGnuxM4Vgruc\nT1UMHsZJE/kefPe95NhzJtu+ii/v345ZqHhsGPyfeJYV2CiS2iTIqxvyvrlidrVw\nhqird1CKLuv0++/FY50O8Tq4xb7Kz9tIQODtCSBsex24sB2awHt3RdCwmW7d9F6Z\nBmWycKllFtuXjNf0bDNCJLctVAywUK28lwjrQw86y3VO9ktmVCDSsSBJd0TbhD7Y\nUnvkanTJzWhF+vCoQwarCuD4ZdaWBvlLTIFv0XjJ7VA2+RlwRuYvTN2PlIRzLvxr\n4+JiIiounGnBH5WyAVxdu6enWsdIKCImujm0JUqvSXLJtY/mU5LUIyaGe9wBnODx\nReStvNPCWaehgC83NHMkO7t+An9zDummDZF3mzwUZRO8NXPAowmw+X+Yt+47jUOA\nulHXarjiRuom0InW369JJ9ZUmd1m9pCmoQ+V/YPaQ56y5riIz4W4HJqAaqksh4vO\n0JMyIr3VJjBDxVR6QA9UMHV2PTVUAFA9vYTuv9xTXV3yHJFewX442H67WwARAQAB\ntCFNeWxlcyBCb3JpbnMgPG1ib3JpbnNAZ29vZ2xlLmNvbT6JAjkEEwEIACMFAliQ\nsTgCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDnO8ZBzBH0yJgDEACb\n5LGFZogzl6Kiunk0w4hjNg7Cue7/M+VGo72IcPg53P/36G7Qtd7kMRpTIi2CCFpr\n5jLhb655fvMYsrQjpqLDXrqElHA+Qgv71Dm8CTO0CZb8estNKJ47HS7hwMjOe3Zm\nYBVro2iP/4sl5JEUwhLO19ia4JCcxO8wp/T9ai6merBrh3wykm0LO+VFfcDhN93K\n+TuP66xNULybRxPJI7qi3A6ETzPbaP9o9yHpU0B7cCkYDXr6c8S6X63aeTtoNOvl\nRExDgb64j7mkqPPNueDVgTRLJRowAT63ZyxM0UtlDYwAtwOyys6bbG+es55Bo9vy\nNWTT3GtHJlL8WqPef66D+yQ+sNdTmvld4mElfhBmEavVA/k+Z30Dyu+vz1vU/xo3\nBVDzjZK9iLaxGeb1EYc9QoR1JJD/RSHw82bYcLFVfGkd5LTPWMwE+rTYWpwVszA0\nHPzDJuGaOCHYfFNZX/6y6xCA0dEcx/HeLlvE/ytBhe1wOiVDuWxZOvhOjMFd6VLT\nJ/6XJoyaDbljibBPC6Bo5Gk4yCA/gwOLW5lVYXoD0I4kWslZCH5QBYztW3M6MsVP\n+id0DXjy4i6qd0iUnjwmvXQp5u67UQmdxsEDimyjC4wXKQrUAImjF68QrROOfNCb\nAmQ4nz6kETKgPqRkIHIYnzn0XbcWKAibnZjcn4jJLrQhTXlsZXMgQm9yaW5zIDxt\nYm9yaW5zQHVzLmlibS5jb20+iQIfBDABCAAJBQJYkLEeAh0AAAoJEOc7xkHMEfTI\nKr8QANu71NmLwCVUCCT0PW7Ey4sZitKF46Vf80kpVCbIwEvOnigs2JJKZJxSXNdC\nNHEc5/XakXgYuu9BmjZXHGga35ZCUvrif8hP6KZUzyp6we4o4O0+UdGKW0W0rwn7\nD9acxfICrpjhbI5iXLiKVM8C2Qo9bjHXZ8i0HbEH8kQpFbyh5YV7gpclqrWEiY65\nJIA5t+SQL373B0Xf0u7pTwoQI4S8J+BpDbLEK9PpvW0NCNQ/z87cIIXPT/rpAkVI\n2r78abO+SnFzGkd+WpLu9Vm5HiUsCGWD2lIfZASBqcENyDg+blxmEmI5wBh+PEO1\nmteYBh9sXkGhlkgJWa/Yrt5fNV29O/uaROPKdpR6G/Rbs5NZax1QcjWqIC1sr8hd\n/N3p9w2q3IAK1YjG1ahwet2Rl0xL70d3/QUZXdo+fcCnJgOx06aEWBJQX9ualjSN\nxbzxvRAm3PYJeXkgiuapN+aBZYDs2YuP8XTPDdNTkz80oG0v/ANUcTN+IUSPa41c\nWsjnBrFu2OSLC8YuwBvdMgNUF0GEpBY9+UfL+S/FpGtBflnkeE0kq0UVuT0J8/un\n90UHRU3sUMfUA1t8tQ6F0DnOAjb7Ogtwh/nhjHkwP02VJcyu6jjHv4aSp14NXgnG\nN4Kl4JuNcYRknHDMFwyNH5D2cm3CVT8UArINaCbxvrPmkHwbiQIxBBMBCgAbBQJW\nlY6UAhsDAwsJBwMVCggCHgECF4ADFgIBAAoJEOc7xkHMEfTIecEQAIi4C62S+o1r\nd5abdaMfnQyTGC9ynWjH1RPpihRy2cG9HuVtklAiyu0FtX4MzA39nvqy6tM/XROP\npAoN9XPicvbORr62Vq1YMNS6Na4L/BKOpIngNmcAD2Xqb7Hy/f+z8cUH1/6INEEa\nM5Zcx9x2h493JUVbRls8xx56uchMD2Dm2s195pdQjVg9U8T57ssNrA2MHY4RRxw7\nJRV5Pettmg0k6TiaaVo+BjAbe7rke+WdHJNefttCsIG8P4/rX8rhnFWJZWpBjBgV\nFeL2iSGhxyQbKcfGhrhsWeiiTg/wvw3epiH/cHSz9e8cXwCBtOKZujv6STrnl5i0\nbuTHOKSz5gZAp7QCUGoXTO1otWMyzBBeRiDL3KHmi3mzGZJGV7VkmT8D7S8mCFV5\noT+j7zzoHNPhiiB9ha9lfW+r3S8MypfpGFnNvjn2O3YvXnwA9BVudaTSk3NQAxS5\n2PjNYEazsvNeOjTueyJwoBEM7+tq2TBXny72B9h/bRl68KGkVuuHha4wKHTMa0Vr\nhaLCSzFq6TTmJmBg53BagiXKORHihTV88666Uoj2oEIzDN1L7C9wjN2G+gRCjFyT\npb4N7NgR/FZQbhJFx31rj2GAmLFv9tkv8Ow7BMUarZqvAb8UJEi+lwEOVrN4lRvF\nDrVZPEY/hu2qVrkgKUcd6v2gX5cSQ1a/tCVNeWxlcyBCb3JpbnMgPG15bGVzLmJv\ncmluc0BnbWFpbC5jb20+iQI0BBMBCgAeBQJWlY6UAhsDAwsJBwMVCggCHgECF4AD\nFgIBAhkBAAoJEOc7xkHMEfTIB1IP/jd39peJKGZkKeK7X4fUB6CmnxWAWX7aTe4c\nZA9/Rpbts7O6LRYaErlabEqYW3RUXIiuqr34Z/2sw9JGaPCmXWBP2d6mwSaCyJW4\nd8+mrv+BzAcoWjdf6XdohLCNp/9XwAsE9Pe/i4I1oxLWYRsnlJBEK8ANpseDImiw\nR4D5HLnelCEt73Jhl0stDtlALz+4Ex5nq0PL+QYDKE6Ol6Blut3Zr0InL77PLBHc\nfl6CTKPs3jbHZVS2zve8Zz2iI73mpqzSkSqB5ZZmdPCof5a1d5Tm+hcfu9VG4xPA\nSuAIGuB/wLQX9BK7t18LFH7oPej6pn97WmkchnO+SQzhVxG1OKdNNCA8/qikUAxH\ni+TNz990hQU8AaUR0LPcmoreY+QZX7EJjn1rpa4KKmxigNGFwiTLqScBekwpIv9V\nDOoVEnPJ2MjFfHTXpFED2btey4bKWneisqAgiUxLcBv8h7ibBG/TdgBxmKzofeuD\nSLRZH206wfMhff+YAqADF/Rg8CafZBMErNM1BUNg3IBgwH/GKqsX5Qt2IyVQf3NY\nAkRXZUHWMqB+/TEON3gAkd7ZvYDP1KEINUnVA3xDwztA+bP2tlBnJdLkBis/nOYF\nZtsi8AkityhOzVC+7dnKw1QoqwuGBxwJgX9hmqgtETJw0HabXEPosyAngh57iDVF\nPSaK4+sniQJLBBMBCgA1AwsJBwMVCggCHgECF4ADFgIBAhkBFiEExPDf/06MGoI2\nQJ0I5zvGQcwR9MgFAlv0OAgCGwEACgkQ5zvGQcwR9MjstxAAxesRqumspWU9ODeh\nJ9KucmBGNecVd7Q3+E27Wn4zZcoHu1X6eb0bu9mbbF6CCB0srPqJnsinQnDZP83I\ngyYTHelWIeFLSW80heDZB/KUW7758OqAvL9SahDtbrDqWr5rKc8JNOYqpBdbhCsj\nCyHrtZwTkPOgc9lV/RNaijbmz7LwH6aDCofsCXXsjq2U2sv8yq3DQN7aawaNZcrb\nweeEvWLsMxP+dbt5HQptp783i3xxCmgG3KE/tB6dwhs+PkWhktnIm8xeurZGCaCi\nOTH7oGJzTWOQF6fYLZfeDW7Z+aTAPgnt++c5V/fWP0bR+AfH0Md7C+/lYbORc6fr\nXmjjpsDid4D2eBZpkL8e+Js5v8IWQX5E6Y9hxoECyRe/NXkRf4zWRfrl5xvucKSt\ntN41EbTxjmth/ay5ux1d1NmlLJ4gg+Yh81h/g392w7UPC4U+NaRcpFIMGPbtZtyp\nx8HdkT2NGbDraF6azEkLA2K2ugbTfJ8VwZinxJR+K9iT2ROfAmYuqOvR1j9koso7\n9OnsrIbPU+cfqav4GfIaAtjBq1UnayMZ/scldC1e04srUcCBypRrhfjgwscAQV4G\nyuLSj2xG66BDB8zF6VXK0vaJcynv3GrIWH4pdYLX9WmevlQrqcU90KzuG0S9UUJg\nfJBAWWNQg28xEDcB6ChDKdmb24yJAksEEwEKADUDCwkHAxUKCAIeAQIXgAMWAgEC\nGwEWIQTE8N//TowagjZAnQjnO8ZBzBH0yAUCW/Q5HwIZAQAKCRDnO8ZBzBH0yF/G\nD/93QJn3CekgK+dzYprVC3jJ9vbNMAmcpReWi9SnmGfxFnDSS9tjSRnI0xgxCMeV\noPYjP7m3sVPgA0qU46sGQJ4gQWiIheM/zy1JsKKtp0sJNN6WH8jpfCKkq1VaOGU7\nkLbOxmVcsaO/J3Vzi+o+4GfAopfAkeSiuisKmG7YmfOp+Bpj6vADMs0sLrCPucl8\nloi0CA1ph3Xh8r8XKCkWrih1SHk0VXpCgAiwjMfx7m1nzmpw0Adhz4DmJWna6Njs\nnyLPbyul6niW6ddKsijFZ2K59mkNLknISUuATrl+OEQkBL+Ji0dgAGBM/jdNLG7h\noRQYQZEZoUedUz2Hr9g9VNMOO6tTtEUlADV+mu1GSw3AotcZeti3OvdZRa4LShpe\nU6Miz0qk66k+YlOHl6n5UdwpxnJawSTHhUk//CEDFNyTosOtt9NPmIob4vayyRbx\n4ylttld8pdZ02cyQWq+28+ojng4PvPzWYb4J5kJayHURx8AYlZapYH1+g3pKzXsL\ns1F1gBaYFuFpN7ODJxgucP7kWgD9KzEH2/M5qCB1nY6xdr5hzBYUZqKtGbwIRZWI\n2mYjqGu8PpOgYoEf2FP0qa5ib6MXrFqIIo8XIDwMUmwA4KL2B+EJOagB0pUew6uE\nNNZESgJHS9vT47aNPtE8q12uovCBFqpaXoRqN/InPR954LQlTXlsZXMgQm9yaW5z\nIDxteWxlc2Jvcmluc0Bnb29nbGUuY29tPokCNwQTAQoAIQUCWJFrDgIbAwULCQgH\nAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDnO8ZBzBH0yPLPEACtalzeY8Ycz2Ay4s+D\nb43IQucEzWWA/oO+G8cmIIyTgO7uhyAS8ArN8Wqbc5WLHnIvZw7D1WdX8wgx0Hpo\n1hzJRX1XmZSvZ3N6so/QWMKFCNXkIGTBjhWH+eoJ2w0hzhz80pkH8NQsw5lx3b+I\nf+RzE9NEP8CV4zfxdTKY0X5uLyIoB0XGfHCQh4yTra/aqaUXTEKsWINiiwPy8ulD\ntOHIZKo+uN2Zr9FBsJQswP8n62XfS3ig8O1l7dktjNALJQfCeiPC2Fw8eJ964t9h\nt20P4nwiL7E7k7B6aiHQFAoqkBKzErsOZBUJXst2JCRGA7hbDXxa4swqvtScjZVA\nERigDVG4y4i4G96Q3tSwpHQsUE5R4S6XeR9scuv9ElcvV2M2B0d4EVV9EyHdeDEb\nKYAv0yhOhrznLuJT9KndMVsWyHTtGFt6o5pAqMgBjdEv/ONsdUchG85UoLgSHrRo\ndHaaFXPbXkjmqLaETvYb9S5GNW1K6GiSyHCROTPXoob2SFX8wluazAJieYU/ovN8\nftyH6K7HWwkSmrXf0//7kPEF7+P0LvSX4Ri/X2zfa+GgkfmIK66n8Vl/+YXSZxr8\n3Yf06k16Nl0loYZqYYkhQvdxKIyrXKx4zLiIU3QOKWFUy5EvAFwg++i5s8YvSvxb\n72p5tlhZ7C2I5/zzZG6+VPFEa4kCOQQTAQgAIwUCWJ4DrwIbAwcLCQgHAwIBBhUI\nAgkKCwQWAgMBAh4BAheAAAoJEOc7xkHMEfTI3RUQAKagnz10ZI0WUXYbQlZ09eUG\nzDzxA8gpsMAoEb31+vo3bwFJ8hlErSkWe/WsHoaF7y0BiqWlUYibdpKrdmNnivbs\nj5TTb5MEndP/kKYsfKQZtbNZwP5ITU3lKVEPHCBZbDYQWKPdQBSq/6qvQ1D1/lSr\n6VEhML0p/XbFy9st22jMqTWiSEu6xHyOf7t6+niLcLuBo/edR/+jOEF8qizGYZaU\nR7eFtRkWD5I8y8sPWtjjiRmbnV/1YcJNfZKDNu4ReVzXh9iJBt3iC8HY1nUFo2ic\n2bZ31odwpGLrfebHtL63jyu7BW1GrlQK7NwrQbgFg2ePpNCv62Pzz+LUkXl4UH2Q\nKFRBhJ+MMmq9Tx4IIAUrcOx/wc292S8+VOoH404Scp8y13dsW4v1YmvbO7zobomF\neTA1TZ371q7OqumxtCl2B8gnAFxzBPH7W6O3YHSs2zEpwtd3r20VS/WZ2owl8+HL\n1hGg1AY+LCVBsX4BiBF/4e4qr/6BghvScximLbIThS9jLJCJs0jphhPKudS7dMAQ\nveGSlWJUJ1stLqoWkmQuo0ndArLtnHQF+pFRtNcaIqmn2ZOQM+GD91PxIlMmR/hw\ndKzVf6b5ncwvfS2di0ySl8v50SgBvZTbLm/C2Qh5VcB9NolzVHqICtoVO/fD4I3P\ngS52Asdx6Deeq188yoXUiQJQBBMBCAA6AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwEC\nHgECF4AWIQTE8N//TowagjZAnQjnO8ZBzBH0yAUCW/Q5HwAKCRDnO8ZBzBH0yPtu\nEACUVtMYUeB8NTZC5e4ceP8D0fciwxvcXKngRSm/BItY/Hi4gWn01Us5cG/7hh6y\nnW16f2DLWMTQL8EIcUZ7kiKvBCJc/v6X/4XCPGJthGrsiFzPiaFUv2qzhSooQkGB\n72Qi1WhdvLn1ocSkUDWbFeEJCnGxH5bVBSntDu0nVU8DwVTB/NQ8V2HZDl4e/mWo\ncteekAVzXw1Nl1v6PUNMexGMCQgqiU4xkWD/Ypv7G00fA0cg26hJxfawWJgnVIBW\nGKHHl24y34oK9nmTB6OYQcdPkMg4sOHMKILR8P6/iahoJXnErjhmwa1q6XbF632g\nl1ZE1BMNIZqeurLNnRecvYDrF2MKzid6+jMGb452QHMRLw40EqxVLkNBkePvo1sv\nZcTtsQbpv5r9yaBr2RZvvFf/vGBrsBWjtsZuOWwIUzdLaA8qPCHDKbEqJ5YqMuyG\nQ59viNd/DPiJhtUci9e7DOLajnPN2+B9h+pM7YYBvwaTs1QGWw0RAhMP1y4PooyQ\nwu2KMrCW5yGlawtFkdSQE3hZWzb6JRfBQG6m5ufo1c6CP0yLSaQwV4oOqaBXWk5S\ndE5155xBsXRRHx2bq2hUs3BP2OCGYJSHopX1cuJVs4nTVCu3Uc5svw2B8jCuFUIU\nBgxYn/icYrAEhU1+JFeuj2FIweM3qFMV/D1YMurLWYZDJrQ/TXlsZXMgQm9yaW5z\nIChOb3QgdXNlZCBhZnRlciBKYW51YXJ5IDIwMTcpIDxtYm9yaW5zQHVzLmlibS5j\nb20+iQI2BDABCAAgFiEExPDf/06MGoI2QJ0I5zvGQcwR9MgFAlv0OTMCHQAACgkQ\n5zvGQcwR9MjmshAAnt7iyUzrgmdJwhT9fwaUAgzDCjieKN7OPMZ3YgSl7J3rNVEj\nR3mLWEnlWcMT/n6aQBn0iIYO+GNDDcm0MI/SPP72+4YUa/sjC84Zw3popoQj0jav\nxV0kMZfY3L7ma1S03mD/At5YIqF94rHx3CIlh/0XzGK7F6KYrjI0GJVJb6AVGGzU\nviL4GhMrN9u8An7Y1rOPzXYYDTfQPg+SgDThNeNrr/Ehg/F+RHB/uOjg6l/n0Bcv\nIP63MqX6TmUxDO3tPRngLM2dzFOcAk0CevPw4zeAHWcK05Q6jWZw/DlyVxO9wAqy\n/g/OxpMTpyALcWdMCyDVPMmV0pdnW0WIgypYCEKzaaCWDTfYbzAkiq+9gy94TLKf\nUKoW69pxRQ+zLzyKhQziMLArstyyNDKqXeOD/EiOrTJCSzhGvb1ZIt8FyyYyKT0e\n+geNzd8d59yzxwFlFiOYuRglsHu8TpQJhw2sz3YwMC9uJFUSFvccrO/CnewW6RIJ\n3rfJFEX6seMz7+XN8tj7PxghwTg0uLPIRQGFr3xI2PQn4MORLp7P9QjdUHZcNR/u\nC9yxhonj30pGcT2/BC1PJQjeUGYHrATHwzzjFR75eKsC+O4BetAasAEbI+FLbKp0\nR+sAkTkuz/5T11H2QoNhwD3oi2abbJnqfYLbceTgd6ZTAcRag7kZdNyNgVWJAjkE\nEwEIACMFAlihZaMCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDnO8ZB\nzBH0yL7CEADb1Z7WnCwpLEfHWJAFfbMiJ/Lh821U2CTz2eJKulFup0d5PvXWxkS+\npAZP2Dp9P4m95lc/6jD2SxapqFk5EYd6ghngS32bTneB4y0Ob76RbJ5FpjeAVtyY\nv5UnmB8l1OWb/WfWDsW6NcvbTh74a7K3t5Id9RPQDea2/cdilUt3cH5jeDyMfptG\nguianzZX+/IQ1Gxnbj5uk5B3JhFX2yU/16qs1E3CbDVZO9OO6xsWRqPk8W1vEYtw\nj6Hu0Efy4UPyMSD6dXjbuqDFsnGOpuxGITYmoH++o/yb/U+0eV5kbcWattc+PfOX\nETQuWrqKA/mqXTolY37d4AG3svw2T4aWOj9g7c6tTBV3R0X6FuWp+NAYOSIJ20Ya\nnIPRGNftfNljQdoms57UeNyHjTWV15ZCyFcVuKABt76ug1d+5cDbjmC07HRlL25D\nHf7tc5nnH1/QvMFOPxMXn5Ou+khNb+bIQOeFA1L1IWhpw2y2WeujH4l34rRP0bht\n/7hX5MXinN/wrFCpN0WG7SgNzrv9DvQuqSiFQokIVHvx1UonZJNBgGdxauuAqmo3\ndgcs9EBQx8Cr9egUmPhOJpgFl2MNmle6TvrYr4m+l12yx1P1oCdam5v0K97qPmWL\n+JO3+CMGItJG0m/Z8bW37fdH7qt8ZiZPwc2OjWdn+hSDvGmic0yBm7kBDQRWlY6U\nAQgAt8I05Quf43Yto5yKKYXLbwPF2qpq0Hg+hmi7oHwn8tc81P+y28xm29Jsz3Zx\ndTk/IbUBbvgljayJ1A6jNrBxNLasdhEPNiqCvbkHbhY8l99xitBRZEIfnAx5Ew0i\nEJKKseuxRz/o4Hob/KwM6cHPxuEIKFqaY/qtRsHD3t+FjAms7H1DGMq//ossOj2N\nFmckDTFIDiLcBpb6u0LGKltqxfG5eqjvCj5V8Vyu3+xEZtUnC73nOluw22kHDtyp\nSvrVILBVQJBxGMM+zBstsmzTf3x040tLgfTg5MkRRRrBF3INQYSbIBzcvplk7OnT\nprShGVuNQXly+qYKafsUHAnwlQARAQABiQI2BCgBCgAgFiEExPDf/06MGoI2QJ0I\n5zvGQcwR9MgFAlvb8sgCHQAACgkQ5zvGQcwR9MhI/Q/9FpQud4D5Qq2eKfCto7HL\nXZPCQTeIBJEoqtRCvLXfVw2Il2oMmhApGr86l7pEO95SWhQvzX7yYNTpptMc9meU\nrEoIyPR/M27MfCK1JEzWzjRde/L0KpoVaMX4kIxuSgdsrsHMLZYP8YVxXiIrWPsn\nd9CHFfqsvoLx4mwxf9S2pBPJ+qNB588ir7GANjtBfVUnWUlqc0fyzT3BAZdfz7rv\n1+LmjJaHKoYuPwm6Tk3mYUnxmZFodJ0GdLDbxTMDzWitDNZz/2Y06VM/3sTpzXvP\n6x8po85zcTlxvHHsF+eJv8wYPY6MXipFR75CnVxSCavJvlcvX8W+PLyXz4ISQocm\n1RiMNE0UCcabl1LIMVNrQPtfh5LGnr/Iz3L+OEYqsygMC16TIZeLS5uljL2hNiAz\nI37phI71hgEPJflS/ikyYMkDbFR2IUQ+iqBfRvr7FGmcSFlmTxPANcLu+j00F52k\nMcIKfjoirfXTw3MNjHOaVpmTX4VwlRQHHwMJXOeOy13h7ihf436NyVXQAeIb2cQQ\nFSsZX8islTbjtOheM3MjOdC8dVeO4HL6iXO0/ohiDyCqhm5va8GtjyD1j0LsCCYZ\nKSIaoh9n6lyIKdPqwUxwxFabtVY6j3XcUaBZ9/v8X2gQHAv4MsSBpMxSzfLnHGEE\ndTHLEeSSsNo1nYpj0BLDiMCJA1sEGAEKACYFCQVQqc0WIQTE8N//TowagjZAnQjn\nO8ZBzBH0yAUCW/Q4dgIbDgEpwF0gBBkBCgAGBQJWlY6UAAoJEN6hY3GXQDGl4DQI\nAJJpkD6tNpTwO3I3ZFrW2BdLcWJ54z3CIY/JnrYot2LHg5HyXLFXOSFQzKoNzbOl\ntnLnUkfXIH8PiXOTHlbRIAXq0cOlFwH7xiu5IVV3vUxXuOhcdUxCda1v4XNJTSjT\nXCX0IWDyJbIxUYmEBLzouwPVSnKWrRV6hw0Rkr41p2X2ryRKUC+3+XhXfxl8xUzT\nsymME0ajp9xEkBM2OuZWzkUMG8E0+Fe9OIusd2gYcI5qpzjBWj5VOvUEIK5j2ZGk\npPkezZFEvwHKQxSebdS/89h4ihf13huVOpZg8vz52tHreo50xRJAzpDD0EqbleZF\na5mMnIW1okm19sS0pxzlod4JEOc7xkHMEfTIz+wQAJtL+M2ypBCuxroRS9JHLCJR\nUSkWiSkSh7CAz7A4KWb4tVXZAkQCaUDtPaHjT6ZSYa4nXu7XYZ/RIRVER0srb7jC\nci+P7Yi+XWEoFzMYar1VMeWoac2Yk+wSotH1Ew0usr88w5nzwFgyarEyRpTiMbg0\nUZS5GhI0O50K5wbm8XuxnoSFSGJqdBfuNnf9uvSFXlUFc5f3c6mf6xZd/5gK+d7W\nZKN9Ca5Lx9fOqGnb8dnmPTwTUn0wu3HdqmLOVZXjomhH/Pxh/wPRUMoniyw6hct8\nb0gI7aQD7Dn06Cr4ScPY8n0f/Sfmaq8Y8Cz5ELiIZUyCt5RHPQxlS9kvsi6e0dOM\n6uEMI8UIBh09pltAKznd0QOr+IOR3RodiOqo6XBJLfuLat5pezJU9iNUTYljGk6B\nrkI2NBwQmMxKUIev2+QUeJYTTc8adFXilAIS1TXr5uzOMWLObDsTiz/gGI8zlmET\n58SnqwXBFWdJ368MPHHYs/Op1Tgfd3oYuPYnkQbyj9fYA9LHOs/qQZo2XNKLR9A7\nIlFuwhlebvSMVtsV1fPOde3PNiSk3vhJdHVrUQZWB0kzVlJoY3Gtr2sJeIs4tObx\nkqoeonyQAoDZl+ZzrHMEPjouRRsOXH+4ymSePcYoQgdHmrAtDP7VKo/AiAhC+Gyq\n+N9uvS0OJ7OatFeJxTr4uQENBFaVjpQBCAC95gv1WH4byN01w/Gvuid661hyVPFs\nsMBdwXVw/KCfiHvV0asTe02luwvEbwrcLyfFB1wvQ3AGdGnksAX9A0uHFYtsVGfF\neVQtT0xxZz2hQLpUUpIEY6a11u7LMqd4EiuLQFNequOZziUjd3C8fFFFfUF/iStu\nTxRN4zY/m23o1yInXJCWJe8+TqIdV4/4ta/6ToCQboouflNXBmMdsR+UZw+vBf/W\n9ZA/JKn/fqTH3W337FvD8tb5JrxvHI2+i8fyhdBoQWYeWTQGGA3WfJ+260WlPsVw\nl+CV/qWNc/HlYnKeJvVtoCe7vRWw+wvpJWVfFCeZ83J5L62zbLuGol1DABEBAAGJ\nA0QEGAEKAA8FAlaVjpQFCQ8JnAACGyIBKQkQ5zvGQcwR9MjAXSAEGQEKAAYFAlaV\njpQACgkQkzsB9AtcqUbjGAf/auRS2oQ9ylkc8dPph3qq/JBUsDhgNp3tXAgccj5e\n05F6roZsQ6UdQlppC2HChs70d9nTvCKdv0N4ycybH5BjfKt0yJ1Lnu9KnRnWwmwD\nr1Ro4Jww7gcRkSgwLhbjlhFmEwcnlX+4vju4IeNt75KztHAaf37UOuYUCk09Con8\nphkLi5cnFtLypK1m1yNsR1wpiyh6AB23Nc4xojUbVgAJmDOs+YBOnmNDvGmjiXlg\nLIJuofh0MydSJcOOXgC/Z1zNfQlt30MqnDZT2ssCwZNtG0S/fqFYoM9b0JvQVyo7\n17zDgzG/q146Knj5ZAyAhOShVncE5ouLcFiLU0lFqNOk3rQBD/47QSWAigIWwdxV\ngjg1JYPOaYVep4TWOWVXDbCcDas7yCnerR9yMR3nsuOjALcZUUFl+vApf3gbQm2X\nhYe3M1TKZTGe7PrPfmNPoLmKM00OB3/64CzNoaBKGnrWmXSEVOJsjHitRPh9di5C\nHC74mxiCITuQuMYbjA1o4/USq2gGuFH6+5345uLYr+LPbCV9uEXjkuuH+ibwHv3m\n4DaSfjZf4WGBjCt/bH77aOQ7YxwndW9l2/kChXHNBiSRRvekmsI+Er+XsDCB/uql\nG+utBw5f62meWEnaR5ZRKN3UqTVBxsU8pZAbiRScxRwxanxUb5YIsG7UyV5gXkMU\nDCQasZBXqlA10w6zXhDLnFkmhVis24vfj0Fh4qsDE9uQ2E09jFeF02LfmOZe9cgT\nGeh7SxwmByOFwcL2uBfc05WYP0cRjgzMBmc0vOLkRSxu1ZXX9K6L+2OeiNucLGru\n6dw+8Fk2IxLy+gqwUhdeN7CFy075U0tEFu8zXwwk5or9AlV5HyXC++wPOXL1By8D\nxg+nI5lWvzcxeXeeTR+QZPSuNnMfO82G8vTNZKgtsYrcr3lcIHM0e45SokIyVENx\n2BbjdZgzPOku8w4ZLGWbfqfgTKdwKjhsMyX04w+anvxwBlJpqecmpsqsZmnhs3Mi\nCei6k96jcO6sYiJO+vTB65BkfKY2WrkBDQRb2goTAQgAztxdnR1C/j38n64JlSlO\ndSTWaxV4XVDGu4YLQnoA017JAkrbkIlz8T2KQ5X9yNBdLqRZy1QCWZyPFndAdZ0i\n4cy4nuhdYQlShXg2KkcSUhUUI7LKHAXk59cWXne58UJFHqZYCGyvrorKJ84R8OpN\ncjw9OXANgvdH2TWHr58vcYrVKPB6RrKjH8BI91x9OjnQkN9kUhSf+yxjYISoG2O6\nLE7IAa9GI7sD8V0XGdOgwbFhEstofmlFWZAP2DwwkblN+7rPk7hcs76ecc7ZoCbD\np0RL5lYoIag3EVce2gAu6+TTsUeO6hh1nUGdgy9R00npKuecsYsXpV+VQ/r/uk/W\nGwARAQABiQI8BBgBCAAmFiEExPDf/06MGoI2QJ0I5zvGQcwR9MgFAlvaChMCGwwF\nCQeGH4AACgkQ5zvGQcwR9MgBVQ//WWqsFzL/j14eeSYFivamp5Exfs2gA6+38Jps\np3oW0kbpIpq0BdAue558HDx/pluZwcGTMhzijWZYzWVeLVXwcit/+5FduKTBAw6A\ncD1Tgd9meAy23lxBAANj1Loz+PxMpIHLmE9zUIKWrwDGEYEVXLHk2oVCbntUXVdM\nZK3yathVZyBsMiLWXL8AghHyZN5gt15QSTm2KyaN4XbYZqVDjk64bJzi+31wY7YP\n0bajpE0fQcugaB9KlBXt+nLgVHCNqym3C4dU6OXCOafoRYnz7qASiHGkY5EX4iS9\n+MlmA5UvKjOBg4bjUFADxnMGmiFyjWRNuoxxXAE30422qpvpmTPcGW+OJkY0Ir2D\nK6w008wv98GaUGr1ZPjA6O8Oeks2+m3o+9l7GNv1uiiTiSMzJmmdCG2F94ZSAyzA\noZuqEvytOYMCBBYVBN3FqGEyb0aNsJnvB+6tJOxKdvdJcZNIXmbqvo8uCeZDk4et\ne5BlxYQEC2yGuDAKgqqcP376d8NAgpGfL6oG32EQ0PpZXJidHpz5U6lTQZpVPiB5\n6tZfWAlrtI0SDsQGdhe3XmiKxlCji9BT1YNuGginkadLXvmISg7Is0s3rgsjC61/\nKu9xqajxZHvDBZ9cNCnpq3PQIWLai1YFCGDmsEDc7nF/g89NnfQRoTvbTm2v+iYt\n4G5Uhcw=\n=YIVB\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQGNBGKD3OQBDAC3ESxNd7dHfM7Hl3sE7Xn2osS4UZkJtmXA7hdbfybzf164wCbL\ncYECq0GrGfgdnKEMWNzr2S08KkUWQwJZd70Jt1voVpqWVXdtBH/KxGwifixMkTEy\nlu0ePvJM7L5HNOIZP5njcAU03hKgIibYQW+SWj/G37yfdyNprN2uX8p4CUyJbnBc\nYOZ2W1tUzNsddvTV03JlDmfR5kwHoi5sTCqvQWTzsIQn/vGHxMqa3XjabfSvim1A\nytE1J7VIiu7P9hW1prEfUVY5+ggswUCfJl4A4WcCwFLIaIdOreiakAix7Hn5AD4D\nlyskTzDy6QRpzFVm6YyrKzUzggqa+bQ5/9aq8LdKVim/f/LmEuSQdwkEt0rOWhAX\nYJQrnJT8IFLqmgnJEygGkwcdXOBGRERRB8Mes0rfrgYHYW0WqGI5fMxyL1Ti9w+0\nAH6QFq1IoWZY8bzGk1bJe57lgJrshavpSc1ftKTqsFAoLYDsMF6lxkNyS7+OZMIx\nU9hbvuJgdPj7/lUAEQEAAbQjUmFmYWVsR1NTIDxyYWZhZWwubnVudUBob3RtYWls\nLmNvbT6JAdQEEwEKAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQSJDAjb\nhXkWL+4N+duL6rTfz1Ve9AUCZowKYQUJB8qUfQAKCRCL6rTfz1Ve9OI7C/9mQxcc\ng/oZxn4QlxWaNjqrLLjDt5D64BMFWlqAIg+9OiABF3dAAYdkRLvQ4Wxq2xHauf2z\ndu1pbCdKxO4lhGDVbMjKgCvfjH21foORH/ZR/daOt9lc3ywFGg9WMN4Vlt9+cO4f\ndENOMMNpDVPWiIZ0VPJZcFNXtHmBgT3CmKjVZQUDUerhp6qaRxkMqUdVnYfieUKX\nlDdviMKQoVHmzaDlexgvsKyCX6NzjCBKsigOQeC+hqt3AdyN3IG2sBAVBrMGvqN2\nMXfgebr1ZDJnC0Y0hA6zAeyzKrR5vrzB7oDQAl2Jze9e0hinjtcCGOo7+Xna6Dm2\nGP2Gj04hNSk6JXARU03KZWnMryRqQCDNxfdHy9ShmPAD3PuH/g/VCQMeQsB1S1H+\nm/XVp2I+G/fZj6L7iZpR5URbYQFSSL7UIVjyFTymU8e8PkkRqXDI0nboaZBVikbl\nFmYAINtsVJLHY70lAZ+0BJCGs9QIETguxFtsofRw3pqnuy93FKV2/T2wJUa5AY0E\nYoPc5AEMAN+Z6DX1O0fLkt0lq+N70gmO+AlFI9l4L2HKBiPCMMPCXP/iX/04zVzm\n6n3rl5ypNo+Q4um6eGwL9UGrzUJSwcD0nsvK8U+SVyDpp8e3i4+ph2XRiC5Bkktf\ngye2vTAgE9clqnDpQGnaQ689gOd9nPQAUqNXnibuZsnETusbu/+HQDqM4wdSxTGX\nQ4PaqjmyATeUcTVwh8bzdBOLZ8O2eilFgNhY30cycxevI68SnLzPz7riXTQo0pKb\nf6hvK5kn3nULn5l7b+QFtuVbffe9vo3J3OT8lEX9Cvd73y01fgDRXs5j1Zbg5OaO\nMXqMthbndq+enlhkD4vyCF07LkuHBk8lMX1yUVysMx/iqN7YS/2ZEMkJt095Q/6D\ncNigEUpTvgtPJYxHam1uXQb3Ellhap/YeCkkgOs2FOeytaIR8na/A7TjPwOM6v/t\nar+ENQDF1nChrqhlLin9j+kyiwkTypWJ0kmyU58fZGvlSh1JfjVNaMuM4f6xoFQF\nb88Au4p8swARAQABiQG8BBgBCgAmAhsMFiEEiQwI24V5Fi/uDfnbi+q0389VXvQF\nAmaMCowFCQfKlKgACgkQi+q0389VXvSQBQwAsMvjMThyU14b/Ba3zfC4fqtBd17l\nRExTlyCpjJj7Kt8tiFSM1Yq0M30ndQtZY2+tpiX8iyjgWPYpcbNgm6T3jOFV1tgt\np2m7bYiGTqa7o0VQEcdu+52GqNmrLv7aLZGoCM8kNWaRGyi32433EWdz6b+1cfT8\nH7lIrLKvBdwrOV5q1XMQLf2DDNLQUhLqGb6qE6EG9/Rw4e8uc10w3wz0xr3Le1+F\nlrC1KFC0XaHoBCW0gNq7tK0gG+aaASIXg8qQS/cT3Tf00jq/M7j4Vl6QwOsOwZw1\nhn/ydBQfK3Tv+Hxe060vWehIyc/nfnw9oo4AetNKQqieNFjfh7CHhAIaTVDisc13\n0rQWJtTmloRBoXA0uwLc6dIvIWi1hL7KgEI55zSeXUdFIpwWjRcNxdiLQ46GagtV\nMj+1hz8EOU7J3vY04ZRHDyapCRYoRXd/N8MUnsZ/ySRdA/Sk57Ujn9UH3nFEhD6A\nH9y08K6zB4JFN7saJiCj2Q7W2nXuEUhRVs2K\n=L7AX\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF222c0BEAC/wIiI7EYmA7yprNa/0en2leF+CrF09BlCItTHH5IgjSLGq2tI\nBi3hIhf7TitDlu6GphHlFjvhj6UDgdEmr0itcoOLRhtER6WlmMaXtS+im5fPSLWW\nskZSAh1YC3iqOQCErkAnVFUWY5nUbWfxgv0pKrc5GTT2RkiD6ngor5YIAkRaYQ+n\nniHsekUYOuLln0p4n/K0/iRw5NMok9Q2FwlEj7H0kCfDPuqsgfEoDXoVv8QSVIpB\n1gdOQ7e2MeMAB6U5o0OjqzMxPUrIkDmgGIBvCgcCN33lMNO4DWlhr3vF90EhKvWP\nLy4kTa4Gctt9f5kICzb7AYZJG7+F8hrVHpbF0fXzTgZsO/BBf4ERTMKGfj7ZXq7e\nGARTfDgzR9yxWfxfo47jUd8amVk/qj9O94lIPobEUeP7SKPy2jIRTx04HcdMDPAF\nokzJf1cwCghc19mN+ro31rcnud0Za0EM7Yxq89GHvHiUEzxj2XWny3n583V4Lh6c\n2bAm0tcqmJlLholeFo3qW/nBSCde0BjwfamKd4KB80tsF8Qu6OdahFT8ybaCA2ls\ndcks9uAXXqwyTmXhwe22CHk/919Ubk0DFPozgj0AaDf+vQz+lKxDUuY0FaSEo3sP\nnw7JmG1fdz2jAw0UvK4xGrYE8nTlF85mOBhV7zjwW57b9x07Og0zilqZhwARAQAB\ntB1SaWNoYXJkIExhdSA8cmxhdUByZWRoYXQuY29tPokCOQQTAQIAIwUCX3X/5wIb\nAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEMQ87EXBerk8y0gQALZv85ID\neHIDsbf05A3q5G614MQzRuU3rXBlLpTEv6DJorQll3hhmvRU4aQzX2D3JTzOAb8W\nsu+cHUXJvU11rCIsAQN3L5yWEG11hld/oDG3j5S0sM+/3YvqKjluWhQpYvOrTQUR\noJqn5UvKNzZ68cWgQDJOS3XVw5SLstB3ctoa3me0sSkSVs7Gy9L2SJUnnc33GGEr\nUJCo7u/0eD5+ihNnP4buga+xd8w4zqe9gEzh8BZMi+soAv2kNC4wlMbErJUh0Msq\nLTEJKmbNsVeGX0gwjlJR0sPGbfNWlN4lw6xAljFeRjRJg59Z9gk5P5+UHabUZLFk\n9U98dj/8tclmxoa9ceMW1VVOBcpVskhUpF7DK7j0ojjz9iRXXWIxkn5dgnAP58eK\n+WZtSQ5lBbzyLFFlr5c51/FZoFurVACWymHNiyA3Xg5tsv2e7a31T1oPC0K9T3Zx\nnavSgnx0Gb0SRJM2W0kJwIjdX61iHN8yisnD4+DMHWGZmNgPN/tVhpSVKVKJC1do\nWlDgaoi2agnRtgfI0G9Em1CN7yHBCRpWaVERAaP/+uBogAwWOZFNgQjwVtU6jZYz\noLgazKbQXDf859eJ6C6AwWxrBiMMsdLsuQoFTmAztZS3efbLXU0qO4NkQ5QpEMP/\n9U6873G4QApdzEHojTyTt18ffmvZjkzpbj7WtB9SaWNoYXJkIExhdSA8cmljbGF1\nQHVrLmlibS5jb20+iQJRBDABCAA7FiEEyC+jrhy+3Gvka5NgxDzsRcF6uTwFAmDR\nt8QdHSBDaGFuZ2VkIGVtcGxveWVyIDIwMjAtMTAtMDEACgkQxDzsRcF6uTyfNA/+\nIchjvyChF8f5CEIKvfT46yg3JrCl8sETf6cTR+ZY6ZleVgHD4/AM6yZXDg6B3gfj\nUgZMpp1fu76N1zY+OQ6fPH9hgOGEsfKX//n5AJCCxhESXPlxQ7rvAkOLqUa8UsML\nI8ueh19Rv+afEL4Z7l+mJF3HjGZAInVhbXg7OBp9x2Y1YhyGQe074bT1gX7UPdfT\nPmmkT7cD92ec1uxJVSYbG4UzUZb46fZSUmgyRAlz3sTng2y7an9t/auzPNrzm+DC\nSplupDqwu07MrfiKUnGfJs6C0tx9LGY6KQQKZR5yCVqp+bWhRuFd04e8gIX2qq34\nvgU+GbulJoz63OJ3tu1igouoVnS7OwoYrEIiWZI3agzkb0VvpAlqVInOrXmZtvFn\nV3wLW7RfXf6sO3sSjgVBGCunxNasbaTCtUk1jpiMQKZpg1LwSEcLEAXt5wIDZuWl\n827/CHSEuLqJNkJsTRYXZe/hXvWm09OGSPQglcAeRH9fytWxBBMd82LRcsuYw/b6\ndxw9qkwaLEZKN2vtvdJYu3BrS4PndU5Z2T530rdpign07ZpIDPvxElJ8KuFRgikN\nFujKeAcMQ+PaZVWXBTEXsmqVJNPpLcun+Rb+ufpiwhehlqbnhdyqF40Rxivf2pk+\ngy0bKrCl+AEYiqJ+dKpUs50PYApvQCoKq6eVjoEnsACJAk4EEwEKADgWIQTIL6Ou\nHL7ca+Rrk2DEPOxFwXq5PAUCXbbZzQIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIX\ngAAKCRDEPOxFwXq5PGi/D/4yqrdmfkGqJBDHXfE6wnbm2+rtpr0F587CFtKeC7P9\nlJzDBXGvU22nf4pYB1c+UsLRvM+l3pQAfxJe8lg1fc6Phso1cb9WVquqHhkPDT+c\nlgkGV8c0M9T2lRpDOLXmn7UfoqVq6aGCI7fqVf6mq0YCcprsAx6cPFd6G6jF6qEq\nMaw7Yx+6gESRymI2FbifEHAEOWZHcS/H+itRN6OQG76n5W/PmVO8bsCqxTQlTqLS\nARX7bMFVI/J/F00DNjqI2sWzNx2FLsEbfG+NSrnGmun/Dz0M//TTwpAORTdQ5xGF\nHcxNCsuNeRHVvbArP7NXIydMl5mBCs8W9fAZkNVchiVVgMovn+APA0/zhCjw/+I6\nEwGnPtOYzENcriKPF/5ZTrv/moGVWktfdgTO8Ygbx2Z4953U0JMAQc88CyY1Rnw7\n5S/tjmT+hwlGMb+YKiwq9+P3Zo5+9dPHz+aL4M5gskZDBP2Iu+c0ixgukoKdYf8d\nmje7UsuF2RvW0y0Z/wIhNSo6/N/hYr6i5cMoDeZ6zMVZZEyFPx/JnvAX6B7t+7Br\nMNFRtjvG9TNt5P4BkoBy0fL5Admid/oWlDLz6posj5ayfjb4ihB91BI1ORaqG8oL\nAUC6C1vb8dmvCPGIyM0pmJnALc5/glnDNqyOVRrYAQXowNrlVPdbX3dYbZ0ooGAe\nwbQhUmljaGFyZCBMYXUgPHJpY2hhcmQubGF1QGlibS5jb20+iQJUBBMBCgA+AhsD\nBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAFiEEyC+jrhy+3Gvka5NgxDzsRcF6\nuTwFAmhcK9QCGQEACgkQxDzsRcF6uTzocw/9HMMhhddNoJeqOAFnKSKcKm5uw1cc\ngTezizurj6W7GGKmJAvzLHz9gD+xz3TjAe+E4ZAkQNF2x0OmuEiHN1ST3lqtmF1J\nfz3C1/WvtTTm03h6t5NQRtBzCLhXW7mH6Qbof8yI3pozM9t/mhmvkkr7FjJxC8cO\nA8VbNXIVChZrRBrQZXfr06PkjDg7qEzSKZgDA10oSBJexZksf8g1L0D7NuEUu3dL\ngwrL2+FlT3RCmEEhEei//V4gTbwA2DXjgro556vVv1SlgJWOsaD3228XT05jSta7\njKswMyhS/U+/e7rt3BWhm/sxdHpZXOnQ0tqB8/veu4aI79DFTP//oDI45xwXXFSw\nZwF9GEvOlX1q5ZUA4eS2mxY1hHrj7Lo9VZwW1cZou5msqKXpe6+CLcSjPbIPT51V\nVFTbmx9ps+0sxCa2cbNu/DvOlxAmZj2c9ceW4fsAiS4m8K4Z0nM8yy+t+2JHh8d4\n/GpkLMMWdYGq3xTxRS4mCekEZ28LWvwjo9/X06UvSGSu+Z47VxmR7oVeSIt8gPw0\n73gAYz4gb+cXTfAm+LOk5i4j564Ixqh5pIkjwasMQS5vlswWETq1hmDsCDCNMgLI\nbbQYlUQgCFClPl+i4TXfWc7b0K3AUSjeThG4ZpsjDhhAl/uD6ykNMugZt66XEJoD\nOvzI76MwP0rwuX25Ag0EXbbZzQEQAL9YA50WXd+iCK2rTlDk4Pv8piGkBu92CJ8Z\nlbP37AriS0xKYm78sWFqRwflFoerUwdPbC7PV5FuslRC3Y7T2T7uJOU08YEue5nC\nXgLJxnbtpjCKoLlgDWgLgLcmtfQnQrZkIZmYQ6zlTFHrJZ+Mg29ku/JeZ7HHB3EP\ndQoFd0EIJJJy5IUhJA10xnjND3RrSaApS0Q7swui8LXNOtLa/tpGXF/0OA6OjIXB\nxuT8lgTTUtk6zz+ESw0BgI+GnYZmL65m/PSfTVd79PujWhP3e/OmDti8JxWVsvjh\ntbmS2ZNuQEKAvGJS/ZoMrap2cuA7OrDM0/Ndoq9dft5yhWZbkwBNevPwXSo9ZVgt\nK+mZyVrQPKTfPusjF27HwPw1xrSvj1h1b1bAlg19FJTTAv5GqOePlnbgUlPvJYt9\nR3gipBy2ZIwWV9dfRZe848dz3dReD/+q1fNkQJJC76pv7T0CboEMHvKryKfsKNp6\nTHyHWRE472kkQZ7qF2ssxu3d+JHFvn+KEAmIbR+UfS5hnENVallHXRU4gtEAae8c\nBlXNnP8swzO6BkgGqsERtvATTdb8xjRSUIcqPxv7EIRG57lnEHuGr6N1Xa6FAxTm\nhOy27AlmnbQyaJmpDMe5s5XHApUbRA4Mq1qSbcOFNml3zUVKnCXaXY0B6MM5F3RP\nhRnx9LHRABEBAAGJAjYEGAEKACAWIQTIL6OuHL7ca+Rrk2DEPOxFwXq5PAUCXbbZ\nzQIbDAAKCRDEPOxFwXq5PLlHD/9kI4bENYzm/IE1EK0zp48LZCsaeZGZ/hyW0qJ9\nlnLyXKRmilHAeLmD+tRXEnCOzmFwqftJpQJditx79uoyUiTiOA/yexia4/hrItZ8\n+E7lXQmvA6vEFRMNZ+5+TtlOMMS8BL1kdyJIC589nDZorA8l8401e9nAGVtowhk/\njWpF3tuRfb7sVKvvWpzee/EJ1ntmUXi8FrhflMhBJafQaRdLFnrGTjr3iwh05TDE\nAbpwzTfZQkj6YljJAFz+QwNZV9mK9hGzq1ExGo3B7EXdY7qelQIYTEByPXkRXa9j\ntUYJZOKX12hyCYfONIFFcZcNryxbF+X7UtCnTrgyK8LZ3L1t2xKOxumvoeLnfOqX\nWdizm25eu1vaBKSmdYwwC9z9DYZqImYtOksLQoolqEh0LcqJBKJuItMKmDsBW5EB\n5IFinbpmzxa2X4rvX7qNNQ46ky0sJzLW+bollsrn40S021IUyXq/FsisJTyFz7Nd\neTvEgr8uvOZJf++r9oEZw48siZNqjvPsejQjacu9UyXM0dCnJSaOm8OnZy8TpRB/\nibYKg149T1Y2+JrwHaXdKiM0U4k3a9X+TjA8BCV0+m3eY97cuFqXItaEGg/3FJyf\n9l5FS1bmjbondfTk3+rBsZ/tzDds+Jw2ir2mncO1jXgVls8xieBGoRWvH1N7nSSM\nNBG2Fw==\n=Cg9A\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFKKodABCADiE7Ex8GXnQNgipqbTADO5+BfufYFeq9YLEKkuOUfnjAZ8Wzle\n4eLL4rdfFSuwuUO0rkSFOpNjkjKqxfRo0RkmlMxdHwT2auf/yrfX4EyhyKDn1Vh8\nMP2JecXQN3FVa1yR8AMGfT0zOP138MNp21tNp3Dy9r/ds6ZhttrnR+mrKnhKMmTj\n1J+MX/LKw3o9ERIz0O8dxw75pA27npX1EcSCM1Vcq1bam7xD6d3cfQtfQsidXkQ/\nnFpD7BQFU+nemYaa6Vkuy4VJ11AMLNvzoWc2iHofD0kO60am3z6x8t63m+BUSU5I\nr7B5GNbatekJqu/Qn1qrCjyuXcExEsGnCJl/ABEBAAG0ElJvZCBWYWdnIDxyQHZh\nLmdnPokBOAQTAQIAIgUCUoqh0AIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA\nCgkQwnN5L32DVF2cywf/Vws0J68vxn+ngUzq/wcWlQANfwMFUcD/8eM0N1B3OMXQ\n9+GSlsuEUvh6/oxYxn4EPIgdqsV25SB/fAUz4uN50qvc0ft+wTgh20pnMP0qLf7/\nadb/dBf/NTV4TWzHaUDAkwPXqPd4He7AI5/PZeaMGmJPJmeR8ZM0ZrvLsNTmYV6N\nbyWcqYvbbRSNSn4ypb/QbYjFQZB2QKrC1LAW9jpdNnfQViYeZDmoSRaCTOv7SeSy\nTkzOhMFRZDP9NmUvnl3chWNdmBoLls3/lO1Kpuc8h+nXkgU1hUyvsPjs8zBaqUDI\noMudExnECyEUHlZvVLlfpocznOPqlBhxjR0Q9VRYYrQXUm9kIFZhZ2cgPHJvZEB2\nYWdnLm9yZz6JATgEEwECACIFAlKKo5ACGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B\nAheAAAoJEMJzeS99g1RdocEIAJCkX71Kddk6B1HD9V80dpTVvm+YMup2qca6LqLt\nsiYE/O/XZHRZZ1WJRdxTGqGLKLkHgea0PUaxrcUxSzibDFJqEcRBz90ojaVu2jXb\n8Wbr9PkNcV0ABivyPCpx0IFUxKj3+94akK9DOzwLpAf2QMSm0JlQhdql8K0JCRyk\n9ehkBCxcssVKocgZTCRur475lYNDU4SiQoJJ7iFirf1SvNAoeXwXiqDAR2q/k5Vr\nANmfzKvmQ4UMciExvQaxc+q7LsBI0/EzFtWCnhPabEzhY8lzqsxlfdEbFXWFO1V6\n206FBYuymTE6IDxgtrhVg6FZgmWSrxnWWasJSZxv2iWhwgK5AQ0EUoqh0AEIANGU\nbt///24seQv1o9hgAWJ6i7sjC79jCH1mtPlLjAsUcGg+16fTwAlII1Z2ffXYKs9M\nvcGBNVdxkR8S1g+aYM/ds3hY2CglHe7zN+/pkYr5I1jchmCE6LQDbGA/yIfiufMk\nUFB1Pry34P+G3mcnENfeETns/26yCSJ9plysIggJiPKS3ihrPnp8qjCEByzBn70H\nRkliS4nnjws1aSG67aWUn0RdELrK7MgmEWRacrMu308pgdn7XQ/hUUPcsOAqiI9t\nc0xeG2FXEg2WS7aklqAw7yjEpJK7qid0ntEbKy3Erlu29ZxzH/kphNJH5eQFgXJ0\nguhG/Sm4ljt45nn7H+8AEQEAAYkBHwQYAQIACQUCUoqh0AIbDAAKCRDCc3kvfYNU\nXVfxCAC1ajXnKPFswIU2RgJETuY1GgUHNL8oU3bp5oGhocKPcDPQL8rLZkAhTfKY\nkRoc6hLS5wcgz8FSEEz5oMesBWCXSZBS8xTW0vgncbrTUVnVmCAz88qeQ7SA9RVm\ngnpgKnVAv46azZQkB+x1FR2scSEf7uooGo5zxB7LvSwRX+bgyct5TRcs37lLLaaG\nlgsy7yrcZYqqUXjEOGrZ78KMNDifK+X0XYoGY+p4sCfl4Uf46qANa4shQMZjKaWG\nZpiqs673aIg0MoZPCyTTO6Atfsv2Li8EossDZpvJuroJFZw5zvIEy7AiDAcCZjMj\n8FLoLzom0A1FNxCvgzOraMITOobs\n=dTMc\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFhJehkBEADNX8qrO9msK8u1znGaBG+Fr0FS5qzMxpC9oStGZV8abX/rrLkN\nNiImTUMQG6Ooz7luOBSSF7VbYT2xSrgzuYV8WrSJE4Oo0AjVNn2YnbwgyzcQ5FhY\noDcfthDk1HALwXPxjyxvWA2RYf9NZj5OsT2j7nzVoRrQZRtDDB4l2dyEObZ4Am5R\nMRdmAApgHYB1vdTqseHIQjB14V5RcuEzZaE6qez/vJuCHWQby5y2c7JhbY4Hj7gw\nMCkB4I7ToHX0PSIpDOAqBXb1OZiI834Y+Q9pP/HF5ormpcK1hccoARQWXano7AQb\nfiQnSYh6kr6HJbzNR/YVxIHdW+yuxrZheX39EerKejndgUx7RrHmRm9K+7ostMEM\nKq++K3HYLdMag6loazn6qdX6DWgNhSJdsblJUOoqCnPQBmZMGtxpZqh3Oet3tlWm\nxF/ksmc5NmvcdZUtSndqSYa4xsegHl34mkefw4s8GmkIP6d3eqNpunC7Kh0FzkgP\nkWLENpusSYpF0qVtJ40uAgW7U42d5AIf9kc3zFn/yF3c/RHy5NjE4x/fAq6iB0s0\nEFnLXW8397YJY1PvHnvQzTQOWSkzwwyym85kjU22UWn7vKl/NlYmol6RydlCZvW0\nK0C7qg5AgWp/TkJGiX+6Wj0jVvswn0LelEIgb+yBiBjb4mEYLwgA5zadkwARAQAB\ntChSdWJlbiBCcmlkZ2V3YXRlciA8cnViZW5AYnJpZGdld2F0ZXIuZGU+iQI9BBMB\nCAAnBQJY27LjAhsjBQkJZgGABQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEPB0\nlrPrPBdijzcP/iNelF4LLAJrz9sCfe8hAm0lk4cg3AM3XBuR/k1M4LsJQNd0iUb0\nTQNQeVcuFpZ7WANKgTtNXlU1C9u2QYNSikn+NJwglc0g6ukL80CKu5tdpOTCRlFj\nVaHacRyg5tE3tjo03E6YHPS/bfmfOOVCccJfo6w9S9zncmxM2qxYZTjWA/3QLDwd\nBMS7jIIBcM9fZTqANIGhjzctpqHfGoB+wZisx3UxyGu3OIa5nswP5alqIOyajwLn\nJirzmc9/+CEf85ap33gul6bEX68nEVaDUo9ft531z02tlNrFfX4YaT+um8t1oBdx\nkYq2qB0vvxme/q2Lzy5JIzLKkSaimHyXzahI3YhflQUUatVsfZBSnclpNrPvKxLN\nUI1GVkODrbR9ps9JAHo+IRhFk+HoC28CpvfEsOhzB45xwbEgzprQVyoRJQ2KGnOl\nYoTYr9L+o4/dxQVCCQganVQW1FyCKcAip5dfCwHQUBmMlhkc/QdeZotEBN2mKOzE\n+hUPkiWIiQMFJ1x2AXcOjjnEIOJ3zHFmnQ134K17P+Alkwwp4V9hCqoLg2tG5wlF\naUTAThqDZNdxI/VTl4SK+YIYoUZfKLohfSk5eOx3g2d0SYjlMf/6pR29XOez7Nee\nSGzuYv58ireisaWNeYbCCYU84KTVatsyh/4JD0bJG788nbLYDqB0yk6PuQINBFhJ\nehkBEADDZLZSbGS2Y8FCL9v1SwDcTfZnJzx0Qau+HX4Are3/lVipHFDSg33lrtjs\nsKkNrQNnBp6IV8udSvh17XnitH/oV4DA72MdFWBlxoZ74Lo3V3+n0KJdBOAmn9Bd\npPq+8kdBIH3tCKHuEWEw7XtoyYlu1FZ/bsR74x4TcDi7UG8nmiYALZ2hOfnSnUp8\nax2ZzzUZUzh72qUEWa1eSp9p4rLTJMnwygcSxJcS1Jv97D4fq03mW9Zxen4wuXQ/\n386Ec0Yc8LGmv461PbPOjtuV1vEeOTWWSTx8k0Qsch/TJXxKLbcVxOfQ0sZyOq/i\nosWrMFSa6+JOtZYZIEXtPxdDzvYZFcc1euzdhVTN+tfYulWmBjE92ILdM2Rcgl4R\n1r4c+9C/Q8DbNXf/4ZiSxoL7rGWhIwCp0nD5mNOTQyY2v+PTlqIrg52ZsS/t0pwy\nv39KLiZICUJFHuE4I2qLonriLxnZrgtYfPyqDQmtNidoqG4++nsFX4SNoSxUXaAw\nPLxnxfwMDdrmzIHquQP4OHIQCOwQx1PNwo1+XmMVD2v/IXjDUP9yeAFYC3Evf3yE\nuq8ldbHxKHsS2aoOlEWniWpRIBVtJnqgCbtbP80p0itCse1SkzYZfsHCO9XqBOrS\ne63R5eprdFO1ixA60k00xYVVB1pFPmUYzeoUXEmNNVzeu0sRiwARAQABiQIlBBgB\nCAAPBQJYSXoZAhsMBQkJZgGAAAoJEPB0lrPrPBdiO+MP+wbMbkkDN5D9gjz4Dnty\nZW4P/47oGLuOiH8SdIui+XlPt8eWSie6iYZPEiS9jrenb/qism0ejpFuOk7wiLCI\nYnM8G8C42y5FfFSVVQzKHJ4SyCovpkB8ENcxAdvpbtcX4e5ASwrGFUWdeZ+sErEy\nKPe9TqDpjgHLqzFENSiR7hXHm6+BGslMRrn9VnrKQPIQeN9VB0YZIP5fPcsMvxm0\no8Cw9FkMXcZqrJzNH6wX1HIqO6GD8aT+dUPKupKmzDyG3YX1SJ3IyCXNtpnB15jV\nKzd8hM1cguuihc248pUA73uqn5pD6zZJzpIfZIr0CUhVyevJTiRzqLcuK9dizMI/\nbgYPpYuFmUlm/D/AciG2vTNGJ/yit9Yk0+7NIt979okP5aDP4fleLcGydbZOzOmI\ns4PDe1TmA59jphVDnNqZ52M9XWPYIT4xo4HI1WEGh4pQ+gU6n4W6mh9unSrgdvjO\nU1PLlzRL7h/ZhkUkLP30vgHco35muGBMW6/Ni/RQwxblR1TdpZ2RwvDr5t2u5HBU\nnpqSZaj8YOWI+DPDYGYzqQwFgyGLH0J32l5zzpcggwhEoDsQSMHKxekHD9bX0Bck\n4gpJCw5QwoZHeeSczEFZq6JGvWM6zIM8JKg4gGwIcZcJse/s9+H3+WvrwYFk1Nto\nfyCIa9sx6lcYB+gDJgESL0Nt\n=hSfG\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFl60g4BEAChHPOjxooUAUjigTKIERl8uYyOTA0JL9nICb7Azbl2J3ygmku6\nHdbaqgfaHRwap+hE0s8/oLkccFJVnab6b0rexWQEvarOtzkARJ0wqbxQIQBJKhfS\nV9KCjeacnohnd7CZCW64PtNLC1M9J7rBR32/f5YjllVQeZ/JesWW4HjxbxQLQZ5q\nccjuFw3ZG82zXZZ6gn5b1hNcrDuBLhmQ70UV25rNQopM916o62jXVIbCRNh/nflb\nhGaWrmnhw97HtrIgkrqH+AlzNJwF5YUhEe1SumjFo4YLDos7FtzZ+BO/KPJPqYFB\nkqNzpZHH2FGp+jtxca2zhPFJGxm8KmyoznmX4iYZeI/wtlsXzHs8nP/Pduuw8Q5a\nT9sIRBpw2M7/iElJED9YAr7xAv92xnha2cBAR1rgD/9u453+NvYSJRZiIkcCSx3e\nHT9VtAuEWozkM02isHB1s24+0UDvWN0zKbFLVPpLM/Ctlp8YgsPF4lLi3V2/YDbs\n2n1dr4moYrEGPF6oMCT6xlrpItkkGO3o2lSq0/2+AjL7uEOBI0e2s/2xLh0OXUCU\nVWj3oqJUvZYaNpjKsxLan9p+zWtzK4iBSVw5znfg5XBVYFJghmnlKN+BlCpaWEJV\nAKm2K5QKYOOrF0dHGYmXq7BmSitCDLfFc+7K/0tH7YfN/XYHSHYtT7OtBQARAQAB\ntD1TaGVsbGV5IFZvaHIgKHNlY3VyaXR5IGlzIG1ham9yIGtleSkgPHNoZWxsZXku\ndm9ockBnbWFpbC5jb20+iQI3BBMBCgAhBQJZetIOAhsDBQsJCAcDBRUKCQgLBRYC\nAwEAAh4BAheAAAoJEPE5k6dVmWU8m6IP/2mrwX/bxyg4fzh07MqTwYSC2kfjkZgH\nqBdwDmhJCq72erkTK5oq+7T7x+7f8mewM7ZDGXT/ccH6ys+AHXLM/6WDm71LczYn\nnhlPZMOmfqCtCqavyx7veVUwQEwFr8NKJg0+U7ROPf4EO3g5NYL5wEN9rSFUFGkw\nuSInJ07FY7/OD0Ej4Y9hUbdWUzFsk1jdmDjJGN+k1W6Vjv0Q+4d1IKfOpgb5H0Mx\nL9KCQlsAJbLcINo/oYu+hJt38au6I1hnuT19lGDmCG8ZGcmPYXYSthtWX/II7SW+\n/7g1FzL4VIBZvPvjtQCjmKOHMhnyw+lWF7biPDO7EldR3bmlruATXyDJ+yAaHD2R\nhzHPswzsueAF1cA7Z9XsyLJ/g0/t9yNIhI+7LJJD6GlKiVH+ogP/Wzm4mpDweXBa\nlmlXsZeq+BVV4Roh8Ab1AEIijpvRsYQ4TsK2sTpg+TzqQ/UpBuK1NaW5tr0G/zJZ\nip3D0wo/Mn7+sJjKqHY36phi8cJ6PFTE052l7Kw8XMTI2sEZ42g8BuqtllFGY78t\nqlyGvhjeJt5Mdjvdj5U8A+6AkUu1JXlQoKjdbdLTpcOzqV0JxAXORNQ4EAsyNRHR\n4Ocs1vHlO10k/7/3xtpwatRp+7D7BdlBhOpV75+xtO968I06ddk7aYtmdHceQ10a\nYaxE+YRoBubRuQINBFl60g4BEADnTYF3VoC++RSmvfykLv9KF0xuptSL4yEdmn+q\nY4kKZD9U8+tsvmYlsoAms0+0kjNXcAtpmgr/oLXG273R06anpFgeX4KMTrvJ3tct\nBXO5JuoYEmZrlzoHJ1PaPEJfO6EuEADl2D6arlBtO2unBeKuqMkfL+dV4E8mtNay\nE/H+qfX+JVZGyPMKbG15mYxcyd0yRrqKh/ZhyGtBEyBzxXP8XbTx6l0oFCrHGC2t\n2pRe/tb2XwBjv+VAHfHNkxHGraHA316lGIAMgB3Aj5kwdoVCq5OH38lQr1U55WRa\np1yMsmDU4nuk17hMOW9zPqLDve39URVvNRtFwNQmex8PiqtWn52aHsEuUqZJAHTU\nEpuNXOJXjNtsfQYY9FBLCrKisvhge2Hnx7IaVn3dkKLKM7LXeOpUYKLfTUkTp3pG\ns5HLFThTG5PAHHJYQNtRedR/zdJa5Znu98XNlGIpCRMLdRkvmUahVGh/FUw5o9d3\nbOalBY20CDcOvLBwasySZO7buu+y025LVaIizFSsAwRd9KCvTHFBwKM0ui0JHx5Z\nlgx8PYwPJxOJAeuclVnHFcuBesi+wK/uAwujyVxjtmMglCO0pyAWeL9vJUIxn83J\ng2euk2msmEuzVTOPObhuV9iOkTRY2wdl248ymoooZuNBbB8KZ4VBK9gHgShEtBec\ndgILQQARAQABiQIfBBgBCgAJBQJZetIOAhsMAAoJEPE5k6dVmWU8pLgP/it40xsG\ng1RDip1+5ctMVW8+DRLDT9zfq6OBd/fHY02Nbbw1ZWK43tS0mliWMHM3Zc/ujy/9\n4nbKawYWKy2rGv/JFTGU/0gU8renvKyZHWUJe2rgAj9HgaERUnpJaHpvpkl/yjZd\nyeTvLuVIqefRnyxPQg9ce55CL1fL+VFraVnohWkeEkWNDqUSUuXmUS7VVCvYTjnq\nT/R3/hXnEOiPx/j0zCUK6TgGelhf7ZfKIHAnU3t/5eAjf1oH3BkhEpRKPAQB8STq\nP/Fr1pntFB21HtNwwqZJV5XIoidAbGJLncrMBxuZILjmbv9QDPE/A6X5fuhOzetK\nsS5ZppwKr9D4kpz5bpn7xXPyCJVfn1djccLq54ppHJK68eEkZwjCouOj1nkx4m0p\nF6lEMPCvDTBkAhZGagp5BmbCeOoaOmGOXlYRqBX0OY9nicxmbFN6rcxpUDQ2OeW8\nDc6e3lMPrzI2TiswkaMnUTWWT7EAiKE9k8iFGlNICNpiTqz+Q/GSXRazRBS8rCnX\n1im+g2KkWs9SXaMcbSeO31wlO+ZdD5NcYlc7GLQm8z+KONat/CMOPLf5JrHQt4vJ\nd83bmcM7vvf4bBddioM4BiiydSKXAYoFDZzs7xXuce3LpCleYnUISVBF5g3KVLSE\n1j7Q6fERAXlFlv7ciEuKBz5A3SK7Xt7Eb7vQ\n=kARQ\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFltAggBEADHYmcgBOWwJTVRJCnqEpC8IvOber468ikSgNolQHFbyUkJy/kd\ncx+byBnvqs+s050N6EocIkmPvaa+ptNYf21uDnGKPyFqPMKn68iAXwVDasUK1SST\nlQSixf4qyHjcD7oyDm+1behw0J+KEnjLj941/Q4TOTu93ntRtgBKX0urXTvGjuxk\niHyMiPSiisuV4S0cpi5XsPOPrCvRFrx6xUGRAPf5+MVJkbS5AknmE/aFaMa7yfXe\nhZEYIwJzHFgYYRTZH4RB+a6fO3VqVdEEO2oHtR34c4bEn28rtgcrJv/3rTa1yXZx\nWf/qGHthRUXY+eHwV+Ih3zOxlQ+nGBK5sarqpOLF2iuVYbmtJeYo6b0LQRVxNEOo\nkmxEOJEpkKJfq1nWRd3hY80KRnNCwCbGjM5i2s8IbyDtvmyVCZAtpBkQOpL24Uej\nO15EaqJUMLbAwbrj3vNZZBRcWC4/MWL8seYYn05cIRKp9tf8+JsJFpq1VYcgtMjJ\nbu11+B/lhuNwDow+iBETfHgwNl61B9/2AlyMo2qGnnJ9Q/fBxJDV+F/cSun/zyr5\nks5wIuzY8fDYzmqaYROgZObGDwqbEON5wl/iQKFSMfLB138AP1TY7yDLueuuohpL\nCxEiVntr6+d7FIWIDfJS7FLQJvC6riUfp9TWXjnqPjIQPeraGNlqKSUIeQARAQAB\ntCJSdXkgQWRvcm5vIDxydXlhZG9ybm9AaG90bWFpbC5jb20+iQI5BBMBCAAjBQJZ\nbQIIAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQl7AUGb2S+AqKBw//\naQJ7OXWKXIiIr45ojfTJ7IaFbhaRE3awRyzrnnaGmZSiv4RN6Uzbx7FrzOPVKr/S\nzelUVYlRt+umZCIcB3fv0bOqa32GXHNN6mVPQL1OWFPfS6NqV9tEpE3bdGmffYck\n1r3Hst/kL5OeTp6VV7YP1bMy1kvoGNzOWKnZx1sV5FKOVWmJ05mG6QGj+rFOEE5C\n/mQbs6x8/aoIVXMNdNJMGPcA/+lPKaz1vk2yIt1r5YTtTlzz0IihltYUihuoi22G\nViwSOqjtK6c6HhfeUOfz53rZKjgtcmQNFlypVJLCb2tUZQSTauOiaY25Qs3jkvTX\nHi+QqIWH3slDBtF/CsppDFb02jSFyHYbNvWnlOPHAcjYHwMGPXdNJCVDB9a8XQHU\nlYJQFvy1uDefycWYZk9zveaeHEiB/zHX5q16yT2jQxpt1oPjZzVU/fmPtIw5vHmn\nHMG1lO6A22mKXArmH+RwLrSIYIT9VYpY5nkhKikCPe4mAL3jQmkObAJh6q8+cVGG\n8+CjEQXMYQ/6ui8+2vqUNfakzOCdzUDc+pTIm93kGXkMaUObS94ocMxqBZgFpiGS\nix1oxF9ggAzIySu+FEflxzyNBqXyCg/CwQl5hBkWhTJ8cdBWCCbHKZvDwgF0otSH\nH5xJnvc4OKF46CCrXezT9tn3ZnE7/eZse9f0gSKteXO5Ag0EWW0CCAEQAOjS4fWh\nZ6dmAs4suTyf26i+rpDiL8SRoR2uxH4G2fepxFWHPPsiYEdGyXFeY87I80la9bJ1\n7LjYqdTscNq1jQPfkeV6wd+XOm8oDXHszvuZMLPApc7BBOEcMpvG4X8iABVn4/Aq\nYqOAHyztph9Fai1TefqgBxlLJNGXUDCruqJxIQpAlEPgV/kSmvTen4ieiaECWupa\nnox6RY/012HhpkwNtVBuVQwTd33/FHCysZZvv92rZyFqIfkLP5am1xUmbShsmmaX\n0VOUjjyrMaCHrdwAnG09qDRRltKQiSjBWv4qH2EZl6E7KPQQdIIeUBCKU2tSQLw4\nfaQj5Mgjnbt57XYA8UALuQQxg5rIKrgqg9602Sp+JlP1xbNe+RgIRzK5foR10rAT\noDYWsDLDtFEM08zNWAsgndt1BbtFOS38oiLYFpscFAvKke8Z6SG68bhqvLK+jh+S\ncBrCTc2VCUA+MkGgpWbUjvEYrBgjpChmj+CHThOGRE1PPNz7lpHFdgFkIsDDSyrW\nFaJuqS4/oWz1zpivKDim8AATiRxhCiVDd+l9bR9YKHHTaBcZw8FJT2YUsH6/dTKZ\neOjFaNH6nY/A0S4QAXI2TPIl7rTwCHm9+GxqJtTPIqHfvoZ2hfL3N3LguZxjuEEp\n48mDr+Pvib2HdoTYc6KeqBJ6xl+hCs2vwE2FABEBAAGJAh8EGAEIAAkFAlltAggC\nGwwACgkQl7AUGb2S+AoKVBAAj8SuwYHG3c0cgcgKxV6WcYLyPuZywsUZA02CA70B\ngSZi6lyrhPb2akXq3Mrh0NX0GxfgDHokggaMuXZtuluj/9FhWCqlvcG4sb3gujnX\nunzzYBZ8KtgPDLFV4zAVdHBsQnSFKFeemVvKYD1vlkGPkHoO8JHl9gZz/mei0OER\ncyYbyw4ufUEgSEGaKf1BfHveXeM5F2atthtjYvhsq5RsrUB9QazG/UKu0fMCof/6\n3WkwlJoi00SNtMbwqFkhnjxZkZ9S+flLj4TXciGuopNkzZwnUtBjTqrSjgedTKpH\n8S5vPiqBORR8hcb3lKKHSIyIBDHkf0Tk5sDNjobmRzp0LQ7hKh3HgCfNMLOwffTO\nw8ZMI/B14VHnsrzrUIms4Gs8lohT4FdbC+SxW9bdN8ifGPVojD6IsxQXpgTXGddT\nZJDuFrNZJsrPguinZSzXBIA1sqLHf4jc6iH/qkdOr3jmDWiFtXJD5mH8hy+a2NZ9\nVNsIyghvEedwy61grPghFDrkJKN/nmbTsoS5zVIkBwCtvdY7/8cXdY4QFXWREWAu\nzvT091yoDiEFqFc0HUTEHzJEHwDiBNaRvWvsph3/wejwrPz6IZ8jh/dvhTH1ueF7\nn+uWqOu9Yo24d3z8jRopp7dTponoPYTQKmH8uzNeqvO3DFxm7fJ7TSrXaYJndOQ3\nAI4=\n=Sf/w\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBFTROWUBCACslqx8p2znj3CwEqWK+bEgyfxykVC1iFEABB6UCQ5UrlAiYTjI\n0vwFaTlbWkD3dWBxiFN2+n24Lro549ATmXGO+i0Sacr7DTgawZdkJuM17nNmlAW1\nc1lo6D/KfQ1K7QrakloQw10LzLLW3uxi3OXVoefY1JKTeQn43jolrCHho9iNvZ0N\nxyihQYzSiRzqMQGltKw5UDdbhwuzr9jROgHuUH+msOzax9IkLb8mm2VqJ3HaDJWk\noAaU92leGoicEBhR8qC3zGzua7pRFK8qhjaSSL/N/NpCu4ud6axHaBomfn5HJQNT\ndTHB6R6wsVgMED9vfZHqJeyltDvA8FDw4uQnABEBAAG0OUNocmlzdG9waGVyIERp\nY2tpbnNvbiA8Y2hyaXN0b3BoZXIucy5kaWNraW5zb25AZ21haWwuY29tPokBOAQT\nAQIAIgUCVNE5ZQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQbVqCrH43\nCTvBaAf9HEU1MhfIF8qlGno0WQojtEW8hLskw0Dd4OeG3cLsSmCa72zEjEVHw82X\ng862h3vfEybf7nd+mxdoSDT3iLwD8NOW6pnzW4/RjRGwvKKUhYggu8oi3xBSNj+h\nGRg2dkRWpCtqJo1q0XUdh34iqJUpk2isYvsQuHJrbcglPLO+tuFFNZ0JTf1f895s\nOnP1f+N1ygOnhehRoxO8gjncU3M8TXSsX8LQuCYfrBXayT5kZ49j5/+HOS8dHxYE\nR9e4LpPIWpfWQtXgXZKxcpyu0x25ZO6jkQLhleXtRpCfDO3DJw7l80suGf7Vjt0P\nXiYk5K2Z6x7h9rhWkEN92kTmRSbErrkBDQRU0TllAQgA1g9MDLyGI3/W+oXwrl2r\n2DKvJFRALeUHyedU+oaGo47XBKvNk4UdIDeHuUvf5DzYJW6t8GH1G55ZdYGik9/M\n16/6b1eYA2T7P6kjOmCGtv3KMkCLbymlFxb5SWEWwVR16L+5eXfVKbEBT7n2MGwT\nc42DCJzg7APZasaJuRQDoPgQFVQ1WX+0eXimAgdYlbtVjZmrkaIZbzGIcET1lJdB\nxOj+bR0pXIXbOvo5FlCVMmGAefrDePhqfuFMAQup8d4Gd7V19AcV8FyNUrVkji/a\niupi4FcBKLuF5yybJLY5d/Ij0pZ7MGUcbUhe9CbOZv9fvZBnL1Ukl9bxfchzrM2h\nVwARAQABiQEfBBgBAgAJBQJU0TllAhsMAAoJEG1agqx+Nwk7vzAH/iTv3qDimLGA\n9YdgSJ0h1aWZBgU2okJLLEeZQQuNHzM+ekQDhBA6Bdb938VtNUAdCSABBKUlFeq7\n+cqpcH1YgHyBv6K6avTI0F2Y1+nYIqZoe4n1QlcWg858fg4zzjBPU+s2eVIl9rOZ\nkMioU0UgM53DOhz/KjCHIWeLCpZAdfXsK2+lzWLINoYJ767wTNkXWPcxj2mGtht3\nhCOcTHK5toVhlytM7vGVacn0xwOhNSNMBwFq6rucIi/fgLheNDFgLPykE48XmLau\nfb3Fyii+q1BCWWZsyZjkLW7kcpf62i/YlrJHjWRheWLblLtxqy4ZiKqqLCtyfh9a\nxr5u2jsokh8=\n=2Ugv\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQENBEx8nbMBCACjmblSAGggunFHAWRGZLWLKltA2PG6rIM0bOokJFWtGwRqBCAa\ndKuNwBGy7eBwFQAxuHnNwDKqyGgCKUBe4RUuz0gKr1WgkPAzHZppo/n5BhE4iIxr\nlWJBKVKk/gjXVUBPhRPWNTa23JbzJHntxzHqeMQWIwIdBXoyOf0tOuXcfH2oVBdq\np8nFaeJQ906F6olUD8U12LgIhkg6/NTDLymwkau4YcOe8c2repNITVFaP6w5FmSj\naWTnyFXpdnVF4fWpbrLXsPBG72UMsAyWW4XuMtO07t4MvzgKBQALmGqlGMVtVkCI\njBgYD250NqBGKPmBrfJQVYbEesOZqNAF7bdNABEBAAG0J2lzYWFjcyAoaHR0cDov\nL2Jsb2cuaXpzLm1lLykgPGlAaXpzLm1lPokBOAQTAQIAIgUCTHydswIbAwYLCQgH\nAwIGFQgCCQoLBBYCAwECHgECF4AACgkQsKeLCmxIHPYyyAf8CUkbVGxWid46g9jq\nhYJd4o2Au0l6Y5prhraugbMw72PUstn6VAqx77Voe4NS5J/8942HHWjtlMIn42gU\nB5DS6gnGDFpo/64d3AZZ66meOE7OHcD2qo/kvziIPq77paOu4ZLF6XcY1xycCCkq\nL+8zzH409o6uR/LN4APeUcCmnqugibA1vOmQcvU1Ks+X0hKEHOkjDjws8F3yUokG\nahUrtvYqJ7qNx5RQvKzvcNbhM7omZ2KXH57YyhyvSdUvfjzaFv7D2CABDlVk4xxT\nGAZjmAKrKI6mvJLU36Ip9XJTH4J7iAqOe2phUSmOdZOfRrF6qFkvmNNNkH4MbDu/\np9IPOLkBDQRMfJ2zAQgArSXiNKQXWZizpdNy/C5fWIqmczpW8MwnVY99PfB6+gnA\nRxZ1GX4J1APd1rniOEOEEgWiB+QsihuMLHYuGHBhQo1zvrrmvUAZpNwz4NovcCAq\n3AzMMk+VQYDYWqqkUFnct1dLblf6SuuZ/beWUk+Rju1mRQoi9heMMwjvNlqPBc0v\nN8y3I8WhxCtQpWIMvQs7LN3v0s8AWNCV9VsQxmgtYpx5kMe3aYMJWEa+RzqhNvgP\nFwfOUaBXQ07dBqLOhTjMomEVeBoCkBU8mrIrgqoOkucKZE5/Hlqb8d1y0AiO02bs\nzCHPc5Wx5aCpq+EYWhskM8Zg3CpXhHQx3rE8oMnX7wARAQABiQEfBBgBAgAJBQJM\nfJ2zAhsMAAoJELCniwpsSBz2bckH/0+0te0aioSQWEb39JYZCcBvXvvnpL/pHgPa\nZ6tOizCf8/3tSRbwxI2CQ19p8ji95v+A0c1G4LwiTfZY3lEkIk0ZL1M1Ky82x/lc\n6hhsIVQ3JdrCSuOUzMhgQQk+I+xPr8gx4+1GL+Ia9F44o0CP0WgPeLshmK03hmjy\nZqC+u0j/R8OQqS/kVe7qt41nmNZzwsROuKuJt1xFD2GMquL+Z4oCu4YLKM13WPkd\n+ntZI9Gu0N7YDY4tKQCtcjs7z7AwVpfCesnuJtMtFb1+xuyt5DErMVN83Mi1VrUu\npYtVXNkSmiSUWMmh7QfVNFrWDqlP8vUi3BIEV3FtjXblPkbKbow=\n=o1Jn\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFiGktYBEADoBPdUkwVA9dNViz2wxb+e3XiaQaesSHvRReDpOpWQ7yuw2yLd\nxeUer6Iexcoje/i18x+eD7FF1gi+Lo2J1LVIRchTCx2vGs9P2iYW1iypCRl89C72\nsq0aHz6SiW0OActk5FOJtlOycuYpGra8bKqyTk8en17s6EyjEcvQ54FWacriLz6f\nk1ZnV3mBIiy03IWEOaVUxIvmuBM8MQRUXYn/BxUX1Vpo0qpqf9qtXR7QbiUyjTN/\ndHUz3vxYT266afEsOmFOgdU2LwsZsNKASUnHsRzNMeMqTIopED3MLVH1IvxsAEyl\nlA0fEHV1pCEI8ue6Gbvfn2o0r+GyXAZFB7pJweSJKnF4kmvLfj6a5o/UBG1JWQBB\nZFlnjpCZF5hL8W6ldcMj0eCED2PEbFGiEirkNzjyU1sUesSluLsvOc4fzr0PYFBN\nGAn9SNTlEq5FpCubwpsmKsZDq/UWaY9fSguC/UhRe6oknty5swKtkp4hKrrTPjwU\nVTN/fwdgiHKF/NIovdP+vhItkv34pBcqF89udPXtsDHtyo1Bm17ezFXVGXWSnwfw\np9KdLVnIXGbKe2z1cpmvM3AI1QaWpl2nA+bXfYFVarHhTp+nWs5PzSUXEItD9K1r\nSUa9Vz6oQx1WpsM9ZZi3rF4sKhSRc2r1VBUoeETQjPzjK0zsSqdA4VwGBQARAQAB\ntCNJdGFsbyBBLiBDYXNhcyA8bWVAaXRhbG9hY2FzYXMuY29tPokCOAQTAQgALAUC\nWIaS1gkQI+/v6TxM//4CGwMFCR4TOAACGQEECwcJAwUVCAoCAwQWAAECAADH0hAA\n2H1WNEsPxwuuyNWAp4Lz+dwPpymTs6psfm8qOx7npErQAGlTdlJL2vMl1P6He9Oc\niBEoJQFrDbFy/ug34YI1PdUnsybIXg3INM6MGI+j9a9yTULzWfa3j7Tkg23oAvtm\nfkd94QZZUujvNvNF4Jd2beSaiJ9jHHAgSc9l4lovLeclFSVMxabn2V9TzyrRELIF\nl0j36a6IPu+hIhHk27pR/8SvD5ivJdwEuVEgb2TWcwvlwBwfWqG+HK70WPoHZJ4N\nwEcrfsrLGI6awhjkfUqxfuKN1HUystRIhuo4OmKk3ioUc9H4jMPIBZezZB0QASu6\nHfdILNhfWtxWlVBTRu4BEGUYr5fPHAhdSf9XUq7ZtNGXl4puC+fhsHpX1/GtS83e\nD+Z2YH+kYsK32KYSo9xWiICmcttMnocggVP+s15GiaormIM0bbseMbGh8gpuSqEU\nnaP8kQEkqkbgMetUSS6noZPHMDMIcuvpGSbKnfYtBSrnKtXq7t7u1XoejJoQOjrL\nBp8C4FN+HcMBx8xqd2SkV26MZWeIauP08nxTHj8nG7Wk3XnW4eJ8whO5UKSaOtLq\nB8XMKhLNxBXvKM15y+ex7mKkJzKjpAnbIKTAr5+75VxbLklXD4U69Lji2AYtywF7\nE8861k/FV5nUYIxWM9rA0yM6OYHSMsEDaWa8MmSJK6a5Ag0EWIaS1gEQAK9E6slK\nFUYVeOWV2qv4OlMyw3scGKuczu/p6xql3UcYk0FA2ErXq8YLo3APt+k4nlufQDMT\nVE80pn8Jc4SgKd7vQzhe7OyRSWpHviTC9FzGRXVYAc34AFQg5eZ8hVBmJD1szwWV\nQUWhbvkxcN3xR5o6cxrE4x9gxCfTMKT7TDajpQcq3JMkRDov1d8V49rFOrGlaVaA\nMvnQl4s9ypBsXlq/znXGmk+pGutIxq3QThPkjiFbab3oDgpMJe3RPKtzOJhInV6W\nGJdmmAn5mXASmTeUPfYkONqvj2ClzHY2ejiqPaIx3HrYPb87GlyQuhE1qPbmx2AL\nslkHOYYbBu5JsTWrlBPCMwids1xyxSYU0QJY8Ey+kkr9EL78e3Pyrfve3/jlbh3v\nNc2BDGUAoX301WFnUQEPkJLLdDqo+p2tt0mHcOVUf8qcWX6EvDGyeNXRWFc8mCyD\nrZPMgYOVL83o3kLraWP1wJbpuJ6ThBQuA3X82LSF50rpoF3MO2lLgJHWzWtxr6uC\nqKauA62Xqolbf4xLG2IuwMssMBixl2Fae4GFQHtcjIEG02KvmsWJss2OR3FQXhSD\nz1T32by804WJNo4GPLetO8X1e0SpjeqD8pJR/vlbCnjKzUu4DtGgqQ0RP9ZewaJT\njt5LR0PoM5CZIqusAg9+qx5b2mEkP6Ftus9ZABEBAAGJAjUEGAEIACkFAliGktYJ\nECPv7+k8TP/+AhsMBQkeEzgABAsHCQMFFQgKAgMEFgABAgAACwkP/RpocTf+3Fp4\nxTVt8OzSdYgGZKuqFW8cS/LMjNYrfQPo1+a/ts/zWEgt9rY9/GMiA4Ie10DjG0Cp\nXcbb/7tR5YsqW/S26JmbHynyZCQDoyw6e4NHixZNDxV3RquRPLOUE7C/P9IvxhcN\nLFZ5ICBJJtD5GLtevDAT4GNxZJ4ppuqaBDgensttDQi9Dl/6EFZ8u+6AKAcj/s9E\n+FBulqWUh1AsTtChq+XxoMbwCp43q0Et+OfX1FGSi21ue1tSVIb5ahiTaFiLJ1kZ\nGUrCQ19yy5po0XSn2kfQdHpGuySeurFP6XwNoubgHAgwVeOdK4IQ9+IneRXhvNFE\n0PuI5+iR2MmKiPgKGsVHrjrWQOXvOp2QYipTjmpD5qSWjRZMW9+KJOuwxcukiGsI\n2fygZJPR4zy7cYJ+YwVvGE7z3s1MNifPXA4xxe4xWonjz1oMoq8RXzMuWONSMmJl\nUOdurRATVpvNV2YG0lEDfvfZu4HCvOUcvnPgFxpnB7VtCw8cDPIL0Skmfs+0lx0O\nR8GTU+wZbH1yY++q9fVdubxShWJ7TH7CB7lIzvvkl4N1HjWUed1bDrtHLn0aBBqm\nQ6hquBOorI1gxgDFkGoq928iFLyN0C3mV1qAmlWq5EKlKr3U4DEwbRMUYIFcqO2r\nOweTnxa0BqWTj1O87/SvSKdOd9ZI5GIp\n=K6ke\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFSvCTEBEADIa8J6pku+vT9RZ/cU4wKmC441OVghEZ8Cuct4AynkZQZ8Hpra\n4mq9SEjB9t2KSM7kvN/yBrrJBJwAnR7Q+e3+gfthL8Hmgr7K2J+qJdSm7Va/LcSK\nzZjN8UX0EFC+gh+gda9qm0nwRTgxR9k9nWu3l6zcvEsLE79m9Uir3W8BtGak9HCU\n69aSaaWupoqTXgPvYuh0LaF5C+qEccUls/Bmuw8FPP+T8OmOc5SU8pD9uz2r2S+p\nrBqh6rutBBqzPRl19nR9MCv/2jYmPqyCtvBbalxy8fvxC4wuBSarkgUD2dj/aIqa\njUMMBDFELXxFwTKd73RQtxnHha9VsbIFpy5wpt0NBq9/Yi2ZI44Q4PqccOs+ByKJ\n8iZsvg46WDwmZ58pU8Bxkl/Qaz9numDfGYYV1Vhk45ACob67zYGDgVE1X2BBe5iY\nJIA8hergbPZf3j5DA/5cCEONqTCLc70XYWE31x2+6DcywZ2xxJfMw8eEOihCBMwe\nrNiMYH0uENEo/b6q71g23rNC/mNhZCYF8k8crbCmbuKDNjaQA6zxQW9E4hzqkkte\nTfNRi06il3fAKbkfDjIX0kH+/XGaCd0rYK3mvx32tVzuZmk86EEFot/+OOAh4zkq\nQ/DirFRXnGCbJVPtyGWO65CutAlFSoOaVN7G3tJhQCQGg5jb41l27d904QARAQAB\ntCFKdWxpZW4gR2lsbGkgPGpnaWxsaUBmYXN0bWFpbC5mbT6JAj0EEwEKACcFAlSv\nCTECGwMFCQeGH4AFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQUKMFH4iMYo02\nxQ//bdrpGrxbSlZnC+cMS0dRzZ6zbW/r1QPV/Bag4GeWl61BhMSdGg99Feb2kkqH\n47P7wv23PyzGT1aaUnMwlQeR/tVz3gVCHfe1rAQ6pNtZYEA5b/IF4RhIYoZr+9ke\nwlNIJk/zSCVd6110nzMrb9Z82cJiIb9MPiYzw3BW3Gzw7EsdGPbFwiCsRZf4BApa\nHMY+T2j8AlENDNSOtsvlLwKRiSQqd00XvEciZ/xtB1VYgNVGHN+21sVZdadj8+Oi\nH2iHnbdcElVadsCpKdcmETqteRyrXXA0FW5WPEM5N1qNWT3Aml4C22cU+S8Kdx79\n5uPKUQjgOWl6/x6z2HxSPWMOGVS5+X/r047vOGa3kap9RbOTiyxQNixcsxomHUQL\nJcYU+K+dzSeuXY6uc33gSY1a9QkKdzWI8+ECbS7CaKg/540AOtRswbXWxpRpGz2l\nB5sfN4g53aCn1XvcMDWtjrkXNBn4tRyoH/YUohWU4IPBtyetKSr5UgngHNVBkDNF\nWKn7vpcfeM6Tc40cdyQEvc+bmVdcsUmBY7wzkzJTyIf9YBSJXD4MhN0PzJHdmNvA\n9R3dyv4beYDKWqxxgH6/f6xVgI7nPM8UhDbM0FcztwbUcrM+jX1uv/6XR4/AYE2e\nUVRfplMrlJKoZlX/5wP1H0BX7xHdL6P1S4AZg2K9INKeuce5Ag0EVK8JMQEQAKdI\nri92rNrpBoU2vhVsbNNGaJV1A+jDvyoOJ+ahbG2EJKMjkOHZTfW5ZrO3GWpmXQJ+\neTCy3nbBkKTNI/HxKc7xU1WpnK/YRyRtDOJrUN2MiMvo5HYmv+g5fDoG/8oS4KXZ\n6nn09UCZPwo+B00nKWLFIcFblMvZh/a7h3r3kVu4yCEKSu4gO7Vhdz0wHJhy3PSh\ntRDh9BTjHaW7R10o8agwHMXKeoWyOZUZb9QqifbnK98gVHmw6qT6FlY3czFWtSUk\nbk4O3Ew2tiupguTrenC8+Mp+qyd9r7WHJZrKfNYQYLD32eojXvd3VCrSmfYbVUlh\nmvSFTE/95d0EMAuxAodKVtpayqyQKDXKfb2X2gtoCWKaYtxYlh/XVqiuh+BYAZzA\ntiRLmLe0joPhm9ew7z5PvMJ8Xl4HU+BX1TexNfviFvE4Q7xqaEnJLG82ms/pPzAr\nx5qIcUPkEtR3vu6kyvk3AZXc7D7ZQtPhaN49CNES3g50rvF7bY2Rw1xBfxMUpUyA\nq2btT31NWIj5Hrx8wr/ivPxMzxpNQu4ujuo74f4ilaXlsksNxN5JPPDCmVc8pRMV\nlIhjd7T5E/4dwiKCt14G3Lgeoynln9czO80jasYTxs2Ietl5EhZ110DqUhG9GIId\nf5d3Qb56l3Nv9Shrtlhu0q02aQayaP2HkFHchXxbABEBAAGJAiUEGAEKAA8FAlSv\nCTECGwwFCQeGH4AACgkQUKMFH4iMYo1xPA//TKoprQhJ365yHH/h2ZqSXP0V4UkF\n5WGxzf0k+BBKzgKnhH4yCBwyRU1txbZ+V4mTf5odoKb7h90NJNzWgLDqkURXAK/M\nCRc6KdaGiOrIXNWQKayCDwhQ3LXU7FstzTzPFKiwlYsRuCw+36CSEkRzB+onLoBA\nVOzh1QAlLLO+hdUDs/OswS3GNRg+HGltazgy/LZ3nJ2lsqXOmHGgXe+P8eZKTvJV\nrg48rmws5NbhK4JHA7oVvJb8mCaOvsOh3Sj5BTgdJQCTClYqjyhcX3D54OQumXYL\n3pAWHZ2+po75Ybg8KzcDosgYl2+2byxVDTWv4muP67t1Latqg0LmJrlsjxdIG8s4\n1WMdXvei9kXU1qr15yIsGVQ81tOxmb/m15S3JyubyQXVP6zfqUrhS8LGk4wpEUyw\noUyfo0DMkpIwSPlV0KkSo5pApY//cUNr9MEYJDUTZGgclY4JxtF18LtnKUmb74Mt\nLD0YJhGRrdrZluYcl9yBfvPDEtb4PmD00dlpyUk6ehf38L3XOmWyCxqa6jjL9dax\nTNYE7DPKQo5n2WKKuCqjMfyeRnwCqgO4BwsocxPhZl3NzW/mH0orA2mxwg/6MJUF\nk7rTC4J6kM9hoUCMOJ0XqBfQZVeQd2x3bkZpx1ubH6L5ilZHKSvHcqOy6HE4wyDz\nUSXWhEefc3s6beE=\n=v6Nn\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQGiBEPOjg4RBAC2iPU+EHukOrmApMnhYym03gV/VbdPDydVVj+fc7TyjULlKWP7\niEMFZb58EBjjK4Db3O5JiC9yZ7NRgYvqCFGP7hTVBTykJucXIyT8wCmaAImrtAlg\nhA7LKTKlMdkPMz+iTiaVivt5F2W24Lfy/f664J5POcUH3Y5e1dhImNY6fwCg9TN8\nT2QKrFuudsbvqdw+w9I9ZD8EALBfpb39xdZenQllhq6MnODIzeHf5+wQV0slAzaO\nRZCAVWodGtNx3NYomvmOuhY3iwFrTiGW7r+3CDqt/4us1vhn/y/A8JijReltOeF0\nnbTM9HzD+3MrlTZMSfR9lzpu941IDkvw67NeFdSHPxLEEcAxI+eoS5dYsdjM3isb\nOvv1A/9jJFYcPg+CRDPYVsY7ok+JW6olXfDzK0pg9zKS2gNbYq2AhyvKKjM/L1Ca\nRkmpliBQZEq3QarXrirdwtR9283JKQ7K5UgigkCDqxE2C7jF4XZ6BA41Wh63GPFF\nhV1J7R+LI/FZiG0gE0y+bckeSB68+wdh8jnb2JCkNkegbBU70LQvVGltb3RoeSBK\nIEZvbnRhaW5lIChPRlRDKSA8dGpmb250YWluZUBvZnRjLm5ldD6IaAQTEQIAKAIb\nAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAlMeUUgFCREw9rcACgkQfTP/nQJG\nQG1lcgCfdK0g8n4Rwe7ng5CiGsK2aeFu3tMAn2GJN5GDVyVpxIvDMAITPIcbpJFi\niGgEExECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJVFZjCBQkTKD4x\nAAoJEH0z/50CRkBt9DUAn3JLT9PifudI9mbufjOvNhTRjNzBAKDnPR1ceqWO3F78\nO02juhMZp82YfYhoBBMRAgAoBQJRPNokAhsDBQkPT38mBgsJCAcDAgYVCAIJCgsE\nFgIDAQIeAQIXgAAKCRB9M/+dAkZAbSbgAJ4q2SMC4N9bzJwiU1fdz8evS2z5xgCg\nhyS/CRrGGzlBbaQfLsY2h6CVftO0MlRpbW90aHkgSiBGb250YWluZSAoV29yaykg\nPHRqLmZvbnRhaW5lQGpveWVudC5jb20+iGgEExECACgCGwMGCwkIBwMCBhUIAgkK\nCwQWAgMBAh4BAheABQJTHlFIBQkRMPa3AAoJEH0z/50CRkBtgOgAoKCVOmY7DUec\nppH25/ZNtzhUZUBQAKCv6nNAXhafNJ1KEi9nPLsweUv6CohoBBMRAgAoAhsDBgsJ\nCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCVRWYwgUJEyg+MQAKCRB9M/+dAkZAbSXB\nAJ9T4QxHcQiglAj6unDkpNCfQd8gAwCfd3zAVN6xtlDI119a/Gvb5H2JskeIaAQT\nEQIAKAUCUTzaRgIbAwUJD09/JgYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ\nfTP/nQJGQG0vcQCfXBAfor5DHZEd0vrUAtHoZXIiRNEAoKs9sryP9dD65Uf8P0eL\nW7NpB/Y5tDRUaW1vdGh5IEogRm9udGFpbmUgKFBlcnNvbmFsKSA8dGpmb250YWlu\nZUBnbWFpbC5jb20+iGsEExECACsCGwMFCQ9PfyYGCwkIBwMCBhUIAgkKCwQWAgMB\nAh4BAheABQJRPNqyAhkBAAoJEH0z/50CRkBtqIwAn2HZ88QHvZFReoqNo/saO4ax\nzqxyAJ94cWr+bwMO8wbx2JHTtGxRKx+s+ohrBBMRAgArAhsDBgsJCAcDAgYVCAIJ\nCgsEFgIDAQIeAQIXgAIZAQUCUx5RRQUJETD2twAKCRB9M/+dAkZAbe1gAKC/YnU4\nK3YvGN3zDZZqA45F6dGUywCcCzQs5rgW4ivr4kVTWb0JJXh6BNCIawQTEQIAKwIb\nAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4ACGQEFAlUVmL8FCRMoPjEACgkQfTP/\nnQJGQG1yCgCgrxLj45QV/4cZ8rarKJjetNdBj8gAoMxW6LSPod4qwTE2jw2Qf4wP\nlXC7tEBUaW1vdGh5IEogRm9udGFpbmUgKFBlcnNvbmFsIEtleSkgPHRqZm9udGFp\nbmVAYXR4Y29uc3VsdGluZy5jb20+iGQEExECACQCGwMGCwkIBwMCAxUCAwMWAgEC\nHgECF4AFAk1yezwFCQ1mVBUACgkQfTP/nQJGQG2ITACg3Zd9owEpcatNeuPrWpmL\nM3yORKIAn2kmpLHReRpKQ+buF/I2SUq5uLXbiGQEExECACQCGwMGCwkIBwMCAxUC\nAwMWAgECHgECF4AFAlE82bQFCQ9PfyYACgkQfTP/nQJGQG0qEQCfbXfhJFcYc/7k\nlu56ErfoVejcFdEAoOdUqZR1xrvo2KlJ5VjLLfYQSrjAiGQEExECACQCGwMGCwkI\nBwMCAxUCAwMWAgECHgECF4AFAlMeUUgFCREw9rcACgkQfTP/nQJGQG21QQCdEysx\nve0BrhHvguEY000u2qib94YAnjAEizeGyU24omSDGaRu4R3ZXf21iGQEExECACQC\nGwMGCwkIBwMCAxUCAwMWAgECHgECF4AFAlUVmMIFCRMoPjEACgkQfTP/nQJGQG27\n0ACfTnIRPUS4LBzdfibQITWkhntX71IAn2ie7nGByDTPHvGrweLrymQtvUj/iGQE\nExECACQFAkPOjg4CGwMFCQlmAYAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQfTP/\nnQJGQG0ljQCcD9WLRu209WbSIgKQtqiC1moxqXsAoIbKSLaI7jL+a3jH3bWuoomq\nnNLpuQINBEPOjhMQCADE7uQ2/Z/yXL6asrYXkTLUIJ1toTkdYe8qVK/rW7XrjZye\nXjx88PUGLL+480iTqQhDuUMvTONKW+09RwXuXk88OT6IpDxTfrUoYUQnLrE6O9ZV\nYTJOdVXUbNv7j/Yl7RTGCoeNp/A+NmdWa1fW2UU3ME2OyQU5Zn/7U5YkNwgVFlpu\nh59xWWTnZtwxBuhBufBc+dSm5kItZ31XbA6yGH917klpm7EWrRgzyQmT9y/K5PtE\nQDs2oLg3+O7yezz8mG1JpIR13CoLjgdQqtVSEs0bZG4vKvwquG1DyVCcjLunwZmr\nERUv1fG0n1sXnHIA9d67a5tFasQHBKdcC4xVj+tLAAMFB/904UJbUVM/bsP0pJFZ\nJ0p1rhXlcxyTs+xngq5oed5y1AogmGIwSAyn/LWm78GgSsy4vJuQWxpE1oNb3TF7\nv3GSi6XKKarX0Ne842YC27Sz6GgG3T7O8HHXGxduNPnNoiREaLGEsJacuA/zyGmn\nQlKBxQK3aXulkZmXr7nzVUTUAdy/z1vljJ+/hnxNsroQPV3/97hscU4qlr+Ga3Na\n2SK6/0528bc1c2EytS9+hUcPXiIRxBAFapSoWWJI1tBMRggQheWWsxFFVFk0WlYa\nW9doKJ3aVpt/xObNlurt/b3J8UJ0CgumwAgBDDqQiHIuvwvIh+llMcOCjSmOL1kX\n6/rwiE8EGBECAA8FAkPOjhMCGwwFCQlmAYAACgkQfTP/nQJGQG0jIgCggpvZkUdq\nIuKp+2ArWFlzlhT9eWoAoLnbH9U3VeVJMqipWJhNYHcwekXfuQINBE1ygEoBEADM\n2zl4oVCqfpwxw5luyfkac4E4A4vgGZgA88n7LMLAG8kkHr+JCdCi/z+K7WB1F6Gq\nWzoJPS9l/IF/GHRndrsRRQ13nXbHrem0ZjRSiCrRU7o+WZ/3y+IFIrjn74hTxJIW\nOJM+Y/QkfLv8vNgbcTGOAB3qMv1dq9cNReX98JQ2DW+U/FZPyvGSP6hc0JzcahQ6\neLsq/Y1BZWj0ET1ZSClYRdooaiFdKuEKGSH70WTpxrDjuymDOaNLfmgfmJpS26U8\ncEE6ThQ91phzQpD/MiWVaRFGSq71TxIMAdNoQZgugirutVGGQ8zD6FHnd9sL52H9\nMmzFltjMf12aosW51HFW28B1c1Mxy4P4DlWlfUeYG1OYKAiU231tyFP1uMnk+hCG\nsL7ntgAF/SM0WWqXjUWNpzt1EcDCsFHN7ZUI2uVUcbwoqZ/XlP2TgPzsZBKG4jXg\nFOXEKLGvYHaTc5xoGYP1lr8uB9oihkv6c6q10hjvTEPxAi40IIzdTQsXdVOlaPjd\nb2yI3UUqruEYv6OTIxdYZXJg64z99v6n0eFtuRPFEHcyiuyIxVik3fB+mKiCBW7x\nR3KRRo2nwiPq9W1PT5lClIdd5W2GnVm0aARlbQrFcNLBTNBi+osBopNvFpat5rKX\nDzniioD2CfESmW/t49LFqkPBk6Lg07SHAIkQyoHhYQARAQABiEkEGBECAAkFAk1y\ngEoCGwwACgkQfTP/nQJGQG2l6ACfbyXz7xaWlSaubTDOo/N6yKFkKSQAoILPCUOi\nUhw2iju+XrCVJ/AXUtwH\n=AG5V\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBF/qTWsBEADlnzvN5W//gwj5oOpnyPQLjjguiXi0NPe9o0LcQgOmccD8a76R\nr4VQDDM9iFieOcmdcJzTeEcTli165+pBTilqR/RBjq63N4jFzzsiCDJaf8utUhlW\nV7ISG3tpzEJWcgdqK+YlNgVv5C0K1BwvXfh5H5P8pRzvLTpmnhvBIoV4srnVP158\nPifAkbeEBIZU5xyjmFSgevX1QSvjpIdAGvo7RKNzNbbG8SK5KNOkrPzGq3lOtpwA\nduj21q55MZrDEIxYxBwCtcx24qkEyBe01ox/K61yqs8HVFn0vJZ44ghLwUzR+dPf\nfQD8VKrNrmIu8Bh+NZeLUiRSb7eZAwNjeDA4+AgSF1ntp89iKPSmeycslwjSXj2M\n1GzXjOCucEn+kYC5FBIEmfLn9vAiLL98V8IlV0OkljIN0VF8eCaGmiFcX0+4mdaK\nl7XS5v8dGVHZ9ons4i5aP1oyWtMhW4rqe59kHzzrHIXJEmu8wOCCq0CtirSh6r4V\nTBsIxWJwkVLFY94LLuC0XF57HPVg1smU/sXDhXUWNUhiPKtsYXfc/jwZvXwJjmXY\nHO+6/jXWDsdDlMneG9ip+bFCfYA8Zi1GvVUtfJ1rU3GGIIowicbYT9y1pURFC7Hi\nvAPPpNJN+ZKuOlfe3Rhjwr7uVjjNWjMzdzxhessE2BjMgBMsCzVOv2nPvwARAQAB\ntChEYW5pZWxsZSBBZGFtcyA8YWRhbXpkYW5pZWxsZUBnbWFpbC5jb20+iQJXBBMB\nCABBAhsDBQkHhhy9BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEdPEmArbxxOkT\n+qN606iWE2Q7YgEFAl/rK/ACGQEACgkQ06iWE2Q7YgG3HxAAmTVUQ78hN0ynUFjY\nvQxdtKLhj7adYQFC63CsV5mueScnw+qo92yvrm1SxM+/YJ8dfBHnT2UFclXbN0je\nCrZwpj6GBoNF6WdwguunUsAtIAqhsTzyovGRioOcKjn+laat9q/gKgs78hCWYl3+\n76dE6CprjRPXl1uXF8wWmSkRFQlgHPsvFXKATm9vWRSVYqlCHXk5IuOAhJJbkacq\n4aUx889zlXyZrM8ALhML+j3gWSwFt2XiADxAHQ0Y9GsM3KNLfpsAhameV++/H9DZ\nmS9xz4IAZn1kq1dCF1I2NKLkuZkdHh3WCcWMhm5yM5kLad3X4cq5KTg9PNgbB8Uy\n2VnUv91xIbnsr0EIo0pit5ii6EtCsbU1CTI0arXbo5BV1TTf0O255Hwxe5C+pLiY\nNrR9XJZ70cF4Em6BbVfs2GpSxiACIf3JCSd7gZYtArfR660esZGdxZeC8a00Tx/o\nIZpyyTvz5qUWOykWt5kk0Nz7hhnz2SU3z85+6FHW9bAl3cQnuBoIbBvxO7kTNYYT\ny4KKhhvwFXIB+EL9VGedQAf2r3SEAKqmmdHemRMf8c2clrQIJqTUjuZdpI4BZUqL\nIba3v7AIdENhFCGjsb2moKv+q4XD/YH582Rym66HVfFtw1/tvVwXxM8AcEIONktW\nKF5i7i+kdwodOpepex2rHiDXZsSJAlQEEwEIAD4WIQR08SYCtvHE6RP6o3rTqJYT\nZDtiAQUCX+pgZwIbAwUJB4YcvQULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRDT\nqJYTZDtiAXozEACA+AIiaN55SlktI3+vDKWV2EZmgycWJ3z9bZNJj+P7qM31sB0L\n+ciT5ZrF7ktX9wn+oVWimU8DhpQO/bdYUbzePpJ6ng/YrRF33RKcH9dMk99Pre1u\nvkTs88Wi5FYyYjFIcbxWY+MkxlzhpqVjU71Woj7Y1SacTaHNZoHl089Rnq8l/8WH\nDoGHLNVavcU8uKGv8465YS+1pX2lxSg6ste0UN94kxepLCnD9MmgO60at2m3qBLX\nJbysf/LYeaEQpn3z5EKhN+f17tqW4Zyo9N6LaI9eY2EnwMh9uM2woSKSDuLyI5jx\n6wAgoHKJwn6ps7xbU81CYdXs9hZRPxegyCd2VCQD0btQ5k9WJfKRuPJt2d8c3vqg\nn5hJIWpQF3V6OErlz3CO2abWihJrYrBFtdXTqgA2XwNdny/C70P+axk7bt3ne9K7\n4BJlLIIWllGTXehyJa1n0AVw08m/+iHYo7334iJZZ0KGScxFyUgnPpxwKIkRdVA/\nCXqN4J/nmb6OKxsM+u4ypiV5VDb7sWb/iPTrBikGG8ZDN4DtOvRzHWvz5n5zwsiG\n2tnCF6HLnkOUVGFCD5xByiGwqogcPr+SqsJ3BsRV3WxGt6DNZBOX6kGuNBcpTz7l\nTrPdWLX3JPReTLgarSxBHzgULMJwkfecnzxXddWF+S0qkwQVQdIeR1VfRLQqRGFu\naWVsbGUgQWRhbXMgPGRhbmllbGxlLmFkYW1zQGhlcm9rdS5jb20+iQJUBBMBCAA+\nFiEEdPEmArbxxOkT+qN606iWE2Q7YgEFAl/qUJoCGwMFCQeGHL0FCwkIBwIGFQoJ\nCAsCBBYCAwECHgECF4AACgkQ06iWE2Q7YgGWoA/+L5mVMtm3tvFKxs3OwN0ORhSH\nrU5YQ9sSVTrh9/uOrjkITywB6tHI/QPmHcil5T+nrld5dJWg63ybb5zZPLU+L6tH\nh+g6nylyGeo/YCcp24WcQj9bTpMn6q+nkmkIZ2hic4nUXs9mal6/Tb/FrDqr/JEG\neDpCimAhTyXmZeehGuQ0lZwayVp/XutIAzZkDALY1IpUYLmsoptMTqazy52/Fgk6\nzT+fqqln+d+2YsNrGUxsH08kq6nlovf3J+B4CUJqgdWUqT7/E3bX9Yl0waR9TzO4\n6rdHOIyxtRDbj7UkNAHt6ANWmJZy4QzFY1fMarDlSyAYnG4OSInGQlKP7rs97+U4\nywd2HWRsACWFuQgPyyK17IIO5AFN0EYLD6J+MPfz7SRrQWLD/TD7HIU2SX53jmjz\nVTfSEsruSEs3T4RiKah5tDydNnriWhTfoRsx88s9aFaCgcZjJueb7Yvi8LGMSSxJ\nSzqjVvCkFOdXrwbvMT2fpUY9zjX9i/+y/JerZaxJs4Jc/bWFS+6irMDPYaU+jrtO\nkbd683Tv9edxj0TZE840Wlciu1jfGNeNn+QHyozQdO+7ASABuWnlzDQJfG58pThv\nCBvgAbhr3pWhwQM2xMLD7JvCrrBAapSULW99TndeONp5G3RWyjXa6jXmoLEWqwN5\n6CS8+k071ntkKxFcjua0LkRhbmllbGxlIEFkYW1zIDxkYW5pZWxsZS5hZGFtc0Bz\nYWxlc2ZvcmNlLmNvbT6JAlQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC\nF4AFCQeGHL0WIQR08SYCtvHE6RP6o3rTqJYTZDtiAQUCX+sr7wAKCRDTqJYTZDti\nAd2IEACCMdIFYKq77tY09OD6BBIPJYzgSCLm4teswU1Dj/Farv56xlIcm1vs8mq+\npvU+1lkvpTwGYSi3x0j0ZJNxtOMYpoiiNLFKQZZoXLpwAFwO0aIfTPS3ZO4qTUNX\nMOAk2UweQfZah5Qo1ljw3n2uz2lj8QOz7V2rdHMicvIXw39ep63ZHzq6KIlsKvQm\nzm0qPQ6/2vA0HXBN67Ab5228U4RkFdKC3rTHxw0EMIq4mwYpW1lys+zitN2qcefm\nEolT1mJk+WNjelgB95/HrFzoIUkt7V6+7vSgJlQ8vMLJMV+GZieMaTv5XVrW+VoC\nhYYy/i3ccRjacn5C9v6yvKP92cP/ER90JUnwmiKWw5dVvT/oiyX1mXsNPC9iBQM0\n7ErsVwfWGWVWHYpDmeF9HKpFPh+l1M+u/DTS7vIBMeF/DlEZZx37coKKkk+/17YA\nccUSeDGi/yRBV63aWWEZsOQG0lQD6Jqw1xliAcCqjyUL6t1GK9gt0aNa7iQv38eJ\nRM8lKI6EVfgaPXeVpEUDUTdvtSVXS4F6Ch1R83b2aIlH6V4+3M/5IN2jRTehEeqE\nb/GX2lFKrq2tz1PHFDBKyxGX5h89LDnoHTA36JbyHrPtc5PmvjFTSpeRyCix5WnH\nQVUAtk1VABC5DRbATPtAkTpHGVp+UahyhHGOjzmO92l+SsoqNIkCVwQTAQgAQQIb\nAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAUJB4YcvRYhBHTxJgK28cTpE/qjetOo\nlhNkO2IBBQJf6lCbAhkBAAoJENOolhNkO2IBE1wQAKLyZ5D4GB2xojA1Uvuhw0Gr\nm/T9Ti2BrH4h8Vm9iAObTuz38osUZb//d5x313iBy0Wu169TD3eA+RUxybsnP3Cn\nzOX1osh4w8zAn3HMFUD0OrS8cBbTD341MxcS1lHa+RIYa+D0e4VQQehb5zMRNxxt\n8zkqGJL7MeCJrWL8YL8AGA6LXpZUfW+liZVvNBirzHSVYkDWjPf594zn88DQEPSN\nVMw8D2QjwwVrzXvydgpSy+yR2+2lEkh8bhZnZMjPNAwUaSb3BsBh1PPoTb1J31GH\nKT1z8yECP1/EvOKkk4UnWYKYD2W6GRUuSzItn+BHa0GzlCSLcaDMZCyDsxRVOCUU\n307k7NSS/NwX8MUY664YS9JkcWhCslnNkL7mFI7kDq4kEzgapGitWNbnMsuS2tQ0\nM87BooiuW5GMoh3ZZUcuXJuyLcIjKmrayLwToHgQW8XdKe5qXNw3mH5/1qXKGiYY\nDVH1U6GTc9bs0xLf1MyykoMm7uqY7knVwMawC4/ipuHCz0jf+GA5+shs+8RxP55m\nTXXO2QnqM82Ac4LcI8ucgVfq1vjF5XUWTwTpjOVzU/D10z+T2kj93YPOFWON1TeX\nSMzrYathhyKWtyJJg7qBQaTLc80Sp8htYaAmFtHIHpKQcrQr1FPTJGLAADoPUlA4\naf+jP8Nmn4SlWHcF6YoHiQJUBBMBCAA+AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4B\nAheAFiEEdPEmArbxxOkT+qN606iWE2Q7YgEFAl/qTa4FCQeGHL0ACgkQ06iWE2Q7\nYgGNCQ//T0uJJvmuWSSQ6JdMzwqjSpvI4EXfRFn55rtW7R3m6UP7ihdQCXTzsChL\nKN3VSXmLd9N0BKdTaNjh/FD7SoJIMaVPXnD6wjjH1+o9RzkrXiXwNJEvlQ9v4kId\nnqsODA8hFTSN9umyf/WA2VqJ62erQSAkhXqgD19tQ4PdB58aG4hlg2xhXP/LhzLm\nO/2KRy1pbeZfEUFBObpymP5cD2QrQYk9T0xIGv+QZUolqiOoks21Oh9a1ArN6CMk\nnFdq6mbJF3Ev802TLSpJ6oy+F0AhrW8eEjKh0G3LO+jcz0CWFjuOKuRJt+v4gbr+\njXc465sbjSDH1K5ys2lyO8HYpFgiVmzLXba/ibmBszDQGZFY7oAynxTczAtyJteV\n/8luCLvQ8Ki3cc68NcmYYRrDGp3iLhmVnf/jwxffvei2zVJZGv03gY4vGkZJyfFO\nSmqH/y/UrvdKn0d2Pd/Ym1KpW65UDHYqz3bsg8D2NltZFT7QWHP+QVxXMp6JGfrO\nqVPwnLHEHNaRQaveokjAxQADCNBULjDBXKQtFNzKRPKY9dia9OXriTj3EE+PZ+MY\nTvJvzXOmjQpI7ZVRTYFAdjHpjqU4C0AGeGVxB3xdMXglaQZKiNV2JvidbjTczd52\n4iZMFtrnoM8JOgpD6fSbQJnsEb1hzbP2QJo+dPSnx0GBjTFNu5eJAlQEEwEIAD4W\nIQR08SYCtvHE6RP6o3rTqJYTZDtiAQUCX+pNawIbAwUJB4YcvQULCQgHAgYVCgkI\nCwIEFgIDAQIeAQIXgAAKCRDTqJYTZDtiAUujD/9DuQT9ZRV93ev+63Tn/fX0031C\nNXhov18cQByhdyP4xzhFY/B/2AHyfvNbbP7GPkWqFmyEwhtdTcfuXOeDl6puV+3W\nP6w4NRmhEkdtwfOlmHo0vQGvGdOa80PCJPXOuDD0PybL/sJSBlRETquiqxgKwYQp\n78DWaEiE01wxcDnAcfmJBiKW7urGFrIfmvgLaeI6p8bqHOrIF8T0MhnoVSceUXV7\n4EBjWBajxJNhYMnn8VsqkbmVEcA/4Mgthes61yxflwlqbrTTg5+AmOM+fqF8rJdF\nnLrCoza5bIOlY22rRs+tMqvwiv4SrafncwdAqSxlGDDvxXVUpyC30kULOiHatjni\nxcf5SfQwp2f2tKAEKpsiTRc6UTwf2A1lQboosWi14NeP/TbmCs827xsuCxUpkSLe\nOOlG8dWkwVaJKGmMNAbvuiDIdsWO6c15unYuUqQrZ8OVQMKZkhrKJZJdXUxXtiz3\nKWLaYlQ4EmK8PfRAuMTE7Ugac9U9utKp8hTrs5E+on+E3XFqKBl9teWtbw+8zn72\neAsCwCu/yLLo7tXG1oUlkoreAeSmUexoWNmrC6xwVmPGonxj7m2HYgjkrS0dxGBc\n9v9m3A/Py67HZaaLowsEQYDGX47hLhZcwntUyC0YTLNSA7bDwdeX6QEQ/yzbyVgM\nAmu+vfkFZL1GU8DhE7kCDQRf6k1rARAAucHY4jWkVnzie+2CdEvMJJ69UVtbOSDe\nnNgH1UFqQJwueLJTAxr0dMr4BxbE7L/8BHaHD52JNufOAKmGnrXY1MK1JKl7cPN6\ndBJPA52zykc50KBuIEM1Vy2eAlYvX14Ffyf/Mt0KkAAmqGW1Ti8pWlUez59HzdWj\nV7ELB77eGgB+J7VEMZIhJGxptlqqU4RNV09euuwa3zvL1IUxe0K+L4SK4vbJrCCz\nPjwXHXrOXYtcKj8+VjfyjAg5oXCbI+TNNwwtmNoH3N5dBEjnvyAYOWUDYcG+OFoN\ng2uMYrSOOc3VOMx8p0pMEYY4lJCEBBIBFL+wCqEeXyeq6cJ6N7wGqKdpueNDnA8g\nYKOaA0Ax1G6KS3Zd4ZJV2zIKtPEHK0cvR3jlaQ+Y0rszqjqLjWfU463KKf+5P7GM\nuKuGghohjUAbzmbs7lCfZL9I44Ria2kBfGQm/w3GbFbL599RtyjVvkcLZGvWX1yH\nK7p4VIWKciWAdydFjIeDPC6vLKxmHC2urom94A0geJCgQ2BXPf22b+PaXPpB5WOa\nnbAt+FenKWzK+8q2e3Lp8aIbJgY2nXh9SzAeQlBnAIANF6vxmzVYEs1WhL6vxTGu\n6kPf0yTn5qOFnL+GuGm8eJqSDk7MZDY1hloqxWgWebWP7uan5U+cqsni6XPyHXP7\n/wJxXg5GSQMAEQEAAYkCPAQYAQgAJhYhBHTxJgK28cTpE/qjetOolhNkO2IBBQJf\n6k1rAhsMBQkHhhy9AAoJENOolhNkO2IB0psP/1Dmb1dbzoEeoTCQObL9ivZal+tN\nWv1OxWsAjE4ITVLkOLaHMdLSAQAoXju1iRN+bFO11qXXETVrzvNKuTfk7XalReOE\nJIFF01xSKQbECKaSx8y+CKUpWowidLV3m2utNy9sInFtYGdm0HMlNgEhKQrO9u6P\nyKusVYaT9/c8NL5Gaksgbvii7Mgwc9a1Hv/ffFdTmOOv+sw5KUkmR3Kv0SXRtXNG\nT1MKkVdUdZ6PjtcqDIH0J/xV+JVjE5DmjGkb8Rzk+WeWXehzMDXdQuonsUh2mUdG\nqi77vK6hMauD9w79rQjP3fH5AYlH0mtowCUODrGLdUnVskdWqw6lV9LXTQUwTiTF\nRCb8ehLe4t7bkdh5uxcTpwN1bLMx9dpu4M3hCAh5DW1UAcuDpCDS2vrKQsLN2/2z\nkOTH5HDnvlp75/QC5B7cLe6nj4yUSe6twFFnT50T/hDYJPnzvcqKGZDTM7jEWjtR\n+QFjCI21FYOwO+ddCtHRPr0CtC++H3OJc3AVqI4YNMvGH0MI5yP+K3+/bwRpCYKB\nptG2zf386NG8iZZtBPkHRtxWwgBfs05rGw/eIcFkDSea4G9CvTsgOczxny/mIbPw\nZZ4mxiQ4srJvZcj63UV3H4Jsr4vXJrhRSDX5Va8mAyF+rF6g4Cjgxp1fqkB0A1lK\nni5lUGYmUmXIuRub\n=EVa1\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGHo9TgBEADbSK0AjEvbVkjrvHk3HG1InM3H0kqEjXxenzTukSHQOl8ytLUD\ngP1PPzuHmgTqgONkNa3JNHv7AMO7lUukIYTSvtzOI6fl2i13ZeASDGCBfFHYjxeA\nAcwVe0lTbQUrQA6sUTBJIxL/3JcP0h8mCc5usIiafSclgnTTMbjhbyN5/GJ4AYgv\nv85oyarvX5q2qQhtP6JcevhNwTAxU00XBnPyMr5bL9CSAImOpHDAk/8CLoC4UIW5\nioBFINVzZ1DVq1e5O6JTx1XOshimCCom/VFs0LZg35kpKTRMG/kBkXx+8ZfqQPan\njpQ7PWO+H6+AYQl2azWAnmQbyAFqXI03ipQzaGbAya7pPPI36+CK54GnlZIrUJIL\n5ho91tHzHVyEpOhuWRMhflqpya6y94u0WVAjgjCALB5qdzUCku6hUJvJkxsU+ncp\n8JM/4N5uiQPw5kIgNGvMuWcOz4Gpk9zUuG4/b+3C8OpFIcyJqlDA6VCbDEdVVVK1\n0IO9fm5rJn3n0qrwCRymeyzB2zO5ckW7LqhULd/ZcMi0JR4QyN/IpaE4EcSUW6w/\nQ0nu2i9mFZSyb2ZHmQNkcqDSJ7+ykLKXdGIeND1A5NCntg2fBbCTxtVbSLOCwnRy\nM1fRQzR7+6DSvuMIFvwaQdzwDvl/zoxsSt8ZgoBWadzMuur/yVHBH+VjmQARAQAB\ntCZCcnlhbiBFbmdsaXNoIDxicnlhbkBicnlhbmVuZ2xpc2guY29tPokCTgQTAQoA\nOBYhBBQfB1lbez/+dDCak3QFUzvlfH1XBQJh6PU4AhsDBQsJCAcCBhUKCQgLAgQW\nAgMBAh4BAheAAAoJEHQFUzvlfH1Xqr8QAMlZvdmrH7LckkLz/xLJM/Itp+Jcdlvl\nLw+C9yrzb8mVw92P3YriwpgefCb0k7EOwkG8TVtqh49oAjBgUV7tXpreOR5NzE0D\n2ihtoBPFGIjAKuuu594yVYf9gYEjRZ1yX8S/p+fZqNa9mv/g5mVhRq4M/v5JiaCt\nR9rCr/xW8RJWKsO/iXeVcAiY4liHd+eXbYiAqFDCITTu/EFWx1ovlHrEnbJ3Eqm4\nOeuK9TO+w+YUpouhAkLlyM4LgM4Y2ldQ3dYHcB1+G1jCuXR0hRD0bjE1EodP3xZH\nvBHXjVkeMuxHc0b5aJ6JY73l8K4VIaD42gHex77HEVBdUw8BFW6QWh8Y2d4142rW\nSLK36/nb8OTbw3VR7FSHfNv6+c2yAWm3+ni48w8A0IsfkleYvH8QedZe2RfKls1S\ncnkb5OLWzTm9bFRumDDpM9vqqtWOkOLNv2URhactRciZ8ZSuyDKKRZ/bqMesLEfA\nKKJyUca/o0N6rbeasulXYXUI1T/PXUFyP+8r19zN4VeqjdbC5HnZKRlu/SSjE8VU\nN24MR+P0Lypg/B2cLgNvuehNCkDfEYQOso2cB9mSAsvpc7PaJOJiG/9QAiXC9Ztc\nMTYfhqCJJzZ1biOMzCOtX9bhjDcEygRApvbvUtj84pJsR7wHaCxoDzcPPf6oAvlF\ntLD3CfsuzXXWiQIzBBABCgAdFiEEVO4USbAo/MQxUhAa2gJupRO6Ng8FAmIVXnkA\nCgkQ2gJupRO6Ng+yLhAAs+jqXpdUxRb6I9aUEG/r4XzUw6IdDlekFwzGHDers1xQ\nUMF6Ftt3AaTYrdAyG4HvwN61V3/epWGyyESlOHubrtHFc+w5laAJF+onbynu+Lli\nFSNkgqHc6AaTPp+GtTepwsvjGSkpVeGSjpADtz/IoK4FkQ2v0x26nhPVmUGFUelg\nHNjfr/AkFiC3+dKlBKPJWUTKMGKx8/p9jxNJ7UuBXbRI1FeR+GFcMaMCJQ8bm8MB\nbgaeXOzqY+USQGgIVM04GiBWAPj6fVz9RByhfcYQzGt1s+17n94+6CmhkOaDKqec\njnjXa56WnFVaib909YCRXyPi+0iDr40MqSmNKzrmz3g2W3l62pjCGQOy6B41miLM\n0VipRhgJZ4gNcf1LhfOZI3PUzK+DA7ATD9+HQ4x4y8BqJkyyKAovN8M9pH7ARFR9\nBbRil7dxU/7uXmMmhrCDghGPRzZOxlnvzqdCLDCjN4qXg29p5UpfgtAI8mZ8jfGD\nHiHxasSl11WfLueeM7BscldTrF3bd35z4G/Cuy9V/OpbWxojJGfU5zYzPwTg0Cbp\n0+y/pcQlU2c9lVxFiAwsgCQjwCcBaNW5DzZ/Mslrg0Yz5lAgLYGBbg6SWNGOJ0aj\nGSp6mJHRkgyRQPRjpKrYY/sfrxtVnQXbmZ3PvaooDiPyn9iColHgp081PA5bixG5\nAg0EYej1OAEQAOMKA1m67HIgfFz1ebL4j+KRVIllqE29+ASJTmuMpWlZiO/HBIGI\nnOnSQleHULFmjRIukTqyvYYpf7a0S8gbJMgXHwlW1gfLIJ8VF2wZ6OUwHg2s0Gaa\n4iyp6gI9tZDEmZEfAb/7WX+ouHvlPLiToM3ils99gvhwX2iv8YXhakgC/0eJOb7h\nfkKixlCoc8Gb5L1LzeRrQsJ2HoDVZDyk1BZ124wtPdTK8impsQL5F/4dafo7DY6R\ng+WJ/eZv50NpK21JJihaP4lq0fcqdbaa+hkRfiai/h1OVhG5fURnP44mt0b7AE7T\nt0O0t1ghS2REMWcWgAEiPaV5Uww1SucP6+X5+9CaYcsOZ35JxSg/VeipC4RMJkd5\n00pA41N4fpRtN38OJfLUOY5Fik6CrejP48v+PACPDkU9TnGO3Ng1ttnP37E9j1Qb\n+mpJ/dpf8q3JaIuXOMwkavp2PebborhrjUH5TLMytXTrVOuMqINYat7ap62VIW5U\n6dyZnyd6SB05Lf2nUkH5R1UpOSsThcENCHiY3Is5hBfqQf3lVBmNdCfUWZl0+j2m\n5WrF+7pG+IZU7cZ69e5zH9X78HL6OgJlTjiZWjMv2wWicWniz2RrATnnYKjrgYBJ\nQGhjo5T1u9h/U5FcFAgiiKfGzdHTD8iA9lC72zG08ssGg4cgQ4v4GLdZABEBAAGJ\nAjYEGAEKACAWIQQUHwdZW3s//nQwmpN0BVM75Xx9VwUCYej1OAIbDAAKCRB0BVM7\n5Xx9V1LbD/91t98rvV7PASnIWx9Ujc7Hf6ItHI+gdZsfw23jg2LwyefZYZxuLkok\nLT0aIVeZxh9OXCt1+HNEzWyPAaKyzPTzmTgDumhja1Fwduyi/BhHPeCNY46dygmE\nSdG78pLxcUvfsGKpyUwdeRHOwIJ8wmbwBq3AVpk89+EAddCC/VJzLRqf4BjF2sEi\nAKl2mwJhUtXgWzMN9yEj9/wh42WMtGKLMc7QXzf3xABkT0iGLoNbVhe9jeSAdHT1\nNyz1LgMnMmsVbESkqLNbaz95zHJP6NYv5UvUVK9FaWJHhFFGg8khG/U2tOjMNK41\nxeXTyOBkpc9LpgRwOAy0YQIYgzRkOv90/1xU0zFZXRhkCslkclz4dpk48mGKfq6F\n5t/xQDL8Xy4xllAaA+MfOFgh0KG5zD24X4Ve7C5tl6YVvWd8XA8YMQPTsx498BYY\nZoFo5CpitxS+U3wFbyD14DFLl5BKXLm3CvqR5/RQntUNd0oGQo8210bUNJMVLqS2\nlheM0/ykjIQiwCrun5UPxklwXDAYZTRtWD2tKmRvPaJLJecW4254jIR54EOJ2CLV\n42Z7a78BYbeLYEJym5V/IDEd2Vpd1/luW9TT2/E3A+4nbzwT7WHuLOQZzgCB2JFx\nyudDESHgKZ0E+4nz3kcyoat9yiPqNiIx3Cj4fDiRu/lJrLY+bpAwi7kCDQRh6Pce\nARAAqUMuuYnRU8sTdJbEyfbYy8XxiUiYN7J4chovmvKb6T6m8lqNkexcEe9Zgq1Z\nBd1WzuEHtz6Y59pYGGvLkR7BGBZ4WVIZbRuMzjXYZDLdmng4vThvqPgAce/uwIio\n4uVfElhixD/hUrPBfrBNK8YQvWiJq6MIXf3M/ieE2wdq3vGRy5u4OFOOFXJU7IKE\nRub4oCd38EYrS/ntwRY2+X7kgzGZ3c0suiZd9Mj/YuY+zQGVyvTYMjAKTcaT5fFA\nV7Z6OGeedmBfyICeefqW0oozwXnEt3Xh507aBQ2PKAYScYY9URSLGanx1LzYHRla\nfnOXr+efpti//ZpCYfwnPtc1Qz+VeQHuJl2l1qvCftWE56QlOkoFXiTLhezvGvY1\nLfypTDf9EcWvBNSdC7ztdjWHrIsrEheHGMGmMms1hb5vfNYJ8I81FJ9QA5MsQssR\n+3a8YmzSo38Mh/VOJ5t6pYEVjWPturkaXx+9xb4IvKg2VJ22risByW9zcK6gsuGX\nji3LCeHZSJr+8BS7KJurKBlK0fZgtDLEEzcZeACkj8anjKMgNARtdm5ger2ClT7V\ngOoHHssCi+0oXZZPYHdEzyir3qMUWDvdz0856YPEIJRcGP/q1ALroScVCMWR99bm\nggfQZd1c+zpdrGzsFpM7cz7fqygIjfdN+PT7vWSJsqr7Lk0AEQEAAYkCNgQYAQoA\nIBYhBBQfB1lbez/+dDCak3QFUzvlfH1XBQJh6PceAhsgAAoJEHQFUzvlfH1XEGgP\n/RKmZQx8ZwTM8aHvaKQzc8j19MvnlNiZwyhpEurIlISdwteRNPA8Prb+c61RvDSf\n3DbsI6J9EcYlwLZ01a7bf6qNlYvxCfgm9k7N4nsLxFYBgUZjvgUOFqlrPsIto7IZ\n517cyiRjqu7fHVS+aSguz/7L09041LPKls8Zu2boLT93EYbuj3RZm+ItmC2YN7Mv\nAozTjlMDMgJL5fSjfrTRkzrwNOJ4J+RyMlFcMzTRiPYI/gUAdeS3wBCm3lLHIbiC\n7U19sqZlbXBvHPwyARp/PlUo5i5/Br3oBAzcTIMxgUOdIRVUCxEgltu+RKyWMQhH\nTzhk5oIUR/wIcwGZK7stFDrpSubKVgJ9v6M/S5rbDffDvNeTtkx97ZANifizi0U4\n5UGaOkWDObkLx9zvPeaZMI/DmC/5LSMNVS53hbllYgtB+bHMjio8S7d8cbxKahsx\nc4rr77gfQAy+V9d6F9mgPgL1Jgt8CQx/olROIkzJnzXLLx1pl/jBxq71C+oNJcP0\nUposRhf6OMb6CbaMJExfV8cM3wsBfSdK9Px+M/TtmWHUDnUqlAInRWm/S3QOMA2w\nPggS8SeMj1QnC9JLQIiMKNUMpZ8Pq0XAQSQy7mWYwYN6/W3SqqZuJSxogDSIK1J6\nAdTumtl+mDJRFlYwC0LHorFIhLjym1o4FbcdU440P6xC\n=48+4\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmDMEZAFttBYJKwYBBAHaRw8BAQdA9UUQNclFp0rIrgtQnNw6BgjDINkFPoVbuS4H\nsQNEf+e0LEp1YW4gSm9zw6kgQXJib2xlZGEgPHNveWp1YW5hcmJvbEBnbWFpbC5j\nb20+iJMEExYKADsWIQTdeS9Zc8beUsQyy9rHer+gDdvytwUCZAFttAIbAwULCQgH\nAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRDHer+gDdvyt3PYAP9A8XbvZYT+N7k9\n2xnRMfrAUep6TLfWbx9uf7k/hm/+KAEAmqUYV1afcuwU2xXE5I8m25VMnCEKFFEF\n52tW2baWkQW4OARkAW20EgorBgEEAZdVAQUBAQdAtwscgbxby3vew2hn9F+KlVPL\nvFBPjnvODcnsqlO2mXQDAQgHiHgEGBYKACAWIQTdeS9Zc8beUsQyy9rHer+gDdvy\ntwUCZAFttAIbDAAKCRDHer+gDdvytzxaAQDvYX4o1Y6R30bYwIXemGgbO8GlCkgk\n5it7MjeSk8vUygEApE5zIi5OtP8TlPiMgu2MoJbIltqqDCKWTtHPIQRNIwk=\n=IisY\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: A363 A499 291C BBC9 40DD  62E4 1F10 027A F002 F8B0\nComment: ulises Gascon <ulisesgascongonzalez@gmail.com>\n\nxsFNBF0VqLoBEACiPJYKX/UT5OFnucsBQqSmFNPsRD6JaClRqNe8wQfOZKFNLyat\njtNj2Bvuq2wDTdKSiwcT3PWtPCEVEQ5i4MMzwmnflAV4KTtj8mLCGTR3ighnf9kF\nhBdX+G4I3lQ2rIAc7ie+sI67zFmsAC7wFTw06DrB18vxl5uX7H5UqDXLsOQKE3+D\nQ2SsygI+JsCanaZ+kk6pxgflNDlWj5uRIPe82Cwxg0gS0aQKX5m//diavfhlPmuo\nYaQioe8/b6Bo9re7opWhtEFfYyGUxaRxVTLoMRwWcacspwqHcGe+rp88YmLMUXDh\nPLmgGw8aAsf+b6Wcj12zPusny1sJoG7zwm37a98blyCoYFzx/xTG6gq/RLud/xdU\nOOOhPGMH9wQK9ngVYG3Wr+LWU0ABrUBayY1wE3QBj7wYkoK6BEYknzkzm7y4tO2j\nrv/9dxV8kt8zUEDwUq01Uj3TDe3YAbbYhXTVIXFwVarCM4AmdIrvKbJZz0JWCIA9\n6M3NVyIJHqY2KYsm/YWsWMDqieLQci5M78o3wSdr4vsbvTRRGnmpEXw5cU16qY+/\nnpWm3R2H4o3IV9qRrrcYTgMdS6QohCV3qBeTRCdy7n3YB6X78ITIo/I9ogGG2nrs\ni+mj0R6F39Y6Y/KQzDM1ECWjsk4pxdK71JGXWZWersmI8rymbtd/WT+UKwARAQAB\nzS51bGlzZXMgR2FzY29uIDx1bGlzZXNnYXNjb25nb256YWxlekBnbWFpbC5jb20+\nwsGUBBMBCAA+AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEo2OkmSkcu8lA\n3WLkHxACevAC+LAFAmg9l54FCRDLiWQACgkQHxACevAC+LAE/g/7BmvYINuaFeQX\nHjGRXVfkcXojrNKF5/co5XpvxaNl50UOrq+tInUg23/Q2ES76VMgONUIgIUqP71d\n/09D/dehFnEeHCJhflCMjAbuZPTovjyfTPPwqKQUMLl+P4z7QAq4HKiuqP6hQW0r\nIDsRsiODmDGMXgxA3O8tIphUmgQJi1GhiZXRZh8kNAo3d4pbkhoBXXXlgm+vJVu6\nhcf2KCjciNrsqw+V9oNq8LyZytpKBdYprph6eCvaiGlGUk6PMzM+6tNBPbYJPt0v\nyVQTGvfZrHe1auEjbh/oFColO/UgHfyAKe3yc+AnKuUWyLei+imz0fTio7Oj5d5C\n5HTUQCaWTwEM0sODb05zI9EHjkpzRHyTwEuZM9gO+by5M9M8pxJ60wrUrftOgDMe\nKm8+lIXmz6mYgfoOFHAzozwQDjfSCT1Fq30pWcCb3UiBb/zYV/N1CTqjnoEmHXiB\n5dSrEzNDBmSIVvJpbY1sokOfxD8PNi0kcvNiZnxZg+ogECjPKtPx5VbEr0FYZEW7\nQddAM163jfxmnLdYdtst9CxSqB6uMiz9F1ybMp8H4QE4wbmdGziqqebRV0m4EOiJ\nrJWmJnWFzaScG1dGU+Ez3ICL3Q4JHfHiQi8tu6rRUa7nCBtA28h43H+uIoHqapOZ\nOw/ZPZtFApgGgnLyN6VT38mTgIuRq5bCwZQEEwEIAD4CGwMFCwkIBwIGFQoJCAsC\nBBYCAwECHgECF4AWIQSjY6SZKRy7yUDdYuQfEAJ68AL4sAUCZHme/QUJCyZdQwAK\nCRAfEAJ68AL4sFb+EACOc8YAcl6I3uGnRAhiu0F4tUI+ls0W+1FgMTZItkCH7Yg5\nBLsu5arxs/Jn5YtEuV2Q2RipC2RJtNf/MKtJ94ubrljZQ3Ha3UApwq4qojiIm4mM\nBlK+gKnewX76axyauXU+WC0cmpTTAhTYPpFFNG80J3aWIJa6gbuMvqnfvuA3Spwx\n/SOsmUfnpKVFc11Tf1pE+1KcvvoKlAN2Xx/xNGT6GTsgxNWNCFpDVomSV5tnNd6g\nHT1/k6nnefrC11NqzqSwy6DLNjijFZ0jn6tJFZThg2r2RQC5RZvXoM448+aeBN4k\nzr3D16ojbXvCMpqHuU2PkZUgLjw7wVSaUbe1xUv5OmseprV+4R7t6FRIcc2yfRA9\nLUdh44bmdGBJ1yxiP+eFay+NqNiK7LYo3Z/Rbcdc/KLttR6wB6l4BLZ31VP0Dm7J\nSk5VK9LlsBleifYkldI14e4GkA3qR9C23YLyiAEeUi+bd/yW1wirCFxoplx0pwCr\nHi+Gr5EgLWDia/ODfQh3ZJfRI37efaMmRqjN4FyGvQaIyqCu9/Qv9MNE9JZSw93m\n9/2kK84lH+LyCoqDmFN1WlRs+FSc7PpR401bmthtruj1zDmvwxZOB/xmSdPE2R6R\n3JO9S0DqvVuNhbv4sntegLXY9tNJzfBKFkcPm84WJkOg7TzYkOE5eyLN4aG7mMLB\nlAQTAQgAPgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBKNjpJkpHLvJQN1i\n5B8QAnrwAviwBQJgthu8BQkHYtoCAAoJEB8QAnrwAviw9SsP/0VnbVs2BDS9BzzR\n8mjF7xcGGXgUJosusaDRmNHfGBgnH0SKH8TOql295TyGwzJyI4yUf/snq5YL6tUf\n5rPDFf+YqIfWkIJZ0lqxGzDqFXxV0Q1IxrxMaLDKZ0sFsV2fxXFRhpuvzGWkn7Gb\ne0EjWcHlI1a3gvdDpXV0HiH0ZwD1VAq57mooCr2UQH5A5IKgd5Kzy7z6gxBeNw5w\nq/gnxwkqON7WpAg4CXlEldL+xpS6sLTfB4apPCOOfjYL3dQTvatKZswm5UdYTgk/\nGO6Zqky2PZzRuXnoJ2vEDNTjNKtH33hRGLBrQDfYeAsrqQClrwJTK7cN40CC7Dh5\nZ23qcyuRo5SZZP6jC8VLf5+svFv+PQUZmZ+vojp8XzdGuXxCa7eeToHJOclgyA41\nMf0LJmJuaMT/3V1FHl26awrjB4RLBnDo0ULtAMFLhP29suc88BEO1HuDlV2SoJvx\nmuLyPdyA+i0r5zHxROwctQygHBaHVFX8ZSwG5+ZH7Daz08/tHk9J8mt3tR4jaBV8\nrn8RXaqg5lNcnXL28YSe3f7vsWzkODPEufR1dx4tvdCKM/Qpc4KUV9UIooX/QAeD\nU0URc+9x09CU7Ue7rh87v+a2riG3s9fNRGK5m/I8N/wbNBorf7J7TV5yNkDXs40A\nd0k7PmZYMKHxiosj1yWelPRQjokvwsGUBBMBCAA+FiEEo2OkmSkcu8lA3WLkHxAC\nevAC+LAFAl0VqLoCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ\nHxACevAC+LDNmg//aDq4im2VJLm+3wY0DNYYnkyBcRupgqkFUPQD+nhbKLvCWeLt\nrNZmi20ODZYNfhZqhvyfkoaq6NBCPSagVhU/2H/n/aLTM+y4VfYbtOFjWA8JrUyB\nwsPgIMxNoDqe1pZNAgFdly6/wS9OUbg4HyEhvTU6LzMbXHZ6ZZDfcgMMwPV3+/sw\nge4gmhTNkAF+jeiwM097Q2zLctAeH5kxXWmhUex4oWW/mP+Z2KTp7yKc1Fg3fy21\nzQ4CCyDE8lWszC+caxL6QgwRcmO5FGKGvkYTGkkGWFOa6Sfm8rJHI5XjPzXtq/+E\nyUrrvV3fxdDBJYsqM5HZt0uyaB7NTU7a4VGG6aIqjlaujZSXmHs0LZWFn5SpVmwc\nQ2/H7lK+lWzczOMMTmpQPiqPeRu0WIGZnrc2d8gVUTVKJOClCfQTFeBPSwwA1qFo\nPbZ4dNXg/TcAWEIdtwKPVq440hH10ZyYdW2POEw1tMthy/58mpxc0+W6rixpgT+D\nSEPmBdbgk4/XZOYk6sCJnp7L7CBBRXs36DTELZMzrlvTjR3weR9D32/G43Us6Se5\nyNdjKrkBsmtHYrSvwtokXpCO4tu3hVsJQ9juzsx9Dsf1WTV82VDT592K4HSh5APp\n1KJ2Z5gELlqqOOef9QRIK9EEgN15oSjXEkIRJkq2m7LHMingmvm+ST3qIxDOwU0E\naHptGwEQAKvzjhzR8jBL5Ey1CsD2kStMhyNMEGL+5m15Vzch06jmttzJX2xMDFLy\n/Vm3vdM1YnM+gQheRZpzRbYBRtJja27CBu/YJP0/PvuIW940Lvp+MGuWdg9VJ7Hq\nLjT1GQSJ4SgrkC+p7wUMtW59SeCditzRX5SIYsMryds/T8HYH8n3YyuOn0z5VjKG\nwKww77mUJp6QA9CNtNxeiELJXovg0uYp/kPfAOVck8WtCHXKFm8tZ/469/PtnT3s\njFK3/nya1zBUi2OlQhhpQwRgk+tiSKWbnQEmSIh7v5ZRfYph3pdpnYWf7eHLzF+k\nZLK3kHf0S9L0QR/xraCRvViQIeVyyf3Q5sXggfxtHIF9mXPdXkMPonT8T8Bp0IGS\nqFVKwvY8osQ945/WWEE06pmX6X0buE6tsnVZVHNdH76soFh3MKlg+hlxDTivhtk5\nuIj8S0BG7Z0YxkVM4dobUGsum5Mbkl52Zq/+RHkFGPUvp0BL3Xw0BgOk1uj5NVOQ\nS/VVN4FDkjq8iPb97JumsbxbPD3maCcM7Z8BZE1HJl0mUsqSblLLy+cARWNlWSfr\njMN2OUxhF+6a5AfndJv1PndAlGbpEd04UWaODbZ+D29DocmNKKVOuCNf0bOWZmir\noBQFzHs1CorUjg2CSZWkjoC/P1BGwWoygsYGy1QLXe2/knxCTOgVABEBAAHCw7IE\nGAEKACYWIQSjY6SZKRy7yUDdYuQfEAJ68AL4sAUCaHptGwIbAgUJA8JnAAJACRAf\nEAJ68AL4sMF0IAQZAQoAHRYhBMKyXZtCctspVluofzx4JPOaiVdYBQJoem0bAAoJ\nEDx4JPOaiVdYgWMP/i2TATu3s+8yL74Q2W7H+85QrC3nGGN8FVeDskXwbu/fdmTF\nop/6A2nPSP04f3x+OoIY+J/d1KGdk0HGEmf8DAVFJOJhc1jQ9gUteHLGfjwHXqp4\nzh8tszs/HZ2zwvgO3fVN6NlhhMX5A4sH0Obzxih/KhkwlRcBbXYYvuT6WpaM1S7B\no9jthsrY2rL0lVaHL4o3dCCRVR5FKdy2mYNlgcsEyWDmGa8Ss2CqCTaIrxNxfZS3\neASxDoV380uiR2i/KV9BLtElz/YAXShmQJ8CYmFYgzCDGlTfZBoQonRnm5d1g93H\nONB7n9Vta6pBLDvDdEJiB/Oy1G8LSowW5juQB5bLf6PZksoYmbhjcIwX+gpnklZr\nXxOTYe0S01y8a5lD9wx0L+WiKinwETRnn5XoMMrx9c1nfOqixkPAKy/nwnoOYSPY\nwLTY1GXT87taZfc3BRGkmRxcrv3sU4qrzHab8jJ0Oax53vvcHI9qmdcRBDtb8X8h\n7uXHZTu+bVRBtiFO6HhHEhY5squGzNP0YphZSdL7dXj+rBZ611MA0dmBwp27dwlA\nV26KEF8DWp780akC7lOb1g83Yag4lEofCduWSHMeaLRckD7HwDjOecLXALfIJNSS\nhPWPr5WP9kNnBjrnzU48tCxfnx8eJUMsy673S/8DStTyKH1mk2BBIbQ6kYzYuDkP\n/j7dtChcatXNpjtV0IDctbq2tPWb67cPpTEBTaiAjoC1zFYstSblQU1h9SDFMyMU\nutKlTfuqlmbiPHmSyaZyvaSVZlx1Yx8yA96Lq79ATd+CnYl8CWQDaQQ4E+i4psJp\nrSn7XgnF+RBhujZiP/jcRuTwJ1RZm2v4pNtBmAaW5ZXPyR4fKZLFsW22FJDNzLtZ\ncBBz8HPD3IGH0spUaf5PalYoNpBgh6euCWP8W0fCKyIPy6bIL5ycHuo3ErWzIHLe\nkO9gGeaSN/t1VLgdE16Gaozu8Oypx2u0c9fhR7aqYTOxPfcrekuBEevHAKxOe1bI\nEqcgqdxht3bXFvfeqx6kvmn8Y9EhGjA8W/PWraVoCrKVdHXVe47l4i/1QZU3UxnE\neAj97ArW6H/Os1cjK9K77xzCpAz8FMT7AaPQq3uReUaDqoNIMTO+tCFB2dYQYeX8\nYGgILe40bMpCnvY6zxC7UvlO+YxhZSQkF80Ytk/2eHuoLeEiM9IW/0+zxjP6SNmn\nfhlkLevudlFFxoYlg5uWH6BIKLSUF1gCRIFKj3T1OnMrDlEAkNYrA3WATxHWEYAZ\nNsZ4wS4I0oPY2bZ8ScS+2qwmcrUf4Zoq/praBJY9GYslAh29MmXmvSMuVt0SlYYW\nKdMepn86/V0vJYpLKmNHrhToycaaVIN3p69Ap5mIztWLzsFNBF0VqLoBEAC/lPmx\nQvfX2S520XOnOD0GnvqnKFUvICc+hfU9vW7o7Dy9ZdGFLRgmkrZbXCNowwPlGI66\nVSOUfwueEvmJh5BQRXIv7gkvLhC7yO7OpyqAiLVrux2K69b7Jw/y91FZZZyaOyH8\nkXdVNO7qAQ4aOTTln+DbIXa2WW1fljUktbFhSzjK3CRtVL7NUgHrFePGfETZimII\nU4ZxjtX52NLQpyoh56WoGpW9+oXe2wEGYYYcHJszKD9iZyNCpSULT7pRNFwZQ3yQ\nXNptOotYCw0L8gAmSwJ6SUge+MdLk1BGpXEji7rEvUxj99ymh3sTWqczdKAgYWtw\niis0KDpLrCtDohrc0JJxc2D2cI1FbcF+b4GA1+KGUAR9yd3+EC5yXLYPU0d3BN5a\nXjCaXCr/vWLS4/LcXBAIjzGF1Jdr1a5uQBD7JBv/4JxLCd9r9aqfU+pSUgM0+4oB\n1Pxqo+0fm7m42ALve9c+t5Yq7q9B/eHSx6sacfq7DD+Eo6NuxIZF9prl8b83uPE/\nYr0INE+Jm/DPLO9FfQYuuLZsyb3RcQ8RaArVdWMteYBke2tbAxlaWK2X+qvDqjsb\nRNzjQKZEM+ib8uWcLxQQIF8g/6OAY6JXPNJrYTMyAkRsy8regIyZcCs9KVw6+jAn\nHOXAyFURqpyDallSGd2sUFURidTqgrZIVBJ6yQARAQABwsOyBBgBCAAmAhsuFiEE\no2OkmSkcu8lA3WLkHxACevAC+LAFAmR5nv0FCQsmXUMCQAkQHxACevAC+LDBdCAE\nGQEIAB0WIQSmAjUw/FNGH+yR+ZwEzT8v3geVeAUCXRWougAKCRAEzT8v3geVeFHE\nEACsKQ79VNKKCjh7tcREWAIz1R/2Y6WQxBxA94swo0TxrNRKUgRdHCqQ9+hI0erf\namB4Wr3+6/qBdm93qTj8xZ9P+9EyKIEBpK1v7X0XDl21XpYjtvBIs5AcQYnPUrs/\nZpGb5yXTY1vI5cJg27aPwkeqEBpnFIz2JsgPQVnDLk0ltU/1pGtObIWH4JkRl6xY\nFFuGEtxdF+0XBeaOFvL5e8Ds1bLr+wRXCYa0b1o0US8t8uqWwQ/Kg4fSfT86Gjkf\nU9NtNe2LUjoKRZk4miWbC5ZvcCmS8U3/qN3+AFG5URRq86fQSSWvEqPQqmdg8E9t\nNy6KYXBCHU75hlw9zPasdc7vw3UUIqCpkohOIzdLArt+sMVklTKlhmNjCkbpguBK\n/Ef7K12JyVHnUUhyxm03sKKLALn5qBlkwlXqSLgCKPYSYSFhV9uX4ZezStceV4we\nx1mocU0EJZXzbhQiPhaIQFFXyIpubvFpw4lvrNZ085Qit0JduuEr4MUDDBt0HcQO\nS5apPpRkNYU7ZFYgINcGbt9iUWLrTsVm6kQVAXqeIKM7uJ5LpS1ADwDOdWAK4leo\nFqCReb9rcPA22raDLe8Q1PF8cADttBwX1mX9sAn6NdcBBvNemUSm8+RlL4W2g5EI\n/LboJEP5seO32vQRua0MO70/G2SlzqidbVdTi/4x4BSC5EjXD/9vlfu/y2B2lHZf\nHGQ5FJYFBsThjyoBxGU1aKE67vHZlei384B74J0dettcoDIKodmk7aE/kHHVdxhZ\nZAM7U3NUp8B4TyFQHpxRXtqVP26tqTnhsvHjQSwUIe/NVSVzn3buSVofXy9ViG0w\nTjIIFYnMUqk7aUvZJa1lqdZ2zWuSmNOjQ1UcDNRj/fp5SU8K1qiOYCyHn230VGVT\nf2UUNJn11y5/Ev2Hw3hzDwkAK+C7XhRIKE83U+tcpEs2xlPTN1glTPmKlcjj/8vr\nrgiM6nc2PKF0iHbJdargKEAJZBfECs6yUJ6qqdPGLtYPecw8XVgt9ZgFvY1JveZH\nTwxYPtuk+3WmL3Wu9Uqew2mmVFY6N0dYUE3A/RQWNTorRddAGhYVTeSOU+nSKUG3\nvh939JLc6whDHMwR2WsvKjEoL8SiC02Jf+fS/QVDk4Gyb0aYxpe0BKijGWd/AvGZ\nTaCG1w18TW69zeZKudUv1U4k2SB2Da+tx23g73GSW+gRZOLnKPtHb0T9+i2U8YKg\ntc/FlkvjF1JRltNeTbk+cB0YT+UEHegvlX7umMKqUPKD54VrmafT28B1sTbIh1ir\n9n2viPgGK+INdVp+7N6Gym0j4TdCnPg2X5/KX5MVBEGQpkRJCyJoSRh5QVbjwXf7\n5gz29ym+3kgbwS6FwUp1P1BBxrBTTsLDsgQYAQgAJgIbLhYhBKNjpJkpHLvJQN1i\n5B8QAnrwAviwBQJgthvRBQkHYtoXAkAJEB8QAnrwAviwwXQgBBkBCAAdFiEEpgI1\nMPxTRh/skfmcBM0/L94HlXgFAl0VqLoACgkQBM0/L94HlXhRxBAArCkO/VTSigo4\ne7XERFgCM9Uf9mOlkMQcQPeLMKNE8azUSlIEXRwqkPfoSNHq32pgeFq9/uv6gXZv\nd6k4/MWfT/vRMiiBAaStb+19Fw5dtV6WI7bwSLOQHEGJz1K7P2aRm+cl02NbyOXC\nYNu2j8JHqhAaZxSM9ibID0FZwy5NJbVP9aRrTmyFh+CZEZesWBRbhhLcXRftFwXm\njhby+XvA7NWy6/sEVwmGtG9aNFEvLfLqlsEPyoOH0n0/Oho5H1PTbTXti1I6CkWZ\nOJolmwuWb3ApkvFN/6jd/gBRuVEUavOn0EklrxKj0KpnYPBPbTcuimFwQh1O+YZc\nPcz2rHXO78N1FCKgqZKITiM3SwK7frDFZJUypYZjYwpG6YLgSvxH+ytdiclR51FI\ncsZtN7CiiwC5+agZZMJV6ki4Aij2EmEhYVfbl+GXs0rXHleMHsdZqHFNBCWV824U\nIj4WiEBRV8iKbm7xacOJb6zWdPOUIrdCXbrhK+DFAwwbdB3EDkuWqT6UZDWFO2RW\nICDXBm7fYlFi607FZupEFQF6niCjO7ieS6UtQA8AznVgCuJXqBagkXm/a3DwNtq2\ngy3vENTxfHAA7bQcF9Zl/bAJ+jXXAQbzXplEpvPkZS+FtoORCPy26CRD+bHjt9r0\nEbmtDDu9Pxtkpc6onW1XU4v+MeAUguSKSg/8Ciu/o/I9G+6JV+ZZyvNtmCR95gLL\na05lvNQ2BrV7dh9+azF2mTDBsO8jPFxI6yqbZxccMTkfy9OIrtsurOoxsLPg442o\nlyUfjYWNRyEKzo5YN6hrk+q6KFEFJUkmJPu3ApGYIbVFDDPs+iQVQKPw5WxpBssZ\nEnaPNT4sEfcz8xUXDp2R1zNY1tirieOEGJXEroA/ssGF6cbCr4gYH7HrUO7ZLSpE\n0ivr5njHZyjl//xCxbiJD+E2qBrBhwW3mJxFq3L3jo8R1Ijut7TY4w33QhlsfoGH\n7mpxFaoHznsT+GuH2CRxdimOTGpv8dCl+0qhvZhpqvAoZqaQGuTfBjeP//J/RdbP\nbNND+ROnv7zZReamM9JGrQXtuT51cEI7rwViv8Y43heazqRN/bM6LZQUIM3kWB57\nIMUZCiDJOKd1BD71fsU4dTM0BiyczpYpr1O9cUjGgn6h5Khkwdi+4s1ij0oQo+Hc\nXDSkeCIOg31DV0rmHUTRUeUHdPoXFEwWS1lAPJw4nwsZ5e/BuCF20Sw2lfTUyFxf\no+C1H7Ams0/QnUe9RbGeICEA3ElZeZ6hetFVggdMm1vXsWyo4+hP5YzmbW0eapRA\nS/5FNbjs3Ie9hliikjitL6ip7F7/0x8PcRu2mRnjYrdTpsNnK8h3vzgsySaSI7/O\nIG8Tn3MVI7yg2LjOwU0EaHpt/AEQAMAQRKtjJbseOA4djkpN3I26rT0Z7z3bpvCZ\nKDTB1J09zuzBf9FLP/mZTt63Y10+cH8eDqK2Jx/Jn4TxQMAlMU+5YMkDOuzdj7sB\nyBIkiinYOFG7tcQHu5jSWYxNo26rjJ+82omVMjwP0NmYHyYVpPGaN08UjV6Hwsq4\nVxZf8pKHVcQtk4tAuBsO8drJ4R2kGX3AFxmZ5DMH7Q2oxBy0O4kG2DQsSl7kF7my\nSwNwPw1Eppx2UCHtPa1r6DIL3vaUJQhrEW/z2HMS4I/HsqfrKc//hdEuWWIx3PcL\noFGqQHNfPiwLOiZqQTu3VLCwazrNfQNZpZugWwo+YK3kuN2UMp4CTybFW4o7lnyb\nhXN88+Qj1tpdf30ItHDIs2P8i9eODT6Ssxn98nmhIyZSrxlgvaTDV/fJqDsVG46B\nSdHS8h73yxlROGEEvE6g/ip7hSbFHiql8TrnQnRH2UzH+PJbmdTU16cKxR0VZ56w\nV0OXhH/iSJdNV/jKAt/HiPz+Jn6I1C35eUIJtlcMIHGue4JAxmbrGJ++GZrgG7DP\nUNz85VZo+TNzmDpG5gHV8TG6birttsqWfHyyu4ccYqdv5dOBBsrKB00r45alHMXJ\ndZ7mf1M6OQDqY/pS5MYzZSj+iDAs43gsvWuQTeU1lYDbIN69t/LmgdShTrj52dTQ\nnFTBAn81ABEBAAHCwXwEGAEKACYWIQSjY6SZKRy7yUDdYuQfEAJ68AL4sAUCaHpt\n/AIbDAUJA8JnAAAKCRAfEAJ68AL4sLtxD/9EGdh2RiWB3WDeCy+6VE2fE1a1j2qG\nb1I9MzaagGIjNfNLQa0ZRd4C8F2PxMq44g9pJT14Ti/TydW8UnavcO2eg5AP+mrO\nP4bF8I+mtx1YtnyDPOBPtaxFXc1h1qF70KDyzQJl9C3ni/NrbvI8TTyh7JjFEqfy\ng5PU+m2TBwoK+cQoAVb6NEA9bAzKsayqVg596E4A3VEn8LkiXshe96MGXwENCZbU\nJhU1+C5M+q2XUi4BwfnbccgW3f67HyPEYt1dyYuQD18RM2I61yvUfCS9UMjZuBv3\nQKERDap46x6fg7nfq7NZqBB4Ktb0pp//NJJdP8eP7zs+tbuLEDvLF3+RhiBUrR2d\nWx7qZLM1JRqHd85ttvB1xK7f/38TE7J2STpIpHlBgWroqWUYbTw3hiIfN9pNSike\nM8hKjZ+w58HrXrx8gxN0tq60c9tAsxy7wpZmvufn06T9AaqPGnArfh3mAzk4G9jG\n15JcGO5YKrE1M9y0pqyBgdku+zp87D8TEuWBa3GPHMVqkwz5Tm/ovpa6ms2KiuNK\n9qVYb8JaUg5AxOnkxJSjnomRCVfTf6yccexdmE4EEkUNhFj/6Y+UA4WCxhAS4Gra\nLDARUWnKPkw2YY4m7cWPDHzXF+pN3KHLej+u1O+0y1q9OmpQ0yogo1fnzmeIHvJY\niYmSNsSq9FUzTw==\n=CCuY\n-----END PGP PUBLIC KEY BLOCK-----\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGYFoj0BEACm4UKYcykICb5oxZQQxSZRYwzkSngpeFcrruHVHfg2jcQ+VmRV\nC3NrbhSrBQuJ0pMx/zq/yZB6K4JS+EMf5GpaX2ZsVsj/MPoSKVHcyXR4clIulCxN\nrUyKYS78awl3bE+dwf9U+IY2fMoMVLwNL8kT2Yr28dI2u47bOPRqxDTxJ8VkRMR2\n4Nv8VbFn2kZVm4u/ZE4lVlAr82vuM8dOdo+RA6OTfnJRBtuwp8YmSLQnoE+BeR+i\nLgbmqOFSqAsQ4z5tl6PlwUMQn7k/GiYfGGKzgpZ9eq265xu7u7f2cXk3SAnxf2Tm\nv3JLsdLd3wbxGOSAd9Ciy+VNmhW06khd9JGriVyslapSNu0ZdH4RepPqjTEItHLE\ndnUwlcmJGKnbE3n7Q6mTez2pMtNYNAeA4LK26qHkHqkgAlkgIZKG3SMlD9wc3FKf\nSpMdEQw9RqAZivO0CoiFRC+VknRVFy4N/F0nrvC4uHDEomIueJswN2r0LWhMDmlV\nj0CGfDQ1SDeU0QpVtuQ5wjpp3UumLtj+uzfU6Y01mrtxH2hNbXKWiYFlDSH17wra\nzYGyEWDnz7owLbxEN1c7sQgHVTVgFzQs/zRjS27HE3bWK2O+vXWD+mceXMHUL0om\n04V2TFig5GaGPr2GSD4eY5Em4G2FzmwPGhjB+nP8nHmsQLAuMUhIR47yNwARAQAB\ntCptYXJjby1pcHBvbGl0byA8bWFyY29pcHBvbGl0bzU0QGdtYWlsLmNvbT6JAlcE\nEwEIAEEWIQTMaPWjEG/0SDIuSO0n9eONWwohXwUCZgWiPQIbAwUJEswDAAULCQgH\nAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRAn9eONWwohX7lMD/4yCMpJqxGKaSsc\n5hDbr5ua0uQRnziFBUPz/RFF6RmSDDCZ+Guck2A+8d7WHh/bmXhz9sUIRp04oLpn\nsJAkbbdNJaePmRxEOoi1Z1yUhLlfpq9ZB1Y8z9Hgsk4fzbBcpvyGrfpmuRx1B8F5\n4QO02VGPp+i/Jek+PPCpyXSSFVVe41ROHeAFoAdAsk/Pn2K/xP8sFWf2yZJDxauE\nNUP67aK7q84N4iC93ioVaW/tdVGdOKKwSCo1jxEnWqMCHe44/BMzDzjNzcGNFNNS\n2Wp5x1Bzmsj4SDHjWpfgfNzOuWzbdH0H52KiQW5I/TDw/WnAMDAm/ECe1V0n/+ON\ngmCMCf/iRmYlLWRf27aGK5OlH+cpF/fsuWe14QvSbLKgO6d3nZ3kJ6bdrkeI0+eM\nsnPVMtc9Sfo1Begl4XMOMLXoGA5Q0tZpCue+o7HfJ2hEtYQVL3G2yIgWwLcw//Zt\n/N9sYOJAGvMi2GQubqTryBloskV/DAT8cH3ttokOWF/EZarWkJmtOMpGIT+tpnyt\nYnpV/R6sAqT0whqxo4A4Me8ncFIhbviJNBdy/hi0qJxHvVDURGHaMFCcYGzzfjlH\n/nXOGCfInzEmmaLUkyqoM+mcLOvWBacprlXpm8Vd+OprgljeBI6JyCZYnIJycNQq\nU2drHjHrgFl2JEmvHwCzuP0Vqr/GxbkCDQRmBaI9ARAA4jotNS9OKK8tT3ORqpqE\nNs4j1MMHQW9tJ9K2M3rqLLsUx72MN3NIEzidEzGyr7HKdBQ88XC25TRqtKhljUFp\n3m3sw7jauZcTCHF/vaW5Vkfix9qL5BDiqQ7T54o05nmCxXBWKDa64JFA0GcR5xZe\nYORi/EujoeU2xWaXZQBuU0RLItraGJnIIUCmsPxrSde0EBTpjNJ0zEKqdUWwx2JD\n5sxs2Ln1olJFA4hKCuGnYhjojQxapB7HKanmqMJD6mvQVCjUmw1FNaNDLfFq/hx9\nyF2vTNZ1BzUvQfYBqKswnD6/Q+ButpjaDyGP8w2+NVWCQlPxVXiHcOBDNh8JSySM\nESHi5vltXujKZAkr+q67OZrKpa53Mtw0PAEuM5wl+Dv2Ut3Z3mWIa+8h8AO/SXnA\nRXzzsM6M8sHMiF12IIzxAtfve8eINor+gEhB9LJdobOq+o8tu6la9UOotY+dJPL1\npy6SuZBbOSpJRio7PwuDz478PbbfyD3HSiRcv9UWCUgpdfiPNLJz8NCCYwwM0CwN\nlKOvc0pEBQxufHOMDxEWv7RxOdxWiODwLZrlyE6eLh5BaxM/AMwOWJH5ReGaAA0V\nDRjXHRm+vOCXLENeH+ZlTqnKIHHmKDPJdybzllsxaFp02+c6sf7Gj9BPdA0rzJrd\nprnboL8oBr8HJzvDw6m02kMAEQEAAYkCPAQYAQgAJhYhBMxo9aMQb/RIMi5I7Sf1\n441bCiFfBQJmBaI9AhsMBQkSzAMAAAoJECf1441bCiFfXugP/1iYMqMM7MRifFe/\nHIwhBmUGBOXvRrOdYEnoQOQM5CV+ro1mgVLr3alHo6xc5ZYwINq3AvfS0XTLG0z1\ng7zQpictpK4mo2sTRujeJpf6TPgJ7aI9+fYDnfq+SmhDgKIlR20NUxLMgK8u2eBc\nEF8gqqGBldHV6b6TbDBZGW6xAVGXe49NLd8Q1rHPCUVA4SsDF0Wgn9gaiarMqlmO\ntcrsalTvGrbsDzyHY8p+OktYeJPCVy0iaiT5RTwkGjyhInSzH0Qyb91aYXKJdH74\nc6BPFjoXeEM/n/pH3cu5h4x3m+8Z7X5l9/UrV9kBM5TxwinTwGUuQDLes0mjwspU\nc3kgPGgPGzRp5+wTcRfiF00luEFUxRtBLCId6PKSH3ZhDjRA25M0Yp4qP81wgu6S\nqlbB+goIZtbEAJeIxWNerMVeC1FobuFa9S6t9PAUlvX7mMlBAMDOv6czFkrl7rSj\nyQw4lcYv23z/o42yFG+EcnEQ3l7K3j1qmkFDiEfopbQVBNpE69stjpO1sQV4fVYr\neu0agvd1+yKZrcoEo+npXyzXPckRsHchS6pbhck1vFtgKwXpPCjSC0e6IwrDgAGw\n0smdXeIIwNoMVaY3oksWA8DdRdNCaHqYalW+8LytiOOcBvgFCMcUsr0NcLstWwyi\nZWf0a3VP6Gco5bmDPhvGoLEs9Vw5\n=57kS\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGHwIyoBEADN55NGkn1hvOjFotJVr8aeU6/xGZF3gPLi7q2qaX5CXtVMGS2B\n5h9kiBKrNo1+xeC1+jRu9r5179lTiYV808qNFBQdr+5ZBnOoszadlMPMtU89qsR9\njxr8wJT563nIPoCeRl+0oFeam9ktAZnnpLz0dmPxyHHVaFXsVauDpwjJxOPo5Vyo\n2MHTacVUBWZA6R92ZETWIOHSg3ZtLf+jq7IyzeYSnj31kbx5djGtawLKZZ9bbIdr\nihRysKAaHabf+x7mHs9VYnioygC5z91vKJxJcPCNinjFM29gU7qoooYgjmoXFrmy\n3X+AdmtK6gNKgEzoFyHThPp1ta8YoNKd9LrCW/eF3Mz/k0LnvJSTCEzY3ynwMjXm\nDP06ljDwMEll2pk4utFykYmczxdvc6XYRzCUDlpTNBbnUxo9wtWS5P972j/Rrila\n4NmvZbgSCf5nmJfouCRLqxiSAB+hkilikjCGx/zvd5gUYyvrB/scSn0WsIFOA626\nY/JpBVtERKXcercRBZlRPYlKVoKXopT2p3WS2nRmj/HvOMTH9KdxF7jwEF5pguic\nWLKQtjFkHVWgZgCi6cSwohL0ANch9HcQjU/PB1zqyMYUxDuMxwA5nzeKLfOHY7cS\nXbvVmeLwA0ArEXWTIXH1chDcaGW2LKbqlHS8fRnogJ9ZZ8REWTbX4y7abQARAQAB\ntC9BbnRvaW5lIGR1IEhhbWVsIDxkdWhhbWVsYW50b2luZTE5OTVAZ21haWwuY29t\nPokCVQQTAQgAPwIbAwULCQgHAgMiAgEGFQoJCAsCBBYCAwECHgcCF4AWIQTA1iSE\nOfHVYEqv+0Ah2QD/2yM3VgUCYfBtoQIZAQAKCRAh2QD/2yM3Vu3PD/4jPvierFEH\nss1ekNSOoIuLWZfjQudlLZy1w7ANPEIY5at11EZ4s9bh3QRoNM8Ztw3mNojXqDPX\ntBJ5DHFb9dvqVS3cRV8XjDWOKFO370tYEW35nozV41XenrSJpc3NYlr48Rmx+8mH\nZ0Fd3S0aOEkb+yLpAVxwKRyHyaKjJugz7Bq9rNFrgAqkIL6PTcS2UpEt6QRpcMtb\nizHQcQT2kk7ULAS+LChKyqUUXC2jmAgGwAgBUjQ3Dx8z3UBNxjaTNuLgywftroGu\ne543ubOR2OWOEeLRFapHg+GPLgm7q8cmz0aSvs4ezFhOa45uOwXVVDFsMsXFOG8Q\n73TC3+GoF0+3hCDCROSUsyd/OzhLMlLMBuW6EqSlfXjwuqmIuQ31mXz67ORwcO3k\nA6GjkzxHhNq8i6gu1MC/nQLOVwTwqttvpBcbxclU7RRRvrFzr9/YsM+asqLwQ0sQ\nw+JEnVaFDcq+BCa4zQaAYUtkMuGibnwLAHlPVk1iityrW5bgFO7fokZHa7pUXBZ3\nEfviff512Zho9Hd1zkrJdYpnoOXyoho/TlzD63n6DMA3Z1cfF7MM4pqx38xxasch\nyYbkXwHIYUQ5BivgNYC6hcgMHM8DlENpOpPFFHciFLvv8ORI8cM+PR1RlsmCwRDJ\nEjN8Y4cFqHUtBFy3DAZTp1AD8dOiJBVqyLkCDQRh8CMqARAA2ez9vkDBw5sN2OZQ\ndkLiqpd0YW+v8muDmc3JqNIIqduSFuG2amW7ueSeQ7anfrLZwugLWozX+AKACVQt\n945dmvnvwLC5r3ej5iUdnrqsrdSGn062v/ZtgYoheaVSOeHQKAF3N0+SzDQOBAzE\nfPmziMbBDhC3UQiEqIzrHlrTfxaI2e+scJpFzXnpGWhxrWZsF93eCZmbcnH8uzug\neEIjAxevrNNnKC3G+wWklVJpTTAsUHv8SPGHVkX9BUbLBoPuTdZja7BiD4cSMr1n\nc2BFR3xBIzFdmIztBHjpvgqwKAauUcAsgtKFFWDy8NjYjBCzb/YSlpMC1JYQIF9X\nHSQTPA8dw1ZJPjcHFjSza7FsF0OUeDQNtId3uVxCsfJ6xEqlHw746e/ZZ+GJHgmX\nQurEwvMPOxg954jBVLPAx3YYLNkfqA+MrX0AvgwNCr7/Jva0bK238uKOZhpBIUBz\nMTVbY0IYFh06lPHAP+YS3tkyc+68+m6c6UTikSnNN1K3LQxvODfydt5jSzjG/+qr\nAN5pZLpbHKWCGGsEhjS1exs30BTUnJMJMSqRoPsnvOoJXfePQMXq45b26hmQw9gJ\n/7mzVOOKzgnPpdIlAO6hkp7HfWHKoLUGOOHRIJcuKkEi8iYmc/Rb8S3HsohtrOAs\nkKGGOVnr8W2CuBTLNJMVOsDgWfMAEQEAAYkCNgQYAQgAIBYhBMDWJIQ58dVgSq/7\nQCHZAP/bIzdWBQJh8CMqAhsMAAoJECHZAP/bIzdWvoIP/1Gj1Of+sF0ZemozOmMS\nJR4K8hnsKboaklPtimor0cUYHwuCYS2YZR2nUdAu8vhhc6iYHRN0deZR2cWMXDF2\n5vhVx6LDHRVNkeoW4SXOAt2OX7iJGZn21MhkkXA4+FyOUhbLrUl3E+Ea00dlygA3\nSt9VsiV5LOn2siAYwf8rTUWw60LZkyXZqhyZObXY0L69iBgwN7GW+bKWQee5SV0f\nIw3EC2qiYyxKv8B60/HkAzx4mKsfsOr/CNMqsJpSeho1Je9enCPzPxm5+9bGJ3oq\nGuCxNRW1J8WxhDg72I8iBMypLHVg0iL8tVDHLqB9JJs+CxWzRojxIR/p7lOiBMGh\n7PX6ONA9Jb8q7PLQzGmz8cIJkqzj/XlsmIONPHR2IEW9k+vQVd7S68M1f+XQKdn5\nyPaUFCTuRZC46FpiBWWvNI7ATKv4c+AdgwFPHzojt9TSd05AQJjChYbIWh0FilX6\nOeB+4MoqHUx1W/R/40tjxX48Q1/OYU45S6PaqrLeOM99jmf2gW7R226sJK0DFO3S\nWVS5izHknfSdJouA9teJ8FYz9wJqLAymjgI/n4XLk+62/VdgtRDRU4gq7BtH+mb9\nlzRFvHZnq6EP1QgDOW55OhdXTqb9v4P3bM77Ez7qHQWKoZOoC0mYvXJff3SOzkOE\nTh80Z8v5rFX5xNw+zn0Ee+yr\n=SZFY\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmDMEaGA63BYJKwYBBAHaRw8BAQdAo/yU+MutacFmmn0CEX495goNrBxR24235XLM\ncvHYjfq0L0FudG9pbmUgZHUgSGFtZWwgPGR1aGFtZWxhbnRvaW5lMTk5NUBnbWFp\nbC5jb20+iI4EExYKADYWIQRb6KP2yKXAHRBsCtggsaOQsWjTVgUCaGA63AIbAwQL\nCQgHBBUKCQgFFgIDAQACHgUCF4AACgkQILGjkLFo01afgwEA/sLHqsj7ml2vyDoT\nKDPE8n9a80ZOh14OfnlOe0cCZA8BAMEOOk7QFI69DIlV1nMiqcFCqQFoSzBU2LkI\nR17p/j4NtDNBbnRvaW5lIGR1IEhhbWVsIDxhbnRvaW5lLmR1aGFtZWxAcGxhdGZv\ncm1hdGljLmRldj6IjgQTFgoANhYhBFvoo/bIpcAdEGwK2CCxo5CxaNNWBQJpsCMx\nAhsDBAsJCAcEFQoJCAUWAgMBAAIeAQIXgAAKCRAgsaOQsWjTVr/sAPwIBsG8g6ND\nzoNRTX1wPKBvfZg1NP7tYCyM5sxQfrpuLAEA05AhG4xBILfhL/f0pqR5jXfxg6gz\nT6WfeVeS6zeHZwe4OARoYDrcEgorBgEEAZdVAQUBAQdAQVmtih8AO3ryBQMR/22x\nWHVKLjAbCiH2cMxNH+iy1RQDAQgHiHgEGBYKACAWIQRb6KP2yKXAHRBsCtggsaOQ\nsWjTVgUCaGA63AIbDAAKCRAgsaOQsWjTVu8oAP9Bc+QY+9FikX3YvMgWAqiDlVOy\no0y6UIZGBMSQlF80wAD/d34LqtVIVe9oe5NO3xA75+6Ew8tGeAjUq/ovagr5dAU=\n=JsVv\n-----END PGP PUBLIC KEY BLOCK-----\n\n"
  },
  {
    "path": "src/assets/gpg/swift.asc",
    "content": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBGGJWe0BEADGVbVhCEWnCMdAoxCaUaCPNomG5wdzw+sgx8FvqCFiGqYq/qzN\nckaydk+XWfiDT/Vo/NjMYnUJ0+gdSua1X0IUGqQlATYhKSGTHqgab4nwDCym0nFl\nSBHPDgmMTNO57dHSGYduPjuisuhq7i0pybyn/oXuHAW5SIlz7bfpaz2jzFDY4xEP\nTXImllHOmTxBsDdwv2J+H158w1NSHJoHeXpPIse3VHlcwJVNeGYMiDx4Qw9TfaL5\nfI7GgjbcELCXw/pGjbiz/JFX7Fzm4snesnqwIG3TN4kH3BdKRNMFnyN3zNZxQTaZ\nLNCr3NCzhmmWTjeX5VSu6C+W8wuYRAThqJ42HpPR78zgv6pMnHgdhqquqAfL/Oid\nXlISbQ4bSdc1y8xkLb86pzwzrLV3LmHjJ3NAi9U1QXygW0ikTgbB9LPzaTSGVU+y\n0PMQ6JrRfSvyt5G7RmVzqm1ro8fkmeZBjNUf7GXCldn9linbhKzh/IvvPTYeNhIK\nT99giWSChvZyR950vE5a4WEYKV3taJRLCqXHH1d7FKC080pvPR9VsqWB/thQ48Vr\ndPleEa6O9IFMDudpOfsXTnHtnO7wKssN9RtxpotRukIhLGWxjHED3Rrt93T+IMQz\nkpKz+Tcz/koM8SuAcYX15N/jeW8BzgA6Y6ODI/OSAMBzMQUYME5S7F7xOwARAQAB\ntEZTd2lmdCBBdXRvbWF0aWMgU2lnbmluZyBLZXkgIzQgPHN3aWZ0LWluZnJhc3Ry\ndWN0dXJlQGZvcnVtcy5zd2lmdC5vcmc+iQJUBBMBCgA+AhsDBQsJCAcDBRUKCQgL\nBRYCAwEAAh4BAheAFiEE6BPIkoIKb6E3VbJo8WffGs+c4GkFAmkXkkAFCQtQn1MA\nCgkQ8WffGs+c4GlQpw/+LUkquzG+3wt6WzHThd8m99PcVygHR4YnI/GTRYsno7l/\nw4bB3WxhK8BFTr5GzsEDd2gPSIyKvqrcN1GP2lj96VyNfksh8LledNpzGz1HAgIt\nRY8NgzdQWqrOiyPK7T3cOkpOzwx4TNFTvEnKU/bPcdZM/muvLFManJr7bOvhuWGX\nKafvD6Q2EwofIIRaIocaVlsai1jJZcYCiB3UpTQL+pg1kdlYSVwnarEBvuAGEJan\nUlYuyS0hGFHpoU9VkxxTH0FzETN+03AtPXVaVJdjfmhrBUbWg7envpIUZ15z7PdD\nXgddnfoMIpfiVerr7DgbUdo3WervDtCo1PSMh8CeY14sdVsPlufCwP6zMLMllDBm\nVCEHN4vOCfabA/+GSev0Mtli60OUdFAVSKt0pGddONDWSrYezRD9lfofq5ZnRqFa\n50K6IrWoczkv1Toh1NBh5V0bmnVx0gwa4rmNrrY1casCs4KprySkdKvOha7IFrf0\nYHNUjRf1i0v8Ep2oE8nRgbVwbh0mxCyHchux7RIty85vyqQh/nff1ArChQxtrWsr\nOk/0iS+TmMi+o/IxBR5KzaewYXHWKfuAYkGWPCbwxgc24Zd+hAHpnstZ33zcpL9K\n1dQz0ClfOCKYQYZJ2MID1Ry27bPh5fJdWuGcXFlkhIebvXjllbD44yeIdCvc0rg=\n=12qA\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBFyUJhwBEADDBN6jVDScsgzfQDxSQga0Og4O3N/nIquwi/DGOgsAsTMWcVA1\ngmRJb792vWa9CmnHILl3ap8zObDSbcXg90nx+eCzWJjG+Ud5c7xuam96NR8ntKmU\n8+BbH/dp8zc9WJB37TiWcaLsddrn58zfm7Ml6P9M48WAeRJX8nxVBTw1SjXJurW0\nAb8LOgfb60I09Skq72Ud7HaYJOG03iNTf6qLlF977OQsHCb21BnKSAmJqapUS96/\nVOngz7TBzYz4rntfetb8hg28WtUl1s5BQzWaFunkP03b8mPh3PL1SZxutwViVWBu\nhf9kJtx/MLb79fnuJEOus1FvDqJdpd83H+XmXMIDYWgcBIBVrLT5HDtRerjF178H\nokb1F+gboGIqhnx25xTPIYctSHPgJRScZp4WKrqQLKswAmSL4YJXnkXSff05l4gE\nWXQpEMLBZa46qmu8lj8HfoZSbP9lfvEtZ6A+Q3sfh3gjYPv7e6n37x22tSgvyzCb\njHU1pA2rv10AHK7EIeEQElN+zCyAbmKuhPBiCyxDFg5Dx3xNkYwg9szBJ0KleVD4\n+Y3PZJ4N+u+SSATYnHGtmzvkhiNtqJCCwuaqY+jjVObzzqvLLtGjtjxNUWi2X4He\nq+r2fubjCOW14UnQ06qfr3mVUSmuLSKs8BD8qTGuqlgcenGsY0bk0qUPcwARAQAB\ntD5Td2lmdCA1LnggUmVsZWFzZSBTaWduaW5nIEtleSA8c3dpZnQtaW5mcmFzdHJ1\nY3R1cmVAc3dpZnQub3JnPokCPAQTAQoAJwIbAwULCQgHAwUVCgkICwUWAgMBAAIe\nAQIXgAUCZBiLlAUJC0bMeAAKCRCSXMHM7T0VYSogD/i38g/nf1JSDrWMWVKLzTWA\nMO9V9JR1wcxx3YNQmGPzUv+gdXgOv8kWSKSJ5zopTrWJg/AJ6etShX7HpjXeHULp\naJGLohlMQuPCqD2+HvxpY67iA9i49owkzQI4gSIC6UwtCluWQCgcz2qE5zBWB1nK\nImegSYn9mHIooJ9em4UwHdEDztWPYeB192M+Eq1+HK3BlEFDrMxWdzVuEQ+oGslm\n4Z5apV+r65fQa9T4rRxOpau8T9tKpXfaw+IzUDUE4PRTOyOkR8AOFm9hIg5KlV9z\n1bhDRS4Xpb6i3H91OyGROoB6QsTCmVGnSw35bzYjlOc5I1bAtqJu3EC30gV97kCj\nbtm/cQLb+su/DEwjp4/lRtQagmRmHUuvJyPA+WNNiPYY/Ldzfy3w/SK4eJqM3Ctv\niEs+btFLg4yXCBmL6UFZ4rmZ++x11DoW9l63b/9PJYPASXBGXamqsrMvX+IozjQ1\nCzlI8Pi5XwZfa/yAMiNXTveKItZJFUl4L4xMz2Fk6q8vByb5P2TziooTNtpjJedg\n+W2ZNKatqZtvqowJlr9utWmogInrlv+YSLXN43kVt/X+Dbi1qzIE0FnApLPJEw+x\nnuahcoGN56UfxsdlmMDQ1QWs0Zp1DzXGOwAo9ciEIxrqlxR7N8rMluDv9vltVnZZ\n1p6hhnwu6nXqf83I5GJK\n=77jt\n-----END PGP PUBLIC KEY BLOCK-----\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBGbolYEBEADEvoijjZaq+5hLyiOHMns6+i/1mxczO5g9ZuXANYMI5uKXNgED\ndWoJRJV1DKwY+1f9oBdcEctD0um4LY6346p38SJOurk/zRqlEx25sAq0bbOn0epE\nBrOkHnmgBp+C5gWgrk+gKGjOXw63m2ipKp5joxP7QI7iplb7LRHnqOWqVFPF6c+A\ny5zq7/FFfECwHYdkS3IV8uYG0qPmKDYoJgqCbySGzbHTiawFt8OJS5xYqzhXrClh\nKMJf6orq8gNF4eBwa6FkyJFyPf/s8mbW3wREirL9DFinurMK68pUA7SDxLsegGgt\n2PVse5o+1TVcKTDTCV0v5gmiQyXIUzvB87GaJLVIEIwYb08jtSBMvVLdVIpWv6RJ\nbi7za2LvfaCBcpSAbqCtoq/lk9NYrXs8uiENxW0srIWoKoe6Gfvz0XvJEjJPIMNH\ncy/42Nt3kgn6V3lHTioTPhxyEJ8AZ+s7yIeVR5fYuxdlVwe6zhiwvGtjWLmjTZBY\nRbXayDV3ekNL3rEQ4qhXrvcmW0/v7n+vzf6a7Wog6R4pHr67BafM3v9M6jpu4Lqk\nmLyXU/lX1+VTzKz7vDCz8CXafYUP8wFYGGW73xzd6Kho8vya1E4WNg+UPnYcu2SV\nTkQe50I2Ik95QEAEdG3DJrLiGuLwH170KgeMYpWffNLtUNH1oCkh1lj8jQARAQAB\ntEVTd2lmdCA2LnggUmVsZWFzZSBTaWduaW5nIEtleSA8c3dpZnQtaW5mcmFzdHJ1\nY3R1cmVAZm9ydW1zLnN3aWZ0Lm9yZz6JAj0EEwEKACcFAmbolYECGwMFCQPCZwAF\nCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ74CoZrR6mB/DIhAAnSHnGfRpr/0A\n98dWa2uM2tt4oGT1+SN+va544/vu6CAc9jhvS871GvHe25B5HL5S6MDF3dim3oQe\nzIGaIx3DUhbb0/JLeayL3NfhbCed5DX0W1XIQtksjYuHnvBRD+zrhcTQKqumR+LU\nNVOh6l4o2Ko+aAYc8mIm+HufryRKJSWup1ZnExEdcZZEzyY4kT0H1fxAIWWU3NI1\nLDtq1O0Wl5CTUHU7mI/h2eWrxFDg4SmfV9dv4uBXyvxherHEhImJXceQ4ZkxvYGF\namXjlNzIr8c6y/IE8Q775nkfG5+4Gt+bGIJqxeSzfc4wq+txMa85TtRpgSthgqFi\n+yQx5qghs3y8Pqj3kDatJB41oQZ221WbBRc2uvFDMWUaOtJ/pRymCN54FUwxUm6U\naM4VTWbGw0es1QRO+Px25Thoh8a5a3Fu0s9fa1sDJOUYSc7vfyRUfqNOVv5g8rnS\nsPTmOGGjrjxWHA0oL7B5hxCR+/jBhw+6mLu18qwGI7YpgyZYSzowPY+LrMm/J973\nSyUtlCb2o42WhDR9FsX0AGvLhZpxy4Q7br7Pa2RXwmWEaxZik0iQ2Sg4pEvL5tVd\naFIUvVsFlayfXSBCZVjH0uyh0Vkk1ERZpSmxkRWgzp5MRIfkP5eh9009uhEUmxHV\nYih/un915S6ObH32x1IbJfi0cGK1NUA=\n=sWSN\n-----END PGP PUBLIC KEY BLOCK-----\n\n"
  },
  {
    "path": "src/assets/mise-extra.usage.kdl",
    "content": "source_code_link_template #\"\"\"\n{%- set path = path | replace(from='-', to='_') -%}\n{%- if cmd.subcommands | length > 0 -%}\n{%- set path = path | split(pat=\"/\") | slice(end=1) | concat(with=\"mod.rs\") | join(sep=\"/\") -%}\n{%- else -%}\n{%- set path = path ~ \".rs\" -%}\n{%- endif -%}\nhttps://github.com/jdx/mise/blob/main/src/cli/{{path}}\n\"\"\"#\n\ncomplete \"alias\" run=\"mise alias ls {{words[PREV]}} | awk '{print $2}'\"\ncomplete \"config_file\" type=\"file\"\ncomplete \"new_plugin\" run=\"mise plugins --all\"\ncomplete \"installed_tool\" run=\"mise ls -i | awk '{print $1}' | uniq\"\ncomplete \"plugin\" run=\"mise plugins --core --user\"\ncomplete \"prefix\" run=\"mise ls-remote {{words[PREV]}}\"\ncomplete \"setting\" run=\"mise settings --complete\" descriptions=#true\ncomplete \"task\" run=\"mise tasks ls --complete\" descriptions=#true\ncomplete \"tool\" run=\"mise registry --complete\" descriptions=#true\ncomplete \"env_var\" run=#\"mise set --complete | awk '{print $1\"=\"}'\"#\ncomplete \"env_key\" run=\"mise set --complete\"\ncomplete \"backend\" run=\"mise backends\"\ncomplete \"bin_name\" run=\"mise which --complete\"\n\ncomplete \"tool@version\" run=#\"\"\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    versions=$(mise ls-remote $tool $prefix | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise registry | awk '{print $1}')\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"\"\"#\n\ncomplete \"installed_tool@version\" run=#\"\"\"\ncur=\"{{words[CURRENT]}}\"\ncase $cur in\n  *@*)\n    tool=\"$(echo \"$cur\" | cut -d'@' -f1)\"\n    prefix=\"$(echo \"$cur\" | cut -d'@' -f2)\"\n\n    if [ ! -z \"$prefix\" ]; then\n      prefix=\"--prefix $prefix\"\n    fi\n    versions=$(mise ls --installed $tool $prefix | awk '{print $2}' | sed '1!G;h;$!d')\n\n    for version in $versions; do\n      echo \"$tool@$version\"\n    done\n    ;;\n  *)\n    plugins=$(mise ls --installed | awk '{print $1}' | sed '1!G;h;$!d')\n    for plugin in $plugins; do\n      echo \"$plugin@\"\n    done\n    ;;\nesac\n\"\"\"#\n"
  },
  {
    "path": "src/backend/aqua.rs",
    "content": "use crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\n\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::get_filename_from_url;\nuse crate::cli::args::BackendArg;\nuse crate::cli::version::{ARCH, OS};\nuse crate::config::Settings;\nuse crate::file::{TarFormat, TarOptions};\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::{PlatformInfo, ProvenanceType};\nuse crate::path::{Path, PathBuf, PathExt};\nuse crate::plugins::VERSION_REGEX;\nuse crate::registry::REGISTRY;\nuse crate::toolset::ToolVersion;\nuse crate::{\n    aqua::aqua_registry_wrapper::{\n        AQUA_REGISTRY, AquaChecksum, AquaChecksumType, AquaMinisignType, AquaPackage,\n        AquaPackageType,\n    },\n    cache::{CacheManager, CacheManagerBuilder},\n};\nuse crate::{backend::Backend, config::Config};\nuse crate::{env, file, github, minisign};\nuse async_trait::async_trait;\nuse eyre::{ContextCompat, Result, bail, eyre};\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse regex::Regex;\nuse std::borrow::Cow;\nuse std::fmt::Debug;\nuse std::{collections::HashSet, sync::Arc};\n\n#[derive(Debug)]\npub struct AquaBackend {\n    ba: Arc<BackendArg>,\n    id: String,\n    version_tags_cache: CacheManager<Vec<(String, String)>>,\n}\n\n#[async_trait]\nimpl Backend for AquaBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Aqua\n    }\n\n    async fn description(&self) -> Option<String> {\n        AQUA_REGISTRY\n            .package(&self.ba.tool_name)\n            .await\n            .ok()\n            .and_then(|p| p.description.clone())\n    }\n\n    async fn install_operation_count(&self, tv: &ToolVersion, _ctx: &InstallContext) -> usize {\n        let pkg = match AQUA_REGISTRY\n            .package_with_version(&self.id, &[&tv.version])\n            .await\n        {\n            Ok(pkg) => pkg,\n            Err(_) => return 3, // fallback to default\n        };\n        let format = pkg.format(&tv.version, os(), arch()).unwrap_or_default();\n\n        let mut count = 1; // download\n        // Count checksum operation if explicitly configured OR if this is a GitHub release\n        // (GitHub API may provide a digest even without explicit checksum config)\n        if pkg.checksum.as_ref().is_some_and(|c| c.enabled())\n            || pkg.r#type == AquaPackageType::GithubRelease\n        {\n            count += 1;\n        }\n        if needs_extraction(format, &pkg.r#type) {\n            count += 1;\n        }\n        count\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        let pkg = match AQUA_REGISTRY.package(&self.ba.tool_name).await {\n            Ok(pkg) => pkg,\n            Err(_) => return vec![],\n        };\n\n        let mut features = vec![];\n\n        // Check base package and all version overrides for security features\n        // This gives a complete picture of available security features across all versions\n        let all_pkgs: Vec<&AquaPackage> = std::iter::once(&pkg)\n            .chain(pkg.version_overrides.iter())\n            .collect();\n\n        // Fetch release assets to detect actual security features\n        let release_assets = if !pkg.repo_owner.is_empty() && !pkg.repo_name.is_empty() {\n            let repo = format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name);\n            github::list_releases(&repo)\n                .await\n                .ok()\n                .and_then(|releases| releases.first().cloned())\n                .map(|r| r.assets)\n                .unwrap_or_default()\n        } else {\n            vec![]\n        };\n\n        // Checksum - check registry config OR actual release assets\n        let has_checksum_config = all_pkgs.iter().any(|p| {\n            p.checksum\n                .as_ref()\n                .is_some_and(|checksum| checksum.enabled())\n        });\n        let has_checksum_assets = release_assets.iter().any(|a| {\n            let name = a.name.to_lowercase();\n            name.contains(\"sha256\")\n                || name.contains(\"checksum\")\n                || name.ends_with(\".sha256\")\n                || name.ends_with(\".sha512\")\n        });\n        if has_checksum_config || has_checksum_assets {\n            let algorithm = all_pkgs\n                .iter()\n                .filter_map(|p| p.checksum.as_ref())\n                .find_map(|c| c.algorithm.as_ref().map(|a| a.to_string()))\n                .or_else(|| {\n                    if has_checksum_assets {\n                        Some(\"sha256\".to_string())\n                    } else {\n                        None\n                    }\n                });\n            features.push(SecurityFeature::Checksum { algorithm });\n        }\n\n        // GitHub Artifact Attestations - check registry config OR actual release assets\n        let has_attestations_config = all_pkgs.iter().any(|p| {\n            p.github_artifact_attestations\n                .as_ref()\n                .is_some_and(|a| a.enabled.unwrap_or(true))\n        });\n        let has_attestations_assets = release_assets.iter().any(|a| {\n            let name = a.name.to_lowercase();\n            name.ends_with(\".sigstore.json\") || name.ends_with(\".sigstore\")\n        });\n        if has_attestations_config || has_attestations_assets {\n            let signer_workflow = all_pkgs\n                .iter()\n                .filter_map(|p| p.github_artifact_attestations.as_ref())\n                .find_map(|a| a.signer_workflow.clone());\n            features.push(SecurityFeature::GithubAttestations { signer_workflow });\n        }\n\n        // SLSA - check registry config OR actual release assets\n        let has_slsa_config = all_pkgs.iter().any(|p| {\n            p.slsa_provenance\n                .as_ref()\n                .is_some_and(|s| s.enabled.unwrap_or(true))\n        });\n        let has_slsa_assets = release_assets.iter().any(|a| {\n            let name = a.name.to_lowercase();\n            name.contains(\".intoto.jsonl\")\n                || name.contains(\"provenance\")\n                || name.ends_with(\".attestation\")\n        });\n        if has_slsa_config || has_slsa_assets {\n            features.push(SecurityFeature::Slsa { level: None });\n        }\n\n        // Cosign (nested in checksum) - check registry config OR actual release assets\n        let has_cosign_config = all_pkgs.iter().any(|p| {\n            p.checksum\n                .as_ref()\n                .and_then(|c| c.cosign.as_ref())\n                .is_some_and(|cosign| cosign.enabled.unwrap_or(true))\n        });\n        let has_cosign_assets = release_assets.iter().any(|a| {\n            let name = a.name.to_lowercase();\n            name.ends_with(\".sig\") || name.contains(\"cosign\")\n        });\n        if has_cosign_config || has_cosign_assets {\n            features.push(SecurityFeature::Cosign);\n        }\n\n        // Minisign - check registry config OR actual release assets\n        let has_minisign_config = all_pkgs.iter().any(|p| {\n            p.minisign\n                .as_ref()\n                .is_some_and(|m| m.enabled.unwrap_or(true))\n        });\n        let has_minisign_assets = release_assets.iter().any(|a| {\n            let name = a.name.to_lowercase();\n            name.ends_with(\".minisig\")\n        });\n        if has_minisign_config || has_minisign_assets {\n            let public_key = all_pkgs\n                .iter()\n                .filter_map(|p| p.minisign.as_ref())\n                .find_map(|m| m.public_key.clone());\n            features.push(SecurityFeature::Minisign { public_key });\n        }\n\n        features\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let pkg = match AQUA_REGISTRY.package(&self.id).await {\n            Ok(pkg) => pkg,\n            Err(e) => {\n                warn!(\"Remote versions cannot be fetched: {}\", e);\n                return Ok(vec![]);\n            }\n        };\n\n        if pkg.repo_owner.is_empty() || pkg.repo_name.is_empty() {\n            warn!(\n                \"aqua package {} does not have repo_owner and/or repo_name.\",\n                self.id\n            );\n            return Ok(vec![]);\n        }\n\n        let tags_with_timestamps = match get_tags_with_created_at(&pkg).await {\n            Ok(tags) => tags,\n            Err(e) => {\n                warn!(\"Remote versions cannot be fetched: {}\", e);\n                return Ok(vec![]);\n            }\n        };\n\n        let mut versions = Vec::new();\n        for (tag, created_at) in tags_with_timestamps.into_iter().rev() {\n            let mut version = tag.as_str();\n            match pkg.version_filter_ok(version) {\n                Ok(true) => {}\n                Ok(false) => continue,\n                Err(e) => {\n                    warn!(\"[{}] aqua version filter error: {e}\", self.ba());\n                    continue;\n                }\n            }\n            let versioned_pkg = pkg.clone().with_version(&[version], os(), arch());\n            if let Some(prefix) = &versioned_pkg.version_prefix {\n                if let Some(_v) = version.strip_prefix(prefix) {\n                    version = _v;\n                } else {\n                    continue;\n                }\n            }\n            version = version.strip_prefix('v').unwrap_or(version);\n\n            // Validate the package has assets\n            let check_pkg = AQUA_REGISTRY\n                .package_with_version(&self.id, &[&tag])\n                .await\n                .unwrap_or_default();\n            if !check_pkg.no_asset && check_pkg.error_message.is_none() {\n                let release_url = format!(\n                    \"https://github.com/{}/{}/releases/tag/{}\",\n                    pkg.repo_owner, pkg.repo_name, tag\n                );\n                versions.push(VersionInfo {\n                    version: version.to_string(),\n                    created_at,\n                    release_url: Some(release_url),\n                    ..Default::default()\n                });\n            }\n        }\n        Ok(versions)\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        // Check if URL already exists in lockfile platforms first\n        // This allows us to skip API calls when lockfile has the URL\n        let platform_key = self.get_platform_key();\n        let existing_platform = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|asset| asset.url.clone());\n\n        // Skip get_version_tags() API call if we have lockfile URL\n        let tag = if existing_platform.is_some() {\n            None // We'll determine version from URL instead\n        } else {\n            match self.get_version_tags().await {\n                Ok(tags) => tags\n                    .iter()\n                    .find(|(version, _)| version == &tv.version)\n                    .map(|(_, tag)| tag.clone()),\n                Err(e) => {\n                    warn!(\n                        \"[{}] failed to fetch version tags, URL may be incorrect: {e}\",\n                        self.id\n                    );\n                    None\n                }\n            }\n        };\n        if tag.is_none() && existing_platform.is_none() && !tv.version.starts_with('v') {\n            debug!(\n                \"[{}] no tag found for version {}, will try with 'v' prefix\",\n                self.id, tv.version\n            );\n        }\n        let mut v = tag.clone().unwrap_or_else(|| tv.version.clone());\n        let mut v_prefixed =\n            (tag.is_none() && !tv.version.starts_with('v')).then(|| format!(\"v{v}\"));\n        let versions = match &v_prefixed {\n            Some(v_prefixed) => vec![v.as_str(), v_prefixed.as_str()],\n            None => vec![v.as_str()],\n        };\n        let pkg = AQUA_REGISTRY\n            .package_with_version(&self.id, &versions)\n            .await?;\n        if let Some(prefix) = &pkg.version_prefix\n            && !v.starts_with(prefix)\n        {\n            v = format!(\"{prefix}{v}\");\n            // Don't add prefix to v_prefixed if it already starts with the prefix\n            v_prefixed = v_prefixed.map(|vp| {\n                if vp.starts_with(prefix) {\n                    vp\n                } else {\n                    format!(\"{prefix}{vp}\")\n                }\n            });\n        }\n        validate(&pkg)?;\n\n        // Validate lockfile URL matches expected asset pattern from registry\n        // This handles cases where the registry format changed (e.g., raw binary -> tar.gz)\n        // Only validate for GithubRelease packages - other types use fixed URL formats\n        let validated_url = if let Some(ref url) = existing_platform {\n            if pkg.r#type != AquaPackageType::GithubRelease {\n                existing_platform // Skip validation for non-release package types\n            } else {\n                let cached_filename = get_filename_from_url(url);\n                let cached_filename_lower = cached_filename.to_lowercase();\n                // Check assets for both version variants (with and without v prefix)\n                let version_variants: Vec<&str> = match &v_prefixed {\n                    Some(vp) => vec![v.as_str(), vp.as_str()],\n                    None => vec![v.as_str()],\n                };\n                let matches = version_variants.iter().any(|ver| {\n                    pkg.asset_strs(ver, os(), arch())\n                        .unwrap_or_default()\n                        .iter()\n                        .any(|expected| {\n                            // Case-insensitive match to align with github_release_asset behavior\n                            cached_filename == *expected\n                                || cached_filename_lower == expected.to_lowercase()\n                        })\n                });\n                if matches {\n                    existing_platform\n                } else {\n                    warn!(\n                        \"lockfile asset '{}' doesn't match registry, refreshing\",\n                        cached_filename\n                    );\n                    None\n                }\n            }\n        } else {\n            None\n        };\n\n        let (url, v, filename, api_digest) = if let Some(validated_url) = validated_url.clone() {\n            let url = validated_url;\n            let filename = get_filename_from_url(&url);\n            // Determine which version variant was used based on the URL or filename\n            // Check for version_prefix (e.g., \"jq-\" for jq), \"v\" prefix, or raw version\n            let v = if let Some(prefix) = &pkg.version_prefix {\n                let prefixed_version = format!(\"{prefix}{}\", tv.version);\n                if url.contains(&prefixed_version) || filename.contains(&prefixed_version) {\n                    prefixed_version\n                } else if url.contains(&format!(\"v{}\", tv.version))\n                    || filename.contains(&format!(\"v{}\", tv.version))\n                {\n                    format!(\"v{}\", tv.version)\n                } else {\n                    tv.version.clone()\n                }\n            } else if url.contains(&format!(\"v{}\", tv.version))\n                || filename.contains(&format!(\"v{}\", tv.version))\n            {\n                format!(\"v{}\", tv.version)\n            } else {\n                tv.version.clone()\n            };\n            (url, v, filename, None)\n        } else {\n            let (url, v, digest) = if let Some(v_prefixed) = v_prefixed {\n                // Try v-prefixed version first because most aqua packages use v-prefixed versions\n                match self.get_url(&pkg, v_prefixed.as_ref()).await {\n                    // If the url is already checked, use it\n                    Ok((url, true, digest)) => (url, v_prefixed, digest),\n                    Ok((url_prefixed, false, digest_prefixed)) => {\n                        let (url, _, digest) = self.get_url(&pkg, &v).await?;\n                        // If the v-prefixed URL is the same as the non-prefixed URL, use it\n                        if url == url_prefixed {\n                            (url_prefixed, v_prefixed, digest_prefixed)\n                        } else {\n                            // If they are different, check existence\n                            match HTTP.head(&url_prefixed).await {\n                                Ok(_) => (url_prefixed, v_prefixed, digest_prefixed),\n                                Err(_) => (url, v, digest),\n                            }\n                        }\n                    }\n                    Err(err) => {\n                        let (url, _, digest) =\n                            self.get_url(&pkg, &v).await.map_err(|e| err.wrap_err(e))?;\n                        (url, v, digest)\n                    }\n                }\n            } else {\n                let (url, _, digest) = self.get_url(&pkg, &v).await?;\n                (url, v, digest)\n            };\n            let filename = get_filename_from_url(&url);\n\n            (url, v.to_string(), filename, digest)\n        };\n\n        let format = pkg.format(&v, os(), arch()).unwrap_or_default();\n\n        self.download(ctx, &tv, &url, &filename).await?;\n\n        if validated_url.is_none() {\n            // Store the asset URL and digest (if available) in the tool version\n            let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n            platform_info.url = Some(url.clone());\n            if let Some(digest) = api_digest.clone() {\n                debug!(\"using GitHub API digest for checksum verification\");\n                platform_info.checksum = Some(digest);\n            }\n        }\n\n        // Advance to checksum operation if applicable\n        if pkg.checksum.as_ref().is_some_and(|c| c.enabled()) || api_digest.is_some() {\n            ctx.pr.next_operation();\n        }\n        self.verify(ctx, &mut tv, &pkg, &v, &filename).await?;\n\n        // Advance to extraction operation if applicable\n        if needs_extraction(format, &pkg.r#type) {\n            ctx.pr.next_operation();\n        }\n        self.install(ctx, &tv, &pkg, &v, &filename)?;\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        if self.symlink_bins(tv) {\n            return Ok(vec![tv.install_path().join(\".mise-bins\")]);\n        }\n\n        let install_path = tv.install_path();\n        let cache: CacheManager<Vec<PathBuf>> =\n            CacheManagerBuilder::new(tv.cache_path().join(\"bin_paths.msgpack.z\"))\n                .with_fresh_file(install_path.clone())\n                .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n                .build();\n\n        let paths = cache\n            .get_or_try_init_async(async || {\n                let pkg = AQUA_REGISTRY\n                    .package_with_version(&self.id, &[&tv.version])\n                    .await?;\n\n                let srcs = self.srcs(&pkg, tv)?;\n                let paths = if srcs.is_empty() {\n                    vec![install_path.clone()]\n                } else {\n                    srcs.iter()\n                        .map(|(_, dst)| dst.parent().unwrap().to_path_buf())\n                        .collect()\n                };\n                Ok(paths\n                    .into_iter()\n                    .unique()\n                    .filter(|p| p.exists())\n                    .map(|p| p.strip_prefix(&install_path).unwrap().to_path_buf())\n                    .collect())\n            })\n            .await?\n            .iter()\n            .map(|p| p.mount(&install_path))\n            .collect();\n        Ok(paths)\n    }\n\n    fn fuzzy_match_filter(&self, versions: Vec<String>, query: &str) -> Vec<String> {\n        let escaped_query = regex::escape(query);\n        let query = if query == \"latest\" {\n            \"\\\\D*[0-9].*\"\n        } else {\n            &escaped_query\n        };\n        let query_regex = Regex::new(&format!(\"^{query}([-.].+)?$\")).unwrap();\n        versions\n            .into_iter()\n            .filter(|v| {\n                if query == v {\n                    return true;\n                }\n                if VERSION_REGEX.is_match(v) {\n                    return false;\n                }\n                query_regex.is_match(v)\n            })\n            .collect()\n    }\n\n    /// Resolve platform-specific lock information for any target platform.\n    /// This enables cross-platform lockfile generation without installation.\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // Map Platform to Aqua's os/arch conventions\n        let target_os = match target.os_name() {\n            \"macos\" => \"darwin\",\n            other => other,\n        };\n        let target_arch = match target.arch_name() {\n            \"x64\" => \"amd64\",\n            other => other,\n        };\n\n        // Get version tag\n        let tag = match self.get_version_tags().await {\n            Ok(tags) => tags\n                .iter()\n                .find(|(version, _)| version == &tv.version)\n                .map(|(_, tag)| tag.clone()),\n            Err(e) => {\n                warn!(\n                    \"[{}] failed to fetch version tags for lockfile, URL may be incorrect: {e}\",\n                    self.id\n                );\n                None\n            }\n        };\n        let tag_is_none = tag.is_none();\n        if tag_is_none && !tv.version.starts_with('v') {\n            debug!(\n                \"[{}] no tag found for version {} during lock, will try with 'v' prefix\",\n                self.id, tv.version\n            );\n        }\n        let mut v = tag.unwrap_or_else(|| tv.version.clone());\n        let v_prefixed = (tag_is_none && !tv.version.starts_with('v')).then(|| format!(\"v{v}\"));\n        let versions = match &v_prefixed {\n            Some(v_prefixed) => vec![v.as_str(), v_prefixed.as_str()],\n            None => vec![v.as_str()],\n        };\n\n        // Get package and apply version/overrides directly for the target platform.\n        // Using package_with_version() here would apply overrides for the current host\n        // platform first, which can leak host-specific overrides into cross-platform lock.\n        let pkg = AQUA_REGISTRY.package(&self.id).await?;\n        let pkg = pkg.with_version(&versions, target_os, target_arch);\n\n        // Apply version prefix if present\n        if let Some(prefix) = &pkg.version_prefix\n            && !v.starts_with(prefix)\n        {\n            v = format!(\"{prefix}{v}\");\n        }\n\n        // Check if this platform is supported\n        if !is_platform_supported(&pkg.supported_envs, target_os, target_arch) {\n            debug!(\n                \"aqua package {} does not support {}: supported_envs={:?}\",\n                self.id,\n                target.to_key(),\n                pkg.supported_envs\n            );\n            return Ok(PlatformInfo::default());\n        }\n\n        // Get URL and checksum for the target platform\n        let (url, checksum) = match pkg.r#type {\n            AquaPackageType::GithubRelease => {\n                // For GitHub releases, we need to find the asset for the target platform\n                let asset_strs = pkg.asset_strs(&v, target_os, target_arch)?;\n                match self.github_release_asset(&pkg, &v, asset_strs).await {\n                    Ok((url, digest)) => (Some(url), digest),\n                    Err(e) => {\n                        debug!(\n                            \"Failed to get GitHub release asset for {} on {}: {}\",\n                            self.id,\n                            target.to_key(),\n                            e\n                        );\n                        (None, None)\n                    }\n                }\n            }\n            AquaPackageType::GithubArchive | AquaPackageType::GithubContent => {\n                (Some(self.github_archive_url(&pkg, &v)), None)\n            }\n            AquaPackageType::Http => (pkg.url(&v, target_os, target_arch).ok(), None),\n            _ => (None, None),\n        };\n\n        let name = url.as_ref().map(|u| get_filename_from_url(u));\n\n        // Try to get checksum from checksum file if not available from GitHub API\n        let checksum = match checksum {\n            Some(c) => Some(c),\n            None => self\n                .fetch_checksum_from_file(&pkg, &v, target_os, target_arch, name.as_deref())\n                .await\n                .ok()\n                .flatten(),\n        };\n\n        // Detect provenance from aqua registry config\n        let provenance = self.detect_provenance_type(&pkg);\n\n        Ok(PlatformInfo {\n            url,\n            checksum,\n            provenance,\n            ..Default::default()\n        })\n    }\n}\n\nimpl AquaBackend {\n    /// Detect provenance type from aqua registry package config.\n    ///\n    /// Returns the highest-priority provenance type that is configured and\n    /// enabled for the package. GithubAttestations is NOT detected here\n    /// because it requires downloading the artifact to query the attestation\n    /// API — it is recorded at install-time after successful verification.\n    ///\n    /// NOTE: For packages with both `slsa_provenance` and `github_artifact_attestations`,\n    /// this returns `Slsa`. Subsequent `mise install` will enforce SLSA verification even\n    /// though attestations would also work. If SLSA verification fails (missing asset,\n    /// format change), the lockfile entry must be deleted and re-locked.\n    fn detect_provenance_type(&self, pkg: &AquaPackage) -> Option<ProvenanceType> {\n        let settings = Settings::get();\n\n        // Check for SLSA provenance (highest priority available at lock-time)\n        if settings.slsa\n            && settings.aqua.slsa\n            && let Some(slsa) = &pkg.slsa_provenance\n            && slsa.enabled != Some(false)\n        {\n            return Some(ProvenanceType::Slsa { url: None });\n        }\n\n        // Check for cosign (nested under checksum config, requires checksum enabled)\n        // Only record cosign provenance if we can actually verify it natively\n        // (key-based or bundle-based). Tools that only use opts require the external\n        // cosign CLI which we don't shell out to.\n        if settings.aqua.cosign\n            && let Some(checksum) = &pkg.checksum\n            && checksum.enabled()\n            && let Some(cosign) = checksum.cosign.as_ref()\n            && cosign.enabled != Some(false)\n            && (cosign.key.is_some() || cosign.bundle.is_some())\n        {\n            return Some(ProvenanceType::Cosign);\n        }\n\n        // Check for minisign\n        if settings.aqua.minisign\n            && let Some(minisign) = &pkg.minisign\n            && minisign.enabled != Some(false)\n        {\n            return Some(ProvenanceType::Minisign);\n        }\n\n        None\n    }\n\n    pub fn from_arg(ba: BackendArg) -> Self {\n        let full = ba.full_without_opts();\n        let mut id = full.split_once(\":\").unwrap_or((\"\", &full)).1;\n        if !id.contains(\"/\") {\n            id = REGISTRY\n                .get(id)\n                .and_then(|t| t.backends.iter().find_map(|s| s.full.strip_prefix(\"aqua:\")))\n                .unwrap_or_else(|| {\n                    warn!(\"invalid aqua tool: {}\", id);\n                    id\n                });\n        }\n        let cache_path = ba.cache_path.clone();\n        Self {\n            id: id.to_string(),\n            ba: Arc::new(ba),\n            version_tags_cache: CacheManagerBuilder::new(cache_path.join(\"version_tags.msgpack.z\"))\n                .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n                .build(),\n        }\n    }\n\n    async fn get_version_tags(&self) -> Result<&Vec<(String, String)>> {\n        self.version_tags_cache\n            .get_or_try_init_async(|| async {\n                let pkg = AQUA_REGISTRY.package(&self.id).await?;\n                let mut versions = Vec::new();\n                if !pkg.repo_owner.is_empty() && !pkg.repo_name.is_empty() {\n                    let tags = get_tags(&pkg).await?;\n                    for tag in tags.into_iter().rev() {\n                        let mut version = tag.as_str();\n                        match pkg.version_filter_ok(version) {\n                            Ok(true) => {}\n                            Ok(false) => continue,\n                            Err(e) => {\n                                warn!(\"[{}] aqua version filter error: {e}\", self.ba());\n                                continue;\n                            }\n                        }\n                        let pkg = pkg.clone().with_version(&[version], os(), arch());\n                        if let Some(prefix) = &pkg.version_prefix {\n                            if let Some(_v) = version.strip_prefix(prefix) {\n                                version = _v;\n                            } else {\n                                continue;\n                            }\n                        }\n                        version = version.strip_prefix('v').unwrap_or(version);\n                        versions.push((version.to_string(), tag));\n                    }\n                } else {\n                    bail!(\n                        \"aqua package {} does not have repo_owner and/or repo_name.\",\n                        self.id\n                    );\n                }\n                Ok(versions)\n            })\n            .await\n    }\n\n    async fn get_url(&self, pkg: &AquaPackage, v: &str) -> Result<(String, bool, Option<String>)> {\n        match pkg.r#type {\n            AquaPackageType::GithubRelease => self\n                .github_release_url(pkg, v)\n                .await\n                .map(|(url, digest)| (url, true, digest)),\n            AquaPackageType::GithubContent => {\n                if pkg.path.is_some() {\n                    Ok((self.github_content_url(pkg, v), false, None))\n                } else {\n                    bail!(\"github_content package requires `path`\")\n                }\n            }\n            AquaPackageType::GithubArchive => Ok((self.github_archive_url(pkg, v), false, None)),\n            AquaPackageType::Http => pkg.url(v, os(), arch()).map(|url| (url, false, None)),\n            ref t => bail!(\"unsupported aqua package type: {t}\"),\n        }\n    }\n\n    async fn github_release_url(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n    ) -> Result<(String, Option<String>)> {\n        let asset_strs = pkg.asset_strs(v, os(), arch())?;\n        self.github_release_asset(pkg, v, asset_strs).await\n    }\n\n    async fn github_release_asset(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n        asset_strs: IndexSet<String>,\n    ) -> Result<(String, Option<String>)> {\n        let gh_id = format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name);\n        let gh_release = github::get_release(&gh_id, v).await?;\n\n        // Prioritize order of asset_strs\n        let asset = asset_strs\n            .iter()\n            .find_map(|expected| {\n                gh_release.assets.iter().find(|a| {\n                    a.name == *expected || a.name.to_lowercase() == expected.to_lowercase()\n                })\n            })\n            .wrap_err_with(|| {\n                format!(\n                    \"no asset found: {}\\nAvailable assets:\\n{}\",\n                    asset_strs.iter().join(\", \"),\n                    gh_release.assets.iter().map(|a| &a.name).join(\"\\n\")\n                )\n            })?;\n\n        Ok((asset.browser_download_url.to_string(), asset.digest.clone()))\n    }\n\n    fn github_archive_url(&self, pkg: &AquaPackage, v: &str) -> String {\n        let gh_id = format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name);\n        format!(\"https://github.com/{gh_id}/archive/refs/tags/{v}.tar.gz\")\n    }\n\n    fn github_content_url(&self, pkg: &AquaPackage, v: &str) -> String {\n        let gh_id = format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name);\n        let path = pkg.path.as_deref().unwrap();\n        format!(\"https://raw.githubusercontent.com/{gh_id}/{v}/{path}\")\n    }\n\n    /// Fetch checksum from a checksum file without downloading the actual tarball.\n    /// This is used for cross-platform lockfile generation.\n    async fn fetch_checksum_from_file(\n        &self,\n        pkg: &AquaPackage,\n        v: &str,\n        target_os: &str,\n        target_arch: &str,\n        filename: Option<&str>,\n    ) -> Result<Option<String>> {\n        let Some(checksum_config) = &pkg.checksum else {\n            return Ok(None);\n        };\n        if !checksum_config.enabled() {\n            return Ok(None);\n        }\n        let Some(filename) = filename else {\n            return Ok(None);\n        };\n\n        // Get the checksum file URL\n        let url = match checksum_config._type() {\n            AquaChecksumType::GithubRelease => {\n                let asset_strs = checksum_config.asset_strs(pkg, v, target_os, target_arch)?;\n                match self.github_release_asset(pkg, v, asset_strs).await {\n                    Ok((url, _)) => url,\n                    Err(e) => {\n                        debug!(\"Failed to get checksum file asset: {}\", e);\n                        return Ok(None);\n                    }\n                }\n            }\n            AquaChecksumType::Http => checksum_config.url(pkg, v, target_os, target_arch)?,\n        };\n\n        // Download checksum file content\n        let checksum_content = match HTTP.get_text(&url).await {\n            Ok(content) => content,\n            Err(e) => {\n                debug!(\"Failed to download checksum file {}: {}\", url, e);\n                return Ok(None);\n            }\n        };\n\n        // Parse checksum from file content\n        let checksum_str =\n            self.parse_checksum_from_content(&checksum_content, checksum_config, filename)?;\n\n        Ok(Some(format!(\n            \"{}:{}\",\n            checksum_config.algorithm(),\n            checksum_str\n        )))\n    }\n\n    /// Parse a checksum from checksum file content for a specific filename.\n    fn parse_checksum_from_content(\n        &self,\n        content: &str,\n        checksum_config: &AquaChecksum,\n        filename: &str,\n    ) -> Result<String> {\n        let mut checksum_file = content.to_string();\n\n        if checksum_config.file_format() == \"regexp\" {\n            let pattern = checksum_config.pattern();\n            if let Some(file_pattern) = &pattern.file {\n                let re = regex::Regex::new(file_pattern.as_str())?;\n                if let Some(line) = checksum_file\n                    .lines()\n                    .find(|l| re.captures(l).is_some_and(|c| c[1].to_string() == filename))\n                {\n                    checksum_file = line.to_string();\n                } else {\n                    debug!(\n                        \"no line found matching {} in checksum file for {}\",\n                        file_pattern, filename\n                    );\n                }\n            }\n            let re = regex::Regex::new(pattern.checksum.as_str())?;\n            if let Some(caps) = re.captures(checksum_file.as_str()) {\n                checksum_file = caps[1].to_string();\n            } else {\n                debug!(\n                    \"no checksum found matching {} in checksum file\",\n                    pattern.checksum\n                );\n            }\n        }\n\n        // Standard format: \"<hash>  <filename>\" or \"<hash> *<filename>\"\n        let checksum_str = checksum_file\n            .lines()\n            .filter_map(|l| {\n                let split = l.split_whitespace().collect_vec();\n                if split.len() == 2 {\n                    Some((\n                        split[0].to_string(),\n                        split[1]\n                            .rsplit_once('/')\n                            .map(|(_, f)| f)\n                            .unwrap_or(split[1])\n                            .trim_matches('*')\n                            .to_string(),\n                    ))\n                } else {\n                    None\n                }\n            })\n            .find(|(_, f)| f == filename)\n            .map(|(c, _)| c)\n            .unwrap_or(checksum_file);\n\n        let checksum_str = checksum_str\n            .split_whitespace()\n            .next()\n            .unwrap_or(&checksum_str);\n        Ok(checksum_str.to_string())\n    }\n\n    /// Download a URL to a path, or convert a local path string to PathBuf.\n    /// Returns the path where the file is located.\n    async fn download_url_to_path(\n        &self,\n        url: &str,\n        download_path: &Path,\n        ctx: &InstallContext,\n    ) -> Result<PathBuf> {\n        if url.starts_with(\"http\") {\n            let path = download_path.join(get_filename_from_url(url));\n            HTTP.download_file(url, &path, Some(ctx.pr.as_ref()))\n                .await?;\n            Ok(path)\n        } else {\n            Ok(PathBuf::from(url))\n        }\n    }\n\n    async fn download(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        url: &str,\n        filename: &str,\n    ) -> Result<()> {\n        let tarball_path = tv.download_path().join(filename);\n        if tarball_path.exists() {\n            return Ok(());\n        }\n        ctx.pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(url, &tarball_path, Some(ctx.pr.as_ref()))\n            .await?;\n        Ok(())\n    }\n\n    async fn verify(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pkg: &AquaPackage,\n        v: &str,\n        filename: &str,\n    ) -> Result<()> {\n        // Check if the lockfile expects provenance for this platform, then clear it\n        // so we can detect whether verification actually re-set it\n        let platform_key = self.get_platform_key();\n        let locked_provenance = tv\n            .lock_platforms\n            .get_mut(&platform_key)\n            .and_then(|pi| pi.provenance.take());\n\n        // When the lockfile specifies a provenance type, only run that specific mechanism.\n        // This prevents false-positive downgrade errors when a tool supports multiple mechanisms\n        // (e.g., both minisign and cosign) that would otherwise compete for the provenance slot.\n        let skip_attestations = locked_provenance\n            .as_ref()\n            .is_some_and(|l| !l.is_github_attestations());\n        let skip_slsa = locked_provenance.as_ref().is_some_and(|l| !l.is_slsa());\n        let skip_minisign = locked_provenance.as_ref().is_some_and(|l| !l.is_minisign());\n        let skip_cosign = locked_provenance.as_ref().is_some_and(|l| !l.is_cosign());\n\n        if !skip_attestations {\n            self.verify_github_artifact_attestations(ctx, tv, pkg, v, filename)\n                .await?;\n        }\n        if !skip_slsa {\n            // Short-circuit: if a higher-priority mechanism already recorded provenance, skip SLSA\n            let already_verified = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|pi| pi.provenance.as_ref())\n                .is_some_and(|p| *p > ProvenanceType::Slsa { url: None });\n            if !already_verified {\n                self.verify_slsa(ctx, tv, pkg, v, filename).await?;\n            }\n        }\n        if !skip_minisign {\n            // Short-circuit: if SLSA or GithubAttestations already recorded provenance, skip minisign.\n            // Cosign runs later in the checksum block, so it cannot be set at this point.\n            let already_verified = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|pi| pi.provenance.as_ref())\n                .is_some_and(|p| p.is_slsa() || p.is_github_attestations());\n            if !already_verified {\n                self.verify_minisign(ctx, tv, pkg, v, filename).await?;\n            }\n        }\n\n        let download_path = tv.download_path();\n        if let Some(checksum) = &pkg.checksum\n            && checksum.enabled()\n        {\n            let checksum_path = download_path.join(format!(\"{filename}.checksum\"));\n            let platform_key = self.get_platform_key();\n            let needs_checksum = tv\n                .lock_platforms\n                .get(&platform_key)\n                .is_none_or(|pi| pi.checksum.is_none());\n\n            let needs_cosign = !skip_cosign;\n            // Short-circuit cosign if a higher-priority mechanism already recorded provenance.\n            // Safe to cache: provenance is only modified by the single-threaded verification\n            // methods above (attestations, slsa, minisign), all of which have completed by now.\n            let cosign_already_verified = needs_cosign\n                && tv\n                    .lock_platforms\n                    .get(&platform_key)\n                    .and_then(|pi| pi.provenance.as_ref())\n                    .is_some_and(|p| *p > ProvenanceType::Cosign);\n            // Re-download only if the checksum file doesn't exist yet. An existing file\n            // from a prior attempt is trusted because the download directory is version-specific\n            // and the final artifact is independently verified by verify_checksum at the end.\n            if (needs_checksum || (needs_cosign && !cosign_already_verified))\n                && !checksum_path.exists()\n            {\n                let url = match checksum._type() {\n                    AquaChecksumType::GithubRelease => {\n                        let asset_strs = checksum.asset_strs(pkg, v, os(), arch())?;\n                        self.github_release_asset(pkg, v, asset_strs).await?.0\n                    }\n                    AquaChecksumType::Http => checksum.url(pkg, v, os(), arch())?,\n                };\n                HTTP.download_file(&url, &checksum_path, Some(ctx.pr.as_ref()))\n                    .await?;\n            }\n\n            if !skip_cosign && !cosign_already_verified && checksum_path.exists() {\n                self.cosign_checksums(ctx, pkg, v, tv, &checksum_path, &download_path)\n                    .await?;\n            }\n\n            if needs_checksum && checksum_path.exists() {\n                let checksum_content = file::read_to_string(&checksum_path)?;\n                let checksum_str =\n                    self.parse_checksum_from_content(&checksum_content, checksum, filename)?;\n                let checksum_val = format!(\"{}:{}\", checksum.algorithm(), checksum_str);\n                let platform_key = self.get_platform_key();\n                let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n                platform_info.checksum = Some(checksum_val);\n            }\n        }\n        // If lockfile recorded provenance, verify that the type matches\n        // (checked after all verification methods including cosign have had a chance to record)\n        if let Some(ref expected) = locked_provenance {\n            let platform_key = self.get_platform_key();\n            let got = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|pi| pi.provenance.as_ref());\n            if !got.is_some_and(|g| std::mem::discriminant(g) == std::mem::discriminant(expected)) {\n                let got_str = got\n                    .map(|g| g.to_string())\n                    .unwrap_or_else(|| \"no verification\".to_string());\n                return Err(eyre!(\n                    \"Lockfile requires {expected} provenance for {tv} but {got_str} was used. \\\n                     This may indicate a downgrade attack. Enable the corresponding verification setting \\\n                     or update the lockfile.\"\n                ));\n            }\n        }\n\n        let tarball_path = tv.download_path().join(filename);\n        self.verify_checksum(ctx, tv, &tarball_path)?;\n        Ok(())\n    }\n\n    async fn verify_minisign(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pkg: &AquaPackage,\n        v: &str,\n        filename: &str,\n    ) -> Result<()> {\n        if !Settings::get().aqua.minisign {\n            return Ok(());\n        }\n        if let Some(minisign) = &pkg.minisign {\n            if minisign.enabled == Some(false) {\n                debug!(\"minisign is disabled for {tv}\");\n                return Ok(());\n            }\n            ctx.pr.set_message(\"verify minisign\".to_string());\n            debug!(\"minisign: {:?}\", minisign);\n            let sig_path = match minisign._type() {\n                AquaMinisignType::GithubRelease => {\n                    let asset = minisign.asset(pkg, v, os(), arch())?;\n                    let (repo_owner, repo_name) = resolve_repo_info(\n                        minisign.repo_owner.as_ref(),\n                        minisign.repo_name.as_ref(),\n                        pkg,\n                    );\n                    let url = github::get_release(&format!(\"{repo_owner}/{repo_name}\"), v)\n                        .await?\n                        .assets\n                        .into_iter()\n                        .find(|a| a.name == asset)\n                        .map(|a| a.browser_download_url);\n                    if let Some(url) = url {\n                        let path = tv.download_path().join(asset);\n                        HTTP.download_file(&url, &path, Some(ctx.pr.as_ref()))\n                            .await?;\n                        path\n                    } else {\n                        warn!(\"no asset found for minisign of {tv}: {asset}\");\n                        return Ok(());\n                    }\n                }\n                AquaMinisignType::Http => {\n                    let url = minisign.url(pkg, v, os(), arch())?;\n                    let path = tv.download_path().join(filename).with_extension(\".minisig\");\n                    HTTP.download_file(&url, &path, Some(ctx.pr.as_ref()))\n                        .await?;\n                    path\n                }\n            };\n            let data = file::read(tv.download_path().join(filename))?;\n            let sig = file::read_to_string(sig_path)?;\n            minisign::verify(&minisign.public_key(pkg, v, os(), arch())?, &data, &sig)?;\n\n            // Record minisign provenance if no higher-priority verification already recorded\n            let platform_key = self.get_platform_key();\n            let pi = tv.lock_platforms.entry(platform_key).or_default();\n            if pi.provenance.is_none() {\n                pi.provenance = Some(ProvenanceType::Minisign);\n            }\n        }\n        Ok(())\n    }\n\n    async fn verify_slsa(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pkg: &AquaPackage,\n        v: &str,\n        filename: &str,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        if !settings.slsa || !settings.aqua.slsa {\n            return Ok(());\n        }\n        if let Some(slsa) = &pkg.slsa_provenance {\n            if slsa.enabled == Some(false) {\n                debug!(\"slsa is disabled for {tv}\");\n                return Ok(());\n            }\n\n            ctx.pr.set_message(\"verify slsa\".to_string());\n\n            // Download the provenance file\n            let mut slsa_pkg = pkg.clone();\n            (slsa_pkg.repo_owner, slsa_pkg.repo_name) =\n                resolve_repo_info(slsa.repo_owner.as_ref(), slsa.repo_name.as_ref(), pkg);\n\n            let (provenance_path, provenance_download_url) =\n                match slsa.r#type.as_deref().unwrap_or_default() {\n                    \"github_release\" => {\n                        let asset_strs = slsa.asset_strs(pkg, v, os(), arch())?;\n                        if asset_strs.is_empty() {\n                            warn!(\"no asset configured for slsa verification of {tv}\");\n                            return Ok(());\n                        }\n                        match self.github_release_asset(&slsa_pkg, v, asset_strs).await {\n                            Ok((url, _)) => {\n                                let asset_filename = get_filename_from_url(&url);\n                                let path = tv.download_path().join(asset_filename);\n                                HTTP.download_file(&url, &path, Some(ctx.pr.as_ref()))\n                                    .await?;\n                                (path, url)\n                            }\n                            Err(e) => {\n                                warn!(\"no asset found for slsa verification of {tv}: {e}\");\n                                return Ok(());\n                            }\n                        }\n                    }\n                    \"http\" => {\n                        let url = slsa.url(pkg, v, os(), arch())?;\n                        let path = tv.download_path().join(get_filename_from_url(&url));\n                        HTTP.download_file(&url, &path, Some(ctx.pr.as_ref()))\n                            .await?;\n                        (path, url)\n                    }\n                    t => {\n                        warn!(\"unsupported slsa type: {t}\");\n                        return Ok(());\n                    }\n                };\n\n            let artifact_path = tv.download_path().join(filename);\n\n            // Use native sigstore-verification crate for SLSA verification\n            // Default to SLSA level 1 (sops provides level 1, newer tools provide level 2+)\n            let min_level = 1u8;\n\n            match sigstore_verification::verify_slsa_provenance(\n                &artifact_path,\n                &provenance_path,\n                min_level,\n            )\n            .await\n            {\n                Ok(true) => {\n                    ctx.pr\n                        .set_message(format!(\"✓ SLSA provenance verified (level {})\", min_level));\n                    debug!(\n                        \"SLSA provenance verified successfully for {tv} at level {}\",\n                        min_level\n                    );\n                    // Record provenance in lockfile only if not already set by a\n                    // higher-priority verification (github-attestations runs first)\n                    let platform_key = self.get_platform_key();\n                    let pi = tv.lock_platforms.entry(platform_key).or_default();\n                    if pi.provenance.is_none() {\n                        pi.provenance = Some(ProvenanceType::Slsa {\n                            url: Some(provenance_download_url.clone()),\n                        });\n                    }\n                }\n                Ok(false) => {\n                    return Err(eyre!(\"SLSA provenance verification failed for {tv}\"));\n                }\n                Err(e) => {\n                    // Use proper error type matching instead of string matching\n                    match &e {\n                        sigstore_verification::AttestationError::NoAttestations => {\n                            // SLSA verification was explicitly configured but attestations are missing\n                            // This should be treated as a security failure, not a warning\n                            return Err(eyre!(\n                                \"SLSA verification failed for {tv}: Package configuration requires SLSA provenance but no attestations found\"\n                            ));\n                        }\n                        _ => {\n                            return Err(eyre!(\"SLSA verification error for {tv}: {e}\"));\n                        }\n                    }\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn verify_github_artifact_attestations(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pkg: &AquaPackage,\n        _v: &str,\n        filename: &str,\n    ) -> Result<()> {\n        // Check if attestations are enabled via global and aqua-specific settings\n        let settings = Settings::get();\n        if !settings.github_attestations || !settings.aqua.github_attestations {\n            debug!(\"GitHub artifact attestations verification disabled\");\n            return Ok(());\n        }\n\n        if let Some(github_attestations) = &pkg.github_artifact_attestations {\n            if github_attestations.enabled == Some(false) {\n                debug!(\"GitHub artifact attestations verification is disabled for {tv}\");\n                return Ok(());\n            }\n\n            ctx.pr\n                .set_message(\"verify GitHub artifact attestations\".to_string());\n\n            let artifact_path = tv.download_path().join(filename);\n\n            // Get expected workflow from registry\n            let signer_workflow = pkg\n                .github_artifact_attestations\n                .as_ref()\n                .and_then(|att| att.signer_workflow.clone());\n\n            match sigstore_verification::verify_github_attestation(\n                &artifact_path,\n                &pkg.repo_owner,\n                &pkg.repo_name,\n                env::GITHUB_TOKEN.as_deref(),\n                signer_workflow.as_deref(),\n            )\n            .await\n            {\n                Ok(true) => {\n                    ctx.pr\n                        .set_message(\"✓ GitHub artifact attestations verified\".to_string());\n                    debug!(\"GitHub artifact attestations verified successfully for {tv}\");\n                    let platform_key = self.get_platform_key();\n                    let pi = tv.lock_platforms.entry(platform_key).or_default();\n                    if pi.provenance.is_none() {\n                        pi.provenance = Some(ProvenanceType::GithubAttestations);\n                    }\n                }\n                Ok(false) => {\n                    return Err(eyre!(\n                        \"GitHub artifact attestations verification returned false for {tv}\"\n                    ));\n                }\n                Err(sigstore_verification::AttestationError::NoAttestations) => {\n                    return Err(eyre!(\n                        \"No GitHub artifact attestations found for {tv}, but they are expected per aqua registry configuration\"\n                    ));\n                }\n                Err(e) => {\n                    return Err(eyre!(\n                        \"GitHub artifact attestations verification failed for {tv}: {e}\"\n                    ));\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    async fn cosign_checksums(\n        &self,\n        ctx: &InstallContext,\n        pkg: &AquaPackage,\n        v: &str,\n        tv: &mut ToolVersion,\n        checksum_path: &Path,\n        download_path: &Path,\n    ) -> Result<()> {\n        if !Settings::get().aqua.cosign {\n            return Ok(());\n        }\n        if let Some(cosign) = pkg.checksum.as_ref().and_then(|c| c.cosign.as_ref()) {\n            if cosign.enabled == Some(false) {\n                debug!(\"cosign is disabled for {tv}\");\n                return Ok(());\n            }\n\n            ctx.pr\n                .set_message(\"verify checksums with cosign\".to_string());\n\n            // Use native sigstore-verification crate\n            if let Some(key) = &cosign.key {\n                // Key-based verification\n                let mut key_pkg = pkg.clone();\n                (key_pkg.repo_owner, key_pkg.repo_name) =\n                    resolve_repo_info(key.repo_owner.as_ref(), key.repo_name.as_ref(), pkg);\n                let key_arg = match key.r#type.as_deref().unwrap_or_default() {\n                    \"github_release\" => {\n                        let asset_strs = key.asset_strs(pkg, v, os(), arch())?;\n                        if asset_strs.is_empty() {\n                            String::new()\n                        } else {\n                            self.github_release_asset(&key_pkg, v, asset_strs).await?.0\n                        }\n                    }\n                    \"http\" => key.url(pkg, v, os(), arch())?,\n                    t => {\n                        warn!(\n                            \"unsupported cosign key type for {}/{}: {t}\",\n                            pkg.repo_owner, pkg.repo_name\n                        );\n                        String::new()\n                    }\n                };\n                if !key_arg.is_empty() {\n                    // Download or locate the public key\n                    let key_path = self\n                        .download_url_to_path(&key_arg, download_path, ctx)\n                        .await?;\n\n                    // Download signature if specified\n                    let sig_path = if let Some(signature) = &cosign.signature {\n                        let mut sig_pkg = pkg.clone();\n                        (sig_pkg.repo_owner, sig_pkg.repo_name) = resolve_repo_info(\n                            signature.repo_owner.as_ref(),\n                            signature.repo_name.as_ref(),\n                            pkg,\n                        );\n                        let sig_arg = match signature.r#type.as_deref().unwrap_or_default() {\n                            \"github_release\" => {\n                                let asset_strs = signature.asset_strs(pkg, v, os(), arch())?;\n                                if asset_strs.is_empty() {\n                                    String::new()\n                                } else {\n                                    self.github_release_asset(&sig_pkg, v, asset_strs).await?.0\n                                }\n                            }\n                            \"http\" => signature.url(pkg, v, os(), arch())?,\n                            t => {\n                                warn!(\n                                    \"unsupported cosign signature type for {}/{}: {t}\",\n                                    pkg.repo_owner, pkg.repo_name\n                                );\n                                String::new()\n                            }\n                        };\n                        if !sig_arg.is_empty() {\n                            self.download_url_to_path(&sig_arg, download_path, ctx)\n                                .await?\n                        } else {\n                            // Default signature path\n                            checksum_path.with_extension(\"sig\")\n                        }\n                    } else {\n                        // Default signature path\n                        checksum_path.with_extension(\"sig\")\n                    };\n\n                    // Verify with key\n                    match sigstore_verification::verify_cosign_signature_with_key(\n                        checksum_path,\n                        &sig_path,\n                        &key_path,\n                    )\n                    .await\n                    {\n                        Ok(true) => {\n                            ctx.pr\n                                .set_message(\"✓ Cosign signature verified with key\".to_string());\n                            debug!(\"Cosign signature verified successfully with key for {tv}\");\n                            let platform_key = self.get_platform_key();\n                            let pi = tv.lock_platforms.entry(platform_key).or_default();\n                            if pi\n                                .provenance\n                                .as_ref()\n                                .is_none_or(|p| *p < ProvenanceType::Cosign)\n                            {\n                                pi.provenance = Some(ProvenanceType::Cosign);\n                            }\n                        }\n                        Ok(false) => {\n                            return Err(eyre!(\"Cosign signature verification failed for {tv}\"));\n                        }\n                        Err(e) => {\n                            return Err(eyre!(\"Cosign verification error for {tv}: {e}\"));\n                        }\n                    }\n                }\n            } else if let Some(bundle) = &cosign.bundle {\n                // Bundle-based keyless verification\n                let mut bundle_pkg = pkg.clone();\n                (bundle_pkg.repo_owner, bundle_pkg.repo_name) =\n                    resolve_repo_info(bundle.repo_owner.as_ref(), bundle.repo_name.as_ref(), pkg);\n                let bundle_arg = match bundle.r#type.as_deref().unwrap_or_default() {\n                    \"github_release\" => {\n                        let asset_strs = bundle.asset_strs(pkg, v, os(), arch())?;\n                        if asset_strs.is_empty() {\n                            String::new()\n                        } else {\n                            self.github_release_asset(&bundle_pkg, v, asset_strs)\n                                .await?\n                                .0\n                        }\n                    }\n                    \"http\" => bundle.url(pkg, v, os(), arch())?,\n                    t => {\n                        warn!(\n                            \"unsupported cosign bundle type for {}/{}: {t}\",\n                            pkg.repo_owner, pkg.repo_name\n                        );\n                        String::new()\n                    }\n                };\n                if !bundle_arg.is_empty() {\n                    let bundle_path = self\n                        .download_url_to_path(&bundle_arg, download_path, ctx)\n                        .await?;\n\n                    // Verify with bundle (keyless)\n                    match sigstore_verification::verify_cosign_signature(\n                        checksum_path,\n                        &bundle_path,\n                    )\n                    .await\n                    {\n                        Ok(true) => {\n                            ctx.pr\n                                .set_message(\"✓ Cosign bundle verified (keyless)\".to_string());\n                            debug!(\"Cosign bundle verified successfully for {tv}\");\n                            let platform_key = self.get_platform_key();\n                            let pi = tv.lock_platforms.entry(platform_key).or_default();\n                            if pi\n                                .provenance\n                                .as_ref()\n                                .is_none_or(|p| *p < ProvenanceType::Cosign)\n                            {\n                                pi.provenance = Some(ProvenanceType::Cosign);\n                            }\n                        }\n                        Ok(false) => {\n                            return Err(eyre!(\"Cosign bundle verification failed for {tv}\"));\n                        }\n                        Err(e) => {\n                            return Err(eyre!(\"Cosign bundle verification error for {tv}: {e}\"));\n                        }\n                    }\n                }\n            } else {\n                debug!(\"cosign for {tv} uses opts-only config, skipping native verification\");\n            }\n        }\n        Ok(())\n    }\n\n    fn install(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        pkg: &AquaPackage,\n        v: &str,\n        filename: &str,\n    ) -> Result<()> {\n        let tarball_path = tv.download_path().join(filename);\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        let install_path = tv.install_path();\n        file::remove_all(&install_path)?;\n        let format = pkg.format(v, os(), arch())?;\n        let mut bin_names: Vec<Cow<'_, str>> = pkg\n            .files\n            .iter()\n            .filter_map(|file| match file.src(pkg, v, os(), arch()) {\n                Ok(Some(s)) => Some(Cow::Owned(s)),\n                Ok(None) => Some(Cow::Borrowed(file.name.as_str())),\n                Err(_) => None,\n            })\n            .collect();\n        if bin_names.is_empty() {\n            let fallback_name = pkg\n                .name\n                .as_deref()\n                .and_then(|n| n.split('/').next_back())\n                .unwrap_or(&pkg.repo_name);\n            bin_names = vec![Cow::Borrowed(fallback_name)];\n        }\n        let bin_paths: Vec<_> = bin_names\n            .iter()\n            .map(|name| {\n                let name_str: &str = name.as_ref();\n                install_path.join(name_str)\n            })\n            .map(|path| {\n                if cfg!(windows) && pkg.complete_windows_ext {\n                    path.with_extension(\"exe\")\n                } else {\n                    path\n                }\n            })\n            .collect();\n        let first_bin_path = bin_paths\n            .first()\n            .expect(\"at least one bin path should exist\");\n        let tar_opts = TarOptions {\n            pr: Some(ctx.pr.as_ref()),\n            ..TarOptions::new(TarFormat::from_ext(format))\n        };\n        let mut make_executable = false;\n        if let AquaPackageType::GithubArchive = pkg.r#type {\n            file::untar(&tarball_path, &install_path, &tar_opts)?;\n        } else if let AquaPackageType::GithubContent = pkg.r#type {\n            file::create_dir_all(&install_path)?;\n            file::copy(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format == \"raw\" {\n            file::create_dir_all(&install_path)?;\n            file::copy(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format.starts_with(\"tar\") {\n            file::untar(&tarball_path, &install_path, &tar_opts)?;\n            make_executable = true;\n        } else if format == \"zip\" {\n            file::unzip(&tarball_path, &install_path, &Default::default())?;\n            make_executable = true;\n        } else if format == \"gz\" {\n            file::create_dir_all(&install_path)?;\n            file::un_gz(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format == \"xz\" {\n            file::create_dir_all(&install_path)?;\n            file::un_xz(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format == \"zst\" {\n            file::create_dir_all(&install_path)?;\n            file::un_zst(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format == \"bz2\" {\n            file::create_dir_all(&install_path)?;\n            file::un_bz2(&tarball_path, first_bin_path)?;\n            make_executable = true;\n        } else if format == \"dmg\" {\n            file::un_dmg(&tarball_path, &install_path)?;\n        } else if format == \"pkg\" {\n            file::un_pkg(&tarball_path, &install_path)?;\n        } else {\n            bail!(\"unsupported format: {}\", format);\n        }\n\n        if make_executable {\n            for bin_path in &bin_paths {\n                // bin_path should exist, but doesn't when the registry is outdated\n                if bin_path.exists() {\n                    file::make_executable(bin_path)?;\n                } else {\n                    warn!(\"bin path does not exist: {}\", bin_path.display());\n                }\n            }\n        }\n\n        let srcs = self.srcs(pkg, tv)?;\n        for (src, dst) in &srcs {\n            if src != dst && src.exists() && !dst.exists() {\n                if cfg!(windows) {\n                    file::copy(src, dst)?;\n                } else {\n                    let src = PathBuf::from(\".\").join(src.file_name().unwrap().to_str().unwrap());\n                    file::make_symlink(&src, dst)?;\n                }\n            }\n        }\n\n        if self.symlink_bins(tv) {\n            self.create_symlink_bin_dir(tv, &srcs)?;\n        }\n\n        Ok(())\n    }\n\n    /// Creates a `.mise-bins` directory with symlinks only to the binaries defined in the aqua registry.\n    /// This prevents bundled dependencies (like Python in aws-cli) from being exposed on PATH.\n    fn create_symlink_bin_dir(&self, tv: &ToolVersion, srcs: &[(PathBuf, PathBuf)]) -> Result<()> {\n        let symlink_dir = tv.install_path().join(\".mise-bins\");\n        file::create_dir_all(&symlink_dir)?;\n\n        for (_, dst) in srcs {\n            if let Some(bin_name) = dst.file_name() {\n                let symlink_path = symlink_dir.join(bin_name);\n                if dst.exists() && !symlink_path.exists() {\n                    file::make_symlink_or_copy(dst, &symlink_path)?;\n                }\n            }\n        }\n        Ok(())\n    }\n\n    fn symlink_bins(&self, tv: &ToolVersion) -> bool {\n        tv.request\n            .options()\n            .get(\"symlink_bins\")\n            .is_some_and(|v| v == \"true\" || v == \"1\")\n    }\n\n    fn srcs(&self, pkg: &AquaPackage, tv: &ToolVersion) -> Result<Vec<(PathBuf, PathBuf)>> {\n        if pkg.files.is_empty() {\n            let fallback_name = pkg\n                .name\n                .as_deref()\n                .and_then(|n| n.split('/').next_back())\n                .unwrap_or(&pkg.repo_name);\n\n            let mut path = tv.install_path().join(fallback_name);\n            if cfg!(windows) && pkg.complete_windows_ext {\n                path = path.with_extension(\"exe\");\n            }\n\n            return Ok(vec![(path.clone(), path)]);\n        }\n\n        let files: Vec<(PathBuf, PathBuf)> = pkg\n            .files\n            .iter()\n            .map(|f| {\n                let srcs = if let Some(prefix) = &pkg.version_prefix {\n                    vec![f.src(pkg, &format!(\"{}{}\", prefix, tv.version), os(), arch())?]\n                } else {\n                    vec![\n                        f.src(pkg, &tv.version, os(), arch())?,\n                        f.src(pkg, &format!(\"v{}\", tv.version), os(), arch())?,\n                    ]\n                };\n                Ok(srcs\n                    .into_iter()\n                    .flatten()\n                    .map(|src| tv.install_path().join(src))\n                    .map(|mut src| {\n                        let mut dst = src.parent().unwrap().join(f.name.as_str());\n                        if cfg!(windows) && pkg.complete_windows_ext {\n                            src = src.with_extension(\"exe\");\n                            dst = dst.with_extension(\"exe\");\n                        }\n                        (src, dst)\n                    }))\n            })\n            .flatten_ok()\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .unique_by(|(src, _)| src.to_path_buf())\n            .collect();\n        Ok(files)\n    }\n}\n\nasync fn get_tags(pkg: &AquaPackage) -> Result<Vec<String>> {\n    Ok(get_tags_with_created_at(pkg)\n        .await?\n        .into_iter()\n        .map(|(tag, _)| tag)\n        .collect())\n}\n\n/// Get tags with optional created_at timestamps.\n/// Returns (tag_name, Option<created_at>) pairs.\nasync fn get_tags_with_created_at(pkg: &AquaPackage) -> Result<Vec<(String, Option<String>)>> {\n    if let Some(\"github_tag\") = pkg.version_source.as_deref() {\n        // Tags don't have created_at timestamps\n        let versions = github::list_tags(&format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name)).await?;\n        return Ok(versions.into_iter().map(|v| (v, None)).collect());\n    }\n    let releases = github::list_releases(&format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name)).await?;\n    if releases.is_empty() {\n        // Fall back to tags (no timestamps)\n        let versions = github::list_tags(&format!(\"{}/{}\", pkg.repo_owner, pkg.repo_name)).await?;\n        return Ok(versions.into_iter().map(|v| (v, None)).collect());\n    }\n    Ok(releases\n        .into_iter()\n        .map(|r| (r.tag_name, Some(r.created_at)))\n        .collect())\n}\n\nfn validate(pkg: &AquaPackage) -> Result<()> {\n    if pkg.no_asset {\n        bail!(\"no asset released\");\n    }\n    if let Some(message) = &pkg.error_message {\n        bail!(\"{}\", message);\n    }\n    if !is_platform_supported(&pkg.supported_envs, os(), arch()) {\n        bail!(\n            \"unsupported env: {}/{} (supported: {:?})\",\n            os(),\n            arch(),\n            pkg.supported_envs\n        );\n    }\n    match pkg.r#type {\n        AquaPackageType::Cargo => {\n            bail!(\n                \"package type `cargo` is not supported in the aqua backend. Use the cargo backend instead{}.\",\n                pkg.name\n                    .as_ref()\n                    .and_then(|s| s.strip_prefix(\"crates.io/\"))\n                    .map(|name| format!(\": cargo:{name}\"))\n                    .unwrap_or_default()\n            )\n        }\n        AquaPackageType::GoInstall => {\n            bail!(\n                \"package type `go_install` is not supported in the aqua backend. Use the go backend instead{}.\",\n                pkg.path\n                    .as_ref()\n                    .map(|path| format!(\": go:{path}\"))\n                    .unwrap_or_else(|| {\n                        format!(\": go:github.com/{}/{}\", pkg.repo_owner, pkg.repo_name)\n                    })\n            )\n        }\n        _ => {}\n    }\n    Ok(())\n}\n\n/// Resolve repo owner and name from an override config, falling back to pkg defaults.\nfn resolve_repo_info(\n    override_owner: Option<&String>,\n    override_name: Option<&String>,\n    pkg: &AquaPackage,\n) -> (String, String) {\n    let owner = override_owner\n        .cloned()\n        .unwrap_or_else(|| pkg.repo_owner.clone());\n    let name = override_name\n        .cloned()\n        .unwrap_or_else(|| pkg.repo_name.clone());\n    (owner, name)\n}\n\n/// Check if extraction is needed based on format and package type.\nfn needs_extraction(format: &str, pkg_type: &AquaPackageType) -> bool {\n    (!format.is_empty() && format != \"raw\")\n        || matches!(\n            pkg_type,\n            AquaPackageType::GithubArchive | AquaPackageType::GithubContent\n        )\n}\n\n/// Check if a platform is supported by the package's supported_envs.\n/// Returns true if supported, false if not.\nfn is_platform_supported(supported_envs: &[String], os: &str, arch: &str) -> bool {\n    if supported_envs.is_empty() {\n        return true;\n    }\n    let envs: HashSet<&str> = supported_envs.iter().map(|s| s.as_str()).collect();\n    let os_arch = format!(\"{os}/{arch}\");\n    let mut myself: HashSet<&str> = [\"all\", os, arch, os_arch.as_str()].into();\n    // Windows ARM64 can typically run AMD64 binaries via emulation\n    if os == \"windows\" && arch == \"arm64\" {\n        myself.insert(\"windows/amd64\");\n        myself.insert(\"amd64\");\n    }\n    !envs.is_disjoint(&myself)\n}\n\npub fn os() -> &'static str {\n    if cfg!(target_os = \"macos\") {\n        \"darwin\"\n    } else {\n        &OS\n    }\n}\n\npub fn arch() -> &'static str {\n    if cfg!(target_arch = \"x86_64\") {\n        \"amd64\"\n    } else if cfg!(target_arch = \"arm\") {\n        \"armv6l\"\n    } else if cfg!(target_arch = \"aarch64\") {\n        \"arm64\"\n    } else {\n        &ARCH\n    }\n}\n"
  },
  {
    "path": "src/backend/asdf.rs",
    "content": "use std::fmt::{Debug, Formatter};\nuse std::fs;\nuse std::hash::{Hash, Hasher};\nuse std::path::{Path, PathBuf};\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::external_plugin_cache::ExternalPluginCache;\nuse crate::backend::normalize_idiomatic_contents;\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\nuse crate::env_diff::{EnvDiff, EnvDiffOperation, EnvMap};\nuse crate::hash::hash_to_str;\nuse crate::install_context::InstallContext;\nuse crate::plugins::Script::{Download, ExecEnv, Install, ParseIdiomaticFile};\nuse crate::plugins::asdf_plugin::AsdfPlugin;\nuse crate::plugins::mise_plugin_toml::MisePluginToml;\nuse crate::plugins::{PluginType, Script, ScriptManager};\nuse crate::toolset::{ToolRequest, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{backend::Backend, plugins::PluginEnum, timeout};\nuse crate::{dirs, env, file};\nuse async_trait::async_trait;\nuse color_eyre::eyre::{Result, WrapErr, eyre};\nuse console::style;\nuse heck::ToKebabCase;\n\n/// This represents a plugin installed to ~/.local/share/mise/plugins\npub struct AsdfBackend {\n    pub ba: Arc<BackendArg>,\n    pub name: String,\n    pub plugin_path: PathBuf,\n    pub repo_url: Option<String>,\n    pub toml: MisePluginToml,\n    plugin: Arc<AsdfPlugin>,\n    plugin_enum: PluginEnum,\n    cache: ExternalPluginCache,\n    latest_stable_cache: CacheManager<Option<String>>,\n    alias_cache: CacheManager<Vec<(String, String)>>,\n    idiomatic_filename_cache: CacheManager<Vec<String>>,\n}\n\nimpl AsdfBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        let name = ba.tool_name.clone();\n        let plugin_path = dirs::PLUGINS.join(ba.short.to_kebab_case());\n        let plugin = AsdfPlugin::new(name.clone(), plugin_path.clone());\n        let mut toml_path = plugin_path.join(\"mise.plugin.toml\");\n        if plugin_path.join(\"rtx.plugin.toml\").exists() {\n            toml_path = plugin_path.join(\"rtx.plugin.toml\");\n        }\n        let toml = MisePluginToml::from_file(&toml_path).unwrap();\n        let plugin = Arc::new(plugin);\n        let plugin_enum = PluginEnum::Asdf(plugin.clone());\n        Self {\n            cache: ExternalPluginCache::default(),\n            latest_stable_cache: CacheManagerBuilder::new(\n                ba.cache_path.join(\"latest_stable.msgpack.z\"),\n            )\n            .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n            .with_fresh_file(plugin_path.clone())\n            .with_fresh_file(plugin_path.join(\"bin/latest-stable\"))\n            .build(),\n            alias_cache: CacheManagerBuilder::new(ba.cache_path.join(\"aliases.msgpack.z\"))\n                .with_fresh_file(plugin_path.clone())\n                .with_fresh_file(plugin_path.join(\"bin/list-aliases\"))\n                .build(),\n            idiomatic_filename_cache: CacheManagerBuilder::new(\n                ba.cache_path.join(\"idiomatic_filenames.msgpack.z\"),\n            )\n            .with_fresh_file(plugin_path.clone())\n            .with_fresh_file(plugin_path.join(\"bin/list-legacy-filenames\"))\n            .build(),\n            plugin_path,\n            plugin,\n            plugin_enum,\n            repo_url: None,\n            toml,\n            name,\n            ba: Arc::new(ba),\n        }\n    }\n\n    fn fetch_cached_idiomatic_file(&self, idiomatic_file: &Path) -> Result<Option<String>> {\n        let fp = self.idiomatic_cache_file_path(idiomatic_file);\n        if !fp.exists() || fp.metadata()?.modified()? < idiomatic_file.metadata()?.modified()? {\n            return Ok(None);\n        }\n\n        Ok(Some(fs::read_to_string(fp)?.trim().into()))\n    }\n\n    fn idiomatic_cache_file_path(&self, idiomatic_file: &Path) -> PathBuf {\n        self.ba\n            .cache_path\n            .join(\"idiomatic\")\n            .join(&self.name)\n            .join(hash_to_str(&idiomatic_file.to_string_lossy()))\n            .with_extension(\"txt\")\n    }\n\n    fn write_idiomatic_cache(&self, idiomatic_file: &Path, idiomatic_version: &str) -> Result<()> {\n        let fp = self.idiomatic_cache_file_path(idiomatic_file);\n        file::create_dir_all(fp.parent().unwrap())?;\n        file::write(fp, idiomatic_version)?;\n        Ok(())\n    }\n\n    async fn fetch_bin_paths(&self, config: &Arc<Config>, tv: &ToolVersion) -> Result<Vec<String>> {\n        let list_bin_paths = self.plugin_path.join(\"bin/list-bin-paths\");\n        let bin_paths = if matches!(tv.request, ToolRequest::System { .. }) {\n            Vec::new()\n        } else if list_bin_paths.exists() {\n            let sm = self.script_man_for_tv(config, tv).await?;\n            // TODO: find a way to enable this without deadlocking\n            // for (t, tv) in ts.list_current_installed_versions(config) {\n            //     if t.name == self.name {\n            //         continue;\n            //     }\n            //     for p in t.list_bin_paths(config, ts, &tv)? {\n            //         sm.prepend_path(p);\n            //     }\n            // }\n            let output = sm.cmd(&Script::ListBinPaths).read()?;\n            output\n                .split_whitespace()\n                .map(|f| {\n                    if f == \".\" {\n                        String::new()\n                    } else {\n                        f.to_string()\n                    }\n                })\n                .collect()\n        } else {\n            vec![\"bin\".into()]\n        };\n        Ok(bin_paths)\n    }\n    async fn fetch_exec_env(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> Result<EnvMap> {\n        let mut sm = self.script_man_for_tv(config, tv).await?;\n        for p in ts.list_paths(config).await {\n            sm.prepend_path(p);\n        }\n        let script = sm.get_script_path(&ExecEnv);\n        let dir = dirs::CWD.clone().unwrap_or_default();\n        let ed = EnvDiff::from_bash_script(&script, &dir, &sm.env, &Default::default())?;\n        let env = ed\n            .to_patches()\n            .into_iter()\n            .filter_map(|p| match p {\n                EnvDiffOperation::Add(key, value) => Some((key, value)),\n                EnvDiffOperation::Change(key, value) => Some((key, value)),\n                _ => None,\n            })\n            .collect();\n        Ok(env)\n    }\n\n    async fn script_man_for_tv(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<ScriptManager> {\n        let mut sm = self.plugin.script_man.clone();\n        for (key, value) in tv.request.options().opts_as_strings() {\n            let k = format!(\"RTX_TOOL_OPTS__{}\", key.to_uppercase());\n            sm = sm.with_env(k, value.clone());\n            let k = format!(\"MISE_TOOL_OPTS__{}\", key.to_uppercase());\n            sm = sm.with_env(k, value);\n        }\n        for (key, value) in tv.request.options().install_env {\n            sm = sm.with_env(key, value.clone());\n        }\n        if let Some(project_root) = &config.project_root {\n            let project_root = project_root.to_string_lossy().to_string();\n            sm = sm.with_env(\"RTX_PROJECT_ROOT\", project_root.clone());\n            sm = sm.with_env(\"MISE_PROJECT_ROOT\", project_root);\n        }\n        let install_type = match &tv.request {\n            ToolRequest::Version { .. } | ToolRequest::Prefix { .. } => \"version\",\n            ToolRequest::Ref { .. } => \"ref\",\n            ToolRequest::Path { .. } => \"path\",\n            ToolRequest::Sub { .. } => \"sub\",\n            ToolRequest::System { .. } => {\n                panic!(\"should not be called for system tool\")\n            }\n        };\n        let install_version = match &tv.request {\n            ToolRequest::Ref { ref_: v, .. } => v, // should not have \"ref:\" prefix\n            _ => &tv.version,\n        };\n        // add env vars from mise.toml files\n        for (key, value) in config.env().await? {\n            sm = sm.with_env(key, value.clone());\n        }\n        let install = tv.install_path().to_string_lossy().to_string();\n        let download = tv.download_path().to_string_lossy().to_string();\n        sm = sm\n            .with_env(\"ASDF_DOWNLOAD_PATH\", &download)\n            .with_env(\"ASDF_INSTALL_PATH\", &install)\n            .with_env(\"ASDF_INSTALL_TYPE\", install_type)\n            .with_env(\"ASDF_INSTALL_VERSION\", install_version)\n            .with_env(\"RTX_DOWNLOAD_PATH\", &download)\n            .with_env(\"RTX_INSTALL_PATH\", &install)\n            .with_env(\"RTX_INSTALL_TYPE\", install_type)\n            .with_env(\"RTX_INSTALL_VERSION\", install_version)\n            .with_env(\"MISE_DOWNLOAD_PATH\", download)\n            .with_env(\"MISE_INSTALL_PATH\", install)\n            .with_env(\"MISE_INSTALL_TYPE\", install_type)\n            .with_env(\"MISE_INSTALL_VERSION\", install_version);\n        Ok(sm)\n    }\n}\n\nimpl Eq for AsdfBackend {}\n\nimpl PartialEq for AsdfBackend {\n    fn eq(&self, other: &Self) -> bool {\n        self.name == other.name\n    }\n}\n\nimpl Hash for AsdfBackend {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.name.hash(state);\n    }\n}\n\n#[async_trait]\nimpl Backend for AsdfBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Asdf\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_plugin_type(&self) -> Option<PluginType> {\n        Some(PluginType::Asdf)\n    }\n\n    /// ASDF plugins handle their own downloads through plugin scripts.\n    /// Lockfile URLs are not applicable since installation is delegated to plugin scripts.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = self.plugin.fetch_remote_versions()?;\n        Ok(versions\n            .into_iter()\n            .map(|v| VersionInfo {\n                version: v,\n                ..Default::default()\n            })\n            .collect())\n    }\n\n    async fn latest_stable_version(&self, config: &Arc<Config>) -> Result<Option<String>> {\n        timeout::run_with_timeout_async(\n            || async {\n                if !self.plugin.has_latest_stable_script() {\n                    return self.latest_version(config, Some(\"latest\".into())).await;\n                }\n                self.latest_stable_cache\n                    .get_or_try_init(|| self.plugin.fetch_latest_stable())\n                    .wrap_err_with(|| {\n                        eyre!(\n                            \"Failed fetching latest stable version for plugin {}\",\n                            style(&self.name).blue().for_stderr(),\n                        )\n                    })\n                    .cloned()\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n    }\n\n    fn get_aliases(&self) -> Result<BTreeMap<String, String>> {\n        if let Some(data) = &self.toml.list_aliases.data {\n            return Ok(self.plugin.parse_aliases(data).into_iter().collect());\n        }\n        if !self.plugin.has_list_alias_script() {\n            return Ok(BTreeMap::new());\n        }\n        let aliases = self\n            .alias_cache\n            .get_or_try_init(|| self.plugin.fetch_aliases())\n            .wrap_err_with(|| {\n                eyre!(\n                    \"Failed fetching aliases for plugin {}\",\n                    style(&self.name).blue().for_stderr(),\n                )\n            })?\n            .iter()\n            .map(|(k, v)| (k.to_string(), v.to_string()))\n            .collect();\n        Ok(aliases)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        if let Some(data) = &self.toml.list_idiomatic_filenames.data {\n            return Ok(self.plugin.parse_idiomatic_filenames(data));\n        }\n        if !self.plugin.has_list_idiomatic_filenames_script() {\n            return Ok(vec![]);\n        }\n        self.idiomatic_filename_cache\n            .get_or_try_init(|| self.plugin.fetch_idiomatic_filenames())\n            .wrap_err_with(|| {\n                eyre!(\n                    \"Failed fetching idiomatic filenames for plugin {}\",\n                    style(&self.name).blue().for_stderr(),\n                )\n            })\n            .cloned()\n    }\n\n    async fn _parse_idiomatic_file(&self, idiomatic_file: &Path) -> Result<Vec<String>> {\n        if let Some(cached) = self.fetch_cached_idiomatic_file(idiomatic_file)? {\n            return Ok(cached.split_whitespace().map(|s| s.to_string()).collect());\n        }\n        trace!(\n            \"parsing idiomatic file: {}\",\n            idiomatic_file.to_string_lossy()\n        );\n        let script = ParseIdiomaticFile(idiomatic_file.to_string_lossy().into());\n        let idiomatic_version = match self.plugin.script_man.script_exists(&script) {\n            true => self.plugin.script_man.read(&script)?,\n            false => fs::read_to_string(idiomatic_file)?,\n        }\n        .to_string();\n        let idiomatic_version = normalize_idiomatic_contents(&idiomatic_version);\n\n        self.write_idiomatic_cache(idiomatic_file, &idiomatic_version)?;\n        if idiomatic_version.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(idiomatic_version\n            .split_whitespace()\n            .map(|s| s.to_string())\n            .collect())\n    }\n\n    fn plugin(&self) -> Option<&PluginEnum> {\n        Some(&self.plugin_enum)\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        let mut sm = self.script_man_for_tv(&ctx.config, &tv).await?;\n\n        for p in ctx.ts.list_paths(&ctx.config).await {\n            sm.prepend_path(p);\n        }\n\n        let run_script = |script| sm.run_by_line(script, ctx.pr.as_ref());\n\n        if sm.script_exists(&Download) {\n            ctx.pr.set_message(\"bin/download\".into());\n            run_script(&Download)?;\n        }\n        ctx.pr.set_message(\"bin/install\".into());\n        run_script(&Install)?;\n        file::remove_dir(&self.ba.downloads_path)?;\n\n        Ok(tv)\n    }\n\n    async fn uninstall_version_impl(\n        &self,\n        config: &Arc<Config>,\n        pr: &dyn SingleReport,\n        tv: &ToolVersion,\n    ) -> Result<()> {\n        if self.plugin_path.join(\"bin/uninstall\").exists() {\n            self.script_man_for_tv(config, tv)\n                .await?\n                .run_by_line(&Script::Uninstall, pr)?;\n        }\n        Ok(())\n    }\n\n    async fn list_bin_paths(&self, config: &Arc<Config>, tv: &ToolVersion) -> Result<Vec<PathBuf>> {\n        Ok(self\n            .cache\n            .list_bin_paths(config, self, tv, async || {\n                self.fetch_bin_paths(config, tv).await\n            })\n            .await?\n            .into_iter()\n            .map(|path| tv.install_path().join(path))\n            .collect())\n    }\n\n    async fn exec_env(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<EnvMap> {\n        let total_start = std::time::Instant::now();\n        if matches!(tv.request, ToolRequest::System { .. }) {\n            return Ok(BTreeMap::new());\n        }\n        if !self.plugin.script_man.script_exists(&ExecEnv) || *env::__MISE_SCRIPT {\n            // if the script does not exist, or we're already running from within a script,\n            // the second is to prevent infinite loops\n            return Ok(BTreeMap::new());\n        }\n        let res = self\n            .cache\n            .exec_env(config, self, tv, async || {\n                self.fetch_exec_env(config, ts, tv).await\n            })\n            .await;\n        trace!(\n            \"exec_env cache.get_or_try_init_async for {} finished in {}ms\",\n            self.name,\n            total_start.elapsed().as_millis()\n        );\n        res\n    }\n}\n\nimpl Debug for AsdfBackend {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"AsdfPlugin\")\n            .field(\"name\", &self.name)\n            .field(\"plugin_path\", &self.plugin_path)\n            .field(\"cache_path\", &self.ba.cache_path)\n            .field(\"downloads_path\", &self.ba.downloads_path)\n            .field(\"installs_path\", &self.ba.installs_path)\n            .field(\"repo_url\", &self.repo_url)\n            .finish()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_debug() {\n        let _config = Config::get().await.unwrap();\n        let plugin = AsdfBackend::from_arg(\"dummy\".into());\n        assert!(format!(\"{plugin:?}\").starts_with(\"AsdfPlugin { name: \\\"dummy\\\"\"));\n    }\n}\n"
  },
  {
    "path": "src/backend/asset_matcher.rs",
    "content": "//! Unified asset matching for backend tool installation\n//!\n//! This module provides a high-level `AssetMatcher` that uses platform heuristics\n//! to score and rank assets for finding the best download for the target platform.\n//!\n//! # Example\n//!\n//! ```ignore\n//! use crate::backend::asset_matcher::AssetMatcher;\n//!\n//! // Auto-detect best asset for a target platform\n//! let asset = AssetMatcher::new()\n//!     .for_target(&target)\n//!     .with_no_app(true) // optional: avoid .app bundles\n//!     .pick_from(&assets)?;\n//! ```\n\nuse eyre::Result;\nuse regex::Regex;\nuse std::sync::LazyLock;\n\nuse super::platform_target::PlatformTarget;\nuse super::static_helpers::get_filename_from_url;\nuse crate::file::TarFormat;\nuse crate::http::HTTP;\n\n// ========== Platform Detection Types (from asset_detector) ==========\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum AssetOs {\n    Linux,\n    Macos,\n    Windows,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum AssetArch {\n    X64,\n    Arm64,\n    X86,\n    Arm,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq)]\npub enum AssetLibc {\n    Gnu,\n    Musl,\n    Msvc,\n}\n\nimpl AssetOs {\n    pub fn matches_target(&self, target: &str) -> bool {\n        match self {\n            AssetOs::Linux => target == \"linux\",\n            AssetOs::Macos => target == \"macos\" || target == \"darwin\",\n            AssetOs::Windows => target == \"windows\",\n        }\n    }\n}\n\nimpl AssetArch {\n    pub fn matches_target(&self, target: &str) -> bool {\n        match self {\n            AssetArch::X64 => target == \"x86_64\" || target == \"amd64\" || target == \"x64\",\n            AssetArch::Arm64 => target == \"aarch64\" || target == \"arm64\",\n            AssetArch::X86 => target == \"x86\" || target == \"i386\" || target == \"i686\",\n            AssetArch::Arm => target == \"arm\",\n        }\n    }\n}\n\nimpl AssetLibc {\n    pub fn matches_target(&self, target: &str) -> bool {\n        match self {\n            AssetLibc::Gnu => target == \"gnu\",\n            AssetLibc::Musl => target == \"musl\",\n            AssetLibc::Msvc => target == \"msvc\",\n        }\n    }\n}\n\n/// Detected platform information from a URL\n#[derive(Debug, Clone)]\npub struct DetectedPlatform {\n    pub os: AssetOs,\n    pub arch: AssetArch,\n    #[allow(unused)]\n    pub libc: Option<AssetLibc>,\n}\n\nimpl DetectedPlatform {\n    /// Convert to mise's platform string format (e.g., \"linux-x64\", \"macos-arm64\")\n    pub fn to_platform_string(&self) -> String {\n        let os_str = match self.os {\n            AssetOs::Linux => \"linux\",\n            AssetOs::Macos => \"macos\",\n            AssetOs::Windows => \"windows\",\n        };\n\n        let arch_str = match self.arch {\n            AssetArch::X64 => \"x64\",\n            AssetArch::Arm64 => \"arm64\",\n            AssetArch::X86 => \"x86\",\n            AssetArch::Arm => \"arm\",\n        };\n\n        format!(\"{os_str}-{arch_str}\")\n    }\n}\n\n// Platform detection patterns\nstatic OS_PATTERNS: LazyLock<Vec<(AssetOs, Regex)>> = LazyLock::new(|| {\n    vec![\n        (\n            AssetOs::Linux,\n            Regex::new(r\"(?i)(?:\\b|_)(?:linux|ubuntu|debian|fedora|centos|rhel|alpine|arch)(?:\\b|_|32|64|-)\")\n                .unwrap(),\n        ),\n        (\n            AssetOs::Macos,\n            Regex::new(r\"(?i)(?:\\b|_)(?:darwin|mac(?:osx?)?|osx)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetOs::Windows,\n            Regex::new(r\"(?i)(?:\\b|_)(?:mingw-w64|win(?:32|64|dows)?)(?:\\b|_)\").unwrap(),\n        ),\n    ]\n});\n\nstatic ARCH_PATTERNS: LazyLock<Vec<(AssetArch, Regex)>> = LazyLock::new(|| {\n    vec![\n        (\n            AssetArch::X64,\n            Regex::new(r\"(?i)(?:\\b|_)(?:x86[_-]64|x64|amd64)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetArch::Arm64,\n            Regex::new(r\"(?i)(?:\\b|_)(?:aarch_?64|arm_?64)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetArch::X86,\n            Regex::new(r\"(?i)(?:\\b|_)(?:x86|i386|i686)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetArch::Arm,\n            Regex::new(r\"(?i)(?:\\b|_)arm(?:v[0-7])?(?:\\b|_)\").unwrap(),\n        ),\n    ]\n});\n\nstatic LIBC_PATTERNS: LazyLock<Vec<(AssetLibc, Regex)>> = LazyLock::new(|| {\n    vec![\n        (\n            AssetLibc::Msvc,\n            Regex::new(r\"(?i)(?:\\b|_)(?:msvc)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetLibc::Gnu,\n            Regex::new(r\"(?i)(?:\\b|_)(?:gnu|glibc)(?:\\b|_)\").unwrap(),\n        ),\n        (\n            AssetLibc::Musl,\n            Regex::new(r\"(?i)(?:\\b|_)(?:musl)(?:\\b|_)\").unwrap(),\n        ),\n    ]\n});\n\n// ========== AssetPicker (from asset_detector) ==========\n\n/// Automatically detects the best asset for the current platform\npub struct AssetPicker {\n    target_os: String,\n    target_arch: String,\n    target_libc: String,\n    no_app: bool,\n}\n\nimpl AssetPicker {\n    /// Create an AssetPicker with an explicit libc setting.\n    /// When no explicit libc is provided, defaults to the platform's standard libc\n    /// (msvc for Windows, gnu for Linux/other). The caller is responsible for passing\n    /// the correct libc qualifier from PlatformTarget — this avoids polluting\n    /// cross-platform lockfile entries with the current system's libc.\n    pub fn with_libc(target_os: String, target_arch: String, libc: Option<String>) -> Self {\n        let target_libc = libc.unwrap_or_else(|| {\n            if target_os == \"windows\" {\n                \"msvc\".to_string()\n            } else {\n                \"gnu\".to_string()\n            }\n        });\n\n        Self {\n            target_os,\n            target_arch,\n            target_libc,\n            no_app: false,\n        }\n    }\n\n    /// Set whether to avoid .app bundles (prefer standalone CLI tools)\n    pub fn with_no_app(mut self, no_app: bool) -> Self {\n        self.no_app = no_app;\n        self\n    }\n\n    /// Picks the best asset from available options\n    pub fn pick_best_asset(&self, assets: &[String]) -> Option<String> {\n        let mut scored_assets = self.score_all_assets(assets);\n        scored_assets.sort_by(|a, b| b.0.cmp(&a.0));\n        scored_assets\n            .first()\n            .filter(|(score, _)| *score > 0)\n            .map(|(_, asset)| asset.clone())\n    }\n\n    /// Picks the best provenance file for the current platform from available assets.\n    /// Returns the provenance file that best matches the target OS and architecture.\n    pub fn pick_best_provenance(&self, assets: &[String]) -> Option<String> {\n        // Filter to only provenance files\n        let provenance_assets: Vec<&String> = assets\n            .iter()\n            .filter(|a| {\n                let name = a.to_lowercase();\n                name.contains(\".intoto.jsonl\")\n                    || name.contains(\"provenance\")\n                    || name.ends_with(\".attestation\")\n            })\n            .collect();\n\n        if provenance_assets.is_empty() {\n            return None;\n        }\n\n        // Score by platform match only (no format/build penalties)\n        let mut scored: Vec<(i32, &String)> = provenance_assets\n            .into_iter()\n            .map(|asset| {\n                let score = self.score_os_match(asset) + self.score_arch_match(asset);\n                (score, asset)\n            })\n            .collect();\n\n        scored.sort_by(|a, b| b.0.cmp(&a.0));\n        scored.first().map(|(_, asset)| (*asset).clone())\n    }\n\n    fn score_all_assets(&self, assets: &[String]) -> Vec<(i32, String)> {\n        assets\n            .iter()\n            .map(|asset| (self.score_asset(asset), asset.clone()))\n            .collect()\n    }\n\n    /// Scores a single asset based on platform compatibility\n    pub fn score_asset(&self, asset: &str) -> i32 {\n        let mut score = 0;\n        score += self.score_os_match(asset);\n        score += self.score_arch_match(asset);\n        if self.target_os == \"linux\" || self.target_os == \"windows\" {\n            score += self.score_libc_match(asset);\n        }\n        score += self.score_format_preferences(asset);\n        score += self.score_build_penalties(asset);\n        score\n    }\n\n    fn score_os_match(&self, asset: &str) -> i32 {\n        for (os, pattern) in OS_PATTERNS.iter() {\n            if pattern.is_match(asset) {\n                return if os.matches_target(&self.target_os) {\n                    100\n                } else {\n                    -100\n                };\n            }\n        }\n        // Check for Windows-specific file extensions (.msi, .exe)\n        // These should be penalized on non-Windows platforms\n        // See: https://github.com/jdx/mise/discussions/7837\n        let lower = asset.to_lowercase();\n        if (lower.ends_with(\".msi\") || lower.ends_with(\".exe\")) && self.target_os != \"windows\" {\n            return -100;\n        }\n        // On Windows, these are valid but don't need a boost - let other\n        // factors (arch match, format preferences) determine the best asset\n        0\n    }\n\n    fn score_arch_match(&self, asset: &str) -> i32 {\n        for (arch, pattern) in ARCH_PATTERNS.iter() {\n            if pattern.is_match(asset) {\n                return if arch.matches_target(&self.target_arch) {\n                    50\n                } else {\n                    // Architecture mismatch should be disqualifying - don't silently\n                    // fall back to incompatible architectures (e.g., x86_64 when arm64\n                    // is requested). See: https://github.com/jdx/mise/discussions/7628\n                    -150\n                };\n            }\n        }\n        0\n    }\n\n    fn score_libc_match(&self, asset: &str) -> i32 {\n        for (libc, pattern) in LIBC_PATTERNS.iter() {\n            if pattern.is_match(asset) {\n                return if libc.matches_target(&self.target_libc) {\n                    25\n                } else {\n                    -10\n                };\n            }\n        }\n        0\n    }\n\n    fn score_format_preferences(&self, asset: &str) -> i32 {\n        let format = TarFormat::from_file_name(asset);\n\n        if format == TarFormat::Zip {\n            if self.target_os == \"windows\" {\n                return 15;\n            } else {\n                return 5;\n            }\n        }\n\n        if format.is_archive() { 10 } else { 0 }\n    }\n\n    fn score_build_penalties(&self, asset: &str) -> i32 {\n        let mut penalty = 0;\n        let asset = asset.to_lowercase();\n        if asset.contains(\"debug\") || asset.contains(\"test\") {\n            penalty -= 20;\n        }\n        if asset.ends_with(\".artifactbundle\") || asset.contains(\".artifactbundle.\") {\n            penalty -= 30;\n        }\n        // Penalize macOS .app bundles on non-macOS platforms\n        if asset.contains(\".app.\") && self.target_os != \"macos\" {\n            penalty -= 100;\n        }\n        // Penalize .app bundles if no_app option is set\n        // .app bundles often contain Xcode extensions or GUI apps, not CLI tools\n        if self.no_app && asset.contains(\".app.\") {\n            penalty -= 50;\n        }\n\n        // Penalize .vsix files\n        if asset.ends_with(\".vsix\") {\n            penalty -= 100;\n        }\n\n        // Penalize metadata/checksum/signature files\n        if asset.ends_with(\".asc\")\n            || asset.ends_with(\".sig\")\n            || asset.ends_with(\".sign\")\n            || asset.ends_with(\".sha256\")\n            || asset.ends_with(\".sha512\")\n            || asset.ends_with(\".sha1\")\n            || asset.ends_with(\".md5\")\n            || asset.ends_with(\".json\")\n            || asset.ends_with(\".txt\")\n            || asset.ends_with(\".xml\")\n            || asset.ends_with(\".sbom\")\n            || asset.ends_with(\".spdx\")\n            || asset.ends_with(\".intoto\")\n            || asset.ends_with(\".attestation\")\n            || asset.ends_with(\".pem\")\n            || asset.ends_with(\".crt\")\n            || asset.ends_with(\".key\")\n            || asset.ends_with(\".pub\")\n            || asset.ends_with(\".manifest\")\n        {\n            penalty -= 100;\n        }\n\n        // Penalize common non-binary filenames\n        if asset.contains(\"release-info\") || asset.contains(\"changelog\") {\n            penalty -= 50;\n        }\n\n        penalty\n    }\n}\n\n/// Detects platform information from a URL\npub fn detect_platform_from_url(url: &str) -> Option<DetectedPlatform> {\n    let mut detected_os = None;\n    let mut detected_arch = None;\n    let mut detected_libc = None;\n\n    let filename = get_filename_from_url(url);\n\n    for (os, pattern) in OS_PATTERNS.iter() {\n        if pattern.is_match(&filename) {\n            detected_os = Some(*os);\n            break;\n        }\n    }\n\n    for (arch, pattern) in ARCH_PATTERNS.iter() {\n        if pattern.is_match(&filename) {\n            detected_arch = Some(*arch);\n            break;\n        }\n    }\n\n    if detected_os == Some(AssetOs::Linux) || detected_os == Some(AssetOs::Windows) {\n        for (libc, pattern) in LIBC_PATTERNS.iter() {\n            if pattern.is_match(&filename) {\n                detected_libc = Some(*libc);\n                break;\n            }\n        }\n    }\n\n    if let (Some(os), Some(arch)) = (detected_os, detected_arch) {\n        Some(DetectedPlatform {\n            os,\n            arch,\n            libc: detected_libc,\n        })\n    } else {\n        None\n    }\n}\n\n/// Common checksum file extensions\nstatic CHECKSUM_EXTENSIONS: LazyLock<Vec<&'static str>> = LazyLock::new(|| {\n    vec![\n        \".sha256\",\n        \".sha256sum\",\n        \".sha256sums\",\n        \".SHA256\",\n        \".SHA256SUM\",\n        \".SHA256SUMS\",\n        \".sha512\",\n        \".sha512sum\",\n        \".sha512sums\",\n        \".SHA512\",\n        \".SHA512SUM\",\n        \".SHA512SUMS\",\n        \".md5\",\n        \".md5sum\",\n        \".checksums\",\n        \".CHECKSUMS\",\n    ]\n});\n\n/// Common checksum filename patterns\nstatic CHECKSUM_PATTERNS: LazyLock<Vec<Regex>> = LazyLock::new(|| {\n    vec![\n        Regex::new(r\"(?i)^sha256sums?\\.txt$\").unwrap(),\n        Regex::new(r\"(?i)^sha512sums?\\.txt$\").unwrap(),\n        Regex::new(r\"(?i)^checksums?\\.txt$\").unwrap(),\n        Regex::new(r\"(?i)^SHASUMS\").unwrap(),\n        Regex::new(r\"(?i)checksums?\\.sha256$\").unwrap(),\n    ]\n});\n\n/// Represents a matched asset with metadata\n#[derive(Debug, Clone)]\npub struct MatchedAsset {\n    /// The asset name/filename\n    pub name: String,\n}\n\n/// Builder for matching assets\n#[derive(Debug, Default)]\npub struct AssetMatcher {\n    /// Target OS (e.g., \"linux\", \"macos\", \"windows\")\n    target_os: Option<String>,\n    /// Target architecture (e.g., \"x86_64\", \"aarch64\")\n    target_arch: Option<String>,\n    /// Target libc variant (e.g., \"gnu\", \"musl\")\n    target_libc: Option<String>,\n    /// Whether to avoid .app bundles\n    no_app: bool,\n}\n\nimpl AssetMatcher {\n    /// Create a new AssetMatcher with default settings\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Configure for a specific target platform\n    pub fn for_target(mut self, target: &PlatformTarget) -> Self {\n        self.target_os = Some(target.os_name().to_string());\n        self.target_arch = Some(target.arch_name().to_string());\n        self.target_libc = target.qualifier().map(|s| s.to_string());\n        self\n    }\n\n    /// Set whether to avoid .app bundles (prefer standalone CLI tools)\n    pub fn with_no_app(mut self, no_app: bool) -> Self {\n        self.no_app = no_app;\n        self\n    }\n\n    /// Pick the best matching asset from a list of names\n    pub fn pick_from(&self, assets: &[String]) -> Result<MatchedAsset> {\n        self.match_by_auto_detection(assets)\n    }\n\n    /// Find checksum file for a given asset\n    pub fn find_checksum_for(&self, asset_name: &str, assets: &[String]) -> Option<String> {\n        let base_name = asset_name\n            .trim_end_matches(\".tar.gz\")\n            .trim_end_matches(\".tar.xz\")\n            .trim_end_matches(\".tar.bz2\")\n            .trim_end_matches(\".zip\")\n            .trim_end_matches(\".tgz\");\n\n        // Try exact match with checksum extension\n        for ext in CHECKSUM_EXTENSIONS.iter() {\n            let checksum_name = format!(\"{asset_name}{ext}\");\n            if assets.iter().any(|a| a == &checksum_name) {\n                return Some(checksum_name);\n            }\n            let checksum_name = format!(\"{base_name}{ext}\");\n            if assets.iter().any(|a| a == &checksum_name) {\n                return Some(checksum_name);\n            }\n        }\n\n        // Try common checksum file patterns\n        for pattern in CHECKSUM_PATTERNS.iter() {\n            for asset in assets {\n                if pattern.is_match(asset) {\n                    return Some(asset.clone());\n                }\n            }\n        }\n\n        None\n    }\n\n    // ========== Internal Methods ==========\n\n    fn create_picker(&self) -> Option<AssetPicker> {\n        let os = self.target_os.as_ref()?;\n        let arch = self.target_arch.as_ref()?;\n        Some(\n            AssetPicker::with_libc(os.clone(), arch.clone(), self.target_libc.clone())\n                .with_no_app(self.no_app),\n        )\n    }\n\n    fn match_by_auto_detection(&self, assets: &[String]) -> Result<MatchedAsset> {\n        let picker = self\n            .create_picker()\n            .ok_or_else(|| eyre::eyre!(\"Target OS and arch must be set for auto-detection\"))?;\n\n        let best = picker.pick_best_asset(assets).ok_or_else(|| {\n            let os = self.target_os.as_deref().unwrap_or(\"unknown\");\n            let arch = self.target_arch.as_deref().unwrap_or(\"unknown\");\n            eyre::eyre!(\n                \"No matching asset found for platform {}-{}\\nAvailable assets:\\n{}\",\n                os,\n                arch,\n                assets.join(\"\\n\")\n            )\n        })?;\n\n        Ok(MatchedAsset { name: best })\n    }\n}\n\n// ========== Checksum Fetching Helpers ==========\n\n/// Represents an asset with its download URL\n#[derive(Debug, Clone)]\npub struct Asset {\n    /// The asset filename\n    pub name: String,\n    /// The download URL for the asset\n    pub url: String,\n}\n\nimpl Asset {\n    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {\n        Self {\n            name: name.into(),\n            url: url.into(),\n        }\n    }\n}\n\n/// Result of a checksum lookup\n#[derive(Debug, Clone)]\npub struct ChecksumResult {\n    /// Algorithm used (sha256, sha512, md5, blake3)\n    pub algorithm: String,\n    /// The hash value\n    pub hash: String,\n    /// Which checksum file this came from\n    pub source_file: String,\n}\n\nimpl ChecksumResult {\n    /// Format as \"algorithm:hash\" string for verification\n    pub fn to_string_formatted(&self) -> String {\n        format!(\"{}:{}\", self.algorithm, self.hash)\n    }\n}\n\n/// Checksum file fetcher that finds and parses checksums from release assets\npub struct ChecksumFetcher<'a> {\n    assets: &'a [Asset],\n}\n\nimpl<'a> ChecksumFetcher<'a> {\n    /// Create a new checksum fetcher with the given assets\n    pub fn new(assets: &'a [Asset]) -> Self {\n        Self { assets }\n    }\n\n    /// Find and fetch the checksum for a specific asset\n    ///\n    /// This method:\n    /// 1. Finds a checksum file that matches the asset name\n    /// 2. Fetches the checksum file\n    /// 3. Parses it to extract the checksum for the target file\n    ///\n    /// Returns None if no checksum file is found or parsing fails.\n    pub async fn fetch_checksum_for(&self, asset_name: &str) -> Option<ChecksumResult> {\n        let asset_names: Vec<String> = self.assets.iter().map(|a| a.name.clone()).collect();\n        let matcher = AssetMatcher::new();\n\n        // First try to find an asset-specific checksum file (e.g., file.tar.gz.sha256)\n        if let Some(checksum_filename) = matcher.find_checksum_for(asset_name, &asset_names)\n            && let Some(checksum_asset) = self.assets.iter().find(|a| a.name == checksum_filename)\n            && let Some(result) = self\n                .fetch_and_parse_checksum(&checksum_asset.url, &checksum_filename, asset_name)\n                .await\n        {\n            return Some(result);\n        }\n\n        // Try common global checksum files by exact name match first\n        let global_patterns = [\n            \"checksums.txt\",\n            \"SHA256SUMS\",\n            \"SHASUMS256.txt\",\n            \"sha256sums.txt\",\n        ];\n        for pattern in global_patterns {\n            if let Some(checksum_asset) = self\n                .assets\n                .iter()\n                .find(|a| a.name.eq_ignore_ascii_case(pattern))\n                && let Some(result) = self\n                    .fetch_and_parse_checksum(&checksum_asset.url, &checksum_asset.name, asset_name)\n                    .await\n            {\n                return Some(result);\n            }\n        }\n\n        // Last resort: try any file with \"checksum\" in the name\n        if let Some(checksum_asset) = self\n            .assets\n            .iter()\n            .find(|a| a.name.to_lowercase().contains(\"checksum\"))\n            && let Some(result) = self\n                .fetch_and_parse_checksum(&checksum_asset.url, &checksum_asset.name, asset_name)\n                .await\n        {\n            return Some(result);\n        }\n\n        None\n    }\n\n    /// Fetch a checksum file and parse it for the target asset\n    async fn fetch_and_parse_checksum(\n        &self,\n        url: &str,\n        checksum_filename: &str,\n        target_asset: &str,\n    ) -> Option<ChecksumResult> {\n        let content = match HTTP.get_text(url).await {\n            Ok(c) => c,\n            Err(e) => {\n                debug!(\"Failed to fetch checksum file {}: {}\", url, e);\n                return None;\n            }\n        };\n\n        // Detect algorithm from filename\n        let algorithm = detect_checksum_algorithm(checksum_filename);\n\n        // Try to parse the checksum\n        parse_checksum_content(&content, target_asset, &algorithm, checksum_filename)\n    }\n}\n\n/// Detect the checksum algorithm from the filename\nfn detect_checksum_algorithm(filename: &str) -> String {\n    let lower = filename.to_lowercase();\n    if lower.contains(\"sha512\") || lower.ends_with(\".sha512\") || lower.ends_with(\".sha512sum\") {\n        \"sha512\".to_string()\n    } else if lower.contains(\"md5\") || lower.ends_with(\".md5\") || lower.ends_with(\".md5sum\") {\n        \"md5\".to_string()\n    } else if lower.contains(\"blake3\") || lower.ends_with(\".b3\") {\n        \"blake3\".to_string()\n    } else {\n        // Default to sha256 (most common)\n        \"sha256\".to_string()\n    }\n}\n\n/// Parse checksum content and extract the hash for a specific file\nfn parse_checksum_content(\n    content: &str,\n    target_file: &str,\n    algorithm: &str,\n    source_file: &str,\n) -> Option<ChecksumResult> {\n    let trimmed = content.trim();\n\n    // Check if this looks like a multi-line SHASUMS file (has lines with two parts)\n    let is_shasums_format = trimmed.lines().any(|line| {\n        let parts: Vec<&str> = line.split_whitespace().collect();\n        parts.len() >= 2\n    });\n\n    if is_shasums_format {\n        // Try standard SHASUMS format: \"<hash>  <filename>\" or \"<hash> *<filename>\"\n        // Parse manually to avoid panic from hash::parse_shasums\n        for line in trimmed.lines() {\n            let mut parts = line.split_whitespace();\n            if let (Some(hash_str), Some(filename)) = (parts.next(), parts.next()) {\n                // Strip leading * or . from filename if present (some formats use this)\n                let clean_filename = filename.trim_start_matches(['*', '.']);\n                if (clean_filename == target_file || filename == target_file)\n                    && is_valid_hash(hash_str, algorithm)\n                {\n                    return Some(ChecksumResult {\n                        algorithm: algorithm.to_string(),\n                        hash: hash_str.to_string(),\n                        source_file: source_file.to_string(),\n                    });\n                }\n            }\n        }\n        // Target file not found in SHASUMS file - return None, don't fall through\n        return None;\n    }\n\n    // Only for single-file checksum (e.g., file.tar.gz.sha256), extract just the hash\n    // Format is typically \"<hash>\" or \"<hash>  <filename>\"\n    if let Some(first_word) = trimmed.split_whitespace().next() {\n        // Validate it looks like a hash (hex string of appropriate length)\n        if is_valid_hash(first_word, algorithm) {\n            return Some(ChecksumResult {\n                algorithm: algorithm.to_string(),\n                hash: first_word.to_string(),\n                source_file: source_file.to_string(),\n            });\n        }\n    }\n\n    None\n}\n\n/// Check if a string looks like a valid hash for the given algorithm\nfn is_valid_hash(s: &str, algorithm: &str) -> bool {\n    let expected_len = match algorithm {\n        \"sha256\" => 64,\n        \"sha512\" => 128,\n        \"md5\" => 32,\n        \"blake3\" => 64,\n        _ => return s.len() >= 32, // At least 128 bits\n    };\n    s.len() == expected_len && s.chars().all(|c| c.is_ascii_hexdigit())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn test_assets() -> Vec<String> {\n        vec![\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-linux-aarch64.tar.gz\".to_string(),\n            \"tool-1.0.0-darwin-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-darwin-arm64.tar.gz\".to_string(),\n            \"tool-1.0.0-windows-x86_64.zip\".to_string(),\n            \"tool-1.0.0-linux-x86_64.tar.gz.sha256\".to_string(),\n            \"checksums.txt\".to_string(),\n        ]\n    }\n\n    #[test]\n    fn test_find_checksum() {\n        let matcher = AssetMatcher::new();\n        let checksum = matcher.find_checksum_for(\"tool-1.0.0-linux-x86_64.tar.gz\", &test_assets());\n        assert_eq!(\n            checksum,\n            Some(\"tool-1.0.0-linux-x86_64.tar.gz.sha256\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_find_checksum_global() {\n        let matcher = AssetMatcher::new();\n        let assets = vec![\"tool-1.0.0.tar.gz\".to_string(), \"checksums.txt\".to_string()];\n        let checksum = matcher.find_checksum_for(\"tool-1.0.0.tar.gz\", &assets);\n        assert_eq!(checksum, Some(\"checksums.txt\".to_string()));\n    }\n\n    // ========== Checksum Helper Tests ==========\n\n    #[test]\n    fn test_detect_checksum_algorithm() {\n        assert_eq!(detect_checksum_algorithm(\"SHA256SUMS\"), \"sha256\");\n        assert_eq!(detect_checksum_algorithm(\"file.sha256\"), \"sha256\");\n        assert_eq!(detect_checksum_algorithm(\"sha256sums.txt\"), \"sha256\");\n        assert_eq!(detect_checksum_algorithm(\"SHA512SUMS\"), \"sha512\");\n        assert_eq!(detect_checksum_algorithm(\"file.sha512\"), \"sha512\");\n        assert_eq!(detect_checksum_algorithm(\"file.md5\"), \"md5\");\n        assert_eq!(detect_checksum_algorithm(\"MD5SUMS\"), \"md5\");\n        assert_eq!(detect_checksum_algorithm(\"checksums.b3\"), \"blake3\");\n        assert_eq!(detect_checksum_algorithm(\"checksums.txt\"), \"sha256\"); // default\n    }\n\n    #[test]\n    fn test_is_valid_hash() {\n        // SHA256 (64 chars)\n        assert!(is_valid_hash(\n            \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n            \"sha256\"\n        ));\n        assert!(!is_valid_hash(\"e3b0c44298fc1c149afbf4c8996fb924\", \"sha256\")); // too short\n\n        // SHA512 (128 chars)\n        assert!(is_valid_hash(\n            \"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e\",\n            \"sha512\"\n        ));\n\n        // MD5 (32 chars)\n        assert!(is_valid_hash(\"d41d8cd98f00b204e9800998ecf8427e\", \"md5\"));\n        assert!(!is_valid_hash(\"d41d8cd98f00b204\", \"md5\")); // too short\n\n        // Invalid characters\n        assert!(!is_valid_hash(\n            \"g3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n            \"sha256\"\n        ));\n    }\n\n    #[test]\n    fn test_parse_checksum_content_shasums_format() {\n        let content = r#\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  tool-1.0.0-linux-x64.tar.gz\nabc123def456abc123def456abc123def456abc123def456abc123def456abcd  tool-1.0.0-darwin-arm64.tar.gz\"#;\n\n        let result = parse_checksum_content(\n            content,\n            \"tool-1.0.0-linux-x64.tar.gz\",\n            \"sha256\",\n            \"SHA256SUMS\",\n        );\n\n        assert!(result.is_some());\n        let r = result.unwrap();\n        assert_eq!(r.algorithm, \"sha256\");\n        assert_eq!(\n            r.hash,\n            \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n        );\n        assert_eq!(r.source_file, \"SHA256SUMS\");\n    }\n\n    #[test]\n    fn test_parse_checksum_content_single_file() {\n        let content = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\n        let result = parse_checksum_content(\n            content,\n            \"tool-1.0.0-linux-x64.tar.gz\",\n            \"sha256\",\n            \"tool-1.0.0-linux-x64.tar.gz.sha256\",\n        );\n\n        assert!(result.is_some());\n        let r = result.unwrap();\n        assert_eq!(r.algorithm, \"sha256\");\n        assert_eq!(\n            r.hash,\n            \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n        );\n    }\n\n    #[test]\n    fn test_parse_checksum_content_with_filename_suffix() {\n        // Checksum file with format: \"<hash>  filename\" should match the filename\n        let content =\n            \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  tool.tar.gz\";\n\n        // Should return the hash when target matches the filename\n        let result = parse_checksum_content(content, \"tool.tar.gz\", \"sha256\", \"tool.sha256\");\n        assert!(result.is_some());\n        let r = result.unwrap();\n        assert_eq!(\n            r.hash,\n            \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n        );\n\n        // Should return None when target doesn't match the filename\n        let result = parse_checksum_content(content, \"other-file.tar.gz\", \"sha256\", \"tool.sha256\");\n        assert!(\n            result.is_none(),\n            \"Should not return hash for wrong target file\"\n        );\n    }\n\n    #[test]\n    fn test_checksum_result_format() {\n        let result = ChecksumResult {\n            algorithm: \"sha256\".to_string(),\n            hash: \"abc123\".to_string(),\n            source_file: \"checksums.txt\".to_string(),\n        };\n\n        assert_eq!(result.to_string_formatted(), \"sha256:abc123\");\n    }\n\n    #[test]\n    fn test_asset_creation() {\n        let asset = Asset::new(\"file.tar.gz\", \"https://example.com/file.tar.gz\");\n        assert_eq!(asset.name, \"file.tar.gz\");\n        assert_eq!(asset.url, \"https://example.com/file.tar.gz\");\n    }\n\n    // ========== Platform Detection Tests ==========\n\n    #[test]\n    fn test_asset_picker_functionality() {\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-darwin-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-windows-x86_64.zip\".to_string(),\n        ];\n\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(picked, \"tool-1.0.0-linux-x86_64.tar.gz\");\n    }\n\n    #[test]\n    fn test_asset_picker_functionality_mixed() {\n        // mixed archive/binary formats like in babs/multiping\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64.xz\".to_string(),\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-darwin-x86_64.xz\".to_string(),\n            \"tool-1.0.0-darwin-aarch64.xz\".to_string(),\n            \"tool-1.0.0-mingw-w64-x86_64.zip\".to_string(),\n        ];\n\n        let picked = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None)\n            .pick_best_asset(&assets)\n            .unwrap();\n        assert_eq!(picked, \"tool-1.0.0-linux-x86_64.tar.gz\");\n\n        let picked = AssetPicker::with_libc(\"macos\".to_string(), \"aarch64\".to_string(), None)\n            .pick_best_asset(&assets)\n            .unwrap();\n        assert_eq!(picked, \"tool-1.0.0-darwin-aarch64.xz\");\n\n        let picked = AssetPicker::with_libc(\"windows\".to_string(), \"x86_64\".to_string(), None)\n            .pick_best_asset(&assets)\n            .unwrap();\n        assert_eq!(picked, \"tool-1.0.0-mingw-w64-x86_64.zip\");\n    }\n\n    #[test]\n    fn test_asset_scoring() {\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n\n        let score_linux = picker.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz\");\n        let score_windows = picker.score_asset(\"tool-1.0.0-windows-x86_64.zip\");\n        let score_linux_arm = picker.score_asset(\"tool-1.0.0-linux-arm64.tar.gz\");\n\n        assert!(\n            score_linux > score_windows,\n            \"Linux should score higher than Windows\"\n        );\n        assert!(\n            score_linux > score_linux_arm,\n            \"x86_64 should score higher than arm64\"\n        );\n        // Architecture mismatch should result in negative score\n        assert!(\n            score_linux_arm < 0,\n            \"Architecture mismatch should be negative, got {}\",\n            score_linux_arm\n        );\n    }\n\n    #[test]\n    fn test_archive_preference() {\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64\".to_string(),\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n        ];\n\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(picked, \"tool-1.0.0-linux-x86_64.tar.gz\");\n    }\n\n    #[test]\n    fn test_platform_detection_from_url() {\n        // Test Node.js URL\n        let url = \"https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\";\n        let platform = detect_platform_from_url(url).unwrap();\n        assert_eq!(platform.os, AssetOs::Macos);\n        assert_eq!(platform.arch, AssetArch::Arm64);\n        assert_eq!(platform.to_platform_string(), \"macos-arm64\");\n\n        // Test Linux x64 URL\n        let url = \"https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz\";\n        let platform = detect_platform_from_url(url).unwrap();\n        assert_eq!(platform.os, AssetOs::Linux);\n        assert_eq!(platform.arch, AssetArch::X64);\n        assert_eq!(platform.libc, Some(AssetLibc::Musl));\n        assert_eq!(platform.to_platform_string(), \"linux-x64\");\n\n        // Test Windows URL\n        let url =\n            \"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_windows_amd64.zip\";\n        let platform = detect_platform_from_url(url).unwrap();\n        assert_eq!(platform.os, AssetOs::Windows);\n        assert_eq!(platform.arch, AssetArch::X64);\n        assert_eq!(platform.to_platform_string(), \"windows-x64\");\n\n        // Test URL without platform info\n        let url = \"https://example.com/generic-tool.tar.gz\";\n        let platform = detect_platform_from_url(url);\n        assert!(platform.is_none());\n    }\n\n    #[test]\n    fn test_platform_string_conversion() {\n        let platform = DetectedPlatform {\n            os: AssetOs::Linux,\n            arch: AssetArch::X64,\n            libc: Some(AssetLibc::Gnu),\n        };\n        assert_eq!(platform.to_platform_string(), \"linux-x64\");\n\n        let platform = DetectedPlatform {\n            os: AssetOs::Macos,\n            arch: AssetArch::Arm64,\n            libc: None,\n        };\n        assert_eq!(platform.to_platform_string(), \"macos-arm64\");\n\n        let platform = DetectedPlatform {\n            os: AssetOs::Windows,\n            arch: AssetArch::X86,\n            libc: None,\n        };\n        assert_eq!(platform.to_platform_string(), \"windows-x86\");\n    }\n\n    #[test]\n    fn test_windows_msvc_preference() {\n        let qsv_assets = vec![\n            \"qsv-8.1.1-x86_64-pc-windows-gnu.zip\".to_string(),\n            \"qsv-8.1.1-x86_64-pc-windows-msvc.zip\".to_string(),\n        ];\n\n        let picker = AssetPicker::with_libc(\"windows\".to_string(), \"x86_64\".to_string(), None);\n        let picked = picker.pick_best_asset(&qsv_assets).unwrap();\n        assert_eq!(picked, \"qsv-8.1.1-x86_64-pc-windows-msvc.zip\");\n    }\n\n    #[test]\n    fn test_for_target_with_libc_qualifier() {\n        use crate::backend::platform_target::PlatformTarget;\n        use crate::platform::Platform;\n\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64-gnu.tar.gz\".to_string(),\n            \"tool-1.0.0-linux-x86_64-musl.tar.gz\".to_string(),\n        ];\n\n        // Test with musl qualifier\n        let platform = Platform::parse(\"linux-x64-musl\").unwrap();\n        let target = PlatformTarget::new(platform);\n        let result = AssetMatcher::new()\n            .for_target(&target)\n            .pick_from(&assets)\n            .unwrap();\n        assert_eq!(result.name, \"tool-1.0.0-linux-x86_64-musl.tar.gz\");\n\n        // Test with gnu qualifier\n        let platform = Platform::parse(\"linux-x64-gnu\").unwrap();\n        let target = PlatformTarget::new(platform);\n        let result = AssetMatcher::new()\n            .for_target(&target)\n            .pick_from(&assets)\n            .unwrap();\n        assert_eq!(result.name, \"tool-1.0.0-linux-x86_64-gnu.tar.gz\");\n    }\n\n    #[test]\n    fn test_parse_checksum_content_returns_none_for_missing_file() {\n        // SHASUMS file that doesn't contain the target file\n        let content = r#\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  tool-linux.tar.gz\nabc123def456abc123def456abc123def456abc123def456abc123def456abcd  tool-darwin.tar.gz\"#;\n\n        // Request checksum for a file that's not in the SHASUMS\n        let result = parse_checksum_content(\n            content,\n            \"tool-windows.tar.gz\", // Not in the file\n            \"sha256\",\n            \"SHA256SUMS\",\n        );\n\n        // Should return None, not the first hash\n        assert!(\n            result.is_none(),\n            \"Should return None when target file is not in SHASUMS\"\n        );\n    }\n    #[test]\n    fn test_zip_scoring() {\n        // Test Windows preference for .zip\n        let picker_win = AssetPicker::with_libc(\"windows\".to_string(), \"x86_64\".to_string(), None);\n        let score_win_zip = picker_win.score_asset(\"tool-1.0.0-windows-x86_64.zip\");\n        let score_win_tar = picker_win.score_asset(\"tool-1.0.0-windows-x86_64.tar.gz\");\n\n        assert!(\n            score_win_zip > score_win_tar,\n            \"Windows should prefer .zip (zip: {}, tar: {})\",\n            score_win_zip,\n            score_win_tar\n        );\n\n        // Test Linux penalty for .zip\n        let picker_linux = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let score_linux_zip = picker_linux.score_asset(\"tool-1.0.0-linux-x86_64.zip\");\n        let score_linux_tar = picker_linux.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz\");\n\n        assert!(\n            score_linux_tar > score_linux_zip,\n            \"Linux should prefer .tar.gz over .zip (zip: {}, tar: {})\",\n            score_linux_zip,\n            score_linux_tar\n        );\n    }\n\n    #[test]\n    fn test_artifactbundle_penalty() {\n        // Test that .artifactbundle files are penalized (they have different internal structure)\n        let picker = AssetPicker::with_libc(\"macos\".to_string(), \"aarch64\".to_string(), None);\n\n        // Test .artifactbundle.zip (like sourcery-2.2.7.artifactbundle.zip)\n        let assets = vec![\n            \"sourcery-2.2.7-macos-arm64.zip\".to_string(),\n            \"sourcery-2.2.7.artifactbundle.zip\".to_string(),\n        ];\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(\n            picked, \"sourcery-2.2.7-macos-arm64.zip\",\n            \".artifactbundle.zip should be penalized\"\n        );\n\n        // Test plain .artifactbundle\n        let assets = vec![\n            \"tool-1.0.0-darwin-arm64.tar.gz\".to_string(),\n            \"tool-1.0.0.artifactbundle\".to_string(),\n        ];\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(\n            picked, \"tool-1.0.0-darwin-arm64.tar.gz\",\n            \".artifactbundle should be penalized\"\n        );\n\n        // Verify penalty scores\n        let score_regular = picker.score_asset(\"sourcery-2.2.7-macos-arm64.zip\");\n        let score_bundle_zip = picker.score_asset(\"sourcery-2.2.7.artifactbundle.zip\");\n        let score_bundle = picker.score_asset(\"tool.artifactbundle\");\n\n        assert!(\n            score_regular > score_bundle_zip,\n            \"Regular zip should score higher than .artifactbundle.zip (regular: {}, bundle: {})\",\n            score_regular,\n            score_bundle_zip\n        );\n        assert!(\n            score_bundle < 0 || score_bundle < score_regular - 20,\n            \".artifactbundle should have penalty applied\"\n        );\n    }\n\n    #[test]\n    fn test_arch_mismatch_rejected() {\n        // Regression test for https://github.com/jdx/mise/discussions/7628\n        // When the requested architecture is not available, we should NOT silently\n        // fall back to a different architecture (e.g., x86_64 when arm64 is requested)\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"aarch64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-darwin-arm64.tar.gz\".to_string(),\n            \"tool-1.0.0-windows-x86_64.zip\".to_string(),\n        ];\n\n        // Should return None because linux-arm64 is not available\n        let picked = picker.pick_best_asset(&assets);\n        assert!(\n            picked.is_none(),\n            \"Should not fall back to x86_64 when arm64 is requested but unavailable\"\n        );\n\n        // Verify the score is negative for arch mismatch\n        let score = picker.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz\");\n        assert!(\n            score < 0,\n            \"Architecture mismatch should result in negative score, got {}\",\n            score\n        );\n    }\n\n    #[test]\n    fn test_metadata_penalty() {\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            \"tool-1.0.0-linux-x86_64.tar.gz.asc\".to_string(),\n            \"tool-1.0.0-linux-x86_64.tar.gz.sha256\".to_string(),\n            \"release-notes.txt\".to_string(),\n        ];\n\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(picked, \"tool-1.0.0-linux-x86_64.tar.gz\");\n\n        // Ensure penalties are applied\n        let score_tar = picker.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz\");\n        let score_asc = picker.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz.asc\");\n        let score_sha = picker.score_asset(\"tool-1.0.0-linux-x86_64.tar.gz.sha256\");\n        let score_txt = picker.score_asset(\"release-notes.txt\");\n\n        assert!(\n            score_tar > score_asc,\n            \"Tarball should score higher than signature\"\n        );\n        assert!(\n            score_tar > score_sha,\n            \"Tarball should score higher than checksum\"\n        );\n        assert!(\n            score_tar > score_txt,\n            \"Tarball should score higher than text file\"\n        );\n\n        // Metadata should have negative score contribution from penalties\n        assert!(score_asc < 0 || score_asc < score_tar - 50);\n    }\n\n    // ========== Provenance Picker Tests ==========\n\n    #[test]\n    fn test_pick_best_provenance_selects_matching_platform() {\n        // Regression test for https://github.com/jdx/mise/discussions/7462\n        // When multiple provenance files exist, select the one matching the target platform\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"buildx-v0.30.1.linux-amd64\".to_string(),\n            \"buildx-v0.30.1.darwin-amd64.provenance.json\".to_string(),\n            \"buildx-v0.30.1.linux-amd64.provenance.json\".to_string(),\n            \"buildx-v0.30.1.windows-amd64.provenance.json\".to_string(),\n        ];\n\n        let picked = picker.pick_best_provenance(&assets).unwrap();\n        assert_eq!(\n            picked, \"buildx-v0.30.1.linux-amd64.provenance.json\",\n            \"Should select Linux provenance for Linux target\"\n        );\n    }\n\n    #[test]\n    fn test_pick_best_provenance_darwin() {\n        let picker = AssetPicker::with_libc(\"macos\".to_string(), \"aarch64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-amd64.provenance.json\".to_string(),\n            \"tool-1.0.0-darwin-arm64.provenance.json\".to_string(),\n            \"tool-1.0.0-darwin-amd64.provenance.json\".to_string(),\n        ];\n\n        let picked = picker.pick_best_provenance(&assets).unwrap();\n        assert_eq!(\n            picked, \"tool-1.0.0-darwin-arm64.provenance.json\",\n            \"Should select darwin-arm64 provenance for macOS arm64 target\"\n        );\n    }\n\n    #[test]\n    fn test_pick_best_provenance_windows() {\n        let picker = AssetPicker::with_libc(\"windows\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"buildkit-v0.26.3.darwin-amd64.provenance.json\".to_string(),\n            \"buildkit-v0.26.3.linux-amd64.provenance.json\".to_string(),\n            \"buildkit-v0.26.3.windows-amd64.provenance.json\".to_string(),\n            \"buildkit-v0.26.3.windows-amd64.tar.gz\".to_string(),\n        ];\n\n        let picked = picker.pick_best_provenance(&assets).unwrap();\n        assert_eq!(\n            picked, \"buildkit-v0.26.3.windows-amd64.provenance.json\",\n            \"Should select Windows provenance for Windows target\"\n        );\n    }\n\n    #[test]\n    fn test_pick_best_provenance_intoto() {\n        // Test with .intoto.jsonl format (SLSA provenance)\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-linux-amd64.tar.gz\".to_string(),\n            \"tool-darwin-amd64.intoto.jsonl\".to_string(),\n            \"tool-linux-amd64.intoto.jsonl\".to_string(),\n        ];\n\n        let picked = picker.pick_best_provenance(&assets).unwrap();\n        assert_eq!(\n            picked, \"tool-linux-amd64.intoto.jsonl\",\n            \"Should select Linux .intoto.jsonl for Linux target\"\n        );\n    }\n\n    #[test]\n    fn test_pick_best_provenance_none_available() {\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-amd64.tar.gz\".to_string(),\n            \"tool-1.0.0-linux-amd64.sha256\".to_string(),\n        ];\n\n        let picked = picker.pick_best_provenance(&assets);\n        assert!(\n            picked.is_none(),\n            \"Should return None when no provenance files exist\"\n        );\n    }\n\n    #[test]\n    fn test_pick_best_provenance_single_provenance() {\n        // When only one provenance exists, return it even if platform doesn't match\n        let picker = AssetPicker::with_libc(\"linux\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"tool-1.0.0-linux-amd64.tar.gz\".to_string(),\n            \"tool-1.0.0.provenance.json\".to_string(), // No platform info\n        ];\n\n        let picked = picker.pick_best_provenance(&assets).unwrap();\n        assert_eq!(\n            picked, \"tool-1.0.0.provenance.json\",\n            \"Should return the only provenance file available\"\n        );\n    }\n\n    #[test]\n    fn test_vsix_vs_gz() {\n        let picker = AssetPicker::with_libc(\"macos\".to_string(), \"x86_64\".to_string(), None);\n        let assets = vec![\n            \"rust-analyzer-x86_64-apple-darwin.gz\".to_string(),\n            \"rust-analyzer-x86_64-apple-darwin.vsix\".to_string(),\n        ];\n\n        let picked = picker.pick_best_asset(&assets).unwrap();\n        assert_eq!(picked, \"rust-analyzer-x86_64-apple-darwin.gz\");\n    }\n}\n"
  },
  {
    "path": "src/backend/backend_type.rs",
    "content": "use std::fmt::{Display, Formatter};\n\n#[derive(\n    Debug,\n    PartialEq,\n    Eq,\n    Hash,\n    Clone,\n    strum::EnumString,\n    strum::EnumIter,\n    strum::AsRefStr,\n    Ord,\n    PartialOrd,\n)]\n#[strum(serialize_all = \"snake_case\")]\npub enum BackendType {\n    Aqua,\n    Asdf,\n    Cargo,\n    Conda,\n    Core,\n    Dotnet,\n    Forgejo,\n    Gem,\n    Github,\n    Gitlab,\n    Go,\n    Npm,\n    Pipx,\n    Spm,\n    Http,\n    S3,\n    Ubi,\n    Vfox,\n    VfoxBackend(String),\n    Unknown,\n}\n\nimpl Display for BackendType {\n    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {\n        match self {\n            BackendType::VfoxBackend(plugin_name) => write!(formatter, \"{plugin_name}\"),\n            _ => write!(formatter, \"{}\", format!(\"{self:?}\").to_lowercase()),\n        }\n    }\n}\n\nimpl BackendType {\n    pub fn guess(s: &str) -> BackendType {\n        let prefix = s.split(':').next().unwrap_or(s);\n\n        match prefix {\n            \"aqua\" => BackendType::Aqua,\n            \"asdf\" => BackendType::Asdf,\n            \"cargo\" => BackendType::Cargo,\n            \"conda\" => BackendType::Conda,\n            \"core\" => BackendType::Core,\n            \"dotnet\" => BackendType::Dotnet,\n            \"forgejo\" => BackendType::Forgejo,\n            \"gem\" => BackendType::Gem,\n            \"github\" => BackendType::Github,\n            \"gitlab\" => BackendType::Gitlab,\n            \"go\" => BackendType::Go,\n            \"npm\" => BackendType::Npm,\n            \"pipx\" => BackendType::Pipx,\n            \"spm\" => BackendType::Spm,\n            \"http\" => BackendType::Http,\n            \"s3\" => BackendType::S3,\n            \"ubi\" => BackendType::Ubi,\n            \"vfox\" => BackendType::Vfox,\n            _ => BackendType::Unknown,\n        }\n    }\n\n    /// Returns true if this backend requires experimental mode to be enabled\n    pub fn is_experimental(&self) -> bool {\n        use super::{conda, dotnet, s3, spm};\n        match self {\n            BackendType::Conda => conda::EXPERIMENTAL,\n            BackendType::Dotnet => dotnet::EXPERIMENTAL,\n            BackendType::S3 => s3::EXPERIMENTAL,\n            BackendType::Spm => spm::EXPERIMENTAL,\n            _ => false,\n        }\n    }\n}\n"
  },
  {
    "path": "src/backend/cargo.rs",
    "content": "use std::collections::BTreeMap;\nuse std::{fmt::Debug, sync::Arc};\n\nuse async_trait::async_trait;\nuse color_eyre::Section;\nuse eyre::{bail, eyre};\nuse url::Url;\n\nuse crate::Result;\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::lookup_platform_key;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::env::GITHUB_TOKEN;\nuse crate::file;\nuse crate::http::HTTP_FETCH;\nuse crate::install_context::InstallContext;\nuse crate::toolset::{ToolRequest, ToolVersion};\n\n#[derive(Debug)]\npub struct CargoBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for CargoBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Cargo\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"rust\"])\n    }\n\n    fn get_optional_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"cargo-binstall\", \"sccache\"])\n    }\n\n    /// Cargo installs packages from crates.io using version specs (e.g., ripgrep@14.0.0).\n    /// It doesn't support installing from direct URLs, so lockfile URLs are not applicable.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        if self.git_url().is_some() {\n            // TODO: maybe fetch tags/branches from git?\n            return Ok(vec![VersionInfo {\n                version: \"HEAD\".into(),\n                ..Default::default()\n            }]);\n        }\n\n        // Use crates.io API which includes created_at timestamps\n        let url = format!(\n            \"https://crates.io/api/v1/crates/{}/versions\",\n            self.tool_name()\n        );\n        let response: CratesIoVersionsResponse = HTTP_FETCH.json(&url).await?;\n\n        let versions = response\n            .versions\n            .into_iter()\n            .filter(|v| !v.yanked)\n            .map(|v| VersionInfo {\n                version: v.num,\n                created_at: Some(v.created_at),\n                ..Default::default()\n            })\n            .rev() // API returns newest first, we want oldest first\n            .collect();\n\n        Ok(versions)\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        // Check if cargo is available\n        self.warn_if_dependency_missing(\n            &ctx.config,\n            \"cargo\",\n            \"To use cargo packages with mise, you need to install Rust first:\\n\\\n              mise use rust@latest\\n\\n\\\n            Or install Rust via https://rustup.rs/\",\n        )\n        .await;\n\n        let config = ctx.config.clone();\n        let install_arg = format!(\"{}@{}\", self.tool_name(), tv.version);\n        let registry_name = &Settings::get().cargo.registry_name;\n\n        let cmd = CmdLineRunner::new(\"cargo\").arg(\"install\");\n        let mut cmd = if let Some(url) = self.git_url() {\n            let mut cmd = cmd.arg(format!(\"--git={url}\"));\n            if let Some(rev) = tv.version.strip_prefix(\"rev:\") {\n                cmd = cmd.arg(format!(\"--rev={rev}\"));\n            } else if let Some(branch) = tv.version.strip_prefix(\"branch:\") {\n                cmd = cmd.arg(format!(\"--branch={branch}\"));\n            } else if let Some(tag) = tv.version.strip_prefix(\"tag:\") {\n                cmd = cmd.arg(format!(\"--tag={tag}\"));\n            } else if tv.version != \"HEAD\" {\n                Err(eyre!(\"Invalid cargo git version: {}\", tv.version).note(\n                    r#\"You can specify \"rev:\", \"branch:\", or \"tag:\", e.g.:\n      * mise use cargo:eza-community/eza@tag:v0.18.0\n      * mise use cargo:eza-community/eza@branch:main\"#,\n                ))?;\n            }\n            cmd\n        } else if self.is_binstall_enabled(&config, &tv).await {\n            let mut cmd = CmdLineRunner::new(\"cargo-binstall\").arg(\"-y\");\n            if let Some(token) = &*GITHUB_TOKEN {\n                cmd = cmd.env(\"GITHUB_TOKEN\", token)\n            }\n            cmd.arg(install_arg)\n        } else if Settings::get().cargo.binstall_only {\n            bail!(\"cargo-binstall is not available, but cargo.binstall_only is set\");\n        } else {\n            cmd.arg(install_arg)\n        };\n\n        let opts = tv.request.options();\n        if let Some(bin) =\n            lookup_platform_key(&opts, \"bin\").or_else(|| opts.get(\"bin\").map(|s| s.to_string()))\n        {\n            cmd = cmd.arg(format!(\"--bin={bin}\"));\n        }\n        if opts\n            .get(\"locked\")\n            .is_none_or(|v| v.to_lowercase() != \"false\")\n        {\n            cmd = cmd.arg(\"--locked\");\n        }\n        if let Some(features) = opts.get(\"features\") {\n            cmd = cmd.arg(format!(\"--features={features}\"));\n        }\n        if let Some(default_features) = opts.get(\"default-features\")\n            && default_features.to_lowercase() == \"false\"\n        {\n            cmd = cmd.arg(\"--no-default-features\");\n        }\n        if let Some(c) = opts.get(\"crate\") {\n            cmd = cmd.arg(c);\n        }\n        if let Some(registry_name) = registry_name {\n            cmd = cmd.arg(format!(\"--registry={registry_name}\"));\n        }\n\n        cmd.arg(\"--root\")\n            .arg(tv.install_path())\n            .with_pr(ctx.pr.as_ref())\n            .envs(ctx.ts.env_with_path_without_tools(&ctx.config).await?)\n            .prepend_path(ctx.ts.list_paths(&ctx.config).await)?\n            .prepend_path(\n                self.dependency_toolset(&ctx.config)\n                    .await?\n                    .list_paths(&ctx.config)\n                    .await,\n            )?\n            .execute()?;\n\n        Ok(tv.clone())\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let opts = request.options();\n        let mut result = BTreeMap::new();\n\n        // These options affect what gets compiled/installed\n        for key in [\"features\", \"default-features\", \"bin\"] {\n            if let Some(value) = opts.get(key) {\n                result.insert(key.to_string(), value.to_string());\n            }\n        }\n\n        result\n    }\n}\n\n/// Returns install-time-only option keys for Cargo backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\"features\".into(), \"default-features\".into(), \"bin\".into()]\n}\n\nimpl CargoBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    async fn is_binstall_enabled(&self, config: &Arc<Config>, tv: &ToolVersion) -> bool {\n        if !Settings::get().cargo.binstall {\n            return false;\n        }\n        if file::which_non_pristine(\"cargo-binstall\").is_none() {\n            match self.dependency_toolset(config).await {\n                Ok(ts) => {\n                    if ts.which(config, \"cargo-binstall\").await.is_none() {\n                        return false;\n                    }\n                }\n                Err(_e) => {\n                    return false;\n                }\n            }\n        }\n        let opts = tv.request.options();\n        if opts.contains_key(\"features\") || opts.contains_key(\"default-features\") {\n            info!(\"not using cargo-binstall because features are specified\");\n            return false;\n        }\n        true\n    }\n\n    /// if the name is a git repo, return the git url\n    fn git_url(&self) -> Option<Url> {\n        if let Ok(url) = Url::parse(&self.tool_name()) {\n            Some(url)\n        } else if let Some((user, repo)) = self.tool_name().split_once('/') {\n            format!(\"https://github.com/{user}/{repo}.git\").parse().ok()\n        } else {\n            None\n        }\n    }\n}\n\n#[derive(Debug, serde::Deserialize)]\nstruct CratesIoVersionsResponse {\n    versions: Vec<CratesIoVersion>,\n}\n\n#[derive(Debug, serde::Deserialize)]\nstruct CratesIoVersion {\n    num: String,\n    yanked: bool,\n    created_at: String,\n}\n"
  },
  {
    "path": "src/backend/conda.rs",
    "content": "use crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::config::Settings;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::{self, Lockfile, PlatformInfo};\nuse crate::toolset::ToolSource;\nuse crate::toolset::ToolVersion;\nuse crate::{backend::Backend, dirs, parallel};\nuse crate::{file, hash};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse itertools::Itertools;\nuse rattler::install::{InstallDriver, InstallOptions, PythonInfo, link_package};\nuse rattler_conda_types::{\n    Channel, ChannelConfig, GenericVirtualPackage, MatchSpec, ParseStrictness,\n    Platform as CondaPlatform, RepoDataRecord, prefix::Prefix, prefix_record::PathsEntry,\n};\nuse rattler_repodata_gateway::{Gateway, RepoData};\nuse rattler_solve::{\n    ChannelPriority, SolveStrategy, SolverImpl, SolverTask, resolvo::Solver as ResolvoSolver,\n};\nuse rattler_virtual_packages::{VirtualPackageOverrides, VirtualPackages};\nuse serde::{Deserialize, Serialize};\nuse std::collections::{BTreeMap, HashSet};\nuse std::fmt::Debug;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse versions::Versioning;\n\n/// Conda package info stored in the shared conda-packages section of lockfiles\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]\npub struct CondaPackageInfo {\n    pub url: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub checksum: Option<String>,\n}\n\n/// Conda backend requires experimental mode to be enabled\npub const EXPERIMENTAL: bool = true;\n\n#[derive(Debug)]\npub struct CondaBackend {\n    ba: Arc<BackendArg>,\n}\n\nimpl CondaBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    fn channel_name(&self) -> String {\n        self.ba\n            .opts()\n            .get(\"channel\")\n            .map(|s| s.to_string())\n            .unwrap_or_else(|| Settings::get().conda.channel.clone())\n    }\n\n    fn channel(&self) -> Result<Channel> {\n        let name = self.channel_name();\n        let root_dir = std::env::current_dir().unwrap_or_else(|_| dirs::HOME.to_path_buf());\n        let config = ChannelConfig::default_with_root_dir(root_dir);\n        Channel::from_str(&name, &config)\n            .map_err(|e| eyre::eyre!(\"invalid conda channel '{}': {}\", name, e))\n    }\n\n    fn create_gateway() -> Gateway {\n        Gateway::builder()\n            .with_cache_dir(dirs::CACHE.join(\"conda\"))\n            .finish()\n    }\n\n    /// Map a mise PlatformTarget to a rattler conda Platform\n    fn target_to_conda_platform(target: &PlatformTarget) -> CondaPlatform {\n        match (target.os_name(), target.arch_name()) {\n            (\"linux\", \"x64\") => CondaPlatform::Linux64,\n            (\"linux\", \"arm64\") => CondaPlatform::LinuxAarch64,\n            (\"macos\", \"x64\") => CondaPlatform::Osx64,\n            (\"macos\", \"arm64\") => CondaPlatform::OsxArm64,\n            (\"windows\", \"x64\") => CondaPlatform::Win64,\n            _ => CondaPlatform::NoArch,\n        }\n    }\n\n    fn detect_virtual_packages(platform: CondaPlatform) -> Vec<GenericVirtualPackage> {\n        VirtualPackages::detect_for_platform(platform, &VirtualPackageOverrides::default())\n            .map(|vp| vp.into_generic_virtual_packages().collect())\n            .unwrap_or_default()\n    }\n\n    /// Flatten gateway RepoData into owned records for the solver, deduplicating\n    /// by URL to avoid DuplicateRecords errors when the same package appears in\n    /// multiple subdir queries (e.g. platform + noarch).\n    fn flatten_repodata(repodata: &[RepoData]) -> Vec<RepoDataRecord> {\n        let mut seen = HashSet::new();\n        repodata\n            .iter()\n            .flat_map(|rd| rd.iter().cloned())\n            .filter(|r| seen.insert(r.url.clone()))\n            .collect()\n    }\n\n    /// Fetch repodata and solve the conda environment for the given specs and platform.\n    async fn solve_packages(\n        &self,\n        specs: Vec<MatchSpec>,\n        platform: CondaPlatform,\n    ) -> Result<Vec<RepoDataRecord>> {\n        let channel = self.channel()?;\n        let gateway = Self::create_gateway();\n\n        let repodata: Vec<RepoData> = gateway\n            .query([channel], [platform, CondaPlatform::NoArch], specs.clone())\n            .recursive(true)\n            .await\n            .map_err(|e| eyre::eyre!(\"failed to fetch repodata: {}\", e))?;\n\n        let flat_records = Self::flatten_repodata(&repodata);\n        let virtual_packages = Self::detect_virtual_packages(platform);\n\n        let task = SolverTask {\n            available_packages: [flat_records.as_slice()],\n            specs,\n            virtual_packages,\n            locked_packages: vec![],\n            pinned_packages: vec![],\n            constraints: vec![],\n            timeout: None,\n            channel_priority: ChannelPriority::Strict,\n            exclude_newer: None,\n            min_age: None,\n            strategy: SolveStrategy::Highest,\n        };\n\n        let mut solver = ResolvoSolver;\n        let result = solver\n            .solve(task)\n            .map_err(|e| eyre::eyre!(\"conda solve failed: {}\", e))?;\n\n        Ok(result.records)\n    }\n\n    /// Shared data dir for all conda package archives (shared across tools)\n    fn conda_data_dir() -> PathBuf {\n        dirs::DATA.join(\"conda-packages\")\n    }\n\n    /// Get the filename portion of a package URL\n    fn url_filename(url: &url::Url) -> String {\n        url.path_segments()\n            .and_then(|mut s| s.next_back())\n            .unwrap_or(\"package\")\n            .to_string()\n    }\n\n    /// Strip .conda or .tar.bz2 extension to get the basename key\n    fn record_basename(record: &RepoDataRecord) -> String {\n        let filename = Self::url_filename(&record.url);\n        filename\n            .strip_suffix(\".conda\")\n            .or_else(|| filename.strip_suffix(\".tar.bz2\"))\n            .unwrap_or(&filename)\n            .to_string()\n    }\n\n    /// Format sha256 as \"sha256:<hex>\" if present\n    fn format_sha256(record: &RepoDataRecord) -> Option<String> {\n        record\n            .package_record\n            .sha256\n            .as_ref()\n            .map(|h| format!(\"sha256:{}\", hex::encode(h)))\n    }\n\n    /// Verify a file's sha256 against an expected \"sha256:<hex>\" checksum.\n    /// Returns Ok(true) if matches, Ok(false) if mismatches, or Ok(true)\n    /// if no expected checksum is provided (skip verification).\n    fn verify_checksum(path: &std::path::Path, expected: Option<&str>) -> Result<bool> {\n        let Some(expected) = expected else {\n            return Ok(true);\n        };\n        let Some(expected_hex) = expected.strip_prefix(\"sha256:\") else {\n            return Ok(true);\n        };\n        let actual_hex = hash::file_hash_sha256(path, None)?;\n        Ok(actual_hex == expected_hex)\n    }\n\n    /// Download a file to dest with optional checksum verification.\n    /// Uses atomic writes: downloads to a temp file, verifies, then renames.\n    /// If dest already exists and checksum matches, skips download.\n    async fn download_to(url: &str, dest: &std::path::Path, checksum: Option<&str>) -> Result<()> {\n        if dest.exists() && Self::verify_checksum(dest, checksum)? {\n            return Ok(());\n        }\n\n        file::create_dir_all(Self::conda_data_dir())?;\n        let temp = dest.with_extension(format!(\"tmp.{}\", std::process::id()));\n        HTTP.download_file(url, &temp, None).await?;\n\n        if !Self::verify_checksum(&temp, checksum)? {\n            let _ = file::remove_all(&temp);\n            let display_checksum = checksum.unwrap_or(\"unknown\");\n            return Err(eyre::eyre!(\n                \"checksum mismatch for {}: expected {}\",\n                url,\n                display_checksum,\n            ));\n        }\n\n        file::rename(&temp, dest)?;\n        Ok(())\n    }\n\n    /// Download a single package archive to the shared conda data dir.\n    async fn download_record(record: RepoDataRecord) -> Result<PathBuf> {\n        let url_str = record.url.to_string();\n        let filename = Self::url_filename(&record.url);\n        let dest = Self::conda_data_dir().join(&filename);\n        let checksum = Self::format_sha256(&record);\n\n        Self::download_to(&url_str, &dest, checksum.as_deref()).await?;\n        Ok(dest)\n    }\n\n    /// Download a package by URL with optional checksum (for locked installs).\n    async fn download_url_with_checksum(\n        (url_str, checksum): (String, Option<String>),\n    ) -> Result<PathBuf> {\n        let filename = url_str.rsplit('/').next().unwrap_or(\"package\").to_string();\n        let dest = Self::conda_data_dir().join(&filename);\n\n        Self::download_to(&url_str, &dest, checksum.as_deref()).await?;\n        Ok(dest)\n    }\n\n    /// Extract a downloaded conda package archive into dest using rattler.\n    async fn extract_package(archive: &std::path::Path, dest: &std::path::Path) -> Result<()> {\n        rattler_package_streaming::tokio::fs::extract(archive, dest)\n            .await\n            .map_err(|e| eyre::eyre!(\"failed to extract {}: {}\", archive.display(), e))?;\n        Ok(())\n    }\n\n    /// Extract a package to a temp dir and link it into the prefix using rattler.\n    ///\n    /// This handles text and binary prefix replacement (replacing conda build\n    /// placeholders with the actual install path), file permissions, and macOS\n    /// code signing — all via rattler's link_package.\n    async fn install_package(\n        archive: &std::path::Path,\n        prefix: &Prefix,\n        driver: &InstallDriver,\n        python_info: Option<PythonInfo>,\n    ) -> Result<Vec<PathsEntry>> {\n        let temp_dir = tempfile::tempdir()?;\n        Self::extract_package(archive, temp_dir.path()).await?;\n        let install_options = InstallOptions {\n            python_info,\n            ..InstallOptions::default()\n        };\n        let paths = link_package(temp_dir.path(), prefix, driver, install_options)\n            .await\n            .map_err(|e| eyre::eyre!(\"failed to link {}: {}\", archive.display(), e))?;\n        Ok(paths)\n    }\n\n    /// Extract PythonInfo from the solved records if a python package is present.\n    /// This is needed to correctly install noarch python packages.\n    fn python_info_from_records(\n        records: &[RepoDataRecord],\n        platform: CondaPlatform,\n    ) -> Option<PythonInfo> {\n        records\n            .iter()\n            .find(|r| r.package_record.name.as_normalized() == \"python\")\n            .and_then(|r| {\n                PythonInfo::from_version(\n                    r.package_record.version.version(),\n                    r.package_record.python_site_packages_path.as_deref(),\n                    platform,\n                )\n                .ok()\n            })\n    }\n\n    /// Extract PythonInfo from conda package basenames (for locked installs).\n    /// Parses basenames using `ArchiveIdentifier` (`<name>-<version>-<build>` format).\n    fn python_info_from_basenames(\n        basenames: &[String],\n        platform: CondaPlatform,\n    ) -> Option<PythonInfo> {\n        use rattler_conda_types::Version;\n        use rattler_conda_types::package::ArchiveIdentifier;\n        use std::str::FromStr;\n        basenames.iter().find_map(|b| {\n            let id = ArchiveIdentifier::from_str(b).ok()?;\n            if id.name != \"python\" {\n                return None;\n            }\n            let version = Version::from_str(&id.version).ok()?;\n            PythonInfo::from_version(&version, None, platform).ok()\n        })\n    }\n\n    fn read_lockfile_for_tool(&self, tv: &ToolVersion) -> Result<Lockfile> {\n        match tv.request.source() {\n            ToolSource::MiseToml(path) => {\n                let (lockfile_path, _) = lockfile::lockfile_path_for_config(path);\n                Lockfile::read(&lockfile_path)\n            }\n            _ => Ok(Lockfile::default()),\n        }\n    }\n\n    /// Install from a fresh solve (no lockfile deps).\n    async fn install_fresh(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        platform_key: &str,\n    ) -> Result<()> {\n        let tool_name = self.tool_name();\n        let spec_str = format!(\"{}=={}\", tool_name, tv.version);\n        let match_spec = MatchSpec::from_str(&spec_str, ParseStrictness::Lenient)\n            .map_err(|e| eyre::eyre!(\"invalid conda spec '{}': {}\", spec_str, e))?;\n\n        ctx.pr.set_message(\"fetching repodata\".to_string());\n        let records = self\n            .solve_packages(vec![match_spec], CondaPlatform::current())\n            .await?;\n\n        // Separate main package from deps\n        let tool_name_norm = tool_name.to_lowercase();\n        let (main_vec, dep_records): (Vec<_>, Vec<_>) = records\n            .into_iter()\n            .partition(|r| r.package_record.name.as_normalized() == tool_name_norm);\n\n        let main_record = main_vec\n            .into_iter()\n            .next()\n            .ok_or_else(|| eyre::eyre!(\"main package {} not found in solve result\", tool_name))?;\n\n        // Build ordered list: deps first, main last\n        let mut all_records = dep_records;\n        all_records.push(main_record.clone());\n\n        // Extract python info from solved records for noarch python packages\n        let python_info = Self::python_info_from_records(&all_records, CondaPlatform::current());\n\n        // Download all in parallel\n        ctx.pr\n            .set_message(format!(\"downloading {} packages\", all_records.len()));\n        let downloaded = parallel::parallel(all_records.clone(), Self::download_record).await?;\n\n        // Create conda prefix and install driver\n        let install_path = tv.install_path();\n        file::remove_all(&install_path)?;\n        file::create_dir_all(&install_path)?;\n        let prefix = Prefix::create(&install_path)\n            .map_err(|e| eyre::eyre!(\"failed to create conda prefix: {}\", e))?;\n        let driver = InstallDriver::default();\n\n        let mut main_paths = Vec::new();\n        for (record, archive) in all_records.iter().zip(downloaded.iter()) {\n            let name = record.package_record.name.as_normalized();\n            let is_main = name == tool_name_norm;\n            ctx.pr.set_message(format!(\"installing {name}\"));\n            let paths =\n                Self::install_package(archive, &prefix, &driver, python_info.clone()).await?;\n            if is_main {\n                main_paths = paths;\n            }\n        }\n\n        Self::make_bins_executable(&install_path)?;\n        self.create_symlink_bin_dir(tv, &main_paths)?;\n\n        // Store lockfile info\n        let n_deps = all_records.len() - 1; // all except main\n        let dep_basenames: Vec<String> = all_records[..n_deps]\n            .iter()\n            .map(Self::record_basename)\n            .collect();\n\n        let platform_info = tv\n            .lock_platforms\n            .entry(platform_key.to_string())\n            .or_default();\n        platform_info.url = Some(main_record.url.to_string());\n        platform_info.checksum = Self::format_sha256(&main_record);\n        platform_info.conda_deps = Some(dep_basenames.clone());\n\n        // Store dep package info in tv.conda_packages for lockfile update\n        for record in &all_records[..n_deps] {\n            let basename = Self::record_basename(record);\n            tv.conda_packages.insert(\n                (platform_key.to_string(), basename),\n                CondaPackageInfo {\n                    url: record.url.to_string(),\n                    checksum: Self::format_sha256(record),\n                },\n            );\n        }\n\n        Ok(())\n    }\n\n    /// Install using URLs stored in the lockfile (deterministic/reproducible path).\n    async fn install_from_locked(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        platform_key: &str,\n    ) -> Result<()> {\n        ctx.pr.set_message(\"using locked dependencies\".to_string());\n\n        let platform_info = tv\n            .lock_platforms\n            .get(platform_key)\n            .ok_or_else(|| eyre::eyre!(\"no lock info for platform {}\", platform_key))?;\n\n        let main_url = platform_info\n            .url\n            .as_ref()\n            .ok_or_else(|| eyre::eyre!(\"no URL in lockfile for {}\", self.tool_name()))?\n            .clone();\n        let main_checksum = platform_info.checksum.clone();\n\n        let dep_basenames = platform_info.conda_deps.clone().unwrap_or_default();\n        let lockfile = self.read_lockfile_for_tool(tv)?;\n\n        // Extract python info from basenames for noarch python packages\n        let python_info =\n            Self::python_info_from_basenames(&dep_basenames, CondaPlatform::current());\n\n        // Collect dep (url, checksum) pairs from lockfile (deps first, main last)\n        let mut downloads: Vec<(String, Option<String>)> = vec![];\n        for basename in &dep_basenames {\n            if let Some(pkg_info) = lockfile.get_conda_package(platform_key, basename) {\n                downloads.push((pkg_info.url.clone(), pkg_info.checksum.clone()));\n            } else {\n                return Err(eyre::eyre!(\n                    \"conda package {} not found in lockfile for {}\",\n                    basename,\n                    platform_key\n                ));\n            }\n        }\n        downloads.push((main_url, main_checksum));\n\n        ctx.pr\n            .set_message(format!(\"downloading {} packages\", downloads.len()));\n        let downloaded = parallel::parallel(downloads, Self::download_url_with_checksum).await?;\n\n        let install_path = tv.install_path();\n        file::remove_all(&install_path)?;\n        file::create_dir_all(&install_path)?;\n        let prefix = Prefix::create(&install_path)\n            .map_err(|e| eyre::eyre!(\"failed to create conda prefix: {}\", e))?;\n        let driver = InstallDriver::default();\n\n        let mut main_paths = Vec::new();\n        for archive in &downloaded {\n            let filename = archive.file_name().and_then(|n| n.to_str()).unwrap_or(\"?\");\n            ctx.pr.set_message(format!(\"installing {filename}\"));\n            // main package is always last, so main_paths ends up with its entries\n            main_paths =\n                Self::install_package(archive, &prefix, &driver, python_info.clone()).await?;\n        }\n\n        Self::make_bins_executable(&install_path)?;\n        self.create_symlink_bin_dir(tv, &main_paths)?;\n\n        // Repopulate tv.conda_packages from lockfile so downstream lockfile update preserves entries\n        for basename in &dep_basenames {\n            if let Some(pkg_info) = lockfile.get_conda_package(platform_key, basename) {\n                tv.conda_packages.insert(\n                    (platform_key.to_string(), basename.clone()),\n                    pkg_info.clone(),\n                );\n            }\n        }\n\n        Ok(())\n    }\n\n    fn make_bins_executable(install_path: &std::path::Path) -> Result<()> {\n        let bin_path = if cfg!(windows) {\n            install_path.join(\"Library\").join(\"bin\")\n        } else {\n            install_path.join(\"bin\")\n        };\n        if bin_path.exists() {\n            for entry in std::fs::read_dir(&bin_path)? {\n                let entry = entry?;\n                let path = entry.path();\n                if path.is_file() {\n                    file::make_executable(&path)?;\n                }\n            }\n        }\n        Ok(())\n    }\n\n    /// Creates a `.mise-bins` directory with symlinks only to binaries from the main package.\n    /// Uses the PathsEntry list returned by rattler's link_package to identify which files\n    /// belong to the main package (excluding transitive dependency binaries).\n    fn create_symlink_bin_dir(&self, tv: &ToolVersion, main_paths: &[PathsEntry]) -> Result<()> {\n        let symlink_dir = tv.install_path().join(\".mise-bins\");\n        file::create_dir_all(&symlink_dir)?;\n\n        let install_path = tv.install_path();\n        let bin_dirs: &[&std::path::Path] = if cfg!(windows) {\n            &[\n                std::path::Path::new(\"Library/bin\"),\n                std::path::Path::new(\"Scripts\"),\n                std::path::Path::new(\"bin\"),\n            ]\n        } else {\n            &[std::path::Path::new(\"bin\")]\n        };\n\n        for entry in main_paths {\n            if !bin_dirs\n                .iter()\n                .any(|dir| entry.relative_path.starts_with(dir))\n            {\n                continue;\n            }\n            let Some(bin_name) = entry.relative_path.file_name() else {\n                continue;\n            };\n            let src = install_path.join(&entry.relative_path);\n            let dst = symlink_dir.join(bin_name);\n            if src.exists() && !dst.exists() {\n                file::make_symlink_or_copy(&src, &dst)?;\n            }\n        }\n        Ok(())\n    }\n\n    /// Resolve conda packages for lockfile's shared conda-packages section.\n    /// Returns a map of basename -> CondaPackageInfo for deps of this tool on the given platform.\n    pub async fn resolve_conda_packages(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<BTreeMap<String, CondaPackageInfo>> {\n        let platform = Self::target_to_conda_platform(target);\n        let tool_name = self.tool_name();\n        let spec_str = format!(\"{}=={}\", tool_name, tv.version);\n        let match_spec = MatchSpec::from_str(&spec_str, ParseStrictness::Lenient)\n            .map_err(|e| eyre::eyre!(\"invalid conda spec '{}': {}\", spec_str, e))?;\n\n        let records = self.solve_packages(vec![match_spec], platform).await?;\n\n        let tool_name_norm = tool_name.to_lowercase();\n        let mut result = BTreeMap::new();\n        for record in &records {\n            if record.package_record.name.as_normalized() == tool_name_norm {\n                continue;\n            }\n            let basename = Self::record_basename(record);\n            result.insert(\n                basename,\n                CondaPackageInfo {\n                    url: record.url.to_string(),\n                    checksum: Self::format_sha256(record),\n                },\n            );\n        }\n\n        Ok(result)\n    }\n}\n\n#[async_trait]\nimpl Backend for CondaBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Conda\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let channel = self.channel()?;\n        let current_platform = CondaPlatform::current();\n        let tool_name = self.tool_name();\n\n        let gateway = Self::create_gateway();\n        let match_spec = MatchSpec::from_str(&tool_name, ParseStrictness::Lenient)\n            .map_err(|e| eyre::eyre!(\"invalid match spec for '{}': {}\", tool_name, e))?;\n\n        let repodata: Vec<RepoData> = gateway\n            .query(\n                [channel],\n                [current_platform, CondaPlatform::NoArch],\n                [match_spec],\n            )\n            .await\n            .map_err(|e| eyre::eyre!(\"failed to list versions for '{}': {}\", tool_name, e))?;\n\n        // Collect unique versions across all repodata results\n        let mut version_set: std::collections::HashSet<String> = std::collections::HashSet::new();\n        for data in &repodata {\n            for record in data {\n                version_set.insert(record.package_record.version.to_string());\n            }\n        }\n\n        let versions = version_set\n            .into_iter()\n            .map(|version| VersionInfo {\n                version,\n                ..Default::default()\n            })\n            .sorted_by_cached_key(|v| Versioning::new(&v.version))\n            .collect();\n\n        Ok(versions)\n    }\n\n    /// Override to bypass the shared remote_versions cache since conda's\n    /// channel option affects which versions are available.\n    async fn list_remote_versions_with_info(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<VersionInfo>> {\n        self._list_remote_versions(config).await\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        Settings::get().ensure_experimental(\"conda backend\")?;\n\n        let platform_key = self.get_platform_key();\n        let has_locked = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|p| p.url.as_ref())\n            .is_some();\n\n        if has_locked {\n            self.install_from_locked(ctx, &mut tv, &platform_key)\n                .await?;\n        } else {\n            self.install_fresh(ctx, &mut tv, &platform_key).await?;\n        }\n\n        Ok(tv)\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let platform = Self::target_to_conda_platform(target);\n        let tool_name = self.tool_name();\n        let spec_str = format!(\"{}=={}\", tool_name, tv.version);\n\n        let match_spec = match MatchSpec::from_str(&spec_str, ParseStrictness::Lenient) {\n            Ok(s) => s,\n            Err(e) => {\n                debug!(\"invalid conda spec '{}': {}\", spec_str, e);\n                return Ok(PlatformInfo::default());\n            }\n        };\n\n        let records = match self.solve_packages(vec![match_spec], platform).await {\n            Ok(r) => r,\n            Err(e) => {\n                debug!(\n                    \"failed to resolve {} for {}: {}\",\n                    tool_name,\n                    target.to_key(),\n                    e\n                );\n                return Ok(PlatformInfo::default());\n            }\n        };\n\n        let tool_name_norm = tool_name.to_lowercase();\n        let mut main_record = None;\n        let mut dep_basenames: Vec<String> = vec![];\n\n        for record in &records {\n            if record.package_record.name.as_normalized() == tool_name_norm {\n                main_record = Some(record.clone());\n            } else {\n                dep_basenames.push(Self::record_basename(record));\n            }\n        }\n\n        match main_record {\n            Some(main) => Ok(PlatformInfo {\n                url: Some(main.url.to_string()),\n                checksum: Self::format_sha256(&main),\n                size: None,\n                url_api: None,\n                conda_deps: Some(dep_basenames),\n                ..Default::default()\n            }),\n            None => Ok(PlatformInfo::default()),\n        }\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        let mise_bins = tv.install_path().join(\".mise-bins\");\n        if mise_bins.exists() {\n            return Ok(vec![mise_bins]);\n        }\n\n        // Fallback for tools installed before this change\n        let install_path = tv.install_path();\n        if cfg!(windows) {\n            // Conda packages on Windows can put binaries in either location\n            // depending on the build variant (MSVC vs MSYS2/MinGW)\n            Ok(vec![\n                install_path.join(\"Library\").join(\"bin\"),\n                install_path.join(\"bin\"),\n            ])\n        } else {\n            Ok(vec![install_path.join(\"bin\")])\n        }\n    }\n}\n"
  },
  {
    "path": "src/backend/dotnet.rs",
    "content": "use std::sync::Arc;\n\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::Settings;\nuse crate::http::HTTP_FETCH;\nuse crate::{backend::Backend, config::Config};\nuse async_trait::async_trait;\nuse eyre::eyre;\n\n/// Dotnet backend requires experimental mode to be enabled\npub const EXPERIMENTAL: bool = true;\n\n#[derive(Debug)]\npub struct DotnetBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for DotnetBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Dotnet\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"dotnet\"])\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        let feed_url = self.get_search_url().await?;\n\n        let feed: NugetFeedSearch = HTTP_FETCH\n            .json(format!(\n                \"{}?q={}&packageType=dotnettool&take=1&prerelease={}\",\n                feed_url,\n                &self.tool_name(),\n                Settings::get()\n                    .dotnet\n                    .package_flags\n                    .contains(&\"prerelease\".to_string())\n            ))\n            .await?;\n\n        if feed.total_hits == 0 {\n            return Err(eyre!(\"No tool found\"));\n        }\n\n        let data = feed.data.first().ok_or_else(|| eyre!(\"No data found\"))?;\n\n        // Because the nuget API is a search API we need to check name of the tool we are looking for\n        if data.id.to_lowercase() != self.tool_name().to_lowercase() {\n            return Err(eyre!(\"Tool {} not found\", &self.tool_name()));\n        }\n\n        Ok(data\n            .versions\n            .iter()\n            .map(|x| VersionInfo {\n                version: x.version.clone(),\n                ..Default::default()\n            })\n            .collect())\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &crate::install_context::InstallContext,\n        tv: crate::toolset::ToolVersion,\n    ) -> eyre::Result<crate::toolset::ToolVersion> {\n        Settings::get().ensure_experimental(\"dotnet backend\")?;\n\n        // Check if dotnet is available\n        self.warn_if_dependency_missing(\n            &ctx.config,\n            \"dotnet\",\n            \"To use dotnet tools with mise, you need to install .NET SDK first:\\n\\\n              mise use dotnet@latest\\n\\n\\\n            Or install .NET SDK via https://dotnet.microsoft.com/download\",\n        )\n        .await;\n\n        let mut cli = CmdLineRunner::new(\"dotnet\")\n            .arg(\"tool\")\n            .arg(\"install\")\n            .arg(self.tool_name())\n            .arg(\"--tool-path\")\n            .arg(tv.install_path().join(\"bin\"));\n\n        if &tv.version != \"latest\" {\n            cli = cli.arg(\"--version\").arg(&tv.version);\n        }\n\n        cli.with_pr(ctx.pr.as_ref())\n            .envs(self.dependency_env(&ctx.config).await?)\n            .execute()?;\n\n        Ok(tv)\n    }\n}\n\nimpl DotnetBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    async fn get_search_url(&self) -> eyre::Result<String> {\n        let settings = Settings::get();\n        let nuget_registry = settings.dotnet.registry_url.as_str();\n\n        let services: NugetFeed = HTTP_FETCH.json(nuget_registry).await?;\n\n        let feed = services\n            .resources\n            .iter()\n            .find(|x| x.service_type == \"SearchQueryService/3.5.0\")\n            .or_else(|| {\n                services\n                    .resources\n                    .iter()\n                    .find(|x| x.service_type == \"SearchQueryService\")\n            })\n            .ok_or_else(|| eyre!(\"No SearchQueryService found\"))?;\n\n        Ok(feed.id.clone())\n    }\n}\n\n#[derive(serde::Deserialize)]\nstruct NugetFeed {\n    resources: Vec<NugetFeedResource>,\n}\n\n#[derive(serde::Deserialize)]\nstruct NugetFeedResource {\n    #[serde(rename = \"@id\")]\n    id: String,\n    #[serde(rename = \"@type\")]\n    service_type: String,\n}\n\n#[derive(serde::Deserialize)]\nstruct NugetFeedSearch {\n    #[serde(rename = \"totalHits\")]\n    total_hits: i32,\n    data: Vec<NugetFeedSearchData>,\n}\n\n#[derive(serde::Deserialize)]\nstruct NugetFeedSearchData {\n    id: String,\n    versions: Vec<NugetFeedSearchDataVersion>,\n}\n\n#[derive(serde::Deserialize)]\nstruct NugetFeedSearchDataVersion {\n    version: String,\n}\n"
  },
  {
    "path": "src/backend/external_plugin_cache.rs",
    "content": "use crate::backend::asdf::AsdfBackend;\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::config::Config;\nuse crate::env;\nuse crate::env_diff::EnvMap;\nuse crate::hash::hash_to_str;\nuse crate::tera::{BASE_CONTEXT, get_tera};\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse dashmap::DashMap;\nuse eyre::{WrapErr, eyre};\nuse std::sync::Arc;\n\n#[derive(Debug, Default)]\npub struct ExternalPluginCache {\n    list_bin_paths: DashMap<ToolRequest, CacheManager<Vec<String>>>,\n    exec_env: DashMap<ToolRequest, CacheManager<EnvMap>>,\n}\n\nimpl ExternalPluginCache {\n    pub async fn list_bin_paths<F, Fut>(\n        &self,\n        config: &Arc<Config>,\n        plugin: &AsdfBackend,\n        tv: &ToolVersion,\n        fetch: F,\n    ) -> eyre::Result<Vec<String>>\n    where\n        Fut: Future<Output = eyre::Result<Vec<String>>>,\n        F: FnOnce() -> Fut,\n    {\n        let cm = self\n            .list_bin_paths\n            .entry(tv.request.clone())\n            .or_insert_with(|| {\n                let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key {\n                    Some(key) => {\n                        let key = render_cache_key(config, tv, key);\n                        let filename = format!(\"{key}.msgpack.z\");\n                        tv.cache_path().join(\"list_bin_paths\").join(filename)\n                    }\n                    None => tv.cache_path().join(\"list_bin_paths.msgpack.z\"),\n                };\n                CacheManagerBuilder::new(list_bin_paths_filename)\n                    .with_fresh_file(plugin.plugin_path.clone())\n                    .with_fresh_file(tv.install_path())\n                    .build()\n            });\n        let start = std::time::Instant::now();\n        let res = cm.get_or_try_init_async(fetch).await.cloned();\n        trace!(\n            \"external_plugin_cache.list_bin_paths for {} took {}ms\",\n            plugin.name,\n            start.elapsed().as_millis()\n        );\n        res\n    }\n\n    pub async fn exec_env<F, Fut>(\n        &self,\n        config: &Config,\n        plugin: &AsdfBackend,\n        tv: &ToolVersion,\n        fetch: F,\n    ) -> eyre::Result<EnvMap>\n    where\n        Fut: Future<Output = eyre::Result<EnvMap>>,\n        F: FnOnce() -> Fut,\n    {\n        let cm = self.exec_env.entry(tv.request.clone()).or_insert_with(|| {\n            let exec_env_filename = match &plugin.toml.exec_env.cache_key {\n                Some(key) => {\n                    let key = render_cache_key(config, tv, key);\n                    let filename = format!(\"{key}.msgpack.z\");\n                    tv.cache_path().join(\"exec_env\").join(filename)\n                }\n                None => tv.cache_path().join(\"exec_env.msgpack.z\"),\n            };\n            CacheManagerBuilder::new(exec_env_filename)\n                .with_fresh_file(plugin.plugin_path.clone())\n                .with_fresh_file(tv.install_path())\n                .build()\n        });\n        let start = std::time::Instant::now();\n        let res = cm.get_or_try_init_async(fetch).await.cloned();\n        trace!(\n            \"external_plugin_cache.exec_env for {} took {}ms\",\n            plugin.name,\n            start.elapsed().as_millis()\n        );\n        res\n    }\n}\n\nfn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> String {\n    let elements = cache_key\n        .iter()\n        .map(|tmpl| {\n            let s = parse_template(config, tv, tmpl).unwrap();\n            let s = s.trim().to_string();\n            trace!(\"cache key element: {} -> {}\", tmpl.trim(), s);\n            let mut s = hash_to_str(&s);\n            s = s.chars().take(10).collect();\n            s\n        })\n        .collect::<Vec<String>>();\n    elements.join(\"-\")\n}\n\nfn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> eyre::Result<String> {\n    let mut ctx = BASE_CONTEXT.clone();\n    ctx.insert(\"project_root\", &config.project_root);\n    ctx.insert(\"opts\", &tv.request.options().opts_as_strings());\n    get_tera(\n        config\n            .project_root\n            .as_ref()\n            .or(env::current_dir().as_ref().ok())\n            .map(|p| p.as_path()),\n    )\n    .render_str(tmpl, &ctx)\n    .wrap_err_with(|| eyre!(\"failed to parse template: {tmpl}\"))\n}\n"
  },
  {
    "path": "src/backend/gem.rs",
    "content": "use crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::file;\nuse crate::http::HTTP_FETCH;\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolVersion;\nuse crate::{Result, config::Config, env};\nuse async_trait::async_trait;\nuse indoc::formatdoc;\nuse serde::Deserialize;\nuse std::path::Path;\nuse std::{fmt::Debug, sync::Arc};\nuse tokio::sync::OnceCell as TokioOnceCell;\n\nconst GEM_PROGRAM: &str = if cfg!(windows) { \"gem.cmd\" } else { \"gem\" };\n\n/// Cached gem source URL, memoized globally after first successful detection\nstatic GEM_SOURCE: TokioOnceCell<String> = TokioOnceCell::const_new();\n\n#[derive(Debug)]\npub struct GemBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for GemBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Gem\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"ruby\"])\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        // Get the gem source URL using the mise-managed Ruby environment\n        let source_url = self.get_gem_source(config).await;\n\n        // Use RubyGems-compatible API to get versions with timestamps\n        let url = format!(\"{}api/v1/versions/{}.json\", source_url, self.tool_name());\n        let response: Vec<RubyGemsVersion> = HTTP_FETCH.json(&url).await?;\n\n        // RubyGems API returns newest-first, mise expects oldest-first\n        let mut versions: Vec<VersionInfo> = response\n            .into_iter()\n            .map(|v| VersionInfo {\n                version: v.number,\n                created_at: v.created_at,\n                ..Default::default()\n            })\n            .collect();\n        versions.reverse();\n\n        Ok(versions)\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        // Check if gem is available\n        self.warn_if_dependency_missing(\n            &ctx.config,\n            \"gem\",\n            \"To use gem packages with mise, you need to install Ruby first:\\n\\\n              mise use ruby@latest\",\n        )\n        .await;\n\n        CmdLineRunner::new(GEM_PROGRAM)\n            .arg(\"install\")\n            .arg(self.tool_name())\n            .arg(\"--version\")\n            .arg(&tv.version)\n            .arg(\"--install-dir\")\n            .arg(tv.install_path().join(\"libexec\"))\n            .with_pr(ctx.pr.as_ref())\n            .envs(self.dependency_env(&ctx.config).await?)\n            .execute()?;\n\n        // We install the gem to {install_path}/libexec and create a wrapper script for each executable\n        // in {install_path}/bin that sets GEM_HOME and executes the gem installed\n        env_script_all_bin_files(&tv.install_path())?;\n\n        #[cfg(unix)]\n        {\n            // Rewrite shebangs for better compatibility:\n            // - System Ruby: uses `#!/usr/bin/env ruby` for PATH-based resolution\n            // - Mise Ruby: uses minor version symlink (e.g., .../ruby/3.1/bin/ruby) so patch\n            //   upgrades don't break gems, while still being pinned to a minor version\n            rewrite_gem_shebangs(&tv.install_path())?;\n\n            // Create a ruby symlink in libexec/bin for polyglot script fallback\n            // RubyGems polyglot scripts have: exec \"$bindir/ruby\" \"-x\" \"$0\" \"$@\"\n            create_ruby_symlink(&tv.install_path())?;\n        }\n\n        Ok(tv)\n    }\n}\n\nimpl GemBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    /// Get the primary gem source URL using the mise-managed Ruby environment.\n    /// The result is memoized globally after first successful detection.\n    async fn get_gem_source(&self, config: &Arc<Config>) -> &'static str {\n        const DEFAULT_SOURCE: &str = \"https://rubygems.org/\";\n\n        // Get the mise-managed Ruby environment\n        let env = self.dependency_env(config).await.unwrap_or_default();\n\n        // Try to initialize the source - only memoize on success\n        match GEM_SOURCE\n            .get_or_try_init(|| async {\n                let output = crate::cmd::cmd_read_async(GEM_PROGRAM, &[\"sources\"], &env)\n                    .await\n                    .map_err(|e| eyre::eyre!(\"failed to run `gem sources`: {e}\"))?;\n\n                Ok::<_, eyre::Report>(parse_gem_source_output(&output))\n            })\n            .await\n        {\n            Ok(source) => source.as_str(),\n            Err(e) => {\n                warn!(\"{e}, falling back to rubygems.org\");\n                DEFAULT_SOURCE\n            }\n        }\n    }\n}\n\n/// RubyGems API response for version info\n#[derive(Debug, Deserialize)]\nstruct RubyGemsVersion {\n    number: String,\n    created_at: Option<String>,\n}\n\n/// Parse gem sources output to extract the primary source URL.\n/// Output format:\n/// ```\n/// *** CURRENT SOURCES ***\n///\n/// https://rubygems.org/\n/// ```\nfn parse_gem_source_output(output: &str) -> String {\n    for line in output.lines() {\n        let line = line.trim();\n        if line.starts_with(\"http://\") || line.starts_with(\"https://\") {\n            // Ensure URL ends with /\n            return if line.ends_with('/') {\n                line.to_string()\n            } else {\n                format!(\"{}/\", line)\n            };\n        }\n    }\n    // Default to rubygems.org if no source found\n    \"https://rubygems.org/\".to_string()\n}\n\n#[cfg(unix)]\nfn env_script_all_bin_files(install_path: &Path) -> eyre::Result<bool> {\n    let install_bin_path = install_path.join(\"bin\");\n    let install_libexec_path = install_path.join(\"libexec\");\n\n    file::create_dir_all(&install_bin_path)?;\n\n    for path in get_gem_executables(install_path)? {\n        let file_name = path\n            .file_name()\n            .ok_or_else(|| eyre::eyre!(\"invalid gem executable path: {}\", path.display()))?;\n        let exec_path = install_bin_path.join(file_name);\n        let gem_exec_path = path.to_str().ok_or_else(|| {\n            eyre::eyre!(\n                \"gem executable path contains invalid UTF-8: {}\",\n                path.display()\n            )\n        })?;\n        let gem_home = install_libexec_path.to_str().ok_or_else(|| {\n            eyre::eyre!(\n                \"libexec path contains invalid UTF-8: {}\",\n                install_libexec_path.display()\n            )\n        })?;\n        file::write(\n            &exec_path,\n            formatdoc!(\n                r#\"\n                #!/usr/bin/env bash\n                GEM_HOME=\"{gem_home}\" exec {gem_exec_path} \"$@\"\n                \"#,\n                gem_home = gem_home,\n                gem_exec_path = gem_exec_path,\n            ),\n        )?;\n        file::make_executable(&exec_path)?;\n    }\n\n    Ok(true)\n}\n\n#[cfg(windows)]\nfn env_script_all_bin_files(install_path: &Path) -> eyre::Result<bool> {\n    let install_bin_path = install_path.join(\"bin\");\n    let install_libexec_path = install_path.join(\"libexec\");\n\n    file::create_dir_all(&install_bin_path)?;\n\n    for path in get_gem_executables(install_path)? {\n        // On Windows, create .cmd wrapper scripts\n        let file_stem = path\n            .file_stem()\n            .ok_or_else(|| eyre::eyre!(\"invalid gem executable path: {}\", path.display()))?\n            .to_string_lossy();\n        let exec_path = install_bin_path.join(format!(\"{}.cmd\", file_stem));\n        let gem_exec_path = path.to_str().ok_or_else(|| {\n            eyre::eyre!(\n                \"gem executable path contains invalid UTF-8: {}\",\n                path.display()\n            )\n        })?;\n        let gem_home = install_libexec_path.to_str().ok_or_else(|| {\n            eyre::eyre!(\n                \"libexec path contains invalid UTF-8: {}\",\n                install_libexec_path.display()\n            )\n        })?;\n        file::write(\n            &exec_path,\n            formatdoc!(\n                r#\"@echo off\n                set \"GEM_HOME={gem_home}\"\n                \"{gem_exec_path}\" %*\n                \"#,\n                gem_home = gem_home,\n                gem_exec_path = gem_exec_path,\n            ),\n        )?;\n    }\n\n    Ok(true)\n}\n\nfn get_gem_executables(install_path: &Path) -> eyre::Result<Vec<std::path::PathBuf>> {\n    // TODO: Find a way to get the list of executables from the gemspec of the\n    //       installed gem rather than just listing the files in the bin directory.\n    let install_libexec_bin_path = install_path.join(\"libexec/bin\");\n    let files = file::ls(&install_libexec_bin_path)?\n        .into_iter()\n        .filter(|p| file::is_executable(p))\n        .collect();\n    Ok(files)\n}\n\n#[cfg(unix)]\n/// Creates a `ruby` symlink in libexec/bin/ for RubyGems polyglot script fallback.\n///\n/// RubyGems polyglot scripts include: `exec \"$bindir/ruby\" \"-x\" \"$0\" \"$@\"`\n/// This fallback runs when the script is executed via /bin/sh instead of ruby.\n/// We create a symlink to the mise-managed Ruby (using minor version) so\n/// the fallback works correctly.\nfn create_ruby_symlink(install_path: &Path) -> eyre::Result<()> {\n    let libexec_bin = install_path.join(\"libexec/bin\");\n    let ruby_symlink = libexec_bin.join(\"ruby\");\n\n    // Don't overwrite if it already exists\n    if ruby_symlink.exists() || ruby_symlink.is_symlink() {\n        return Ok(());\n    }\n\n    // Find which Ruby we're using by checking an existing gem executable's shebang\n    let executables = get_gem_executables(install_path)?;\n    let Some(exec_path) = executables.first() else {\n        return Ok(());\n    };\n\n    let content = file::read_to_string(exec_path)?;\n    let lines: Vec<&str> = content.lines().collect();\n    let Some((_, shebang_line)) = find_ruby_shebang(&lines) else {\n        return Ok(());\n    };\n\n    // Extract the ruby path from the shebang\n    let ruby_path = shebang_line\n        .trim_start_matches(\"#!\")\n        .split_whitespace()\n        .next()\n        .unwrap_or(\"\");\n\n    if ruby_path.is_empty() {\n        return Ok(());\n    }\n\n    // Only create symlink for mise-managed Ruby\n    // For system Ruby, the shebang is #!/usr/bin/env ruby, which we can't symlink to\n    if !is_mise_ruby_path(ruby_path) {\n        return Ok(());\n    }\n\n    // Create symlink to the ruby executable\n    file::make_symlink(Path::new(ruby_path), &ruby_symlink)?;\n    Ok(())\n}\n\n#[cfg(unix)]\n/// Rewrites shebangs in gem executables to improve compatibility.\n///\n/// For system Ruby: Uses `#!/usr/bin/env ruby` for PATH-based resolution.\n/// For mise-managed Ruby: Uses minor version symlink (e.g., `.../ruby/3.1/bin/ruby`)\n/// so that patch upgrades (3.1.0 → 3.1.1) don't break gems.\n///\n/// Handles both regular Ruby scripts and RubyGems polyglot scripts which have\n/// `#!/bin/sh` on line 1 but the actual Ruby shebang after `=end`.\nfn rewrite_gem_shebangs(install_path: &Path) -> eyre::Result<()> {\n    let executables = get_gem_executables(install_path)?;\n\n    for exec_path in executables {\n        let content = file::read_to_string(&exec_path)?;\n        let lines: Vec<&str> = content.lines().collect();\n\n        if lines.is_empty() {\n            continue;\n        }\n\n        // Find the Ruby shebang line - either line 1 or after =end for polyglot scripts\n        let (shebang_line_idx, shebang_line) = if let Some(info) = find_ruby_shebang(&lines) {\n            info\n        } else {\n            continue;\n        };\n\n        // Extract the Ruby path and any arguments from the shebang\n        let shebang_content = shebang_line.trim_start_matches(\"#!\");\n        let mut parts = shebang_content.split_whitespace();\n        let ruby_path = parts.next().unwrap_or(\"\");\n        let shebang_args: Vec<&str> = parts.collect();\n\n        let new_shebang = if is_mise_ruby_path(ruby_path) {\n            // Mise-managed Ruby: use minor version symlink, preserving any arguments\n            match to_minor_version_shebang(ruby_path) {\n                Some(path) => {\n                    if shebang_args.is_empty() {\n                        format!(\"#!{path}\")\n                    } else {\n                        format!(\"#!{path} {}\", shebang_args.join(\" \"))\n                    }\n                }\n                None => continue, // Keep original if we can't parse\n            }\n        } else {\n            // System Ruby: use env-based shebang\n            // Note: env shebangs generally can't preserve arguments portably\n            \"#!/usr/bin/env ruby\".to_string()\n        };\n\n        // Rewrite the file with new shebang at the correct line\n        let mut new_lines: Vec<&str> = lines.clone();\n        let new_shebang_ref: &str = &new_shebang;\n        new_lines[shebang_line_idx] = new_shebang_ref;\n        let trailing_newline = if content.ends_with('\\n') { \"\\n\" } else { \"\" };\n        let new_content = format!(\"{}{trailing_newline}\", new_lines.join(\"\\n\"));\n        file::write(&exec_path, &new_content)?;\n    }\n\n    Ok(())\n}\n\n#[cfg(unix)]\n/// Finds the Ruby shebang line in a script.\n/// Returns (line_index, line_content) or None if not found.\n///\n/// For regular Ruby scripts, this is line 0 with `#!...ruby...`.\n/// For RubyGems polyglot scripts (starting with `#!/bin/sh`), the Ruby shebang\n/// is the first `#!...ruby...` line after `=end`.\nfn find_ruby_shebang<'a>(lines: &'a [&'a str]) -> Option<(usize, &'a str)> {\n    let first_line = lines.first()?;\n\n    // Check if first line is a Ruby shebang\n    if first_line.starts_with(\"#!\") && first_line.contains(\"ruby\") {\n        return Some((0, first_line));\n    }\n\n    // Check for polyglot format: #!/bin/sh followed by =end and then Ruby shebang\n    if first_line.starts_with(\"#!/bin/sh\") {\n        let mut found_end = false;\n        for (idx, line) in lines.iter().enumerate().skip(1) {\n            if line.trim() == \"=end\" {\n                found_end = true;\n                continue;\n            }\n            if found_end && line.starts_with(\"#!\") && line.contains(\"ruby\") {\n                return Some((idx, line));\n            }\n        }\n    }\n\n    None\n}\n\n#[cfg(unix)]\n/// Checks if a Ruby path is within mise's installs directory.\nfn is_mise_ruby_path(ruby_path: &str) -> bool {\n    let ruby_installs = env::MISE_INSTALLS_DIR.join(\"ruby\");\n    Path::new(ruby_path).starts_with(&ruby_installs)\n}\n\n#[cfg(unix)]\n/// Converts a full version Ruby shebang to use the minor version symlink.\n/// e.g., `/home/user/.mise/installs/ruby/3.1.0/bin/ruby` → `/home/user/.mise/installs/ruby/3.1/bin/ruby`\nfn to_minor_version_shebang(ruby_path: &str) -> Option<String> {\n    let ruby_installs = env::MISE_INSTALLS_DIR.join(\"ruby\");\n    let ruby_installs_str = ruby_installs.to_string_lossy();\n\n    // Check if path matches pattern: {installs}/ruby/{version}/bin/ruby\n    let path = Path::new(ruby_path);\n    let rel_path = path.strip_prefix(&ruby_installs).ok()?;\n    let mut components = rel_path.components();\n\n    // First component should be the version (e.g., \"3.1.0\")\n    let version_component = components.next()?.as_os_str().to_string_lossy();\n    let version_str = version_component.as_ref();\n\n    // Extract minor version (e.g., \"3.1.0\" → \"3.1\")\n    let minor_version = extract_minor_version(version_str)?;\n\n    // Reconstruct the path with minor version\n    let remaining: std::path::PathBuf = components.collect();\n    Some(format!(\n        \"{}/{}/{}\",\n        ruby_installs_str,\n        minor_version,\n        remaining.display()\n    ))\n}\n\n#[cfg(any(unix, test))]\n/// Extracts major.minor from a version string.\n/// e.g., \"3.1.0\" → \"3.1\", \"3.2.1-preview1\" → \"3.2\"\nfn extract_minor_version(version: &str) -> Option<String> {\n    let parts: Vec<&str> = version.split('.').collect();\n    if parts.len() >= 2 {\n        Some(format!(\"{}.{}\", parts[0], parts[1]))\n    } else {\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_extract_minor_version() {\n        assert_eq!(extract_minor_version(\"3.1.0\"), Some(\"3.1\".to_string()));\n        assert_eq!(extract_minor_version(\"3.2.1\"), Some(\"3.2\".to_string()));\n        assert_eq!(\n            extract_minor_version(\"3.1.0-preview1\"),\n            Some(\"3.1\".to_string())\n        );\n        assert_eq!(extract_minor_version(\"2.7.8\"), Some(\"2.7\".to_string()));\n        assert_eq!(extract_minor_version(\"3\"), None);\n        assert_eq!(extract_minor_version(\"latest\"), None);\n    }\n}\n"
  },
  {
    "path": "src/backend/github.rs",
    "content": "use crate::backend::SecurityFeature;\nuse crate::backend::VersionInfo;\nuse crate::backend::asset_matcher::{self, Asset, AssetPicker, ChecksumFetcher};\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::{\n    get_filename_from_url, install_artifact, lookup_platform_key, lookup_platform_key_for_target,\n    template_string, try_with_v_prefix, try_with_v_prefix_and_repo, verify_artifact,\n};\nuse crate::cli::args::{BackendArg, ToolVersionType};\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::file;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::{PlatformInfo, ProvenanceType};\nuse crate::toolset::ToolVersionOptions;\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse crate::{backend::Backend, forgejo, github, gitlab};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse regex::Regex;\nuse std::collections::{BTreeMap, HashMap};\nuse std::fmt::Debug;\nuse std::sync::Arc;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct UnifiedGitBackend {\n    ba: Arc<BackendArg>,\n}\n\nstruct ReleaseAsset {\n    name: String,\n    url: String,\n    url_api: String,\n    digest: Option<String>,\n}\n\nconst DEFAULT_GITHUB_API_BASE_URL: &str = \"https://api.github.com\";\nconst DEFAULT_GITLAB_API_BASE_URL: &str = \"https://gitlab.com/api/v4\";\nconst DEFAULT_FORGEJO_API_BASE_URL: &str = \"https://codeberg.org/api/v1\";\n\n/// Status returned from verification attempts\nenum VerificationStatus {\n    /// No attestations or provenance found (not an error, tool may not have them)\n    NoAttestations,\n    /// An error occurred during verification\n    Error(String),\n}\n\n/// Check if an SLSA verification error indicates a format/parsing issue rather than\n/// an actual verification failure. Some provenance files (e.g., BuildKit raw provenance)\n/// exist but aren't in a sigstore-verifiable format.\nfn is_slsa_format_issue(e: &sigstore_verification::AttestationError) -> bool {\n    match e {\n        sigstore_verification::AttestationError::NoAttestations => true,\n        sigstore_verification::AttestationError::Verification(msg) => {\n            msg.contains(\"does not contain valid attestations\")\n                || msg.contains(\"No certificate found\")\n                || msg.contains(\"neither DSSE envelope nor message signature\")\n        }\n        _ => false,\n    }\n}\n\n/// Returns install-time-only option keys for GitHub/GitLab backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\n        \"asset_pattern\".into(),\n        \"url\".into(),\n        \"version_prefix\".into(),\n        \"no_app\".into(),\n    ]\n}\n\n#[async_trait]\nimpl Backend for UnifiedGitBackend {\n    fn get_type(&self) -> BackendType {\n        if self.is_gitlab() {\n            BackendType::Gitlab\n        } else if self.is_forgejo() {\n            BackendType::Forgejo\n        } else {\n            BackendType::Github\n        }\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<SecurityFeature> {\n        // Only report security features for GitHub (not GitLab yet)\n        if self.is_gitlab() || self.is_forgejo() {\n            return vec![];\n        }\n\n        let mut features = vec![];\n\n        // Get the latest release to check for security assets\n        let repo = self.ba.tool_name();\n        let opts = self.ba.opts();\n        let api_url = self.get_api_url(&opts);\n\n        let releases = github::list_releases_from_url(api_url.as_str(), &repo)\n            .await\n            .unwrap_or_default();\n\n        let latest_release = releases.first();\n\n        // Check for checksum files in assets\n        if let Some(release) = latest_release {\n            let has_checksum = release.assets.iter().any(|a| {\n                let name = a.name.to_lowercase();\n                name.contains(\"sha256\")\n                    || name.contains(\"checksum\")\n                    || name.ends_with(\".sha256\")\n                    || name.ends_with(\".sha512\")\n            });\n            if has_checksum {\n                features.push(SecurityFeature::Checksum {\n                    algorithm: Some(\"sha256\".to_string()),\n                });\n            }\n        }\n\n        // Check for GitHub artifact Attestations (assets with .sigstore.json or .sigstore extension)\n        if let Some(release) = latest_release {\n            let has_attestations = release.assets.iter().any(|a| {\n                let name = a.name.to_lowercase();\n                name.ends_with(\".sigstore.json\") || name.ends_with(\".sigstore\")\n            });\n            if has_attestations {\n                features.push(SecurityFeature::GithubAttestations {\n                    signer_workflow: None,\n                });\n            }\n        }\n\n        // Check for SLSA provenance (intoto.jsonl files)\n        if let Some(release) = latest_release {\n            let has_slsa = release.assets.iter().any(|a| {\n                let name = a.name.to_lowercase();\n                name.contains(\".intoto.jsonl\")\n                    || name.contains(\"provenance\")\n                    || name.ends_with(\".attestation\")\n            });\n            if has_slsa {\n                features.push(SecurityFeature::Slsa { level: None });\n            }\n        }\n\n        features\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let repo = self.ba.tool_name();\n        let id = self.ba.to_string();\n        let opts = config\n            .get_tool_opts(&self.ba)\n            .await?\n            .unwrap_or_else(|| self.ba.opts());\n        let api_url = self.get_api_url(&opts);\n        let version_prefix = opts.get(\"version_prefix\");\n\n        // Derive web URL base from API URL for enterprise support\n        let web_url_base = if self.is_gitlab() {\n            if api_url == DEFAULT_GITLAB_API_BASE_URL {\n                format!(\"https://gitlab.com/{}\", repo)\n            } else {\n                // Enterprise GitLab - derive web URL from API URL\n                let web_url = api_url.replace(\"/api/v4\", \"\");\n                format!(\"{}/{}\", web_url, repo)\n            }\n        } else if self.is_forgejo() {\n            if api_url == DEFAULT_FORGEJO_API_BASE_URL {\n                format!(\"https://codeberg.org/{}\", repo)\n            } else {\n                // Enterprise Forgejo - derive web URL from API URL\n                let web_url = api_url.replace(\"/api/v1\", \"\");\n                format!(\"{}/{}\", web_url, repo)\n            }\n        } else if api_url == DEFAULT_GITHUB_API_BASE_URL {\n            format!(\"https://github.com/{}\", repo)\n        } else {\n            // Enterprise GitHub - derive web URL from API URL\n            let web_url = api_url.replace(\"/api/v3\", \"\").replace(\"api.\", \"\");\n            format!(\"{}/{}\", web_url, repo)\n        };\n\n        // Get releases with full metadata from GitHub or GitLab\n        let raw_versions: Vec<VersionInfo> = if self.is_gitlab() {\n            gitlab::list_releases_from_url(api_url.as_str(), &repo)\n                .await?\n                .into_iter()\n                .filter(|r| version_prefix.is_none_or(|p| r.tag_name.starts_with(p)))\n                .map(|r| VersionInfo {\n                    version: self.strip_version_prefix(&r.tag_name, &opts),\n                    created_at: r.released_at,\n                    release_url: Some(format!(\"{}/-/releases/{}\", web_url_base, r.tag_name)),\n                    ..Default::default()\n                })\n                .collect()\n        } else if self.is_forgejo() {\n            forgejo::list_releases_from_url(api_url.as_str(), &repo)\n                .await?\n                .into_iter()\n                .filter(|r| version_prefix.is_none_or(|p| r.tag_name.starts_with(p)))\n                .map(|r| VersionInfo {\n                    version: self.strip_version_prefix(&r.tag_name, &opts),\n                    created_at: Some(r.created_at),\n                    release_url: Some(format!(\"{}/releases/tag/{}\", web_url_base, r.tag_name)),\n                    ..Default::default()\n                })\n                .collect()\n        } else {\n            github::list_releases_from_url(api_url.as_str(), &repo)\n                .await?\n                .into_iter()\n                .filter(|r| version_prefix.is_none_or(|p| r.tag_name.starts_with(p)))\n                .map(|r| VersionInfo {\n                    version: self.strip_version_prefix(&r.tag_name, &opts),\n                    created_at: Some(r.created_at),\n                    release_url: Some(format!(\"{}/releases/tag/{}\", web_url_base, r.tag_name)),\n                    ..Default::default()\n                })\n                .collect()\n        };\n\n        // Apply common validation and reverse order\n        let versions = raw_versions\n            .into_iter()\n            .filter(|v| match v.version.parse::<ToolVersionType>() {\n                Ok(ToolVersionType::Version(_)) => true,\n                _ => {\n                    warn!(\"Invalid version: {id}@{}\", v.version);\n                    false\n                }\n            })\n            .rev()\n            .collect();\n\n        Ok(versions)\n    }\n\n    async fn latest_stable_version(&self, config: &Arc<Config>) -> eyre::Result<Option<String>> {\n        if Settings::get().offline() {\n            trace!(\"Skipping latest stable version due to offline mode\");\n            return Ok(None);\n        }\n\n        let repo = self.ba.tool_name();\n        let opts = config\n            .get_tool_opts(&self.ba)\n            .await?\n            .unwrap_or_else(|| self.ba.opts());\n        let api_url = self.get_api_url(&opts);\n        let version_prefix = opts.get(\"version_prefix\");\n\n        let latest_tag = if self.is_gitlab() {\n            // GitLab doesn't have a \"latest\" endpoint\n            return self.latest_version(config, Some(\"latest\".into())).await;\n        } else if self.is_forgejo() {\n            match forgejo::get_release_for_url(&api_url, &repo, \"latest\").await {\n                Ok(r) => Some(r.tag_name),\n                Err(e) => {\n                    debug!(\"Failed to fetch latest Forgejo release for {repo}: {e}\");\n                    None\n                }\n            }\n        } else {\n            match github::get_release_for_url(&api_url, &repo, \"latest\").await {\n                Ok(r) => Some(r.tag_name),\n                Err(e) => {\n                    debug!(\"Failed to fetch latest GitHub release for {repo}: {e}\");\n                    None\n                }\n            }\n        };\n\n        let latest_version = latest_tag\n            .filter(|tag| version_prefix.is_none_or(|p| tag.starts_with(p)))\n            .map(|tag| self.strip_version_prefix(&tag, &opts));\n\n        match latest_version {\n            Some(version) => Ok(Some(version)),\n            None => self.latest_version(config, Some(\"latest\".into())).await,\n        }\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let repo = self.repo();\n        let opts = ctx\n            .config\n            .get_tool_opts(&self.ba)\n            .await?\n            .unwrap_or_else(|| self.ba.opts());\n        let api_url = self.get_api_url(&opts);\n\n        // Check if URL already exists in lockfile platforms first\n        let platform_key = self.get_platform_key();\n\n        let asset = if let Some(existing_platform) = tv.lock_platforms.get(&platform_key)\n            && existing_platform.url.is_some()\n        {\n            debug!(\n                \"Using existing URL from lockfile for platform {}: {}\",\n                platform_key,\n                existing_platform.url.clone().unwrap_or_default()\n            );\n            ReleaseAsset {\n                name: get_filename_from_url(existing_platform.url.as_deref().unwrap_or(\"\")),\n                url: existing_platform.url.clone().unwrap_or_default(),\n                url_api: existing_platform.url_api.clone().unwrap_or_default(),\n                digest: None, // Don't use old digest from lockfile, will be fetched fresh if needed\n            }\n        } else {\n            // Find the asset URL for this specific version\n            self.resolve_asset_url(&tv, &opts, &repo, &api_url).await?\n        };\n\n        // Download and install\n        self.download_and_install(ctx, &mut tv, &asset, &opts)\n            .await?;\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<std::path::PathBuf>> {\n        if self.get_filter_bins(tv).is_some() {\n            return Ok(vec![tv.install_path().join(\".mise-bins\")]);\n        }\n\n        self.discover_bin_paths(tv)\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let opts = request.options();\n        let mut result = BTreeMap::new();\n\n        // These options affect which artifact is downloaded\n        for key in [\"asset_pattern\", \"url\", \"version_prefix\"] {\n            if let Some(value) = opts.get(key) {\n                result.insert(key.to_string(), value.to_string());\n            }\n        }\n\n        result\n    }\n\n    /// Resolve platform-specific lock information for cross-platform lockfile generation.\n    /// This fetches release asset metadata including SHA256 digests from GitHub/GitLab API.\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let repo = self.repo();\n        let opts = tv.request.options();\n        let api_url = self.get_api_url(&opts);\n\n        // Resolve asset for the target platform\n        let asset = self\n            .resolve_asset_url_for_target(tv, &opts, &repo, &api_url, target)\n            .await;\n\n        match asset {\n            Ok(asset) => {\n                // Detect provenance availability from release assets and attestation API\n                let provenance = if !self.is_gitlab() && !self.is_forgejo() {\n                    self.detect_provenance_type(\n                        tv,\n                        &opts,\n                        &repo,\n                        &api_url,\n                        asset.digest.as_deref(),\n                        target,\n                    )\n                    .await\n                } else {\n                    None\n                };\n\n                Ok(PlatformInfo {\n                    url: Some(asset.url),\n                    url_api: Some(asset.url_api),\n                    checksum: asset.digest,\n                    provenance,\n                    ..Default::default()\n                })\n            }\n            Err(e) => {\n                debug!(\n                    \"Failed to resolve asset for {} on {}: {}\",\n                    self.ba.full(),\n                    target.to_key(),\n                    e\n                );\n                Ok(PlatformInfo::default())\n            }\n        }\n    }\n}\n\nimpl UnifiedGitBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    /// Detect what provenance type is available for a release by checking its assets\n    /// and querying the GitHub attestation API.\n    async fn detect_provenance_type(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n        asset_digest: Option<&str>,\n        target: &PlatformTarget,\n    ) -> Option<ProvenanceType> {\n        let settings = Settings::get();\n        let version = &tv.version;\n        let version_prefix = opts.get(\"version_prefix\");\n\n        let release =\n            try_with_v_prefix_and_repo(version, version_prefix, Some(repo), |candidate| {\n                let api_url = api_url.to_string();\n                let repo = repo.to_string();\n                async move { github::get_release_for_url(&api_url, &repo, &candidate).await }\n            })\n            .await\n            .ok()?;\n\n        // Check github-attestations first (higher priority, matching install verification order)\n        // Uses the asset digest from the GitHub API to query attestations without downloading\n        if settings.github_attestations\n            && settings.github.github_attestations\n            && let Some(digest) = asset_digest\n        {\n            let parts: Vec<&str> = repo.split('/').collect();\n            if parts.len() == 2 {\n                let (owner, repo_name) = (parts[0], parts[1]);\n                match sigstore_verification::sources::github::GitHubSource::new(\n                    owner,\n                    repo_name,\n                    env::GITHUB_TOKEN.as_deref(),\n                ) {\n                    Ok(source) => {\n                        use sigstore_verification::AttestationSource;\n                        let artifact_ref = sigstore_verification::ArtifactRef::from_digest(digest);\n                        match source.fetch_attestations(&artifact_ref).await {\n                            Ok(attestations) if !attestations.is_empty() => {\n                                return Some(ProvenanceType::GithubAttestations);\n                            }\n                            Ok(_) => {}\n                            Err(e) => {\n                                warn!(\n                                    \"GitHub attestation API query failed for {owner}/{repo_name}: {e}. \\\n                                     Lockfile may not record github-attestations provenance.\"\n                                );\n                            }\n                        }\n                    }\n                    Err(e) => {\n                        warn!(\n                            \"Failed to create GitHub attestation source for {owner}/{repo_name}: {e}. \\\n                             Lockfile may not record github-attestations provenance.\"\n                        );\n                    }\n                }\n            }\n        }\n\n        // Check for SLSA provenance from release assets using the same platform-aware\n        // picker as install-time verification. This ensures we only record SLSA provenance\n        // when a matching provenance file exists for the target platform.\n        if settings.slsa && settings.github.slsa {\n            let asset_names: Vec<String> = release.assets.iter().map(|a| a.name.clone()).collect();\n            let picker = AssetPicker::with_libc(\n                target.os_name().to_string(),\n                target.arch_name().to_string(),\n                target.qualifier().map(|s| s.to_string()),\n            );\n            if picker.pick_best_provenance(&asset_names).is_some() {\n                return Some(ProvenanceType::Slsa { url: None });\n            }\n        }\n\n        None\n    }\n\n    fn is_gitlab(&self) -> bool {\n        self.ba.backend_type() == BackendType::Gitlab\n    }\n\n    fn is_forgejo(&self) -> bool {\n        self.ba.backend_type() == BackendType::Forgejo\n    }\n\n    fn repo(&self) -> String {\n        // Use tool_name() method to properly resolve aliases\n        // This ensures that when an alias like \"test-edit = github:microsoft/edit\" is used,\n        // the repository name is correctly extracted as \"microsoft/edit\"\n        self.ba.tool_name()\n    }\n\n    // Helper to format asset names for error messages\n    fn format_asset_list<'a, I>(assets: I) -> String\n    where\n        I: Iterator<Item = &'a String>,\n    {\n        assets.cloned().collect::<Vec<_>>().join(\", \")\n    }\n\n    fn get_api_url(&self, opts: &ToolVersionOptions) -> String {\n        opts.get(\"api_url\")\n            .unwrap_or(if self.is_gitlab() {\n                DEFAULT_GITLAB_API_BASE_URL\n            } else if self.is_forgejo() {\n                DEFAULT_FORGEJO_API_BASE_URL\n            } else {\n                DEFAULT_GITHUB_API_BASE_URL\n            })\n            .to_string()\n    }\n\n    /// Downloads and installs the asset\n    async fn download_and_install(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        asset: &ReleaseAsset,\n        opts: &ToolVersionOptions,\n    ) -> Result<()> {\n        let filename = asset.name.clone();\n        let file_path = tv.download_path().join(&filename);\n\n        // Check if we'll verify checksum\n        let has_checksum = lookup_platform_key(opts, \"checksum\")\n            .or_else(|| opts.get(\"checksum\").map(|s| s.to_string()))\n            .is_some();\n\n        // Store the asset URL and digest (if available) in the tool version\n        let platform_key = self.get_platform_key();\n        let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n        platform_info.url = Some(asset.url.clone());\n        platform_info.url_api = Some(asset.url_api.clone());\n        if let Some(digest) = &asset.digest {\n            debug!(\"using GitHub API digest for checksum verification\");\n            platform_info.checksum = Some(digest.clone());\n        }\n\n        let url = match asset.url_api.starts_with(DEFAULT_GITHUB_API_BASE_URL)\n            || asset.url_api.starts_with(DEFAULT_GITLAB_API_BASE_URL)\n            || asset.url_api.starts_with(DEFAULT_FORGEJO_API_BASE_URL)\n        {\n            // check if url is reachable, 404 might indicate a private repo or asset.\n            // This is needed, because private repos and assets cannot be downloaded\n            // via browser url, therefore a fallback to api_url is needed in such cases.\n            // Also check Content-Type - if it's text/html, we got a login page (private repo).\n            true => match HTTP.head(asset.url.clone()).await {\n                Ok(resp) => {\n                    let content_type = resp\n                        .headers()\n                        .get(\"content-type\")\n                        .and_then(|v| v.to_str().ok())\n                        .unwrap_or(\"\");\n                    if content_type.contains(\"text/html\") {\n                        debug!(\"Browser URL returned HTML (likely auth page), using API URL\");\n                        asset.url_api.clone()\n                    } else {\n                        asset.url.clone()\n                    }\n                }\n                Err(_) => asset.url_api.clone(),\n            },\n\n            // Custom API URLs usually imply that a custom GitHub/GitLab instance is used.\n            // Often times such instances do not allow browser URL downloads, e.g. due to\n            // upstream company SSOs. Therefore, using the api_url for downloading is the safer approach.\n            false => {\n                debug!(\n                    \"Since the tool resides on a custom GitHub/GitLab API ({:?}), the asset download will be performed using the given API instead of browser URL download\",\n                    asset.url_api\n                );\n                asset.url_api.clone()\n            }\n        };\n\n        let headers = if self.is_gitlab() {\n            gitlab::get_headers(&url)\n        } else if self.is_forgejo() {\n            forgejo::get_headers(&url)\n        } else {\n            github::get_headers(&url)\n        };\n\n        ctx.pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file_with_headers(url, &file_path, &headers, Some(ctx.pr.as_ref()))\n            .await?;\n\n        // Verify and install\n        ctx.pr.next_operation();\n        if has_checksum {\n            verify_artifact(tv, &file_path, opts, Some(ctx.pr.as_ref()))?;\n        }\n        self.verify_checksum(ctx, tv, &file_path)?;\n\n        // Verify attestations or SLSA (check attestations first, fall back to SLSA)\n        let provenance_result = self\n            .verify_attestations_or_slsa(ctx, tv, &file_path)\n            .await?;\n\n        // Record provenance verification result in lock_platforms\n        if let Some(provenance_type) = provenance_result {\n            let platform_key = self.get_platform_key();\n            let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n            platform_info.provenance = Some(provenance_type);\n        }\n\n        ctx.pr.next_operation();\n        install_artifact(tv, &file_path, opts, Some(ctx.pr.as_ref()))?;\n\n        if let Some(bins) = self.get_filter_bins(tv) {\n            self.create_symlink_bin_dir(tv, bins)?;\n        }\n\n        Ok(())\n    }\n\n    /// Discovers bin paths in the installation directory\n    fn discover_bin_paths(&self, tv: &ToolVersion) -> Result<Vec<std::path::PathBuf>> {\n        let opts = tv.request.options();\n        if let Some(bin_path_template) = lookup_platform_key(&opts, \"bin_path\")\n            .or_else(|| opts.get(\"bin_path\").map(|s| s.to_string()))\n        {\n            let bin_path = template_string(&bin_path_template, tv);\n            return Ok(vec![tv.install_path().join(&bin_path)]);\n        }\n\n        let bin_path = tv.install_path().join(\"bin\");\n        if bin_path.exists() {\n            return Ok(vec![bin_path]);\n        }\n\n        // Check for macOS .app bundle structure at root (happens when auto-strip removed .app wrapper)\n        // Look for Contents/MacOS/ which indicates a stripped .app bundle\n        let contents_macos = tv.install_path().join(\"Contents\").join(\"MacOS\");\n        if contents_macos.is_dir() {\n            return Ok(vec![contents_macos]);\n        }\n\n        // Check if the root directory contains an executable file\n        // If so, use the root directory as a bin path\n        if let Ok(entries) = std::fs::read_dir(tv.install_path()) {\n            for entry in entries.flatten() {\n                let path = entry.path();\n                if path.is_file() && file::is_executable(&path) {\n                    return Ok(vec![tv.install_path()]);\n                }\n            }\n        }\n\n        // Look for bin directory or executables in subdirectories (for extracted archives)\n        let mut paths = Vec::new();\n        if let Ok(entries) = std::fs::read_dir(tv.install_path()) {\n            for entry in entries.flatten() {\n                let path = entry.path();\n                if path.is_dir() {\n                    // Check for macOS .app bundles (e.g., SwiftFormat.app/Contents/MacOS/)\n                    let path_str = path.file_name().unwrap_or_default().to_string_lossy();\n                    if path_str.ends_with(\".app\") {\n                        let macos_dir = path.join(\"Contents\").join(\"MacOS\");\n                        if macos_dir.is_dir() {\n                            paths.push(macos_dir);\n                            continue;\n                        }\n                    }\n                    // Check for {subdir}/bin\n                    let sub_bin_path = path.join(\"bin\");\n                    if sub_bin_path.exists() {\n                        paths.push(sub_bin_path);\n                    } else {\n                        // Check for executables directly in subdir (e.g., tusd_darwin_arm64/tusd)\n                        if let Ok(sub_entries) = std::fs::read_dir(&path) {\n                            for sub_entry in sub_entries.flatten() {\n                                let sub_path = sub_entry.path();\n                                if sub_path.is_file() && file::is_executable(&sub_path) {\n                                    paths.push(path.clone());\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        if paths.is_empty() {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(paths)\n        }\n    }\n\n    /// Resolves the asset URL using either explicit patterns or auto-detection.\n    /// Delegates to resolve_asset_url_for_target with the current platform.\n    async fn resolve_asset_url(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n    ) -> Result<ReleaseAsset> {\n        let current_platform = PlatformTarget::from_current();\n        self.resolve_asset_url_for_target(tv, opts, repo, api_url, &current_platform)\n            .await\n    }\n\n    /// Resolves asset URL for a specific target platform (for cross-platform lockfile generation)\n    async fn resolve_asset_url_for_target(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n        target: &PlatformTarget,\n    ) -> Result<ReleaseAsset> {\n        // Check for direct platform-specific URLs first\n        if let Some(direct_url) = lookup_platform_key_for_target(opts, \"url\", target) {\n            return Ok(ReleaseAsset {\n                name: get_filename_from_url(&direct_url),\n                url: direct_url.clone(),\n                url_api: direct_url.clone(),\n                digest: None, // Direct URLs don't have API digest\n            });\n        }\n\n        let version = &tv.version;\n        let version_prefix = opts.get(\"version_prefix\");\n        if self.is_gitlab() {\n            try_with_v_prefix(version, version_prefix, |candidate| async move {\n                self.resolve_gitlab_asset_url_for_target(\n                    tv, opts, repo, api_url, &candidate, target,\n                )\n                .await\n            })\n            .await\n        } else if self.is_forgejo() {\n            try_with_v_prefix(version, version_prefix, |candidate| async move {\n                self.resolve_forgejo_asset_url_for_target(\n                    tv, opts, repo, api_url, &candidate, target,\n                )\n                .await\n            })\n            .await\n        } else {\n            // Pass full repo for trying reponame@version formats\n            try_with_v_prefix_and_repo(\n                version,\n                version_prefix,\n                Some(repo),\n                |candidate| async move {\n                    self.resolve_github_asset_url_for_target(\n                        tv, opts, repo, api_url, &candidate, target,\n                    )\n                    .await\n                },\n            )\n            .await\n        }\n    }\n\n    /// Resolves GitHub asset URL for a specific target platform\n    async fn resolve_github_asset_url_for_target(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n        version: &str,\n        target: &PlatformTarget,\n    ) -> Result<ReleaseAsset> {\n        let release = github::get_release_for_url(api_url, repo, version).await?;\n        let available_assets: Vec<String> = release.assets.iter().map(|a| a.name.clone()).collect();\n\n        // Build asset list with URLs for checksum fetching\n        let assets_with_urls: Vec<Asset> = release\n            .assets\n            .iter()\n            .map(|a| Asset::new(&a.name, &a.browser_download_url))\n            .collect();\n\n        // Try explicit pattern first\n        if let Some(pattern) = lookup_platform_key_for_target(opts, \"asset_pattern\", target)\n            .or_else(|| opts.get(\"asset_pattern\").map(|s| s.to_string()))\n        {\n            // Template the pattern for the target platform\n            let templated_pattern = template_string_for_target(&pattern, tv, target);\n\n            let asset = release\n                .assets\n                .into_iter()\n                .find(|a| self.matches_pattern(&a.name, &templated_pattern))\n                .ok_or_else(|| {\n                    eyre::eyre!(\n                        \"No matching asset found for pattern: {}\\nAvailable assets: {}\",\n                        templated_pattern,\n                        Self::format_asset_list(available_assets.iter())\n                    )\n                })?;\n\n            // Try to get checksum from API digest or fetch from release assets\n            let digest = if asset.digest.is_some() {\n                asset.digest\n            } else {\n                self.try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n                    .await\n            };\n\n            return Ok(ReleaseAsset {\n                name: asset.name,\n                url: asset.browser_download_url,\n                url_api: asset.url,\n                digest,\n            });\n        }\n\n        // Fall back to auto-detection for target platform\n        let no_app = opts\n            .get(\"no_app\")\n            .and_then(|v| v.parse::<bool>().ok())\n            .unwrap_or(false);\n        let asset_name = asset_matcher::AssetMatcher::new()\n            .for_target(target)\n            .with_no_app(no_app)\n            .pick_from(&available_assets)?\n            .name;\n        let asset = self\n            .find_asset_case_insensitive(&release.assets, &asset_name, |a| &a.name)\n            .ok_or_else(|| {\n                eyre::eyre!(\n                    \"Auto-detected asset not found: {}\\nAvailable assets: {}\",\n                    asset_name,\n                    Self::format_asset_list(available_assets.iter())\n                )\n            })?;\n\n        // Try to get checksum from API digest or fetch from release assets\n        let digest = if asset.digest.is_some() {\n            asset.digest.clone()\n        } else {\n            self.try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n                .await\n        };\n\n        Ok(ReleaseAsset {\n            name: asset.name.clone(),\n            url: asset.browser_download_url.clone(),\n            url_api: asset.url.clone(),\n            digest,\n        })\n    }\n\n    /// Resolves GitLab asset URL for a specific target platform\n    async fn resolve_gitlab_asset_url_for_target(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n        version: &str,\n        target: &PlatformTarget,\n    ) -> Result<ReleaseAsset> {\n        let release = gitlab::get_release_for_url(api_url, repo, version).await?;\n        let available_assets: Vec<String> = release\n            .assets\n            .links\n            .iter()\n            .map(|a| a.name.clone())\n            .collect();\n\n        // Build asset list with URLs for checksum fetching\n        let assets_with_urls: Vec<Asset> = release\n            .assets\n            .links\n            .iter()\n            .map(|a| Asset::new(&a.name, &a.direct_asset_url))\n            .collect();\n\n        // Try explicit pattern first\n        if let Some(pattern) = lookup_platform_key_for_target(opts, \"asset_pattern\", target)\n            .or_else(|| opts.get(\"asset_pattern\").map(|s| s.to_string()))\n        {\n            // Template the pattern for the target platform\n            let templated_pattern = template_string_for_target(&pattern, tv, target);\n\n            let asset = release\n                .assets\n                .links\n                .into_iter()\n                .find(|a| self.matches_pattern(&a.name, &templated_pattern))\n                .ok_or_else(|| {\n                    eyre::eyre!(\n                        \"No matching asset found for pattern: {}\\nAvailable assets: {}\",\n                        templated_pattern,\n                        Self::format_asset_list(available_assets.iter())\n                    )\n                })?;\n\n            // GitLab doesn't provide digests, so try fetching from release assets\n            let digest = self\n                .try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n                .await;\n\n            return Ok(ReleaseAsset {\n                name: asset.name,\n                url: asset.direct_asset_url.clone(),\n                url_api: asset.url,\n                digest,\n            });\n        }\n\n        // Fall back to auto-detection for target platform\n        let no_app = opts\n            .get(\"no_app\")\n            .and_then(|v| v.parse::<bool>().ok())\n            .unwrap_or(false);\n        let asset_name = asset_matcher::AssetMatcher::new()\n            .for_target(target)\n            .with_no_app(no_app)\n            .pick_from(&available_assets)?\n            .name;\n        let asset = self\n            .find_asset_case_insensitive(&release.assets.links, &asset_name, |a| &a.name)\n            .ok_or_else(|| {\n                eyre::eyre!(\n                    \"Auto-detected asset not found: {}\\nAvailable assets: {}\",\n                    asset_name,\n                    Self::format_asset_list(available_assets.iter())\n                )\n            })?;\n\n        // GitLab doesn't provide digests, so try fetching from release assets\n        let digest = self\n            .try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n            .await;\n\n        Ok(ReleaseAsset {\n            name: asset.name.clone(),\n            url: asset.direct_asset_url.clone(),\n            url_api: asset.url.clone(),\n            digest,\n        })\n    }\n\n    /// Resolves Forgejo asset URL for a specific target platform\n    async fn resolve_forgejo_asset_url_for_target(\n        &self,\n        tv: &ToolVersion,\n        opts: &ToolVersionOptions,\n        repo: &str,\n        api_url: &str,\n        version: &str,\n        target: &PlatformTarget,\n    ) -> Result<ReleaseAsset> {\n        let release = forgejo::get_release_for_url(api_url, repo, version).await?;\n        let available_assets: Vec<String> = release.assets.iter().map(|a| a.name.clone()).collect();\n\n        // Build asset list with URLs for checksum fetching\n        let assets_with_urls: Vec<Asset> = release\n            .assets\n            .iter()\n            .map(|a| Asset::new(&a.name, &a.browser_download_url))\n            .collect();\n\n        // Helper to build API attachment URL\n        let asset_url_api = |asset_uuid: &str| {\n            format!(\n                \"{}/attachments/{}\",\n                api_url.replace(\"/api/v1\", \"\"),\n                asset_uuid\n            )\n        };\n\n        // Try explicit pattern first\n        if let Some(pattern) = lookup_platform_key_for_target(opts, \"asset_pattern\", target)\n            .or_else(|| opts.get(\"asset_pattern\").map(|s| s.to_string()))\n        {\n            // Template the pattern for the target platform\n            let templated_pattern = template_string_for_target(&pattern, tv, target);\n\n            let asset = release\n                .assets\n                .into_iter()\n                .find(|a| self.matches_pattern(&a.name, &templated_pattern))\n                .ok_or_else(|| {\n                    eyre::eyre!(\n                        \"No matching asset found for pattern: {}\\nAvailable assets: {}\",\n                        templated_pattern,\n                        Self::format_asset_list(available_assets.iter())\n                    )\n                })?;\n\n            // Try to get checksum from API digest or fetch from release assets\n            let digest = self\n                .try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n                .await;\n\n            return Ok(ReleaseAsset {\n                name: asset.name,\n                url: asset.browser_download_url,\n                url_api: asset_url_api(&asset.uuid),\n                digest,\n            });\n        }\n\n        // Fall back to auto-detection for target platform\n        let no_app = opts\n            .get(\"no_app\")\n            .and_then(|v| v.parse::<bool>().ok())\n            .unwrap_or(false);\n        let asset_name = asset_matcher::AssetMatcher::new()\n            .for_target(target)\n            .with_no_app(no_app)\n            .pick_from(&available_assets)?\n            .name;\n        let asset = self\n            .find_asset_case_insensitive(&release.assets, &asset_name, |a| &a.name)\n            .ok_or_else(|| {\n                eyre::eyre!(\n                    \"Auto-detected asset not found: {}\\nAvailable assets: {}\",\n                    asset_name,\n                    Self::format_asset_list(available_assets.iter())\n                )\n            })?;\n\n        // Try to get checksum from API digest or fetch from release assets\n        let digest = self\n            .try_fetch_checksum_from_assets(&assets_with_urls, &asset.name)\n            .await;\n\n        Ok(ReleaseAsset {\n            name: asset.name.clone(),\n            url: asset.browser_download_url.clone(),\n            url_api: asset_url_api(&asset.uuid),\n            digest,\n        })\n    }\n\n    fn find_asset_case_insensitive<'a, T>(\n        &self,\n        assets: &'a [T],\n        target_name: &str,\n        get_name: impl Fn(&T) -> &str,\n    ) -> Option<&'a T> {\n        // First try exact match, then case-insensitive\n        assets\n            .iter()\n            .find(|a| get_name(a) == target_name)\n            .or_else(|| {\n                let target_lower = target_name.to_lowercase();\n                assets\n                    .iter()\n                    .find(|a| get_name(a).to_lowercase() == target_lower)\n            })\n    }\n\n    fn matches_pattern(&self, asset_name: &str, pattern: &str) -> bool {\n        // Simple pattern matching - convert glob-like pattern to regex\n        let regex_pattern = pattern\n            .replace(\".\", \"\\\\.\")\n            .replace(\"*\", \".*\")\n            .replace(\"?\", \".\");\n\n        if let Ok(re) = Regex::new(&format!(\"^{regex_pattern}$\")) {\n            re.is_match(asset_name)\n        } else {\n            // Fallback to simple contains check\n            asset_name.contains(pattern)\n        }\n    }\n\n    fn strip_version_prefix(&self, tag_name: &str, opts: &ToolVersionOptions) -> String {\n        // If a custom version_prefix is configured, strip it first\n        if let Some(prefix) = opts.get(\"version_prefix\")\n            && let Some(stripped) = tag_name.strip_prefix(prefix)\n        {\n            return stripped.to_string();\n        }\n\n        // Handle projectname@version format (e.g., \"tectonic@0.15.0\" -> \"0.15.0\")\n        // Only strip if the prefix matches the repo short name or full repo name to ensure\n        // we can reconstruct the tag later during installation. For repos with multiple\n        // packages (e.g., tectonic@ and tectonic_xetex_layout@), users must configure\n        // version_prefix to install packages that don't match the repo name.\n        if let Some(caps) = regex!(r\"^([^@]+)@(\\d.*)$\").captures(tag_name) {\n            let prefix = caps.get(1).unwrap().as_str();\n            let version = caps.get(2).unwrap().as_str();\n            let repo = self.repo();\n            let repo_short_name = repo.split('/').next_back();\n            // Strip if prefix matches repo short name OR full repo name\n            if repo_short_name == Some(prefix) || repo == prefix {\n                return version.to_string();\n            }\n        }\n\n        // Fall back to stripping 'v' prefix\n        if tag_name.starts_with('v') {\n            tag_name.trim_start_matches('v').to_string()\n        } else {\n            tag_name.to_string()\n        }\n    }\n\n    /// Tries to fetch a checksum for an asset from release checksum files.\n    ///\n    /// This method looks for checksum files (SHA256SUMS, *.sha256, etc.) in the release\n    /// assets and attempts to extract the checksum for the target asset.\n    ///\n    /// Returns the checksum in \"sha256:hash\" format if found, None otherwise.\n    async fn try_fetch_checksum_from_assets(\n        &self,\n        assets: &[Asset],\n        asset_name: &str,\n    ) -> Option<String> {\n        let fetcher = ChecksumFetcher::new(assets);\n        match fetcher.fetch_checksum_for(asset_name).await {\n            Some(result) => {\n                debug!(\n                    \"Found checksum for {} from {}: {}\",\n                    asset_name,\n                    result.source_file,\n                    result.to_string_formatted()\n                );\n                Some(result.to_string_formatted())\n            }\n            None => {\n                trace!(\"No checksum file found for {}\", asset_name);\n                None\n            }\n        }\n    }\n\n    fn get_filter_bins(&self, tv: &ToolVersion) -> Option<Vec<String>> {\n        let opts = tv.request.options();\n        let filter_bins = lookup_platform_key(&opts, \"filter_bins\")\n            .or_else(|| opts.get(\"filter_bins\").map(|s| s.to_string()))?;\n\n        Some(\n            filter_bins\n                .split(',')\n                .map(|s| s.trim().to_string())\n                .filter(|s| !s.is_empty())\n                .collect(),\n        )\n    }\n\n    /// Creates a `.mise-bins` directory with symlinks only to the binaries specified in filter_bins.\n    fn create_symlink_bin_dir(&self, tv: &ToolVersion, bins: Vec<String>) -> Result<()> {\n        let symlink_dir = tv.install_path().join(\".mise-bins\");\n        file::create_dir_all(&symlink_dir)?;\n\n        // Find where the actual binaries are\n        let install_path = tv.install_path();\n        let bin_paths = self.discover_bin_paths(tv)?;\n\n        // Collect all possible source directories (install root + discovered bin paths)\n        let mut src_dirs = bin_paths;\n        if !src_dirs.contains(&install_path) {\n            src_dirs.push(install_path);\n        }\n\n        for bin_name in bins {\n            // Find the binary in any of the source directories\n            let mut found = false;\n            for dir in &src_dirs {\n                let src = dir.join(&bin_name);\n                if src.exists() {\n                    let dst = symlink_dir.join(&bin_name);\n                    if !dst.exists() {\n                        file::make_symlink_or_copy(&src, &dst)?;\n                    }\n                    found = true;\n                    break;\n                }\n            }\n\n            if !found {\n                warn!(\n                    \"Could not find binary '{}' in install directories. Available paths: {:?}\",\n                    bin_name, src_dirs\n                );\n            }\n        }\n        Ok(())\n    }\n\n    /// Verify artifact using GitHub artifact attestations or SLSA provenance.\n    /// Tries attestations first, falls back to SLSA if no attestations found.\n    /// If verification is attempted and fails, it's a hard error.\n    ///\n    /// Returns `Ok(Some((type, url)))` if provenance was verified successfully,\n    /// or `Ok(None)` if no provenance was found (not an error).\n    async fn verify_attestations_or_slsa(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        file_path: &std::path::Path,\n    ) -> Result<Option<ProvenanceType>> {\n        let settings = Settings::get();\n\n        // Read the expected provenance from the lockfile. We use .clone() because tv is\n        // &ToolVersion. The result is validated against this expectation at every return\n        // point: successful verification checks type match, and no-verification triggers\n        // a downgrade error.\n        let platform_key = self.get_platform_key();\n        let locked_provenance = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|pi| pi.provenance.clone());\n\n        // Only verify for GitHub repos (not GitLab/Forgejo)\n        if self.is_gitlab() || self.is_forgejo() {\n            if let Some(ref expected) = locked_provenance {\n                return Err(eyre::eyre!(\n                    \"Lockfile requires {expected} provenance for {tv} but verification is not available \\\n                     for GitLab/Forgejo backends. This may indicate a downgrade attack.\"\n                ));\n            }\n            return Ok(None);\n        }\n\n        // When the lockfile specifies a provenance type, only run that specific mechanism\n        let skip_attestations = locked_provenance\n            .as_ref()\n            .is_some_and(|l| !l.is_github_attestations());\n        let skip_slsa = locked_provenance.as_ref().is_some_and(|l| !l.is_slsa());\n\n        // Try GitHub artifact attestations first (if enabled globally and for github backend)\n        if !skip_attestations && settings.github_attestations && settings.github.github_attestations\n        {\n            match self\n                .try_verify_github_attestations(ctx, tv, file_path)\n                .await\n            {\n                Ok(true) => {\n                    // Defense-in-depth: verify the result matches the lockfile expectation\n                    if let Some(ref expected) = locked_provenance\n                        && !expected.is_github_attestations()\n                    {\n                        return Err(eyre::eyre!(\n                            \"Lockfile requires {expected} provenance for {tv} but github-attestations was verified. \\\n                             This may indicate a provenance type mismatch.\"\n                        ));\n                    }\n                    return Ok(Some(ProvenanceType::GithubAttestations));\n                }\n                Ok(false) => {\n                    // Attestations exist but verification failed - hard error\n                    return Err(eyre::eyre!(\n                        \"GitHub artifact attestations verification failed for {tv}\"\n                    ));\n                }\n                Err(VerificationStatus::NoAttestations) => {\n                    // No attestations - fall through to try SLSA\n                    debug!(\"No GitHub artifact attestations found for {tv}, trying SLSA\");\n                }\n                Err(VerificationStatus::Error(e)) => {\n                    // Error during verification - hard error\n                    return Err(eyre::eyre!(\n                        \"GitHub artifact attestations verification error for {tv}: {e}\"\n                    ));\n                }\n            }\n        }\n\n        // Fall back to SLSA provenance (if enabled globally and for github backend)\n        if !skip_slsa && settings.slsa && settings.github.slsa {\n            match self.try_verify_slsa(ctx, tv, file_path).await {\n                Ok((true, provenance_url)) => {\n                    // Defense-in-depth: verify the result matches the lockfile expectation\n                    if let Some(ref expected) = locked_provenance\n                        && !expected.is_slsa()\n                    {\n                        return Err(eyre::eyre!(\n                            \"Lockfile requires {expected} provenance for {tv} but slsa was verified. \\\n                             This may indicate a provenance type mismatch.\"\n                        ));\n                    }\n                    return Ok(Some(ProvenanceType::Slsa {\n                        url: provenance_url,\n                    }));\n                }\n                Ok((false, _)) => {\n                    // Provenance exists but verification failed - hard error\n                    return Err(eyre::eyre!(\"SLSA provenance verification failed for {tv}\"));\n                }\n                Err(VerificationStatus::NoAttestations) => {\n                    // No provenance found - this is fine\n                    debug!(\"No SLSA provenance found for {tv}\");\n                }\n                Err(VerificationStatus::Error(e)) => {\n                    // Error during verification - hard error\n                    return Err(eyre::eyre!(\"SLSA verification error for {tv}: {e}\"));\n                }\n            }\n        }\n\n        // If lockfile recorded provenance but no verification succeeded, it's a downgrade attack\n        if let Some(ref expected) = locked_provenance {\n            return Err(eyre::eyre!(\n                \"Lockfile requires {expected} provenance for {tv} but verification was not performed. \\\n                 This may indicate a downgrade attack. Enable the corresponding verification setting \\\n                 or update the lockfile.\"\n            ));\n        }\n\n        Ok(None)\n    }\n\n    /// Try to verify GitHub artifact attestations. Returns:\n    /// - Ok(true) if attestations exist and verified successfully\n    /// - Ok(false) if attestations exist but verification failed\n    /// - Err(NoAttestations) if no attestations found\n    /// - Err(Error) if an error occurred during verification\n    async fn try_verify_github_attestations(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        file_path: &std::path::Path,\n    ) -> std::result::Result<bool, VerificationStatus> {\n        ctx.pr\n            .set_message(\"verify GitHub artifact attestations\".to_string());\n\n        // Parse owner/repo from the repo string\n        let repo = self.repo();\n        let parts: Vec<&str> = repo.split('/').collect();\n        if parts.len() != 2 {\n            return Err(VerificationStatus::Error(format!(\n                \"Invalid repo format: {repo}\"\n            )));\n        }\n        let (owner, repo_name) = (parts[0], parts[1]);\n\n        match sigstore_verification::verify_github_attestation(\n            file_path,\n            owner,\n            repo_name,\n            env::GITHUB_TOKEN.as_deref(),\n            None, // We don't know the expected workflow\n        )\n        .await\n        {\n            Ok(verified) => {\n                if verified {\n                    ctx.pr\n                        .set_message(\"✓ GitHub artifact attestations verified\".to_string());\n                    debug!(\"GitHub artifact attestations verified successfully for {tv}\");\n                }\n                Ok(verified)\n            }\n            Err(sigstore_verification::AttestationError::NoAttestations) => {\n                Err(VerificationStatus::NoAttestations)\n            }\n            Err(e) => Err(VerificationStatus::Error(e.to_string())),\n        }\n    }\n\n    /// Try to verify SLSA provenance. Returns:\n    /// - Ok((true, Some(url))) if provenance exists and verified successfully\n    /// - Ok((false, _)) if provenance exists but verification failed\n    /// - Err(NoAttestations) if no provenance found\n    /// - Err(Error) if an error occurred during verification\n    async fn try_verify_slsa(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        file_path: &std::path::Path,\n    ) -> std::result::Result<(bool, Option<String>), VerificationStatus> {\n        if self.is_gitlab() || self.is_forgejo() {\n            return Err(VerificationStatus::NoAttestations);\n        }\n\n        ctx.pr.set_message(\"verify SLSA provenance\".to_string());\n\n        // Get the release to find provenance assets\n        let repo = self.repo();\n        let opts = tv.request.options();\n        let api_url = self.get_api_url(&opts);\n        let version = &tv.version;\n\n        // Try to get the release (with version prefix support)\n        let version_prefix = opts.get(\"version_prefix\");\n        let release =\n            match try_with_v_prefix_and_repo(version, version_prefix, Some(&repo), |candidate| {\n                let api_url = api_url.clone();\n                let repo = repo.clone();\n                async move { github::get_release_for_url(&api_url, &repo, &candidate).await }\n            })\n            .await\n            {\n                Ok(r) => r,\n                Err(e) => {\n                    return Err(VerificationStatus::Error(format!(\n                        \"Failed to get release: {e}\"\n                    )));\n                }\n            };\n\n        // Find the best provenance asset for the current platform\n        let asset_names: Vec<String> = release.assets.iter().map(|a| a.name.clone()).collect();\n        let current_platform = PlatformTarget::from_current();\n        let picker = AssetPicker::with_libc(\n            current_platform.os_name().to_string(),\n            current_platform.arch_name().to_string(),\n            current_platform.qualifier().map(|s| s.to_string()),\n        );\n\n        let provenance_name = match picker.pick_best_provenance(&asset_names) {\n            Some(name) => name,\n            None => return Err(VerificationStatus::NoAttestations),\n        };\n\n        let provenance_asset = release\n            .assets\n            .iter()\n            .find(|a| a.name == provenance_name)\n            .expect(\"provenance asset should exist since we found its name\");\n\n        // Download the provenance file\n        let download_dir = tv.download_path();\n        let provenance_path = download_dir.join(&provenance_asset.name);\n\n        ctx.pr\n            .set_message(format!(\"download {}\", provenance_asset.name));\n        if let Err(e) = HTTP\n            .download_file(\n                &provenance_asset.browser_download_url,\n                &provenance_path,\n                Some(ctx.pr.as_ref()),\n            )\n            .await\n        {\n            return Err(VerificationStatus::Error(format!(\n                \"Failed to download provenance: {e}\"\n            )));\n        }\n\n        ctx.pr.set_message(\"verify SLSA provenance\".to_string());\n\n        // Verify the provenance\n        let provenance_download_url = provenance_asset.browser_download_url.clone();\n        match sigstore_verification::verify_slsa_provenance(\n            file_path,\n            &provenance_path,\n            1, // Minimum SLSA level\n        )\n        .await\n        {\n            Ok(verified) => {\n                if verified {\n                    debug!(\"SLSA provenance verified successfully for {tv}\");\n                    Ok((true, Some(provenance_download_url)))\n                } else {\n                    Ok((false, None))\n                }\n            }\n            Err(e) => {\n                if is_slsa_format_issue(&e) {\n                    debug!(\"SLSA provenance file not in verifiable format for {tv}: {e}\");\n                    Err(VerificationStatus::NoAttestations)\n                } else {\n                    Err(VerificationStatus::Error(e.to_string()))\n                }\n            }\n        }\n    }\n}\n\n/// Templates a string pattern with version and target platform values\nfn template_string_for_target(template: &str, tv: &ToolVersion, target: &PlatformTarget) -> String {\n    let version = &tv.version;\n    let os = target.os_name();\n    let arch = target.arch_name();\n\n    // Map to common naming conventions\n    let darwin_os = if os == \"macos\" { \"darwin\" } else { os };\n    let amd64_arch = match arch {\n        \"x64\" => \"amd64\",\n        _ => arch, // arm64 stays as \"arm64\" in amd64/arm64 convention\n    };\n    let x86_64_arch = match arch {\n        \"x64\" => \"x86_64\",\n        \"arm64\" => \"aarch64\",\n        _ => arch,\n    };\n    // GNU-style arch: x64 -> x86_64, arm64 stays arm64 (used by opam, etc.)\n    let gnu_arch = match arch {\n        \"x64\" => \"x86_64\",\n        _ => arch,\n    };\n\n    // Check for legacy {placeholder} syntax (any of the supported placeholders)\n    let has_legacy_placeholder = [\n        \"{version}\",\n        \"{os}\",\n        \"{arch}\",\n        \"{darwin_os}\",\n        \"{amd64_arch}\",\n        \"{x86_64_arch}\",\n        \"{gnu_arch}\",\n    ]\n    .iter()\n    .any(|p| template.contains(p) && !template.contains(&format!(\"{{{p}}}\")));\n\n    if has_legacy_placeholder {\n        deprecated_at!(\n            \"2026.3.0\",\n            \"2027.3.0\",\n            \"legacy-version-template\",\n            \"Use Tera syntax (e.g., {{{{ version }}}}) instead of legacy {{version}} in templates\"\n        );\n        // Legacy support: replace {placeholder} patterns\n        return template\n            .replace(\"{version}\", version)\n            .replace(\"{os}\", os)\n            .replace(\"{arch}\", arch)\n            .replace(\"{darwin_os}\", darwin_os)\n            .replace(\"{amd64_arch}\", amd64_arch)\n            .replace(\"{x86_64_arch}\", x86_64_arch)\n            .replace(\"{gnu_arch}\", gnu_arch);\n    }\n\n    // Use Tera rendering for templates\n    let mut ctx = crate::tera::BASE_CONTEXT.clone();\n    ctx.insert(\"version\", version);\n    ctx.insert(\"os\", os);\n    ctx.insert(\"arch\", arch);\n    ctx.insert(\"darwin_os\", darwin_os);\n    ctx.insert(\"amd64_arch\", amd64_arch);\n    ctx.insert(\"x86_64_arch\", x86_64_arch);\n    ctx.insert(\"gnu_arch\", gnu_arch);\n\n    let mut tera = crate::tera::get_tera(None);\n    // Register target-aware os() and arch() functions that use the target platform\n    // instead of the compile-time platform\n    let make_remapping_fn = |value: String| {\n        move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n            if let Some(s) = args.get(value.as_str()).and_then(|v| v.as_str()) {\n                Ok(tera::Value::String(s.to_string()))\n            } else {\n                Ok(tera::Value::String(value.clone()))\n            }\n        }\n    };\n    tera.register_function(\"os\", make_remapping_fn(os.to_string()));\n    tera.register_function(\"arch\", make_remapping_fn(arch.to_string()));\n\n    match tera.render_str(template, &ctx) {\n        Ok(rendered) => rendered,\n        Err(e) => {\n            warn!(\"Failed to render template '{}': {}\", template, e);\n            template.to_string()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::cli::args::BackendArg;\n\n    fn create_test_backend() -> UnifiedGitBackend {\n        UnifiedGitBackend::from_arg(BackendArg::new(\n            \"github\".to_string(),\n            Some(\"github:test/repo\".to_string()),\n        ))\n    }\n\n    #[test]\n    fn test_pattern_matching() {\n        let backend = create_test_backend();\n        assert!(backend.matches_pattern(\"test-v1.0.0.zip\", \"test-*\"));\n        assert!(!backend.matches_pattern(\"other-v1.0.0.zip\", \"test-*\"));\n    }\n\n    #[test]\n    fn test_version_prefix_functionality() {\n        let backend = create_test_backend();\n        let default_opts = ToolVersionOptions::default();\n\n        // Test with no version prefix configured\n        assert_eq!(\n            backend.strip_version_prefix(\"v1.0.0\", &default_opts),\n            \"1.0.0\"\n        );\n        assert_eq!(\n            backend.strip_version_prefix(\"1.0.0\", &default_opts),\n            \"1.0.0\"\n        );\n\n        // Test projectname@version format - only strips if prefix matches repo name\n        // Backend uses \"github:test/repo\" so repo short name is \"repo\", full name is \"test/repo\"\n        assert_eq!(\n            backend.strip_version_prefix(\"repo@0.15.0\", &default_opts),\n            \"0.15.0\"\n        );\n        assert_eq!(\n            backend.strip_version_prefix(\"repo@1.2.3\", &default_opts),\n            \"1.2.3\"\n        );\n        // Also accepts full repo name as prefix\n        assert_eq!(\n            backend.strip_version_prefix(\"test/repo@2.0.0\", &default_opts),\n            \"2.0.0\"\n        );\n        // Should NOT strip if prefix doesn't match repo name (prevents listing\n        // versions that can't be installed)\n        assert_eq!(\n            backend.strip_version_prefix(\"other_package@0.15.0\", &default_opts),\n            \"other_package@0.15.0\"\n        );\n        // Should not match if part after @ doesn't start with a digit\n        assert_eq!(\n            backend.strip_version_prefix(\"repo@beta\", &default_opts),\n            \"repo@beta\"\n        );\n\n        // Test with custom version prefix\n        let mut opts = ToolVersionOptions::default();\n        opts.opts.insert(\n            \"version_prefix\".to_string(),\n            toml::Value::String(\"release-\".to_string()),\n        );\n\n        assert_eq!(\n            backend.strip_version_prefix(\"release-1.0.0\", &opts),\n            \"1.0.0\"\n        );\n        assert_eq!(backend.strip_version_prefix(\"1.0.0\", &opts), \"1.0.0\");\n    }\n\n    #[test]\n    fn test_find_asset_case_insensitive() {\n        let backend = create_test_backend();\n\n        // Mock asset structs for testing\n        struct TestAsset {\n            name: String,\n        }\n\n        let assets = vec![\n            TestAsset {\n                name: \"tool-1.0.0-linux-x86_64.tar.gz\".to_string(),\n            },\n            TestAsset {\n                name: \"tool-1.0.0-Darwin-x86_64.tar.gz\".to_string(),\n            },\n            TestAsset {\n                name: \"tool-1.0.0-Windows-x86_64.zip\".to_string(),\n            },\n        ];\n\n        // Test exact match (should find immediately)\n        let result =\n            backend.find_asset_case_insensitive(&assets, \"tool-1.0.0-linux-x86_64.tar.gz\", |a| {\n                &a.name\n            });\n        assert!(result.is_some());\n        assert_eq!(result.unwrap().name, \"tool-1.0.0-linux-x86_64.tar.gz\");\n\n        // Test case-insensitive match for Darwin (capital D)\n        let result = backend.find_asset_case_insensitive(\n            &assets,\n            \"tool-1.0.0-darwin-x86_64.tar.gz\", // lowercase 'd'\n            |a| &a.name,\n        );\n        assert!(result.is_some());\n        assert_eq!(result.unwrap().name, \"tool-1.0.0-Darwin-x86_64.tar.gz\");\n\n        // Test case-insensitive match for Windows (capital W)\n        let result = backend.find_asset_case_insensitive(\n            &assets,\n            \"tool-1.0.0-windows-x86_64.zip\", // lowercase 'w'\n            |a| &a.name,\n        );\n        assert!(result.is_some());\n        assert_eq!(result.unwrap().name, \"tool-1.0.0-Windows-x86_64.zip\");\n\n        // Test no match\n        let result =\n            backend.find_asset_case_insensitive(&assets, \"nonexistent-asset.tar.gz\", |a| &a.name);\n        assert!(result.is_none());\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_no_attestations() {\n        let err = sigstore_verification::AttestationError::NoAttestations;\n        assert!(is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_invalid_format() {\n        // This is the exact error from BuildKit raw provenance files parsed line-by-line\n        let err = sigstore_verification::AttestationError::Verification(\n            \"File does not contain valid attestations or SLSA provenance\".to_string(),\n        );\n        assert!(is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_no_certificate() {\n        let err = sigstore_verification::AttestationError::Verification(\n            \"No certificate found in attestation bundle\".to_string(),\n        );\n        assert!(is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_no_dsse_envelope() {\n        let err = sigstore_verification::AttestationError::Verification(\n            \"Bundle has neither DSSE envelope nor message signature\".to_string(),\n        );\n        assert!(is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_real_verification_failure() {\n        // Digest mismatch = real verification failure, NOT a format issue\n        let err = sigstore_verification::AttestationError::Verification(\n            \"Artifact digest mismatch: expected abc123\".to_string(),\n        );\n        assert!(!is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_signature_failure() {\n        // Signature verification failure = real failure, NOT a format issue\n        let err = sigstore_verification::AttestationError::Verification(\n            \"P-256 signature verification failed: invalid signature\".to_string(),\n        );\n        assert!(!is_slsa_format_issue(&err));\n    }\n\n    #[test]\n    fn test_is_slsa_format_issue_api_error() {\n        let err = sigstore_verification::AttestationError::Api(\"connection refused\".to_string());\n        assert!(!is_slsa_format_issue(&err));\n    }\n}\n"
  },
  {
    "path": "src/backend/go.rs",
    "content": "use crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::Config;\nuse crate::config::Settings;\nuse crate::install_context::InstallContext;\nuse crate::timeout;\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse async_trait::async_trait;\nuse itertools::Itertools;\nuse std::collections::BTreeMap;\nuse std::{fmt::Debug, sync::Arc};\nuse xx::regex;\n\n#[derive(Debug)]\npub struct GoBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for GoBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Go\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"go\"])\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        // Check if go is available\n        self.warn_if_dependency_missing(\n            config,\n            \"go\",\n            \"To use go packages with mise, you need to install Go first:\\n\\\n              mise use go@latest\\n\\n\\\n            Or install Go via https://go.dev/dl/\",\n        )\n        .await;\n\n        timeout::run_with_timeout_async(\n            async || {\n                let tool_name = self.tool_name();\n                let parts = tool_name.split('/').collect::<Vec<_>>();\n                let module_root_index = if parts[0] == \"github.com\" {\n                    // Try likely module root index first\n                    if parts.len() >= 3 {\n                        if parts.len() > 3 && regex!(r\"^v\\d+$\").is_match(parts[3]) {\n                            Some(3)\n                        } else {\n                            Some(2)\n                        }\n                    } else {\n                        None\n                    }\n                } else {\n                    None\n                };\n                let indices = module_root_index\n                    .into_iter()\n                    .chain((1..parts.len()).rev())\n                    .unique()\n                    .collect::<Vec<_>>();\n\n                for i in indices {\n                    let mod_path = parts[..=i].join(\"/\");\n                    let res = cmd!(\n                        \"go\",\n                        \"list\",\n                        \"-mod=readonly\",\n                        \"-m\",\n                        \"-versions\",\n                        \"-json\",\n                        mod_path\n                    )\n                    .full_env(self.dependency_env(config).await?)\n                    .read();\n                    if let Ok(raw) = res {\n                        let res = serde_json::from_str::<GoModInfo>(&raw);\n                        if let Ok(mod_info) = res {\n                            // remove the leading v from the versions\n                            let versions = mod_info\n                                .versions\n                                .into_iter()\n                                .map(|v| VersionInfo {\n                                    version: v.trim_start_matches('v').to_string(),\n                                    ..Default::default()\n                                })\n                                .collect();\n                            return Ok(versions);\n                        }\n                    };\n                }\n\n                Ok(vec![])\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        // Check if go is available\n        self.warn_if_dependency_missing(\n            &ctx.config,\n            \"go\",\n            \"To use go packages with mise, you need to install Go first:\\n\\\n              mise use go@latest\\n\\n\\\n            Or install Go via https://go.dev/dl/\",\n        )\n        .await;\n\n        let opts = self.ba.opts();\n\n        let install = async |v| {\n            let mut cmd = CmdLineRunner::new(\"go\").arg(\"install\").arg(\"-mod=readonly\");\n\n            if let Some(tags) = opts.get(\"tags\") {\n                cmd = cmd.arg(\"-tags\").arg(tags);\n            }\n\n            cmd.arg(format!(\"{}@{v}\", self.tool_name()))\n                .with_pr(ctx.pr.as_ref())\n                .envs(self.dependency_env(&ctx.config).await?)\n                .env(\"GOBIN\", tv.install_path().join(\"bin\"))\n                .execute()\n        };\n\n        // try \"v\" prefix if the version starts with semver\n        let use_v = regex!(r\"^\\d+\\.\\d+\\.\\d+\").is_match(&tv.version);\n\n        if use_v {\n            if install(format!(\"v{}\", tv.version)).await.is_err() {\n                warn!(\"Failed to install, trying again without added 'v' prefix\");\n            } else {\n                return Ok(tv);\n            }\n        }\n\n        install(tv.version.clone()).await?;\n\n        Ok(tv)\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let opts = request.options();\n        let mut result = BTreeMap::new();\n\n        // tags affect compilation\n        if let Some(value) = opts.get(\"tags\") {\n            result.insert(\"tags\".to_string(), value.to_string());\n        }\n\n        result\n    }\n}\n\n/// Returns install-time-only option keys for Go backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\"tags\".into()]\n}\n\nimpl GoBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n}\n\n#[derive(Debug, serde::Deserialize)]\n#[serde(rename_all = \"PascalCase\")]\npub struct GoModInfo {\n    versions: Vec<String>,\n}\n"
  },
  {
    "path": "src/backend/http.rs",
    "content": "use crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::static_helpers::{\n    clean_binary_name, get_filename_from_url, list_available_platforms_with_key,\n    lookup_platform_key, rename_executable_in_dir, template_string, verify_artifact,\n};\nuse crate::backend::version_list;\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::config::Settings;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolVersion;\nuse crate::toolset::ToolVersionOptions;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{dirs, file, hash};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse std::fmt::Debug;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::time::{SystemTime, UNIX_EPOCH};\n\n// Constants\nconst HTTP_TARBALLS_DIR: &str = \"http-tarballs\";\nconst METADATA_FILE: &str = \"metadata.json\";\n\n/// Helper to get an option value with platform-specific fallback\nfn get_opt(opts: &ToolVersionOptions, key: &str) -> Option<String> {\n    lookup_platform_key(opts, key).or_else(|| opts.get(key).map(|s| s.to_string()))\n}\n\n/// Metadata stored alongside cached extractions\n#[derive(Debug, Serialize, Deserialize)]\nstruct CacheMetadata {\n    url: String,\n    checksum: Option<String>,\n    size: u64,\n    extracted_at: u64,\n    platform: String,\n}\n\n/// Describes what type of content was extracted to cache\n#[derive(Debug, Clone)]\nenum ExtractionType {\n    /// A single raw file (not an archive) with its filename\n    RawFile { filename: String },\n    /// An archive (tarball, zip, etc.) that was extracted\n    Archive,\n}\n\n/// Information about a downloaded file's format\nstruct FileInfo {\n    /// Path with effective extension (after applying format option)\n    effective_path: PathBuf,\n    /// File extension\n    extension: String,\n    /// Detected archive format\n    format: file::TarFormat,\n    /// Whether this is a compressed single binary (not a tar archive)\n    is_compressed_binary: bool,\n}\n\nimpl FileInfo {\n    /// Analyze a file path and options to determine format information\n    fn new(file_path: &Path, opts: &ToolVersionOptions) -> Self {\n        // Apply format config to determine effective extension\n        let effective_path = if let Some(added_ext) = get_opt(opts, \"format\") {\n            let mut path = file_path.to_path_buf();\n            let current_ext = path.extension().and_then(|e| e.to_str()).unwrap_or(\"\");\n            let new_ext = if current_ext.is_empty() {\n                added_ext\n            } else {\n                format!(\"{}.{}\", current_ext, added_ext)\n            };\n            path.set_extension(new_ext);\n            path\n        } else {\n            file_path.to_path_buf()\n        };\n\n        let file_name = effective_path.file_name().unwrap().to_string_lossy();\n        let format = file::TarFormat::from_file_name(&file_name);\n\n        let extension = format\n            .extension()\n            .map(|s| s.to_string())\n            .unwrap_or_else(|| {\n                effective_path\n                    .extension()\n                    .and_then(|s| s.to_str())\n                    .unwrap_or(\"\")\n                    .to_string()\n            });\n\n        let is_compressed_binary = !format.is_archive() && format != file::TarFormat::Raw;\n\n        Self {\n            effective_path,\n            extension,\n            format,\n            is_compressed_binary,\n        }\n    }\n\n    /// Get the filename portion of the effective path\n    fn file_name(&self) -> String {\n        self.effective_path\n            .file_name()\n            .unwrap()\n            .to_string_lossy()\n            .to_string()\n    }\n\n    /// Get the decompressed name (for compressed binaries)\n    fn decompressed_name(&self) -> String {\n        self.file_name()\n            .trim_end_matches(&format!(\".{}\", self.extension))\n            .to_string()\n    }\n}\n\n#[derive(Debug)]\npub struct HttpBackend {\n    ba: Arc<BackendArg>,\n}\n\nimpl HttpBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    // -------------------------------------------------------------------------\n    // Cache path helpers\n    // -------------------------------------------------------------------------\n\n    /// Get the http-tarballs directory in DATA (survives `mise cache clear`)\n    fn tarballs_dir() -> PathBuf {\n        dirs::DATA.join(HTTP_TARBALLS_DIR)\n    }\n\n    /// Get the path to a specific cache entry\n    fn cache_path(&self, cache_key: &str) -> PathBuf {\n        Self::tarballs_dir().join(cache_key)\n    }\n\n    /// Get the path to the metadata file for a cache entry\n    fn metadata_path(&self, cache_key: &str) -> PathBuf {\n        self.cache_path(cache_key).join(METADATA_FILE)\n    }\n\n    /// Check if a cache entry exists and is valid\n    fn is_cached(&self, cache_key: &str) -> bool {\n        self.cache_path(cache_key).exists() && self.metadata_path(cache_key).exists()\n    }\n\n    // -------------------------------------------------------------------------\n    // Cache key generation\n    // -------------------------------------------------------------------------\n\n    /// Generate a cache key based on file content and extraction options\n    fn cache_key(&self, file_path: &Path, opts: &ToolVersionOptions) -> Result<String> {\n        let checksum = hash::file_hash_blake3(file_path, None)?;\n\n        // Include extraction options that affect output structure\n        // Note: bin_path is NOT included - handled at symlink time for deduplication\n        let mut parts = vec![checksum];\n\n        if let Some(strip) = get_opt(opts, \"strip_components\") {\n            parts.push(format!(\"strip_{strip}\"));\n        }\n\n        // Include rename_exe in cache key since it modifies the extracted content\n        if let Some(rename) = get_opt(opts, \"rename_exe\") {\n            parts.push(format!(\"rename_{rename}\"));\n            // When rename_exe is used, bin_path affects where the rename happens,\n            // so different bin_path values result in different cached content\n            if let Some(bin_path) = get_opt(opts, \"bin_path\") {\n                parts.push(format!(\"binpath_{bin_path}\"));\n            }\n        }\n\n        let key = parts.join(\"_\");\n        debug!(\"Cache key: {}\", key);\n        Ok(key)\n    }\n\n    // -------------------------------------------------------------------------\n    // Filename determination\n    // -------------------------------------------------------------------------\n\n    /// Determine the destination filename for a raw file or compressed binary\n    fn dest_filename(\n        &self,\n        file_path: &Path,\n        file_info: &FileInfo,\n        opts: &ToolVersionOptions,\n    ) -> String {\n        // Check for explicit bin name first\n        if let Some(bin_name) = get_opt(opts, \"bin\") {\n            return bin_name;\n        }\n\n        // Auto-clean the binary name\n        let raw_name = if file_info.is_compressed_binary {\n            file_info.decompressed_name()\n        } else {\n            file_path.file_name().unwrap().to_string_lossy().to_string()\n        };\n\n        clean_binary_name(&raw_name, Some(&self.ba.tool_name))\n    }\n\n    // -------------------------------------------------------------------------\n    // Extraction type detection\n    // -------------------------------------------------------------------------\n\n    /// Detect extraction type from an existing cache directory\n    /// This handles the case where a cache hit occurs but the original extraction\n    /// used different options (e.g., different `bin` name)\n    fn extraction_type_from_cache(&self, cache_key: &str, file_info: &FileInfo) -> ExtractionType {\n        // For archives, we don't need to detect the filename\n        if !file_info.is_compressed_binary && file_info.format != file::TarFormat::Raw {\n            return ExtractionType::Archive;\n        }\n\n        // For raw files, find the actual filename in the cache directory\n        let cache_path = self.cache_path(cache_key);\n        for entry in xx::file::ls(&cache_path).unwrap_or_default() {\n            if let Some(name) = entry.file_name().map(|n| n.to_string_lossy().to_string()) {\n                // Skip metadata file\n                if name != METADATA_FILE {\n                    return ExtractionType::RawFile { filename: name };\n                }\n            }\n        }\n\n        // Fallback: shouldn't happen if cache is valid, but use a sensible default\n        ExtractionType::RawFile {\n            filename: self.ba.tool_name.clone(),\n        }\n    }\n\n    // -------------------------------------------------------------------------\n    // Extraction\n    // -------------------------------------------------------------------------\n\n    /// Extract artifact to cache with atomic rename\n    fn extract_to_cache(\n        &self,\n        tv: &ToolVersion,\n        file_path: &Path,\n        cache_key: &str,\n        url: &str,\n        opts: &ToolVersionOptions,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<ExtractionType> {\n        let cache_path = self.cache_path(cache_key);\n\n        // Ensure parent directory exists\n        file::create_dir_all(Self::tarballs_dir())?;\n\n        // Create unique temp directory for atomic extraction\n        let tmp_path = Self::tarballs_dir().join(format!(\n            \"{}.tmp-{}-{}\",\n            cache_key,\n            std::process::id(),\n            SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis()\n        ));\n\n        // Clean up any stale temp directory\n        if tmp_path.exists() {\n            let _ = file::remove_all(&tmp_path);\n        }\n\n        // Perform extraction\n        let extraction_type = self.extract_artifact(tv, &tmp_path, file_path, opts, pr)?;\n\n        // Atomic replace\n        if cache_path.exists() {\n            file::remove_all(&cache_path)?;\n        }\n        std::fs::rename(&tmp_path, &cache_path)?;\n\n        // Write metadata\n        self.write_metadata(cache_key, url, file_path, opts)?;\n\n        Ok(extraction_type)\n    }\n\n    /// Extract a single artifact to the given directory\n    fn extract_artifact(\n        &self,\n        tv: &ToolVersion,\n        dest: &Path,\n        file_path: &Path,\n        opts: &ToolVersionOptions,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<ExtractionType> {\n        file::create_dir_all(dest)?;\n\n        let file_info = FileInfo::new(file_path, opts);\n\n        if file_info.is_compressed_binary {\n            self.extract_compressed_binary(dest, file_path, &file_info, opts, pr)\n        } else if file_info.format == file::TarFormat::Raw {\n            self.extract_raw_file(dest, file_path, &file_info, opts, pr)\n        } else {\n            self.extract_archive(tv, dest, file_path, &file_info, opts, pr)\n        }\n    }\n\n    /// Extract a compressed binary (gz, xz, bz2, zst)\n    fn extract_compressed_binary(\n        &self,\n        dest: &Path,\n        file_path: &Path,\n        file_info: &FileInfo,\n        opts: &ToolVersionOptions,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<ExtractionType> {\n        let filename = self.dest_filename(file_path, file_info, opts);\n        let dest_file = dest.join(&filename);\n\n        // Report extraction progress (no bytes - we don't know total for extraction)\n        if let Some(pr) = pr {\n            pr.set_message(format!(\"extract {}\", file_info.file_name()));\n        }\n\n        file::untar(\n            file_path,\n            &dest_file,\n            &file::TarOptions {\n                pr,\n                ..file::TarOptions::new(file_info.format)\n            },\n        )?;\n\n        file::make_executable(&dest_file)?;\n        Ok(ExtractionType::RawFile { filename })\n    }\n\n    /// Extract a raw (uncompressed) file\n    fn extract_raw_file(\n        &self,\n        dest: &Path,\n        file_path: &Path,\n        file_info: &FileInfo,\n        opts: &ToolVersionOptions,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<ExtractionType> {\n        let filename = self.dest_filename(file_path, file_info, opts);\n        let dest_file = dest.join(&filename);\n\n        // Report extraction progress (no bytes - we don't know total for extraction)\n        if let Some(pr) = pr {\n            pr.set_message(format!(\"extract {}\", file_info.file_name()));\n        }\n\n        file::copy(file_path, &dest_file)?;\n\n        file::make_executable(&dest_file)?;\n        Ok(ExtractionType::RawFile { filename })\n    }\n\n    /// Extract an archive (tar, zip, etc.)\n    fn extract_archive(\n        &self,\n        tv: &ToolVersion,\n        dest: &Path,\n        file_path: &Path,\n        file_info: &FileInfo,\n        opts: &ToolVersionOptions,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<ExtractionType> {\n        let mut strip_components: Option<usize> =\n            get_opt(opts, \"strip_components\").and_then(|s| s.parse().ok());\n\n        // Auto-detect strip_components=1 for single-directory archives\n        if strip_components.is_none()\n            && get_opt(opts, \"bin_path\").is_none()\n            && file::should_strip_components(file_path, file_info.format).unwrap_or(false)\n        {\n            debug!(\"Auto-detected single directory archive, using strip_components=1\");\n            strip_components = Some(1);\n        }\n\n        let tar_opts = file::TarOptions {\n            format: file_info.format,\n            strip_components: strip_components.unwrap_or(0),\n            pr,\n            preserve_mtime: false,\n        };\n\n        file::untar(file_path, dest, &tar_opts)?;\n\n        // Handle rename_exe option for archives\n        if let Some(rename_to) = get_opt(opts, \"rename_exe\") {\n            // When bin_path is not explicitly set, auto-detect bin/ subdirectory to match\n            // the same logic used by discover_bin_paths() for PATH construction\n            let search_dir = if let Some(bin_path_template) = get_opt(opts, \"bin_path\") {\n                let bin_path = template_string(&bin_path_template, tv);\n                dest.join(&bin_path)\n            } else {\n                let bin_dir = dest.join(\"bin\");\n                if bin_dir.is_dir() {\n                    bin_dir\n                } else {\n                    dest.to_path_buf()\n                }\n            };\n            // rsplit('/') always yields at least one element (the full string if no delimiter)\n            let tool_name = self.ba.tool_name.rsplit('/').next().unwrap();\n            rename_executable_in_dir(&search_dir, &rename_to, Some(tool_name))?;\n        }\n\n        Ok(ExtractionType::Archive)\n    }\n\n    /// Write cache metadata file\n    fn write_metadata(\n        &self,\n        cache_key: &str,\n        url: &str,\n        file_path: &Path,\n        opts: &ToolVersionOptions,\n    ) -> Result<()> {\n        let metadata = CacheMetadata {\n            url: url.to_string(),\n            checksum: get_opt(opts, \"checksum\"),\n            size: file_path.metadata()?.len(),\n            extracted_at: SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(),\n            platform: self.get_platform_key(),\n        };\n\n        let json = serde_json::to_string_pretty(&metadata)?;\n        file::write(self.metadata_path(cache_key), json)?;\n        Ok(())\n    }\n\n    // -------------------------------------------------------------------------\n    // Symlink creation\n    // -------------------------------------------------------------------------\n\n    /// Create install symlink(s) from install directory to cache\n    fn create_install_symlink(\n        &self,\n        tv: &ToolVersion,\n        cache_key: &str,\n        extraction_type: &ExtractionType,\n        opts: &ToolVersionOptions,\n    ) -> Result<()> {\n        let cache_path = self.cache_path(cache_key);\n\n        // Determine version name for install path\n        let version_name = if tv.version == \"latest\" || tv.version.is_empty() {\n            &cache_key[..7.min(cache_key.len())] // Content-based versioning\n        } else {\n            &tv.version\n        };\n\n        let install_path = tv.ba().installs_path.join(version_name);\n\n        // Clean up existing install\n        if install_path.exists() {\n            file::remove_all(&install_path)?;\n        }\n        if let Some(parent) = install_path.parent() {\n            file::create_dir_all(parent)?;\n        }\n\n        // Handle raw files with bin_path specially for deduplication\n        if let ExtractionType::RawFile { filename } = extraction_type\n            && let Some(bin_path_template) = get_opt(opts, \"bin_path\")\n        {\n            let bin_path = template_string(&bin_path_template, tv);\n            let dest_dir = install_path.join(&bin_path);\n            file::create_dir_all(&dest_dir)?;\n\n            let cached_file = cache_path.join(filename);\n            let install_file = dest_dir.join(filename);\n            file::make_symlink(&cached_file, &install_file)?;\n            return Ok(());\n        }\n\n        // Default: symlink entire install path to cache\n        file::make_symlink(&cache_path, &install_path)?;\n        Ok(())\n    }\n\n    /// Create additional symlink for implicit versions (latest, empty)\n    fn create_version_alias_symlink(&self, tv: &ToolVersion, cache_key: &str) -> Result<()> {\n        if tv.version != \"latest\" && !tv.version.is_empty() {\n            return Ok(());\n        }\n\n        let content_version = &cache_key[..7.min(cache_key.len())];\n        let original_path = tv.ba().installs_path.join(&tv.version);\n        let content_path = tv.ba().installs_path.join(content_version);\n\n        if original_path.exists() {\n            file::remove_all(&original_path)?;\n        }\n        if let Some(parent) = original_path.parent() {\n            file::create_dir_all(parent)?;\n        }\n\n        file::make_symlink(&content_path, &original_path)?;\n        Ok(())\n    }\n\n    // -------------------------------------------------------------------------\n    // Checksum verification\n    // -------------------------------------------------------------------------\n\n    /// Verify or generate checksum for lockfile support\n    fn verify_checksum(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        file_path: &Path,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let filename = file_path.file_name().unwrap().to_string_lossy();\n        let lockfile_enabled = settings.lockfile_enabled();\n\n        let platform_key = self.get_platform_key();\n        let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n\n        // Verify or generate checksum\n        if let Some(checksum) = &platform_info.checksum {\n            ctx.pr.set_message(format!(\"checksum {filename}\"));\n            let (algo, check) = checksum\n                .split_once(':')\n                .ok_or_else(|| eyre::eyre!(\"Invalid checksum format: {checksum}\"))?;\n            hash::ensure_checksum(file_path, check, Some(ctx.pr.as_ref()), algo)?;\n        } else if lockfile_enabled {\n            ctx.pr.set_message(format!(\"generate checksum {filename}\"));\n            let h = hash::file_hash_blake3(file_path, Some(ctx.pr.as_ref()))?;\n            platform_info.checksum = Some(format!(\"blake3:{h}\"));\n        }\n\n        // Verify or record size\n        if let Some(expected_size) = platform_info.size {\n            ctx.pr.set_message(format!(\"verify size {filename}\"));\n            let actual_size = file_path.metadata()?.len();\n            if actual_size != expected_size {\n                return Err(eyre::eyre!(\n                    \"Size mismatch for {filename}: expected {expected_size}, got {actual_size}\"\n                ));\n            }\n        } else if lockfile_enabled {\n            platform_info.size = Some(file_path.metadata()?.len());\n        }\n\n        Ok(())\n    }\n\n    // -------------------------------------------------------------------------\n    // Version listing\n    // -------------------------------------------------------------------------\n\n    /// Fetch versions from version_list_url if configured\n    async fn fetch_versions(&self, config: &Arc<Config>) -> Result<Vec<String>> {\n        let opts = if !self.ba.opts().contains_key(\"version_list_url\") {\n            config.get_tool_opts(&self.ba).await?.unwrap_or_default()\n        } else {\n            self.ba.opts()\n        };\n\n        let url = match opts.get(\"version_list_url\") {\n            Some(url) => url.to_string(),\n            None => return Ok(vec![]),\n        };\n\n        let regex = opts.get(\"version_regex\");\n        let json_path = opts.get(\"version_json_path\");\n        let version_expr = opts.get(\"version_expr\");\n\n        version_list::fetch_versions(&url, regex, json_path, version_expr).await\n    }\n}\n\n/// Returns install-time-only option keys for HTTP backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\n        \"url\".into(),\n        \"checksum\".into(),\n        \"version_list_url\".into(),\n        \"version_regex\".into(),\n        \"version_json_path\".into(),\n        \"version_expr\".into(),\n        \"format\".into(),\n        \"rename_exe\".into(),\n    ]\n}\n\n#[async_trait]\nimpl Backend for HttpBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Http\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn install_operation_count(&self, tv: &ToolVersion, _ctx: &InstallContext) -> usize {\n        let opts = tv.request.options();\n        super::http_install_operation_count(\n            get_opt(&opts, \"checksum\").is_some(),\n            &self.get_platform_key(),\n            tv,\n        )\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = self.fetch_versions(config).await?;\n        Ok(versions\n            .into_iter()\n            .map(|v| VersionInfo {\n                version: v,\n                ..Default::default()\n            })\n            .collect())\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let opts = tv.request.options();\n\n        // Get URL template\n        let url_template = get_opt(&opts, \"url\").ok_or_else(|| {\n            let platform_key = self.get_platform_key();\n            let available = list_available_platforms_with_key(&opts, \"url\");\n            if !available.is_empty() {\n                eyre::eyre!(\n                    \"No URL for platform {platform_key}. Available: {}. \\\n                     Provide 'url' or add 'platforms.{platform_key}.url'\",\n                    available.join(\", \")\n                )\n            } else {\n                eyre::eyre!(\"Http backend requires 'url' option\")\n            }\n        })?;\n\n        let url = template_string(&url_template, &tv);\n\n        // Download\n        let filename = get_filename_from_url(&url);\n        let file_path = tv.download_path().join(&filename);\n\n        // Record URL in lock platforms\n        let platform_key = self.get_platform_key();\n        tv.lock_platforms\n            .entry(platform_key.clone())\n            .or_default()\n            .url = Some(url.clone());\n\n        // For lockfile checksum verification\n        let settings = Settings::get();\n        let lockfile_enabled = settings.lockfile_enabled();\n        let has_lockfile_checksum = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|p| p.checksum.as_ref())\n            .is_some();\n\n        ctx.pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&url, &file_path, Some(ctx.pr.as_ref()))\n            .await?;\n\n        // Verify artifact (checksum if provided)\n        if get_opt(&opts, \"checksum\").is_some() {\n            ctx.pr.next_operation();\n        }\n        verify_artifact(&tv, &file_path, &opts, Some(ctx.pr.as_ref()))?;\n\n        // Generate cache key\n        let cache_key = self.cache_key(&file_path, &opts)?;\n        let file_info = FileInfo::new(&file_path, &opts);\n\n        // Acquire lock and extract or reuse cache\n        let cache_path = self.cache_path(&cache_key);\n        let _lock = crate::lock_file::get(&cache_path, ctx.force)?;\n\n        // Determine extraction type based on whether we're using cache or extracting fresh\n        // On cache hit, we need to detect the actual filename from the cache (which may differ\n        // from current options if a previous extraction used different `bin` name)\n        ctx.pr.next_operation();\n        let extraction_type = if self.is_cached(&cache_key) {\n            ctx.pr.set_message(\"using cached tarball\".into());\n            // Report extraction operation as complete (instant since we're using cache)\n            ctx.pr.set_length(1);\n            ctx.pr.set_position(1);\n            self.extraction_type_from_cache(&cache_key, &file_info)\n        } else {\n            ctx.pr.set_message(\"extracting to cache\".into());\n            self.extract_to_cache(\n                &tv,\n                &file_path,\n                &cache_key,\n                &url,\n                &opts,\n                Some(ctx.pr.as_ref()),\n            )?\n        };\n\n        // Create symlinks\n        self.create_install_symlink(&tv, &cache_key, &extraction_type, &opts)?;\n        self.create_version_alias_symlink(&tv, &cache_key)?;\n\n        // Verify checksum for lockfile\n        if lockfile_enabled || has_lockfile_checksum {\n            ctx.pr.next_operation();\n        }\n        self.verify_checksum(ctx, &mut tv, &file_path)?;\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        let opts = tv.request.options();\n\n        // Check for explicit bin_path\n        if let Some(bin_path_template) = get_opt(&opts, \"bin_path\") {\n            let bin_path = template_string(&bin_path_template, tv);\n            return Ok(vec![tv.install_path().join(bin_path)]);\n        }\n\n        // Check for bin directory\n        let bin_dir = tv.install_path().join(\"bin\");\n        if bin_dir.exists() {\n            return Ok(vec![bin_dir]);\n        }\n\n        // Search subdirectories for bin directories\n        let mut paths = Vec::new();\n        if let Ok(entries) = std::fs::read_dir(tv.install_path()) {\n            for entry in entries.flatten() {\n                let path = entry.path();\n                if path.is_dir() {\n                    let sub_bin = path.join(\"bin\");\n                    if sub_bin.exists() {\n                        paths.push(sub_bin);\n                    }\n                }\n            }\n        }\n\n        if paths.is_empty() {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(paths)\n        }\n    }\n}\n"
  },
  {
    "path": "src/backend/jq.rs",
    "content": "/// Simplified jq-like JSON path extraction.\n///\n/// Supports a subset of jq syntax for extracting values from JSON:\n/// - `.` - root value\n/// - `.[]` - iterate over array elements\n/// - `.[].field` - extract field from each array element\n/// - `.field` - extract field from object\n/// - `.field[]` - iterate over array in field\n/// - `.field[].subfield` - extract subfield from array elements\n/// - `.field.subfield` - nested field access\n/// - `.[?field=value]` - filter array elements where field equals value\n/// - `.releases[?channel=stable].version` - filter then extract\n///\n/// Values are extracted as strings, with 'v' prefix stripped from version-like values.\nuse eyre::Result;\n\n/// Extract string values from JSON using a jq-like path expression\n///\n/// # Examples\n/// ```\n/// use mise::backend::jq::extract;\n/// use serde_json::json;\n///\n/// let data = json!([\"1.0.0\", \"2.0.0\"]);\n/// assert_eq!(extract(&data, \".[]\").unwrap(), vec![\"1.0.0\", \"2.0.0\"]);\n///\n/// let data = json!([{\"version\": \"v1.0.0\"}, {\"version\": \"v2.0.0\"}]);\n/// assert_eq!(extract(&data, \".[].version\").unwrap(), vec![\"1.0.0\", \"2.0.0\"]);\n/// ```\npub fn extract(json: &serde_json::Value, path: &str) -> Result<Vec<String>> {\n    let mut results = Vec::new();\n    let path = path.trim();\n\n    // Handle empty path or \".\" as root\n    if path.is_empty() || path == \".\" {\n        extract_values(json, &mut results);\n        return Ok(results);\n    }\n\n    // Remove leading dot if present\n    let path = path.strip_prefix('.').unwrap_or(path);\n\n    // Parse the path and extract values\n    extract_recursive(json, path, &mut results);\n\n    Ok(results)\n}\n\n/// Extract values with auto-detection of common version patterns\npub fn extract_auto(json: &serde_json::Value) -> Vec<String> {\n    let mut results = Vec::new();\n\n    match json {\n        serde_json::Value::String(s) => {\n            let v = normalize_version(s);\n            if !v.is_empty() {\n                results.push(v);\n            }\n        }\n        serde_json::Value::Array(arr) => {\n            for val in arr {\n                if let Some(v) = val.as_str() {\n                    let v = normalize_version(v);\n                    if !v.is_empty() {\n                        results.push(v);\n                    }\n                } else if let Some(obj) = val.as_object() {\n                    // Try common version field names\n                    for field in [\"version\", \"tag_name\", \"name\", \"tag\", \"v\"] {\n                        if let Some(v) = obj.get(field).and_then(|v| v.as_str()) {\n                            let v = normalize_version(v);\n                            if !v.is_empty() {\n                                results.push(v);\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        serde_json::Value::Object(obj) => {\n            // Check for common patterns like {\"versions\": [...]} or {\"releases\": [...]}\n            for field in [\"versions\", \"releases\", \"tags\", \"version\", \"release\"] {\n                if let Some(val) = obj.get(field) {\n                    let extracted = extract_auto(val);\n                    if !extracted.is_empty() {\n                        return extracted;\n                    }\n                }\n            }\n        }\n        _ => {}\n    }\n\n    results\n}\n\nfn extract_recursive(json: &serde_json::Value, path: &str, results: &mut Vec<String>) {\n    if path.is_empty() {\n        // End of path, extract value(s)\n        extract_values(json, results);\n        return;\n    }\n\n    // Handle array iteration \"[]\"\n    if path == \"[]\" {\n        if let Some(arr) = json.as_array() {\n            for val in arr {\n                extract_values(val, results);\n            }\n        }\n        return;\n    }\n\n    // Handle \"[].\" prefix (iterate then continue path)\n    if let Some(rest) = path.strip_prefix(\"[].\") {\n        if let Some(arr) = json.as_array() {\n            for val in arr {\n                extract_recursive(val, rest, results);\n            }\n        }\n        return;\n    }\n\n    // Handle filter syntax \"[?field=value]\" or \"[?field=value].\"\n    if let Some(filter_content) = path.strip_prefix(\"[?\") {\n        if let Some(end_bracket) = filter_content.find(']') {\n            let filter_expr = &filter_content[..end_bracket];\n            let rest = &filter_content[end_bracket + 1..];\n            let rest = rest.strip_prefix('.').unwrap_or(rest);\n\n            // Parse filter expression \"field=value\"\n            if let Some((filter_field, filter_value)) = filter_expr.split_once('=')\n                && let Some(arr) = json.as_array()\n            {\n                for val in arr {\n                    // Check if this element matches the filter\n                    if let Some(obj) = val.as_object()\n                        && let Some(field_val) = obj.get(filter_field)\n                        && field_val.as_str() == Some(filter_value)\n                    {\n                        if rest.is_empty() {\n                            extract_values(val, results);\n                        } else {\n                            extract_recursive(val, rest, results);\n                        }\n                    }\n                }\n            }\n        }\n        return;\n    }\n\n    // Handle field access with possible continuation\n    // Find where the field name ends (at '.' or '[')\n    let (field, rest) = if let Some(idx) = path.find(['.', '[']) {\n        let (f, r) = path.split_at(idx);\n        // Strip the leading dot if present, but preserve '[' for array handling\n        let rest = r.strip_prefix('.').unwrap_or(r);\n        (f, rest)\n    } else {\n        (path, \"\")\n    };\n\n    if let Some(obj) = json.as_object()\n        && let Some(val) = obj.get(field)\n    {\n        extract_recursive(val, rest, results);\n    }\n}\n\nfn extract_values(json: &serde_json::Value, results: &mut Vec<String>) {\n    match json {\n        serde_json::Value::String(s) => {\n            let v = normalize_version(s);\n            if !v.is_empty() {\n                results.push(v);\n            }\n        }\n        serde_json::Value::Array(arr) => {\n            for val in arr {\n                if let Some(s) = val.as_str() {\n                    let v = normalize_version(s);\n                    if !v.is_empty() {\n                        results.push(v);\n                    }\n                }\n            }\n        }\n        serde_json::Value::Number(n) => {\n            results.push(n.to_string());\n        }\n        serde_json::Value::Object(obj) => {\n            // Try common version field names\n            for field in [\"version\", \"tag_name\", \"name\", \"tag\", \"v\"] {\n                if let Some(v) = obj.get(field).and_then(|v| v.as_str()) {\n                    let v = normalize_version(v);\n                    if !v.is_empty() {\n                        results.push(v);\n                        break;\n                    }\n                }\n            }\n        }\n        _ => {}\n    }\n}\n\n/// Normalize a version string by trimming whitespace and stripping 'v' prefix\nfn normalize_version(s: &str) -> String {\n    s.trim().trim_start_matches('v').to_string()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serde_json::json;\n\n    #[test]\n    fn test_extract_root_string() {\n        let data = json!(\"v2.0.53\");\n        assert_eq!(extract(&data, \".\").unwrap(), vec![\"2.0.53\"]);\n    }\n\n    #[test]\n    fn test_extract_root_array() {\n        let data = json!([\"1.0.0\", \"2.0.0\"]);\n        assert_eq!(extract(&data, \".\").unwrap(), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_array_iterate() {\n        let data = json!([\"v1.0.0\", \"v2.0.0\"]);\n        assert_eq!(extract(&data, \".[]\").unwrap(), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_array_field() {\n        let data = json!([{\"version\": \"1.0.0\"}, {\"version\": \"2.0.0\"}]);\n        assert_eq!(\n            extract(&data, \".[].version\").unwrap(),\n            vec![\"1.0.0\", \"2.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_nested_field() {\n        let data = json!({\"data\": {\"version\": \"1.0.0\"}});\n        assert_eq!(extract(&data, \".data.version\").unwrap(), vec![\"1.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_nested_array() {\n        let data = json!({\"data\": {\"versions\": [\"1.0.0\", \"2.0.0\"]}});\n        assert_eq!(\n            extract(&data, \".data.versions[]\").unwrap(),\n            vec![\"1.0.0\", \"2.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_deeply_nested() {\n        let data =\n            json!({\"releases\": [{\"info\": {\"version\": \"1.0.0\"}}, {\"info\": {\"version\": \"2.0.0\"}}]});\n        assert_eq!(\n            extract(&data, \".releases[].info.version\").unwrap(),\n            vec![\"1.0.0\", \"2.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_object_field_array() {\n        let data = json!({\"versions\": [\"1.0.0\", \"2.0.0\"]});\n        assert_eq!(\n            extract(&data, \".versions[]\").unwrap(),\n            vec![\"1.0.0\", \"2.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_empty_path() {\n        let data = json!(\"1.0.0\");\n        assert_eq!(extract(&data, \"\").unwrap(), vec![\"1.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_missing_field() {\n        let data = json!({\"foo\": \"bar\"});\n        assert!(extract(&data, \".missing\").unwrap().is_empty());\n    }\n\n    #[test]\n    fn test_extract_auto_string() {\n        let data = json!(\"v1.0.0\");\n        assert_eq!(extract_auto(&data), vec![\"1.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_auto_array_strings() {\n        let data = json!([\"v1.0.0\", \"v2.0.0\"]);\n        assert_eq!(extract_auto(&data), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_auto_array_objects() {\n        let data = json!([{\"version\": \"1.0.0\"}, {\"tag_name\": \"v2.0.0\"}]);\n        assert_eq!(extract_auto(&data), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_auto_object_versions_field() {\n        let data = json!({\"versions\": [\"1.0.0\", \"2.0.0\"]});\n        assert_eq!(extract_auto(&data), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_auto_object_releases_field() {\n        let data = json!({\"releases\": [\"1.0.0\", \"2.0.0\"]});\n        assert_eq!(extract_auto(&data), vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_extract_filter_simple() {\n        let data = json!([\n            {\"version\": \"1.0.0\", \"channel\": \"stable\"},\n            {\"version\": \"2.0.0\", \"channel\": \"beta\"},\n            {\"version\": \"3.0.0\", \"channel\": \"stable\"}\n        ]);\n        assert_eq!(\n            extract(&data, \".[?channel=stable].version\").unwrap(),\n            vec![\"1.0.0\", \"3.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_filter_nested() {\n        let data = json!({\n            \"releases\": [\n                {\"version\": \"1.0.0\", \"channel\": \"stable\"},\n                {\"version\": \"2.0.0\", \"channel\": \"beta\"},\n                {\"version\": \"3.0.0\", \"channel\": \"stable\"}\n            ]\n        });\n        assert_eq!(\n            extract(&data, \".releases[?channel=stable].version\").unwrap(),\n            vec![\"1.0.0\", \"3.0.0\"]\n        );\n    }\n\n    #[test]\n    fn test_extract_filter_no_match() {\n        let data = json!([\n            {\"version\": \"1.0.0\", \"channel\": \"beta\"},\n            {\"version\": \"2.0.0\", \"channel\": \"dev\"}\n        ]);\n        assert!(\n            extract(&data, \".[?channel=stable].version\")\n                .unwrap()\n                .is_empty()\n        );\n    }\n\n    #[test]\n    fn test_extract_filter_whole_object() {\n        let data = json!([\n            {\"version\": \"1.0.0\", \"channel\": \"stable\"},\n            {\"version\": \"2.0.0\", \"channel\": \"beta\"}\n        ]);\n        // Without a field after filter, extracts version-like fields from matched objects\n        let result = extract(&data, \".[?channel=stable]\").unwrap();\n        assert_eq!(result, vec![\"1.0.0\"]);\n    }\n}\n"
  },
  {
    "path": "src/backend/mod.rs",
    "content": "use std::collections::{BTreeMap, HashMap, HashSet};\nuse std::ffi::OsString;\nuse std::fmt::{Debug, Display, Formatter};\nuse std::fs::File;\nuse std::hash::Hash;\nuse std::ops::Deref;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, Mutex};\nuse tokio::sync::Mutex as TokioMutex;\n\nuse jiff::Timestamp;\n\nuse crate::cli::args::{BackendArg, ToolVersionType};\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::file::{display_path, remove_all, remove_all_with_warning};\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::path_env::PathEnv;\nuse crate::platform::Platform;\nuse crate::plugins::core::CORE_PLUGINS;\nuse crate::plugins::{PluginType, VERSION_REGEX};\nuse crate::registry::{REGISTRY, full_to_url, normalize_remote, tool_enabled};\nuse crate::runtime_symlinks::is_runtime_symlink;\nuse crate::toolset::outdated_info::OutdatedInfo;\nuse crate::toolset::{\n    ResolveOptions, ToolRequest, ToolVersion, Toolset, install_state, is_outdated_version,\n};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{\n    cache::{CacheManager, CacheManagerBuilder},\n    plugins::PluginEnum,\n};\nuse crate::{dirs, env, file, hash, lock_file, versions_host};\nuse async_trait::async_trait;\nuse backend_type::BackendType;\nuse console::style;\nuse eyre::{Result, WrapErr, bail, eyre};\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse platform_target::PlatformTarget;\nuse regex::Regex;\nuse std::sync::LazyLock as Lazy;\n\npub mod aqua;\npub mod asdf;\npub mod asset_matcher;\npub mod backend_type;\npub mod cargo;\npub mod conda;\npub mod dotnet;\nmod external_plugin_cache;\npub mod gem;\npub mod github;\npub mod go;\npub mod http;\npub mod jq;\npub mod npm;\npub mod pipx;\npub mod platform_target;\npub mod s3;\npub mod spm;\npub mod static_helpers;\npub mod ubi;\npub mod version_list;\npub mod vfox;\n\npub type ABackend = Arc<dyn Backend>;\npub type BackendMap = BTreeMap<String, ABackend>;\npub type BackendList = Vec<ABackend>;\npub type VersionCacheManager = CacheManager<Vec<VersionInfo>>;\n\n/// Information about a GitHub/GitLab release for platform-specific tools\n#[derive(Debug, Clone)]\npub struct GitHubReleaseInfo {\n    pub repo: String,\n    pub asset_pattern: Option<String>,\n    pub api_url: Option<String>,\n    pub release_type: ReleaseType,\n}\n\n#[derive(Debug, Clone)]\npub enum ReleaseType {\n    GitHub,\n    GitLab,\n}\n\n/// Information about a tool version including optional metadata like creation time\n#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]\npub struct VersionInfo {\n    pub version: String,\n    #[serde(skip_serializing_if = \"Option::is_none\", default)]\n    pub created_at: Option<String>,\n    /// URL to the release page (e.g., GitHub/GitLab release page)\n    #[serde(skip_serializing_if = \"Option::is_none\", default)]\n    pub release_url: Option<String>,\n    /// If true, this is a rolling release (like \"nightly\") that should always\n    /// be considered potentially outdated for `mise up` purposes\n    #[serde(default)]\n    pub rolling: bool,\n    /// Checksum of the release asset, used to detect changes in rolling releases\n    #[serde(skip_serializing_if = \"Option::is_none\", default)]\n    pub checksum: Option<String>,\n}\n\nimpl VersionInfo {\n    /// Filter versions to only include those released before the given timestamp.\n    /// Versions without a created_at timestamp are included by default.\n    pub fn filter_by_date(versions: Vec<Self>, before: Timestamp) -> Vec<Self> {\n        use crate::duration::parse_into_timestamp;\n        versions\n            .into_iter()\n            .filter(|v| {\n                match &v.created_at {\n                    Some(ts) => {\n                        // Parse the timestamp using parse_into_timestamp which handles\n                        // RFC3339, date-only (YYYY-MM-DD), and other formats\n                        match parse_into_timestamp(ts) {\n                            Ok(created) => created < before,\n                            Err(_) => {\n                                // If we can't parse the timestamp, include the version\n                                trace!(\"Failed to parse timestamp: {}\", ts);\n                                true\n                            }\n                        }\n                    }\n                    // Include versions without timestamps\n                    None => true,\n                }\n            })\n            .collect()\n    }\n}\n\n/// Security feature information for a tool\n#[derive(Debug, Clone, serde::Serialize)]\n#[serde(tag = \"type\", rename_all = \"snake_case\")]\npub enum SecurityFeature {\n    Checksum {\n        #[serde(skip_serializing_if = \"Option::is_none\")]\n        algorithm: Option<String>,\n    },\n    GithubAttestations {\n        #[serde(skip_serializing_if = \"Option::is_none\")]\n        signer_workflow: Option<String>,\n    },\n    Slsa {\n        #[serde(skip_serializing_if = \"Option::is_none\")]\n        level: Option<u8>,\n    },\n    Cosign,\n    Minisign {\n        #[serde(skip_serializing_if = \"Option::is_none\")]\n        public_key: Option<String>,\n    },\n    Gpg,\n}\n\nstatic TOOLS: Mutex<Option<Arc<BackendMap>>> = Mutex::new(None);\n\npub async fn load_tools() -> Result<Arc<BackendMap>> {\n    if let Some(memo_tools) = TOOLS.lock().unwrap().clone() {\n        return Ok(memo_tools);\n    }\n    install_state::init().await?;\n    time!(\"load_tools start\");\n    let core_tools = CORE_PLUGINS.values().cloned().collect::<Vec<ABackend>>();\n    let mut tools = core_tools;\n    // add tools with idiomatic files so they get parsed even if no versions are installed\n    tools.extend(\n        REGISTRY\n            .values()\n            .filter(|rt| !rt.idiomatic_files.is_empty() && rt.is_supported_os())\n            .filter_map(|rt| arg_to_backend(rt.short.into())),\n    );\n    time!(\"load_tools core\");\n    tools.extend(\n        install_state::list_tools()\n            .values()\n            .filter(|ist| ist.full.is_some())\n            .flat_map(|ist| arg_to_backend(ist.clone().into())),\n    );\n    time!(\"load_tools install_state\");\n    tools.retain(|backend| {\n        tool_enabled(\n            &Settings::get().enable_tools(),\n            &Settings::get().disable_tools(),\n            &backend.id().to_string(),\n        )\n    });\n    tools.retain(|backend| {\n        !Settings::get()\n            .disable_backends\n            .contains(&backend.get_type().to_string())\n    });\n\n    let tools: BackendMap = tools\n        .into_iter()\n        .map(|backend| (backend.ba().short.clone(), backend))\n        .collect();\n    let tools = Arc::new(tools);\n    *TOOLS.lock().unwrap() = Some(tools.clone());\n    time!(\"load_tools done\");\n    Ok(tools)\n}\n\npub fn list() -> BackendList {\n    TOOLS\n        .lock()\n        .unwrap()\n        .as_ref()\n        .unwrap()\n        .values()\n        .cloned()\n        .collect()\n}\n\npub fn get(ba: &BackendArg) -> Option<ABackend> {\n    let mut tools = TOOLS.lock().unwrap();\n    let tools_ = tools.as_ref().unwrap();\n    if let Some(backend) = tools_.get(&ba.short) {\n        Some(backend.clone())\n    } else if let Some(backend) = arg_to_backend(ba.clone()) {\n        let mut tools_ = tools_.deref().clone();\n        tools_.insert(ba.short.clone(), backend.clone());\n        *tools = Some(Arc::new(tools_));\n        Some(backend)\n    } else {\n        None\n    }\n}\n\npub fn remove(short: &str) {\n    let mut tools = TOOLS.lock().unwrap();\n    let mut tools_ = tools.as_ref().unwrap().deref().clone();\n    tools_.remove(short);\n    *tools = Some(Arc::new(tools_));\n}\n\npub fn arg_to_backend(ba: BackendArg) -> Option<ABackend> {\n    match ba.backend_type() {\n        BackendType::Core => {\n            CORE_PLUGINS\n                .get(&ba.short)\n                .or_else(|| {\n                    // this can happen if something like \"corenode\" is aliased to \"core:node\"\n                    ba.full()\n                        .strip_prefix(\"core:\")\n                        .and_then(|short| CORE_PLUGINS.get(short))\n                })\n                .cloned()\n        }\n        BackendType::Aqua => Some(Arc::new(aqua::AquaBackend::from_arg(ba))),\n        BackendType::Asdf => Some(Arc::new(asdf::AsdfBackend::from_arg(ba))),\n        BackendType::Cargo => Some(Arc::new(cargo::CargoBackend::from_arg(ba))),\n        BackendType::Conda => Some(Arc::new(conda::CondaBackend::from_arg(ba))),\n        BackendType::Dotnet => Some(Arc::new(dotnet::DotnetBackend::from_arg(ba))),\n        BackendType::Forgejo => Some(Arc::new(github::UnifiedGitBackend::from_arg(ba))),\n        BackendType::Gem => Some(Arc::new(gem::GemBackend::from_arg(ba))),\n        BackendType::Github => Some(Arc::new(github::UnifiedGitBackend::from_arg(ba))),\n        BackendType::Gitlab => Some(Arc::new(github::UnifiedGitBackend::from_arg(ba))),\n        BackendType::Go => Some(Arc::new(go::GoBackend::from_arg(ba))),\n        BackendType::Npm => Some(Arc::new(npm::NPMBackend::from_arg(ba))),\n        BackendType::Pipx => Some(Arc::new(pipx::PIPXBackend::from_arg(ba))),\n        BackendType::Spm => Some(Arc::new(spm::SPMBackend::from_arg(ba))),\n        BackendType::Http => Some(Arc::new(http::HttpBackend::from_arg(ba))),\n        BackendType::S3 => Some(Arc::new(s3::S3Backend::from_arg(ba))),\n        BackendType::Ubi => Some(Arc::new(ubi::UbiBackend::from_arg(ba))),\n        BackendType::Vfox => Some(Arc::new(vfox::VfoxBackend::from_arg(ba, None))),\n        BackendType::VfoxBackend(plugin_name) => Some(Arc::new(vfox::VfoxBackend::from_arg(\n            ba,\n            Some(plugin_name.to_string()),\n        ))),\n        BackendType::Unknown => None,\n    }\n}\n\n/// Returns install-time-only option keys for a backend type.\n/// These are options that only affect installation/download, not post-install behavior.\n/// Used to filter cached options when config provides its own options.\npub fn install_time_option_keys_for_type(backend_type: &BackendType) -> Vec<String> {\n    match backend_type {\n        BackendType::Http => http::install_time_option_keys(),\n        BackendType::S3 => s3::install_time_option_keys(),\n        BackendType::Github | BackendType::Gitlab => github::install_time_option_keys(),\n        BackendType::Ubi => ubi::install_time_option_keys(),\n        BackendType::Cargo => cargo::install_time_option_keys(),\n        BackendType::Go => go::install_time_option_keys(),\n        BackendType::Pipx => pipx::install_time_option_keys(),\n        _ => vec![],\n    }\n}\n\n/// Normalize idiomatic file contents by removing comments and empty lines.\n/// Full-line and inline comments are supported by .python-version, .nvmrc, etc.\npub(crate) fn normalize_idiomatic_contents(contents: &str) -> String {\n    contents\n        .lines()\n        .filter_map(|line| {\n            let trimmed = line.trim();\n\n            // Skip empty lines or lines that are entirely comments\n            if trimmed.is_empty() || trimmed.starts_with('#') {\n                return None;\n            }\n\n            // Find an inline comment marked by a `#` preceded by whitespace, preserving valid `#` chars in versions like `tool#tag`\n            let comment_idx = trimmed.char_indices().find_map(|(i, c)| {\n                if c == '#' && trimmed[..i].ends_with(char::is_whitespace) {\n                    Some(i)\n                } else {\n                    None\n                }\n            });\n\n            // Strip the inline comment if found, otherwise retain the whole trimmed string\n            let without_inline = if let Some(idx) = comment_idx {\n                trimmed[..idx].trim()\n            } else {\n                trimmed\n            };\n\n            // Double check the line hasn't become empty after stripping the comment\n            if without_inline.is_empty() {\n                None\n            } else {\n                Some(without_inline)\n            }\n        })\n        .collect::<Vec<_>>()\n        .join(\"\\n\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_normalize_idiomatic_contents() {\n        assert_eq!(normalize_idiomatic_contents(\"tool # and a comment\"), \"tool\");\n        assert_eq!(normalize_idiomatic_contents(\"tool#tag\"), \"tool#tag\");\n        assert_eq!(\n            normalize_idiomatic_contents(\"tool#tag # comment\"),\n            \"tool#tag\"\n        );\n        assert_eq!(normalize_idiomatic_contents(\"   # full line comment\"), \"\");\n        assert_eq!(\n            normalize_idiomatic_contents(\"3.12.3\\n3.11.11\"),\n            \"3.12.3\\n3.11.11\"\n        );\n        assert_eq!(\n            normalize_idiomatic_contents(\"3.12.3 # inline\\n# comment\\n3.11.11\"),\n            \"3.12.3\\n3.11.11\"\n        );\n        assert_eq!(\n            normalize_idiomatic_contents(\"# full line comment\\n3.14.2 # inline comment\\n   \\n\\n\"),\n            \"3.14.2\"\n        );\n    }\n}\n\n#[async_trait]\npub trait Backend: Debug + Send + Sync {\n    fn id(&self) -> &str {\n        &self.ba().short\n    }\n    fn tool_name(&self) -> String {\n        self.ba().tool_name()\n    }\n    fn get_type(&self) -> BackendType {\n        BackendType::Core\n    }\n    fn ba(&self) -> &Arc<BackendArg>;\n\n    /// Generates a platform key for lockfile storage.\n    /// Default implementation uses the current platform key (os-arch or os-arch-qualifier),\n    /// which includes the libc qualifier on musl systems.\n    fn get_platform_key(&self) -> String {\n        Platform::current().to_key()\n    }\n\n    /// Resolves the lockfile options for a tool request on a target platform.\n    /// These options affect artifact identity and must match exactly for lockfile lookup.\n    ///\n    /// For the current platform: resolves from Settings and ToolRequest options\n    /// For other platforms (cross-platform mise lock): uses sensible defaults\n    ///\n    /// Backends should override this to return options that affect which artifact is downloaded.\n    fn resolve_lockfile_options(\n        &self,\n        _request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        BTreeMap::new() // Default: no options affect artifact identity\n    }\n\n    /// Returns all platform variants that should be locked for a given base platform.\n    ///\n    /// Some tools have compile-time variants (e.g., bun has baseline/musl variants)\n    /// that result in different download URLs and checksums. This method allows\n    /// backends to declare all variants so `mise lock` can fetch checksums for each.\n    ///\n    /// Default returns just the base platform. Backends should override this to\n    /// return additional variants when applicable.\n    ///\n    /// Example: For bun on linux-x64, this might return:\n    /// - linux-x64 (default, AVX2)\n    /// - linux-x64-baseline (no AVX2)\n    /// - linux-x64-musl (musl libc)\n    /// - linux-x64-musl-baseline (musl + no AVX2)\n    fn platform_variants(&self, platform: &Platform) -> Vec<Platform> {\n        vec![platform.clone()] // Default: just the base platform\n    }\n\n    /// Whether this backend supports URL-based locking in locked mode.\n    /// Backends that use external installers (like rustup for Rust) should override\n    /// this to return false, since they don't have downloadable artifacts with lockable URLs.\n    fn supports_lockfile_url(&self) -> bool {\n        true\n    }\n\n    async fn description(&self) -> Option<String> {\n        None\n    }\n    async fn security_info(&self) -> Vec<SecurityFeature> {\n        vec![]\n    }\n    fn get_plugin_type(&self) -> Option<PluginType> {\n        None\n    }\n    /// If any of these tools are installing in parallel, we should wait for them to finish\n    /// before installing this tool.\n    fn get_dependencies(&self) -> Result<Vec<&str>> {\n        Ok(vec![])\n    }\n    /// dependencies which wait for install but do not warn, like cargo-binstall\n    fn get_optional_dependencies(&self) -> Result<Vec<&str>> {\n        Ok(vec![])\n    }\n    fn get_all_dependencies(&self, optional: bool) -> Result<IndexSet<BackendArg>> {\n        let all_fulls = self.ba().all_fulls();\n        if all_fulls.is_empty() {\n            // this can happen on windows where we won't be able to install this os/arch so\n            // the fact there might be dependencies is meaningless\n            return Ok(Default::default());\n        }\n        let mut deps: Vec<&str> = self.get_dependencies()?;\n        if optional {\n            deps.extend(self.get_optional_dependencies()?);\n        }\n        let mut deps: IndexSet<_> = deps.into_iter().map(BackendArg::from).collect();\n        if let Some(rt) = REGISTRY.get(self.ba().short.as_str()) {\n            // add dependencies from registry/\n            deps.extend(rt.depends.iter().map(BackendArg::from));\n        }\n        deps.retain(|ba| &**self.ba() != ba);\n        deps.retain(|ba| !all_fulls.contains(&ba.full()));\n        for ba in deps.clone() {\n            if let Ok(backend) = ba.backend() {\n                deps.extend(backend.get_all_dependencies(optional)?);\n            }\n        }\n        Ok(deps)\n    }\n\n    async fn list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<String>> {\n        Ok(self\n            .list_remote_versions_with_info(config)\n            .await?\n            .into_iter()\n            .map(|v| v.version)\n            .collect())\n    }\n\n    /// List remote versions with additional metadata like created_at timestamps.\n    /// Results are cached. Backends can override `_list_remote_versions_with_info`\n    /// to provide timestamp information.\n    ///\n    /// This method first tries the versions host (mise-versions.jdx.dev) which provides\n    /// version info with created_at timestamps. If that fails, it falls back to the\n    /// backend's `_list_remote_versions_with_info` implementation.\n    async fn list_remote_versions_with_info(\n        &self,\n        config: &Arc<Config>,\n    ) -> eyre::Result<Vec<VersionInfo>> {\n        let remote_versions = self.get_remote_version_cache();\n        let remote_versions = remote_versions.lock().await;\n        let ba = self.ba().clone();\n        let id = self.id();\n\n        // Check if this is an external plugin with a custom remote - skip versions host if so\n        let use_versions_host = if let Some(plugin) = self.plugin()\n            && let Ok(Some(remote_url)) = plugin.get_remote_url()\n        {\n            // Check if remote matches the registry default\n            let normalized_remote =\n                normalize_remote(&remote_url).unwrap_or_else(|_| \"INVALID_URL\".into());\n            let shorthand_remote = REGISTRY\n                .get(plugin.name())\n                .and_then(|rt| rt.backends().first().map(|b| full_to_url(b)))\n                .unwrap_or_default();\n            let matches =\n                normalized_remote == normalize_remote(&shorthand_remote).unwrap_or_default();\n            if !matches {\n                trace!(\n                    \"Skipping versions host for {} because it has a non-default remote\",\n                    ba.short\n                );\n            }\n            matches\n        } else {\n            // For non-plugin backends (e.g. github:, cargo:), check if the backend matches\n            // the registry's default. When a user aliases a tool to a different backend\n            // (e.g. `php = \"github:verzly/php\"`), the versions host would return versions\n            // from the registry's default backend which may not match the aliased backend.\n            let full = ba.full();\n            if let Some(rt) = REGISTRY.get(ba.short.as_str()) {\n                let is_registry_backend = rt.backends().iter().any(|b| *b == full);\n                if !is_registry_backend {\n                    trace!(\n                        \"Skipping versions host for {} because backend {} is not the registry default\",\n                        ba.short, full\n                    );\n                }\n                is_registry_backend\n            } else {\n                true // Not in registry, safe to use versions host\n            }\n        };\n\n        if Settings::get().offline() {\n            trace!(\n                \"Skipping remote version listing for {} due to offline mode\",\n                ba.to_string()\n            );\n            return Ok(vec![]);\n        }\n\n        let versions = remote_versions\n            .get_or_try_init_async(|| async {\n                trace!(\"Listing remote versions for {}\", ba.to_string());\n                // Try versions host first (now returns VersionInfo with timestamps)\n                if use_versions_host {\n                    match versions_host::list_versions(&ba.short).await {\n                        Ok(Some(versions)) => {\n                            trace!(\n                                \"Got {} versions from versions host for {}\",\n                                versions.len(),\n                                ba.to_string()\n                            );\n                            return Ok(versions);\n                        }\n                        Ok(None) => {}\n                        Err(e) => {\n                            debug!(\"Error getting versions from versions host: {:#}\", e);\n                        }\n                    }\n                }\n                trace!(\n                    \"Calling backend to list remote versions for {}\",\n                    ba.to_string()\n                );\n                let versions = self\n                    ._list_remote_versions(config)\n                    .await?\n                    .into_iter()\n                    .filter(|v| match v.version.parse::<ToolVersionType>() {\n                        Ok(ToolVersionType::Version(_)) => true,\n                        _ => {\n                            warn!(\"Invalid version: {id}@{}\", v.version);\n                            false\n                        }\n                    })\n                    .collect_vec();\n                if versions.is_empty() && self.get_type() != BackendType::Http {\n                    warn!(\"No versions found for {id}\");\n                }\n                Ok(versions)\n            })\n            .await?;\n        Ok(versions.clone())\n    }\n\n    /// Backend implementation for fetching remote versions with metadata.\n    /// Override this to provide version listing with optional timestamp information.\n    /// Return `VersionInfo` with `created_at: None` if timestamps are not available.\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>>;\n\n    async fn latest_stable_version(&self, config: &Arc<Config>) -> eyre::Result<Option<String>> {\n        self.latest_version(config, Some(\"latest\".into())).await\n    }\n    fn list_installed_versions(&self) -> Vec<String> {\n        install_state::list_versions(&self.ba().short)\n    }\n    fn is_version_installed(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        check_symlink: bool,\n    ) -> bool {\n        let check_path = |install_path: &Path, check_symlink: bool| {\n            let is_installed = install_path.exists();\n            let is_not_incomplete = !self.incomplete_file_path(tv).exists();\n            let is_valid_symlink = !check_symlink || !is_runtime_symlink(install_path);\n\n            let installed = is_installed && is_not_incomplete && is_valid_symlink;\n            if log::log_enabled!(log::Level::Trace) && !installed {\n                let mut msg = format!(\n                    \"{} is not installed, path: {}\",\n                    self.ba(),\n                    display_path(install_path)\n                );\n                if !is_installed {\n                    msg += \" (not installed)\";\n                }\n                if !is_not_incomplete {\n                    msg += \" (incomplete)\";\n                }\n                if !is_valid_symlink {\n                    msg += \" (runtime symlink)\";\n                }\n                trace!(\"{}\", msg);\n            }\n            installed\n        };\n        match tv.request {\n            ToolRequest::System { .. } => true,\n            _ => {\n                if let Some(install_path) = tv.request.install_path(config)\n                    && check_path(&install_path, true)\n                {\n                    // For Prefix requests, install_path finds any installed dir\n                    // matching the prefix (e.g., \"1.0.0\" for prefix \"1\"), but if\n                    // the ToolVersion resolved to a different version (e.g., \"1.1.0\"),\n                    // we must not treat it as installed.\n                    if let ToolRequest::Prefix { .. } = &tv.request\n                        && install_path\n                            .file_name()\n                            .is_some_and(|f| f.to_string_lossy() != tv.version)\n                    {\n                        return check_path(&tv.install_path(), check_symlink);\n                    }\n                    return true;\n                }\n                check_path(&tv.install_path(), check_symlink)\n            }\n        }\n    }\n    async fn is_version_outdated(&self, config: &Arc<Config>, tv: &ToolVersion) -> bool {\n        let latest = match tv.latest_version(config).await {\n            Ok(latest) => latest,\n            Err(e) => {\n                warn!(\n                    \"Error getting latest version for {}: {:#}\",\n                    self.ba().to_string(),\n                    e\n                );\n                return false;\n            }\n        };\n        !self.is_version_installed(config, tv, true) || is_outdated_version(&tv.version, &latest)\n    }\n    fn symlink_path(&self, tv: &ToolVersion) -> Option<PathBuf> {\n        let path = tv.install_path();\n        if !path.is_symlink() {\n            return None;\n        }\n        // Only skip symlinks pointing within installs (user aliases, not backend-managed)\n        if let Ok(Some(target)) = file::resolve_symlink(&path) {\n            let target = if target.is_absolute() {\n                target\n            } else {\n                path.parent().unwrap_or(&path).join(&target)\n            };\n            // Canonicalize to resolve any \"..\" components before checking.\n            // If target doesn't exist (canonicalize fails), don't skip - treat as needing install\n            let Ok(target) = target.canonicalize() else {\n                return None;\n            };\n            // Canonicalize INSTALLS too for consistent comparison (handles symlinked data dirs)\n            let installs = dirs::INSTALLS\n                .canonicalize()\n                .unwrap_or(dirs::INSTALLS.to_path_buf());\n            if target.starts_with(&installs) {\n                return Some(path);\n            }\n            // Also check shared install directories\n            for shared_dir in env::shared_install_dirs() {\n                let shared = shared_dir\n                    .canonicalize()\n                    .unwrap_or(shared_dir.to_path_buf());\n                if target.starts_with(&shared) {\n                    return Some(path);\n                }\n            }\n        }\n        None\n    }\n    fn create_symlink(&self, version: &str, target: &Path) -> Result<Option<(PathBuf, PathBuf)>> {\n        let link = self.ba().installs_path.join(version);\n        if link.exists() {\n            return Ok(None);\n        }\n        file::create_dir_all(link.parent().unwrap())?;\n        let link = file::make_symlink(target, &link)?;\n        Ok(Some(link))\n    }\n    fn list_installed_versions_matching(&self, query: &str) -> Vec<String> {\n        let versions = self.list_installed_versions();\n        self.fuzzy_match_filter(versions, query)\n    }\n    async fn list_versions_matching(\n        &self,\n        config: &Arc<Config>,\n        query: &str,\n    ) -> eyre::Result<Vec<String>> {\n        let versions = self.list_remote_versions(config).await?;\n        Ok(self.fuzzy_match_filter(versions, query))\n    }\n\n    /// List versions matching a query, optionally filtered by release date.\n    /// Use this when you have a `before_date` from ResolveOptions.\n    async fn list_versions_matching_with_opts(\n        &self,\n        config: &Arc<Config>,\n        query: &str,\n        before_date: Option<Timestamp>,\n    ) -> eyre::Result<Vec<String>> {\n        let versions = match before_date {\n            Some(before) => {\n                // Use version info to filter by date\n                let versions_with_info = self.list_remote_versions_with_info(config).await?;\n                let filtered = VersionInfo::filter_by_date(versions_with_info, before);\n                // Warn if no versions have timestamps\n                if filtered.iter().all(|v| v.created_at.is_none()) && !filtered.is_empty() {\n                    debug!(\n                        \"Backend {} does not provide release dates; --before filter may not work as expected\",\n                        self.id()\n                    );\n                }\n                filtered.into_iter().map(|v| v.version).collect()\n            }\n            None => self.list_remote_versions(config).await?,\n        };\n        Ok(self.fuzzy_match_filter(versions, query))\n    }\n\n    async fn latest_version(\n        &self,\n        config: &Arc<Config>,\n        query: Option<String>,\n    ) -> eyre::Result<Option<String>> {\n        match query {\n            Some(query) => {\n                let mut matches = self.list_versions_matching(config, &query).await?;\n                if matches.is_empty() && query == \"latest\" {\n                    matches = self.list_remote_versions(config).await?;\n                }\n                Ok(find_match_in_list(&matches, &query))\n            }\n            None => self.latest_stable_version(config).await,\n        }\n    }\n\n    /// Get the latest version, optionally filtered by release date.\n    /// Use this when you have a `before_date` from ResolveOptions.\n    async fn latest_version_with_opts(\n        &self,\n        config: &Arc<Config>,\n        query: Option<String>,\n        before_date: Option<Timestamp>,\n    ) -> eyre::Result<Option<String>> {\n        match query {\n            Some(query) => {\n                let mut matches = self\n                    .list_versions_matching_with_opts(config, &query, before_date)\n                    .await?;\n                if matches.is_empty() && query == \"latest\" {\n                    // Fall back to all versions if no match\n                    matches = match before_date {\n                        Some(before) => {\n                            let versions_with_info =\n                                self.list_remote_versions_with_info(config).await?;\n                            VersionInfo::filter_by_date(versions_with_info, before)\n                                .into_iter()\n                                .map(|v| v.version)\n                                .collect()\n                        }\n                        None => self.list_remote_versions(config).await?,\n                    };\n                }\n                Ok(find_match_in_list(&matches, &query))\n            }\n            None => {\n                // For stable version, apply date filter if provided\n                match before_date {\n                    Some(before) => {\n                        let matches = self\n                            .list_versions_matching_with_opts(config, \"latest\", Some(before))\n                            .await?;\n                        Ok(find_match_in_list(&matches, \"latest\"))\n                    }\n                    None => self.latest_stable_version(config).await,\n                }\n            }\n        }\n    }\n    fn latest_installed_version(&self, query: Option<String>) -> eyre::Result<Option<String>> {\n        match query {\n            Some(query) => {\n                let matches = self.list_installed_versions_matching(&query);\n                Ok(find_match_in_list(&matches, &query))\n            }\n            None => {\n                let installed_symlink = self.ba().installs_path.join(\"latest\");\n                if installed_symlink.exists() {\n                    let Some(target) = file::resolve_symlink(&installed_symlink)? else {\n                        return Ok(Some(\"latest\".to_string()));\n                    };\n                    let version = target\n                        .file_name()\n                        .ok_or_else(|| eyre!(\"Invalid symlink target\"))?\n                        .to_string_lossy()\n                        .to_string();\n                    Ok(Some(version))\n                } else {\n                    Ok(None)\n                }\n            }\n        }\n    }\n\n    /// Check if a version is a rolling release (like \"nightly\") that should\n    /// always be considered potentially outdated for `mise up` purposes\n    async fn is_version_rolling(&self, config: &Arc<Config>, version: &str) -> bool {\n        let versions = match self.list_remote_versions_with_info(config).await {\n            Ok(v) => v,\n            Err(_) => return false,\n        };\n        versions.iter().any(|v| v.version == version && v.rolling)\n    }\n\n    /// Get version info for a specific version (including checksum for rolling releases)\n    async fn get_version_info(&self, config: &Arc<Config>, version: &str) -> Option<VersionInfo> {\n        let versions = match self.list_remote_versions_with_info(config).await {\n            Ok(v) => v,\n            Err(_) => return None,\n        };\n        versions.into_iter().find(|v| v.version == version)\n    }\n\n    /// Check if a rolling version has changed (by comparing checksums)\n    /// Returns true if the version should be updated\n    async fn is_rolling_version_outdated(&self, config: &Arc<Config>, version: &str) -> bool {\n        use crate::toolset::install_state;\n\n        // Get the latest version info\n        let version_info = match self.get_version_info(config, version).await {\n            Some(v) if v.rolling => v,\n            _ => return false, // Not rolling or not found\n        };\n\n        // If no checksum available, we can't detect changes - don't assume outdated\n        let Some(latest_checksum) = version_info.checksum else {\n            trace!(\n                \"No checksum available for rolling version {}, cannot detect updates\",\n                version\n            );\n            return false;\n        };\n\n        // Compare with stored checksum\n        let stored_checksum = install_state::read_checksum(&self.ba().short, version);\n        match stored_checksum {\n            Some(stored) if stored == latest_checksum => {\n                trace!(\"Rolling version {} checksum unchanged\", version);\n                false\n            }\n            Some(stored) => {\n                trace!(\n                    \"Rolling version {} checksum changed: {} -> {}\",\n                    version, stored, latest_checksum\n                );\n                true\n            }\n            None => {\n                trace!(\n                    \"No stored checksum for rolling version {}, assuming outdated\",\n                    version\n                );\n                true\n            }\n        }\n    }\n\n    async fn warn_if_dependencies_missing(&self, config: &Arc<Config>) -> eyre::Result<()> {\n        let deps = self\n            .get_all_dependencies(false)?\n            .into_iter()\n            .filter(|ba| &**self.ba() != ba)\n            .map(|ba| ba.short)\n            .collect::<HashSet<_>>();\n        if !deps.is_empty() {\n            trace!(\"Ensuring dependencies installed for {}\", self.id());\n            let ts = config.get_tool_request_set().await?.filter_by_tool(deps);\n            let missing = ts.missing_tools(config).await;\n            if !missing.is_empty() {\n                warn_once!(\n                    \"missing dependency: {}\",\n                    missing.iter().map(|d| d.to_string()).join(\", \"),\n                );\n            }\n        }\n        Ok(())\n    }\n    fn purge(&self, pr: &dyn SingleReport) -> eyre::Result<()> {\n        rmdir(&self.ba().installs_path, pr)?;\n        rmdir(&self.ba().cache_path, pr)?;\n        rmdir(&self.ba().downloads_path, pr)?;\n        Ok(())\n    }\n    fn get_aliases(&self) -> eyre::Result<BTreeMap<String, String>> {\n        Ok(BTreeMap::new())\n    }\n\n    /// Returns a list of idiomatic filenames for this tool.\n    ///\n    /// This method is additive:\n    /// 1. It calls `_idiomatic_filenames` to get backend-specific filenames.\n    /// 2. It checks the Registry for any additional filenames defined there.\n    async fn idiomatic_filenames(&self) -> Result<Vec<String>> {\n        let mut filenames = self._idiomatic_filenames().await?;\n        if let Some(rt) = REGISTRY.get(self.id()) {\n            filenames.extend(rt.idiomatic_files.iter().map(|s| s.to_string()));\n        }\n        filenames = filenames.into_iter().unique().collect();\n        Ok(filenames)\n    }\n\n    /// Backend-specific implementation for `idiomatic_filenames`.\n    /// Override this to provide native idiomatic filenames for the backend.\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![])\n    }\n\n    /// Parses an idiomatic version file to extract the version.\n    ///\n    /// This handles special files like `package.json` which are parsed natively to avoid\n    /// every backend needing to implement `package.json` support. For other files, it\n    /// delegates to `_parse_idiomatic_file`.\n    async fn parse_idiomatic_file(&self, path: &Path) -> eyre::Result<Vec<String>> {\n        if path.file_name().is_some_and(|f| f == \"package.json\") {\n            return crate::config::config_file::idiomatic_version::package_json::parse(\n                path,\n                self.id(),\n            );\n        }\n        self._parse_idiomatic_file(path).await\n    }\n\n    /// Backend-specific implementation for `parse_idiomatic_file`.\n    /// Default implementation reads the file and treats each whitespace-separated token as a version.\n    /// Override to provide format-specific parsing; return `Err` on real failures so the plugin is skipped.\n    async fn _parse_idiomatic_file(&self, path: &Path) -> eyre::Result<Vec<String>> {\n        let contents = file::read_to_string(path)?;\n        let normalized = normalize_idiomatic_contents(&contents);\n        if normalized.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(normalized\n            .split_whitespace()\n            .map(|s| s.to_string())\n            .collect())\n    }\n\n    fn plugin(&self) -> Option<&PluginEnum> {\n        None\n    }\n\n    async fn install_version(\n        &self,\n        ctx: InstallContext,\n        mut tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        // Check for --locked mode: if enabled and no lockfile URL exists, fail early\n        // Exempt tool stubs from lockfile requirements since they are ephemeral\n        // Also exempt backends that don't support URL locking (e.g., Rust uses rustup)\n        // This must run before the dry-run check so that --locked --dry-run still validates\n        let settings = Settings::get();\n        if (ctx.locked || settings.locked) && settings.lockfile == Some(false) {\n            bail!(\n                \"locked mode requires lockfile to be enabled\\n\\\n                hint: Remove `lockfile = false` or set `lockfile = true`, or disable locked mode\"\n            );\n        }\n        if ctx.locked && !tv.request.source().is_tool_stub() && self.supports_lockfile_url() {\n            let platform_key = self.get_platform_key();\n            let has_lockfile_url = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|p| p.url.as_ref())\n                .is_some();\n            if !has_lockfile_url {\n                bail!(\n                    \"No lockfile URL found for {} on platform {} (--locked mode)\\n\\\n                    hint: Run `mise lock` to generate lockfile URLs, or disable locked mode\",\n                    tv.style(),\n                    platform_key\n                );\n            }\n        }\n\n        // Handle dry-run mode early to avoid plugin installation\n        if ctx.dry_run {\n            use crate::ui::progress_report::ProgressIcon;\n            if self.is_version_installed(&ctx.config, &tv, true) {\n                ctx.pr\n                    .finish_with_icon(\"already installed\".into(), ProgressIcon::Skipped);\n            } else {\n                ctx.pr\n                    .finish_with_icon(\"would install\".into(), ProgressIcon::Skipped);\n            }\n            return Ok(tv);\n        }\n\n        if let Some(plugin) = self.plugin() {\n            plugin.is_installed_err()?;\n        }\n\n        // If --force and the install path resolved to a shared dir (but wasn't explicitly\n        // set via --system/--shared), redirect to primary dir to avoid modifying shared installs.\n        if ctx.force\n            && tv.install_path.is_none()\n            && env::install_path_category(&tv.install_path()) != env::InstallPathCategory::Local\n        {\n            tv.install_path = Some(tv.ba().installs_path.join(tv.tv_pathname()));\n        }\n\n        let will_uninstall = ctx.force && self.is_version_installed(&ctx.config, &tv, true);\n\n        // Query backend for operation count and set up progress tracking\n        let install_ops = self.install_operation_count(&tv, &ctx).await;\n        let total_ops = if will_uninstall {\n            install_ops + 1\n        } else {\n            install_ops\n        };\n        ctx.pr.start_operations(total_ops);\n\n        if will_uninstall {\n            self.uninstall_version(&ctx.config, &tv, ctx.pr.as_ref(), false)\n                .await?;\n            ctx.pr.next_operation();\n        } else if self.is_version_installed(&ctx.config, &tv, true) {\n            return Ok(tv);\n        }\n\n        // Track the installation asynchronously (fire-and-forget)\n        // Do this before install so the request has time to complete during installation\n        versions_host::track_install(tv.short(), &tv.ba().full(), &tv.version);\n\n        ctx.pr.set_message(\"install\".into());\n        let _lock = lock_file::get(&tv.install_path(), ctx.force)?;\n\n        // Double-checked (locking) that it wasn't installed while we were waiting for the lock\n        if self.is_version_installed(&ctx.config, &tv, true) && !ctx.force {\n            return Ok(tv);\n        }\n\n        self.create_install_dirs(&tv)?;\n\n        let old_tv = tv.clone();\n        let tv = match self.install_version_(&ctx, tv).await {\n            Ok(tv) => tv,\n            Err(e) => {\n                self.cleanup_install_dirs_on_error(&old_tv);\n                // Pass through the error - it will be wrapped at a higher level\n                return Err(e);\n            }\n        };\n\n        let install_path = tv.install_path();\n        if install_path.starts_with(*dirs::INSTALLS) {\n            install_state::write_backend_meta(self.ba())?;\n        } else if env::install_path_category(&install_path) != env::InstallPathCategory::Local {\n            // For --system/--shared installs, write manifest to the target installs dir\n            if let Some(installs_dir) = install_path.parent().and_then(|p| p.parent()) {\n                let manifest = installs_dir.join(\".mise-installs.toml\");\n                install_state::write_backend_meta_to(self.ba(), &manifest)?;\n            }\n        }\n\n        self.cleanup_install_dirs(&tv);\n        // attempt to touch all the .tool-version files to trigger updates in hook-env\n        let mut touch_dirs = vec![dirs::DATA.to_path_buf()];\n        touch_dirs.extend(ctx.config.config_files.keys().cloned());\n        for path in touch_dirs {\n            let err = file::touch_dir(&path);\n            if let Err(err) = err {\n                trace!(\"error touching config file: {:?} {:?}\", path, err);\n            }\n        }\n        let incomplete_path = self.incomplete_file_path(&tv);\n        if let Err(err) = file::remove_file(&incomplete_path) {\n            debug!(\"error removing incomplete file: {:?}\", err);\n        } else {\n            // Sync parent directory to ensure file removal is immediately visible\n            if let Some(parent) = incomplete_path.parent()\n                && let Err(err) = file::sync_dir(parent)\n            {\n                debug!(\"error syncing incomplete file parent directory: {:?}\", err);\n            }\n        }\n        if let Some(script) = tv.request.options().get(\"postinstall\") {\n            ctx.pr\n                .finish_with_message(\"running custom postinstall hook\".to_string());\n            self.run_postinstall_hook(&ctx, &tv, script).await?;\n        }\n        ctx.pr.finish_with_message(\"installed\".to_string());\n        Ok(tv)\n    }\n\n    async fn run_postinstall_hook(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        script: &str,\n    ) -> eyre::Result<()> {\n        // Get pre-tools environment variables from config\n        let mut env_vars = self.exec_env(&ctx.config, &ctx.ts, tv).await?;\n\n        // Add pre-tools environment variables from config if available\n        if let Some(config_env) = ctx.config.env_maybe() {\n            for (k, v) in config_env {\n                env_vars.entry(k).or_insert(v);\n            }\n        }\n\n        // Use the backend's list_bin_paths to get the correct binary directories\n        // instead of hardcoding install_path/bin, which may not match the actual\n        // binary location for backends like aqua\n        let bin_paths = self.list_bin_paths(&ctx.config, tv).await?;\n        let mut path_env = PathEnv::from_iter(env::PATH.clone());\n        for p in bin_paths {\n            path_env.add(p);\n        }\n\n        CmdLineRunner::new(&*env::SHELL)\n            .env(&*env::PATH_KEY, path_env.join())\n            .env(\"MISE_TOOL_INSTALL_PATH\", tv.install_path())\n            .env(\"MISE_TOOL_NAME\", tv.ba().short.clone())\n            .env(\"MISE_TOOL_VERSION\", tv.version.clone())\n            .with_pr(ctx.pr.as_ref())\n            .arg(env::SHELL_COMMAND_FLAG)\n            .arg(script)\n            .envs(env_vars)\n            .execute()?;\n        Ok(())\n    }\n\n    /// Returns the number of operations for installation progress tracking.\n    /// Override this if your backend has a different number of operations.\n    /// Default is 3: download, checksum, extract\n    async fn install_operation_count(&self, _tv: &ToolVersion, _ctx: &InstallContext) -> usize {\n        3\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion>;\n    async fn uninstall_version(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n        dryrun: bool,\n    ) -> eyre::Result<()> {\n        pr.set_message(\"uninstall\".into());\n\n        if !dryrun {\n            self.uninstall_version_impl(config, pr, tv).await?;\n        }\n        let rmdir = |dir: &Path| {\n            if !dir.exists() {\n                return Ok(());\n            }\n            pr.set_message(format!(\"remove {}\", display_path(dir)));\n            if dryrun {\n                return Ok(());\n            }\n            remove_all_with_warning(dir)\n        };\n        rmdir(&tv.install_path())?;\n        if !Settings::get().always_keep_download {\n            rmdir(&tv.download_path())?;\n        }\n        rmdir(&tv.cache_path())?;\n        Ok(())\n    }\n    async fn uninstall_version_impl(\n        &self,\n        _config: &Arc<Config>,\n        _pr: &dyn SingleReport,\n        _tv: &ToolVersion,\n    ) -> Result<()> {\n        Ok(())\n    }\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        match tv.request {\n            ToolRequest::System { .. } => Ok(vec![]),\n            _ => Ok(vec![tv.install_path().join(\"bin\")]),\n        }\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        _tv: &ToolVersion,\n    ) -> Result<BTreeMap<String, String>> {\n        Ok(BTreeMap::new())\n    }\n\n    async fn which(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        bin_name: &str,\n    ) -> eyre::Result<Option<PathBuf>> {\n        let bin_paths = self\n            .list_bin_paths(config, tv)\n            .await?\n            .into_iter()\n            .filter(|p| p.parent().is_some());\n        for bin_path in bin_paths {\n            let paths_with_ext = if cfg!(windows) {\n                vec![\n                    bin_path.clone(),\n                    bin_path.join(bin_name).with_extension(\"exe\"),\n                    bin_path.join(bin_name).with_extension(\"cmd\"),\n                    bin_path.join(bin_name).with_extension(\"bat\"),\n                    bin_path.join(bin_name).with_extension(\"ps1\"),\n                ]\n            } else {\n                vec![bin_path.join(bin_name)]\n            };\n            for bin_path in paths_with_ext {\n                if bin_path.exists() && file::is_executable(&bin_path) {\n                    return Ok(Some(bin_path));\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    fn create_install_dirs(&self, tv: &ToolVersion) -> eyre::Result<()> {\n        let _ = remove_all_with_warning(tv.install_path());\n        if !Settings::get().always_keep_download {\n            let _ = remove_all_with_warning(tv.download_path());\n        }\n        let _ = remove_all_with_warning(tv.cache_path());\n        let _ = file::remove_file(tv.install_path()); // removes if it is a symlink\n        file::create_dir_all(tv.install_path())?;\n        file::create_dir_all(tv.download_path())?;\n        file::create_dir_all(tv.cache_path())?;\n        File::create(self.incomplete_file_path(tv))?;\n        Ok(())\n    }\n    fn cleanup_install_dirs_on_error(&self, tv: &ToolVersion) {\n        if !Settings::get().always_keep_install {\n            let _ = remove_all_with_warning(tv.install_path());\n            // Clean up the incomplete marker from cache\n            let _ = file::remove_file(self.incomplete_file_path(tv));\n            // Remove parent installs dir if it's now empty (no other versions present)\n            let installs_path = &self.ba().installs_path;\n            if installs_path.exists()\n                && let Ok(entries) = file::dir_subdirs(installs_path)\n                && entries.is_empty()\n            {\n                let _ = remove_all_with_warning(installs_path);\n            }\n            self.cleanup_install_dirs(tv);\n        }\n    }\n    fn cleanup_install_dirs(&self, tv: &ToolVersion) {\n        if !Settings::get().always_keep_download {\n            let _ = remove_all_with_warning(tv.download_path());\n        }\n    }\n    fn incomplete_file_path(&self, tv: &ToolVersion) -> PathBuf {\n        install_state::incomplete_file_path(&tv.ba().short, &tv.tv_pathname())\n    }\n\n    async fn path_env_for_cmd(&self, config: &Arc<Config>, tv: &ToolVersion) -> Result<OsString> {\n        let path = self\n            .list_bin_paths(config, tv)\n            .await?\n            .into_iter()\n            .chain(\n                self.dependency_toolset(config)\n                    .await?\n                    .list_paths(config)\n                    .await,\n            )\n            .chain(env::PATH.clone());\n        Ok(env::join_paths(path)?)\n    }\n\n    async fn dependency_toolset(&self, config: &Arc<Config>) -> eyre::Result<Toolset> {\n        let dependencies = self\n            .get_all_dependencies(true)?\n            .into_iter()\n            .map(|ba| ba.short)\n            .collect();\n        let mut ts: Toolset = config\n            .get_tool_request_set()\n            .await?\n            .filter_by_tool(dependencies)\n            .into();\n        ts.resolve(config).await?;\n        Ok(ts)\n    }\n\n    async fn dependency_which(&self, config: &Arc<Config>, bin: &str) -> Option<PathBuf> {\n        if let Some(bin) = file::which_non_pristine(bin) {\n            return Some(bin);\n        }\n        let Ok(ts) = self.dependency_toolset(config).await else {\n            return None;\n        };\n        let (b, tv) = ts.which(config, bin).await?;\n        b.which(config, &tv, bin).await.ok().flatten()\n    }\n\n    /// Check if a required dependency is available and show a warning if not.\n    /// This provides a consistent warning message format across all backends.\n    /// Changed to warning instead of error to avoid CI failures on Windows.\n    async fn warn_if_dependency_missing(\n        &self,\n        config: &Arc<Config>,\n        program: &str,\n        install_instructions: &str,\n    ) {\n        let found = if self.dependency_which(config, program).await.is_some() {\n            true\n        } else if cfg!(windows) {\n            // On Windows, also check for program with Windows executable extensions\n            let settings = Settings::get();\n            let mut found = false;\n            for ext in &settings.windows_executable_extensions {\n                if self\n                    .dependency_which(config, &format!(\"{}.{}\", program, ext))\n                    .await\n                    .is_some()\n                {\n                    found = true;\n                    break;\n                }\n            }\n            found\n        } else {\n            false\n        };\n\n        if !found {\n            warn!(\n                \"{} may be required but was not found.\\n\\n{}\",\n                program, install_instructions\n            );\n        }\n    }\n\n    async fn dependency_env(&self, config: &Arc<Config>) -> eyre::Result<BTreeMap<String, String>> {\n        let mut env = self\n            .dependency_toolset(config)\n            .await?\n            .full_env(config)\n            .await?;\n\n        // Remove mise shims from PATH to prevent infinite shim recursion when a\n        // dependency tool (e.g., go) is configured but not installed. Without this,\n        // the shim for the dependency would call `mise exec` which would call the\n        // shim again infinitely.\n        if let Some(path_val) = env.get(&*env::PATH_KEY) {\n            let paths: Vec<_> = env::split_paths(path_val).collect();\n            let original_len = paths.len();\n            #[cfg(not(windows))]\n            let filtered: Vec<_> = paths\n                .into_iter()\n                .filter(|p| p.as_path() != *dirs::SHIMS)\n                .collect();\n            #[cfg(windows)]\n            let filtered: Vec<_> = {\n                // Pre-compute once; case-insensitive + separator-normalised to handle\n                // path variations such as ~/.local/share/mise\\shims vs\n                // C:\\Users\\user\\.local\\share\\mise\\shims\n                let shims_normalized = dirs::SHIMS\n                    .to_string_lossy()\n                    .to_lowercase()\n                    .replace('/', \"\\\\\");\n                paths\n                    .into_iter()\n                    .filter(|p| {\n                        let expanded = file::replace_path(p);\n                        expanded.to_string_lossy().to_lowercase().replace('/', \"\\\\\")\n                            != shims_normalized\n                    })\n                    .collect()\n            };\n            if filtered.len() != original_len {\n                let joined = env::join_paths(&filtered)?;\n                env.insert(\n                    env::PATH_KEY.to_string(),\n                    joined.to_string_lossy().into_owned(),\n                );\n            }\n        }\n\n        Ok(env)\n    }\n\n    fn fuzzy_match_filter(&self, versions: Vec<String>, query: &str) -> Vec<String> {\n        let escaped_query = regex::escape(query);\n        let query_pattern = if query == \"latest\" {\n            \"v?[0-9].*\"\n        } else {\n            &escaped_query\n        };\n        // For numeric-ish prefixes like \"1.2\" we want to match \"1.2.3\" / \"1.2-rc1\" etc,\n        // but NOT \"1.20\". The old pattern achieved this by requiring a separator after the query.\n        // However, vendor-prefixed queries like \"temurin-\" need to match digits immediately after\n        // the prefix (e.g. \"temurin-25.0.1\").\n        let query_regex = if query != \"latest\" && query.ends_with('-') {\n            Regex::new(&format!(\"^{query_pattern}.*$\")).unwrap()\n        } else {\n            Regex::new(&format!(\"^{query_pattern}([+\\\\-.].+)?$\")).unwrap()\n        };\n\n        // Also create a regex without the 'v' prefix if query starts with 'v'\n        // This allows \"v1.0.0\" to match \"1.0.0\" in registries that don't use v-prefix\n        let query_without_v_regex = if query.starts_with('v') || query.starts_with('V') {\n            let without_v = regex::escape(&query[1..]);\n            let re = if query.ends_with('-') {\n                Regex::new(&format!(\"^{without_v}.*$\")).unwrap()\n            } else {\n                Regex::new(&format!(\"^{without_v}([+\\\\-.].+)?$\")).unwrap()\n            };\n            Some(re)\n        } else {\n            None\n        };\n\n        versions\n            .into_iter()\n            .filter(|v| {\n                if query == v {\n                    return true;\n                }\n                if VERSION_REGEX.is_match(v) {\n                    return false;\n                }\n                if query_regex.is_match(v) {\n                    return true;\n                }\n                // Try matching without the 'v' prefix\n                if let Some(ref re) = query_without_v_regex\n                    && re.is_match(v)\n                {\n                    return true;\n                }\n                false\n            })\n            .collect()\n    }\n\n    fn get_remote_version_cache(&self) -> Arc<TokioMutex<VersionCacheManager>> {\n        // use a mutex to prevent deadlocks that occurs due to reentrant cache access\n        static REMOTE_VERSION_CACHE: Lazy<\n            Mutex<HashMap<String, Arc<TokioMutex<VersionCacheManager>>>>,\n        > = Lazy::new(Default::default);\n\n        REMOTE_VERSION_CACHE\n            .lock()\n            .unwrap()\n            .entry(self.ba().full())\n            .or_insert_with(|| {\n                let mut cm = CacheManagerBuilder::new(\n                    self.ba().cache_path.join(\"remote_versions.msgpack.z\"),\n                )\n                .with_fresh_duration(Settings::get().fetch_remote_versions_cache());\n                if let Some(plugin_path) = self.plugin().map(|p| p.path()) {\n                    cm = cm\n                        .with_fresh_file(plugin_path.clone())\n                        .with_fresh_file(plugin_path.join(\"bin/list-all\"))\n                }\n\n                TokioMutex::new(cm.build()).into()\n            })\n            .clone()\n    }\n\n    fn verify_checksum(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        file: &Path,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let filename = file.file_name().unwrap().to_string_lossy().to_string();\n        let lockfile_enabled = settings.lockfile_enabled();\n\n        // Get the platform key for this tool and platform\n        let platform_key = self.get_platform_key();\n\n        // Get or create asset info for this platform\n        let platform_info = tv.lock_platforms.entry(platform_key.clone()).or_default();\n\n        if let Some(checksum) = &platform_info.checksum {\n            ctx.pr.set_message(format!(\"checksum {filename}\"));\n            if let Some((algo, check)) = checksum.split_once(':') {\n                hash::ensure_checksum(file, check, Some(ctx.pr.as_ref()), algo)?;\n            } else {\n                bail!(\"Invalid checksum: {checksum}\");\n            }\n        } else if lockfile_enabled {\n            ctx.pr.set_message(format!(\"generate checksum {filename}\"));\n            let hash = hash::file_hash_blake3(file, Some(ctx.pr.as_ref()))?;\n            platform_info.checksum = Some(format!(\"blake3:{hash}\"));\n        }\n\n        // Handle size verification and generation\n        if let Some(expected_size) = platform_info.size {\n            ctx.pr.set_message(format!(\"verify size {filename}\"));\n            let actual_size = file.metadata()?.len();\n            if actual_size != expected_size {\n                bail!(\n                    \"Size mismatch for {}: expected {}, got {}\",\n                    filename,\n                    expected_size,\n                    actual_size\n                );\n            }\n        } else if lockfile_enabled {\n            platform_info.size = Some(file.metadata()?.len());\n        }\n        Ok(())\n    }\n\n    async fn outdated_info(\n        &self,\n        _config: &Arc<Config>,\n        _tv: &ToolVersion,\n        _bump: bool,\n        _opts: &ResolveOptions,\n    ) -> Result<Option<OutdatedInfo>> {\n        Ok(None)\n    }\n\n    // ========== Lockfile Metadata Fetching Methods ==========\n\n    /// Optional: Provide tarball URL for platform-specific tool installation\n    /// Backends can implement this for simple tarball-based tools\n    async fn get_tarball_url(\n        &self,\n        _tv: &ToolVersion,\n        _target: &PlatformTarget,\n    ) -> Result<Option<String>> {\n        Ok(None) // Default: no tarball URL available\n    }\n\n    /// Optional: Provide GitHub/GitLab release info for platform-specific tool installation\n    /// Backends can implement this for GitHub/GitLab release-based tools\n    async fn get_github_release_info(\n        &self,\n        _tv: &ToolVersion,\n        _target: &PlatformTarget,\n    ) -> Result<Option<GitHubReleaseInfo>> {\n        Ok(None) // Default: no GitHub release info available\n    }\n\n    /// Resolve platform-specific lock information without installation\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // Try simple tarball approach first\n        if let Some(tarball_url) = self.get_tarball_url(tv, target).await? {\n            return self\n                .resolve_lock_info_from_tarball(&tarball_url, tv, target)\n                .await;\n        }\n\n        // Try GitHub/GitLab release approach second\n        if let Some(release_info) = self.get_github_release_info(tv, target).await? {\n            return self\n                .resolve_lock_info_from_github_release(&release_info, tv, target)\n                .await;\n        }\n\n        // Fall back to basic platform info without URLs/metadata\n        self.resolve_lock_info_fallback(tv, target).await\n    }\n\n    /// Shared logic for processing tarball-based tools\n    /// Downloads tarball headers, extracts size and URL info, and populates PlatformInfo\n    async fn resolve_lock_info_from_tarball(\n        &self,\n        tarball_url: &str,\n        _tv: &ToolVersion,\n        _target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // For now, just return basic info with the URL\n        // In a full implementation, this would:\n        // 1. Make HEAD request to get content-length\n        // 2. Potentially download to get checksum\n        // 3. Handle any URL-specific logic\n        Ok(PlatformInfo {\n            checksum: None, // TODO: Implement checksum fetching\n            size: None,     // TODO: Implement size fetching via HEAD request\n            url: Some(tarball_url.to_string()),\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n\n    /// Shared logic for processing GitHub/GitLab release-based tools\n    /// Queries release API, finds platform-specific assets, and populates PlatformInfo\n    async fn resolve_lock_info_from_github_release(\n        &self,\n        release_info: &GitHubReleaseInfo,\n        _tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // For now, just return basic info\n        // In a full implementation, this would:\n        // 1. Query GitHub/GitLab release API\n        // 2. Find matching asset for the target platform\n        // 3. Extract download URL, size, and checksums\n        let asset_name = release_info.asset_pattern.as_ref().map(|pattern| {\n            pattern\n                .replace(\"{os}\", target.os_name())\n                .replace(\"{arch}\", target.arch_name())\n        });\n\n        // Combine api_url (base URL) with asset_name to get full download URL\n        let asset_url = match (&release_info.api_url, &asset_name) {\n            (Some(base_url), Some(name)) => Some(format!(\"{}/{}\", base_url, name)),\n            _ => asset_name.clone(),\n        };\n\n        Ok(PlatformInfo {\n            checksum: None, // TODO: Implement checksum fetching from releases\n            size: None,     // TODO: Implement size fetching from GitHub API\n            url: asset_url,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n\n    /// Fallback method when no specific metadata resolution is available\n    /// Returns minimal PlatformInfo without external URLs\n    async fn resolve_lock_info_fallback(\n        &self,\n        _tv: &ToolVersion,\n        _target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // This is the fallback - no external metadata available\n        // The tool would need to be installed to generate platform info\n        Ok(PlatformInfo {\n            checksum: None,\n            size: None,\n            url: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n}\n\n/// Helper function for calculating install operation count in HTTP/S3-style backends.\n/// Used by HttpBackend and S3Backend to avoid code duplication.\npub fn http_install_operation_count(\n    has_checksum_opt: bool,\n    platform_key: &str,\n    tv: &ToolVersion,\n) -> usize {\n    let settings = Settings::get();\n    let mut count = 2; // download + extraction\n    if has_checksum_opt {\n        count += 1;\n    }\n    let lockfile_enabled = settings.lockfile_enabled();\n    let has_lockfile_checksum = tv\n        .lock_platforms\n        .get(platform_key)\n        .and_then(|p| p.checksum.as_ref())\n        .is_some();\n    if lockfile_enabled || has_lockfile_checksum {\n        count += 1;\n    }\n    count\n}\n\nfn find_match_in_list(list: &[String], query: &str) -> Option<String> {\n    match list.contains(&query.to_string()) {\n        true => Some(query.to_string()),\n        false => list.last().map(|s| s.to_string()),\n    }\n}\n\nfn rmdir(dir: &Path, pr: &dyn SingleReport) -> eyre::Result<()> {\n    if !dir.exists() {\n        return Ok(());\n    }\n    pr.set_message(format!(\"remove {}\", &dir.to_string_lossy()));\n    remove_all(dir).wrap_err_with(|| {\n        format!(\n            \"Failed to remove directory {}\",\n            style(&dir.to_string_lossy()).cyan().for_stderr()\n        )\n    })\n}\n\npub fn unalias_backend(backend: &str) -> &str {\n    match backend {\n        \"nodejs\" => \"node\",\n        \"golang\" => \"go\",\n        _ => backend.trim_start_matches(\"core:\"),\n    }\n}\n\n#[test]\nfn test_unalias_backend() {\n    assert_eq!(unalias_backend(\"node\"), \"node\");\n    assert_eq!(unalias_backend(\"nodejs\"), \"node\");\n    assert_eq!(unalias_backend(\"core:node\"), \"node\");\n    assert_eq!(unalias_backend(\"golang\"), \"go\");\n}\n\nimpl Display for dyn Backend {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.id())\n    }\n}\n\nimpl Eq for dyn Backend {}\n\nimpl PartialEq for dyn Backend {\n    fn eq(&self, other: &Self) -> bool {\n        self.get_plugin_type() == other.get_plugin_type() && self.id() == other.id()\n    }\n}\n\nimpl Hash for dyn Backend {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.id().hash(state)\n    }\n}\n\nimpl PartialOrd for dyn Backend {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for dyn Backend {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.id().cmp(other.id())\n    }\n}\n\npub async fn reset() -> Result<()> {\n    install_state::reset();\n    *TOOLS.lock().unwrap() = None;\n    load_tools().await?;\n    Ok(())\n}\n"
  },
  {
    "path": "src/backend/npm.rs",
    "content": "use crate::Result;\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::settings::NpmPackageManager;\nuse crate::config::{Config, Settings};\nuse crate::install_context::InstallContext;\nuse crate::timeout;\nuse crate::toolset::ToolVersion;\nuse async_trait::async_trait;\nuse serde_json::Value;\nuse std::{fmt::Debug, sync::Arc};\nuse tokio::sync::Mutex as TokioMutex;\n\n#[derive(Debug)]\npub struct NPMBackend {\n    ba: Arc<BackendArg>,\n    // use a mutex to prevent deadlocks that occurs due to reentrant cache access\n    latest_version_cache: TokioMutex<CacheManager<Option<String>>>,\n}\n\nconst NPM_PROGRAM: &str = if cfg!(windows) { \"npm.cmd\" } else { \"npm\" };\n\n#[async_trait]\nimpl Backend for NPMBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Npm\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        // npm CLI is always needed for version queries (npm view), plus the configured\n        // package manager for installation. We avoid listing all package managers to\n        // prevent incorrect dependency edges.\n        let settings = Settings::get();\n        let package_manager = settings.npm.package_manager;\n        let tool_name = self.tool_name();\n\n        // Avoid circular dependency when installing npm itself\n        // But we still need the configured package manager for installation\n        if tool_name == \"npm\" {\n            return match package_manager {\n                NpmPackageManager::Bun => Ok(vec![\"node\", \"bun\"]),\n                NpmPackageManager::Pnpm => Ok(vec![\"node\", \"pnpm\"]),\n                NpmPackageManager::Npm => Ok(vec![\"node\"]),\n            };\n        }\n\n        // Avoid circular dependency when installing the configured package manager\n        // e.g., npm:bun with bun configured, or npm:pnpm with pnpm configured\n        if tool_name == package_manager.to_string() {\n            // Still need npm for version queries\n            return Ok(vec![\"node\", \"npm\"]);\n        }\n\n        // For regular packages: need npm (for version queries) + configured package manager\n        let mut deps = vec![\"node\", \"npm\"];\n        match package_manager {\n            NpmPackageManager::Bun => deps.push(\"bun\"),\n            NpmPackageManager::Pnpm => deps.push(\"pnpm\"),\n            NpmPackageManager::Npm => {} // npm is already in deps\n        }\n        Ok(deps)\n    }\n\n    /// NPM installs packages from npm registry using version specs (e.g., eslint@8.0.0).\n    /// It doesn't support installing from direct URLs, so lockfile URLs are not applicable.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        // Use npm CLI to respect custom registry configurations\n        self.ensure_npm_for_version_check(config).await;\n        timeout::run_with_timeout_async(\n            async || {\n                let env = self.dependency_env(config).await?;\n\n                let raw = cmd!(\n                    NPM_PROGRAM,\n                    \"view\",\n                    self.tool_name(),\n                    \"versions\",\n                    \"time\",\n                    \"--json\"\n                )\n                .full_env(&env)\n                .env(\"NPM_CONFIG_UPDATE_NOTIFIER\", \"false\")\n                .read()?;\n                let data: Value = serde_json::from_str(&raw)?;\n                let versions = data[\"versions\"]\n                    .as_array()\n                    .ok_or_else(|| eyre::eyre!(\"invalid versions\"))?;\n                let time = data[\"time\"]\n                    .as_object()\n                    .ok_or_else(|| eyre::eyre!(\"invalid time\"))?;\n                let version_info = versions\n                    .iter()\n                    .filter_map(|v| v.as_str())\n                    .map(|version| {\n                        let created_at = time\n                            .get(version)\n                            .and_then(|v| v.as_str())\n                            .map(|s| s.to_string());\n                        VersionInfo {\n                            version: version.to_string(),\n                            created_at,\n                            ..Default::default()\n                        }\n                    })\n                    .collect();\n\n                Ok(version_info)\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n    }\n\n    async fn latest_stable_version(&self, config: &Arc<Config>) -> eyre::Result<Option<String>> {\n        // TODO: Add bun support for getting latest version without npm\n        // See TODO in _list_remote_versions for details\n        self.ensure_npm_for_version_check(config).await;\n        let cache = self.latest_version_cache.lock().await;\n        let this = self;\n        timeout::run_with_timeout_async(\n            async || {\n                cache\n                    .get_or_try_init_async(async || {\n                        // Always use npm for getting version info since bun info requires package.json\n                        // bun is only used for actual package installation\n                        let raw =\n                            cmd!(NPM_PROGRAM, \"view\", this.tool_name(), \"dist-tags\", \"--json\")\n                                .full_env(this.dependency_env(config).await?)\n                                .env(\"NPM_CONFIG_UPDATE_NOTIFIER\", \"false\")\n                                .read()?;\n                        let dist_tags: Value = serde_json::from_str(&raw)?;\n                        match dist_tags[\"latest\"] {\n                            Value::String(ref s) => Ok(Some(s.clone())),\n                            _ => this.latest_version(config, Some(\"latest\".into())).await,\n                        }\n                    })\n                    .await\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n        .cloned()\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        self.check_install_deps(&ctx.config).await;\n        match Settings::get().npm.package_manager {\n            NpmPackageManager::Bun => {\n                CmdLineRunner::new(\"bun\")\n                    .arg(\"install\")\n                    .arg(format!(\"{}@{}\", self.tool_name(), tv.version))\n                    .arg(\"--global\")\n                    .arg(\"--trust\")\n                    // Isolated linker does not symlink binaries into BUN_INSTALL_BIN properly.\n                    // https://github.com/jdx/mise/discussions/7541\n                    .arg(\"--linker\")\n                    .arg(\"hoisted\")\n                    .with_pr(ctx.pr.as_ref())\n                    .envs(ctx.ts.env_with_path_without_tools(&ctx.config).await?)\n                    .env(\"BUN_INSTALL_GLOBAL_DIR\", tv.install_path())\n                    .env(\"BUN_INSTALL_BIN\", tv.install_path().join(\"bin\"))\n                    .prepend_path(ctx.ts.list_paths(&ctx.config).await)?\n                    .prepend_path(\n                        self.dependency_toolset(&ctx.config)\n                            .await?\n                            .list_paths(&ctx.config)\n                            .await,\n                    )?\n                    .current_dir(tv.install_path())\n                    .execute()?;\n            }\n            NpmPackageManager::Pnpm => {\n                let bin_dir = tv.install_path().join(\"bin\");\n                crate::file::create_dir_all(&bin_dir)?;\n                CmdLineRunner::new(\"pnpm\")\n                    .arg(\"add\")\n                    .arg(\"--global\")\n                    .arg(format!(\"{}@{}\", self.tool_name(), tv.version))\n                    .arg(\"--global-dir\")\n                    .arg(tv.install_path())\n                    .arg(\"--global-bin-dir\")\n                    .arg(&bin_dir)\n                    .with_pr(ctx.pr.as_ref())\n                    .envs(ctx.ts.env_with_path_without_tools(&ctx.config).await?)\n                    .prepend_path(ctx.ts.list_paths(&ctx.config).await)?\n                    .prepend_path(\n                        self.dependency_toolset(&ctx.config)\n                            .await?\n                            .list_paths(&ctx.config)\n                            .await,\n                    )?\n                    // required to avoid pnpm error \"global bin dir isn't in PATH\"\n                    // https://github.com/pnpm/pnpm/issues/9333\n                    .prepend_path(vec![bin_dir])?\n                    .execute()?;\n            }\n            _ => {\n                CmdLineRunner::new(NPM_PROGRAM)\n                    .arg(\"install\")\n                    .arg(\"-g\")\n                    .arg(format!(\"{}@{}\", self.tool_name(), tv.version))\n                    .arg(\"--prefix\")\n                    .arg(tv.install_path())\n                    .with_pr(ctx.pr.as_ref())\n                    .envs(ctx.ts.env_with_path_without_tools(&ctx.config).await?)\n                    .env(\"NPM_CONFIG_UPDATE_NOTIFIER\", \"false\")\n                    .prepend_path(ctx.ts.list_paths(&ctx.config).await)?\n                    .prepend_path(\n                        self.dependency_toolset(&ctx.config)\n                            .await?\n                            .list_paths(&ctx.config)\n                            .await,\n                    )?\n                    .execute()?;\n            }\n        }\n        Ok(tv)\n    }\n\n    #[cfg(windows)]\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &crate::toolset::ToolVersion,\n    ) -> eyre::Result<Vec<std::path::PathBuf>> {\n        if Settings::get().npm.package_manager == NpmPackageManager::Npm {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(vec![tv.install_path().join(\"bin\")])\n        }\n    }\n}\n\nimpl NPMBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self {\n            latest_version_cache: TokioMutex::new(\n                CacheManagerBuilder::new(ba.cache_path.join(\"latest_version.msgpack.z\"))\n                    .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n                    .build(),\n            ),\n            ba: Arc::new(ba),\n        }\n    }\n\n    /// Check dependencies for version checking (always needs npm)\n    async fn ensure_npm_for_version_check(&self, config: &Arc<Config>) {\n        // We always need npm for querying package versions\n        // TODO: Once bun supports querying packages without package.json, this can be updated\n        self.warn_if_dependency_missing(\n            config,\n            \"npm\", // Use \"npm\" for dependency check, which will check npm.cmd on Windows\n            \"To use npm packages with mise, you need to install Node.js first:\\n\\\n              mise use node@latest\\n\\n\\\n            Note: npm is required for querying package information, even when using bun for installation.\",\n        )\n        .await\n    }\n\n    /// Check dependencies for package installation (npm or bun based on settings)\n    async fn check_install_deps(&self, config: &Arc<Config>) {\n        match Settings::get().npm.package_manager {\n            NpmPackageManager::Bun => {\n                self.warn_if_dependency_missing(\n                    config,\n                    \"bun\",\n                    \"To use npm packages with bun, you need to install bun first:\\n\\\n                      mise use bun@latest\\n\\n\\\n                    Or switch back to npm by setting:\\n\\\n                      mise settings npm.package_manager=npm\",\n                )\n                .await\n            }\n            NpmPackageManager::Pnpm => {\n                self.warn_if_dependency_missing(\n                    config,\n                    \"pnpm\",\n                    \"To use npm packages with pnpm, you need to install pnpm first:\\n\\\n                      mise use pnpm@latest\\n\\n\\\n                    Or switch back to npm by setting:\\n\\\n                      mise settings npm.package_manager=npm\",\n                )\n                .await\n            }\n            _ => {\n                self.warn_if_dependency_missing(\n                    config,\n                    \"npm\",\n                    \"To use npm packages with mise, you need to install Node.js first:\\n\\\n                      mise use node@latest\\n\\n\\\n                    Alternatively, you can use bun or pnpm instead of npm by setting:\\n\\\n                      mise settings npm.package_manager=bun\",\n                )\n                .await\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::cli::args::{BackendArg, BackendResolution};\n\n    fn create_npm_backend(tool: &str) -> NPMBackend {\n        let ba = BackendArg::new_raw(\n            \"npm\".to_string(),\n            Some(tool.to_string()),\n            tool.to_string(),\n            None,\n            BackendResolution::new(true),\n        );\n        NPMBackend::from_arg(ba)\n    }\n\n    #[test]\n    fn test_get_dependencies_for_npm_itself() {\n        // When the tool is npm itself (npm:npm) with default settings (npm as package manager),\n        // it should only depend on node. With bun/pnpm configured, it would include those too.\n        let backend = create_npm_backend(\"npm\");\n        let deps = backend.get_dependencies().unwrap();\n        assert_eq!(deps, vec![\"node\"]);\n    }\n\n    #[test]\n    fn test_get_dependencies_default_package_manager() {\n        // With default settings (npm), packages should depend on node + npm\n        let backend = create_npm_backend(\"prettier\");\n        let deps = backend.get_dependencies().unwrap();\n        assert!(deps.contains(&\"node\"));\n        assert!(deps.contains(&\"npm\"));\n        assert!(!deps.contains(&\"bun\"));\n        assert!(!deps.contains(&\"pnpm\"));\n    }\n}\n"
  },
  {
    "path": "src/backend/pipx.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::{Backend, VersionInfo};\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::file;\nuse crate::github;\nuse crate::http::HTTP_FETCH;\nuse crate::install_context::InstallContext;\nuse crate::timeout;\nuse crate::toolset::{ToolRequest, ToolVersion, ToolVersionOptions, Toolset, ToolsetBuilder};\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse async_trait::async_trait;\nuse eyre::{Result, eyre};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse regex::Regex;\nuse std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::{fmt::Debug, sync::Arc};\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct PIPXBackend {\n    ba: Arc<BackendArg>,\n    latest_version_cache: CacheManager<Option<String>>,\n}\n\n#[async_trait]\nimpl Backend for PIPXBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Pipx\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"pipx\"])\n    }\n\n    fn get_optional_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"uv\"])\n    }\n\n    /// Pipx installs packages from PyPI or Git using version specs (e.g., black==24.3.0).\n    /// It doesn't support installing from direct URLs, so lockfile URLs are not applicable.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        match self.tool_name().parse()? {\n            PipxRequest::Pypi(package) => {\n                let registry_url = Self::get_registry_url()?;\n                if registry_url.contains(\"/json\") {\n                    debug!(\"Fetching JSON for {}\", package);\n                    let url = registry_url.replace(\"{}\", &package);\n                    let data: PypiPackage = HTTP_FETCH.json(url).await?;\n\n                    // Get versions sorted and attach timestamps from the first file in each release\n                    let versions = data\n                        .releases\n                        .into_iter()\n                        .sorted_by_cached_key(|(v, _)| Versioning::new(v))\n                        .map(|(version, files)| {\n                            // Get the earliest upload_time from the release files\n                            let created_at = files\n                                .iter()\n                                .filter_map(|f| f.upload_time.as_ref())\n                                .min()\n                                .cloned();\n                            VersionInfo {\n                                version,\n                                created_at,\n                                ..Default::default()\n                            }\n                        })\n                        .collect();\n\n                    Ok(versions)\n                } else {\n                    debug!(\"Fetching HTML for {}\", package);\n                    let url = registry_url.replace(\"{}\", &package);\n                    let html = HTTP_FETCH.get_html(url).await?;\n\n                    // PEP-0503 (HTML format doesn't include timestamps)\n                    let version_re = regex!(\n                        r#\"href=[\"'][^\"']*/([^/]+)\\.tar\\.gz(?:#(md5|sha1|sha224|sha256|sha384|sha512)=[0-9A-Fa-f]+)?[\"']\"#\n                    );\n\n                    let versions: Vec<VersionInfo> = version_re\n                        .captures_iter(&html)\n                        .filter_map(|cap| {\n                            let filename = cap.get(1)?.as_str();\n                            let escaped_package = regex::escape(&package);\n                            // PEP-503: normalize package names by replacing hyphens with character class that allows -, _, .\n                            let re_str = escaped_package.replace(r\"\\-\", r\"[\\-_.]\");\n                            let re_str = format!(\"^{re_str}-(.+)$\");\n                            let pkg_re = regex::Regex::new(&re_str).ok()?;\n                            let pkg_version = pkg_re.captures(filename)?.get(1)?.as_str();\n                            Some(VersionInfo {\n                                version: pkg_version.to_string(),\n                                ..Default::default()\n                            })\n                        })\n                        .sorted_by_cached_key(|v| Versioning::new(&v.version))\n                        .collect();\n\n                    Ok(versions)\n                }\n            }\n            PipxRequest::Git(url) if url.starts_with(\"https://github.com/\") => {\n                let repo = url.strip_prefix(\"https://github.com/\").unwrap();\n                let data = github::list_releases(repo).await?;\n                Ok(data\n                    .into_iter()\n                    .rev()\n                    .map(|r| VersionInfo {\n                        version: r.tag_name,\n                        created_at: Some(r.created_at),\n                        ..Default::default()\n                    })\n                    .collect())\n            }\n            PipxRequest::Git { .. } => Ok(vec![VersionInfo {\n                version: \"latest\".to_string(),\n                ..Default::default()\n            }]),\n        }\n    }\n\n    async fn latest_stable_version(&self, config: &Arc<Config>) -> eyre::Result<Option<String>> {\n        let this = self;\n        timeout::run_with_timeout_async(\n            async || {\n                this.latest_version_cache\n                    .get_or_try_init_async(async || match this.tool_name().parse()? {\n                        PipxRequest::Pypi(package) => {\n                            let registry_url = Self::get_registry_url()?;\n                            if registry_url.contains(\"/json\") {\n                                debug!(\"Fetching JSON for {}\", package);\n                                let url = registry_url.replace(\"{}\", &package);\n                                let pkg: PypiPackage = HTTP_FETCH.json(url).await?;\n                                Ok(Some(pkg.info.version))\n                            } else {\n                                debug!(\"Fetching HTML for {}\", package);\n                                let url = registry_url.replace(\"{}\", &package);\n                                let html = HTTP_FETCH.get_html(url).await?;\n\n                                 // PEP-0503\n                                let version_re = regex!(r#\"href=[\"'][^\"']*/([^/]+)\\.tar\\.gz(?:#(md5|sha1|sha224|sha256|sha384|sha512)=[0-9A-Fa-f]+)?[\"']\"#);\n\n                                let version = version_re\n                                    .captures_iter(&html)\n                                    .filter_map(|cap| {\n                                        let filename = cap.get(1)?.as_str();\n                                        let escaped_package = regex::escape(&package);\n                                        // PEP-503: normalize package names by replacing hyphens with character class that allows -, _, .\n                                        let re_str = escaped_package.replace(r\"\\-\", r\"[\\-_.]\");\n                                        let re_str = format!(\"^{re_str}-(.+)$\");\n                                        let pkg_re = regex::Regex::new(&re_str).ok()?;\n                                        let pkg_version =\n                                            pkg_re.captures(filename)?.get(1)?.as_str();\n                                        Some(pkg_version.to_string())\n                                    })\n                                    .filter(|v| {\n                                        !v.contains(\"dev\")\n                                            && !v.contains(\"a\")\n                                            && !v.contains(\"b\")\n                                            && !v.contains(\"rc\")\n                                    })\n                                    .sorted_by_cached_key(|v| Versioning::new(v))\n                                    .next_back();\n\n                                Ok(version)\n                            }\n                        }\n                        _ => this.latest_version(config, Some(\"latest\".into())).await,\n                    })\n                    .await\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n        .cloned()\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        // Check if pipx is available (unless uvx is being used)\n        let use_uvx = self.uv_is_installed(&ctx.config).await\n            && Settings::get().pipx.uvx != Some(false)\n            && tv.request.options().get(\"uvx\") != Some(\"false\");\n\n        if !use_uvx {\n            self.warn_if_dependency_missing(\n                &ctx.config,\n                \"pipx\",\n                \"To use pipx packages with mise, you need to install pipx first:\\n\\\n                  mise use pipx@latest\\n\\n\\\n                Alternatively, you can use uv/uvx by installing uv:\\n\\\n                  mise use uv@latest\",\n            )\n            .await;\n        }\n\n        let pipx_request = self\n            .tool_name()\n            .parse::<PipxRequest>()?\n            .pipx_request(&tv.version, &tv.request.options());\n\n        if use_uvx {\n            ctx.pr\n                .set_message(format!(\"uv tool install {pipx_request}\"));\n            let mut cmd = Self::uvx_cmd(\n                &ctx.config,\n                &[\"tool\", \"install\", &pipx_request],\n                self,\n                &tv,\n                &ctx.ts,\n                ctx.pr.as_ref(),\n            )\n            .await?;\n            if let Some(args) = tv.request.options().get(\"uvx_args\") {\n                cmd = cmd.args(shell_words::split(args)?);\n            }\n            cmd.execute()?;\n        } else {\n            ctx.pr.set_message(format!(\"pipx install {pipx_request}\"));\n            let mut cmd = Self::pipx_cmd(\n                &ctx.config,\n                &[\"install\", &pipx_request],\n                self,\n                &tv,\n                &ctx.ts,\n                ctx.pr.as_ref(),\n            )\n            .await?;\n            if let Some(args) = tv.request.options().get(\"pipx_args\") {\n                cmd = cmd.args(shell_words::split(args)?);\n            }\n            cmd.execute()?;\n        }\n\n        // Fix venv Python symlink to use minor version path\n        // This allows patch upgrades (3.12.1 → 3.12.2) to work without reinstalling\n        let pkg_name = self.tool_name();\n        fix_venv_python_symlink(&tv.install_path(), &pkg_name)?;\n\n        Ok(tv)\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let opts = request.options();\n        let mut result = BTreeMap::new();\n\n        // These options affect what gets installed\n        for key in [\"extras\", \"pipx_args\", \"uvx_args\", \"uvx\"] {\n            if let Some(value) = opts.get(key) {\n                result.insert(key.to_string(), value.to_string());\n            }\n        }\n\n        result\n    }\n}\n\n/// Returns install-time-only option keys for PIPX backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\n        \"extras\".into(),\n        \"pipx_args\".into(),\n        \"uvx_args\".into(),\n        \"uvx\".into(),\n    ]\n}\n\nimpl PIPXBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self {\n            latest_version_cache: CacheManagerBuilder::new(\n                ba.cache_path.join(\"latest_version.msgpack.z\"),\n            )\n            .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n            .build(),\n            ba: Arc::new(ba),\n        }\n    }\n\n    fn get_index_url() -> eyre::Result<String> {\n        let registry_url = Settings::get().pipx.registry_url.clone();\n\n        // Remove {} placeholders and trailing slashes\n        let mut url = registry_url\n            .replace(\"{}\", \"\")\n            .trim_end_matches('/')\n            .to_string();\n\n        // Handle different URL formats and convert to simple format\n        if url.contains(\"pypi.org\") {\n            // For pypi.org, convert any format to simple format\n            if url.contains(\"/pypi/\") {\n                // Replace /pypi/*/json or /pypi/*/simple with /simple\n                let re = Regex::new(r\"/pypi/[^/]*/(?:json|simple)$\").unwrap();\n                url = re.replace(&url, \"/simple\").to_string();\n            } else if !url.ends_with(\"/simple\") {\n                // If it's pypi.org but doesn't already end with /simple, make it /simple\n                let base_url = url.split(\"/simple\").next().unwrap_or(&url);\n                url = format!(\"{}/simple\", base_url.trim_end_matches('/'));\n            }\n        } else {\n            // For custom registries, ensure they end with /simple\n            if url.ends_with(\"/json\") {\n                // Replace /json with /simple\n                url = url.replace(\"/json\", \"/simple\");\n            } else if !url.ends_with(\"/simple\") {\n                // If it doesn't end with /simple, append it\n                url = format!(\"{url}/simple\");\n            }\n        }\n\n        debug!(\"Converted registry URL to index URL: {}\", url);\n        Ok(url)\n    }\n\n    fn get_registry_url() -> eyre::Result<String> {\n        let registry_url = Settings::get().pipx.registry_url.clone();\n\n        debug!(\"Pipx registry URL: {}\", registry_url);\n\n        let re = Regex::new(r\"^(http|https)://.*\\{\\}.*$\").unwrap();\n\n        if !re.is_match(&registry_url) {\n            return Err(eyre!(\n                \"Registry URL must be a valid URL and contain a {{}} placeholder\"\n            ));\n        }\n\n        Ok(registry_url)\n    }\n\n    pub async fn reinstall_all(config: &Arc<Config>) -> Result<()> {\n        let ts = ToolsetBuilder::new().build(config).await?;\n        let pipx_tools = ts\n            .list_installed_versions(config)\n            .await?\n            .into_iter()\n            .filter(|(b, _tv)| b.ba().backend_type() == BackendType::Pipx)\n            .collect_vec();\n        if Settings::get().pipx.uvx != Some(false) {\n            let pr = MultiProgressReport::get().add(\"reinstalling pipx tools with uvx\");\n            for (b, tv) in pipx_tools {\n                for (cmd, tool) in &[\n                    (\"uninstall\", tv.ba().tool_name.to_string()),\n                    (\"install\", format!(\"{}=={}\", tv.ba().tool_name, tv.version)),\n                ] {\n                    let args = &[\"tool\", cmd, tool];\n                    Self::uvx_cmd(config, args, &*b, &tv, &ts, pr.as_ref())\n                        .await?\n                        .execute()?;\n                }\n            }\n        } else {\n            let pr = MultiProgressReport::get().add(\"reinstalling pipx tools\");\n            for (b, tv) in pipx_tools {\n                let args = &[\"reinstall\", &tv.ba().tool_name];\n                Self::pipx_cmd(config, args, &*b, &tv, &ts, pr.as_ref())\n                    .await?\n                    .execute()?;\n            }\n        }\n        Ok(())\n    }\n\n    async fn uvx_cmd<'a>(\n        config: &Arc<Config>,\n        args: &[&str],\n        b: &dyn Backend,\n        tv: &ToolVersion,\n        ts: &Toolset,\n        pr: &'a dyn SingleReport,\n    ) -> Result<CmdLineRunner<'a>> {\n        let mut cmd = CmdLineRunner::new(\"uv\");\n        for arg in args {\n            cmd = cmd.arg(arg);\n        }\n        cmd.with_pr(pr)\n            .env(\"UV_TOOL_DIR\", tv.install_path())\n            .env(\"UV_TOOL_BIN_DIR\", tv.install_path().join(\"bin\"))\n            .env(\"UV_INDEX\", Self::get_index_url()?)\n            .envs(ts.env_with_path_without_tools(config).await?)\n            .prepend_path(ts.list_paths(config).await)?\n            .prepend_path(vec![tv.install_path().join(\"bin\")])?\n            .prepend_path(b.dependency_toolset(config).await?.list_paths(config).await)\n    }\n\n    async fn pipx_cmd<'a>(\n        config: &Arc<Config>,\n        args: &[&str],\n        b: &dyn Backend,\n        tv: &ToolVersion,\n        ts: &Toolset,\n        pr: &'a dyn SingleReport,\n    ) -> Result<CmdLineRunner<'a>> {\n        let mut cmd = CmdLineRunner::new(\"pipx\");\n        for arg in args {\n            cmd = cmd.arg(arg);\n        }\n        cmd.with_pr(pr)\n            .env(\"PIPX_HOME\", tv.install_path())\n            .env(\"PIPX_BIN_DIR\", tv.install_path().join(\"bin\"))\n            .env(\"PIP_INDEX_URL\", Self::get_index_url()?)\n            .envs(ts.env_with_path_without_tools(config).await?)\n            .prepend_path(ts.list_paths(config).await)?\n            .prepend_path(vec![tv.install_path().join(\"bin\")])?\n            .prepend_path(b.dependency_toolset(config).await?.list_paths(config).await)\n    }\n\n    async fn uv_is_installed(&self, config: &Arc<Config>) -> bool {\n        self.dependency_which(config, \"uv\").await.is_some()\n    }\n}\n\nenum PipxRequest {\n    /// git+https://github.com/psf/black.git@24.2.0\n    /// psf/black@24.2.0\n    Git(String),\n    /// black@24.2.0\n    Pypi(String),\n}\n\nimpl PipxRequest {\n    fn extras_from_opts(&self, opts: &ToolVersionOptions) -> String {\n        match opts.get(\"extras\") {\n            Some(extras) => format!(\"[{extras}]\"),\n            None => String::new(),\n        }\n    }\n\n    fn pipx_request(&self, v: &str, opts: &ToolVersionOptions) -> String {\n        let extras = self.extras_from_opts(opts);\n\n        if v == \"latest\" {\n            match self {\n                PipxRequest::Git(url) => format!(\"git+{url}.git\"),\n                PipxRequest::Pypi(package) => format!(\"{package}{extras}\"),\n            }\n        } else {\n            match self {\n                PipxRequest::Git(url) => format!(\"git+{url}.git@{v}\"),\n                PipxRequest::Pypi(package) => format!(\"{package}{extras}=={v}\"),\n            }\n        }\n    }\n}\n\n#[derive(serde::Deserialize)]\nstruct PypiPackage {\n    releases: IndexMap<String, Vec<PypiRelease>>,\n    info: PypiInfo,\n}\n\n#[derive(serde::Deserialize)]\nstruct PypiInfo {\n    version: String,\n}\n\n#[derive(serde::Deserialize)]\nstruct PypiRelease {\n    upload_time: Option<String>,\n}\n\nimpl FromStr for PipxRequest {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Some(cap) = regex!(r\"(git\\+)(.*)(\\.git)\").captures(s) {\n            Ok(PipxRequest::Git(cap.get(2).unwrap().as_str().to_string()))\n        } else if s.contains('/') {\n            Ok(PipxRequest::Git(format!(\"https://github.com/{s}\")))\n        } else {\n            Ok(PipxRequest::Pypi(s.to_string()))\n        }\n    }\n}\n\n/// Check if a path is within mise's Python installs directory\n#[cfg(unix)]\nfn is_mise_managed_python(path: &Path) -> bool {\n    let installs_dir = &*env::MISE_INSTALLS_DIR;\n    path.starts_with(installs_dir.join(\"python\"))\n}\n\n/// Convert a Python path with full version to use minor version\n/// e.g., .../python/3.12.1/bin/python → .../python/3.12/bin/python\n#[cfg(unix)]\nfn path_with_minor_version(path: &Path) -> Option<PathBuf> {\n    let path_str = path.to_str()?;\n\n    // Match pattern: /python/X.Y.Z/ and replace with /python/X.Y/\n    let re = regex!(r\"/python/(\\d+)\\.(\\d+)\\.\\d+/\");\n    if re.is_match(path_str) {\n        let result = re.replace(path_str, \"/python/$1.$2/\");\n        Some(PathBuf::from(result.to_string()))\n    } else {\n        None\n    }\n}\n\n/// Ensure the minor version symlink exists for a Python installation path.\n/// For example, if the path is `.../python/3.12.1/bin/python3`, this ensures\n/// that `.../python/3.12` exists as a symlink to `./3.12.1`.\n///\n/// This is normally done by `runtime_symlinks::rebuild()`, but that runs after\n/// postinstall hooks. We need to create it early so that venv symlinks work\n/// immediately for postinstall hooks.\n#[cfg(unix)]\nfn ensure_minor_version_symlink(full_version_path: &Path) -> Result<()> {\n    // Extract version components from path like .../python/3.12.1/bin/python3\n    // Use same regex pattern as path_with_minor_version for consistency\n    let re = regex!(r\"/python/(\\d+)\\.(\\d+)\\.(\\d+)/\");\n    let path_str = match full_version_path.to_str() {\n        Some(s) => s,\n        None => return Ok(()),\n    };\n\n    let caps = match re.captures(path_str) {\n        Some(c) => c,\n        None => return Ok(()),\n    };\n\n    let minor_version = format!(\"{}.{}\", &caps[1], &caps[2]); // e.g., \"3.12\"\n    let full_version = format!(\"{}.{}.{}\", &caps[1], &caps[2], &caps[3]); // e.g., \"3.12.1\"\n\n    let installs_dir = &*env::MISE_INSTALLS_DIR;\n    let python_installs = installs_dir.join(\"python\");\n    let minor_version_dir = python_installs.join(&minor_version);\n    let full_version_dir = python_installs.join(&full_version);\n\n    // Only create if the minor version symlink doesn't exist but the full version does\n    if !minor_version_dir.exists() && full_version_dir.exists() {\n        trace!(\n            \"Creating early minor version symlink: {:?} -> ./{:?}\",\n            minor_version_dir, full_version\n        );\n        // Use relative symlink with \"./\" prefix like runtime_symlinks does\n        // This allows is_runtime_symlink() to identify it for cleanup/updates\n        file::make_symlink(&PathBuf::from(\".\").join(&full_version), &minor_version_dir)?;\n    }\n\n    Ok(())\n}\n\n/// Fix the venv Python symlinks to use mise's minor version path\n/// This allows patch upgrades (3.12.1 → 3.12.2) to work without reinstalling\n///\n/// The venv structure typically has:\n/// - python -> python3 (relative symlink)\n/// - python3 -> /path/to/mise/installs/python/3.12.1/bin/python3 (absolute symlink)\n///\n/// We need to fix the absolute symlink to use minor version path (3.12 instead of 3.12.1)\n#[cfg(unix)]\nfn fix_venv_python_symlink(install_path: &Path, pkg_name: &str) -> Result<()> {\n    // For Git-based packages like \"psf/black\", the venv directory is just \"black\"\n    // Extract the actual package name (last component after any '/')\n    let actual_pkg_name = pkg_name.rsplit('/').next().unwrap_or(pkg_name);\n\n    // Check both possible venv locations: {pkg}/ for uvx, venvs/{pkg}/ for pipx\n    let venv_dirs = [\n        install_path.join(actual_pkg_name),\n        install_path.join(\"venvs\").join(actual_pkg_name),\n    ];\n\n    trace!(\n        \"fix_venv_python_symlink: checking venv dirs: {:?}\",\n        venv_dirs\n    );\n\n    for venv_dir in &venv_dirs {\n        let bin_dir = venv_dir.join(\"bin\");\n        if !bin_dir.exists() {\n            continue;\n        }\n\n        // Check python, python3, and python3.X symlinks for the one with absolute mise path\n        for name in &[\"python\", \"python3\"] {\n            let symlink_path = bin_dir.join(name);\n            if !symlink_path.is_symlink() {\n                continue;\n            }\n\n            let target = match file::resolve_symlink(&symlink_path)? {\n                Some(t) => t,\n                None => continue,\n            };\n\n            // Skip relative symlinks (like python -> python3)\n            if !target.is_absolute() {\n                continue;\n            }\n\n            if !is_mise_managed_python(&target) {\n                continue; // Leave non-mise Python alone (homebrew, uv, etc.)\n            }\n\n            if let Some(minor_path) = path_with_minor_version(&target)\n                && target.exists()\n            {\n                // Create the minor version symlink (e.g., python/3.12 -> python/3.12.1)\n                // if it doesn't exist yet. This is normally done by runtime_symlinks::rebuild,\n                // but that runs after postinstall hooks, so we need to create it now\n                // to ensure the venv symlink works immediately for postinstall hooks.\n                ensure_minor_version_symlink(&target)?;\n\n                trace!(\n                    \"Updating venv Python symlink {:?} to use minor version: {:?}\",\n                    symlink_path, minor_path\n                );\n                file::make_symlink(&minor_path, &symlink_path)?;\n            }\n        }\n    }\n    Ok(())\n}\n\n/// No-op on non-Unix platforms\n#[cfg(not(unix))]\nfn fix_venv_python_symlink(_install_path: &Path, _pkg_name: &str) -> Result<()> {\n    Ok(())\n}\n"
  },
  {
    "path": "src/backend/platform_target.rs",
    "content": "use crate::platform::Platform;\n\n/// Represents a target platform for lockfile metadata fetching\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct PlatformTarget {\n    pub platform: Platform,\n}\n\nimpl PlatformTarget {\n    pub fn new(platform: Platform) -> Self {\n        Self { platform }\n    }\n\n    pub fn from_current() -> Self {\n        Self::new(Platform::current())\n    }\n\n    pub fn os_name(&self) -> &str {\n        &self.platform.os\n    }\n\n    pub fn arch_name(&self) -> &str {\n        &self.platform.arch\n    }\n\n    pub fn qualifier(&self) -> Option<&str> {\n        self.platform.qualifier.as_deref()\n    }\n\n    pub fn to_key(&self) -> String {\n        self.platform.to_key()\n    }\n\n    /// Returns true if this target matches the current platform\n    pub fn is_current(&self) -> bool {\n        self.platform == Platform::current()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_platform_target_creation() {\n        let platform = Platform::parse(\"linux-x64\").unwrap();\n        let target = PlatformTarget::new(platform.clone());\n\n        assert_eq!(target.platform, platform);\n        assert_eq!(target.os_name(), \"linux\");\n        assert_eq!(target.arch_name(), \"x64\");\n        assert_eq!(target.qualifier(), None);\n        assert_eq!(target.to_key(), \"linux-x64\");\n    }\n\n    #[test]\n    fn test_platform_target_with_qualifier() {\n        let platform = Platform::parse(\"linux-x64-musl\").unwrap();\n        let target = PlatformTarget::new(platform);\n\n        assert_eq!(target.os_name(), \"linux\");\n        assert_eq!(target.arch_name(), \"x64\");\n        assert_eq!(target.qualifier(), Some(\"musl\"));\n        assert_eq!(target.to_key(), \"linux-x64-musl\");\n    }\n\n    #[test]\n    fn test_from_current() {\n        let target = PlatformTarget::from_current();\n        let current_platform = Platform::current();\n\n        assert_eq!(target.platform, current_platform);\n    }\n}\n"
  },
  {
    "path": "src/backend/s3.rs",
    "content": "//! S3 backend for mise - downloads tools from Amazon S3 or S3-compatible storage\n//!\n//! S3 backend requires experimental mode to be enabled.\n//!\n//! This backend allows installing tools from private or public S3 buckets.\n//! It supports version discovery via S3 object listing or manifest files.\n//!\n//! ## Configuration\n//!\n//! ```toml\n//! [tools]\n//! mytool = { version = \"1.0.0\", backend = \"s3\", url = \"s3://bucket/tools/mytool-{version}.tar.gz\" }\n//!\n//! # With version discovery from manifest\n//! [tools.mytool]\n//! backend = \"s3\"\n//! version = \"latest\"\n//! url = \"s3://bucket/tools/mytool-{version}.tar.gz\"\n//! version_list_url = \"s3://bucket/tools/versions.json\"\n//!\n//! # With S3 listing-based discovery\n//! [tools.mytool]\n//! backend = \"s3\"\n//! version = \"latest\"\n//! url = \"s3://bucket/tools/mytool-{version}.tar.gz\"\n//! version_prefix = \"tools/mytool-\"\n//! version_regex = \"mytool-([0-9.]+)\"\n//!\n//! # With custom endpoint (MinIO, etc.)\n//! [tools.mytool]\n//! backend = \"s3\"\n//! url = \"s3://bucket/tools/mytool-{version}.tar.gz\"\n//! endpoint = \"https://minio.internal:9000\"\n//! region = \"us-east-1\"\n//! ```\n\n/// S3 backend is experimental and requires `experimental = true` in settings\npub const EXPERIMENTAL: bool = true;\n\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::static_helpers::{\n    get_filename_from_url, install_artifact, lookup_with_fallback, template_string, verify_artifact,\n};\nuse crate::backend::version_list;\nuse crate::backend::{Backend, VersionInfo};\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\nuse crate::file;\nuse crate::hash;\nuse crate::install_context::InstallContext;\nuse crate::toolset::{ToolVersion, ToolVersionOptions};\nuse crate::ui::progress_report::SingleReport;\nuse async_trait::async_trait;\nuse aws_config::BehaviorVersion;\nuse aws_sdk_s3::Client as S3Client;\nuse eyre::{Result, bail, eyre};\nuse regex::Regex;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse tokio::sync::OnceCell;\nuse url::Url;\n\n/// Parsed S3 URL components\n#[derive(Debug, Clone)]\nstruct S3Url {\n    bucket: String,\n    key: String,\n}\n\nimpl S3Url {\n    /// Parse an S3 URL like \"s3://bucket/path/to/object?region=us-west-2\"\n    fn parse(url_str: &str) -> Result<Self> {\n        let url = Url::parse(url_str).map_err(|e| eyre!(\"Invalid S3 URL: {e}\"))?;\n\n        if url.scheme() != \"s3\" {\n            bail!(\"URL must use s3:// scheme, got: {}\", url.scheme());\n        }\n\n        let bucket = url\n            .host_str()\n            .ok_or_else(|| eyre!(\"S3 URL must include bucket name\"))?\n            .to_string();\n\n        if bucket.is_empty() {\n            bail!(\"S3 URL must include bucket name\");\n        }\n\n        let key = url.path().trim_start_matches('/').to_string();\n\n        Ok(Self { bucket, key })\n    }\n}\n\n/// S3 backend for downloading tools from Amazon S3 or S3-compatible storage\n#[derive(Debug)]\npub struct S3Backend {\n    ba: Arc<BackendArg>,\n    /// Cached S3 client, lazily initialized\n    client: OnceCell<S3Client>,\n}\n\nimpl S3Backend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self {\n            ba: Arc::new(ba),\n            client: OnceCell::new(),\n        }\n    }\n\n    /// Get or create the S3 client\n    async fn get_client(&self, opts: &ToolVersionOptions) -> Result<&S3Client> {\n        self.client\n            .get_or_try_init(|| async {\n                let region = lookup_with_fallback(opts, \"region\");\n                let endpoint = lookup_with_fallback(opts, \"endpoint\");\n                create_s3_client(region.as_deref(), endpoint.as_deref()).await\n            })\n            .await\n    }\n\n    /// Get option value with platform-specific fallback\n    fn get_opt(opts: &ToolVersionOptions, key: &str) -> Option<String> {\n        lookup_with_fallback(opts, key)\n    }\n\n    /// Resolve the download URL from options and version\n    fn resolve_url(&self, tv: &ToolVersion, opts: &ToolVersionOptions) -> Result<String> {\n        let url_template = Self::get_opt(opts, \"url\").ok_or_else(|| {\n            eyre!(\n                \"S3 backend requires 'url' option. Example: url = \\\"s3://bucket/tool-{{version}}.tar.gz\\\"\"\n            )\n        })?;\n\n        Ok(template_string(&url_template, tv))\n    }\n\n    /// Download an S3 object to a local file\n    async fn download_object(\n        &self,\n        client: &S3Client,\n        s3_url: &S3Url,\n        dest: &Path,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<()> {\n        debug!(\n            \"Downloading s3://{}/{} to {}\",\n            s3_url.bucket,\n            s3_url.key,\n            dest.display()\n        );\n\n        let resp = client\n            .get_object()\n            .bucket(&s3_url.bucket)\n            .key(&s3_url.key)\n            .send()\n            .await\n            .map_err(|e| handle_s3_error(e, &s3_url.bucket, &s3_url.key))?;\n\n        // Get content length for progress reporting\n        let content_length = resp.content_length().unwrap_or(0) as u64;\n        if let Some(pr) = pr {\n            pr.set_length(content_length);\n        }\n\n        // Stream the body to the file\n        let body = resp\n            .body\n            .collect()\n            .await\n            .map_err(|e| eyre!(\"Failed to read S3 response body: {e}\"))?;\n        let bytes = body.into_bytes();\n\n        // Write to temp file then rename for atomic operation\n        let tmp_path = dest.with_extension(\"tmp\");\n        file::write(&tmp_path, &bytes)?;\n        std::fs::rename(&tmp_path, dest)?;\n\n        if let Some(pr) = pr {\n            pr.set_position(content_length);\n        }\n\n        Ok(())\n    }\n\n    /// Fetch versions from a manifest file URL\n    async fn fetch_versions_from_manifest(\n        &self,\n        client: &S3Client,\n        manifest_url: &str,\n        opts: &ToolVersionOptions,\n    ) -> Result<Vec<String>> {\n        let s3_url = S3Url::parse(manifest_url)?;\n\n        // Download manifest to temp location\n        let tmp_dir = tempfile::tempdir()?;\n        let tmp_path = tmp_dir.path().join(\"versions_manifest\");\n        self.download_object(client, &s3_url, &tmp_path, None)\n            .await?;\n\n        // Read and parse the manifest\n        let content = file::read_to_string(&tmp_path)?;\n        let regex = Self::get_opt(opts, \"version_regex\");\n        let json_path = Self::get_opt(opts, \"version_json_path\");\n        let version_expr = Self::get_opt(opts, \"version_expr\");\n\n        version_list::parse_version_list(\n            &content,\n            regex.as_deref(),\n            json_path.as_deref(),\n            version_expr.as_deref(),\n        )\n    }\n\n    /// Fetch versions by listing S3 objects\n    async fn fetch_versions_from_listing(\n        &self,\n        client: &S3Client,\n        bucket: &str,\n        prefix: &str,\n        version_regex: &str,\n    ) -> Result<Vec<String>> {\n        let regex =\n            Regex::new(version_regex).map_err(|e| eyre!(\"Invalid version_regex pattern: {e}\"))?;\n\n        let mut versions = Vec::new();\n        let mut continuation_token: Option<String> = None;\n\n        loop {\n            let mut request = client.list_objects_v2().bucket(bucket).prefix(prefix);\n\n            if let Some(token) = continuation_token {\n                request = request.continuation_token(token);\n            }\n\n            let response = request\n                .send()\n                .await\n                .map_err(|e| handle_s3_error(e, bucket, prefix))?;\n\n            if let Some(contents) = response.contents {\n                for object in contents {\n                    if let Some(key) = object.key {\n                        // Extract version using regex\n                        if let Some(captures) = regex.captures(&key) {\n                            let version = captures\n                                .get(1)\n                                .or_else(|| captures.get(0))\n                                .map(|m| m.as_str().to_string());\n                            if let Some(v) = version\n                                && !versions.contains(&v)\n                            {\n                                versions.push(v);\n                            }\n                        }\n                    }\n                }\n            }\n\n            if response.is_truncated == Some(true) {\n                continuation_token = response.next_continuation_token;\n            } else {\n                break;\n            }\n        }\n\n        Ok(versions)\n    }\n\n    /// Fetch versions using the configured method (manifest or listing)\n    async fn fetch_versions(&self, config: &Arc<Config>) -> Result<Vec<String>> {\n        let opts = config.get_tool_opts(&self.ba).await?.unwrap_or_default();\n\n        // Try manifest-based version discovery first\n        if let Some(manifest_url) = Self::get_opt(&opts, \"version_list_url\") {\n            let client = self.get_client(&opts).await?;\n            return self\n                .fetch_versions_from_manifest(client, &manifest_url, &opts)\n                .await;\n        }\n\n        // Try S3 listing-based version discovery\n        if let Some(version_prefix) = Self::get_opt(&opts, \"version_prefix\") {\n            let version_regex = Self::get_opt(&opts, \"version_regex\")\n                .unwrap_or_else(|| r\"([0-9]+\\.[0-9]+\\.[0-9]+)\".to_string());\n\n            // Extract bucket from url option\n            let url_template = Self::get_opt(&opts, \"url\")\n                .ok_or_else(|| eyre!(\"S3 backend requires 'url' option for version listing\"))?;\n            let s3_url = S3Url::parse(&url_template)?;\n\n            let client = self.get_client(&opts).await?;\n            return self\n                .fetch_versions_from_listing(\n                    client,\n                    &s3_url.bucket,\n                    &version_prefix,\n                    &version_regex,\n                )\n                .await;\n        }\n\n        // No version discovery configured - return empty without needing S3 client\n        Ok(vec![])\n    }\n\n    /// Verify checksum and generate lockfile info\n    fn verify_checksum(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        file_path: &Path,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let filename = file_path.file_name().unwrap().to_string_lossy();\n        let lockfile_enabled = settings.lockfile_enabled();\n\n        let platform_key = self.get_platform_key();\n        let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n\n        // Verify or generate checksum\n        if let Some(checksum) = &platform_info.checksum {\n            ctx.pr.set_message(format!(\"checksum {filename}\"));\n            let (algo, check) = checksum\n                .split_once(':')\n                .ok_or_else(|| eyre!(\"Invalid checksum format: {checksum}\"))?;\n            hash::ensure_checksum(file_path, check, Some(ctx.pr.as_ref()), algo)?;\n        } else if lockfile_enabled {\n            ctx.pr.set_message(format!(\"generate checksum {filename}\"));\n            let h = hash::file_hash_blake3(file_path, Some(ctx.pr.as_ref()))?;\n            platform_info.checksum = Some(format!(\"blake3:{h}\"));\n        }\n\n        // Verify or record size\n        if let Some(expected_size) = platform_info.size {\n            ctx.pr.set_message(format!(\"verify size {filename}\"));\n            let actual_size = file_path.metadata()?.len();\n            if actual_size != expected_size {\n                return Err(eyre!(\n                    \"Size mismatch for {filename}: expected {expected_size}, got {actual_size}\"\n                ));\n            }\n        } else if lockfile_enabled {\n            platform_info.size = Some(file_path.metadata()?.len());\n        }\n\n        Ok(())\n    }\n}\n\n/// Returns install-time-only option keys for S3 backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\n        \"url\".into(),\n        \"checksum\".into(),\n        \"bin_path\".into(),\n        \"version_list_url\".into(),\n        \"version_regex\".into(),\n        \"version_json_path\".into(),\n        \"version_expr\".into(),\n        \"version_prefix\".into(),\n        \"format\".into(),\n        \"region\".into(),\n        \"endpoint\".into(),\n    ]\n}\n\n/// Create an S3 client with the given configuration\nasync fn create_s3_client(region: Option<&str>, endpoint: Option<&str>) -> Result<S3Client> {\n    let mut config_loader = aws_config::defaults(BehaviorVersion::latest());\n\n    if let Some(region) = region {\n        config_loader = config_loader.region(aws_config::Region::new(region.to_string()));\n    }\n\n    let sdk_config = config_loader.load().await;\n\n    let mut s3_config = aws_sdk_s3::config::Builder::from(&sdk_config);\n\n    if let Some(endpoint) = endpoint {\n        s3_config = s3_config.endpoint_url(endpoint).force_path_style(true);\n    }\n\n    Ok(S3Client::from_conf(s3_config.build()))\n}\n\n/// Convert S3 SDK errors to user-friendly error messages\nfn handle_s3_error<E: std::fmt::Debug>(err: E, bucket: &str, key: &str) -> eyre::Report {\n    let err_str = format!(\"{err:?}\");\n\n    if err_str.contains(\"NoSuchKey\") {\n        eyre!(\"S3 object not found: s3://{bucket}/{key}. Check the URL and version.\")\n    } else if err_str.contains(\"NoSuchBucket\") {\n        eyre!(\"S3 bucket not found: {bucket}. Check the bucket name.\")\n    } else if err_str.contains(\"AccessDenied\") || err_str.contains(\"Forbidden\") {\n        eyre!(\n            \"Access denied to S3 bucket '{bucket}'. Check your AWS credentials and IAM permissions.\\n\\\n             Ensure AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set, or use IAM roles.\"\n        )\n    } else if err_str.contains(\"InvalidAccessKeyId\") {\n        eyre!(\"Invalid AWS access key. Check your AWS_ACCESS_KEY_ID environment variable.\")\n    } else if err_str.contains(\"SignatureDoesNotMatch\") {\n        eyre!(\"AWS signature mismatch. Check your AWS_SECRET_ACCESS_KEY environment variable.\")\n    } else if err_str.contains(\"timeout\") || err_str.contains(\"Timeout\") {\n        eyre!(\"S3 request timed out. Check your network connection and endpoint URL.\")\n    } else {\n        eyre!(\"S3 error: {err:?}\")\n    }\n}\n\n#[async_trait]\nimpl Backend for S3Backend {\n    fn get_type(&self) -> BackendType {\n        BackendType::S3\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn install_operation_count(&self, tv: &ToolVersion, _ctx: &InstallContext) -> usize {\n        let opts = tv.request.options();\n        super::http_install_operation_count(\n            Self::get_opt(&opts, \"checksum\").is_some(),\n            &self.get_platform_key(),\n            tv,\n        )\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = self.fetch_versions(config).await?;\n        Ok(versions\n            .into_iter()\n            .map(|v| VersionInfo {\n                version: v,\n                ..Default::default()\n            })\n            .collect())\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        Settings::get().ensure_experimental(\"s3 backend\")?;\n        let opts = tv.request.options();\n\n        // Resolve URL template\n        let url = self.resolve_url(&tv, &opts)?;\n        let s3_url = S3Url::parse(&url)?;\n\n        // Get S3 client\n        let client = self.get_client(&opts).await?;\n\n        // Prepare download path\n        let filename = get_filename_from_url(&url);\n        let file_path = tv.download_path().join(&filename);\n\n        // Record URL in lock platforms\n        let platform_key = self.get_platform_key();\n        tv.lock_platforms\n            .entry(platform_key.clone())\n            .or_default()\n            .url = Some(url.clone());\n\n        // For lockfile checksum verification\n        let settings = Settings::get();\n        let lockfile_enabled = settings.lockfile_enabled();\n        let has_lockfile_checksum = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|p| p.checksum.as_ref())\n            .is_some();\n\n        // Download from S3\n        ctx.pr.set_message(format!(\"download {filename}\"));\n        file::create_dir_all(tv.download_path())?;\n        self.download_object(client, &s3_url, &file_path, Some(ctx.pr.as_ref()))\n            .await?;\n\n        // Verify artifact (checksum/size from options)\n        if Self::get_opt(&opts, \"checksum\").is_some() {\n            ctx.pr.next_operation();\n        }\n        verify_artifact(&tv, &file_path, &opts, Some(ctx.pr.as_ref()))?;\n\n        // Verify/generate lockfile checksum (before extraction for security)\n        if lockfile_enabled || has_lockfile_checksum {\n            ctx.pr.next_operation();\n        }\n        self.verify_checksum(ctx, &mut tv, &file_path)?;\n\n        // Extract and install\n        ctx.pr.next_operation();\n        ctx.pr.set_message(\"extract\".into());\n        install_artifact(&tv, &file_path, &opts, Some(ctx.pr.as_ref()))?;\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        let opts = tv.request.options();\n\n        // Check for explicit bin_path\n        if let Some(bin_path_template) = lookup_with_fallback(&opts, \"bin_path\") {\n            let bin_path = template_string(&bin_path_template, tv);\n            return Ok(vec![tv.install_path().join(bin_path)]);\n        }\n\n        // Check for bin directory\n        let bin_dir = tv.install_path().join(\"bin\");\n        if bin_dir.exists() {\n            return Ok(vec![bin_dir]);\n        }\n\n        // Search subdirectories for bin directories\n        let mut paths = Vec::new();\n        if let Ok(entries) = std::fs::read_dir(tv.install_path()) {\n            for entry in entries.flatten() {\n                let path = entry.path();\n                if path.is_dir() {\n                    let sub_bin = path.join(\"bin\");\n                    if sub_bin.exists() {\n                        paths.push(sub_bin);\n                    }\n                }\n            }\n        }\n\n        if paths.is_empty() {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(paths)\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_s3_url_parse_basic() {\n        let url = S3Url::parse(\"s3://my-bucket/path/to/file.tar.gz\").unwrap();\n        assert_eq!(url.bucket, \"my-bucket\");\n        assert_eq!(url.key, \"path/to/file.tar.gz\");\n    }\n\n    #[test]\n    fn test_s3_url_parse_with_query_params() {\n        // Query params are parsed but region/endpoint come from tool options\n        let url = S3Url::parse(\"s3://my-bucket/path/to/file.tar.gz?region=us-west-2\").unwrap();\n        assert_eq!(url.bucket, \"my-bucket\");\n        assert_eq!(url.key, \"path/to/file.tar.gz\");\n    }\n\n    #[test]\n    fn test_s3_url_parse_root_key() {\n        let url = S3Url::parse(\"s3://bucket/file.tar.gz\").unwrap();\n        assert_eq!(url.bucket, \"bucket\");\n        assert_eq!(url.key, \"file.tar.gz\");\n    }\n\n    #[test]\n    fn test_s3_url_parse_deep_path() {\n        let url = S3Url::parse(\"s3://bucket/path/to/mytool-1.0.0.tar.gz\").unwrap();\n        assert_eq!(url.bucket, \"bucket\");\n        assert_eq!(url.key, \"path/to/mytool-1.0.0.tar.gz\");\n    }\n\n    #[test]\n    fn test_s3_url_invalid_scheme() {\n        let result = S3Url::parse(\"https://bucket/path\");\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn test_s3_url_missing_bucket() {\n        let result = S3Url::parse(\"s3:///path/to/file\");\n        assert!(result.is_err());\n    }\n}\n"
  },
  {
    "path": "src/backend/spm.rs",
    "content": "use crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::git::{CloneOptions, Git};\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolVersion;\nuse crate::{dirs, file, github, gitlab};\nuse async_trait::async_trait;\nuse eyre::WrapErr;\nuse serde::Deserializer;\nuse serde::de::{MapAccess, Visitor};\nuse serde_derive::Deserialize;\nuse std::path::PathBuf;\nuse std::{\n    fmt::{self, Debug},\n    sync::Arc,\n};\nuse strum::{AsRefStr, EnumString, VariantNames};\nuse url::Url;\nuse xx::regex;\n\n/// SPM backend requires experimental mode to be enabled\npub const EXPERIMENTAL: bool = true;\n\n#[derive(Debug)]\npub struct SPMBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for SPMBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Spm\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"swift\"])\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        let provider = GitProvider::from_ba(&self.ba);\n        let repo = SwiftPackageRepo::new(&self.tool_name(), &provider)?;\n        let versions = match provider.kind {\n            GitProviderKind::GitLab => {\n                gitlab::list_releases_from_url(&provider.api_url, repo.shorthand.as_str())\n                    .await?\n                    .into_iter()\n                    .map(|r| VersionInfo {\n                        version: r.tag_name,\n                        created_at: r.released_at,\n                        ..Default::default()\n                    })\n                    .rev()\n                    .collect()\n            }\n            _ => github::list_releases_from_url(&provider.api_url, repo.shorthand.as_str())\n                .await?\n                .into_iter()\n                .map(|r| VersionInfo {\n                    version: r.tag_name,\n                    created_at: Some(r.created_at),\n                    ..Default::default()\n                })\n                .rev()\n                .collect(),\n        };\n\n        Ok(versions)\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        let settings = Settings::get();\n        settings.ensure_experimental(\"spm backend\")?;\n\n        // Check if swift is available\n        self.warn_if_dependency_missing(\n            &ctx.config,\n            \"swift\",\n            \"To use Swift Package Manager (spm) tools with mise, you need to install Swift first:\\n\\\n              mise use swift@latest\\n\\n\\\n            Or install Swift via https://swift.org/download/\",\n        )\n        .await;\n        let provider = GitProvider::from_ba(&self.ba);\n        let repo = SwiftPackageRepo::new(&self.tool_name(), &provider)?;\n        let revision = if tv.version == \"latest\" {\n            self.latest_stable_version(&ctx.config)\n                .await?\n                .ok_or_else(|| eyre::eyre!(\"No stable versions found\"))?\n        } else {\n            tv.version.clone()\n        };\n        let repo_dir = self.clone_package_repo(ctx, &tv, &repo, &revision)?;\n\n        let executables = self.get_executable_names(ctx, &repo_dir, &tv).await?;\n        if executables.is_empty() {\n            return Err(eyre::eyre!(\"No executables found in the package\"));\n        }\n        let bin_path = tv.install_path().join(\"bin\");\n        file::create_dir_all(&bin_path)?;\n        for executable in executables {\n            let exe_path = self\n                .build_executable(&executable, &repo_dir, ctx, &tv)\n                .await?;\n            file::make_symlink(&exe_path, &bin_path.join(executable))?;\n        }\n\n        // delete (huge) intermediate artifacts\n        file::remove_all(tv.install_path().join(\"repositories\"))?;\n        file::remove_all(tv.cache_path())?;\n\n        Ok(tv)\n    }\n}\n\nimpl SPMBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n\n    fn clone_package_repo(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        package_repo: &SwiftPackageRepo,\n        revision: &str,\n    ) -> Result<PathBuf, eyre::Error> {\n        let repo = Git::new(tv.cache_path().join(\"repo\"));\n        if !repo.exists() {\n            debug!(\n                \"Cloning swift package repo {} to {}\",\n                package_repo.url.as_str(),\n                repo.dir.display(),\n            );\n            repo.clone(\n                package_repo.url.as_str(),\n                CloneOptions::default().pr(ctx.pr.as_ref()),\n            )?;\n        }\n        debug!(\"Checking out revision: {revision}\");\n        repo.update_tag(revision.to_string())?;\n\n        // Updates submodules ensuring they match the checked-out revision\n        repo.update_submodules()?;\n\n        Ok(repo.dir)\n    }\n\n    async fn get_executable_names(\n        &self,\n        ctx: &InstallContext,\n        repo_dir: &PathBuf,\n        tv: &ToolVersion,\n    ) -> Result<Vec<String>, eyre::Error> {\n        let package_json = cmd!(\n            \"swift\",\n            \"package\",\n            \"dump-package\",\n            \"--package-path\",\n            &repo_dir,\n            \"--scratch-path\",\n            tv.install_path(),\n            \"--cache-path\",\n            dirs::CACHE.join(\"spm\"),\n        )\n        .full_env(self.dependency_env(&ctx.config).await?)\n        .read()?;\n        let executables = serde_json::from_str::<PackageDescription>(&package_json)\n            .wrap_err(\"Failed to parse package description\")?\n            .products\n            .iter()\n            .filter(|p| p.r#type.is_executable())\n            .map(|p| p.name.clone())\n            .collect::<Vec<String>>();\n        debug!(\"Found executables: {:?}\", executables);\n        Ok(executables)\n    }\n\n    async fn build_executable(\n        &self,\n        executable: &str,\n        repo_dir: &PathBuf,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n    ) -> Result<PathBuf, eyre::Error> {\n        debug!(\"Building swift package\");\n        CmdLineRunner::new(\"swift\")\n            .arg(\"build\")\n            .arg(\"--configuration\")\n            .arg(\"release\")\n            .arg(\"--product\")\n            .arg(executable)\n            .arg(\"--scratch-path\")\n            .arg(tv.install_path())\n            .arg(\"--package-path\")\n            .arg(repo_dir)\n            .arg(\"--cache-path\")\n            .arg(dirs::CACHE.join(\"spm\"))\n            .with_pr(ctx.pr.as_ref())\n            .prepend_path(\n                self.dependency_toolset(&ctx.config)\n                    .await?\n                    .list_paths(&ctx.config)\n                    .await,\n            )?\n            .execute()?;\n\n        let bin_path = cmd!(\n            \"swift\",\n            \"build\",\n            \"--configuration\",\n            \"release\",\n            \"--product\",\n            &executable,\n            \"--package-path\",\n            &repo_dir,\n            \"--scratch-path\",\n            tv.install_path(),\n            \"--cache-path\",\n            dirs::CACHE.join(\"spm\"),\n            \"--show-bin-path\"\n        )\n        .full_env(self.dependency_env(&ctx.config).await?)\n        .read()?;\n        Ok(PathBuf::from(bin_path.trim().to_string()).join(executable))\n    }\n}\n\n#[derive(Clone, Debug, Eq, PartialEq)]\npub struct GitProvider {\n    pub api_url: String,\n    pub kind: GitProviderKind,\n}\n\nimpl Default for GitProvider {\n    fn default() -> Self {\n        Self {\n            api_url: github::API_URL.to_string(),\n            kind: GitProviderKind::GitHub,\n        }\n    }\n}\n\n#[derive(AsRefStr, Clone, Debug, Eq, PartialEq, EnumString, VariantNames)]\npub enum GitProviderKind {\n    #[strum(serialize = \"github\")]\n    GitHub,\n    #[strum(serialize = \"gitlab\")]\n    GitLab,\n}\n\nimpl GitProvider {\n    fn from_ba(ba: &BackendArg) -> Self {\n        let opts = ba.opts();\n\n        let provider = opts\n            .get(\"provider\")\n            .unwrap_or(GitProviderKind::GitHub.as_ref());\n        let kind = if ba.tool_name.contains(\"gitlab.com\") {\n            GitProviderKind::GitLab\n        } else {\n            match provider.to_lowercase().as_str() {\n                \"gitlab\" => GitProviderKind::GitLab,\n                _ => GitProviderKind::GitHub,\n            }\n        };\n\n        let api_url = match opts.get(\"api_url\") {\n            Some(api_url) => api_url.trim_end_matches('/').to_string(),\n            None => match kind {\n                GitProviderKind::GitHub => github::API_URL.to_string(),\n                GitProviderKind::GitLab => gitlab::API_URL.to_string(),\n            },\n        };\n\n        Self { api_url, kind }\n    }\n}\n\n#[derive(Debug)]\nstruct SwiftPackageRepo {\n    /// https://github.com/owner/repo.git\n    url: Url,\n    /// owner/repo_name\n    shorthand: String,\n}\n\nimpl SwiftPackageRepo {\n    /// Parse the slug or the full URL of a GitHub package repository.\n    fn new(name: &str, provider: &GitProvider) -> Result<Self, eyre::Error> {\n        let name = name.strip_prefix(\"spm:\").unwrap_or(name);\n        let shorthand_regex = regex!(r\"^(?:[a-zA-Z0-9_-]+/)+[a-zA-Z0-9._-]+$\");\n        let shorthand_in_url_regex = regex!(\n            r\"^https://(?P<domain>[^/]+)/(?P<shorthand>(?:[a-zA-Z0-9_-]+/)+[a-zA-Z0-9._-]+)\\.git\"\n        );\n\n        let (shorthand, url) = if let Some(caps) = shorthand_in_url_regex.captures(name) {\n            let shorthand = caps.name(\"shorthand\").unwrap().as_str();\n            let url = Url::parse(name)?;\n            (shorthand, url)\n        } else if shorthand_regex.is_match(name) {\n            let host = match provider.kind {\n                GitProviderKind::GitHub => \"github.com\",\n                GitProviderKind::GitLab => \"gitlab.com\",\n            };\n            let url_str = format!(\"https://{}/{}.git\", host, name);\n            let url = Url::parse(&url_str)?;\n            (name, url)\n        } else {\n            Err(eyre::eyre!(\n                \"Invalid Swift package repository: {}. The repository should either be a repository slug (owner/name), or the complete URL (e.g. https://github.com/owner/name.git).\",\n                name\n            ))?\n        };\n\n        Ok(Self {\n            url,\n            shorthand: shorthand.to_string(),\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::cli::args::BackendResolution;\n    use crate::{config::Config, toolset::ToolVersionOptions};\n\n    use super::*;\n    use indexmap::indexmap;\n    use pretty_assertions::assert_str_eq;\n\n    #[tokio::test]\n    async fn test_git_provider_from_ba() {\n        // Example of defining a capture (closure) in Rust:\n        let get_ba = |tool: String, opts: Option<ToolVersionOptions>| {\n            BackendArg::new_raw(\n                \"spm\".to_string(),\n                Some(tool.clone()),\n                tool,\n                opts,\n                BackendResolution::new(true),\n            )\n        };\n\n        assert_eq!(\n            GitProvider::from_ba(&get_ba(\"tool\".to_string(), None)),\n            GitProvider {\n                api_url: github::API_URL.to_string(),\n                kind: GitProviderKind::GitHub\n            }\n        );\n\n        assert_eq!(\n            GitProvider::from_ba(&get_ba(\n                \"tool\".to_string(),\n                Some(ToolVersionOptions {\n                    opts: indexmap![\n                        \"provider\".to_string() => toml::Value::String(\"gitlab\".to_string())\n                    ],\n                    ..Default::default()\n                })\n            )),\n            GitProvider {\n                api_url: gitlab::API_URL.to_string(),\n                kind: GitProviderKind::GitLab\n            }\n        );\n\n        assert_eq!(\n            GitProvider::from_ba(&get_ba(\n                \"tool\".to_string(),\n                Some(ToolVersionOptions {\n                    opts: indexmap![\n                        \"api_url\".to_string() => toml::Value::String(\"https://gitlab.acme.com/api/v4\".to_string()),\n                        \"provider\".to_string() => toml::Value::String(\"gitlab\".to_string()),\n                    ],\n                    ..Default::default()\n                })\n            )),\n            GitProvider {\n                api_url: \"https://gitlab.acme.com/api/v4\".to_string(),\n                kind: GitProviderKind::GitLab\n            }\n        );\n    }\n\n    #[tokio::test]\n    async fn test_spm_repo_init_by_shorthand() {\n        let _config = Config::get().await.unwrap();\n        let package_repo =\n            SwiftPackageRepo::new(\"nicklockwood/SwiftFormat\", &GitProvider::default()).unwrap();\n        assert_str_eq!(\n            package_repo.url.as_str(),\n            \"https://github.com/nicklockwood/SwiftFormat.git\"\n        );\n        assert_str_eq!(package_repo.shorthand, \"nicklockwood/SwiftFormat\");\n\n        let package_repo = SwiftPackageRepo::new(\n            \"acme/nicklockwood/SwiftFormat\",\n            &GitProvider {\n                api_url: gitlab::API_URL.to_string(),\n                kind: GitProviderKind::GitLab,\n            },\n        )\n        .unwrap();\n        assert_str_eq!(\n            package_repo.url.as_str(),\n            \"https://gitlab.com/acme/nicklockwood/SwiftFormat.git\"\n        );\n        assert_str_eq!(package_repo.shorthand, \"acme/nicklockwood/SwiftFormat\");\n    }\n\n    #[tokio::test]\n    async fn test_spm_repo_init_name() {\n        let _config = Config::get().await.unwrap();\n        assert!(\n            SwiftPackageRepo::new(\"owner/name.swift\", &GitProvider::default()).is_ok(),\n            \"name part can contain .\"\n        );\n        assert!(\n            SwiftPackageRepo::new(\"owner/name_swift\", &GitProvider::default()).is_ok(),\n            \"name part can contain _\"\n        );\n        assert!(\n            SwiftPackageRepo::new(\"owner/name-swift\", &GitProvider::default()).is_ok(),\n            \"name part can contain -\"\n        );\n        assert!(\n            SwiftPackageRepo::new(\"owner/name$swift\", &GitProvider::default()).is_err(),\n            \"name part cannot contain characters other than a-zA-Z0-9._-\"\n        );\n    }\n\n    #[tokio::test]\n    async fn test_spm_repo_init_by_url() {\n        let package_repo = SwiftPackageRepo::new(\n            \"https://github.com/nicklockwood/SwiftFormat.git\",\n            &GitProvider::default(),\n        )\n        .unwrap();\n        assert_str_eq!(\n            package_repo.url.as_str(),\n            \"https://github.com/nicklockwood/SwiftFormat.git\"\n        );\n        assert_str_eq!(package_repo.shorthand, \"nicklockwood/SwiftFormat\");\n\n        let package_repo = SwiftPackageRepo::new(\n            \"https://gitlab.acme.com/acme/someuser/SwiftTool.git\",\n            &GitProvider {\n                api_url: \"https://api.gitlab.acme.com/api/v4\".to_string(),\n                kind: GitProviderKind::GitLab,\n            },\n        )\n        .unwrap();\n        assert_str_eq!(\n            package_repo.url.as_str(),\n            \"https://gitlab.acme.com/acme/someuser/SwiftTool.git\"\n        );\n        assert_str_eq!(package_repo.shorthand, \"acme/someuser/SwiftTool\");\n    }\n}\n\n/// https://developer.apple.com/documentation/packagedescription\n#[derive(Deserialize)]\nstruct PackageDescription {\n    products: Vec<PackageDescriptionProduct>,\n}\n\n#[derive(Deserialize)]\nstruct PackageDescriptionProduct {\n    name: String,\n    #[serde(deserialize_with = \"PackageDescriptionProductType::deserialize_product_type_field\")]\n    r#type: PackageDescriptionProductType,\n}\n\n#[derive(Deserialize)]\nenum PackageDescriptionProductType {\n    Executable,\n    Other,\n}\n\nimpl PackageDescriptionProductType {\n    fn is_executable(&self) -> bool {\n        matches!(self, Self::Executable)\n    }\n\n    /// Swift determines the toolchain to use with a given package using a comment in the Package.swift file at the top.\n    /// For example:\n    ///   // swift-tools-version: 6.0\n    ///\n    /// The version of the toolchain can be older than the Swift version used to build the package. This versioning gives\n    /// Apple the flexibility to introduce and flag breaking changes in the toolchain.\n    ///\n    /// How to determine the product type is something that might change across different versions of Swift.\n    ///\n    /// ## Swift 5.x\n    ///\n    /// Product type is a key in the map with an undocumented value that we are not interested in and can be easily skipped.\n    ///\n    /// Example:\n    /// ```json\n    /// \"type\" : {\n    ///     \"executable\" : null\n    /// }\n    /// ```\n    /// or\n    /// ```json\n    /// \"type\" : {\n    ///     \"library\" : [\n    ///       \"automatic\"\n    ///     ]\n    /// }\n    /// ```\n    ///\n    /// ## Swift 6.x\n    ///\n    /// The product type is directly the value under the key \"type\"\n    ///\n    /// Example:\n    ///\n    /// ```json\n    /// \"type\": \"executable\"\n    /// ```\n    ///\n    fn deserialize_product_type_field<'de, D>(\n        deserializer: D,\n    ) -> Result<PackageDescriptionProductType, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct TypeFieldVisitor;\n\n        impl<'de> Visitor<'de> for TypeFieldVisitor {\n            type Value = PackageDescriptionProductType;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a map with a key 'executable' or other types\")\n            }\n\n            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>\n            where\n                V: MapAccess<'de>,\n            {\n                if let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"type\" => {\n                            let value: String = map.next_value()?;\n                            if value == \"executable\" {\n                                Ok(PackageDescriptionProductType::Executable)\n                            } else {\n                                Ok(PackageDescriptionProductType::Other)\n                            }\n                        }\n                        \"executable\" => {\n                            // Skip the value by reading it into a dummy serde_json::Value\n                            let _value: serde_json::Value = map.next_value()?;\n                            Ok(PackageDescriptionProductType::Executable)\n                        }\n                        _ => {\n                            let _value: serde_json::Value = map.next_value()?;\n                            Ok(PackageDescriptionProductType::Other)\n                        }\n                    }\n                } else {\n                    Err(serde::de::Error::custom(\"missing key\"))\n                }\n            }\n        }\n\n        deserializer.deserialize_map(TypeFieldVisitor)\n    }\n}\n"
  },
  {
    "path": "src/backend/static_helpers.rs",
    "content": "// Shared template logic for backends\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::file;\nuse crate::hash;\nuse crate::http::HTTP;\nuse crate::toolset::ToolVersion;\nuse crate::toolset::ToolVersionOptions;\nuse crate::ui::progress_report::SingleReport;\nuse eyre::{Result, bail};\nuse indexmap::IndexSet;\nuse std::path::Path;\nuse std::path::PathBuf;\nuse std::sync::LazyLock;\n\n/// Regex pattern for matching version suffixes like -v1.2.3, _1.2.3, etc.\nstatic VERSION_PATTERN: LazyLock<regex::Regex> =\n    LazyLock::new(|| regex::Regex::new(r\"[-_]v?\\d+(\\.\\d+)*(-[a-zA-Z0-9]+(\\.\\d+)?)?$\").unwrap());\n\n// ========== Checksum Fetching Helpers ==========\n\n/// Fetches a checksum for a specific file from a SHASUMS256.txt-style file.\n/// Uses cached HTTP requests since the same SHASUMS file is fetched for all platforms.\n///\n/// # Arguments\n/// * `shasums_url` - URL to the SHASUMS256.txt file\n/// * `filename` - The filename to look up in the SHASUMS file\n///\n/// # Returns\n/// * `Some(\"sha256:<hash>\")` if found\n/// * `None` if the SHASUMS file couldn't be fetched or filename not found\npub async fn fetch_checksum_from_shasums(shasums_url: &str, filename: &str) -> Option<String> {\n    match HTTP.get_text_cached(shasums_url).await {\n        Ok(shasums_content) => {\n            let shasums = hash::parse_shasums(&shasums_content);\n            shasums.get(filename).map(|h| format!(\"sha256:{h}\"))\n        }\n        Err(e) => {\n            debug!(\"Failed to fetch SHASUMS from {}: {e}\", shasums_url);\n            None\n        }\n    }\n}\n\n/// Fetches a checksum from an individual checksum file (e.g., file.tar.gz.sha256).\n/// The checksum file should contain just the hash, optionally followed by filename.\n///\n/// # Arguments\n/// * `checksum_url` - URL to the checksum file (e.g., `https://example.com/file.tar.gz.sha256`)\n/// * `algo` - The algorithm name to prefix (e.g., \"sha256\")\n///\n/// # Returns\n/// * `Some(\"<algo>:<hash>\")` if found\n/// * `None` if the checksum file couldn't be fetched\npub async fn fetch_checksum_from_file(checksum_url: &str, algo: &str) -> Option<String> {\n    match HTTP.get_text(checksum_url).await {\n        Ok(content) => {\n            // Format is typically \"<hash>  <filename>\" or just \"<hash>\"\n            content\n                .split_whitespace()\n                .next()\n                .map(|h| format!(\"{algo}:{}\", h.trim()))\n        }\n        Err(e) => {\n            debug!(\"Failed to fetch checksum from {}: {e}\", checksum_url);\n            None\n        }\n    }\n}\n\n// ========== Platform Patterns ==========\n\n// Shared OS/arch patterns used across helpers\nconst OS_PATTERNS: &[&str] = &[\n    \"linux\", \"darwin\", \"macos\", \"windows\", \"win\", \"freebsd\", \"openbsd\", \"netbsd\", \"android\",\n    \"unknown\",\n];\n// Longer arch patterns first to avoid partial matches\nconst ARCH_PATTERNS: &[&str] = &[\n    \"x86_64\", \"aarch64\", \"ppc64le\", \"ppc64\", \"armv7\", \"armv6\", \"arm64\", \"amd64\", \"mipsel\",\n    \"riscv64\", \"s390x\", \"i686\", \"i386\", \"x64\", \"mips\", \"arm\", \"x86\",\n];\n\npub trait VerifiableError: Sized + Send + Sync + 'static {\n    fn is_not_found(&self) -> bool;\n    fn into_eyre(self) -> eyre::Report;\n}\n\nimpl VerifiableError for eyre::Report {\n    fn is_not_found(&self) -> bool {\n        self.chain().any(|cause| {\n            if let Some(err) = cause.downcast_ref::<reqwest::Error>() {\n                err.status() == Some(reqwest::StatusCode::NOT_FOUND)\n            } else {\n                false\n            }\n        })\n    }\n\n    fn into_eyre(self) -> eyre::Report {\n        self\n    }\n}\n\nimpl VerifiableError for anyhow::Error {\n    fn is_not_found(&self) -> bool {\n        if self.to_string().contains(\"404\") {\n            return true;\n        }\n        self.chain().any(|cause| {\n            if let Some(err) = cause.downcast_ref::<reqwest::Error>() {\n                err.status() == Some(reqwest::StatusCode::NOT_FOUND)\n            } else {\n                false\n            }\n        })\n    }\n\n    fn into_eyre(self) -> eyre::Report {\n        eyre::eyre!(self)\n    }\n}\n\n/// Helper to try both prefixed and non-prefixed tags for a resolver function\npub async fn try_with_v_prefix<F, Fut, T, E>(\n    version: &str,\n    version_prefix: Option<&str>,\n    resolver: F,\n) -> Result<T>\nwhere\n    F: Fn(String) -> Fut,\n    Fut: Future<Output = std::result::Result<T, E>>,\n    E: VerifiableError,\n{\n    try_with_v_prefix_and_repo(version, version_prefix, None, resolver).await\n}\n\n/// Helper to try various tag formats for a resolver function\n/// Tries version_prefix (if set), v prefix, and optionally repo@version formats\npub async fn try_with_v_prefix_and_repo<F, Fut, T, E>(\n    version: &str,\n    version_prefix: Option<&str>,\n    repo: Option<&str>,\n    resolver: F,\n) -> Result<T>\nwhere\n    F: Fn(String) -> Fut,\n    Fut: Future<Output = std::result::Result<T, E>>,\n    E: VerifiableError,\n{\n    let mut errors = vec![];\n\n    // Generate candidates based on version prefix configuration\n    let mut candidates = if let Some(prefix) = version_prefix {\n        // If a custom prefix is configured, try both prefixed and non-prefixed versions\n        if version.starts_with(prefix) {\n            vec![\n                version.to_string(),\n                version.trim_start_matches(prefix).to_string(),\n            ]\n        } else {\n            vec![format!(\"{}{}\", prefix, version), version.to_string()]\n        }\n    } else if version == \"latest\" {\n        vec![version.to_string()]\n    } else if version.starts_with('v') {\n        vec![\n            version.to_string(),\n            version.trim_start_matches('v').to_string(),\n        ]\n    } else {\n        vec![format!(\"v{version}\"), version.to_string()]\n    };\n\n    // Also try repo@version formats (e.g., tectonic@0.15.0) when no prefix is configured\n    // Try both the repo short name and full repo name\n    // Skip this for \"latest\" since it's a special keyword, not an actual tag\n    if version_prefix.is_none()\n        && version != \"latest\"\n        && let Some(full_repo) = repo\n    {\n        // Try short name first (more common), e.g., \"tectonic@0.15.0\"\n        if let Some(short_name) = full_repo.split('/').next_back() {\n            candidates.push(format!(\"{}@{}\", short_name, version));\n        }\n        // Also try full repo name, e.g., \"tectonic-typesetting/tectonic@0.15.0\"\n        candidates.push(format!(\"{}@{}\", full_repo, version));\n    }\n\n    for candidate in candidates {\n        match resolver(candidate).await {\n            Ok(res) => return Ok(res),\n            Err(e) => {\n                if e.is_not_found() {\n                    errors.push(e.into_eyre());\n                } else {\n                    return Err(e.into_eyre());\n                }\n            }\n        }\n    }\n    Err(errors\n        .pop()\n        .unwrap_or_else(|| eyre::eyre!(\"No matching release found for {version}\")))\n}\n\n/// Returns all possible aliases for the current platform (os, arch),\n/// with the preferred spelling first (macos/x64, linux/x64, etc).\npub fn platform_aliases() -> Vec<(String, String)> {\n    let os = std::env::consts::OS;\n    let arch = std::env::consts::ARCH;\n    let mut aliases = vec![];\n\n    // OS aliases\n    let os_aliases = match os {\n        \"macos\" | \"darwin\" => vec![\"macos\", \"darwin\"],\n        \"linux\" => vec![\"linux\"],\n        \"windows\" => vec![\"windows\"],\n        _ => vec![os],\n    };\n\n    // Arch aliases\n    let arch_aliases = match arch {\n        \"x86_64\" | \"amd64\" => vec![\"x64\", \"amd64\", \"x86_64\"],\n        \"aarch64\" | \"arm64\" => vec![\"arm64\", \"aarch64\"],\n        _ => vec![arch],\n    };\n\n    for os in &os_aliases {\n        for arch in &arch_aliases {\n            aliases.push((os.to_string(), arch.to_string()));\n        }\n    }\n    aliases\n}\n\n/// Looks up a value in ToolVersionOptions using nested platform key format.\n/// Supports nested format (platforms.macos-x64.url) with os-arch dash notation.\n/// Also supports both \"platforms\" and \"platform\" prefixes.\npub fn lookup_platform_key(opts: &ToolVersionOptions, key_type: &str) -> Option<String> {\n    // Try nested platform structure with os-arch format\n    for (os, arch) in platform_aliases() {\n        for prefix in [\"platforms\", \"platform\"] {\n            // Try nested format: platforms.macos-x64.url\n            let nested_key = format!(\"{prefix}.{os}-{arch}.{key_type}\");\n            if let Some(val) = opts.get_nested_string(&nested_key) {\n                return Some(val);\n            }\n            // Try flat format: platforms_macos_arm64_url\n            let flat_key = format!(\"{prefix}_{os}_{arch}_{key_type}\");\n            if let Some(val) = opts.get(&flat_key) {\n                return Some(val.to_string());\n            }\n        }\n    }\n    None\n}\n\n/// Looks up an option value with platform-specific fallback.\n/// First tries platform-specific lookup, then falls back to the base key.\n///\n/// # Arguments\n/// * `opts` - The tool version options to search\n/// * `key` - The option key to look up (e.g., \"bin_path\", \"checksum\")\n///\n/// # Returns\n/// * `Some(value)` if found in platform-specific or base options\n/// * `None` if not found\npub fn lookup_with_fallback(opts: &ToolVersionOptions, key: &str) -> Option<String> {\n    lookup_platform_key(opts, key).or_else(|| opts.get(key).map(|s| s.to_string()))\n}\n\n/// Returns all possible aliases for a given platform target (os, arch).\nfn target_platform_aliases(target: &PlatformTarget) -> Vec<(String, String)> {\n    let os = target.os_name();\n    let arch = target.arch_name();\n    let mut aliases = vec![];\n\n    // OS aliases\n    let os_aliases = match os {\n        \"macos\" | \"darwin\" => vec![\"macos\", \"darwin\"],\n        \"linux\" => vec![\"linux\"],\n        \"windows\" => vec![\"windows\"],\n        _ => vec![os],\n    };\n\n    // Arch aliases\n    let arch_aliases = match arch {\n        \"x64\" | \"amd64\" | \"x86_64\" => vec![\"x64\", \"amd64\", \"x86_64\"],\n        \"arm64\" | \"aarch64\" => vec![\"arm64\", \"aarch64\"],\n        _ => vec![arch],\n    };\n\n    for os in &os_aliases {\n        for arch in &arch_aliases {\n            aliases.push((os.to_string(), arch.to_string()));\n        }\n    }\n    aliases\n}\n\n/// Looks up a value in ToolVersionOptions for a specific target platform.\n/// Used for cross-platform lockfile generation.\npub fn lookup_platform_key_for_target(\n    opts: &ToolVersionOptions,\n    key_type: &str,\n    target: &PlatformTarget,\n) -> Option<String> {\n    // Try nested platform structure with os-arch format\n    for (os, arch) in target_platform_aliases(target) {\n        for prefix in [\"platforms\", \"platform\"] {\n            // Try nested format: platforms.macos-x64.url\n            let nested_key = format!(\"{prefix}.{os}-{arch}.{key_type}\");\n            if let Some(val) = opts.get_nested_string(&nested_key) {\n                return Some(val);\n            }\n            // Try flat format: platforms_macos_arm64_url\n            let flat_key = format!(\"{prefix}_{os}_{arch}_{key_type}\");\n            if let Some(val) = opts.get(&flat_key) {\n                return Some(val.to_string());\n            }\n        }\n    }\n    None\n}\n\n/// Lists platform keys (e.g. \"macos-x64\") for which a given key_type exists (e.g. \"url\").\npub fn list_available_platforms_with_key(opts: &ToolVersionOptions, key_type: &str) -> Vec<String> {\n    let mut set = IndexSet::new();\n\n    // Gather from flat keys\n    for (k, _) in opts.iter() {\n        if let Some(rest) = k\n            .strip_prefix(\"platforms_\")\n            .or_else(|| k.strip_prefix(\"platform_\"))\n            && let Some(platform_part) = rest.strip_suffix(&format!(\"_{}\", key_type))\n        {\n            // Only convert the OS/arch separator underscore to a dash, preserving\n            // underscores inside architecture names like x86_64\n            let platform_key = if let Some((os_part, rest)) = platform_part.split_once('_') {\n                format!(\"{os_part}-{rest}\")\n            } else {\n                platform_part.to_string()\n            };\n            set.insert(platform_key);\n        }\n    }\n\n    // Probe nested keys using shared patterns\n    for os in OS_PATTERNS {\n        for arch in ARCH_PATTERNS {\n            for prefix in [\"platforms\", \"platform\"] {\n                let nested_key = format!(\"{prefix}.{os}-{arch}.{key_type}\");\n                if opts.contains_key(&nested_key) {\n                    set.insert(format!(\"{os}-{arch}\"));\n                }\n            }\n        }\n    }\n\n    set.into_iter().collect()\n}\n\npub fn template_string(template: &str, tv: &ToolVersion) -> String {\n    // Check for legacy {version} syntax and emit deprecation warning\n    if template.contains(\"{version}\") && !template.contains(\"{{version}}\") {\n        deprecated_at!(\n            \"2026.3.0\",\n            \"2027.3.0\",\n            \"legacy-version-template\",\n            \"Use {{{{ version }}}} instead of {{version}} in URL templates\"\n        );\n        // Legacy support: replace {version} placeholder\n        return template.replace(\"{version}\", &tv.version);\n    }\n\n    // Use Tera rendering for templates\n    // Supports {{ version }}, {{ os() }}, {{ arch() }}, etc.\n    let mut ctx = crate::tera::BASE_CONTEXT.clone();\n    ctx.insert(\"version\", &tv.version);\n\n    match crate::tera::get_tera(None).render_str(template, &ctx) {\n        Ok(rendered) => rendered,\n        Err(e) => {\n            warn!(\"Failed to render template '{}': {}\", template, e);\n            template.to_string()\n        }\n    }\n}\n\npub fn get_filename_from_url(url_str: &str) -> String {\n    let filename = if let Ok(url) = url::Url::parse(url_str) {\n        // Use proper URL parsing to get the path and extract filename\n        url.path_segments()\n            .and_then(|mut segments| segments.next_back())\n            .map(|s| s.to_string())\n            .unwrap_or_else(|| url_str.to_string())\n    } else {\n        // Fallback to simple parsing for non-URL strings or malformed URLs\n        url_str\n            .split('/')\n            .next_back()\n            .unwrap_or(url_str)\n            .to_string()\n    };\n    urlencoding::decode(&filename)\n        .map(|s| s.to_string())\n        .unwrap_or(filename)\n}\n\npub fn install_artifact(\n    tv: &crate::toolset::ToolVersion,\n    file_path: &Path,\n    opts: &ToolVersionOptions,\n    pr: Option<&dyn SingleReport>,\n) -> eyre::Result<()> {\n    let install_path = tv.install_path();\n    let mut strip_components = lookup_platform_key(opts, \"strip_components\")\n        .or_else(|| opts.get(\"strip_components\").map(|s| s.to_string()))\n        .and_then(|s| s.parse().ok());\n\n    file::remove_all(&install_path)?;\n    file::create_dir_all(&install_path)?;\n\n    // Use TarFormat for format detection\n    // Check for explicit format option first, then fall back to file extension\n    let format = if let Some(format_opt) = lookup_with_fallback(opts, \"format\") {\n        file::TarFormat::from_ext(&format_opt)\n    } else {\n        file::TarFormat::from_file_name(\n            &file_path.file_name().unwrap_or_default().to_string_lossy(),\n        )\n    };\n\n    // Get file extension and detect format\n    let file_name = file_path.file_name().unwrap().to_string_lossy();\n\n    if !format.is_archive() && format != file::TarFormat::Raw {\n        // Handle compressed single binary\n        let ext = Path::new(&*file_name)\n            .extension()\n            .and_then(|s| s.to_str())\n            .unwrap_or(\"\")\n            .to_string();\n        let decompressed_name = file_name.trim_end_matches(&format!(\".{}\", ext));\n\n        // Determine the destination path with support for bin_path\n        let dest = if let Some(bin_path_template) = lookup_with_fallback(opts, \"bin_path\") {\n            let bin_path = template_string(&bin_path_template, tv);\n            let bin_dir = install_path.join(&bin_path);\n            file::create_dir_all(&bin_dir)?;\n            bin_dir.join(decompressed_name)\n        } else if let Some(bin_name) = lookup_with_fallback(opts, \"bin\") {\n            install_path.join(&bin_name)\n        } else {\n            // Auto-clean binary names by removing OS/arch suffixes\n            let cleaned_name = clean_binary_name(decompressed_name, Some(&tv.ba().tool_name));\n            install_path.join(cleaned_name)\n        };\n\n        file::untar(\n            file_path,\n            &dest,\n            &file::TarOptions {\n                pr,\n                ..file::TarOptions::new(format)\n            },\n        )?;\n\n        file::make_executable(&dest)?;\n    } else if format == file::TarFormat::Raw {\n        // Copy the file directly to the bin_path directory or install_path\n        if let Some(bin_path_template) = lookup_with_fallback(opts, \"bin_path\") {\n            let bin_path = template_string(&bin_path_template, tv);\n            let bin_dir = install_path.join(&bin_path);\n            file::create_dir_all(&bin_dir)?;\n            let dest = bin_dir.join(file_path.file_name().unwrap());\n            file::copy(file_path, &dest)?;\n            file::make_executable(&dest)?;\n        } else if let Some(bin_name) = lookup_with_fallback(opts, \"bin\") {\n            // If bin is specified, rename the file to this name\n            let dest = install_path.join(&bin_name);\n            file::copy(file_path, &dest)?;\n            file::make_executable(&dest)?;\n        } else {\n            // Always auto-clean binary names by removing OS/arch suffixes\n            let original_name = file_path.file_name().unwrap().to_string_lossy();\n            let cleaned_name = clean_binary_name(&original_name, Some(&tv.ba().tool_name));\n            let dest = install_path.join(cleaned_name);\n            file::copy(file_path, &dest)?;\n            file::make_executable(&dest)?;\n        }\n    } else {\n        // Handle archive formats\n        // Auto-detect if we need strip_components=1 before extracting\n        // Only do this if strip_components was not explicitly set by the user AND bin_path is not configured\n        if strip_components.is_none()\n            && lookup_platform_key(opts, \"bin_path\")\n                .or_else(|| opts.get(\"bin_path\").map(|s| s.to_string()))\n                .is_none()\n            && let Ok(should_strip) = file::should_strip_components(file_path, format)\n            && should_strip\n        {\n            debug!(\"Auto-detected single directory archive, extracting with strip_components=1\");\n            strip_components = Some(1);\n        }\n        let tar_opts = file::TarOptions {\n            strip_components: strip_components.unwrap_or(0),\n            pr,\n            ..file::TarOptions::new(format)\n        };\n\n        // Extract with determined strip_components\n        file::untar(file_path, &install_path, &tar_opts)?;\n\n        // Extract just the repo name from tool_name (e.g., \"opsgenie/opsgenie-lamp\" -> \"opsgenie-lamp\")\n        // This is needed for matching binary names in ZIP archives where exec bits are lost\n        let full_tool_name = tv.ba().tool_name.as_str();\n        let tool_name = full_tool_name.rsplit('/').next().unwrap_or(full_tool_name);\n\n        // Determine search directory based on bin_path option\n        let explicit_bin_path = lookup_with_fallback(opts, \"bin_path\")\n            .map(|t| install_path.join(template_string(&t, tv)));\n\n        // Handle bin= option for archives (renames executable to specified name)\n        // bin= values are relative to install_path, so always use install_path or explicit bin_path\n        if let Some(bin_name) = lookup_with_fallback(opts, \"bin\") {\n            let search_dir = explicit_bin_path.as_deref().unwrap_or(&install_path);\n            rename_executable_in_dir(search_dir, &bin_name, Some(tool_name))?;\n        }\n\n        // Handle rename_exe option for archives\n        // When bin_path is not explicitly set, auto-detect bin/ subdirectory to match\n        // the same logic used by discover_bin_paths() for PATH construction\n        if let Some(rename_to) = lookup_with_fallback(opts, \"rename_exe\") {\n            let search_dir = if let Some(ref dir) = explicit_bin_path {\n                dir.clone()\n            } else {\n                let bin_dir = install_path.join(\"bin\");\n                if bin_dir.is_dir() {\n                    bin_dir\n                } else {\n                    install_path.clone()\n                }\n            };\n            rename_executable_in_dir(&search_dir, &rename_to, Some(tool_name))?;\n        }\n    }\n    Ok(())\n}\n\npub fn verify_artifact(\n    _tv: &crate::toolset::ToolVersion,\n    file_path: &Path,\n    opts: &crate::toolset::ToolVersionOptions,\n    pr: Option<&dyn SingleReport>,\n) -> Result<()> {\n    // Check platform-specific checksum first, then fall back to generic\n    let checksum = lookup_with_fallback(opts, \"checksum\");\n\n    if let Some(checksum) = checksum {\n        verify_checksum_str(file_path, &checksum, pr)?;\n    }\n\n    // Check platform-specific size first, then fall back to generic\n    let size_str = lookup_with_fallback(opts, \"size\");\n\n    if let Some(size_str) = size_str {\n        let expected_size: u64 = size_str.parse()?;\n        let actual_size = file_path.metadata()?.len();\n        if actual_size != expected_size {\n            bail!(\n                \"Size mismatch: expected {}, got {}\",\n                expected_size,\n                actual_size\n            );\n        }\n    }\n\n    Ok(())\n}\n\npub fn verify_checksum_str(\n    file_path: &Path,\n    checksum: &str,\n    pr: Option<&dyn SingleReport>,\n) -> Result<()> {\n    if let Some((algo, hash_str)) = checksum.split_once(':') {\n        hash::ensure_checksum(file_path, hash_str, pr, algo)?;\n    } else {\n        bail!(\"Invalid checksum format: {}\", checksum);\n    }\n    Ok(())\n}\n\n/// File extensions that indicate non-binary files.\nconst SKIP_EXTENSIONS: &[&str] = &[\".txt\", \".md\", \".json\", \".yml\", \".yaml\"];\n\n/// File names (case-insensitive) that should be skipped when looking for executables.\nconst SKIP_FILE_NAMES: &[&str] = &[\"LICENSE\", \"README\"];\n\n/// Checks if a file should be skipped when searching for executables.\n///\n/// # Arguments\n/// * `file_name` - The file name to check\n/// * `strict` - If true, also checks against SKIP_FILE_NAMES and README.* patterns\n///\n/// # Returns\n/// * `true` if the file should be skipped (not a binary)\n/// * `false` if the file might be a binary\nfn should_skip_file(file_name: &str, strict: bool) -> bool {\n    // Skip hidden files\n    if file_name.starts_with('.') {\n        return true;\n    }\n\n    // Skip known non-binary extensions\n    if SKIP_EXTENSIONS.iter().any(|ext| file_name.ends_with(ext)) {\n        return true;\n    }\n\n    // In strict mode, also skip LICENSE/README files\n    if strict {\n        let upper = file_name.to_uppercase();\n        if SKIP_FILE_NAMES.iter().any(|name| upper == *name) || upper.starts_with(\"README.\") {\n            return true;\n        }\n    }\n\n    false\n}\n\n/// Renames the first executable file found in a directory to a new name.\n/// Used by the `rename_exe` and `bin` options to rename binaries after archive extraction.\n///\n/// # Parameters\n/// - `dir`: The directory to search for executables\n/// - `new_name`: The new name for the executable\n/// - `tool_name`: Optional hint for finding non-executable files by name matching.\n///   When provided, if no executable is found, will search for files matching the tool name\n///   and make them executable before renaming.\npub fn rename_executable_in_dir(\n    dir: &Path,\n    new_name: &str,\n    tool_name: Option<&str>,\n) -> eyre::Result<()> {\n    let target_path = dir.join(new_name);\n\n    // Check if target already exists before iterating\n    // (read_dir order is non-deterministic, so we must check first)\n    if target_path.is_file() && file::is_executable(&target_path) {\n        return Ok(());\n    }\n\n    // Check for stripped macOS .app bundle (Contents/MacOS at root level)\n    // This happens when auto-strip removes the .app wrapper directory\n    let contents_macos = dir.join(\"Contents\").join(\"MacOS\");\n    if contents_macos.is_dir() {\n        // Rename within Contents/MacOS instead of moving to root\n        let target_in_macos = contents_macos.join(new_name);\n        if rename_executable_in_app_bundle(&contents_macos, &target_in_macos, tool_name)? {\n            return Ok(());\n        }\n    }\n\n    // Check for macOS .app bundles and look inside Contents/MacOS/\n    for entry in file::ls(dir)? {\n        if entry.is_dir() {\n            let dir_name = entry.file_name().unwrap().to_string_lossy();\n            if dir_name.ends_with(\".app\") {\n                let macos_dir = entry.join(\"Contents\").join(\"MacOS\");\n                if macos_dir.is_dir() {\n                    // Try to rename executable inside the .app bundle\n                    if rename_executable_in_app_bundle(&macos_dir, &target_path, tool_name)? {\n                        return Ok(());\n                    }\n                }\n            }\n        }\n    }\n\n    // First pass: Find executables in the directory (non-recursive for top level)\n    for path in file::ls(dir)? {\n        if path.is_file() && file::is_executable(&path) {\n            let file_name = path.file_name().unwrap().to_string_lossy();\n            if should_skip_file(&file_name, false) {\n                continue;\n            }\n            let target_path_with_extension =\n                keep_required_extensions(dir, &file_name, new_name, target_path);\n\n            file::rename(&path, &target_path_with_extension)?;\n            debug!(\n                \"Renamed {} to {}\",\n                path.display(),\n                target_path_with_extension.display()\n            );\n            return Ok(());\n        }\n    }\n\n    // Second pass: Find non-executable files by name matching (for ZIP archives without exec bit)\n    if let Some(tool_name) = tool_name {\n        for path in file::ls(dir)? {\n            if path.is_file() {\n                let file_name = path.file_name().unwrap().to_string_lossy();\n                if should_skip_file(&file_name, true) {\n                    continue;\n                }\n\n                // Check if filename matches tool name pattern or the target name\n                if file_name.contains(tool_name) || *file_name == *new_name {\n                    let target_path_with_extension =\n                        keep_required_extensions(dir, &file_name, new_name, target_path);\n\n                    file::make_executable(&path)?;\n                    file::rename(&path, &target_path_with_extension)?;\n                    debug!(\n                        \"Found and renamed {} to {} (added exec permissions)\",\n                        path.display(),\n                        target_path_with_extension.display()\n                    );\n                    return Ok(());\n                }\n            }\n        }\n    }\n\n    Ok(())\n}\n\n/// Helper function to rename executable inside a macOS .app bundle\nfn rename_executable_in_app_bundle(\n    macos_dir: &Path,\n    target_path: &Path,\n    tool_name: Option<&str>,\n) -> eyre::Result<bool> {\n    // Find the first executable in the Contents/MacOS directory\n    for path in file::ls(macos_dir)? {\n        if path.is_file() && file::is_executable(&path) {\n            let file_name = path.file_name().unwrap().to_string_lossy();\n            if should_skip_file(&file_name, false) {\n                continue;\n            }\n            file::rename(&path, target_path)?;\n            debug!(\n                \"Renamed .app bundle executable {} to {}\",\n                path.display(),\n                target_path.display()\n            );\n            return Ok(true);\n        }\n    }\n\n    // If no executable found, try matching by tool name\n    if let Some(tool_name) = tool_name {\n        for path in file::ls(macos_dir)? {\n            if path.is_file() {\n                let file_name = path.file_name().unwrap().to_string_lossy();\n                if should_skip_file(&file_name, true) {\n                    continue;\n                }\n                if file_name.to_lowercase().contains(&tool_name.to_lowercase()) {\n                    file::make_executable(&path)?;\n                    file::rename(&path, target_path)?;\n                    debug!(\n                        \"Found and renamed .app bundle file {} to {} (added exec permissions)\",\n                        path.display(),\n                        target_path.display()\n                    );\n                    return Ok(true);\n                }\n            }\n        }\n    }\n\n    Ok(false)\n}\n\nfn keep_required_extensions(\n    dir: &Path,\n    file_name: &str,\n    new_name: &str,\n    target_path: PathBuf,\n) -> PathBuf {\n    if cfg!(windows) {\n        return keep_extensions(\n            dir,\n            file_name,\n            new_name,\n            target_path,\n            &[\".exe\", \".cmd\", \".bat\"],\n        );\n    }\n    target_path\n}\n\nfn keep_extensions(\n    dir: &Path,\n    file_name: &str,\n    new_name: &str,\n    target_path: PathBuf,\n    exts: &[&str],\n) -> PathBuf {\n    for ext in exts {\n        if file_name.to_lowercase().ends_with(ext) && !new_name.to_lowercase().ends_with(ext) {\n            return dir.join(format!(\"{}{}\", new_name, ext));\n        }\n    }\n    target_path\n}\n\n/// Cleans a binary name by removing OS/arch suffixes and version numbers.\n/// This is useful when downloading single binaries that have platform-specific names.\n/// Executable extensions (.exe, .bat, .sh, etc.) are preserved.\n///\n/// # Parameters\n/// - `name`: The binary name to clean\n/// - `tool_name`: Optional hint for the expected tool name. When provided:\n///   - Version removal is more aggressive, only keeping the result if it matches the tool name\n///   - Helps ensure the cleaned name matches the expected tool\n///     – When `None`, version removal is more conservative to avoid over-cleaning\n///\n/// # Examples\n/// - \"docker-compose-linux-x86_64\" -> \"docker-compose\"\n/// - \"tool-darwin-arm64.exe\" -> \"tool.exe\" (preserves extension)\n/// - \"mytool-v1.2.3-windows-amd64\" -> \"mytool\"\n/// - \"app-2.0.0-linux-x64\" -> \"app\" (with tool_name=\"app\")\n/// - \"script-darwin-arm64.sh\" -> \"script.sh\" (preserves .sh extension)\npub fn clean_binary_name(name: &str, tool_name: Option<&str>) -> String {\n    // Extract extension if present (to preserve it)\n    let (name_without_ext, extension) = if let Some(pos) = name.rfind('.') {\n        let potential_ext = &name[pos + 1..];\n        // Common executable extensions to preserve\n        let executable_extensions = [\n            \"exe\", \"bat\", \"cmd\", \"sh\", \"ps1\", \"app\", \"AppImage\", \"run\", \"bin\",\n        ];\n        if executable_extensions.contains(&potential_ext) {\n            (&name[..pos], Some(&name[pos..]))\n        } else {\n            // Not an executable extension, treat it as part of the name\n            (name, None)\n        }\n    } else {\n        (name, None)\n    };\n\n    // Helper to add extension back to a cleaned name\n    let with_ext = |s: String| -> String {\n        match extension {\n            Some(ext) => format!(\"{}{}\", s, ext),\n            None => s,\n        }\n    };\n\n    // Try to find and remove platform suffixes\n    let mut cleaned = name_without_ext.to_string();\n\n    // First try combined OS-arch patterns\n    for os in OS_PATTERNS {\n        for arch in ARCH_PATTERNS {\n            // Try different separator combinations\n            let patterns = [\n                format!(\"-{os}-{arch}\"),\n                format!(\"-{os}_{arch}\"),\n                format!(\"_{os}-{arch}\"),\n                format!(\"_{os}_{arch}\"),\n                format!(\"-{arch}-{os}\"), // Sometimes arch comes before OS\n                format!(\"_{arch}_{os}\"),\n            ];\n\n            for pattern in &patterns {\n                if let Some(pos) = cleaned.rfind(pattern) {\n                    cleaned = cleaned[..pos].to_string();\n                    // Continue processing to also remove version numbers\n                    let result = clean_version_suffix(&cleaned, tool_name);\n                    return with_ext(result);\n                }\n            }\n        }\n    }\n\n    // Try just OS suffix (sometimes arch is omitted)\n    for os in OS_PATTERNS {\n        let patterns = [format!(\"-{os}\"), format!(\"_{os}\")];\n        for pattern in &patterns {\n            if let Some(pos) = cleaned.rfind(pattern.as_str()) {\n                // Only remove if it's at the end or followed by more platform info\n                let after = &cleaned[pos + pattern.len()..];\n                if after.is_empty() || after.starts_with('-') || after.starts_with('_') {\n                    // Check if what comes before looks like a valid name\n                    let before = &cleaned[..pos];\n                    if !before.is_empty() {\n                        cleaned = before.to_string();\n                        let result = clean_version_suffix(&cleaned, tool_name);\n                        // Add the extension back if we had one\n                        return with_ext(result);\n                    }\n                }\n            }\n        }\n    }\n\n    // Try just arch suffix (sometimes OS is omitted)\n    for arch in ARCH_PATTERNS {\n        let patterns = [format!(\"-{arch}\"), format!(\"_{arch}\")];\n        for pattern in &patterns {\n            if let Some(pos) = cleaned.rfind(pattern.as_str()) {\n                // Only remove if it's at the end or followed by more platform info\n                let after = &cleaned[pos + pattern.len()..];\n                if after.is_empty() || after.starts_with('-') || after.starts_with('_') {\n                    // Check if what comes before looks like a valid name\n                    let before = &cleaned[..pos];\n                    if !before.is_empty() {\n                        cleaned = before.to_string();\n                        let result = clean_version_suffix(&cleaned, tool_name);\n                        // Add the extension back if we had one\n                        return with_ext(result);\n                    }\n                }\n            }\n        }\n    }\n\n    // Try to remove version suffixes as a final step\n    let cleaned = clean_version_suffix(&cleaned, tool_name);\n\n    // Add the extension back if we had one\n    with_ext(cleaned)\n}\n\n/// Remove version suffixes from binary names.\n///\n/// When `tool_name` is provided, aggressively removes version patterns but only\n/// if the result matches or relates to the tool name. This prevents accidentally\n/// removing too much from the name.\n///\n/// When `tool_name` is None, only removes clear version patterns at the end\n/// while ensuring we don't leave an empty or invalid result.\nfn clean_version_suffix(name: &str, tool_name: Option<&str>) -> String {\n    // Common version patterns to remove\n    if let Some(tool) = tool_name {\n        // If we have a tool name, only remove version if what remains matches the tool\n        if let Some(m) = VERSION_PATTERN.find(name) {\n            let without_version = &name[..m.start()];\n            if without_version == tool\n                || tool.contains(without_version)\n                || without_version.contains(tool)\n            {\n                return without_version.to_string();\n            }\n        }\n    } else {\n        // No tool name hint, be more conservative\n        // Only remove if it looks like a clear version pattern at the end\n        if let Some(m) = VERSION_PATTERN.find(name) {\n            let without_version = &name[..m.start()];\n            // Make sure we're not left with nothing or just a dash/underscore\n            if !without_version.is_empty()\n                && !without_version.ends_with('-')\n                && !without_version.ends_with('_')\n            {\n                return without_version.to_string();\n            }\n        }\n    }\n\n    name.to_string()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::toolset::ToolVersionOptions;\n    use indexmap::IndexMap;\n\n    #[test]\n    fn test_clean_binary_name() {\n        // Test basic OS/arch removal\n        assert_eq!(\n            clean_binary_name(\"docker-compose-linux-x86_64\", None),\n            \"docker-compose\"\n        );\n        assert_eq!(\n            clean_binary_name(\"docker-compose-linux-x86_64.exe\", None),\n            \"docker-compose.exe\"\n        );\n        assert_eq!(clean_binary_name(\"tool-darwin-arm64\", None), \"tool\");\n        assert_eq!(\n            clean_binary_name(\"mytool-v1.2.3-windows-amd64\", None),\n            \"mytool\"\n        );\n\n        // Test different separators\n        assert_eq!(clean_binary_name(\"app_linux_amd64\", None), \"app\");\n        assert_eq!(clean_binary_name(\"app-linux_x64\", None), \"app\");\n        assert_eq!(clean_binary_name(\"app_darwin-arm64\", None), \"app\");\n\n        // Test arch before OS\n        assert_eq!(clean_binary_name(\"tool-x86_64-linux\", None), \"tool\");\n        assert_eq!(clean_binary_name(\"tool_amd64_windows\", None), \"tool\");\n\n        // Test with tool name hint\n        assert_eq!(\n            clean_binary_name(\"docker-compose-linux-x86_64\", Some(\"docker-compose\")),\n            \"docker-compose\"\n        );\n        assert_eq!(\n            clean_binary_name(\"compose-linux-x86_64\", Some(\"compose\")),\n            \"compose\"\n        );\n\n        // Test single OS or arch suffix\n        assert_eq!(clean_binary_name(\"binary-linux\", None), \"binary\");\n        assert_eq!(clean_binary_name(\"binary-x86_64\", None), \"binary\");\n        assert_eq!(clean_binary_name(\"binary_arm64\", None), \"binary\");\n\n        // Test version removal\n        assert_eq!(clean_binary_name(\"tool-v1.2.3\", None), \"tool\");\n        assert_eq!(clean_binary_name(\"app-2.0.0\", None), \"app\");\n        assert_eq!(clean_binary_name(\"binary_v3.2.1\", None), \"binary\");\n        assert_eq!(clean_binary_name(\"tool-1.0.0-alpha\", None), \"tool\");\n        assert_eq!(clean_binary_name(\"app-v2.0.0-rc1\", None), \"app\");\n\n        // Test version removal with tool name hint\n        assert_eq!(\n            clean_binary_name(\"docker-compose-v2.29.1\", Some(\"docker-compose\")),\n            \"docker-compose\"\n        );\n        assert_eq!(\n            clean_binary_name(\"compose-2.29.1\", Some(\"compose\")),\n            \"compose\"\n        );\n\n        // Test no cleaning needed\n        assert_eq!(clean_binary_name(\"simple-tool\", None), \"simple-tool\");\n\n        // Test that executable extensions are preserved\n        assert_eq!(clean_binary_name(\"app-linux-x64.exe\", None), \"app.exe\");\n        assert_eq!(\n            clean_binary_name(\"tool-v1.2.3-windows.bat\", None),\n            \"tool.bat\"\n        );\n        assert_eq!(\n            clean_binary_name(\"script-darwin-arm64.sh\", None),\n            \"script.sh\"\n        );\n        assert_eq!(\n            clean_binary_name(\"app-linux.AppImage\", None),\n            \"app.AppImage\"\n        );\n\n        // Test edge cases\n        assert_eq!(clean_binary_name(\"linux\", None), \"linux\"); // Just OS name\n        assert_eq!(clean_binary_name(\"\", None), \"\");\n    }\n\n    #[test]\n    fn test_keep_extensions() {\n        let dir = Path::new(\"/tmp\");\n        let initial_target = dir.join(\"new_tool\");\n\n        // Does not append extension not in the list\n        assert_eq!(\n            keep_extensions(\n                dir,\n                \"mytool.sh\",\n                \"new_tool\",\n                initial_target.clone(),\n                &[\".exe\"]\n            ),\n            initial_target\n        );\n\n        // Appends if in the list\n        assert_eq!(\n            keep_extensions(\n                dir,\n                \"mytool.sh\",\n                \"new_tool\",\n                initial_target.clone(),\n                &[\".sh\"]\n            ),\n            dir.join(\"new_tool.sh\")\n        );\n\n        // Case insensitivity handled\n        assert_eq!(\n            keep_extensions(\n                dir,\n                \"mytool.SH\",\n                \"new_tool\",\n                initial_target.clone(),\n                &[\".sh\"]\n            ),\n            dir.join(\"new_tool.sh\")\n        );\n\n        // New name already has extension - avoids double extension\n        assert_eq!(\n            keep_extensions(\n                dir,\n                \"mytool.exe\",\n                \"new_tool.exe\",\n                dir.join(\"new_tool.exe\"),\n                &[\".exe\"]\n            ),\n            dir.join(\"new_tool.exe\")\n        );\n    }\n\n    #[test]\n    fn test_keep_required_extensions() {\n        let dir = Path::new(\"/tmp\");\n        let initial_target = dir.join(\"new_tool\");\n\n        if cfg!(windows) {\n            // Keeps Windows executable extensions\n            assert_eq!(\n                keep_required_extensions(dir, \"mytool.exe\", \"new_tool\", initial_target.clone()),\n                dir.join(\"new_tool.exe\")\n            );\n            assert_eq!(\n                keep_required_extensions(dir, \"mytool.cmd\", \"new_tool\", initial_target.clone()),\n                dir.join(\"new_tool.cmd\")\n            );\n            assert_eq!(\n                keep_required_extensions(dir, \"MYTOOL.BAT\", \"new_tool\", initial_target.clone()),\n                dir.join(\"new_tool.bat\")\n            );\n        } else {\n            // Does not append on non-windows\n            assert_eq!(\n                keep_required_extensions(dir, \"mytool.exe\", \"new_tool\", initial_target.clone()),\n                initial_target\n            );\n        }\n    }\n\n    #[test]\n    fn test_list_available_platforms_with_key_flat_preserves_arch_underscore() {\n        let mut opts = IndexMap::new();\n        // Flat keys with os_arch_keytype naming\n        opts.insert(\n            \"platforms_macos_x86_64_url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x86_64.tar.gz\".to_string()),\n        );\n        opts.insert(\n            \"platforms_linux_x64_url\".to_string(),\n            toml::Value::String(\"https://example.com/linux-x64.tar.gz\".to_string()),\n        );\n        // Different prefix variant also supported\n        opts.insert(\n            \"platform_windows_arm64_url\".to_string(),\n            toml::Value::String(\"https://example.com/windows-arm64.zip\".to_string()),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        let platforms = list_available_platforms_with_key(&tool_opts, \"url\");\n\n        // Should convert only the OS/arch separator underscore to dash\n        assert!(platforms.contains(&\"macos-x86_64\".to_string()));\n        assert!(!platforms.contains(&\"macos-x86-64\".to_string()));\n\n        assert!(platforms.contains(&\"linux-x64\".to_string()));\n        assert!(platforms.contains(&\"windows-arm64\".to_string()));\n    }\n\n    #[test]\n    fn test_verify_artifact_platform_specific() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"platforms\".to_string(),\n            toml::Value::String(\n                r#\"\n[macos-x64]\nchecksum = \"blake3:abc123\"\nsize = \"1024\"\n\n[macos-arm64]\nchecksum = \"blake3:jkl012\"\nsize = \"4096\"\n\n[linux-x64]\nchecksum = \"blake3:def456\"\nsize = \"2048\"\n\n[linux-arm64]\nchecksum = \"blake3:mno345\"\nsize = \"5120\"\n\n[windows-x64]\nchecksum = \"blake3:ghi789\"\nsize = \"3072\"\n\n[windows-arm64]\nchecksum = \"blake3:mno345\"\nsize = \"5120\"\n\"#\n                .to_string(),\n            ),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that platform-specific checksum and size are found\n        // This test verifies that lookup_platform_key is being used correctly\n        // The actual verification would require a real file, but we can test the lookup logic\n        let checksum = lookup_platform_key(&tool_opts, \"checksum\");\n        let size = lookup_platform_key(&tool_opts, \"size\");\n\n        // Skip the test if the current platform isn't supported in the test data\n        if checksum.is_none() || size.is_none() {\n            eprintln!(\n                \"Skipping test_verify_artifact_platform_specific: current platform not supported in test data\"\n            );\n            return;\n        }\n\n        // The exact values depend on the current platform, but we should get some value\n        // If we're not on a supported platform, the test should still pass\n        // since the function should handle missing platform-specific values gracefully\n        assert!(checksum.is_some());\n        assert!(size.is_some());\n    }\n\n    #[test]\n    fn test_verify_artifact_fallback_to_generic() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"checksum\".to_string(),\n            toml::Value::String(\"blake3:generic123\".to_string()),\n        );\n        opts.insert(\"size\".to_string(), toml::Value::String(\"512\".to_string()));\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that generic fallback works when no platform-specific values exist\n        let checksum = lookup_platform_key(&tool_opts, \"checksum\")\n            .or_else(|| tool_opts.get(\"checksum\").map(|s| s.to_string()));\n        let size = lookup_with_fallback(&tool_opts, \"size\");\n\n        assert_eq!(checksum, Some(\"blake3:generic123\".to_string()));\n        assert_eq!(size, Some(\"512\".to_string()));\n    }\n\n    #[test]\n    fn test_lookup_platform_key_bin_path() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"platform\".to_string(),\n            toml::Value::String(\n                r#\"\n[macos-arm64]\nbin_path = \"CMake.app/Contents/bin\"\n\n[linux-x64]\nbin_path = \"bin\"\n\n[windows-x64]\nbin_path = \".\"\n\"#\n                .to_string(),\n            ),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that platform-specific bin_path is found\n        let bin_path = lookup_platform_key(&tool_opts, \"bin_path\");\n\n        // The exact value depends on the current platform\n        if let Some(bp) = bin_path {\n            // Should be one of the platform-specific values\n            assert!(\n                bp == \"CMake.app/Contents/bin\" || bp == \"bin\" || bp == \".\",\n                \"Expected platform-specific bin_path, got: {}\",\n                bp\n            );\n        }\n    }\n\n    #[test]\n    fn test_lookup_platform_key_bin() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"platforms\".to_string(),\n            toml::Value::String(\n                r#\"\n[macos-arm64]\nbin = \"xmake\"\n\n[linux-x64]\nbin = \"xmake\"\n\n[windows-x64]\nbin = \"xmake.exe\"\n\"#\n                .to_string(),\n            ),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that platform-specific bin is found\n        let bin = lookup_platform_key(&tool_opts, \"bin\");\n\n        // The exact value depends on the current platform\n        if let Some(b) = bin {\n            // Should be one of the platform-specific values\n            assert!(\n                b == \"xmake\" || b == \"xmake.exe\",\n                \"Expected platform-specific bin, got: {}\",\n                b\n            );\n        }\n    }\n\n    #[test]\n    fn test_lookup_platform_key_bin_with_fallback() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"bin\".to_string(),\n            toml::Value::String(\"generic-tool\".to_string()),\n        );\n        opts.insert(\n            \"platforms\".to_string(),\n            toml::Value::String(\n                r#\"\n[windows-x64]\nbin = \"tool.exe\"\n\"#\n                .to_string(),\n            ),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that platform-specific bin takes precedence, or falls back to generic\n        let bin = lookup_with_fallback(&tool_opts, \"bin\");\n\n        assert!(bin.is_some());\n        let bin_value = bin.unwrap();\n        // On Windows x64, should get \"tool.exe\", otherwise \"generic-tool\"\n        assert!(\n            bin_value == \"tool.exe\" || bin_value == \"generic-tool\",\n            \"Expected platform-specific or generic bin, got: {}\",\n            bin_value\n        );\n    }\n\n    #[test]\n    fn test_lookup_platform_key_inline_format() {\n        let mut opts = IndexMap::new();\n        opts.insert(\n            \"platforms_windows_x64_bin\".to_string(),\n            toml::Value::String(\"xmake.exe\".to_string()),\n        );\n        opts.insert(\n            \"platforms_linux_x64_bin\".to_string(),\n            toml::Value::String(\"xmake\".to_string()),\n        );\n        opts.insert(\n            \"platforms_macos_arm64_bin\".to_string(),\n            toml::Value::String(\"xmake\".to_string()),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        // Test that flat platform format works\n        let bin = lookup_platform_key(&tool_opts, \"bin\");\n\n        if let Some(b) = bin {\n            assert!(\n                b == \"xmake\" || b == \"xmake.exe\",\n                \"Expected platform-specific bin from flat format, got: {}\",\n                b\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/backend/ubi.rs",
    "content": "use crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::{lookup_platform_key, try_with_v_prefix};\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\nuse crate::env::{\n    GITHUB_TOKEN, GITLAB_TOKEN, MISE_GITHUB_ENTERPRISE_TOKEN, MISE_GITLAB_ENTERPRISE_TOKEN,\n};\nuse crate::install_context::InstallContext;\nuse crate::plugins::VERSION_REGEX;\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse crate::{backend::Backend, toolset::ToolVersionOptions};\nuse crate::{file, github, gitlab, hash};\nuse async_trait::async_trait;\nuse eyre::bail;\nuse regex::Regex;\nuse std::collections::BTreeMap;\nuse std::path::Path;\nuse std::str::FromStr;\nuse std::sync::Arc;\nuse std::sync::OnceLock;\nuse std::{fmt::Debug, sync::LazyLock};\nuse ubi::{ForgeType, UbiBuilder};\nuse xx::regex;\n\n#[derive(Debug)]\npub struct UbiBackend {\n    ba: Arc<BackendArg>,\n}\n\n#[async_trait]\nimpl Backend for UbiBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Ubi\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        if name_is_url(&self.tool_name()) {\n            Ok(vec![VersionInfo {\n                version: \"latest\".to_string(),\n                ..Default::default()\n            }])\n        } else {\n            let opts = self.ba.opts();\n            let forge = match opts.get(\"provider\") {\n                Some(forge) => ForgeType::from_str(forge)?,\n                None => ForgeType::default(),\n            };\n            let api_url = match opts.get(\"api_url\") {\n                Some(api_url) => api_url.strip_suffix(\"/\").unwrap_or(api_url),\n                None => match forge {\n                    ForgeType::GitHub => github::API_URL,\n                    ForgeType::GitLab => gitlab::API_URL,\n                    _ => bail!(\"Unsupported forge type {:?}\", forge),\n                },\n            };\n\n            let tag_regex_cell = OnceLock::new();\n\n            // Build release URL base based on forge type and api_url\n            let release_url_base = match forge {\n                ForgeType::GitHub => {\n                    if api_url == github::API_URL {\n                        format!(\"https://github.com/{}\", self.tool_name())\n                    } else {\n                        // Enterprise GitHub - derive web URL from API URL\n                        let web_url = api_url.replace(\"/api/v3\", \"\").replace(\"api.\", \"\");\n                        format!(\"{}/{}\", web_url, self.tool_name())\n                    }\n                }\n                ForgeType::GitLab => {\n                    if api_url == gitlab::API_URL {\n                        format!(\"https://gitlab.com/{}\", self.tool_name())\n                    } else {\n                        // Enterprise GitLab - derive web URL from API URL\n                        let web_url = api_url.replace(\"/api/v4\", \"\");\n                        format!(\"{}/{}\", web_url, self.tool_name())\n                    }\n                }\n                _ => bail!(\"Unsupported forge type {:?}\", forge),\n            };\n\n            // Helper to check if tag matches tag_regex (if provided)\n            let matches_tag_regex = |tag: &str| -> bool {\n                if let Some(re_str) = opts.get(\"tag_regex\") {\n                    let re = tag_regex_cell.get_or_init(|| Regex::new(re_str).unwrap());\n                    re.is_match(tag)\n                } else {\n                    true\n                }\n            };\n\n            // Helper to strip 'v' prefix from version\n            let strip_v_prefix = |tag: &str| -> String {\n                if regex!(r\"^v[0-9]\").is_match(tag) {\n                    tag[1..].to_string()\n                } else {\n                    tag.to_string()\n                }\n            };\n\n            let mut version_infos: Vec<VersionInfo> = match forge {\n                ForgeType::GitHub => {\n                    let releases =\n                        github::list_releases_from_url(api_url, &self.tool_name()).await?;\n                    if releases.is_empty() {\n                        // Fall back to tags (no created_at available)\n                        github::list_tags_from_url(api_url, &self.tool_name())\n                            .await?\n                            .into_iter()\n                            .filter(|tag| matches_tag_regex(tag))\n                            .map(|tag| {\n                                let release_url =\n                                    format!(\"{}/releases/tag/{}\", release_url_base, tag);\n                                VersionInfo {\n                                    version: strip_v_prefix(&tag),\n                                    release_url: Some(release_url),\n                                    ..Default::default()\n                                }\n                            })\n                            .collect()\n                    } else {\n                        releases\n                            .into_iter()\n                            .filter(|r| matches_tag_regex(&r.tag_name))\n                            .map(|r| {\n                                let release_url =\n                                    format!(\"{}/releases/tag/{}\", release_url_base, r.tag_name);\n                                VersionInfo {\n                                    version: strip_v_prefix(&r.tag_name),\n                                    created_at: Some(r.created_at),\n                                    release_url: Some(release_url),\n                                    ..Default::default()\n                                }\n                            })\n                            .collect()\n                    }\n                }\n                ForgeType::GitLab => {\n                    let releases =\n                        gitlab::list_releases_from_url(api_url, &self.tool_name()).await?;\n                    if releases.is_empty() {\n                        // Fall back to tags (no created_at available)\n                        gitlab::list_tags_from_url(api_url, &self.tool_name())\n                            .await?\n                            .into_iter()\n                            .filter(|tag| matches_tag_regex(tag))\n                            .map(|tag| {\n                                // Use /-/tags/ for tag-only URLs (no release exists)\n                                let release_url = format!(\"{}/-/tags/{}\", release_url_base, tag);\n                                VersionInfo {\n                                    version: strip_v_prefix(&tag),\n                                    release_url: Some(release_url),\n                                    ..Default::default()\n                                }\n                            })\n                            .collect()\n                    } else {\n                        releases\n                            .into_iter()\n                            .filter(|r| matches_tag_regex(&r.tag_name))\n                            .map(|r| {\n                                let release_url =\n                                    format!(\"{}/-/releases/{}\", release_url_base, r.tag_name);\n                                VersionInfo {\n                                    version: strip_v_prefix(&r.tag_name),\n                                    created_at: r.released_at,\n                                    release_url: Some(release_url),\n                                    ..Default::default()\n                                }\n                            })\n                            .collect()\n                    }\n                }\n                _ => bail!(\"Unsupported forge type {:?}\", forge),\n            };\n\n            // Sort: versions starting with digits first, then reverse\n            version_infos.sort_by_cached_key(|vi| !regex!(r\"^[0-9]\").is_match(&vi.version));\n            version_infos.reverse();\n\n            Ok(version_infos)\n        }\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        deprecated!(\n            \"ubi\",\n            \"The ubi backend is deprecated. Use the github backend instead (e.g., github:owner/repo)\"\n        );\n        // Check if lockfile has URL for this platform\n        let platform_key = self.get_platform_key();\n        let lockfile_url = tv\n            .lock_platforms\n            .get(&platform_key)\n            .and_then(|p| p.url.clone());\n\n        let v = tv.version.to_string();\n        let opts = tv.request.options();\n        let bin_path = lookup_platform_key(&opts, \"bin_path\")\n            .or_else(|| opts.get(\"bin_path\").map(|s| s.to_string()))\n            .unwrap_or_else(|| \"bin\".to_string());\n        let extract_all = opts.get(\"extract_all\").is_some_and(|v| v == \"true\");\n        let bin_dir = tv.install_path();\n\n        // Use lockfile URL if available, otherwise fall back to standard resolution\n        if let Some(url) = &lockfile_url {\n            install(url, &v, &bin_dir, extract_all, &opts)\n                .await\n                .map_err(|e| eyre::eyre!(e))?;\n        } else if name_is_url(&self.tool_name()) {\n            install(&self.tool_name(), &v, &bin_dir, extract_all, &opts)\n                .await\n                .map_err(|e| eyre::eyre!(e))?;\n        } else {\n            try_with_v_prefix(&v, None, |candidate| {\n                let opts = opts.clone();\n                let bin_dir = bin_dir.clone();\n                async move {\n                    install(\n                        &self.tool_name(),\n                        &candidate,\n                        &bin_dir,\n                        extract_all,\n                        &opts,\n                    )\n                    .await\n                }\n            })\n            .await?;\n        }\n\n        let mut possible_exes = vec![\n            tv.request\n                .options()\n                .get(\"exe\")\n                .map(|s| s.to_string())\n                .unwrap_or(tv.ba().short.to_string()),\n        ];\n        if cfg!(windows) {\n            possible_exes.push(format!(\"{}.exe\", possible_exes[0]));\n        }\n        let full_binary_path = if let Some(bin_file) = possible_exes\n            .into_iter()\n            .map(|e| bin_dir.join(e))\n            .find(|f| f.exists())\n        {\n            bin_file\n        } else {\n            let mut bin_dir = bin_dir.to_path_buf();\n            if extract_all && bin_dir.join(&bin_path).exists() {\n                bin_dir = bin_dir.join(&bin_path);\n            }\n            file::ls(&bin_dir)?\n                .into_iter()\n                .find(|f| {\n                    !f.file_name()\n                        .is_some_and(|f| f.to_string_lossy().starts_with(\".\"))\n                })\n                .unwrap()\n        };\n        self.verify_checksum(ctx, &mut tv, &full_binary_path)?;\n\n        Ok(tv)\n    }\n\n    fn fuzzy_match_filter(&self, versions: Vec<String>, query: &str) -> Vec<String> {\n        let escaped_query = regex::escape(query);\n        let query = if query == \"latest\" {\n            \"\\\\D*[0-9].*\"\n        } else {\n            &escaped_query\n        };\n        let query_regex = Regex::new(&format!(\"^{query}([-.].+)?$\")).unwrap();\n\n        versions\n            .into_iter()\n            .filter(|v| {\n                if query == v {\n                    return true;\n                }\n                if VERSION_REGEX.is_match(v) {\n                    return false;\n                }\n                query_regex.is_match(v)\n            })\n            .collect()\n    }\n\n    fn verify_checksum(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        file: &Path,\n    ) -> eyre::Result<()> {\n        // For ubi backend, generate a more specific platform key that includes tool-specific options\n        let mut platform_key = self.get_platform_key();\n        let filename = file.file_name().unwrap().to_string_lossy().to_string();\n\n        if let Some(exe) = tv.request.options().get(\"exe\") {\n            platform_key = format!(\"{platform_key}-{exe}\");\n        }\n        if let Some(matching) = tv.request.options().get(\"matching\") {\n            platform_key = format!(\"{platform_key}-{matching}\");\n        }\n        // Include filename to distinguish different downloads for the same platform\n        platform_key = format!(\"{platform_key}-{filename}\");\n\n        // Get or create platform info for this platform key\n        let platform_info = tv.lock_platforms.entry(platform_key.clone()).or_default();\n\n        if let Some(checksum) = &platform_info.checksum {\n            ctx.pr\n                .set_message(format!(\"checksum verify {platform_key}\"));\n            if let Some((algo, check)) = checksum.split_once(':') {\n                hash::ensure_checksum(file, check, Some(ctx.pr.as_ref()), algo)?;\n            } else {\n                bail!(\"Invalid checksum: {platform_key}\");\n            }\n        } else if Settings::get().lockfile_enabled() {\n            ctx.pr\n                .set_message(format!(\"checksum generate {platform_key}\"));\n            let hash = hash::file_hash_blake3(file, Some(ctx.pr.as_ref()))?;\n            platform_info.checksum = Some(format!(\"blake3:{hash}\"));\n        }\n        Ok(())\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Vec<std::path::PathBuf>> {\n        let opts = tv.request.options();\n        if let Some(bin_path) = lookup_platform_key(&opts, \"bin_path\")\n            .or_else(|| opts.get(\"bin_path\").map(|s| s.to_string()))\n        {\n            // bin_path should always point to a directory containing binaries\n            Ok(vec![tv.install_path().join(&bin_path)])\n        } else if opts.get(\"extract_all\").is_some_and(|v| v == \"true\") {\n            Ok(vec![tv.install_path()])\n        } else {\n            let bin_path = tv.install_path().join(\"bin\");\n            if bin_path.exists() {\n                Ok(vec![bin_path])\n            } else {\n                Ok(vec![tv.install_path()])\n            }\n        }\n    }\n\n    /// UBI is deprecated in favor of the github backend and doesn't resolve download URLs\n    /// at lock time. Return false so --locked mode doesn't error for ubi tools.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        request: &ToolRequest,\n        _target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let opts = request.options();\n        let mut result = BTreeMap::new();\n\n        // These options affect which artifact is downloaded\n        for key in [\"exe\", \"matching\", \"matching_regex\", \"provider\"] {\n            if let Some(value) = opts.get(key) {\n                result.insert(key.to_string(), value.to_string());\n            }\n        }\n\n        result\n    }\n}\n\n/// Returns install-time-only option keys for UBI backend.\npub fn install_time_option_keys() -> Vec<String> {\n    vec![\n        \"exe\".into(),\n        \"matching\".into(),\n        \"matching_regex\".into(),\n        \"provider\".into(),\n    ]\n}\n\nimpl UbiBackend {\n    pub fn from_arg(ba: BackendArg) -> Self {\n        Self { ba: Arc::new(ba) }\n    }\n}\n\nfn name_is_url(n: &str) -> bool {\n    n.starts_with(\"http\")\n}\n\nfn set_token<'a>(mut builder: UbiBuilder<'a>, forge: &ForgeType) -> UbiBuilder<'a> {\n    match forge {\n        ForgeType::GitHub => {\n            if let Some(token) = &*GITHUB_TOKEN {\n                builder = builder.token(token)\n            }\n            builder\n        }\n        ForgeType::GitLab => {\n            if let Some(token) = &*GITLAB_TOKEN {\n                builder = builder.token(token)\n            }\n            builder\n        }\n        _ => builder,\n    }\n}\n\nfn set_enterprise_token<'a>(mut builder: UbiBuilder<'a>, forge: &ForgeType) -> UbiBuilder<'a> {\n    match forge {\n        ForgeType::GitHub => {\n            if let Some(token) = &*MISE_GITHUB_ENTERPRISE_TOKEN {\n                builder = builder.token(token);\n            }\n            builder\n        }\n        ForgeType::GitLab => {\n            if let Some(token) = &*MISE_GITLAB_ENTERPRISE_TOKEN {\n                builder = builder.token(token);\n            }\n            builder\n        }\n        _ => builder,\n    }\n}\n\nasync fn install(\n    name: &str,\n    v: &str,\n    bin_dir: &Path,\n    extract_all: bool,\n    opts: &ToolVersionOptions,\n) -> anyhow::Result<()> {\n    let mut builder = UbiBuilder::new().install_dir(bin_dir);\n\n    if name_is_url(name) {\n        builder = builder.url(name);\n    } else {\n        builder = builder.project(name);\n        builder = builder.tag(v);\n    }\n\n    if extract_all {\n        builder = builder.extract_all();\n    } else {\n        if let Some(exe) = opts.get(\"exe\") {\n            builder = builder.exe(exe);\n        }\n        if let Some(rename_exe) = opts.get(\"rename_exe\") {\n            builder = builder.rename_exe_to(rename_exe)\n        }\n    }\n    if let Some(matching) = opts.get(\"matching\") {\n        builder = builder.matching(matching);\n    }\n    if let Some(matching_regex) = opts.get(\"matching_regex\") {\n        builder = builder.matching_regex(matching_regex);\n    }\n\n    let forge = match opts.get(\"provider\") {\n        Some(forge) => ForgeType::from_str(forge)?,\n        None => ForgeType::default(),\n    };\n    builder = builder.forge(forge.clone());\n    builder = set_token(builder, &forge);\n\n    if let Some(api_url) = opts.get(\"api_url\")\n        && !api_url.contains(\"github.com\")\n        && !api_url.contains(\"gitlab.com\")\n    {\n        builder = builder.api_base_url(api_url.strip_suffix(\"/\").unwrap_or(api_url));\n        builder = set_enterprise_token(builder, &forge);\n    }\n\n    let mut ubi = builder.build()?;\n\n    // TODO: hacky but does not compile without it\n    tokio::task::block_in_place(|| {\n        static RT: LazyLock<tokio::runtime::Runtime> = LazyLock::new(|| {\n            tokio::runtime::Builder::new_multi_thread()\n                .enable_all()\n                .build()\n                .unwrap()\n        });\n        RT.block_on(async { ubi.install_binary().await })\n    })\n}\n"
  },
  {
    "path": "src/backend/version_list.rs",
    "content": "/// Version list parsing utilities for fetching remote versions from URLs.\n///\n/// Supports multiple formats:\n/// - Single version (plain text)\n/// - Line-separated versions\n/// - JSON arrays of strings\n/// - JSON arrays of objects with version fields\n/// - JSON objects with nested version arrays\n///\n/// Options:\n/// - `version_list_url`: URL to fetch version list from\n/// - `version_regex`: Regex pattern to extract versions (first capturing group or full match)\n/// - `version_json_path`: JQ-like path to extract versions from JSON (e.g., `.[].version`)\n/// - `version_expr`: Expression using expr-lang syntax to extract versions\nuse crate::backend::jq;\nuse expr::{Context, Environment, Value};\nuse eyre::Result;\nuse regex::Regex;\nuse std::collections::HashSet;\n\n/// Fetch and parse versions from a version list URL\npub async fn fetch_versions(\n    version_list_url: &str,\n    version_regex: Option<&str>,\n    version_json_path: Option<&str>,\n    version_expr: Option<&str>,\n) -> Result<Vec<String>> {\n    use crate::http::HTTP;\n\n    // Fetch the content\n    let response = HTTP.get_text(version_list_url).await?;\n    let content = response.trim();\n\n    // Parse versions based on format\n    parse_version_list(content, version_regex, version_json_path, version_expr)\n}\n\n/// Parse version list from content using optional regex pattern, JSON path, or expr\npub fn parse_version_list(\n    content: &str,\n    version_regex: Option<&str>,\n    version_json_path: Option<&str>,\n    version_expr: Option<&str>,\n) -> Result<Vec<String>> {\n    let mut versions = Vec::new();\n    let trimmed = content.trim();\n\n    // If an expr is provided, use it to evaluate and extract versions\n    // Fail hard if the expression is invalid - don't silently fall through\n    if let Some(expr_str) = version_expr {\n        versions = eval_version_expr(expr_str, trimmed)?;\n    }\n    // If a JSON path is provided (like \".[].version\" or \".versions\"), try to use it\n    // but fall back to text parsing if JSON parsing fails\n    else if let Some(json_path) = version_json_path {\n        if let Ok(json) = serde_json::from_str::<serde_json::Value>(trimmed)\n            && let Ok(extracted) = jq::extract(&json, json_path)\n        {\n            versions = extracted;\n        }\n        // If JSON parsing failed or path extraction failed, fall through to text parsing below\n    }\n    // If a regex is provided, use it to extract versions\n    else if let Some(pattern) = version_regex {\n        let re = Regex::new(pattern)?;\n        for cap in re.captures_iter(content) {\n            // Use the first capturing group if present, otherwise the whole match\n            let version = cap\n                .get(1)\n                .or_else(|| cap.get(0))\n                .map(|m| m.as_str().to_string());\n            if let Some(v) = version {\n                let v = v.trim();\n                if !v.is_empty() {\n                    versions.push(v.to_string());\n                }\n            }\n        }\n    } else {\n        // Try to detect the format automatically\n\n        // Check if it looks like JSON array or object\n        if trimmed.starts_with('[') || trimmed.starts_with('{') {\n            // Try to parse as JSON\n            if let Ok(json) = serde_json::from_str::<serde_json::Value>(trimmed) {\n                versions = jq::extract_auto(&json);\n            }\n        }\n    }\n\n    // If no versions extracted yet, treat as line-separated or single version\n    // This provides fallback for all cases including failed JSON parsing\n    if versions.is_empty() {\n        for line in trimmed.lines() {\n            let line = line.trim();\n            // Skip empty lines and comments\n            if !line.is_empty() && !line.starts_with('#') {\n                // Strip common version prefixes\n                let version = line.trim_start_matches('v');\n                versions.push(version.to_string());\n            }\n        }\n    }\n\n    // Remove duplicates while preserving order\n    let mut seen = HashSet::new();\n    versions.retain(|v| seen.insert(v.clone()));\n\n    // DO NOT sort versions here - the backend/upstream determines version order.\n    // Sorting is handled elsewhere (e.g., versions host, resolve logic).\n\n    Ok(versions)\n}\n\n/// Evaluate a version expression using expr-lang\nfn eval_version_expr(expr_str: &str, body: &str) -> Result<Vec<String>> {\n    use versions::Versioning;\n\n    let mut ctx = Context::default();\n    ctx.insert(\"body\".to_string(), Value::String(body.to_string()));\n\n    // expr-lang 1.0+ has built-in fromJSON, keys, values, len, toJSON functions\n    let mut env = Environment::new();\n\n    // Add sortVersions function for semver-aware sorting\n    env.add_function(\"sortVersions\", |c| {\n        if c.args.len() != 1 {\n            return Err(\"sortVersions() takes exactly one argument\"\n                .to_string()\n                .into());\n        }\n        let Value::Array(arr) = &c.args[0] else {\n            return Err(\"sortVersions() takes an array as the first argument\"\n                .to_string()\n                .into());\n        };\n        let mut versions: Vec<_> = arr\n            .iter()\n            .filter_map(|v| v.as_string().map(|s| s.to_string()))\n            .collect();\n        versions.sort_by_cached_key(|v| Versioning::new(v));\n        Ok(Value::Array(\n            versions.into_iter().map(Value::String).collect(),\n        ))\n    });\n\n    let result = env.eval(expr_str, &ctx)?;\n    value_to_strings(result)\n}\n\n/// Convert expr Value to a list of strings\nfn value_to_strings(value: Value) -> Result<Vec<String>> {\n    match value {\n        Value::Array(arr) => {\n            let mut result = Vec::new();\n            for v in arr {\n                if let Some(s) = value_as_string(&v)\n                    && !s.is_empty()\n                {\n                    result.push(s);\n                }\n            }\n            Ok(result)\n        }\n        _ => {\n            if let Some(s) = value_as_string(&value)\n                && !s.is_empty()\n            {\n                return Ok(vec![s]);\n            }\n            Ok(vec![])\n        }\n    }\n}\n\nfn value_as_string(value: &Value) -> Option<String> {\n    match value {\n        Value::String(s) => Some(s.clone()),\n        Value::Number(n) => Some(n.to_string()),\n        _ => None,\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_single_version() {\n        let content = \"2.0.53\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"2.0.53\"]);\n    }\n\n    #[test]\n    fn test_parse_single_version_with_v_prefix() {\n        let content = \"v2.0.53\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"2.0.53\"]);\n    }\n\n    #[test]\n    fn test_parse_line_separated_versions() {\n        let content = \"1.0.0\\n1.1.0\\n2.0.0\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"1.1.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_line_separated_with_comments() {\n        let content = \"# Latest versions\\n1.0.0\\n# Stable\\n2.0.0\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_array_of_strings() {\n        let content = r#\"[\"1.0.0\", \"1.1.0\", \"2.0.0\"]\"#;\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"1.1.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_array_with_v_prefix() {\n        let content = r#\"[\"v1.0.0\", \"v1.1.0\", \"v2.0.0\"]\"#;\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"1.1.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_array_of_objects_with_version() {\n        let content = r#\"[{\"version\": \"1.0.0\"}, {\"version\": \"2.0.0\"}]\"#;\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_array_of_objects_with_tag_name() {\n        let content = r#\"[{\"tag_name\": \"v1.0.0\"}, {\"tag_name\": \"v2.0.0\"}]\"#;\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_object_with_versions_array() {\n        let content = r#\"{\"versions\": [\"1.0.0\", \"2.0.0\"]}\"#;\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_with_regex() {\n        let content = \"version 1.0.0\\nversion 2.0.0\\nother stuff\";\n        let versions =\n            parse_version_list(content, Some(r\"version (\\d+\\.\\d+\\.\\d+)\"), None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_with_json_path_array_field() {\n        let content = r#\"{\"data\": {\"versions\": [\"1.0.0\", \"2.0.0\"]}}\"#;\n        let versions = parse_version_list(content, None, Some(\".data.versions[]\"), None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_with_json_path_object_array() {\n        let content = r#\"[{\"version\": \"1.0.0\"}, {\"version\": \"2.0.0\"}]\"#;\n        let versions = parse_version_list(content, None, Some(\".[].version\"), None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_with_json_path_nested() {\n        let content =\n            r#\"{\"releases\": [{\"info\": {\"version\": \"1.0.0\"}}, {\"info\": {\"version\": \"2.0.0\"}}]}\"#;\n        let versions =\n            parse_version_list(content, None, Some(\".releases[].info.version\"), None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_removes_duplicates() {\n        let content = \"1.0.0\\n1.0.0\\n2.0.0\\n2.0.0\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_empty_content() {\n        let content = \"\";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert!(versions.is_empty());\n    }\n\n    #[test]\n    fn test_parse_whitespace_only() {\n        let content = \"   \\n\\n   \";\n        let versions = parse_version_list(content, None, None, None).unwrap();\n        assert!(versions.is_empty());\n    }\n\n    #[test]\n    fn test_parse_json_path_with_invalid_json_falls_back_to_text() {\n        // When version_json_path is provided but content is not valid JSON,\n        // it should gracefully fall back to text parsing\n        let content = \"1.0.0\\n2.0.0\";\n        let versions = parse_version_list(content, None, Some(\".[].version\"), None).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_json_path_with_wrong_path_falls_back_to_text() {\n        // When version_json_path doesn't match the JSON structure,\n        // it should fall back to text parsing\n        let content = r#\"{\"other\": \"data\"}\"#;\n        let versions = parse_version_list(content, None, Some(\".[].version\"), None).unwrap();\n        // Falls back to treating JSON as a single line of text\n        assert_eq!(versions, vec![r#\"{\"other\": \"data\"}\"#]);\n    }\n\n    #[test]\n    fn test_parse_flutter_json_with_filter() {\n        // Test Flutter-style JSON with channel filter\n        let content = r#\"{\n            \"releases\": [\n                {\"version\": \"3.38.7\", \"channel\": \"stable\"},\n                {\"version\": \"3.41.0-0.0.pre\", \"channel\": \"beta\"},\n                {\"version\": \"3.38.6\", \"channel\": \"stable\"}\n            ]\n        }\"#;\n        let versions = parse_version_list(\n            content,\n            None,\n            Some(\".releases[?channel=stable].version\"),\n            None,\n        )\n        .unwrap();\n        assert_eq!(versions, vec![\"3.38.7\", \"3.38.6\"]);\n    }\n\n    #[test]\n    fn test_parse_with_version_expr_split() {\n        // Test version_expr with split function\n        let content = \"1.0.0\\n2.0.0\\n3.0.0\";\n        let versions =\n            parse_version_list(content, None, None, Some(r#\"split(body, \"\\n\")\"#)).unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"2.0.0\", \"3.0.0\"]);\n    }\n\n    #[test]\n    fn test_parse_flutter_with_version_expr() {\n        let content = r#\"{\n            \"releases\": [\n                {\"version\": \"3.38.7\", \"channel\": \"stable\"},\n                {\"version\": \"3.41.0-0.0.pre\", \"channel\": \"beta\"},\n                {\"version\": \"3.38.6\", \"channel\": \"stable\"},\n                {\"version\": \"1.0.0\", \"channel\": \"stable\"}\n            ]\n        }\"#;\n        let versions = parse_version_list(\n            content,\n            None,\n            None,\n            Some(r#\"fromJSON(body).releases | filter({ #.channel == \"stable\" }) | map({ #.version }) | sortVersions()\"#),\n        )\n        .unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"3.38.6\", \"3.38.7\"]);\n    }\n\n    #[test]\n    fn test_parse_with_version_expr_json_keys() {\n        // Test version_expr with fromJSON and keys for hashicorp-style JSON\n        let content = r#\"{\"name\":\"sentinel\",\"versions\":{\"0.1.0\":{},\"0.2.0\":{},\"1.0.0\":{}}}\"#;\n        let versions = parse_version_list(\n            content,\n            None,\n            None,\n            Some(r#\"keys(fromJSON(body).versions)\"#),\n        )\n        .unwrap();\n        // Keys may not be in order, so just check we got all versions\n        assert_eq!(versions.len(), 3);\n        assert!(versions.contains(&\"0.1.0\".to_string()));\n        assert!(versions.contains(&\"0.2.0\".to_string()));\n        assert!(versions.contains(&\"1.0.0\".to_string()));\n    }\n\n    #[test]\n    fn test_parse_with_version_expr_filter_keys_with_regex() {\n        // Test version_expr with filter + # matches for Julia-style JSON (keys with non-version entries)\n        let content = r#\"{\"1.0.0\":{},\"1.1.0\":{},\"nightly\":{},\"latest\":{},\"1.2.0-rc1\":{}}\"#;\n        let versions = parse_version_list(\n            content,\n            None,\n            None,\n            Some(r#\"sortVersions(filter(keys(fromJSON(body)), { # matches \"^\\\\d+\\\\.\\\\d+\\\\.\\\\d+(-[0-9A-Za-z\\\\.-]+)?$\" }))\"#),\n        )\n        .unwrap();\n        assert_eq!(versions, vec![\"1.0.0\", \"1.1.0\", \"1.2.0-rc1\"]);\n    }\n}\n"
  },
  {
    "path": "src/backend/vfox.rs",
    "content": "use crate::{env, plugins::PluginEnum, timeout};\nuse async_trait::async_trait;\nuse eyre::{WrapErr, eyre};\nuse heck::ToKebabCase;\nuse std::collections::{BTreeMap, HashMap};\nuse std::fmt::Debug;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::thread;\nuse tokio::sync::RwLock;\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::backend_type::BackendType;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\nuse crate::dirs;\nuse crate::env_diff::EnvMap;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::{PlatformInfo, ProvenanceType};\nuse crate::plugins::Plugin;\nuse crate::plugins::vfox_plugin::VfoxPlugin;\nuse crate::toolset::{ToolVersion, Toolset, install_state};\nuse crate::ui::multi_progress_report::MultiProgressReport;\n\n#[derive(Debug)]\npub struct VfoxBackend {\n    ba: Arc<BackendArg>,\n    plugin: Arc<VfoxPlugin>,\n    plugin_enum: PluginEnum,\n    exec_env_cache: RwLock<HashMap<String, CacheManager<EnvMap>>>,\n    pathname: String,\n    tool_name: Option<String>,\n}\n\n#[async_trait]\nimpl Backend for VfoxBackend {\n    fn get_type(&self) -> BackendType {\n        match self.plugin_enum {\n            PluginEnum::VfoxBackend(_) => BackendType::VfoxBackend(self.plugin.name().to_string()),\n            PluginEnum::Vfox(_) => BackendType::Vfox,\n            _ => unreachable!(),\n        }\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        let this = self;\n        timeout::run_with_timeout_async(\n            || async {\n                let (vfox, _log_rx) = this.plugin.vfox();\n                this.ensure_plugin_installed(config).await?;\n\n                // Use backend methods if the plugin supports them\n                if this.is_backend_plugin() {\n                    Settings::get().ensure_experimental(\"custom backends\")?;\n                    debug!(\"Using backend method for plugin: {}\", this.pathname);\n                    let tool_name = this.get_tool_name()?;\n                    let versions = vfox\n                        .backend_list_versions(&this.pathname, tool_name)\n                        .await\n                        .wrap_err(\"Backend list versions method failed\")?;\n                    return Ok(versions\n                        .into_iter()\n                        .map(|v| VersionInfo {\n                            version: v,\n                            ..Default::default()\n                        })\n                        .collect());\n                }\n\n                // Use default vfox behavior for traditional plugins\n                let versions = vfox.list_available_versions(&this.pathname).await?;\n                Ok(versions\n                    .into_iter()\n                    .rev()\n                    .map(|v| VersionInfo {\n                        version: v.version,\n                        rolling: v.rolling,\n                        checksum: v.checksum,\n                        ..Default::default()\n                    })\n                    .collect())\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        let mut tv = tv;\n        self.ensure_plugin_installed(&ctx.config).await?;\n        let (vfox, log_rx) = self.plugin.vfox();\n        thread::spawn(|| {\n            for line in log_rx {\n                // TODO: put this in ctx.pr.set_message()\n                info!(\"{}\", line);\n            }\n        });\n\n        // Use backend methods if the plugin supports them\n        if self.is_backend_plugin() {\n            Settings::get().ensure_experimental(\"custom backends\")?;\n            let tool_name = self.get_tool_name()?;\n            let tool_opts = tv.request.options();\n            vfox.backend_install(\n                &self.pathname,\n                tool_name,\n                &tv.version,\n                tv.install_path(),\n                tv.download_path(),\n                tool_opts.opts_as_strings(),\n            )\n            .await\n            .wrap_err(\"Backend install method failed\")?;\n            return Ok(tv);\n        }\n\n        // Check lockfile provenance expectation before verification.\n        // Safety: .take() removes provenance from tv before install. If install\n        // fails, tv is discarded via ?, so the removed value is never observed.\n        // If this function is ever refactored to recover from install errors,\n        // locked_provenance must be restored to tv before retrying.\n        let platform_key = self.get_platform_key();\n        let locked_provenance = tv\n            .lock_platforms\n            .get_mut(&platform_key)\n            .and_then(|pi| pi.provenance.take());\n\n        // Use default vfox behavior for traditional plugins\n        let result = vfox\n            .install(&self.pathname, &tv.version, tv.install_path())\n            .await?;\n\n        // Record provenance if attestation verification succeeded\n        if let Some(att) = result.verified_attestation {\n            let provenance = verified_attestation_to_provenance(att);\n            let pi = tv.lock_platforms.entry(platform_key.clone()).or_default();\n            pi.provenance = Some(provenance);\n        }\n\n        // Enforce lockfile provenance — prevent downgrade attacks\n        if let Some(ref expected) = locked_provenance {\n            let got = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|pi| pi.provenance.as_ref());\n            if !got.is_some_and(|g| std::mem::discriminant(g) == std::mem::discriminant(expected)) {\n                let got_str = got\n                    .map(|g| g.to_string())\n                    .unwrap_or_else(|| \"no verification\".to_string());\n                return Err(eyre!(\n                    \"Lockfile requires {expected} provenance for {tv} but {got_str} was used. \\\n                     This may indicate a downgrade attack. Update the lockfile if the plugin's \\\n                     attestation configuration has intentionally changed.\"\n                ));\n            }\n        }\n\n        // Store checksum for rolling version tracking\n        if let Some(sha256) = result.sha256\n            && let Err(e) = install_state::write_checksum(&self.ba.short, &tv.version, &sha256)\n        {\n            warn!(\"failed to write checksum for {}: {e}\", tv);\n        }\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Vec<PathBuf>> {\n        let path = self\n            ._exec_env(config, tv)\n            .await?\n            .iter()\n            .find(|(k, _)| k.to_uppercase() == \"PATH\")\n            .map(|(_, v)| v.to_string())\n            .unwrap_or(\"bin\".to_string());\n        Ok(env::split_paths(&path).collect())\n    }\n\n    async fn exec_env(\n        &self,\n        config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<EnvMap> {\n        Ok(self\n            ._exec_env(config, tv)\n            .await?\n            .into_iter()\n            .filter(|(k, _)| k.to_uppercase() != \"PATH\")\n            .collect())\n    }\n\n    fn plugin(&self) -> Option<&PluginEnum> {\n        Some(&self.plugin_enum)\n    }\n\n    async fn _idiomatic_filenames(&self) -> eyre::Result<Vec<String>> {\n        let (vfox, _log_rx) = self.plugin.vfox();\n\n        let metadata = vfox.metadata(&self.pathname).await?;\n        Ok(metadata.legacy_filenames)\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> eyre::Result<Vec<String>> {\n        let (vfox, _log_rx) = self.plugin.vfox();\n        let response = vfox.parse_legacy_file(&self.pathname, path).await?;\n        if let Some(version) = response.version {\n            return Ok(version.split_whitespace().map(|s| s.to_string()).collect());\n        }\n        Ok(vec![])\n    }\n\n    async fn get_tarball_url(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> eyre::Result<Option<String>> {\n        let config = Config::get().await?;\n        self.ensure_plugin_installed(&config).await?;\n\n        let (os, arch) = Self::to_vfox_platform(target);\n\n        let (vfox, _log_rx) = self.plugin.vfox();\n        let pre_install = vfox\n            .pre_install_for_platform(&self.pathname, &tv.version, os, arch)\n            .await?;\n\n        Ok(pre_install.url)\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> eyre::Result<PlatformInfo> {\n        // Backend plugins use backend_install and have no PreInstall hook;\n        // fall back to the default implementation.\n        if self.is_backend_plugin() {\n            return Ok(PlatformInfo::default());\n        }\n\n        let config = Config::get().await?;\n        self.ensure_plugin_installed(&config).await?;\n\n        let (os, arch) = Self::to_vfox_platform(target);\n\n        let (vfox, _log_rx) = self.plugin.vfox();\n        let (url, att) = vfox\n            .pre_install_provenance_for_platform(&self.pathname, &tv.version, os, arch)\n            .await?;\n\n        let provenance = att.map(verified_attestation_to_provenance);\n\n        Ok(PlatformInfo {\n            url,\n            provenance,\n            ..Default::default()\n        })\n    }\n}\n\nimpl VfoxBackend {\n    fn is_backend_plugin(&self) -> bool {\n        matches!(&self.plugin_enum, PluginEnum::VfoxBackend(_))\n    }\n\n    /// Map mise platform names to the names expected by vfox plugins.\n    fn to_vfox_platform(target: &PlatformTarget) -> (&str, &str) {\n        let os = match target.os_name() {\n            \"macos\" => \"darwin\",\n            os => os,\n        };\n        let arch = match target.arch_name() {\n            \"x64\" => \"amd64\",\n            arch => arch,\n        };\n        (os, arch)\n    }\n\n    fn get_tool_name(&self) -> eyre::Result<&str> {\n        self.tool_name\n            .as_deref()\n            .ok_or_else(|| eyre::eyre!(\"VfoxBackend requires a tool name (plugin:tool format)\"))\n    }\n\n    pub fn from_arg(ba: BackendArg, backend_plugin_name: Option<String>) -> Self {\n        let pathname = match &backend_plugin_name {\n            Some(plugin_name) => plugin_name.clone(),\n            None => ba.short.to_kebab_case(),\n        };\n\n        let plugin_path = dirs::PLUGINS.join(&pathname);\n        let mut plugin = VfoxPlugin::new(pathname.clone(), plugin_path.clone());\n        plugin.full = Some(ba.full());\n        let plugin = Arc::new(plugin);\n\n        // Extract tool name for plugin:tool format\n        let tool_name = if ba.short.contains(':') {\n            ba.short.split_once(':').map(|(_, tool)| tool.to_string())\n        } else {\n            None\n        };\n\n        Self {\n            exec_env_cache: Default::default(),\n            plugin: plugin.clone(),\n            plugin_enum: match backend_plugin_name {\n                Some(_) => PluginEnum::VfoxBackend(plugin),\n                None => PluginEnum::Vfox(plugin),\n            },\n            ba: Arc::new(ba),\n            pathname,\n            tool_name,\n        }\n    }\n\n    async fn _exec_env(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let opts = tv.request.options();\n        let opts_hash = {\n            use std::hash::{Hash, Hasher};\n            let mut hasher = std::collections::hash_map::DefaultHasher::new();\n            opts.hash(&mut hasher);\n            hasher.finish()\n        };\n        let key = format!(\"{}:{:x}\", tv, opts_hash);\n        let cache_file = format!(\"exec_env_{:x}.msgpack.z\", opts_hash);\n        if !self.exec_env_cache.read().await.contains_key(&key) {\n            let mut caches = self.exec_env_cache.write().await;\n            caches.insert(\n                key.clone(),\n                CacheManagerBuilder::new(tv.cache_path().join(&cache_file))\n                    .with_fresh_file(dirs::DATA.to_path_buf())\n                    .with_fresh_file(self.plugin.plugin_path.to_path_buf())\n                    .with_fresh_file(self.ba().installs_path.to_path_buf())\n                    .build(),\n            );\n        }\n        let exec_env_cache = self.exec_env_cache.read().await;\n        let cache = exec_env_cache.get(&key).unwrap();\n        cache\n            .get_or_try_init_async(async || {\n                self.ensure_plugin_installed(config).await?;\n                let (vfox, _log_rx) = self.plugin.vfox();\n\n                // Use backend methods if the plugin supports them\n                let env_keys = if self.is_backend_plugin() {\n                    let tool_name = self.get_tool_name()?;\n                    vfox.backend_exec_env(\n                        &self.pathname,\n                        tool_name,\n                        &tv.version,\n                        tv.install_path(),\n                        opts.opts\n                            .iter()\n                            .map(|(k, v)| {\n                                (\n                                    k.clone(),\n                                    match v {\n                                        toml::Value::String(s) => s.clone(),\n                                        _ => v.to_string(),\n                                    },\n                                )\n                            })\n                            .collect(),\n                    )\n                    .await\n                    .wrap_err(\"Backend exec env method failed\")?\n                } else {\n                    vfox.env_keys(&self.pathname, &tv.version, &opts.opts)\n                        .await?\n                };\n\n                Ok(env_keys\n                    .into_iter()\n                    .fold(BTreeMap::new(), |mut acc, env_key| {\n                        let key = &env_key.key;\n                        if let Some(val) = acc.get(key) {\n                            let mut paths = env::split_paths(val).collect::<Vec<PathBuf>>();\n                            paths.push(PathBuf::from(&env_key.value));\n                            acc.insert(\n                                env_key.key.clone(),\n                                env::join_paths(paths)\n                                    .unwrap()\n                                    .to_string_lossy()\n                                    .to_string(),\n                            );\n                        } else {\n                            acc.insert(key.clone(), env_key.value.clone());\n                        }\n                        acc\n                    }))\n            })\n            .await\n            .cloned()\n    }\n\n    async fn ensure_plugin_installed(&self, config: &Arc<Config>) -> eyre::Result<()> {\n        self.plugin\n            .ensure_installed(config, &MultiProgressReport::get(), false, false)\n            .await\n    }\n}\n\n/// Convert a verified attestation from the vfox crate into the lockfile provenance type.\nfn verified_attestation_to_provenance(att: vfox::VerifiedAttestation) -> ProvenanceType {\n    match att {\n        vfox::VerifiedAttestation::GithubAttestations { .. } => ProvenanceType::GithubAttestations,\n        // The provenance_path is a local filesystem path to the downloaded SLSA\n        // provenance file — ephemeral and only valid during this install session.\n        // Use url: None to match how github and aqua backends handle SLSA at lock-time.\n        vfox::VerifiedAttestation::Slsa { .. } => ProvenanceType::Slsa { url: None },\n        vfox::VerifiedAttestation::Cosign { .. } => ProvenanceType::Cosign,\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[tokio::test]\n    async fn test_vfox_props() {\n        let _config = Config::get().await.unwrap();\n        let backend = VfoxBackend::from_arg(\"vfox:version-fox/vfox-golang\".into(), None);\n        assert_eq!(backend.pathname, \"vfox-version-fox-vfox-golang\");\n        assert_eq!(\n            backend.plugin.full,\n            Some(\"vfox:version-fox/vfox-golang\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_verified_attestation_to_provenance_type() {\n        // GitHub attestations\n        let att = vfox::VerifiedAttestation::GithubAttestations {\n            owner: \"owner\".into(),\n            repo: \"repo\".into(),\n            signer_workflow: None,\n        };\n        let prov = verified_attestation_to_provenance(att);\n        assert!(matches!(prov, ProvenanceType::GithubAttestations));\n\n        // SLSA provenance — url is None because the local path is ephemeral\n        let att = vfox::VerifiedAttestation::Slsa {\n            provenance_path: PathBuf::from(\"/tmp/slsa.json\"),\n        };\n        let prov = verified_attestation_to_provenance(att);\n        assert!(matches!(prov, ProvenanceType::Slsa { url: None }));\n\n        // Cosign signature\n        let att = vfox::VerifiedAttestation::Cosign {\n            sig_or_bundle_path: PathBuf::from(\"/tmp/sig.bundle\"),\n            public_key_path: Some(PathBuf::from(\"/tmp/key.pub\")),\n        };\n        let prov = verified_attestation_to_provenance(att);\n        assert!(matches!(prov, ProvenanceType::Cosign));\n    }\n}\n"
  },
  {
    "path": "src/build_time.rs",
    "content": "use chrono::{DateTime, FixedOffset};\nuse std::sync::LazyLock as Lazy;\n\npub mod built_info {\n    include!(concat!(env!(\"OUT_DIR\"), \"/built.rs\"));\n}\n\npub static BUILD_TIME: Lazy<DateTime<FixedOffset>> =\n    Lazy::new(|| DateTime::parse_from_rfc2822(built_info::BUILT_TIME_UTC).unwrap());\n\npub static TARGET: &str = built_info::TARGET;\n"
  },
  {
    "path": "src/cache.rs",
    "content": "use std::cmp::min;\nuse std::fs::File;\nuse std::io::{Read, Write};\nuse std::path::{Path, PathBuf};\nuse std::time::Duration;\n\nuse eyre::Result;\nuse flate2::Compression;\nuse flate2::read::ZlibDecoder;\nuse flate2::write::ZlibEncoder;\nuse itertools::Itertools;\nuse once_cell::sync::OnceCell;\nuse serde::Serialize;\nuse serde::de::DeserializeOwned;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::build_time::built_info;\nuse crate::config::Settings;\nuse crate::file::{display_path, modified_duration};\nuse crate::hash::hash_to_str;\nuse crate::rand::random_string;\nuse crate::toolset::env_cache::CachedEnv;\nuse crate::{dirs, file};\n\n#[derive(Debug)]\npub struct CacheManagerBuilder {\n    cache_file_path: PathBuf,\n    cache_keys: Vec<String>,\n    fresh_duration: Option<Duration>,\n    fresh_files: Vec<PathBuf>,\n}\n\npub static BASE_CACHE_KEYS: Lazy<Vec<String>> = Lazy::new(|| {\n    [\n        built_info::FEATURES_STR,\n        built_info::PKG_VERSION,\n        built_info::PROFILE,\n        built_info::TARGET,\n    ]\n    .into_iter()\n    .map(|s| s.to_string())\n    .collect()\n});\n\nimpl CacheManagerBuilder {\n    pub fn new(cache_file_path: impl AsRef<Path>) -> Self {\n        let settings = Settings::get();\n        let mut cache_keys = BASE_CACHE_KEYS.clone();\n        cache_keys.extend([settings.os().to_string(), settings.arch().to_string()]);\n        Self {\n            cache_file_path: cache_file_path.as_ref().to_path_buf(),\n            cache_keys,\n            fresh_files: vec![],\n            fresh_duration: None,\n        }\n    }\n\n    pub fn with_fresh_duration(mut self, duration: Option<Duration>) -> Self {\n        self.fresh_duration = duration;\n        self\n    }\n\n    pub fn with_fresh_file(mut self, path: PathBuf) -> Self {\n        self.fresh_files.push(path);\n        self\n    }\n\n    pub fn with_cache_key(mut self, key: String) -> Self {\n        self.cache_keys.push(key);\n        self\n    }\n\n    fn cache_key(&self) -> String {\n        hash_to_str(&self.cache_keys).chars().take(5).collect()\n    }\n\n    pub fn build<T>(self) -> CacheManager<T>\n    where\n        T: Serialize + DeserializeOwned,\n    {\n        let key = self.cache_key();\n        let (base, ext) = file::split_file_name(&self.cache_file_path);\n        let mut cache_file_path = self.cache_file_path;\n        cache_file_path.set_file_name(format!(\"{base}-{key}.{ext}\"));\n        CacheManager {\n            cache_file_path,\n            cache: Box::new(OnceCell::new()),\n            cache_async: Box::new(tokio::sync::OnceCell::new()),\n            fresh_files: self.fresh_files,\n            fresh_duration: self.fresh_duration,\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct CacheManager<T>\nwhere\n    T: Serialize + DeserializeOwned,\n{\n    cache_file_path: PathBuf,\n    fresh_duration: Option<Duration>,\n    fresh_files: Vec<PathBuf>,\n    cache: Box<OnceCell<T>>,\n    cache_async: Box<tokio::sync::OnceCell<T>>,\n}\n\nimpl<T> CacheManager<T>\nwhere\n    T: Serialize + DeserializeOwned,\n{\n    pub fn get_or_try_init<F>(&self, fetch: F) -> Result<&T>\n    where\n        F: FnOnce() -> Result<T>,\n    {\n        let val = self.cache.get_or_try_init(|| {\n            let path = &self.cache_file_path;\n            if self.is_fresh() {\n                match self.parse() {\n                    Ok(val) => return Ok::<_, color_eyre::Report>(val),\n                    Err(err) => {\n                        warn!(\"failed to parse cache file: {} {:#}\", path.display(), err);\n                    }\n                }\n            }\n            let val = (fetch)()?;\n            if let Err(err) = self.write(&val) {\n                warn!(\"failed to write cache file: {} {:#}\", path.display(), err);\n            }\n            Ok(val)\n        })?;\n        Ok(val)\n    }\n\n    pub async fn get_or_try_init_async<F, Fut>(&self, fetch: F) -> Result<&T>\n    where\n        F: FnOnce() -> Fut,\n        Fut: Future<Output = Result<T>>,\n    {\n        let val = self\n            .cache_async\n            .get_or_try_init(|| async {\n                let path = &self.cache_file_path;\n                if self.is_fresh() {\n                    match self.parse() {\n                        Ok(val) => return Ok::<_, color_eyre::Report>(val),\n                        Err(err) => {\n                            warn!(\"failed to parse cache file: {} {:#}\", path.display(), err);\n                        }\n                    }\n                }\n                let val = fetch().await?;\n                if let Err(err) = self.write(&val) {\n                    warn!(\"failed to write cache file: {} {:#}\", path.display(), err);\n                }\n                Ok(val)\n            })\n            .await?;\n        Ok(val)\n    }\n\n    fn parse(&self) -> Result<T> {\n        let path = &self.cache_file_path;\n        trace!(\"reading {}\", display_path(path));\n        let mut zlib = ZlibDecoder::new(File::open(path)?);\n        let mut bytes = Vec::new();\n        zlib.read_to_end(&mut bytes)?;\n        Ok(rmp_serde::from_slice(&bytes)?)\n    }\n\n    pub fn write(&self, val: &T) -> Result<()> {\n        trace!(\"writing {}\", display_path(&self.cache_file_path));\n        if let Some(parent) = self.cache_file_path.parent() {\n            file::create_dir_all(parent)?;\n        }\n        let partial_path = self\n            .cache_file_path\n            .with_extension(format!(\"part-{}\", random_string(8)));\n        let mut zlib = ZlibEncoder::new(File::create(&partial_path)?, Compression::fast());\n        zlib.write_all(&rmp_serde::to_vec_named(&val)?[..])?;\n        file::rename(&partial_path, &self.cache_file_path)?;\n\n        Ok(())\n    }\n\n    #[cfg(test)]\n    pub fn clear(&self) -> Result<()> {\n        let path = &self.cache_file_path;\n        trace!(\"clearing cache {}\", path.display());\n        if path.exists() {\n            file::remove_file(path)?;\n        }\n        Ok(())\n    }\n\n    fn is_fresh(&self) -> bool {\n        if !self.cache_file_path.exists() {\n            return false;\n        }\n        if let Some(fresh_duration) = self.freshest_duration()\n            && let Ok(metadata) = self.cache_file_path.metadata()\n            && let Ok(modified) = metadata.modified()\n        {\n            return modified.elapsed().unwrap_or_default() < fresh_duration;\n        }\n        true\n    }\n\n    fn freshest_duration(&self) -> Option<Duration> {\n        let mut freshest = self.fresh_duration;\n        for path in self.fresh_files.iter().unique() {\n            let duration = modified_duration(path).unwrap_or_default();\n            freshest = Some(match freshest {\n                None => duration,\n                Some(freshest) => min(freshest, duration),\n            })\n        }\n        freshest\n    }\n}\n\npub(crate) struct PruneResults {\n    pub(crate) size: u64,\n    pub(crate) count: u64,\n}\n\npub(crate) struct PruneOptions {\n    pub(crate) dry_run: bool,\n    pub(crate) verbose: bool,\n    pub(crate) age: Duration,\n}\n\npub(crate) fn auto_prune() -> Result<()> {\n    if !rand::random::<u8>().is_multiple_of(100) {\n        return Ok(()); // only prune 1% of the time\n    }\n    let settings = Settings::get();\n    let age = match settings.cache_prune_age_duration() {\n        Some(age) => age,\n        None => {\n            return Ok(());\n        }\n    };\n    let auto_prune_file = dirs::CACHE.join(\".auto_prune\");\n    if let Ok(Ok(modified)) = auto_prune_file.metadata().map(|m| m.modified())\n        && modified.elapsed().unwrap_or_default() < age\n    {\n        return Ok(());\n    }\n    let empty = file::ls(*dirs::CACHE).unwrap_or_default().is_empty();\n    xx::file::touch_dir(&auto_prune_file)?;\n    if empty {\n        return Ok(());\n    }\n    debug!(\n        \"pruning old cache files, this behavior can be modified with the MISE_CACHE_PRUNE_AGE setting\"\n    );\n    let opts = PruneOptions {\n        dry_run: false,\n        verbose: false,\n        age,\n    };\n    prune(*dirs::CACHE, &opts)?;\n    // Also prune env cache using env_cache_ttl\n    let env_cache_dir = CachedEnv::cache_dir();\n    if env_cache_dir.exists() {\n        let env_opts = PruneOptions {\n            dry_run: false,\n            verbose: false,\n            age: settings.env_cache_ttl(),\n        };\n        prune(&env_cache_dir, &env_opts)?;\n    }\n    Ok(())\n}\n\npub(crate) fn prune(dir: &Path, opts: &PruneOptions) -> Result<PruneResults> {\n    let mut results = PruneResults { size: 0, count: 0 };\n    let remove = |file: &Path| {\n        if opts.dry_run || opts.verbose {\n            info!(\"pruning {}\", display_path(file));\n        } else {\n            debug!(\"pruning {}\", display_path(file));\n        }\n        if !opts.dry_run {\n            file::remove_file_or_dir(file)?;\n        }\n        Ok::<(), color_eyre::Report>(())\n    };\n    for subdir in file::dir_subdirs(dir)? {\n        let subdir = dir.join(&subdir);\n        let r = prune(&subdir, opts)?;\n        results.size += r.size;\n        results.count += r.count;\n        let metadata = subdir.metadata()?;\n        // only delete empty directories if they're old\n        if file::ls(&subdir)?.is_empty()\n            && metadata.modified()?.elapsed().unwrap_or_default() > opts.age\n        {\n            remove(&subdir)?;\n            results.count += 1;\n        }\n    }\n    for f in file::ls(dir)? {\n        let path = dir.join(&f);\n        let metadata = path.metadata()?;\n        let elapsed = metadata.accessed()?.elapsed().unwrap_or_default();\n        if elapsed > opts.age {\n            remove(&path)?;\n            results.size += metadata.len();\n            results.count += 1;\n        }\n    }\n    Ok(results)\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n    use pretty_assertions::assert_eq;\n\n    #[tokio::test]\n    async fn test_cache() {\n        let _config = Config::get().await.unwrap();\n        let cache = CacheManagerBuilder::new(dirs::CACHE.join(\"test-cache\")).build();\n        cache.clear().unwrap();\n        let val = cache.get_or_try_init(|| Ok(1)).unwrap();\n        assert_eq!(val, &1);\n        let val = cache.get_or_try_init(|| Ok(2)).unwrap();\n        assert_eq!(val, &1);\n    }\n}\n"
  },
  {
    "path": "src/cli/activate.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse crate::config::Settings;\nuse crate::env::PATH_KEY;\nuse crate::file::touch_dir;\nuse crate::path_env::PathEnv;\nuse crate::shell::{ActivateOptions, ActivatePrelude, Shell, ShellType, get_shell};\nuse crate::toolset::env_cache::CachedEnv;\nuse crate::{dirs, env};\nuse eyre::Result;\nuse itertools::Itertools;\n\n/// Initializes mise in the current shell session\n///\n/// This should go into your shell's rc file or login shell.\n/// Otherwise, it will only take effect in the current session.\n/// (e.g. ~/.zshrc, ~/.zprofile, ~/.zshenv, ~/.bashrc, ~/.bash_profile, ~/.profile, ~/.config/fish/config.fish, or $PROFILE for powershell)\n///\n/// Typically, this can be added with something like the following:\n///\n///     echo 'eval \"$(mise activate zsh)\"' >> ~/.zshrc\n///\n/// However, this requires that \"mise\" is in your PATH. If it is not, you need to\n/// specify the full path like this:\n///\n///     echo 'eval \"$(/path/to/mise activate zsh)\"' >> ~/.zshrc\n///\n/// Customize status output with `status` settings.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Activate {\n    /// Shell type to generate the script for\n    #[clap()]\n    shell_type: Option<ShellType>,\n\n    /// Suppress non-error messages\n    #[clap(long, short)]\n    quiet: bool,\n\n    /// Shell type to generate the script for\n    #[clap(long, short, hide = true)]\n    shell: Option<ShellType>,\n\n    /// Do not automatically call hook-env\n    ///\n    /// This can be helpful for debugging mise. If you run `eval \"$(mise activate --no-hook-env)\"`, then\n    /// you can call `mise hook-env` manually which will output the env vars to stdout without actually\n    /// modifying the environment. That way you can do things like `mise hook-env --trace` to get more\n    /// information or just see the values that hook-env is outputting.\n    #[clap(long)]\n    no_hook_env: bool,\n\n    /// Use shims instead of modifying PATH\n    /// Effectively the same as:\n    ///\n    ///     PATH=\"$HOME/.local/share/mise/shims:$PATH\"\n    ///\n    /// `mise activate --shims` does not support all the features of `mise activate`.\n    /// See https://mise.jdx.dev/dev-tools/shims.html#shims-vs-path for more information\n    #[clap(long, verbatim_doc_comment)]\n    shims: bool,\n\n    /// Show \"mise: <PLUGIN>@<VERSION>\" message when changing directories\n    #[clap(long, hide = true)]\n    status: bool,\n}\n\nimpl Activate {\n    pub fn run(self) -> Result<()> {\n        let shell = get_shell(self.shell_type.or(self.shell))\n            .expect(\"no shell provided. Run `mise activate zsh` or similar\");\n\n        // touch ROOT to allow hook-env to run\n        let _ = touch_dir(&dirs::DATA);\n\n        let mise_bin = if cfg!(target_os = \"linux\") {\n            // linux dereferences symlinks, so use argv0 instead\n            PathBuf::from(&*env::ARGV0)\n        } else {\n            env::MISE_BIN.clone()\n        };\n        match self.shims {\n            true => self.activate_shims(shell.as_ref(), &mise_bin)?,\n            false => self.activate(shell.as_ref(), &mise_bin)?,\n        }\n\n        Ok(())\n    }\n\n    fn activate_shims(&self, shell: &dyn Shell, mise_bin: &Path) -> std::io::Result<()> {\n        let exe_dir = mise_bin.parent().unwrap();\n        let mut prelude = vec![];\n        // For shells with native path dedup/reorder (fish), always emit path commands\n        // using MovePrependEnv so entries get moved to front on re-source (e.g. VS Code).\n        // For other shells, keep the is_dir_in_path guard to avoid PATH growth on re-source.\n        if let Some(p) = self.shims_prepend_path(shell, exe_dir) {\n            prelude.push(p);\n        }\n        if let Some(p) = self.shims_prepend_path(shell, &dirs::SHIMS) {\n            prelude.push(p);\n        }\n        miseprint!(\"{}\", shell.format_activate_prelude(&prelude))?;\n        Ok(())\n    }\n\n    fn activate(&self, shell: &dyn Shell, mise_bin: &Path) -> std::io::Result<()> {\n        let mut prelude = vec![];\n        if let Some(set_path) = remove_shims()? {\n            prelude.push(set_path);\n        }\n        let exe_dir = mise_bin.parent().unwrap();\n        let mut flags = vec![];\n        if self.quiet {\n            flags.push(\" --quiet\");\n        }\n        if self.status {\n            flags.push(\" --status\");\n        }\n        if let Some(prepend_path) = self.prepend_path(exe_dir) {\n            prelude.push(prepend_path);\n        }\n\n        // Generate encryption key for env cache if caching is enabled\n        // This key is session-scoped and lost when the shell closes\n        if Settings::get().env_cache {\n            let key = CachedEnv::ensure_encryption_key();\n            prelude.push(ActivatePrelude::SetEnv(\n                \"__MISE_ENV_CACHE_KEY\".to_string(),\n                key,\n            ));\n        }\n\n        miseprint!(\n            \"{}\",\n            shell.activate(ActivateOptions {\n                exe: mise_bin.to_path_buf(),\n                flags: flags.join(\"\"),\n                no_hook_env: self.no_hook_env,\n                prelude,\n            })\n        )?;\n        Ok(())\n    }\n\n    fn prepend_path(&self, p: &Path) -> Option<ActivatePrelude> {\n        if is_dir_not_in_nix(p) && !is_dir_in_path(p) && !p.is_relative() {\n            Some(ActivatePrelude::PrependEnv(\n                PATH_KEY.to_string(),\n                p.to_string_lossy().to_string(),\n            ))\n        } else {\n            None\n        }\n    }\n\n    /// Used by activate_shims. For shells with native path dedup (fish), skips\n    /// the is_dir_in_path check and uses MovePrependEnv to reorder entries on\n    /// re-source. For other shells, falls back to prepend_path to avoid PATH growth.\n    fn shims_prepend_path(&self, shell: &dyn Shell, p: &Path) -> Option<ActivatePrelude> {\n        if !is_dir_not_in_nix(p) || p.is_relative() {\n            return None;\n        }\n        if shell.supports_move_path() {\n            Some(ActivatePrelude::MovePrependEnv(\n                PATH_KEY.to_string(),\n                p.to_string_lossy().to_string(),\n            ))\n        } else {\n            self.prepend_path(p)\n        }\n    }\n}\n\nfn remove_shims() -> std::io::Result<Option<ActivatePrelude>> {\n    // When not_found_auto_install is enabled, preserve shims in PATH so they can\n    // trigger auto-install for tools that aren't installed yet\n    if Settings::get().not_found_auto_install {\n        return Ok(None);\n    }\n\n    let shims = dirs::SHIMS\n        .canonicalize()\n        .unwrap_or(dirs::SHIMS.to_path_buf());\n    if env::PATH\n        .iter()\n        .filter_map(|p| p.canonicalize().ok())\n        .contains(&shims)\n    {\n        let path_env = PathEnv::from_iter(env::PATH.clone());\n        // PathEnv automatically removes the shims directory\n        let path = path_env.join().to_string_lossy().to_string();\n        Ok(Some(ActivatePrelude::SetEnv(PATH_KEY.to_string(), path)))\n    } else {\n        Ok(None)\n    }\n}\n\nfn is_dir_in_path(dir: &Path) -> bool {\n    let dir = dir.canonicalize().unwrap_or(dir.to_path_buf());\n    env::PATH\n        .clone()\n        .into_iter()\n        .any(|p| p.canonicalize().unwrap_or(p) == dir)\n}\n\nfn is_dir_not_in_nix(dir: &Path) -> bool {\n    !dir.canonicalize()\n        .unwrap_or(dir.to_path_buf())\n        .starts_with(\"/nix/\")\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>eval \"$(mise activate bash)\"</bold>\n    $ <bold>eval \"$(mise activate zsh)\"</bold>\n    $ <bold>mise activate fish | source</bold>\n    $ <bold>execx($(mise activate xonsh))</bold>\n    $ <bold>(&mise activate pwsh) | Out-String | Invoke-Expression</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/args/backend_arg.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::backend::{ABackend, unalias_backend};\nuse crate::config::Config;\nuse crate::plugins::PluginType;\nuse crate::registry::REGISTRY;\nuse crate::toolset::install_state::InstallStateTool;\nuse crate::toolset::{EPHEMERAL_OPT_KEYS, ToolVersionOptions, install_state, parse_tool_options};\nuse crate::{backend, config, dirs, lockfile, registry};\nuse contracts::requires;\nuse eyre::{Result, bail};\nuse heck::{ToKebabCase, ToShoutySnakeCase};\nuse std::collections::HashSet;\nuse std::env;\nuse std::fmt::{Debug, Display};\nuse std::hash::Hash;\nuse std::path::PathBuf;\nuse xx::regex;\n\n/// Metadata about how a backend was resolved.\n/// This struct is designed for extensibility - additional fields can be added\n/// as needed without breaking existing code.\n#[derive(Clone, Debug, Default)]\npub struct BackendResolution {\n    /// Whether the user explicitly specified the full backend (e.g., \"aqua:oven-sh/bun\" vs \"bun\").\n    /// Also true when restored from install state for backward compatibility with existing installations,\n    /// and for plugin-based tools initialized from the plugin registry.\n    pub explicit: bool,\n}\n\nimpl BackendResolution {\n    pub fn new(explicit: bool) -> Self {\n        Self { explicit }\n    }\n}\n\n#[derive(Clone)]\npub struct BackendArg {\n    /// short or full identifier (what the user specified), \"node\", \"prettier\", \"npm:prettier\", \"cargo:eza\"\n    pub short: String,\n    /// full identifier, \"core:node\", \"npm:prettier\", \"cargo:eza\", \"vfox:version-fox/vfox-nodejs\"\n    full: Option<String>,\n    /// the name of the tool within the backend, e.g.: \"node\", \"prettier\", \"eza\", \"vfox-nodejs\"\n    pub tool_name: String,\n    /// ~/.local/share/mise/cache/<THIS>\n    pub cache_path: PathBuf,\n    /// ~/.local/share/mise/installs/<THIS>\n    pub installs_path: PathBuf,\n    /// ~/.local/share/mise/downloads/<THIS>\n    pub downloads_path: PathBuf,\n    pub opts: Option<ToolVersionOptions>,\n    resolution: BackendResolution,\n    // TODO: make this not a hash key anymore to use this\n    // backend: OnceCell<ABackend>,\n}\n\nimpl<A: AsRef<str>> From<A> for BackendArg {\n    fn from(s: A) -> Self {\n        let short = unalias_backend(s.as_ref()).to_string();\n        // Check if this is a full backend identifier (e.g., \"aqua:oven-sh/bun\")\n        // If so, treat it as explicit since the user specified the backend\n        let explicit = if let Some((prefix, _)) = short.split_once(':') {\n            BackendType::guess(prefix) != BackendType::Unknown\n        } else {\n            false\n        };\n        let (short_parsed, tool_name, opts) = parse_backend_components(&short, None);\n        Self::new_raw(\n            short_parsed,\n            None,\n            tool_name,\n            opts,\n            BackendResolution::new(explicit),\n        )\n    }\n}\n\nimpl From<InstallStateTool> for BackendArg {\n    fn from(ist: InstallStateTool) -> Self {\n        let (short, tool_name, mut opts) = parse_backend_components(&ist.short, ist.full.as_ref());\n\n        // Merge manifest opts into the parsed opts (manifest opts provide defaults)\n        if !ist.opts.is_empty() {\n            let tvo = opts.get_or_insert_with(ToolVersionOptions::default);\n            for (k, v) in ist.opts {\n                tvo.opts.entry(k).or_insert(v);\n            }\n        }\n\n        let mut tool = Self::new_raw(\n            short,\n            ist.full,\n            tool_name,\n            opts,\n            BackendResolution::new(ist.explicit_backend),\n        );\n        if let Some(installs_path) = ist.installs_path {\n            tool.installs_path = installs_path;\n        }\n        tool\n    }\n}\n\n/// Split a string like `\"http:hello[url=...,bin=bin]\"` into `(\"http:hello\", \"url=...,bin=bin\")`.\n/// Returns `None` if no bracketed opts are present.\npub fn split_bracketed_opts(s: &str) -> Option<(&str, &str)> {\n    regex!(r\"^(.+)\\[(.+)\\]$\")\n        .captures(s)\n        .map(|c| (c.get(1).unwrap().as_str(), c.get(2).unwrap().as_str()))\n}\n\n/// Strip trailing `[...]` opts from a string, e.g. `\"foo[a=1]\"` → `\"foo\"`.\npub(crate) fn strip_opts(s: &str) -> String {\n    regex!(r#\"\\[.+\\]$\"#).replace_all(s, \"\").to_string()\n}\n\nfn parse_backend_components(\n    short: &str,\n    full: Option<&String>,\n) -> (String, String, Option<ToolVersionOptions>) {\n    let short = unalias_backend(short).to_string();\n    let (_backend, mut tool_name) = full\n        .unwrap_or(&short)\n        .split_once(':')\n        .unwrap_or((\"\", full.unwrap_or(&short)));\n    let short = strip_opts(&short);\n\n    let mut opts = None;\n    if let Some((name, opts_str)) = split_bracketed_opts(tool_name) {\n        tool_name = name;\n        opts = Some(parse_tool_options(opts_str));\n    }\n\n    (short, tool_name.to_string(), opts)\n}\n\nimpl BackendArg {\n    #[requires(!short.is_empty())]\n    pub fn new(short: String, full: Option<String>) -> Self {\n        let resolution = BackendResolution::new(full.is_some());\n        let (short, tool_name, opts) = parse_backend_components(&short, full.as_ref());\n        Self::new_raw(short, full, tool_name, opts, resolution)\n    }\n\n    pub fn new_raw(\n        short: String,\n        full: Option<String>,\n        tool_name: String,\n        opts: Option<ToolVersionOptions>,\n        resolution: BackendResolution,\n    ) -> Self {\n        let pathname = short.to_kebab_case();\n        Self {\n            tool_name,\n            short,\n            full,\n            cache_path: dirs::CACHE.join(&pathname),\n            installs_path: dirs::INSTALLS.join(&pathname),\n            downloads_path: dirs::DOWNLOADS.join(&pathname),\n            opts,\n            resolution,\n            // backend: Default::default(),\n        }\n    }\n\n    /// Returns the kebab-cased directory name used for this tool's install path.\n    /// This is the canonical name used on the filesystem (e.g. \"github-user-repo\").\n    pub fn tool_dir_name(&self) -> String {\n        self.installs_path\n            .file_name()\n            .unwrap()\n            .to_string_lossy()\n            .to_string()\n    }\n\n    pub fn backend(&self) -> Result<ABackend> {\n        // TODO: see above about hash key\n        // let backend = self.backend.get_or_try_init(|| {\n        //     if let Some(backend) = backend::get(self) {\n        //         Ok(backend)\n        //     } else {\n        //         bail!(\"{self} not found in mise tool registry\");\n        //     }\n        // })?;\n        // Ok(backend.clone())\n        if let Some(backend) = backend::get(self) {\n            Ok(backend)\n        } else if let Some((plugin_name, tool_name)) = self.short.split_once(':') {\n            // Check if the plugin exists first\n            if let Some(plugin_type) = install_state::get_plugin_type(plugin_name) {\n                // Plugin exists, but the backend couldn't be created\n                // This could be due to the tool not being available or plugin not properly installed\n                match plugin_type {\n                    PluginType::Asdf => {\n                        bail!(\n                            \"asdf plugin '{plugin_name}' exists but '{tool_name}' is not available or the plugin is not properly installed\"\n                        );\n                    }\n                    PluginType::Vfox => {\n                        bail!(\n                            \"vfox plugin '{plugin_name}' exists but '{tool_name}' is not available or the plugin is not properly installed\"\n                        );\n                    }\n                    PluginType::VfoxBackend => {\n                        bail!(\n                            \"vfox-backend plugin '{plugin_name}' exists but '{tool_name}' is not available or the plugin is not properly installed\"\n                        );\n                    }\n                }\n            } else {\n                // Plugin doesn't exist\n                bail!(\"{plugin_name} is not a valid plugin name\");\n            }\n        } else {\n            // Check if the tool is in the registry but has no available backends\n            if let Some(rt) = REGISTRY.get(self.short.as_str())\n                && rt.backends().is_empty()\n                && !rt.backends.is_empty()\n            {\n                let all_backends: Vec<&str> = rt.backends.iter().map(|rb| rb.full).collect();\n                bail!(\n                    \"{self} is in the mise tool registry but none of its backends ({}) are supported in the current configuration\",\n                    all_backends.join(\", \")\n                );\n            }\n\n            let registry_shorts: Vec<&str> = REGISTRY.keys().copied().collect();\n            let mut suggestions: Vec<String> =\n                xx::suggest::similar_n_with_threshold(&self.short, &registry_shorts, 3, 0.8)\n                    .into_iter()\n                    .filter(|s| *s != self.short)\n                    .map(|s| s.to_string())\n                    .collect();\n\n            let mise_names: HashSet<String> = suggestions.iter().cloned().collect();\n            for aqua_id in crate::aqua::aqua_registry_wrapper::aqua_suggest(&self.short) {\n                // Skip aqua suggestions whose tool name matches an existing mise suggestion\n                let name = aqua_id\n                    .rsplit_once('/')\n                    .map_or(aqua_id.as_str(), |(_, n)| n);\n                if !mise_names.contains(name) {\n                    suggestions.push(format!(\"aqua:{aqua_id}\"));\n                }\n            }\n\n            let mut msg = format!(\"{self} not found in mise tool registry\");\n            if !suggestions.is_empty() {\n                msg.push_str(\"\\n\\nDid you mean?\");\n                for s in suggestions.iter().take(5) {\n                    msg.push_str(&format!(\"\\n  {s}\"));\n                }\n            }\n            bail!(\"{msg}\");\n        }\n    }\n\n    pub fn backend_type(&self) -> BackendType {\n        // Check if this is a valid backend:tool format first\n        if let Some((backend_prefix, _tool_name)) = self.short.split_once(':')\n            && let Ok(backend_type) = backend_prefix.parse::<BackendType>()\n        {\n            return backend_type;\n        }\n\n        // Then check if this is a vfox plugin:tool format\n        if let Some((plugin_name, _tool_name)) = self.short.split_once(':') {\n            // we cannot reliably determine backend type within install state so we check config first\n            if config::is_loaded() && Config::get_().get_repo_url(plugin_name).is_some() {\n                return BackendType::VfoxBackend(plugin_name.to_string());\n            }\n            if let Some(plugin_type) = install_state::get_plugin_type(plugin_name) {\n                return match plugin_type {\n                    PluginType::Vfox => BackendType::Vfox,\n                    PluginType::VfoxBackend => BackendType::VfoxBackend(plugin_name.to_string()),\n                    PluginType::Asdf => BackendType::Asdf,\n                };\n            }\n        }\n\n        // Only check install state for non-plugin:tool format entries\n        if !self.short.contains(':')\n            && let Ok(Some(backend_type)) = install_state::backend_type(&self.short)\n        {\n            return backend_type;\n        }\n\n        let full = self.full();\n        let backend = full.split(':').next().unwrap();\n        if let Ok(backend_type) = backend.parse() {\n            return backend_type;\n        }\n        if config::is_loaded()\n            && let Some(repo_url) = Config::get_().get_repo_url(&self.short)\n        {\n            return if repo_url.contains(\"vfox-\") {\n                BackendType::Vfox\n            } else {\n                // TODO: maybe something more intelligent?\n                BackendType::Asdf\n            };\n        }\n        BackendType::Unknown\n    }\n\n    pub fn full(&self) -> String {\n        let short = unalias_backend(&self.short);\n\n        // Check for environment variable override first\n        // e.g., MISE_BACKENDS_MYTOOLS='github:myorg/mytools'\n        let env_key = format!(\"MISE_BACKENDS_{}\", short.to_shouty_snake_case());\n        if let Ok(env_value) = env::var(&env_key) {\n            return env_value;\n        }\n\n        if config::is_loaded() {\n            if let Some(full) = Config::get_()\n                .all_aliases\n                .get(short)\n                .and_then(|a| a.backend.clone())\n            {\n                return full;\n            }\n            if let Some(url) = Config::get_().repo_urls.get(short) {\n                return format!(\"asdf:{url}\");\n            }\n\n            let config = Config::get_();\n            if let Some(backend) = lockfile::get_locked_backend(&config, short) {\n                return backend;\n            }\n        }\n\n        // For non-explicit short-name tools that are not plugins, use registry's current\n        // backend if available. This allows tools to automatically switch backends when\n        // the registry changes (e.g., when a tool moves from one maintainer to another).\n        if !self.resolution.explicit\n            && install_state::get_plugin_type(short).is_none()\n            && let Some(registry_full) = REGISTRY\n                .get(short)\n                .and_then(|rt| rt.backends().first().cloned())\n        {\n            if let Some(stored_full) = &self.full\n                && stored_full != registry_full\n            {\n                debug!(\n                    \"backend for '{short}' changed from stored '{stored_full}' to registry '{registry_full}'\"\n                );\n            }\n            return registry_full.to_string();\n        }\n\n        if let Some(full) = &self.full {\n            full.clone()\n        } else if let Some(full) = install_state::get_tool_full(short) {\n            full\n        } else if let Some((plugin_name, _tool_name)) = short.split_once(':') {\n            // Check if this is a plugin:tool format\n            if BackendType::guess(short) != BackendType::Unknown {\n                // Handle built-in backends\n                short.to_string()\n            } else if let Some(pt) = install_state::get_plugin_type(plugin_name) {\n                match pt {\n                    PluginType::Asdf => {\n                        // For asdf plugins, plugin:tool format is invalid\n                        // Return just the plugin name since asdf doesn't support plugin:tool structure\n                        plugin_name.to_string()\n                    }\n                    // For vfox plugins, when already in plugin:tool format, return as-is\n                    // because the plugin itself is the backend specification\n                    PluginType::Vfox => short.to_string(),\n                    PluginType::VfoxBackend => short.to_string(),\n                }\n            } else if plugin_name.starts_with(\"asdf-\") {\n                // Handle asdf plugin:tool format even if not installed\n                plugin_name.to_string()\n            } else {\n                short.to_string()\n            }\n        } else if let Some(pt) = install_state::get_plugin_type(short) {\n            match pt {\n                PluginType::Asdf => format!(\"asdf:{short}\"),\n                PluginType::Vfox => format!(\"vfox:{short}\"),\n                PluginType::VfoxBackend => short.to_string(),\n            }\n        } else if let Some(full) = REGISTRY\n            .get(short)\n            .and_then(|rt| rt.backends().first().cloned())\n        {\n            full.to_string()\n        } else {\n            short.to_string()\n        }\n    }\n\n    pub fn full_with_opts(&self) -> String {\n        let full = self.full();\n        if split_bracketed_opts(&full).is_some() {\n            return full;\n        }\n        if let Some(opts) = &self.opts {\n            let opts_str = opts\n                .opts\n                .iter()\n                .filter(|(k, _)| !EPHEMERAL_OPT_KEYS.contains(&k.as_str()))\n                .filter_map(|(k, v)| match v {\n                    toml::Value::String(s) => Some(format!(\"{k}={s}\")),\n                    toml::Value::Table(_) | toml::Value::Array(_) => None,\n                    _ => Some(format!(\"{k}={v}\")),\n                })\n                .collect::<Vec<_>>()\n                .join(\",\");\n            if !full.contains(['[', ']']) && !opts_str.is_empty() {\n                return format!(\"{full}[{opts_str}]\");\n            }\n        }\n        full\n    }\n\n    pub fn full_without_opts(&self) -> String {\n        let full = self.full();\n        if let Some((name, _)) = split_bracketed_opts(&full) {\n            return name.to_string();\n        }\n        full\n    }\n\n    pub fn opts(&self) -> ToolVersionOptions {\n        // Start with registry options as base (if available)\n        let full = self.full();\n        let mut opts = REGISTRY\n            .get(self.short.as_str())\n            .map(|rt| rt.backend_options(&full))\n            .unwrap_or_default();\n\n        // Get user-provided options (from self.opts or from full string)\n        let user_opts = self.opts.clone().unwrap_or_else(|| {\n            if let Some((_, opts_str)) = split_bracketed_opts(&full) {\n                parse_tool_options(opts_str)\n            } else {\n                ToolVersionOptions::default()\n            }\n        });\n\n        // Merge user options on top (user options take precedence)\n        for (k, v) in user_opts.opts {\n            opts.opts.insert(k, v);\n        }\n        for (k, v) in user_opts.install_env {\n            opts.install_env.insert(k, v);\n        }\n        if user_opts.os.is_some() {\n            opts.os = user_opts.os;\n        }\n\n        opts\n    }\n\n    pub fn set_opts(&mut self, opts: Option<ToolVersionOptions>) {\n        self.opts = opts;\n    }\n\n    /// Returns true if the user explicitly specified the full backend identifier.\n    /// When false and the tool is not plugin-based, it may resolve to the current\n    /// registry backend on next operation, allowing automatic backend migration\n    /// when registry/ is updated.\n    pub fn has_explicit_backend(&self) -> bool {\n        self.resolution.explicit\n    }\n\n    /// Returns the stored backend identifier, preferring the explicitly stored value\n    /// over dynamic registry resolution. For non-explicit tools, uses `full()` which\n    /// respects registry updates, allowing automatic backend migration when registry/\n    /// is updated. Used for lockfiles to preserve the actual installed backend when possible.\n    /// Options are stripped since lockfiles have a separate options field.\n    pub fn stored_full(&self) -> String {\n        // For non-explicit tools, use full() which respects registry updates.\n        // This allows tools to automatically switch backends when the registry changes.\n        if !self.resolution.explicit {\n            let full = self.full();\n            // Strip options since lockfiles have a separate options field\n            if let Some((name, _)) = split_bracketed_opts(&full) {\n                return name.to_string();\n            }\n            return full;\n        }\n\n        // For explicit tools, preserve the stored value\n        let full = if let Some(full) = &self.full {\n            full.clone()\n        } else {\n            let short = unalias_backend(&self.short);\n            if let Some(full) = install_state::get_tool_full(short) {\n                full\n            } else if let Some(pt) = install_state::get_plugin_type(short) {\n                match pt {\n                    PluginType::Asdf => format!(\"asdf:{short}\"),\n                    PluginType::Vfox => format!(\"vfox:{short}\"),\n                    PluginType::VfoxBackend => short.to_string(),\n                }\n            } else {\n                self.full()\n            }\n        };\n        // Strip options since lockfiles have a separate options field\n        if let Some((name, _)) = split_bracketed_opts(&full) {\n            return name.to_string();\n        }\n        full\n    }\n\n    pub fn tool_name(&self) -> String {\n        let full = self.full();\n        let (_backend, tool_name) = full.split_once(':').unwrap_or((\"\", &full));\n        strip_opts(tool_name)\n    }\n\n    /// maps something like cargo:cargo-binstall to cargo-binstall and ubi:cargo-binstall, etc\n    pub fn all_fulls(&self) -> HashSet<String> {\n        let full = self.full();\n        let mut all = HashSet::new();\n        for short in registry::shorts_for_full(&full) {\n            let rt = REGISTRY.get(short).unwrap();\n            let backends = rt.backends();\n            if backends.contains(&full.as_str()) {\n                all.insert(rt.short.to_string());\n                all.extend(backends.into_iter().map(|s| s.to_string()));\n            }\n        }\n        all.insert(full);\n        all.insert(self.short.to_string());\n        all\n    }\n\n    pub fn is_os_supported(&self) -> bool {\n        if self.uses_plugin() {\n            return true;\n        }\n        if let Some(rt) = REGISTRY.get(self.short.as_str()) {\n            return rt.is_supported_os();\n        }\n        true\n    }\n\n    pub fn uses_plugin(&self) -> bool {\n        install_state::get_plugin_type(&self.short).is_some()\n    }\n}\n\nimpl Display for BackendArg {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.short)\n    }\n}\n\nimpl Debug for BackendArg {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        if let Some(full) = &self.full {\n            write!(f, r#\"BackendArg({} -> {})\"#, self.short, full)\n        } else {\n            write!(f, r#\"BackendArg({})\"#, self.short)\n        }\n    }\n}\n\nimpl PartialEq for BackendArg {\n    fn eq(&self, other: &Self) -> bool {\n        self.short == other.short\n    }\n}\n\nimpl Eq for BackendArg {}\n\nimpl PartialOrd for BackendArg {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for BackendArg {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.short.cmp(&other.short)\n    }\n}\n\nimpl Hash for BackendArg {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.short.hash(state);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use pretty_assertions::{assert_eq, assert_str_eq};\n\n    #[tokio::test]\n    async fn test_backend_arg() {\n        let _config = Config::get().await.unwrap();\n        let t = |s: &str, full, tool_name, t| {\n            let fa: BackendArg = s.into();\n            assert_str_eq!(full, fa.full());\n            assert_str_eq!(tool_name, fa.tool_name);\n            assert_eq!(t, fa.backend_type());\n        };\n        #[cfg(unix)]\n        let asdf = |s, full, name| t(s, full, name, BackendType::Asdf);\n        let cargo = |s, full, name| t(s, full, name, BackendType::Cargo);\n        // let core = |s, full, name| t(s, full, name, BackendType::Core);\n        let npm = |s, full, name| t(s, full, name, BackendType::Npm);\n        let vfox = |s, full, name| t(s, full, name, BackendType::Vfox);\n\n        #[cfg(unix)]\n        {\n            asdf(\"asdf:clojure\", \"asdf:clojure\", \"clojure\");\n            asdf(\"clojure\", \"asdf:mise-plugins/mise-clojure\", \"clojure\");\n        }\n        cargo(\"cargo:eza\", \"cargo:eza\", \"eza\");\n        // core(\"node\", \"node\", \"node\");\n        npm(\"npm:@antfu/ni\", \"npm:@antfu/ni\", \"@antfu/ni\");\n        npm(\"npm:prettier\", \"npm:prettier\", \"prettier\");\n        vfox(\n            \"vfox:version-fox/vfox-nodejs\",\n            \"vfox:version-fox/vfox-nodejs\",\n            \"version-fox/vfox-nodejs\",\n        );\n    }\n\n    #[tokio::test]\n    async fn test_backend_arg_pathname() {\n        let _config = Config::get().await.unwrap();\n        let t = |s: &str, expected| {\n            let fa: BackendArg = s.into();\n            let actual = fa.installs_path.to_string_lossy();\n            let expected = dirs::INSTALLS.join(expected);\n            assert_str_eq!(actual, expected.to_string_lossy());\n        };\n        t(\"asdf:node\", \"asdf-node\");\n        t(\"node\", \"node\");\n        t(\"cargo:eza\", \"cargo-eza\");\n        t(\"npm:@antfu/ni\", \"npm-antfu-ni\");\n        t(\"npm:prettier\", \"npm-prettier\");\n        t(\n            \"vfox:version-fox/vfox-nodejs\",\n            \"vfox-version-fox-vfox-nodejs\",\n        );\n        t(\"vfox:version-fox/nodejs\", \"vfox-version-fox-nodejs\");\n    }\n\n    #[tokio::test]\n    async fn test_backend_arg_bug_fixes() {\n        let _config = Config::get().await.unwrap();\n\n        // Test that asdf plugins in plugin:tool format return just the plugin name\n        // (asdf doesn't support plugin:tool structure)\n        let fa: BackendArg = \"asdf-plugin:tool\".into();\n        assert_str_eq!(\"asdf-plugin\", fa.full());\n\n        // Test that vfox plugins in plugin:tool format return as-is\n        let fa: BackendArg = \"vfox-plugin:tool\".into();\n        assert_str_eq!(\"vfox-plugin:tool\", fa.full());\n    }\n\n    #[tokio::test]\n    async fn test_backend_arg_improved_error_messages() {\n        let _config = Config::get().await.unwrap();\n\n        // Test that when a plugin exists but the tool is not available,\n        // we get a more specific error message instead of \"not a valid backend name\"\n        let fa: BackendArg = \"nonexistent-plugin:some-tool\".into();\n        let result = fa.backend();\n        assert!(result.is_err());\n        let error_msg = result.unwrap_err().to_string();\n        assert!(\n            error_msg.contains(\"is not a valid plugin name\"),\n            \"Expected error to mention invalid plugin name, got: {error_msg}\"\n        );\n\n        // Note: We can't easily test the case where a plugin exists but the tool doesn't\n        // because that would require setting up actual plugins in the test environment.\n        // The logic has been improved to check plugin existence first and provide\n        // more specific error messages based on the plugin type.\n    }\n\n    #[tokio::test]\n    async fn test_full_with_opts_appends_and_filters() {\n        let _config = Config::get().await.unwrap();\n\n        // start with a normal full like \"npm:prettier\" and attach opts via set_opts\n        let mut fa: BackendArg = \"npm:prettier\".into();\n        fa.set_opts(Some(parse_tool_options(\"a=1,install_env=ignored,b=2\")));\n        // install_env should be filtered out, remaining order preserved\n        assert_str_eq!(\"npm:prettier[a=1,b=2]\", fa.full_with_opts());\n\n        fa = \"http:hello-lock\".into();\n        fa.set_opts(Some(parse_tool_options(\"url=https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz,bin_path=hello-world-1.0.0/bin\")));\n        // install_env should be filtered out, remaining order preserved\n        assert_str_eq!(\n            \"http:hello-lock[url=https://mise.jdx.dev/test-fixtures/hello-world-1.0.0.tar.gz,bin_path=hello-world-1.0.0/bin]\",\n            fa.full_with_opts()\n        );\n    }\n\n    #[tokio::test]\n    async fn test_full_with_opts_preserves_existing_brackets() {\n        let _config = Config::get().await.unwrap();\n\n        // when the full already contains options brackets, full_with_opts should return it unchanged\n        let mut fa = BackendArg::new_raw(\n            \"node\".to_string(),\n            Some(\"node[foo=bar]\".to_string()),\n            \"node\".to_string(),\n            None,\n            BackendResolution::new(true),\n        );\n        assert_str_eq!(\"node[foo=bar]\", fa.full_with_opts());\n\n        fa = BackendArg::new_raw(\n            \"gitlab:jdxcode/mise-test-fixtures\".to_string(),\n            Some(\"gitlab:jdxcode/mise-test-fixtures[asset_pattern=hello-world-1.0.0.tar.gz,bin_path=hello-world-1.0.0/bin]\".to_string()),\n            \"gitlab:jdxcode/mise-test-fixtures\".to_string(),\n            None,\n            BackendResolution::new(true),\n        );\n        assert_str_eq!(\n            \"gitlab:jdxcode/mise-test-fixtures[asset_pattern=hello-world-1.0.0.tar.gz,bin_path=hello-world-1.0.0/bin]\",\n            fa.full_with_opts()\n        );\n    }\n}\n"
  },
  {
    "path": "src/cli/args/env_var_arg.rs",
    "content": "use std::str::FromStr;\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct EnvVarArg {\n    pub key: String,\n    pub value: Option<String>,\n}\n\nimpl FromStr for EnvVarArg {\n    type Err = eyre::Error;\n\n    fn from_str(input: &str) -> eyre::Result<Self> {\n        let ev = match input.split_once('=') {\n            Some((k, v)) => Self {\n                key: k.to_string(),\n                value: Some(v.to_string()),\n            },\n            None => Self {\n                key: input.to_string(),\n                value: None,\n            },\n        };\n        Ok(ev)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n    use test_log::test;\n\n    use super::EnvVarArg;\n\n    #[test]\n    fn valid_values() {\n        let values = [\n            (\"FOO\", new_arg(\"FOO\", None)),\n            (\"FOO=\", new_arg(\"FOO\", Some(\"\"))),\n            (\"FOO=bar\", new_arg(\"FOO\", Some(\"bar\"))),\n        ];\n\n        for (input, want) in values {\n            let got: EnvVarArg = input.parse().unwrap();\n            assert_eq!(got, want);\n        }\n    }\n\n    fn new_arg(key: &str, value: Option<&str>) -> EnvVarArg {\n        EnvVarArg {\n            key: key.to_string(),\n            value: value.map(|s| s.to_string()),\n        }\n    }\n}\n"
  },
  {
    "path": "src/cli/args/mod.rs",
    "content": "pub use backend_arg::{BackendArg, BackendResolution, split_bracketed_opts};\npub use env_var_arg::EnvVarArg;\npub use tool_arg::{ToolArg, ToolVersionType};\n\nmod backend_arg;\nmod env_var_arg;\nmod tool_arg;\n"
  },
  {
    "path": "src/cli/args/tool_arg.rs",
    "content": "use std::path::PathBuf;\nuse std::str::FromStr;\nuse std::{fmt::Display, sync::Arc};\n\nuse crate::cli::args::BackendArg;\nuse crate::toolset::{ToolRequest, ToolSource};\nuse crate::ui::style;\nuse console::style;\nuse eyre::bail;\nuse xx::regex;\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct ToolArg {\n    pub short: String,\n    pub ba: Arc<BackendArg>,\n    pub version: Option<String>,\n    pub version_type: ToolVersionType,\n    pub tvr: Option<ToolRequest>,\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum ToolVersionType {\n    Path(PathBuf),\n    Prefix(String),\n    Ref(String, String),\n    Sub { sub: String, orig_version: String },\n    System,\n    Version(String),\n}\n\nimpl FromStr for ToolArg {\n    type Err = eyre::Error;\n\n    fn from_str(input: &str) -> eyre::Result<Self> {\n        let (backend_input, version) = parse_input(input);\n\n        let ba: Arc<BackendArg> = Arc::new(backend_input.into());\n        let version_type = match version.as_ref() {\n            Some(version) => version.parse()?,\n            None => ToolVersionType::Version(String::from(\"latest\")),\n        };\n        let tvr = version\n            .as_ref()\n            .map(|v| ToolRequest::new(ba.clone(), v, ToolSource::Argument))\n            .transpose()?;\n        Ok(Self {\n            short: ba.short.clone(),\n            tvr,\n            version: version.map(|v| v.to_string()),\n            version_type,\n            ba,\n        })\n    }\n}\n\nimpl FromStr for ToolVersionType {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        trace!(\"parsing ToolVersionType from: {}\", s);\n        Ok(match s.split_once(':') {\n            Some((ref_type @ (\"ref\" | \"tag\" | \"branch\" | \"rev\"), r)) => {\n                Self::Ref(ref_type.to_string(), r.to_string())\n            }\n            Some((\"prefix\", p)) => Self::Prefix(p.to_string()),\n            Some((\"path\", p)) => Self::Path(PathBuf::from(p)),\n            Some((p, v)) if p.starts_with(\"sub-\") => Self::Sub {\n                sub: p.split_once('-').unwrap().1.to_string(),\n                orig_version: v.to_string(),\n            },\n            Some((p, _)) => bail!(\"invalid prefix: {}\", style::ered(p)),\n            None if s == \"system\" => Self::System,\n            None => Self::Version(s.to_string()),\n        })\n    }\n}\n\nimpl Display for ToolVersionType {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Path(p) => write!(f, \"path:{}\", p.to_string_lossy()),\n            Self::Prefix(p) => write!(f, \"prefix:{p}\"),\n            Self::Ref(rt, r) => write!(f, \"{rt}:{r}\"),\n            Self::Sub { sub, orig_version } => write!(f, \"sub-{sub}:{orig_version}\"),\n            Self::System => write!(f, \"system\"),\n            Self::Version(v) => write!(f, \"{v}\"),\n        }\n    }\n}\n\nimpl ToolArg {\n    /// this handles the case where the user typed in:\n    /// mise local node 20.0.0\n    /// instead of\n    /// mise local node@20.0.0\n    ///\n    /// We can detect this, and we know what they meant, so make it work the way\n    /// they expected.\n    pub fn double_tool_condition(tools: &[ToolArg]) -> eyre::Result<Vec<ToolArg>> {\n        let mut tools = tools.to_vec();\n        if tools.len() == 2 {\n            let re = regex!(r\"^\\d+(\\.\\d+)*$\");\n            let a = tools[0].clone();\n            let b = tools[1].clone();\n            if a.tvr.is_none() && b.tvr.is_none() && re.is_match(&b.ba.tool_name) {\n                tools[1].short = a.short.clone();\n                tools[1].tvr = Some(ToolRequest::new(\n                    a.ba.clone(),\n                    &b.ba.tool_name,\n                    ToolSource::Argument,\n                )?);\n                tools[1].ba = a.ba;\n                tools[1].version_type = b.ba.tool_name.parse()?;\n                tools[1].version = Some(b.ba.tool_name.clone());\n                tools.remove(0);\n            }\n        }\n        Ok(tools)\n    }\n\n    pub fn with_version(self, version: &str) -> Self {\n        Self {\n            tvr: Some(ToolRequest::new(self.ba.clone(), version, ToolSource::Argument).unwrap()),\n            version: Some(version.into()),\n            version_type: version.parse().unwrap(),\n            ..self\n        }\n    }\n\n    pub fn style(&self) -> String {\n        let version = self\n            .tvr\n            .as_ref()\n            .map(|t| t.version())\n            .unwrap_or(String::from(\"latest\"));\n        format!(\n            \"{}{}\",\n            style(&self.short).blue().for_stderr(),\n            style(&format!(\"@{version}\")).for_stderr()\n        )\n    }\n}\n\nimpl Display for ToolArg {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match &self.tvr {\n            Some(tvr) => write!(f, \"{tvr}\"),\n            _ => write!(f, \"{}\", self.ba.tool_name),\n        }\n    }\n}\n\nfn parse_input(s: &str) -> (&str, Option<&str>) {\n    let Some((left, right)) = s.split_once('@') else {\n        return (s, None);\n    };\n\n    if left.is_empty() {\n        // Scoped package name starting with '@' (e.g., \"@anthropic-ai/claude-code\")\n        // The first '@' is part of the name, not a version separator\n        // Look for a second '@' to separate name from version\n        return right\n            .split_once('@')\n            .map(|(name, version)| {\n                (\n                    &s[..name.len() + 1],\n                    if version.is_empty() {\n                        None\n                    } else {\n                        Some(version)\n                    },\n                )\n            })\n            .unwrap_or((s, None));\n    }\n\n    if left.ends_with(':') {\n        // Backend format: try to find version in the remaining part\n        return right\n            .split_once('@')\n            .map(|(tool, version)| {\n                (\n                    &s[..left.len() + tool.len() + 1],\n                    if version.is_empty() {\n                        None\n                    } else {\n                        Some(version)\n                    },\n                )\n            })\n            .unwrap_or((s, None));\n    }\n\n    // Simple \"tool@version\" format\n    (left, if right.is_empty() { None } else { Some(right) })\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_tool_arg() {\n        let _config = Config::get().await.unwrap();\n        let tool = ToolArg::from_str(\"node\").unwrap();\n        assert_eq!(\n            tool,\n            ToolArg {\n                short: \"node\".into(),\n                ba: Arc::new(\"node\".into()),\n                version: None,\n                version_type: ToolVersionType::Version(\"latest\".into()),\n                tvr: None,\n            }\n        );\n    }\n\n    #[tokio::test]\n    async fn test_tool_arg_with_version() {\n        let _config = Config::get().await.unwrap();\n        let tool = ToolArg::from_str(\"node@20\").unwrap();\n        assert_eq!(\n            tool,\n            ToolArg {\n                short: \"node\".into(),\n                ba: Arc::new(\"node\".into()),\n                version: Some(\"20\".into()),\n                version_type: ToolVersionType::Version(\"20\".into()),\n                tvr: Some(\n                    ToolRequest::new(Arc::new(\"node\".into()), \"20\", ToolSource::Argument).unwrap()\n                ),\n            }\n        );\n    }\n\n    #[tokio::test]\n    async fn test_tool_arg_with_version_and_alias() {\n        let _config = Config::get().await.unwrap();\n        let tool = ToolArg::from_str(\"nodejs@lts\").unwrap();\n        assert_eq!(\n            tool,\n            ToolArg {\n                short: \"node\".into(),\n                ba: Arc::new(\"node\".into()),\n                version: Some(\"lts\".into()),\n                version_type: ToolVersionType::Version(\"lts\".into()),\n                tvr: Some(\n                    ToolRequest::new(Arc::new(\"node\".into()), \"lts\", ToolSource::Argument).unwrap()\n                ),\n            }\n        );\n    }\n\n    #[tokio::test]\n    async fn test_tool_arg_parse_input() {\n        let _config = Config::get().await.unwrap();\n        let t = |input, f, v| {\n            let (backend, version) = parse_input(input);\n            assert_eq!(backend, f);\n            assert_eq!(version, v);\n        };\n        t(\"erlang\", \"erlang\", None);\n        t(\"erlang@\", \"erlang\", None);\n        t(\"erlang@27.2\", \"erlang\", Some(\"27.2\"));\n        t(\"npm:@antfu/ni\", \"npm:@antfu/ni\", None);\n        t(\"npm:@antfu/ni@\", \"npm:@antfu/ni\", None);\n        t(\"npm:@antfu/ni@1.0.0\", \"npm:@antfu/ni\", Some(\"1.0.0\"));\n        t(\"npm:@antfu/ni@1.0.0@1\", \"npm:@antfu/ni\", Some(\"1.0.0@1\"));\n        t(\"npm:\", \"npm:\", None);\n        t(\"npm:prettier\", \"npm:prettier\", None);\n        t(\"npm:prettier@1.0.0\", \"npm:prettier\", Some(\"1.0.0\"));\n        t(\n            \"ubi:BurntSushi/ripgrep[exe=rg]\",\n            \"ubi:BurntSushi/ripgrep[exe=rg]\",\n            None,\n        );\n        t(\n            \"ubi:BurntSushi/ripgrep[exe=rg,match=musl]\",\n            \"ubi:BurntSushi/ripgrep[exe=rg,match=musl]\",\n            None,\n        );\n        t(\n            \"ubi:BurntSushi/ripgrep[exe=rg,match=musl]@1.0.0\",\n            \"ubi:BurntSushi/ripgrep[exe=rg,match=musl]\",\n            Some(\"1.0.0\"),\n        );\n        // Scoped package names without backend prefix\n        t(\n            \"@anthropic-ai/claude-code\",\n            \"@anthropic-ai/claude-code\",\n            None,\n        );\n        t(\"@biomejs/biome\", \"@biomejs/biome\", None);\n        t(\"@biomejs/biome@latest\", \"@biomejs/biome\", Some(\"latest\"));\n        t(\"@biomejs/biome@1.0.0\", \"@biomejs/biome\", Some(\"1.0.0\"));\n        t(\"@biomejs/biome@\", \"@biomejs/biome\", None);\n    }\n}\n"
  },
  {
    "path": "src/cli/asdf.rs",
    "content": "use std::sync::Arc;\n\nuse clap::ValueHint::CommandWithArguments;\nuse eyre::Result;\nuse itertools::Itertools;\n\nuse crate::cli::Cli;\nuse crate::cli::ls_remote::LsRemote;\nuse crate::config::Config;\nuse crate::toolset::ToolsetBuilder;\n\n/// [internal] simulates asdf for plugins that call \"asdf\" internally\n#[derive(Debug, clap::Args)]\n#[clap(hide = true, verbatim_doc_comment)]\npub struct Asdf {\n    /// all arguments\n    #[clap(allow_hyphen_values = true, value_hint = CommandWithArguments, trailing_var_arg = true)]\n    args: Vec<String>,\n}\n\nimpl Asdf {\n    pub async fn run(mut self) -> Result<()> {\n        let config = Config::get().await?;\n        let mut args = vec![String::from(\"mise\")];\n        args.append(&mut self.args);\n\n        match args.get(1).map(|s| s.as_str()) {\n            Some(\"reshim\") => Box::pin(Cli::run(&args)).await,\n            Some(\"list\") => list_versions(&config, &args).await,\n            Some(\"install\") => {\n                if args.len() == 4 {\n                    let version = args.pop().unwrap();\n                    args[2] = format!(\"{}@{}\", args[2], version);\n                }\n                Box::pin(Cli::run(&args)).await\n            }\n            _ => Box::pin(Cli::run(&args)).await,\n        }\n    }\n}\n\nasync fn list_versions(config: &Arc<Config>, args: &[String]) -> Result<()> {\n    if args[2] == \"all\" {\n        return LsRemote {\n            prefix: None,\n            all: false,\n            plugin: args.get(3).map(|s| s.parse()).transpose()?,\n            json: false,\n        }\n        .run()\n        .await;\n    }\n    let ts = ToolsetBuilder::new().build(config).await?;\n    let mut versions = ts.list_installed_versions(config).await?;\n    let plugin = match args.len() {\n        3 => Some(&args[2]),\n        _ => None,\n    };\n    if let Some(plugin) = plugin {\n        versions.retain(|(_, v)| &v.ba().to_string() == plugin);\n        for (_, version) in versions {\n            miseprintln!(\"{}\", version.version);\n        }\n    } else {\n        for (plugin, versions) in &versions.into_iter().chunk_by(|(_, v)| v.ba().clone()) {\n            miseprintln!(\"{}\", plugin);\n            for (_, tv) in versions {\n                miseprintln!(\"  {}\", tv.version);\n            }\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "src/cli/backends/ls.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse eyre::Result;\nuse strum::IntoEnumIterator;\n\n/// List built-in backends\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"list\", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct BackendsLs {}\n\nimpl BackendsLs {\n    pub fn run(self) -> Result<()> {\n        let mut backends = BackendType::iter().collect::<Vec<BackendType>>();\n        backends.retain(|f| !matches!(f, BackendType::Unknown));\n\n        for backend in backends {\n            miseprintln!(\"{}\", backend);\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise backends ls</bold>\n    aqua\n    asdf\n    cargo\n    core\n    dotnet\n    gem\n    go\n    npm\n    pipx\n    spm\n    ubi\n    vfox\n\"#\n);\n"
  },
  {
    "path": "src/cli/backends/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nmod ls;\n\n#[derive(Debug, clap::Args)]\n#[clap(about = \"Manage backends\", visible_alias = \"b\", aliases = [\"backend\", \"backend-list\"])]\npub struct Backends {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Ls(ls::BackendsLs),\n}\n\nimpl Commands {\n    pub fn run(self) -> Result<()> {\n        match self {\n            Self::Ls(cmd) => cmd.run(),\n        }\n    }\n}\n\nimpl Backends {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self.command.unwrap_or(Commands::Ls(ls::BackendsLs {}));\n\n        cmd.run()\n    }\n}\n"
  },
  {
    "path": "src/cli/bin_paths.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::toolset::ToolsetBuilder;\nuse eyre::Result;\n\n/// List all the active runtime bin paths\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment)]\npub struct BinPaths {\n    /// Tool(s) to look up\n    /// e.g.: ruby@3\n    #[clap(value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    tool: Option<Vec<ToolArg>>,\n}\n\nimpl BinPaths {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let mut tsb = ToolsetBuilder::new();\n        if let Some(tool) = &self.tool {\n            tsb = tsb.with_args(tool);\n        }\n        let mut ts = tsb.build(&config).await?;\n        if let Some(tool) = &self.tool {\n            ts.versions.retain(|k, _| tool.iter().any(|t| *t.ba == **k));\n        }\n        ts.notify_if_versions_missing(&config).await;\n        for p in ts.list_paths(&config).await {\n            miseprintln!(\"{}\", p.display());\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/cache/clear.rs",
    "content": "use crate::dirs::CACHE;\nuse crate::file::{display_path, remove_all};\nuse crate::toolset::env_cache::CachedEnv;\nuse eyre::Result;\nuse filetime::set_file_times;\nuse heck::ToKebabCase;\nuse walkdir::WalkDir;\n\n/// Deletes all cache files in mise\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"c\", alias = \"clean\")]\npub struct CacheClear {\n    /// Plugin(s) to clear cache for\n    /// e.g.: node, python\n    plugin: Option<Vec<String>>,\n\n    /// Mark all cache files as old\n    #[clap(long, hide = true)]\n    outdate: bool,\n}\n\nimpl CacheClear {\n    pub fn run(self) -> Result<()> {\n        let cache_dirs = match &self.plugin {\n            Some(plugins) => plugins\n                .iter()\n                .filter_map(|p| {\n                    let kebab = p.to_kebab_case();\n                    if kebab.is_empty() {\n                        warn!(\"invalid plugin name: {p}\");\n                        None\n                    } else {\n                        Some(CACHE.join(kebab))\n                    }\n                })\n                .collect(),\n            None => vec![CACHE.to_path_buf()],\n        };\n        if self.outdate {\n            for p in cache_dirs {\n                if p.exists() {\n                    debug!(\"outdating cache from {}\", display_path(&p));\n                    let files = WalkDir::new(&p)\n                        .into_iter()\n                        .filter_map(|e| e.ok())\n                        .filter(|e| e.file_type().is_file() || e.file_type().is_dir());\n                    for e in files {\n                        set_file_times(\n                            e.path(),\n                            filetime::FileTime::zero(),\n                            filetime::FileTime::zero(),\n                        )?;\n                    }\n                }\n            }\n        } else {\n            for p in cache_dirs {\n                if p.exists() {\n                    debug!(\"clearing cache from {}\", display_path(&p));\n                    remove_all(p)?;\n                }\n            }\n            // Also clear env cache when clearing all caches\n            if self.plugin.is_none() {\n                CachedEnv::clear()?;\n            }\n            match &self.plugin {\n                Some(plugins) => info!(\"cache cleared for {}\", plugins.join(\", \")),\n                None => info!(\"cache cleared\"),\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/cache/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nuse crate::env;\n\nmod clear;\nmod path;\nmod prune;\n\n/// Manage the mise cache\n///\n/// Run `mise cache` with no args to view the current cache directory.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment)]\npub struct Cache {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Clear(clear::CacheClear),\n    Path(path::CachePath),\n    Prune(prune::CachePrune),\n}\n\nimpl Commands {\n    pub fn run(self) -> Result<()> {\n        match self {\n            Self::Clear(cmd) => cmd.run(),\n            Self::Path(cmd) => cmd.run(),\n            Self::Prune(cmd) => cmd.run(),\n        }\n    }\n}\n\nimpl Cache {\n    pub fn run(self) -> Result<()> {\n        match self.command {\n            Some(cmd) => cmd.run(),\n            None => {\n                // just show the cache dir\n                miseprintln!(\"{}\", env::MISE_CACHE_DIR.display());\n                Ok(())\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/cli/cache/path.rs",
    "content": "use eyre::Result;\n\nuse crate::env;\n\n/// Show the cache directory path\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"dir\")]\npub struct CachePath {}\n\nimpl CachePath {\n    pub fn run(self) -> Result<()> {\n        miseprintln!(\"{}\", env::MISE_CACHE_DIR.display());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/cache/prune.rs",
    "content": "use crate::cache;\nuse crate::cache::{PruneOptions, PruneResults};\nuse crate::config::Settings;\nuse crate::dirs::CACHE;\nuse crate::toolset::env_cache::CachedEnv;\nuse eyre::Result;\nuse number_prefix::NumberPrefix;\nuse std::time::Duration;\n\n/// Removes stale mise cache files\n///\n/// By default, this command will remove files that have not been accessed in 30 days.\n/// Change this with the MISE_CACHE_PRUNE_AGE environment variable.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"p\")]\npub struct CachePrune {\n    /// Plugin(s) to clear cache for\n    /// e.g.: node, python\n    plugin: Option<Vec<String>>,\n\n    /// Show pruned files\n    #[clap(long, short, action = clap::ArgAction::Count)]\n    verbose: u8,\n\n    /// Just show what would be pruned\n    #[clap(long)]\n    dry_run: bool,\n}\n\nimpl CachePrune {\n    pub fn run(self) -> Result<()> {\n        let settings = Settings::get();\n        let opts = PruneOptions {\n            dry_run: self.dry_run,\n            verbose: self.verbose > 0,\n            age: settings\n                .cache_prune_age_duration()\n                .unwrap_or(Duration::from_secs(30 * 24 * 60 * 60)),\n        };\n        let mut results = PruneResults { size: 0, count: 0 };\n\n        // Prune main cache\n        let r = cache::prune(&CACHE.to_path_buf(), &opts)?;\n        results.size += r.size;\n        results.count += r.count;\n\n        // Prune env cache using env_cache_ttl\n        let env_cache_dir = CachedEnv::cache_dir();\n        if env_cache_dir.exists() {\n            let env_opts = PruneOptions {\n                dry_run: self.dry_run,\n                verbose: self.verbose > 0,\n                age: settings.env_cache_ttl(),\n            };\n            let r = cache::prune(&env_cache_dir, &env_opts)?;\n            results.size += r.size;\n            results.count += r.count;\n        }\n\n        let count = results.count;\n        let size = bytes_str(results.size);\n        info!(\"cache pruned {count} files, {size}\");\n        Ok(())\n    }\n}\n\nfn bytes_str(bytes: u64) -> String {\n    match NumberPrefix::binary(bytes as f64) {\n        NumberPrefix::Standalone(bytes) => format!(\"{bytes} bytes\"),\n        NumberPrefix::Prefixed(prefix, n) => format!(\"{n:.1} {prefix}B\"),\n    }\n}\n"
  },
  {
    "path": "src/cli/completion.rs",
    "content": "use crate::cmd::cmd;\nuse crate::config::Config;\nuse crate::toolset::ToolsetBuilder;\nuse clap::ValueEnum;\nuse clap::builder::PossibleValue;\nuse eyre::Result;\nuse strum::EnumString;\n\n/// Generate shell completions\n#[derive(Debug, clap::Args)]\n#[clap(aliases = [\"complete\", \"completions\"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Completion {\n    /// Shell type to generate completions for\n    #[clap(required_unless_present = \"shell_type\")]\n    shell: Option<Shell>,\n\n    /// Shell type to generate completions for\n    #[clap(long = \"shell\", short = 's', hide = true)]\n    shell_type: Option<Shell>,\n\n    /// Include the bash completion library in the bash completion script\n    ///\n    /// This is required for completions to work in bash, but it is not included by default\n    /// you may source it separately or enable this flag to enable it in the script.\n    #[clap(long, verbatim_doc_comment)]\n    include_bash_completion_lib: bool,\n\n    /// Always use usage for completions.\n    /// Currently, usage is the default for fish and bash but not zsh since it has a few quirks\n    /// to work out first.\n    ///\n    /// This requires the `usage` CLI to be installed.\n    /// https://usage.jdx.dev\n    #[clap(long, verbatim_doc_comment, hide = true)]\n    usage: bool,\n}\n\nimpl Completion {\n    pub async fn run(self) -> Result<()> {\n        let shell = self.shell.or(self.shell_type).unwrap();\n\n        let script = match self.call_usage(shell).await {\n            Ok(script) => script,\n            Err(e) => {\n                debug!(\"usage command failed, falling back to prerendered completions\");\n                debug!(\"error: {e:?}\");\n                self.prerendered(shell)\n            }\n        };\n        miseprintln!(\"{}\", script.trim());\n\n        Ok(())\n    }\n\n    async fn call_usage(&self, shell: Shell) -> Result<String> {\n        let config = Config::get().await?;\n        let toolset = ToolsetBuilder::new().build(&config).await?;\n        let mut args = vec![\n            \"generate\".into(),\n            \"completion\".into(),\n            shell.to_string(),\n            \"mise\".into(),\n            \"--usage-cmd\".into(),\n            \"mise usage\".into(),\n            \"--cache-key\".into(),\n            env!(\"CARGO_PKG_VERSION\").into(),\n        ];\n        if self.include_bash_completion_lib {\n            args.push(\"--include-bash-completion-lib\".into());\n        }\n        let output = cmd(\"usage\", args)\n            .full_env(toolset.full_env(&config).await?)\n            .read()?;\n        Ok(output)\n    }\n\n    fn prerendered(&self, shell: Shell) -> String {\n        match shell {\n            Shell::Bash => include_str!(\"../../completions/mise.bash\"),\n            Shell::Fish => include_str!(\"../../completions/mise.fish\"),\n            Shell::PowerShell => include_str!(\"../../completions/mise.ps1\"),\n            Shell::Zsh => include_str!(\"../../completions/_mise\"),\n        }\n        .to_string()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise completion bash --include-bash-completion-lib > ~/.local/share/bash-completion/completions/mise</bold>\n    $ <bold>mise completion zsh  > /usr/local/share/zsh/site-functions/_mise</bold>\n    $ <bold>mise completion fish > ~/.config/fish/completions/mise.fish</bold>\n    $ <bold>mise completion powershell >> $PROFILE</bold>\n\"#\n);\n\n#[derive(Debug, Clone, Copy, EnumString, strum::Display)]\n#[strum(serialize_all = \"snake_case\")]\n#[allow(clippy::enum_variant_names)] // PowerShell is a proper noun\nenum Shell {\n    Bash,\n    Fish,\n    #[strum(serialize = \"powershell\")]\n    PowerShell,\n    Zsh,\n}\n\nimpl ValueEnum for Shell {\n    fn value_variants<'a>() -> &'a [Self] {\n        &[Self::Bash, Self::Fish, Self::PowerShell, Self::Zsh]\n    }\n    fn to_possible_value(&self) -> Option<PossibleValue> {\n        Some(PossibleValue::new(self.to_string()))\n    }\n}\n"
  },
  {
    "path": "src/cli/config/get.rs",
    "content": "use crate::config::top_toml_config;\nuse crate::file::display_path;\nuse eyre::bail;\nuse std::path::PathBuf;\n\n/// Display the value of a setting in a mise.toml file\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ConfigGet {\n    /// The path of the config to display\n    pub key: Option<String>,\n\n    /// The path to the mise.toml file to edit\n    ///\n    /// If not provided, the nearest mise.toml file will be used\n    #[clap(short, long)]\n    pub file: Option<PathBuf>,\n}\n\nimpl ConfigGet {\n    pub fn run(self) -> eyre::Result<()> {\n        let mut file = self.file;\n        if file.is_none() {\n            file = top_toml_config();\n        }\n        if let Some(file) = file {\n            let content = std::fs::read_to_string(&file)?;\n            let config: toml::Value = toml::de::from_str(&content)?;\n            let mut value = &config;\n            if let Some(key) = &self.key {\n                for k in key.split('.') {\n                    value = value.get(k).ok_or_else(|| {\n                        eyre::eyre!(\"Key not found: {} in {}\", key, display_path(&file))\n                    })?;\n                }\n            }\n\n            match value {\n                toml::Value::String(s) => miseprintln!(\"{}\", s),\n                toml::Value::Integer(i) => miseprintln!(\"{}\", i),\n                toml::Value::Boolean(b) => miseprintln!(\"{}\", b),\n                toml::Value::Float(f) => miseprintln!(\"{}\", f),\n                toml::Value::Datetime(d) => miseprintln!(\"{}\", d),\n                toml::Value::Array(a) => {\n                    // seems that the toml crate does not have a way to serialize an array directly?\n                    // workaround which only handle non-nested arrays\n                    let elements: Vec<String> = a\n                        .iter()\n                        .map(|v| match v {\n                            toml::Value::String(s) => format!(\"\\\"{s}\\\"\"),\n                            toml::Value::Integer(i) => i.to_string(),\n                            toml::Value::Boolean(b) => b.to_string(),\n                            toml::Value::Float(f) => f.to_string(),\n                            toml::Value::Datetime(d) => d.to_string(),\n                            toml::Value::Array(_) => \"[...]\".to_string(),\n                            toml::Value::Table(_) => \"{...}\".to_string(),\n                        })\n                        .collect();\n                    miseprintln!(\"[{}]\", elements.join(\", \"));\n                }\n                toml::Value::Table(t) => {\n                    miseprintln!(\"{}\", toml::to_string(t)?);\n                }\n            }\n        } else {\n            bail!(\"No mise.toml file found\");\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise toml get tools.python</bold>\n    3.12\n\"#\n);\n"
  },
  {
    "path": "src/cli/config/ls.rs",
    "content": "use crate::config::Config;\nuse crate::config::config_file::ConfigFile;\nuse crate::config::tracking::Tracker;\nuse crate::file::display_path;\nuse crate::ui::table::MiseTable;\nuse comfy_table::{Attribute, Cell};\nuse eyre::Result;\nuse itertools::Itertools;\n\n/// List config files currently in use\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct ConfigLs {\n    /// Output in JSON format\n    #[clap(short = 'J', long, verbatim_doc_comment)]\n    pub json: bool,\n\n    /// Do not print table header\n    #[clap(long, alias = \"no-headers\", verbatim_doc_comment)]\n    pub no_header: bool,\n\n    /// List all tracked config files\n    #[clap(long, verbatim_doc_comment)]\n    pub tracked_configs: bool,\n}\n\nimpl ConfigLs {\n    pub async fn run(self) -> Result<()> {\n        if self.tracked_configs {\n            self.display_tracked_configs().await?;\n        } else if self.json {\n            self.display_json().await?;\n        } else {\n            self.display().await?;\n        }\n        Ok(())\n    }\n\n    async fn display(&self) -> Result<()> {\n        let config = Config::get().await?;\n        let configs = config\n            .config_files\n            .values()\n            .rev()\n            .map(|cf| cf.as_ref())\n            .collect_vec();\n        let mut table = MiseTable::new(self.no_header, &[\"Path\", \"Tools\"]);\n        for cfg in configs {\n            let ts = cfg.to_tool_request_set().unwrap();\n            let tools = ts.list_tools().into_iter().join(\", \");\n            let tools = if tools.is_empty() {\n                Cell::new(\"(none)\")\n                    .add_attribute(Attribute::Italic)\n                    .add_attribute(Attribute::Dim)\n            } else {\n                Cell::new(tools).add_attribute(Attribute::Dim)\n            };\n            table.add_row(vec![Cell::new(display_path(cfg.get_path())), tools]);\n        }\n        table.truncate(true).print()\n    }\n\n    async fn display_json(&self) -> Result<()> {\n        let array_items = Config::get()\n            .await?\n            .config_files\n            .values()\n            .map(|cf| {\n                let c: &dyn ConfigFile = cf.as_ref();\n                let mut item = serde_json::Map::new();\n                item.insert(\n                    \"path\".to_string(),\n                    serde_json::Value::String(c.get_path().to_string_lossy().to_string()),\n                );\n                let plugins = c\n                    .to_tool_request_set()\n                    .unwrap()\n                    .list_tools()\n                    .into_iter()\n                    .map(|s| serde_json::Value::String(s.to_string()))\n                    .collect::<Vec<serde_json::Value>>();\n                item.insert(\"tools\".to_string(), serde_json::Value::Array(plugins));\n\n                item\n            })\n            .collect::<serde_json::Value>();\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&array_items)?);\n        Ok(())\n    }\n\n    async fn display_tracked_configs(&self) -> Result<()> {\n        let tracked_configs = Tracker::list_all()?.into_iter().unique().sorted();\n        for path in tracked_configs {\n            println!(\"{}\", path.display());\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise config ls</bold>\n    Path                        Tools\n    ~/.config/mise/config.toml  pitchfork\n    ~/src/mise/mise.toml        actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta\n\"#\n);\n"
  },
  {
    "path": "src/cli/config/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nmod get;\nmod ls;\nmod set;\n\n/// Manage config files\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"cfg\", alias = \"toml\")]\npub struct Config {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    #[clap(flatten)]\n    pub ls: ls::ConfigLs,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Get(get::ConfigGet),\n    #[clap(visible_alias = \"list\")]\n    Ls(ls::ConfigLs),\n    Set(set::ConfigSet),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Get(cmd) => cmd.run(),\n            Self::Ls(cmd) => cmd.run().await,\n            Self::Set(cmd) => cmd.run(),\n        }\n    }\n}\n\nimpl Config {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self.command.unwrap_or(Commands::Ls(self.ls));\n\n        cmd.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/config/set.rs",
    "content": "use crate::config::config_file::mise_toml::MiseToml;\nuse crate::config::settings::{SETTINGS_META, SettingsType};\nuse crate::config::top_toml_config;\nuse crate::toml::dedup_toml_array;\nuse clap::ValueEnum;\nuse eyre::bail;\nuse std::path::PathBuf;\n\n/// Set the value of a setting in a mise.toml file\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ConfigSet {\n    /// The path of the config to display\n    pub key: String,\n\n    /// The value to set the key to (optional if provided as KEY=VALUE)\n    pub value: Option<String>,\n\n    /// The path to the mise.toml file to edit\n    ///\n    /// If not provided, the nearest mise.toml file will be used\n    #[clap(short, long)]\n    pub file: Option<PathBuf>,\n\n    #[clap(value_enum, short, long, default_value_t)]\n    pub type_: TomlValueTypes,\n}\n\n#[derive(ValueEnum, Default, Clone, Debug)]\npub enum TomlValueTypes {\n    #[default]\n    Infer,\n    #[value()]\n    String,\n    #[value()]\n    Integer,\n    #[value()]\n    Float,\n    #[value()]\n    Bool,\n    #[value()]\n    List,\n    #[value()]\n    Set,\n}\n\nimpl ConfigSet {\n    pub fn run(self) -> eyre::Result<()> {\n        let (full_key, value) = match self.value {\n            Some(v) => (self.key, v),\n            None => {\n                let (k, v) = self.key.split_once('=').ok_or_else(|| {\n                    eyre::eyre!(\n                        \"Usage: mise config set <KEY>=<VALUE> or mise config set <KEY> <VALUE>\"\n                    )\n                })?;\n                (k.to_string(), v.to_string())\n            }\n        };\n        let mut file = self.file;\n        if file.is_none() {\n            file = top_toml_config();\n        }\n        let Some(file) = file else {\n            bail!(\"No mise.toml file found\");\n        };\n        let mut config: toml_edit::DocumentMut = std::fs::read_to_string(&file)?.parse()?;\n        let mut container = config.as_item_mut();\n        let parts = full_key.split('.').collect::<Vec<&str>>();\n        let last_key = parts.last().unwrap();\n        for (idx, part) in parts.iter().take(parts.len() - 1).enumerate() {\n            container = container\n                .as_table_like_mut()\n                .unwrap()\n                .entry(part)\n                .or_insert({\n                    let mut t = toml_edit::Table::new();\n                    t.set_implicit(true);\n                    toml_edit::Item::Table(t)\n                });\n            // if the key is a tool with a simple value, we want to convert it to a inline table preserving the version\n            let is_simple_tool_version =\n                full_key.starts_with(\"tools.\") && idx == 1 && !container.is_table_like();\n            if is_simple_tool_version {\n                let mut inline_table = toml_edit::InlineTable::new();\n                inline_table.insert(\"version\", container.as_value().unwrap().clone());\n                *container = toml_edit::Item::Value(toml_edit::Value::InlineTable(inline_table));\n            }\n        }\n\n        let infer_bool_or_string = |value: &str| match value {\n            \"true\" | \"yes\" | \"1\" => TomlValueTypes::Bool,\n            \"false\" | \"no\" | \"0\" => TomlValueTypes::Bool,\n            _ => TomlValueTypes::String,\n        };\n        let type_to_use = match self.type_ {\n            TomlValueTypes::Infer => {\n                let expected_type = if !full_key.starts_with(\"settings.\") {\n                    None\n                } else {\n                    SETTINGS_META.get(*last_key)\n                };\n                match expected_type {\n                    Some(meta) => match meta.type_ {\n                        SettingsType::Bool => TomlValueTypes::Bool,\n                        SettingsType::BoolOrString => infer_bool_or_string(&value),\n                        SettingsType::String => TomlValueTypes::String,\n                        SettingsType::Integer => TomlValueTypes::Integer,\n                        SettingsType::Duration => TomlValueTypes::String,\n                        SettingsType::Path => TomlValueTypes::String,\n                        SettingsType::Url => TomlValueTypes::String,\n                        SettingsType::ListString => TomlValueTypes::List,\n                        SettingsType::ListPath => TomlValueTypes::List,\n                        SettingsType::SetString => TomlValueTypes::Set,\n                        SettingsType::IndexMap => TomlValueTypes::String,\n                    },\n                    None => infer_bool_or_string(&value),\n                }\n            }\n            _ => self.type_,\n        };\n\n        let value = match type_to_use {\n            TomlValueTypes::String => toml_edit::value(value),\n            TomlValueTypes::Integer => toml_edit::value(value.parse::<i64>()?),\n            TomlValueTypes::Float => toml_edit::value(value.parse::<f64>()?),\n            TomlValueTypes::Bool => toml_edit::value(value.parse::<bool>()?),\n            TomlValueTypes::List => {\n                let mut list = toml_edit::Array::new();\n                for item in value.split(',').map(|s| s.trim()) {\n                    list.push(item);\n                }\n                toml_edit::Item::Value(toml_edit::Value::Array(list))\n            }\n            TomlValueTypes::Set => {\n                let set = toml_edit::Array::new();\n                toml_edit::Item::Value(toml_edit::Value::Array(dedup_toml_array(&set)))\n            }\n            TomlValueTypes::Infer => bail!(\"Type not found\"),\n        };\n\n        let mut t = toml_edit::Table::new();\n        t.set_implicit(true);\n        let mut table = toml_edit::Item::Table(t);\n        container\n            .as_table_like_mut()\n            .unwrap_or_else(|| table.as_table_like_mut().unwrap())\n            .insert(last_key, value);\n\n        let raw = config.to_string();\n        MiseToml::from_str(&raw, &file)?;\n        std::fs::write(&file, raw)?;\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise config set tools.python 3.12</bold>\n    $ <bold>mise config set settings.always_keep_download true</bold>\n    $ <bold>mise config set env.TEST_ENV_VAR ABC</bold>\n    $ <bold>mise config set settings.disable_tools --type list node,rust</bold>\n\n    # Type for `settings` is inferred\n    $ <bold>mise config set settings.jobs 4</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/current.rs",
    "content": "use console::style;\nuse eyre::{Result, bail};\n\nuse crate::backend::Backend;\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::toolset::{Toolset, ToolsetBuilder};\n\n/// Shows current active and installed runtime versions\n///\n/// This is similar to `mise ls --current`, but this only shows the runtime\n/// and/or version. It's designed to fit into scripts more easily.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true, after_long_help = AFTER_LONG_HELP)]\npub struct Current {\n    /// Plugin to show versions of\n    /// e.g.: ruby, node, cargo:eza, npm:prettier, etc.\n    #[clap()]\n    plugin: Option<BackendArg>,\n}\n\nimpl Current {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let ts = ToolsetBuilder::new().build(&config).await?;\n        match &self.plugin {\n            Some(ba) => {\n                if let Some(plugin) = ba.backend()?.plugin()\n                    && !plugin.is_installed()\n                {\n                    bail!(\"Plugin {ba} is not installed\");\n                }\n                self.one(ts, ba.backend()?.as_ref()).await\n            }\n            None => self.all(ts).await,\n        }\n    }\n\n    async fn one(&self, ts: Toolset, tool: &dyn Backend) -> Result<()> {\n        if let Some(plugin) = tool.plugin()\n            && !plugin.is_installed()\n        {\n            warn!(\"Plugin {} is not installed\", tool.id());\n            return Ok(());\n        }\n        match ts\n            .list_versions_by_plugin()\n            .into_iter()\n            .find(|(p, _)| p.id() == tool.id())\n        {\n            Some((_, versions)) => {\n                miseprintln!(\n                    \"{}\",\n                    versions\n                        .iter()\n                        .map(|v| v.version.to_string())\n                        .collect::<Vec<_>>()\n                        .join(\" \")\n                );\n            }\n            None => {\n                warn!(\n                    \"Plugin {} does not have a version set\",\n                    style(tool.id()).blue().for_stderr()\n                );\n            }\n        };\n        Ok(())\n    }\n\n    async fn all(&self, ts: Toolset) -> Result<()> {\n        let config = Config::get().await?;\n        for (plugin, versions) in ts.list_versions_by_plugin() {\n            if versions.is_empty() {\n                continue;\n            }\n            for tv in versions {\n                if !plugin.is_version_installed(&config, tv, true) {\n                    let source = ts.versions.get(tv.ba()).unwrap().source.clone();\n                    warn!(\n                        \"{}@{} is specified in {}, but not installed\",\n                        &tv.ba(),\n                        &tv.version,\n                        &source\n                    );\n                    hint!(\n                        \"tools_missing\",\n                        \"install missing tools with\",\n                        \"mise install\"\n                    );\n                }\n            }\n            miseprintln!(\n                \"{} {}\",\n                &plugin.id(),\n                versions\n                    .iter()\n                    .map(|v| v.version.to_string())\n                    .collect::<Vec<_>>()\n                    .join(\" \")\n            );\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # outputs `.tool-versions` compatible format\n    $ <bold>mise current</bold>\n    python 3.11.0 3.10.0\n    shfmt 3.6.0\n    shellcheck 0.9.0\n    node 20.0.0\n\n    $ <bold>mise current node</bold>\n    20.0.0\n\n    # can output multiple versions\n    $ <bold>mise current python</bold>\n    3.11.0 3.10.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/deactivate.rs",
    "content": "use eyre::Result;\n\nuse crate::env;\nuse crate::shell::{build_deactivation_script, get_shell};\n\n/// Disable mise for current shell session\n///\n/// This can be used to temporarily disable mise in a shell session.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Deactivate {}\n\nimpl Deactivate {\n    pub fn run(self) -> Result<()> {\n        if !env::is_activated() {\n            // Deactivating when not activated is safe - just show a warning\n            warn!(\n                \"mise is not activated in this shell session. Already deactivated or never activated.\"\n            );\n            return Ok(());\n        }\n\n        let shell = get_shell(None).expect(\"no shell detected\");\n\n        let mut output = build_deactivation_script(&*shell);\n        output.push_str(&shell.unset_env(\"__MISE_ORIG_PATH\"));\n        miseprint!(\"{output}\")?;\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise deactivate</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/direnv/activate.rs",
    "content": "use eyre::Result;\nuse indoc::indoc;\n\n/// Output direnv function to use mise inside direnv\n///\n/// See https://mise.jdx.dev/direnv.html for more information\n///\n/// Because this generates the idiomatic files based on currently installed plugins,\n/// you should run this command after installing new plugins. Otherwise\n/// direnv may not know to update environment variables when idiomatic file versions change.\n#[derive(Debug, clap::Args)]\n#[clap(hide=true, verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct DirenvActivate {}\n\nimpl DirenvActivate {\n    pub async fn run(self) -> Result<()> {\n        miseprintln!(\n            //       source_env \"$(mise direnv envrc \"$@\")\"\n            indoc! {r#\"\n                ### Do not edit. This was autogenerated by 'mise direnv' ###\n                use_mise() {{\n                  direnv_load mise direnv exec\n                }}\n            \"#}\n        );\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise direnv activate > ~/.config/direnv/lib/use_mise.sh</bold>\n    $ <bold>echo 'use mise' > .envrc</bold>\n    $ <bold>direnv allow</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/direnv/envrc.rs",
    "content": "use std::io::Write;\nuse std::{fs::File, sync::Arc};\n\nuse eyre::Result;\nuse xx::file;\n\nuse crate::config::Config;\nuse crate::env;\nuse crate::env::PATH_KEY;\nuse crate::hash::hash_to_str;\nuse crate::toolset::ToolsetBuilder;\n\n/// [internal] This is an internal command that writes an envrc file\n/// for direnv to consume.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true)]\npub struct Envrc {}\n\nimpl Envrc {\n    pub async fn run(self, config: &Arc<Config>) -> Result<()> {\n        let ts = ToolsetBuilder::new().build(config).await?;\n\n        let envrc_path = env::MISE_TMP_DIR\n            .join(\"direnv\")\n            .join(hash_to_str(&env::current_dir()?) + \".envrc\");\n\n        // TODO: exit early if envrc_path exists and is up to date\n        file::mkdirp(envrc_path.parent().unwrap())?;\n        let mut file = File::create(&envrc_path)?;\n\n        writeln!(\n            file,\n            \"### Do not edit. This was autogenerated by 'asdf direnv envrc' ###\"\n        )?;\n        for cf in config.config_files.keys() {\n            writeln!(file, \"watch_file {}\", cf.to_string_lossy())?;\n        }\n        let (env, env_results) = ts.final_env(config).await?;\n        for (k, v) in env {\n            if k == *PATH_KEY {\n                writeln!(file, \"PATH_add {v}\")?;\n            } else {\n                writeln!(\n                    file,\n                    \"export {}={}\",\n                    shell_escape::unix::escape(k.into()),\n                    shell_escape::unix::escape(v.into()),\n                )?;\n            }\n        }\n        for path in ts\n            .list_final_paths(config, env_results)\n            .await?\n            .into_iter()\n            .rev()\n        {\n            writeln!(file, \"PATH_add {}\", path.to_string_lossy())?;\n        }\n\n        miseprintln!(\"{}\", envrc_path.to_string_lossy());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/direnv/exec.rs",
    "content": "use std::sync::Arc;\n\nuse duct::Expression;\nuse eyre::{Result, WrapErr};\nuse serde_derive::Deserialize;\n\nuse crate::config::Config;\nuse crate::toolset::ToolsetBuilder;\n\n/// [internal] This is an internal command that writes an envrc file\n/// for direnv to consume.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true)]\npub struct DirenvExec {}\n\n#[derive(Debug, Default, Deserialize)]\nstruct DirenvWatches {\n    #[serde(rename(deserialize = \"DIRENV_WATCHES\"))]\n    watches: String,\n}\n\nimpl DirenvExec {\n    pub async fn run(self, config: &Arc<Config>) -> Result<()> {\n        let ts = ToolsetBuilder::new().build(config).await?;\n\n        let mut cmd = env_cmd();\n\n        for (k, v) in ts.env_with_path(config).await? {\n            cmd = cmd.env(k, v);\n        }\n\n        let json = cmd!(\"direnv\", \"watch\", \"json\", \".tool-versions\")\n            .read()\n            .wrap_err(\"error running direnv watch\")?;\n        let w: DirenvWatches = serde_json::from_str(&json)?;\n        cmd = cmd.env(\"DIRENV_WATCHES\", w.watches);\n\n        miseprint!(\"{}\", cmd.read()?)?;\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nfn env_cmd() -> Expression {\n    cmd!(\"env\")\n}\n\n#[cfg(not(test))]\nfn env_cmd() -> Expression {\n    cmd!(\"direnv\", \"dump\")\n}\n"
  },
  {
    "path": "src/cli/direnv/mod.rs",
    "content": "use std::sync::Arc;\n\nuse clap::Subcommand;\nuse eyre::Result;\n\nuse crate::config::Config;\n\nmod activate;\nmod envrc;\nmod exec;\n\n/// Output direnv function to use mise inside direnv\n///\n/// See https://mise.jdx.dev/direnv.html for more information\n///\n/// Because this generates the idiomatic files based on currently installed plugins,\n/// you should run this command after installing new plugins. Otherwise\n/// direnv may not know to update environment variables when idiomatic file versions change.\n#[derive(Debug, clap::Args)]\n#[clap(hide = true, verbatim_doc_comment)]\npub struct Direnv {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Activate(activate::DirenvActivate),\n    Envrc(envrc::Envrc),\n    Exec(exec::DirenvExec),\n}\n\nimpl Commands {\n    pub async fn run(self, config: &Arc<Config>) -> Result<()> {\n        match self {\n            Self::Activate(cmd) => cmd.run().await,\n            Self::Envrc(cmd) => cmd.run(config).await,\n            Self::Exec(cmd) => cmd.run(config).await,\n        }\n    }\n}\n\nimpl Direnv {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let cmd = self\n            .command\n            .unwrap_or(Commands::Activate(activate::DirenvActivate {}));\n        cmd.run(&config).await\n    }\n}\n"
  },
  {
    "path": "src/cli/doctor/mod.rs",
    "content": "mod path;\n\nuse crate::{exit, plugins::PluginEnum};\nuse std::collections::HashSet;\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::backend::backend_type::BackendType;\nuse crate::build_time::built_info;\nuse crate::cli::self_update::SelfUpdate;\nuse crate::cli::version;\nuse crate::cli::version::VERSION;\nuse crate::config::{Config, IGNORED_CONFIG_FILES, Settings};\nuse crate::env::PATH_KEY;\nuse crate::file::display_path;\nuse crate::git::Git;\nuse crate::plugins::PluginType;\nuse crate::plugins::core::CORE_PLUGINS;\nuse crate::registry::REGISTRY;\nuse crate::toolset::install_state;\nuse crate::toolset::{ToolVersion, Toolset, ToolsetBuilder};\nuse crate::ui::{info, style};\nuse crate::{backend, dirs, duration, env, file, shims};\nuse console::{Alignment, pad_str, style};\nuse heck::ToSnakeCase;\nuse indexmap::IndexMap;\nuse indoc::formatdoc;\nuse itertools::Itertools;\nuse std::env::split_paths;\nuse std::path::{Path, PathBuf};\nuse strum::IntoEnumIterator;\n\n/// Check mise installation for possible problems\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"dr\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Doctor {\n    #[clap(subcommand)]\n    subcommand: Option<Commands>,\n    #[clap(skip)]\n    errors: Vec<String>,\n    #[clap(skip)]\n    warnings: Vec<String>,\n    #[clap(long, short = 'J')]\n    json: bool,\n}\n\n#[derive(Debug, clap::Subcommand)]\npub enum Commands {\n    Path(path::Path),\n}\n\nimpl Doctor {\n    pub async fn run(self) -> eyre::Result<()> {\n        if let Some(cmd) = self.subcommand {\n            match cmd {\n                Commands::Path(cmd) => cmd.run().await,\n            }\n        } else if self.json {\n            self.doctor_json().await\n        } else {\n            self.doctor().await\n        }\n    }\n\n    async fn doctor_json(mut self) -> crate::Result<()> {\n        let mut data: BTreeMap<String, _> = BTreeMap::new();\n        data.insert(\n            \"version\".into(),\n            serde_json::Value::String(VERSION.to_string()),\n        );\n        data.insert(\"activated\".into(), env::is_activated().into());\n        data.insert(\"shims_on_path\".into(), shims_on_path().into());\n        data.insert(\n            \"self_update_available\".into(),\n            SelfUpdate::is_available().into(),\n        );\n        // Warn about shims+activate conflict, but not when not_found_auto_install is enabled\n        // since that intentionally preserves shims for auto-install functionality\n        if env::is_activated() && shims_on_path() && !Settings::get().not_found_auto_install {\n            self.errors.push(\"shims are on PATH and mise is also activated. You should only use one of these methods.\".to_string());\n        }\n        data.insert(\n            \"build_info\".into(),\n            build_info()\n                .into_iter()\n                .map(|(k, v)| (k.to_snake_case(), v))\n                .collect(),\n        );\n\n        let shell = shell();\n        let mut shell_lines = shell.lines();\n        let mut shell = serde_json::Map::new();\n        if let Some(name) = shell_lines.next() {\n            shell.insert(\"name\".into(), name.into());\n        }\n        if let Some(version) = shell_lines.next() {\n            shell.insert(\"version\".into(), version.into());\n        }\n        data.insert(\"shell\".into(), shell.into());\n        data.insert(\n            \"dirs\".into(),\n            mise_dirs()\n                .into_iter()\n                .map(|(k, p)| (k, p.to_string_lossy().to_string()))\n                .collect(),\n        );\n        let mut aqua = serde_json::Map::new();\n        aqua.insert(\n            \"baked_in_registry_tools\".into(),\n            aqua_registry_count().into(),\n        );\n        data.insert(\"aqua\".into(), aqua.into());\n        data.insert(\"env_vars\".into(), mise_env_vars().into_iter().collect());\n        data.insert(\n            \"settings\".into(),\n            serde_json::from_str(&cmd!(&*env::MISE_BIN, \"settings\", \"-J\").read()?)?,\n        );\n\n        let config = Config::get().await?;\n        let ts = config.get_toolset().await?;\n        self.analyze_shims(&config, ts).await;\n        self.analyze_plugins();\n        self.analyze_backend_mismatches();\n        self.check_path_ordering(ts, &config).await;\n        data.insert(\n            \"paths\".into(),\n            self.paths(ts)\n                .await?\n                .into_iter()\n                .map(|p| p.to_string_lossy().to_string())\n                .collect(),\n        );\n        data.insert(\n            \"config_files\".into(),\n            config\n                .config_files\n                .keys()\n                .map(|p| p.to_string_lossy().to_string())\n                .collect(),\n        );\n        data.insert(\n            \"ignored_config_files\".into(),\n            IGNORED_CONFIG_FILES\n                .iter()\n                .map(|p| p.to_string_lossy().to_string())\n                .collect(),\n        );\n\n        let tools = ts.list_versions_by_plugin().into_iter().map(|(f, tv)| {\n            let versions: serde_json::Value = tv\n                .iter()\n                .filter(|tv| tv.request.is_os_supported())\n                .map(|tv: &ToolVersion| {\n                    let mut tool = serde_json::Map::new();\n                    match f.is_version_installed(&config, tv, true) {\n                        true => {\n                            tool.insert(\"version\".into(), tv.version.to_string().into());\n                        }\n                        false => {\n                            tool.insert(\"version\".into(), tv.version.to_string().into());\n                            tool.insert(\"missing\".into(), true.into());\n                            self.errors.push(format!(\n                                \"tool {tv} is not installed, install with `mise install`\"\n                            ));\n                        }\n                    }\n                    serde_json::Value::from(tool)\n                })\n                .collect();\n            (f.ba().to_string(), versions)\n        });\n        data.insert(\"toolset\".into(), tools.collect());\n\n        if !self.errors.is_empty() {\n            data.insert(\"errors\".into(), self.errors.clone().into_iter().collect());\n        }\n        if !self.warnings.is_empty() {\n            data.insert(\n                \"warnings\".into(),\n                self.warnings.clone().into_iter().collect(),\n            );\n        }\n\n        let out = serde_json::to_string_pretty(&data)?;\n        println!(\"{out}\");\n\n        if !self.errors.is_empty() {\n            exit(1);\n        }\n        Ok(())\n    }\n\n    async fn doctor(mut self) -> eyre::Result<()> {\n        info::inline_section(\"version\", &*VERSION)?;\n        #[cfg(unix)]\n        info::inline_section(\"activated\", yn(env::is_activated()))?;\n        info::inline_section(\"shims_on_path\", yn(shims_on_path()))?;\n        info::inline_section(\"self_update_available\", yn(SelfUpdate::is_available()))?;\n        if !SelfUpdate::is_available()\n            && let Some(instructions) = crate::cli::self_update::upgrade_instructions_text()\n        {\n            info::section(\"self_update_instructions\", instructions)?;\n        }\n        // Warn about shims+activate conflict, but not when not_found_auto_install is enabled\n        // since that intentionally preserves shims for auto-install functionality\n        if env::is_activated() && shims_on_path() && !Settings::get().not_found_auto_install {\n            self.errors.push(\"shims are on PATH and mise is also activated. You should only use one of these methods.\".to_string());\n        }\n\n        let build_info = build_info()\n            .into_iter()\n            .map(|(k, v)| format!(\"{k}: {v}\"))\n            .join(\"\\n\");\n        info::section(\"build_info\", build_info)?;\n        info::section(\"shell\", shell())?;\n        info::section(\"aqua\", aqua_registry_count_str())?;\n\n        let mise_dirs = mise_dirs()\n            .into_iter()\n            .map(|(k, p)| format!(\"{k}: {}\", display_path(p)))\n            .join(\"\\n\");\n        info::section(\"dirs\", mise_dirs)?;\n\n        match Config::get().await {\n            Ok(config) => self.analyze_config(&config).await?,\n            Err(err) => self.errors.push(format!(\"failed to load config: {err}\")),\n        }\n\n        self.analyze_plugins();\n        self.analyze_backend_mismatches();\n\n        let env_vars = mise_env_vars()\n            .into_iter()\n            .map(|(k, v)| format!(\"{k}={v}\"))\n            .join(\"\\n\");\n        if env_vars.is_empty() {\n            info::section(\"env_vars\", \"(none)\")?;\n        } else {\n            info::section(\"env_vars\", env_vars)?;\n        }\n        self.analyze_settings()?;\n\n        if let Some(latest) = version::check_for_new_version(duration::HOURLY).await {\n            version::show_latest().await;\n            self.warnings.push(format!(\n                \"new mise version {latest} available, currently on {}\",\n                *version::V\n            ));\n        }\n\n        miseprintln!();\n\n        if !self.warnings.is_empty() {\n            let warnings_plural = if self.warnings.len() == 1 { \"\" } else { \"s\" };\n            let warning_summary =\n                format!(\"{} warning{warnings_plural} found:\", self.warnings.len());\n            miseprintln!(\"{}\\n\", style(warning_summary).yellow().bold());\n            for (i, check) in self.warnings.iter().enumerate() {\n                let num = style::nyellow(format!(\"{}.\", i + 1));\n                miseprintln!(\"{num} {}\\n\", info::indent_by(check, \"   \").trim_start());\n            }\n        }\n\n        if self.errors.is_empty() {\n            miseprintln!(\"No problems found\");\n        } else {\n            let errors_plural = if self.errors.len() == 1 { \"\" } else { \"s\" };\n            let error_summary = format!(\"{} problem{errors_plural} found:\", self.errors.len());\n            miseprintln!(\"{}\\n\", style(error_summary).red().bold());\n            for (i, check) in self.errors.iter().enumerate() {\n                let num = style::nred(format!(\"{}.\", i + 1));\n                miseprintln!(\"{num} {}\\n\", info::indent_by(check, \"   \").trim_start());\n            }\n            exit(1);\n        }\n\n        Ok(())\n    }\n\n    fn analyze_settings(&mut self) -> eyre::Result<()> {\n        match cmd!(\"mise\", \"settings\").read() {\n            Ok(settings) => {\n                info::section(\"settings\", settings)?;\n            }\n            Err(err) => self.errors.push(format!(\"failed to load settings: {err}\")),\n        }\n        Ok(())\n    }\n    async fn analyze_config(&mut self, config: &Arc<Config>) -> eyre::Result<()> {\n        info::section(\"config_files\", render_config_files(config))?;\n        if IGNORED_CONFIG_FILES.is_empty() {\n            println!();\n            info::inline_section(\"ignored_config_files\", \"(none)\")?;\n        } else {\n            info::section(\n                \"ignored_config_files\",\n                IGNORED_CONFIG_FILES.iter().map(display_path).join(\"\\n\"),\n            )?;\n        }\n        info::section(\"backends\", render_backends())?;\n        info::section(\"plugins\", render_plugins())?;\n\n        for backend in backend::list() {\n            if let Some(plugin) = backend.plugin()\n                && !plugin.is_installed()\n            {\n                self.errors\n                    .push(format!(\"plugin {} is not installed\", &plugin.name()));\n                continue;\n            }\n        }\n\n        if !env::is_activated() && !shims_on_path() {\n            let shims = style::ncyan(display_path(*dirs::SHIMS));\n            if cfg!(windows) {\n                self.errors.push(formatdoc!(\n                    r#\"mise shims are not on PATH\n                    Add this directory to PATH: {shims}\"#\n                ));\n            } else {\n                let cmd = style::nyellow(\"mise help activate\");\n                let url = style::nunderline(\"https://mise.jdx.dev\");\n                self.errors.push(formatdoc!(\n                    r#\"mise is not activated, run {cmd} or\n                        read documentation at {url} for activation instructions.\n                        Alternatively, add the shims directory {shims} to PATH.\n                        Using the shims directory is preferred for non-interactive setups.\"#\n                ));\n            }\n        }\n\n        match ToolsetBuilder::new().build(config).await {\n            Ok(ts) => {\n                self.analyze_shims(config, &ts).await;\n                self.analyze_toolset(&ts).await?;\n                self.analyze_paths(&ts).await?;\n                self.check_path_ordering(&ts, config).await;\n            }\n            Err(err) => self.errors.push(format!(\"failed to load toolset: {err}\")),\n        }\n\n        Ok(())\n    }\n\n    async fn analyze_toolset(&mut self, ts: &Toolset) -> eyre::Result<()> {\n        let config = Config::get().await?;\n        let tools = ts\n            .list_current_versions()\n            .into_iter()\n            .map(|(f, tv)| match f.is_version_installed(&config, &tv, true) {\n                true => (tv.to_string(), style::nstyle(\"\")),\n                false => {\n                    self.errors.push(format!(\n                        \"tool {tv} is not installed, install with `mise install`\"\n                    ));\n                    (tv.to_string(), style::ndim(\"(missing)\"))\n                }\n            })\n            .collect_vec();\n        let max_tool_len = tools\n            .iter()\n            .map(|(t, _)| t.len())\n            .max()\n            .unwrap_or(0)\n            .min(20);\n        let tools = tools\n            .into_iter()\n            .map(|(t, s)| format!(\"{}  {s}\", pad_str(&t, max_tool_len, Alignment::Left, None)))\n            .sorted()\n            .collect::<Vec<_>>()\n            .join(\"\\n\");\n\n        info::section(\"toolset\", tools)?;\n        Ok(())\n    }\n\n    async fn analyze_shims(&mut self, config: &Arc<Config>, toolset: &Toolset) {\n        let mise_bin = file::which(\"mise\").unwrap_or(env::MISE_BIN.clone());\n\n        if let Ok((missing, extra)) = shims::get_shim_diffs(config, mise_bin, toolset).await {\n            let cmd = style::nyellow(\"mise reshim\");\n\n            if !missing.is_empty() {\n                self.errors.push(formatdoc!(\n                    \"shims are missing, run {cmd} to create them\n                     Missing shims: {missing}\",\n                    missing = missing.into_iter().join(\", \")\n                ));\n            }\n\n            if !extra.is_empty() {\n                self.errors.push(formatdoc!(\n                    \"unused shims are present, run {cmd} to remove them\n                     Unused shims: {extra}\",\n                    extra = extra.into_iter().join(\", \")\n                ));\n            }\n        }\n        time!(\"doctor::analyze_shims\");\n    }\n\n    fn analyze_plugins(&mut self) {\n        for plugin in backend::list() {\n            let is_core = CORE_PLUGINS.contains_key(plugin.id());\n            let plugin_type = plugin.get_plugin_type();\n\n            if is_core && matches!(plugin_type, Some(PluginType::Asdf | PluginType::Vfox)) {\n                self.warnings\n                    .push(format!(\"plugin {} overrides a core plugin\", &plugin.id()));\n            }\n        }\n    }\n\n    fn analyze_backend_mismatches(&mut self) {\n        for (short, ist) in install_state::list_tools().iter() {\n            // Skip plugin-based tools (they use the plugin as backend)\n            if install_state::get_plugin_type(short).is_some() {\n                continue;\n            }\n\n            // Get stored backend, skip if none\n            let Some(stored_full) = &ist.full else {\n                continue;\n            };\n\n            // Get registry entry, skip if not in registry\n            let Some(rt) = REGISTRY.get(short.as_str()) else {\n                continue;\n            };\n\n            // Get recommended backend for current platform\n            let backends = rt.backends();\n            let Some(registry_full) = backends.first() else {\n                continue;\n            };\n\n            // Strip options for comparison (e.g., \"github:repo[exe=bin]\" -> \"github:repo\")\n            let stored_stripped = stored_full.split('[').next().unwrap_or(stored_full);\n            let registry_stripped = registry_full.split('[').next().unwrap_or(registry_full);\n\n            // Compare backends\n            if stored_stripped != registry_stripped {\n                let msg = if ist.explicit_backend {\n                    formatdoc!(\n                        r#\"tool '{short}' installed with explicit backend '{stored_full}'\n                           differs from registry recommendation '{registry_full}'.\n                           To switch: mise uninstall --all {short} && mise install {short}\"#\n                    )\n                } else {\n                    formatdoc!(\n                        r#\"tool '{short}' installed with backend '{stored_full}'\n                           but registry now recommends '{registry_full}'.\n                           To migrate: mise uninstall --all {short} && mise install {short}\"#\n                    )\n                };\n                self.warnings.push(msg);\n            }\n        }\n    }\n\n    async fn paths(&mut self, ts: &Toolset) -> eyre::Result<Vec<PathBuf>> {\n        let config = Config::get().await?;\n        let env = ts.full_env(&config).await?;\n        let path = env\n            .get(&*PATH_KEY)\n            .ok_or_else(|| eyre::eyre!(\"Path not found\"))?;\n        Ok(split_paths(path).collect())\n    }\n\n    async fn analyze_paths(&mut self, ts: &Toolset) -> eyre::Result<()> {\n        let paths = self\n            .paths(ts)\n            .await?\n            .into_iter()\n            .map(display_path)\n            .join(\"\\n\");\n\n        info::section(\"path\", paths)?;\n        Ok(())\n    }\n\n    /// Check that mise tool paths appear before system paths in the current PATH.\n    /// This detects cases where shell configuration (e.g. brew, system profile) has\n    /// inserted entries before mise's paths, causing system tools to shadow mise-managed ones.\n    async fn check_path_ordering(&mut self, ts: &Toolset, config: &Arc<Config>) {\n        if !env::is_activated() {\n            return;\n        }\n\n        // Get all mise-managed paths (tool installs, env._.path, UV venv, MISE_ADD_PATH, etc.)\n        let mise_paths = match ts.final_env(config).await {\n            Ok((_env, env_results)) => match ts.list_final_paths(config, env_results).await {\n                Ok(paths) => paths,\n                Err(_) => return,\n            },\n            Err(_) => return,\n        };\n        if mise_paths.is_empty() {\n            return;\n        }\n\n        let current_path = &*env::PATH_NON_PRISTINE;\n        if current_path.is_empty() {\n            return;\n        }\n\n        let resolve = |p: &PathBuf| p.canonicalize().unwrap_or_else(|_| p.clone());\n\n        // Resolve all mise-managed paths for comparison\n        let mise_paths_resolved: HashSet<PathBuf> = mise_paths.iter().map(resolve).collect();\n\n        // Also exclude the mise binary's own directory\n        let mise_bin_parent = env::MISE_BIN.parent().and_then(|p| p.canonicalize().ok());\n\n        // Find the index of the first mise-managed path in the current PATH\n        // Note: mise_bin_parent is intentionally excluded here — it's a directory like\n        // /opt/homebrew/bin that happens to contain the mise binary, not a mise tool path.\n        // Including it would mask the exact PATH ordering issue we're trying to detect.\n        let first_mise_idx = current_path\n            .iter()\n            .position(|p| mise_paths_resolved.contains(&resolve(p)));\n\n        let Some(first_mise_idx) = first_mise_idx else {\n            // No mise paths found in current PATH at all — this is already\n            // covered by the activation check\n            return;\n        };\n\n        if first_mise_idx == 0 {\n            return;\n        }\n\n        // Everything before first_mise_idx is by definition not a mise-managed path.\n        // Filter out the mise binary's own directory (e.g. /opt/homebrew/bin) since\n        // that's not a problematic entry — it's just where mise itself is installed.\n        let paths_display = current_path[..first_mise_idx]\n            .iter()\n            .filter(|p| mise_bin_parent.as_ref().is_none_or(|bp| bp != &resolve(p)))\n            .map(display_path)\n            .join(\"\\n  \");\n\n        if paths_display.is_empty() {\n            return;\n        }\n        self.warnings.push(formatdoc!(\n            r#\"mise tool paths are not first in PATH. These paths take precedence:\n              {paths_display}\n            This may cause system-installed tools to be used instead of mise-managed versions.\n            Ensure `mise activate` runs after other PATH modifications in your shell rc file.\"#\n        ));\n    }\n}\n\nfn shims_on_path() -> bool {\n    env::PATH.contains(&dirs::SHIMS.to_path_buf())\n}\n\nfn yn(b: bool) -> String {\n    if b {\n        style(\"yes\").green().to_string()\n    } else {\n        style(\"no\").red().to_string()\n    }\n}\n\nfn mise_dirs() -> Vec<(String, &'static Path)> {\n    [\n        (\"cache\", &*dirs::CACHE),\n        (\"config\", &*dirs::CONFIG),\n        (\"data\", &*dirs::DATA),\n        (\"shims\", &*dirs::SHIMS),\n        (\"state\", &*dirs::STATE),\n    ]\n    .iter()\n    .map(|(k, v)| (k.to_string(), **v))\n    .collect()\n}\n\nfn mise_env_vars() -> Vec<(String, String)> {\n    const REDACT_KEYS: &[&str] = &[\n        \"MISE_GITHUB_TOKEN\",\n        \"MISE_GITLAB_TOKEN\",\n        \"MISE_GITHUB_ENTERPRISE_TOKEN\",\n        \"MISE_GITLAB_ENTERPRISE_TOKEN\",\n    ];\n    env::vars_safe()\n        .filter(|(k, _)| k.starts_with(\"MISE_\"))\n        .map(|(k, v)| {\n            let v = if REDACT_KEYS.contains(&k.as_str()) {\n                style::ndim(\"REDACTED\").to_string()\n            } else {\n                v\n            };\n            (k, v)\n        })\n        .collect()\n}\n\nfn render_config_files(config: &Config) -> String {\n    config\n        .config_files\n        .keys()\n        .rev()\n        .map(display_path)\n        .join(\"\\n\")\n}\n\nfn render_backends() -> String {\n    let mut s = vec![];\n    for b in BackendType::iter().filter(|b| b != &BackendType::Unknown) {\n        s.push(format!(\"{b}\"));\n    }\n    s.join(\"\\n\")\n}\n\nfn render_plugins() -> String {\n    let plugins = backend::list()\n        .into_iter()\n        .filter(|b| {\n            b.plugin()\n                .is_some_and(|p| p.is_installed() && b.get_type() == BackendType::Asdf)\n        })\n        .collect::<Vec<_>>();\n    let max_plugin_name_len = plugins\n        .iter()\n        .map(|p| p.id().len())\n        .max()\n        .unwrap_or(0)\n        .min(40);\n    plugins\n        .into_iter()\n        .filter(|b| b.plugin().is_some())\n        .map(|p| {\n            let p = p.plugin().unwrap();\n            let padded_name = pad_str(p.name(), max_plugin_name_len, Alignment::Left, None);\n            let extra = match p {\n                PluginEnum::Asdf(_) | PluginEnum::Vfox(_) | PluginEnum::VfoxBackend(_) => {\n                    let git = Git::new(dirs::PLUGINS.join(p.name()));\n                    match git.get_remote_url() {\n                        Some(url) => {\n                            let sha = git\n                                .current_sha_short()\n                                .unwrap_or_else(|_| \"(unknown)\".to_string());\n                            format!(\"{url}#{sha}\")\n                        }\n                        None => \"\".to_string(),\n                    }\n                } // TODO: PluginType::Core => \"(core)\".to_string(),\n            };\n            format!(\"{padded_name}  {}\", style::ndim(extra))\n        })\n        .collect::<Vec<_>>()\n        .join(\"\\n\")\n}\n\nfn build_info() -> IndexMap<String, &'static str> {\n    let mut s = IndexMap::new();\n    s.insert(\"Target\".into(), built_info::TARGET);\n    s.insert(\"Features\".into(), built_info::FEATURES_STR);\n    s.insert(\"Built\".into(), built_info::BUILT_TIME_UTC);\n    s.insert(\"Rust Version\".into(), built_info::RUSTC_VERSION);\n    s.insert(\"Profile\".into(), built_info::PROFILE);\n    s\n}\n\nfn shell() -> String {\n    match env::MISE_SHELL.map(|s| s.to_string()) {\n        Some(shell) => {\n            let shell_cmd = if env::SHELL.ends_with(shell.as_str()) {\n                &*env::SHELL\n            } else {\n                &shell\n            };\n            let version = cmd!(shell_cmd, \"--version\")\n                .read()\n                .unwrap_or_else(|e| format!(\"failed to get shell version: {e}\"));\n            format!(\"{shell_cmd}\\n{version}\")\n        }\n        None => \"(unknown)\".to_string(),\n    }\n}\n\nfn aqua_registry_count() -> usize {\n    aqua_registry::AQUA_STANDARD_REGISTRY_FILES.len()\n}\n\nfn aqua_registry_count_str() -> String {\n    format!(\"baked in registry tools: {}\", aqua_registry_count())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise doctor</bold>\n    [WARN] plugin node is not installed\n\"#\n);\n"
  },
  {
    "path": "src/cli/doctor/path.rs",
    "content": "use crate::Result;\nuse crate::config::Config;\nuse std::env;\n\n/// Print the current PATH entries mise is providing\n#[derive(Debug, clap::Args)]\n#[clap(alias=\"paths\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Path {\n    /// Print all entries including those not provided by mise\n    #[clap(long, short, verbatim_doc_comment)]\n    full: bool,\n}\n\nimpl Path {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let ts = config.get_toolset().await?;\n        let paths = if self.full {\n            let env = ts.env_with_path(&config).await?;\n            let path = env.get(\"PATH\").cloned().unwrap_or_default();\n            env::split_paths(&path).collect()\n        } else {\n            let (_env, env_results) = ts.final_env(&config).await?;\n            ts.list_final_paths(&config, env_results).await?\n        };\n        for path in paths {\n            println!(\"{}\", path.display());\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    Get the current PATH entries mise is providing\n    $ mise doctor path\n    /home/user/.local/share/mise/installs/node/24.0.0/bin\n    /home/user/.local/share/mise/installs/rust/1.90.0/bin\n    /home/user/.local/share/mise/installs/python/3.10.0/bin\n\"#\n);\n"
  },
  {
    "path": "src/cli/edit.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse async_trait::async_trait;\nuse clap::ValueHint;\nuse eyre::{Result, eyre};\nuse indoc::formatdoc;\nuse mise_interactive_config::{\n    BackendInfo, BackendProvider, ConfigResult, InteractiveConfig, ToolInfo, ToolProvider,\n    VersionProvider,\n};\n\nuse strum::IntoEnumIterator;\n\nuse crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::cli::version::VERSION_PLAIN;\nuse crate::config::config_file;\nuse crate::config::{Config, Settings};\nuse crate::file::display_path;\nuse crate::plugins::PluginType;\nuse crate::registry::REGISTRY;\nuse crate::toolset::install_state;\nuse crate::ui::progress_report::{ProgressIcon, SingleReport};\nuse crate::{env, file};\n\n/// Tool provider that lists tools from the mise REGISTRY\nstruct MiseToolProvider;\n\nimpl ToolProvider for MiseToolProvider {\n    fn list_tools(&self) -> Vec<ToolInfo> {\n        REGISTRY\n            .iter()\n            .map(|(name, rt)| ToolInfo {\n                name: name.to_string(),\n                description: rt.description.map(|s| s.to_string()),\n                aliases: rt.aliases.iter().map(|s| s.to_string()).collect(),\n            })\n            .collect()\n    }\n}\n\n/// Version provider that fetches latest versions from backends\nstruct MiseVersionProvider;\n\n#[async_trait]\nimpl VersionProvider for MiseVersionProvider {\n    async fn latest_version(&self, tool: &str) -> Option<String> {\n        // Create BackendArg from tool name\n        let ba = Arc::new(BackendArg::from(tool));\n\n        // Get the backend\n        let backend = ba.backend().ok()?;\n\n        // Get config\n        let config = Config::get().await.ok()?;\n\n        // Get the latest version\n        backend.latest_version(&config, None).await.ok()?\n    }\n}\n\n/// Backend provider that lists available backends\nstruct MiseBackendProvider;\n\nimpl BackendProvider for MiseBackendProvider {\n    fn list_backends(&self) -> Vec<BackendInfo> {\n        let mut backends = Vec::new();\n\n        // Add built-in backend types (skip Core, Unknown, and Vfox/VfoxBackend which are for plugins)\n        for backend_type in BackendType::iter() {\n            let (name, description) = match backend_type {\n                BackendType::Aqua => (\"aqua\", Some(\"Install tools from aquaproj registry\")),\n                BackendType::Asdf => (\"asdf\", Some(\"Install tools via asdf plugins\")),\n                BackendType::Cargo => (\"cargo\", Some(\"Install Rust packages from crates.io\")),\n                BackendType::Conda => (\"conda\", Some(\"Install packages from conda-forge\")),\n                BackendType::Dotnet => (\"dotnet\", Some(\"Install .NET tools\")),\n                BackendType::Forgejo => (\"forgejo\", Some(\"Install from Forgejo releases\")),\n                BackendType::Gem => (\"gem\", Some(\"Install Ruby gems\")),\n                BackendType::Github => (\"github\", Some(\"Install from GitHub releases\")),\n                BackendType::Gitlab => (\"gitlab\", Some(\"Install from GitLab releases\")),\n                BackendType::Go => (\"go\", Some(\"Install Go modules\")),\n                BackendType::Npm => (\"npm\", Some(\"Install npm packages globally\")),\n                BackendType::Pipx => (\"pipx\", Some(\"Install Python CLI tools\")),\n                BackendType::Spm => (\"spm\", Some(\"Install Swift packages\")),\n                BackendType::Http => (\"http\", Some(\"Download files from HTTP URLs\")),\n                BackendType::S3 => (\"s3\", Some(\"Download from S3 buckets\")),\n                BackendType::Ubi => (\"ubi\", Some(\"Universal Binary Installer\")),\n                // Skip internal/meta types\n                BackendType::Core\n                | BackendType::Vfox\n                | BackendType::VfoxBackend(_)\n                | BackendType::Unknown => continue,\n            };\n\n            // Skip experimental backends unless experimental mode is enabled\n            if backend_type.is_experimental() && !Settings::get().experimental {\n                continue;\n            }\n\n            backends.push(BackendInfo {\n                name: name.to_string(),\n                description: description.map(|s| s.to_string()),\n            });\n        }\n\n        // Add plugin-provided backends (vfox-backend plugins)\n        for (plugin_name, plugin_type) in install_state::list_plugins().iter() {\n            if *plugin_type == PluginType::VfoxBackend {\n                backends.push(BackendInfo {\n                    name: plugin_name.clone(),\n                    description: Some(format!(\"Plugin-provided backend: {}\", plugin_name)),\n                });\n            }\n        }\n\n        backends\n    }\n}\n\n/// Edit mise.toml interactively\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Edit {\n    /// Show what would be generated without writing to file\n    #[clap(long, short = 'n')]\n    dry_run: bool,\n    /// Path to the config file to create\n    #[clap(verbatim_doc_comment, value_hint = ValueHint::FilePath)]\n    path: Option<PathBuf>,\n    /// Path to a .tool-versions file to import tools from\n    #[clap(long, short, verbatim_doc_comment, value_hint = ValueHint::FilePath)]\n    tool_versions: Option<PathBuf>,\n}\n\n/// A detected tool with its source and suggested version\n#[derive(Debug, Clone)]\nstruct DetectedTool {\n    name: String,\n    version: Option<String>,\n    #[allow(dead_code)]\n    source: String,\n}\n\nimpl Edit {\n    pub async fn run(self) -> Result<()> {\n        let path = self\n            .path\n            .clone()\n            .unwrap_or_else(|| PathBuf::from(&*env::MISE_DEFAULT_CONFIG_FILENAME));\n\n        if let Some(tool_versions) = &self.tool_versions {\n            // Import from .tool-versions file\n            let doc = self.tool_versions(tool_versions).await?;\n\n            if self.dry_run {\n                info!(\"would write to {}\", display_path(&path));\n                miseprintln!(\"{doc}\");\n            } else {\n                info!(\"writing to {}\", display_path(&path));\n                file::write(&path, doc)?;\n            }\n        } else if self.should_run_interactive() {\n            // Run interactive TOML editor\n            self.interactive(&path).await?;\n        } else {\n            // Non-interactive: output default template\n            let doc = self.default();\n\n            if self.dry_run {\n                info!(\"would write to {}\", display_path(&path));\n                miseprintln!(\"{doc}\");\n            } else {\n                info!(\"writing to {}\", display_path(&path));\n                file::write(&path, doc)?;\n            }\n        }\n\n        Ok(())\n    }\n\n    fn should_run_interactive(&self) -> bool {\n        !Settings::get().yes && console::user_attended_stderr()\n    }\n\n    async fn interactive(&self, path: &Path) -> Result<()> {\n        use crate::ui::progress_report::ProgressReport;\n\n        let title = format!(\"mise {} by @jdx\", &*VERSION_PLAIN);\n\n        // Show loading spinner while setting up\n        let pr = ProgressReport::new(\"edit\".into());\n        pr.set_message(\"Loading...\".into());\n\n        // Create the interactive config editor\n        let mut editor = if path.exists() {\n            pr.set_message(\"Loading config...\".into());\n            InteractiveConfig::open(path.to_path_buf()).map_err(|e| eyre!(e))?\n        } else {\n            InteractiveConfig::new(path.to_path_buf())\n        };\n\n        editor = editor\n            .title(&title)\n            .dry_run(self.dry_run)\n            .with_tool_provider(Box::new(MiseToolProvider))\n            .with_version_provider(Box::new(MiseVersionProvider))\n            .with_backend_provider(Box::new(MiseBackendProvider));\n\n        // Auto-detect tools and add them\n        pr.set_message(\"Detecting tools...\".into());\n        let detected = detect_tools();\n        for tool in detected {\n            let version = tool.version.unwrap_or_else(|| \"latest\".to_string());\n            editor.add_tool(&tool.name, &version);\n        }\n\n        // Auto-detect prepare providers if experimental is enabled\n        if Settings::get().experimental {\n            pr.set_message(\"Detecting prepare providers...\".into());\n            let cwd = env::current_dir().unwrap_or_default();\n            let prepare_providers = crate::prepare::detect_applicable_providers(&cwd);\n            for provider in prepare_providers {\n                editor.add_prepare(&provider);\n            }\n        }\n\n        // Clear the loading spinner before starting the TUI\n        pr.finish_with_icon(\"Ready\".into(), ProgressIcon::Success);\n\n        // Run the editor (now async)\n        match editor.run().await {\n            Ok(ConfigResult::Saved(content)) => {\n                if self.dry_run {\n                    info!(\"would write to {}\", display_path(path));\n                    miseprintln!(\"{content}\");\n                } else {\n                    info!(\"saved to {}\", display_path(path));\n                }\n            }\n            Ok(ConfigResult::Cancelled) => {\n                info!(\"cancelled\");\n            }\n            Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {\n                std::process::exit(130);\n            }\n            Err(e) => return Err(eyre!(e)),\n        }\n\n        Ok(())\n    }\n\n    async fn tool_versions(&self, tool_versions: &Path) -> Result<String> {\n        let to =\n            config_file::parse_or_init(&PathBuf::from(&*env::MISE_DEFAULT_CONFIG_FILENAME)).await?;\n        let from = config_file::parse(tool_versions).await?;\n        let tools = from.to_tool_request_set()?.tools;\n        for (ba, tools) in tools {\n            to.replace_versions(&ba, tools)?;\n        }\n        to.dump()\n    }\n\n    fn default(&self) -> String {\n        formatdoc! {r#\"\n            # mise config files are hierarchical. mise will find all of the config files\n            # in all parent directories and merge them together.\n            # You might have a structure like:\n            #\n            # * ~/work/project/mise.toml   # a config file for a specific work project\n            # * ~/work/mise.toml           # a config file for projects related to work\n            # * ~/.config/mise/config.toml # the global config file\n            # * /etc/mise/config.toml      # the system config file\n            #\n            # This setup allows you to define default versions and configuration across\n            # all projects but override them for specific projects.\n\n            # [env]\n            # NODE_ENV = \"development\"\n            # mise.file = \".env\"                # load vars from a dotenv file\n            # mise.path = \"./node_modules/.bin\" # add a directory to PATH\n\n            # [tools]\n            # node = \"22\"\n            # python = \"3.12\"\n            # go = \"latest\"\n        \"#}\n    }\n}\n\n// ============================================================================\n// Tool detection\n// ============================================================================\n\nfn detect_tools() -> Vec<DetectedTool> {\n    let cwd = env::current_dir().unwrap_or_default();\n    let mut detected = Vec::new();\n    let mut seen_tools = std::collections::HashSet::new();\n\n    // Scan registry for tools with detect files\n    for (name, tool) in REGISTRY.iter() {\n        if tool.detect.is_empty() {\n            continue;\n        }\n\n        for detect_file in tool.detect.iter() {\n            let path = cwd.join(detect_file);\n            if path.exists() && !seen_tools.contains(*name) {\n                let version = extract_version(name, &path);\n                detected.push(DetectedTool {\n                    name: name.to_string(),\n                    version,\n                    source: detect_file.to_string(),\n                });\n                seen_tools.insert(*name);\n                break; // Only detect once per tool\n            }\n        }\n    }\n\n    // Sort by tool name for consistent output\n    detected.sort_by(|a, b| a.name.cmp(&b.name));\n    detected\n}\n\nfn extract_version(tool: &str, path: &Path) -> Option<String> {\n    let filename = path.file_name()?.to_str()?;\n    let content = file::read_to_string(path).ok()?;\n\n    match (tool, filename) {\n        // Node.js version from package.json engines\n        (\"node\", \"package.json\") => {\n            let json: serde_json::Value = serde_json::from_str(&content).ok()?;\n            json.get(\"engines\")\n                .and_then(|e| e.get(\"node\"))\n                .and_then(|v| v.as_str())\n                .map(|s| s.to_string())\n        }\n        // Python version from pyproject.toml\n        (\"python\", \"pyproject.toml\") => {\n            let doc: toml::Value = toml::from_str(&content).ok()?;\n            doc.get(\"project\")\n                .and_then(|p| p.get(\"requires-python\"))\n                .and_then(|v| v.as_str())\n                .map(|s| {\n                    s.trim_start_matches(|c: char| !c.is_ascii_digit())\n                        .to_string()\n                })\n                .filter(|s| !s.is_empty())\n        }\n        // Go version from go.mod\n        (\"go\", \"go.mod\") => content\n            .lines()\n            .find(|line| line.starts_with(\"go \"))\n            .map(|line| line.trim_start_matches(\"go \").trim().to_string()),\n        // Version files (simple text content)\n        (_, f) if f.starts_with('.') && f.ends_with(\"-version\") => {\n            let v = content.trim().to_string();\n            if v.is_empty() { None } else { Some(v) }\n        }\n        (_, \".nvmrc\") => {\n            let v = content.trim().to_string();\n            if v.is_empty() { None } else { Some(v) }\n        }\n        _ => None,\n    }\n}\n\npub static AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise edit</bold>             <dim># edit mise.toml interactively</dim>\n    $ <bold>mise edit .mise.toml</bold>  <dim># edit a specific file</dim>\n    $ <bold>mise edit -y</bold>          <dim># skip interactive editor</dim>\n    $ <bold>mise edit -n</bold>          <dim># preview without writing</dim>\n\"#\n);\n"
  },
  {
    "path": "src/cli/en.rs",
    "content": "use crate::cli::exec::Exec;\nuse std::path::PathBuf;\n\nuse crate::env;\n\n/// Starts a new shell with the mise environment built from the current configuration\n///\n/// This is an alternative to `mise activate` that allows you to explicitly start a mise session.\n/// It will have the tools and environment variables in the configs loaded.\n/// Note that changing directories will not update the mise environment.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct En {\n    /// Directory to start the shell in\n    #[clap(default_value = \".\", verbatim_doc_comment, value_hint = clap::ValueHint::DirPath)]\n    pub dir: PathBuf,\n\n    /// Shell to start\n    ///\n    /// Defaults to $SHELL\n    #[clap(verbatim_doc_comment, long, short = 's')]\n    pub shell: Option<String>,\n}\n\nimpl En {\n    pub async fn run(self) -> eyre::Result<()> {\n        env::set_current_dir(&self.dir)?;\n        let shell = self.shell.unwrap_or((*env::SHELL).clone());\n        let command = shell_words::split(&shell).map_err(|e| eyre::eyre!(e))?;\n\n        Exec {\n            tool: vec![],\n            raw: false,\n            jobs: None,\n            c: None,\n            command: Some(command),\n            no_prepare: false,\n            fresh_env: false,\n        }\n        .run()\n        .await\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise en .</bold>\n    $ <bold>node -v</bold>\n    v20.0.0\n\n    Skip loading bashrc:\n    $ <bold>mise en -s \"bash --norc\"</bold>\n\n    Skip loading zshrc:\n    $ <bold>mise en -s \"zsh -f\"</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/env.rs",
    "content": "use eyre::Result;\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::shell::{ShellType, get_shell};\nuse crate::toolset::{InstallOptions, Toolset, ToolsetBuilder};\nuse indexmap::IndexSet;\n\n/// Exports env vars to activate mise a single time\n///\n/// Use this if you don't want to permanently install mise. It's not necessary to\n/// use this if you have `mise activate` in your shell rc file.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"e\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Env {\n    /// Tool(s) to use\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: Vec<ToolArg>,\n\n    /// Output in dotenv format\n    #[clap(long, short = 'D', overrides_with = \"shell\")]\n    dotenv: bool,\n\n    /// Output in JSON format\n    #[clap(long, short = 'J', overrides_with = \"shell\")]\n    json: bool,\n\n    /// Shell type to generate environment variables for\n    #[clap(long, short, overrides_with = \"json\")]\n    shell: Option<ShellType>,\n\n    /// Output in JSON format with additional information (source, tool)\n    #[clap(long, overrides_with = \"shell\")]\n    json_extended: bool,\n\n    /// Only show redacted environment variables\n    #[clap(long)]\n    redacted: bool,\n\n    /// Only show values of environment variables\n    #[clap(long)]\n    values: bool,\n}\n\nimpl Env {\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .build(&config)\n            .await?;\n        let (_, missing) = ts\n            .install_missing_versions(&mut config, &InstallOptions::default())\n            .await?;\n        ts.notify_missing_versions(missing);\n\n        // Get redacted keys if needed\n        let redacted_keys = if self.redacted {\n            let env_results = config.env_results().await?;\n            let mut keys = IndexSet::new();\n            keys.extend(env_results.redactions.clone());\n            keys.extend(config.redaction_keys());\n            Some(keys)\n        } else {\n            None\n        };\n\n        if self.json {\n            self.output_json(&config, ts, &redacted_keys).await\n        } else if self.json_extended {\n            self.output_extended_json(&config, ts, &redacted_keys).await\n        } else if self.dotenv {\n            self.output_dotenv(&config, ts, &redacted_keys).await\n        } else if self.values {\n            self.output_values(&config, ts, &redacted_keys).await\n        } else {\n            self.output_shell(&config, ts, &redacted_keys).await\n        }\n    }\n\n    async fn output_json(\n        &self,\n        config: &Arc<Config>,\n        ts: Toolset,\n        redacted_keys: &Option<IndexSet<String>>,\n    ) -> Result<()> {\n        let mut env = ts.env_with_path(config).await?;\n\n        if let Some(keys) = redacted_keys {\n            env.retain(|k, _| self.should_include_key(k, keys));\n        }\n\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&env)?);\n        Ok(())\n    }\n\n    async fn output_extended_json(\n        &self,\n        config: &Arc<Config>,\n        ts: Toolset,\n        redacted_keys: &Option<IndexSet<String>>,\n    ) -> Result<()> {\n        let mut res = BTreeMap::new();\n\n        ts.env_with_path(config).await?.iter().for_each(|(k, v)| {\n            res.insert(k.to_string(), BTreeMap::from([(\"value\", v.to_string())]));\n        });\n\n        config.env_with_sources().await?.iter().for_each(|(k, v)| {\n            res.insert(\n                k.to_string(),\n                BTreeMap::from([\n                    (\"value\", v.0.to_string()),\n                    (\"source\", v.1.to_string_lossy().into_owned()),\n                ]),\n            );\n        });\n\n        let tool_map: BTreeMap<String, String> = ts\n            .list_all_versions(config)\n            .await?\n            .into_iter()\n            .map(|(b, tv)| {\n                (\n                    b.id().into(),\n                    tv.request\n                        .source()\n                        .path()\n                        .map(|p| p.to_string_lossy().into_owned())\n                        .unwrap_or_else(|| \"\".to_string()),\n                )\n            })\n            .collect();\n\n        ts.env_from_tools(config)\n            .await\n            .iter()\n            .for_each(|(name, value, tool_id)| {\n                res.insert(\n                    name.to_string(),\n                    BTreeMap::from([\n                        (\"value\", value.to_string()),\n                        (\"tool\", tool_id.to_string()),\n                        (\n                            \"source\",\n                            tool_map\n                                .get(tool_id)\n                                .cloned()\n                                .unwrap_or_else(|| \"unknown_source\".to_string()),\n                        ),\n                    ]),\n                );\n            });\n\n        if let Some(keys) = redacted_keys {\n            res.retain(|k, _| self.should_include_key(k, keys));\n        }\n\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&res)?);\n        Ok(())\n    }\n\n    async fn output_shell(\n        &self,\n        config: &Arc<Config>,\n        ts: Toolset,\n        redacted_keys: &Option<IndexSet<String>>,\n    ) -> Result<()> {\n        let default_shell = get_shell(Some(ShellType::Bash)).unwrap();\n        let shell = get_shell(self.shell).unwrap_or(default_shell);\n        let mut env = ts.env_with_path(config).await?;\n\n        if let Some(keys) = redacted_keys {\n            env.retain(|k, _| self.should_include_key(k, keys));\n        }\n\n        for (k, v) in env {\n            let k = k.to_string();\n            let v = v.to_string();\n            miseprint!(\"{}\", shell.set_env(&k, &v))?;\n        }\n        Ok(())\n    }\n\n    async fn output_dotenv(\n        &self,\n        config: &Arc<Config>,\n        ts: Toolset,\n        redacted_keys: &Option<IndexSet<String>>,\n    ) -> Result<()> {\n        let (mut env, _) = ts.final_env(config).await?;\n\n        if let Some(keys) = redacted_keys {\n            env.retain(|k, _| self.should_include_key(k, keys));\n        }\n\n        for (k, v) in env {\n            let k = k.to_string();\n            let v = v.to_string();\n            miseprint!(\"{}={}\\n\", k, v)?;\n        }\n        Ok(())\n    }\n\n    async fn output_values(\n        &self,\n        config: &Arc<Config>,\n        ts: Toolset,\n        redacted_keys: &Option<IndexSet<String>>,\n    ) -> Result<()> {\n        let mut env = ts.env_with_path(config).await?;\n\n        if let Some(keys) = redacted_keys {\n            env.retain(|k, _| self.should_include_key(k, keys));\n        }\n\n        for (_, v) in env {\n            miseprintln!(\"{}\", v);\n        }\n        Ok(())\n    }\n\n    fn should_include_key(&self, key: &str, redacted_keys: &IndexSet<String>) -> bool {\n        // Check if key matches any redaction pattern (supporting wildcards)\n        redacted_keys.iter().any(|pattern| {\n            if pattern.contains('*') {\n                // Handle wildcard patterns\n                if pattern == \"*\" {\n                    true\n                } else if let Some(prefix) = pattern.strip_suffix('*') {\n                    key.starts_with(prefix)\n                } else if let Some(suffix) = pattern.strip_prefix('*') {\n                    key.ends_with(suffix)\n                } else {\n                    // Pattern has * in the middle, not supported yet\n                    false\n                }\n            } else {\n                key == pattern\n            }\n        })\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>eval \"$(mise env -s bash)\"</bold>\n    $ <bold>eval \"$(mise env -s zsh)\"</bold>\n    $ <bold>mise env -s fish | source</bold>\n    $ <bold>execx($(mise env -s xonsh))</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/exec.rs",
    "content": "use std::collections::BTreeMap;\nuse std::ffi::OsString;\n\nuse clap::ValueHint;\nuse duct::IntoExecutablePath;\n#[cfg(not(any(test, windows)))]\nuse eyre::{Result, bail};\n#[cfg(any(test, windows))]\nuse eyre::{Result, eyre};\n\nuse crate::cli::args::ToolArg;\n#[cfg(any(test, windows))]\nuse crate::cmd;\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::prepare::{PrepareEngine, PrepareOptions};\nuse crate::toolset::env_cache::CachedEnv;\nuse crate::toolset::{InstallOptions, ResolveOptions, ToolsetBuilder};\n\n/// Execute a command with tool(s) set\n///\n/// use this to avoid modifying the shell session or running ad-hoc commands with mise tools set.\n///\n/// Tools will be loaded from mise.toml, though they can be overridden with <RUNTIME> args\n/// Note that only the plugin specified will be overridden, so if a `mise.toml` file\n/// includes \"node 20\" but you run `mise exec python@3.11`; it will still load node@20.\n///\n/// The \"--\" separates runtimes from the commands to pass along to the subprocess.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"x\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Exec {\n    /// Tool(s) to start\n    /// e.g.: node@20 python@3.10\n    #[clap(value_name = \"TOOL@VERSION\")]\n    pub tool: Vec<ToolArg>,\n\n    /// Command string to execute (same as --command)\n    #[clap(conflicts_with = \"c\", required_unless_present = \"c\", last = true)]\n    pub command: Option<Vec<String>>,\n\n    /// Command string to execute\n    #[clap(short, long = \"command\", value_hint = ValueHint::CommandString, conflicts_with = \"command\")]\n    pub c: Option<String>,\n\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    pub jobs: Option<usize>,\n\n    /// Bypass the environment cache and recompute the environment\n    #[clap(long)]\n    pub fresh_env: bool,\n\n    /// Skip automatic dependency preparation\n    #[clap(long)]\n    pub no_prepare: bool,\n\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets --jobs=1\n    #[clap(long, overrides_with = \"jobs\")]\n    pub raw: bool,\n}\n\nimpl Exec {\n    #[async_backtrace::framed]\n    pub async fn run(self) -> eyre::Result<()> {\n        // Temporarily unset cache key to force fresh env computation\n        if self.fresh_env {\n            env::reset_env_cache_key();\n        }\n\n        let mut config = Config::get().await?;\n\n        // Check if any tool arg explicitly specified @latest\n        // If so, resolve to the actual latest version from the registry (not just latest installed)\n        let has_explicit_latest = self\n            .tool\n            .iter()\n            .any(|t| t.tvr.as_ref().is_some_and(|tvr| tvr.version() == \"latest\"));\n\n        let resolve_options = if has_explicit_latest {\n            ResolveOptions {\n                latest_versions: true,\n                use_locked_version: false,\n                ..Default::default()\n            }\n        } else {\n            Default::default()\n        };\n\n        let mut ts = measure!(\"toolset\", {\n            ToolsetBuilder::new()\n                .with_args(&self.tool)\n                .with_default_to_latest(true)\n                .with_resolve_options(resolve_options.clone())\n                .build(&config)\n                .await?\n        });\n\n        let opts = InstallOptions {\n            force: false,\n            jobs: self.jobs,\n            raw: self.raw,\n            // prevent installing things in shims by checking for tty\n            // also don't autoinstall if at least 1 tool is specified\n            // in that case the user probably just wants that one tool\n            missing_args_only: !self.tool.is_empty()\n                || !Settings::get().exec_auto_install\n                || *env::__MISE_SHIM,\n            skip_auto_install: !Settings::get().exec_auto_install || !Settings::get().auto_install,\n            resolve_options,\n            ..Default::default()\n        };\n        let (_, missing) = measure!(\"install_arg_versions\", {\n            ts.install_missing_versions(&mut config, &opts).await?\n        });\n\n        // If we installed new versions for explicit @latest, re-resolve to pick up the installed versions\n        if has_explicit_latest {\n            ts.resolve_with_opts(&config, &opts.resolve_options).await?;\n        }\n\n        measure!(\"notify_if_versions_missing\", {\n            ts.notify_missing_versions(missing);\n        });\n\n        let (program, mut args) = parse_command(&env::SHELL, &self.command, &self.c);\n\n        let mut env = measure!(\"env_with_path\", { ts.env_with_path(&config).await? });\n\n        // Run auto-enabled prepare steps (unless --no-prepare)\n        if !self.no_prepare {\n            let engine = PrepareEngine::new(&config)?;\n            engine\n                .run(PrepareOptions {\n                    auto_only: true, // Only run providers with auto=true\n                    env: env.clone(),\n                    ..Default::default()\n                })\n                .await?;\n        }\n\n        // Ensure MISE_ENV is set in the spawned shell if it was specified via -E flag\n        if !env::MISE_ENV.is_empty() {\n            env.insert(\"MISE_ENV\".to_string(), env::MISE_ENV.join(\",\"));\n        }\n\n        // Ensure cache key is propagated to subprocesses for env caching\n        if Settings::get().env_cache && !self.fresh_env {\n            let key = CachedEnv::ensure_encryption_key();\n            env.insert(\"__MISE_ENV_CACHE_KEY\".to_string(), key);\n        }\n\n        if program.rsplit('/').next() == Some(\"fish\") {\n            let mut cmd = vec![];\n            for (k, v) in env.iter().filter(|(k, _)| *k != \"PATH\") {\n                cmd.push(format!(\n                    \"set -gx {} {}\",\n                    shell_escape::escape(k.into()),\n                    shell_escape::escape(v.into())\n                ));\n            }\n            // TODO: env is being calculated twice with final_env and env_with_path\n            let (_, env_results) = ts.final_env(&config).await?;\n            for p in ts.list_final_paths(&config, env_results).await? {\n                cmd.push(format!(\n                    \"fish_add_path -gm {}\",\n                    shell_escape::escape(p.to_string_lossy())\n                ));\n            }\n            args.insert(0, cmd.join(\"\\n\"));\n            args.insert(0, \"-C\".into());\n        }\n\n        time!(\"exec\");\n        exec_program(program, args, env)\n    }\n}\n\n#[cfg(all(not(test), unix))]\npub fn exec_program<T, U>(program: T, args: U, env: BTreeMap<String, String>) -> Result<()>\nwhere\n    T: IntoExecutablePath,\n    U: IntoIterator,\n    U::Item: Into<OsString>,\n{\n    for (k, v) in env.iter() {\n        env::set_var(k, v);\n    }\n    let args = args.into_iter().map(Into::into).collect::<Vec<_>>();\n    let program = program.to_executable();\n    let program = if program.to_string_lossy().contains('/') {\n        // Already a path, no need to resolve\n        program\n    } else {\n        let cwd = crate::dirs::CWD.clone().unwrap_or_default();\n        let lookup_path = env.get(&*env::PATH_KEY).map(|path_val| {\n            // For program resolution, reorder PATH so that paths added by mise\n            // (tool bins, _.path entries) come before paths from the original\n            // system PATH. This prevents wrapper scripts in the system PATH\n            // (e.g. .devcontainer/bin/tool) from being found before the real\n            // tool binary, which would cause infinite recursion and E2BIG.\n            //\n            // User-configured paths (_.path/venv) maintain their position\n            // relative to tool paths since both are \"mise-added\".\n            // The child process still inherits the full unmodified PATH.\n            let shims_dir = &*crate::dirs::SHIMS;\n            let pristine: std::collections::HashSet<_> = crate::env::PATH.iter().collect();\n            let all_paths: Vec<_> = std::env::split_paths(&OsString::from(path_val)).collect();\n            // Mise-added paths first (preserving relative order)\n            let mise_added: Vec<_> = all_paths\n                .iter()\n                .filter(|p| !pristine.contains(p))\n                .cloned()\n                .collect();\n            // Then original system paths (minus shims)\n            let original: Vec<_> = all_paths\n                .iter()\n                .filter(|p| pristine.contains(p) && *p != shims_dir)\n                .cloned()\n                .collect();\n            std::env::join_paths(mise_added.iter().chain(original.iter())).unwrap()\n        });\n        match which::which_in(&program, lookup_path, cwd) {\n            Ok(resolved) => resolved.into_os_string(),\n            Err(_) => program, // Fall back to original if resolution fails\n        }\n    };\n    let err = exec::Command::new(program.clone()).args(&args).exec();\n    bail!(\"{:?} {err}\", program.to_string_lossy())\n}\n\n#[cfg(all(windows, not(test)))]\npub fn exec_program<T, U>(program: T, args: U, env: BTreeMap<String, String>) -> Result<()>\nwhere\n    T: IntoExecutablePath,\n    U: IntoIterator,\n    U::Item: Into<OsString>,\n{\n    for (k, v) in env.iter() {\n        env::set_var(k, v);\n    }\n    let cwd = crate::dirs::CWD.clone().unwrap_or_default();\n    let program = program.to_executable();\n    // Reorder PATH for program resolution: mise-added paths first, then\n    // original system paths (minus shims). See Unix version for full rationale.\n    let lookup_path = env.get(&*env::PATH_KEY).map(|path_val| {\n        let shims_normalized = crate::dirs::SHIMS\n            .to_string_lossy()\n            .to_lowercase()\n            .replace('/', \"\\\\\");\n        let is_shims = |p: &std::path::PathBuf| {\n            let expanded = crate::file::replace_path(p);\n            expanded.to_string_lossy().to_lowercase().replace('/', \"\\\\\") == shims_normalized\n        };\n        let pristine: std::collections::HashSet<_> = crate::env::PATH\n            .iter()\n            .map(|p| {\n                crate::file::replace_path(p)\n                    .to_string_lossy()\n                    .to_lowercase()\n                    .replace('/', \"\\\\\")\n            })\n            .collect();\n        let all_paths: Vec<_> = std::env::split_paths(&OsString::from(path_val)).collect();\n        let mise_added: Vec<_> = all_paths\n            .iter()\n            .filter(|p| {\n                let normalized = crate::file::replace_path(p)\n                    .to_string_lossy()\n                    .to_lowercase()\n                    .replace('/', \"\\\\\");\n                !pristine.contains(&normalized)\n            })\n            .cloned()\n            .collect();\n        let original: Vec<_> = all_paths\n            .iter()\n            .filter(|p| {\n                let normalized = crate::file::replace_path(p)\n                    .to_string_lossy()\n                    .to_lowercase()\n                    .replace('/', \"\\\\\");\n                pristine.contains(&normalized) && !is_shims(p)\n            })\n            .cloned()\n            .collect();\n        std::env::join_paths(mise_added.iter().chain(original.iter())).unwrap()\n    });\n    let program = which::which_in(program, lookup_path, cwd)?;\n    let cmd = cmd::cmd(program, args);\n\n    // Windows does not support exec in the same way as Unix,\n    // so we emulate it instead by not handling Ctrl-C and letting\n    // the child process deal with it instead.\n    win_exec::set_ctrlc_handler()?;\n\n    let res = cmd.unchecked().run()?;\n    match res.status.code() {\n        Some(code) => {\n            std::process::exit(code);\n        }\n        None => Err(eyre!(\"command failed: terminated by signal\")),\n    }\n}\n\n#[cfg(test)]\npub fn exec_program<T, U>(program: T, args: U, env: BTreeMap<String, String>) -> Result<()>\nwhere\n    T: IntoExecutablePath,\n    U: IntoIterator,\n    U::Item: Into<OsString>,\n{\n    let mut cmd = cmd::cmd(program, args);\n    for (k, v) in env.iter() {\n        cmd = cmd.env(k, v);\n    }\n    let res = cmd.unchecked().run()?;\n    match res.status.code() {\n        Some(0) => Ok(()),\n        Some(code) => Err(eyre!(\"command failed: exit code {}\", code)),\n        None => Err(eyre!(\"command failed: terminated by signal\")),\n    }\n}\n\n#[cfg(all(windows, not(test)))]\nmod win_exec {\n    use eyre::{Result, eyre};\n    use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};\n    use winapi::um::consoleapi::SetConsoleCtrlHandler;\n    // Windows way of creating a process is to just go ahead and pop a new process\n    // with given program and args into existence. But in unix-land, it instead happens\n    // in a two-step process where you first fork the process and then exec the new program,\n    // essentially replacing the current process with the new one.\n    // We use Windows API to set a Ctrl-C handler that does nothing, essentially attempting\n    // to emulate the ctrl-c behavior by not handling it ourselves, and propagating it to\n    // the child process to handle it instead.\n    // This is the same way cargo does it in cargo run.\n    unsafe extern \"system\" fn ctrlc_handler(_: DWORD) -> BOOL {\n        // This is a no-op handler to prevent Ctrl-C from terminating the process.\n        // It allows the child process to handle Ctrl-C instead.\n        TRUE\n    }\n\n    pub(super) fn set_ctrlc_handler() -> Result<()> {\n        if unsafe { SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) } == FALSE {\n            Err(eyre!(\"Could not set Ctrl-C handler.\"))\n        } else {\n            Ok(())\n        }\n    }\n}\n\nfn parse_command(\n    shell: &str,\n    command: &Option<Vec<String>>,\n    c: &Option<String>,\n) -> (String, Vec<String>) {\n    match (&command, &c) {\n        (Some(command), _) => {\n            let (program, args) = command.split_first().unwrap();\n            (program.clone(), args.into())\n        }\n        _ => (\n            shell.into(),\n            vec![env::SHELL_COMMAND_FLAG.into(), c.clone().unwrap()],\n        ),\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise exec node@20 -- node ./app.js</bold>  # launch app.js using node-20.x\n    $ <bold>mise x node@20 -- node ./app.js</bold>     # shorter alias\n\n    # Specify command as a string:\n    $ <bold>mise exec node@20 python@3.11 --command \"node -v && python -V\"</bold>\n\n    # Run a command in a different directory:\n    $ <bold>mise x -C /path/to/project node@20 -- node ./app.js</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/external.rs",
    "content": "use clap::Command;\nuse eyre::Result;\nuse std::collections::HashMap;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::backend;\nuse crate::cli::args::BackendArg;\n\npub static COMMANDS: Lazy<HashMap<String, Command>> = Lazy::new(|| {\n    backend::list()\n        .into_iter()\n        .flat_map(|b| {\n            if let Some(p) = b.plugin() {\n                return p.external_commands().unwrap_or_else(|e| {\n                    let p = p.name();\n                    warn!(\"failed to load external commands for plugin {p}: {e:#}\");\n                    vec![]\n                });\n            }\n            vec![]\n        })\n        .map(|cmd| (cmd.get_name().to_string(), cmd))\n        .collect()\n});\n\npub fn execute(ba: &BackendArg, mut cmd: Command, args: Vec<String>) -> Result<()> {\n    if let Some(subcommand) = cmd.find_subcommand(&args[0]) {\n        let backend = ba.backend()?;\n        if let Some(p) = backend.plugin() {\n            p.execute_external_command(subcommand.get_name(), args)?;\n        }\n    } else {\n        cmd.print_help().unwrap();\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "src/cli/fmt.rs",
    "content": "use crate::Result;\nuse crate::config::ALL_TOML_CONFIG_FILES;\nuse crate::{config, dirs, file};\nuse eyre::bail;\nuse std::io::{self, Read, Write};\nuse taplo::formatter::Options;\n\n/// Formats mise.toml\n///\n/// Sorts keys and cleans up whitespace in mise.toml\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Fmt {\n    /// Format all files from the current directory\n    #[clap(short, long)]\n    pub all: bool,\n\n    /// Check if the configs are formatted, no formatting is done\n    #[clap(short, long)]\n    pub check: bool,\n\n    /// Read config from stdin and write its formatted version into\n    /// stdout\n    #[clap(short, long)]\n    pub stdin: bool,\n}\n\nimpl Fmt {\n    pub fn run(self) -> eyre::Result<()> {\n        if self.stdin {\n            let mut toml = String::new();\n            io::stdin().read_to_string(&mut toml)?;\n\n            let toml = sort(toml)?;\n            let toml = format(toml)?;\n            let mut stdout = io::stdout();\n            write!(stdout, \"{toml}\")?;\n\n            return Ok(());\n        }\n\n        let cwd = dirs::CWD.clone().unwrap_or_default();\n        let configs = if self.all {\n            ALL_TOML_CONFIG_FILES.clone()\n        } else {\n            config::config_files_in_dir(&cwd)\n        };\n        if configs.is_empty() {\n            bail!(\"No config file found in current directory\");\n        }\n        let mut errors = Vec::new();\n        for p in configs {\n            if !p\n                .file_name()\n                .is_some_and(|f| f.to_string_lossy().ends_with(\"toml\"))\n            {\n                continue;\n            }\n            let source = file::read_to_string(&p)?;\n            let toml = source.clone();\n            let toml = sort(toml)?;\n            let toml = format(toml)?;\n            if self.check {\n                if source != toml {\n                    errors.push(p.display().to_string());\n                }\n                continue;\n            }\n            file::write(&p, &toml)?;\n        }\n\n        if !errors.is_empty() {\n            bail!(\n                \"Following config files are not properly formatted:\\n{}\",\n                errors.join(\"\\n\")\n            );\n        }\n\n        Ok(())\n    }\n}\n\nfn sort(toml: String) -> Result<String> {\n    let mut doc: toml_edit::DocumentMut = toml.parse()?;\n    let order = |k: String| match k.as_str() {\n        \"min_version\" => 0,\n        \"env_file\" => 1,\n        \"env_path\" => 2,\n        \"_\" => 3,\n        \"env\" => 4,\n        \"vars\" => 5,\n        \"hooks\" => 6,\n        \"watch_files\" => 7,\n        \"tools\" => 8,\n        \"tasks\" => 10,\n        \"task_config\" => 11,\n        \"redactions\" => 12,\n        \"alias\" => 13,\n        \"plugins\" => 14,\n        \"settings\" => 15,\n        _ => 9,\n    };\n    doc.sort_values_by(|a, _, b, _| order(a.to_string()).cmp(&order(b.to_string())));\n    Ok(doc.to_string())\n}\n\nfn format(toml: String) -> Result<String> {\n    let tmp = taplo::formatter::format(\n        &toml,\n        Options {\n            align_comments: true,\n            align_entries: false,\n            align_single_comments: true,\n            allowed_blank_lines: 2,\n            array_auto_collapse: true,\n            array_auto_expand: true,\n            array_trailing_comma: true,\n            column_width: 80,\n            compact_arrays: true,\n            compact_entries: false,\n            compact_inline_tables: false,\n            crlf: false,\n            indent_entries: false,\n            indent_string: \"  \".to_string(),\n            indent_tables: false,\n            inline_table_expand: true,\n            reorder_arrays: false,\n            reorder_keys: false,\n            reorder_inline_tables: false,\n            trailing_newline: true,\n        },\n    );\n\n    Ok(tmp)\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise fmt</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/bootstrap.rs",
    "content": "use crate::http::HTTP;\nuse crate::ui::info;\nuse crate::{Result, file, minisign};\nuse clap::ValueHint;\nuse std::path::PathBuf;\nuse xx::file::display_path;\nuse xx::regex;\n\n/// Generate a script to download+execute mise\n///\n/// This is designed to be used in a project where contributors may not have mise installed.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Bootstrap {\n    /// Sandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\n    ///\n    /// This is necessary if users may use a different version of mise outside the project.\n    #[clap(long, short, verbatim_doc_comment)]\n    localize: bool,\n    /// Specify mise version to fetch\n    #[clap(long, short = 'V', verbatim_doc_comment)]\n    version: Option<String>,\n    /// instead of outputting the script to stdout, write to a file and make it executable\n    #[clap(long, short, verbatim_doc_comment, num_args=0..=1, default_missing_value = \"./bin/mise\")]\n    write: Option<PathBuf>,\n    /// Directory to put localized data into\n    #[clap(long, verbatim_doc_comment, default_value=\".mise\", value_hint=ValueHint::DirPath)]\n    localized_dir: PathBuf,\n}\n\nimpl Bootstrap {\n    pub async fn run(self) -> eyre::Result<()> {\n        let output = self.generate().await?;\n        if let Some(bin) = &self.write {\n            if let Some(parent) = bin.parent() {\n                file::create_dir_all(parent)?;\n            }\n            file::write(bin, &output)?;\n            file::make_executable(bin)?;\n            miseprintln!(\"Wrote to {}\", display_path(bin));\n        } else {\n            miseprintln!(\"{output}\");\n        }\n        Ok(())\n    }\n\n    async fn generate(&self) -> Result<String> {\n        let url = if let Some(v) = &self.version {\n            format!(\"https://mise.jdx.dev/v{v}/install.sh\")\n        } else {\n            \"https://mise.jdx.dev/install.sh\".into()\n        };\n        let install = HTTP.get_text(&url).await?;\n        let install_sig = HTTP.get_text(format!(\"{url}.minisig\")).await?;\n        minisign::verify(&minisign::MISE_PUB_KEY, install.as_bytes(), &install_sig)?;\n        let install = info::indent_by(install, \"        \");\n        let version = regex!(r#\"version=\"\\$\\{MISE_VERSION:-v([0-9.]+)\\}\"\"#)\n            .captures(&install)\n            .unwrap()\n            .get(1)\n            .unwrap()\n            .as_str();\n\n        let vars = if self.localize {\n            // TODO: this will only work right if it is in the base directory, not an absolute path or has a subdirectory\n            let localized_dir = self.localized_dir.to_string_lossy();\n            format!(\n                r#\"\nlocal project_dir=$( cd -- \"$( dirname -- \"${{BASH_SOURCE[0]}}\" )\" &> /dev/null && cd .. && pwd )\nlocal localized_dir=\"$project_dir/{localized_dir}\"\nexport MISE_DATA_DIR=\"$localized_dir\"\nexport MISE_CONFIG_DIR=\"$localized_dir\"\nexport MISE_CACHE_DIR=\"$localized_dir/cache\"\nexport MISE_STATE_DIR=\"$localized_dir/state\"\nexport MISE_INSTALL_PATH=\"$localized_dir/mise-{version}\"\nexport MISE_TRUSTED_CONFIG_PATHS=\"$project_dir${{MISE_TRUSTED_CONFIG_PATHS:+:$MISE_TRUSTED_CONFIG_PATHS}}\"\nexport MISE_IGNORED_CONFIG_PATHS=\"$HOME/.config/mise${{MISE_IGNORED_CONFIG_PATHS:+:$MISE_IGNORED_CONFIG_PATHS}}\"\n\"#\n            )\n        } else {\n            format!(\n                r#\"\nlocal cache_home=\"${{XDG_CACHE_HOME:-$HOME/.cache}}/mise\"\nexport MISE_INSTALL_PATH=\"$cache_home/mise-{version}\"\n\"#\n            )\n        };\n        let vars = info::indent_by(vars.trim(), \"    \");\n        let script = format!(\n            r#\"\n#!/usr/bin/env bash\nset -eu\n\n__mise_bootstrap() {{\n{vars}\n    install() {{\n        local initial_working_dir=\"$PWD\"\n{install}\n        cd -- \"$initial_working_dir\"\n    }}\n    local MISE_INSTALL_HELP=0\n    test -f \"$MISE_INSTALL_PATH\" || install\n}}\n__mise_bootstrap\nexec \"$MISE_INSTALL_PATH\" \"$@\"\n\"#\n        );\n        Ok(script.trim().to_string())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise generate bootstrap >./bin/mise</bold>\n    $ <bold>chmod +x ./bin/mise</bold>\n    $ <bold>./bin/mise install</bold> – automatically downloads mise to .mise if not already installed\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/config.rs",
    "content": "use crate::Result;\nuse crate::cli::edit;\n\n/// Generate a mise.toml file\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = edit::AFTER_LONG_HELP)]\npub struct Config {\n    #[clap(flatten)]\n    edit: edit::Edit,\n}\n\nimpl Config {\n    pub async fn run(self) -> Result<()> {\n        self.edit.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/generate/devcontainer.rs",
    "content": "use std::collections::HashMap;\n\nuse crate::{\n    dirs,\n    file::{self, display_path},\n    git::Git,\n};\nuse serde::Serialize;\n\n/// Generate a devcontainer to execute mise\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Devcontainer {\n    /// The image to use for the devcontainer\n    #[clap(long, short, verbatim_doc_comment)]\n    image: Option<String>,\n\n    /// Bind the mise-data-volume to the devcontainer\n    #[clap(long, short, verbatim_doc_comment)]\n    mount_mise_data: bool,\n\n    /// The name of the devcontainer\n    #[clap(long, short, verbatim_doc_comment)]\n    name: Option<String>,\n\n    /// write to .devcontainer/devcontainer.json\n    #[clap(long, short)]\n    write: bool,\n}\n\n#[derive(Serialize)]\nstruct DevcontainerTemplate {\n    name: String,\n    image: String,\n    features: HashMap<String, HashMap<String, String>>,\n    customizations: HashMap<String, HashMap<String, Vec<String>>>,\n    mounts: Vec<DevcontainerMount>,\n    #[serde(rename = \"containerEnv\")]\n    container_env: HashMap<String, String>,\n    #[serde(rename = \"remoteEnv\")]\n    remote_env: HashMap<String, String>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    #[serde(rename = \"postCreateCommand\")]\n    post_create_command: Option<String>,\n}\n\n#[derive(Serialize)]\nstruct DevcontainerMount {\n    source: String,\n    target: String,\n    #[serde(rename = \"type\")]\n    type_field: String,\n}\n\nimpl Devcontainer {\n    pub async fn run(self) -> eyre::Result<()> {\n        let output = self.generate()?;\n\n        if self.write {\n            let path = match Git::get_root() {\n                Ok(root) => root.join(\".devcontainer/devcontainer.json\"),\n                Err(_) => dirs::CWD\n                    .as_ref()\n                    .unwrap()\n                    .join(\".devcontainer/devcontainer.json\"),\n            };\n            file::create(&path)?;\n            file::write(&path, &output)?;\n            miseprintln!(\"Wrote to {}\", display_path(&path));\n        } else {\n            miseprintln!(\"{output}\");\n        }\n\n        Ok(())\n    }\n\n    fn generate(&self) -> eyre::Result<String> {\n        let name = self.name.as_deref().unwrap_or(\"mise\");\n        let image = self\n            .image\n            .as_deref()\n            .unwrap_or(\"mcr.microsoft.com/devcontainers/base:ubuntu\");\n\n        let mut post_create_command: Option<String> = None;\n        let mut mounts = vec![];\n        let mut container_env = HashMap::new();\n        let mut remote_env = HashMap::new();\n        if self.mount_mise_data {\n            mounts.push(DevcontainerMount {\n                source: \"mise-data-volume\".to_string(),\n                target: \"/mnt/mise-data\".to_string(),\n                type_field: \"volume\".to_string(),\n            });\n            container_env.insert(\"MISE_DATA_DIR\".to_string(), \"/mnt/mise-data\".to_string());\n            remote_env.insert(\n                \"PATH\".to_string(),\n                \"${containerEnv:PATH}:/mnt/mise-data/shims\".to_string(),\n            );\n            post_create_command = Some(\"sudo chown -R vscode:vscode /mnt/mise-data\".to_string());\n        }\n\n        let mut features = HashMap::new();\n        features.insert(\n            \"ghcr.io/devcontainers-extra/features/mise:1\".to_string(),\n            HashMap::new(),\n        );\n\n        let mut customizations = HashMap::new();\n        let mut extensions = HashMap::new();\n\n        extensions.insert(\n            \"extensions\".to_string(),\n            vec![\"hverlin.mise-vscode\".to_string()],\n        );\n\n        customizations.insert(\"vscode\".to_string(), extensions);\n\n        let template = DevcontainerTemplate {\n            name: name.to_string(),\n            image: image.to_string(),\n            features,\n            customizations,\n            mounts,\n            container_env,\n            remote_env,\n            post_create_command,\n        };\n\n        let output = serde_json::to_string_pretty(&template)?;\n\n        Ok(output)\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise generate devcontainer</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/git_pre_commit.rs",
    "content": "use xx::file::display_path;\n\nuse crate::file;\nuse crate::git::Git;\n\n/// Generate a git pre-commit hook\n///\n/// This command generates a git pre-commit hook that runs a mise task like `mise run pre-commit`\n/// when you commit changes to your repository.\n///\n/// Staged files are passed to the task as `STAGED`.\n///\n/// For more advanced pre-commit functionality, see mise's sister project: https://hk.jdx.dev/\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"pre-commit\", after_long_help = AFTER_LONG_HELP)]\npub struct GitPreCommit {\n    /// The task to run when the pre-commit hook is triggered\n    #[clap(long, short, default_value = \"pre-commit\")]\n    task: String,\n    /// write to .git/hooks/pre-commit and make it executable\n    #[clap(long, short)]\n    write: bool,\n    /// Which hook to generate (saves to .git/hooks/$hook)\n    #[clap(long, default_value = \"pre-commit\")]\n    hook: String,\n}\n\nimpl GitPreCommit {\n    pub async fn run(self) -> eyre::Result<()> {\n        let output = self.generate();\n        if self.write {\n            let path = Git::get_root()?.join(\".git/hooks\").join(&self.hook);\n            if path.exists() {\n                let old_path = path.with_extension(\"old\");\n                miseprintln!(\n                    \"Moving existing hook to {:?}\",\n                    old_path.file_name().unwrap()\n                );\n                file::rename(&path, path.with_extension(\"old\"))?;\n            }\n            file::write(&path, &output)?;\n            file::make_executable(&path)?;\n            miseprintln!(\"Wrote to {}\", display_path(&path));\n        } else {\n            miseprintln!(\"{output}\");\n        }\n        Ok(())\n    }\n\n    fn generate(&self) -> String {\n        let task = &self.task;\n        format!(\n            r#\"#!/bin/sh\nSTAGED=\"$(git diff-index --cached --name-only -z HEAD | xargs -0)\"\nexport STAGED\nexport MISE_PRE_COMMIT=1\nexec mise run {task}\n\"#\n        )\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise generate git-pre-commit --write --task=pre-commit</bold>\n    $ <bold>git commit -m \"feat: add new feature\"</bold> <dim># runs `mise run pre-commit`</dim>\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/github_action.rs",
    "content": "use xx::file;\n\nuse crate::file::display_path;\nuse crate::git::Git;\n\n/// Generate a GitHub Action workflow file\n///\n/// This command generates a GitHub Action workflow file that runs a mise task like `mise run ci`\n/// when you push changes to your repository.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct GithubAction {\n    /// The task to run when the workflow is triggered\n    #[clap(long, short, default_value = \"ci\")]\n    task: String,\n    /// write to .github/workflows/$name.yml\n    #[clap(long, short)]\n    write: bool,\n    /// the name of the workflow to generate\n    #[clap(long, default_value = \"ci\")]\n    name: String,\n}\n\nimpl GithubAction {\n    pub async fn run(self) -> eyre::Result<()> {\n        let output = self.generate()?;\n        if self.write {\n            let path = Git::get_root()?\n                .join(\".github/workflows\")\n                .join(format!(\"{}.yml\", &self.name));\n            file::write(&path, &output)?;\n            miseprintln!(\"Wrote to {}\", display_path(&path));\n        } else {\n            miseprintln!(\"{output}\");\n        }\n        Ok(())\n    }\n\n    fn generate(&self) -> eyre::Result<String> {\n        let branch = Git::new(Git::get_root()?).current_branch()?;\n        let name = &self.name;\n        let task = &self.task;\n        Ok(format!(\n            r#\"name: {name}\n\non:\n  workflow_dispatch:\n  pull_request:\n  push:\n    tags: [\"*\"]\n    branches: [\"{branch}\"]\n\nconcurrency:\n  group: ${{{{ github.workflow }}}}-${{{{ github.ref }}}}\n  cancel-in-progress: true\n\nenv:\n  MISE_EXPERIMENTAL: true\n\njobs:\n  {name}:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v6\n      - uses: jdx/mise-action@v3\n      - run: mise run {task}\n\"#\n        ))\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise generate github-action --write --task=ci</bold>\n    $ <bold>git commit -m \"feat: add new feature\"</bold>\n    $ <bold>git push</bold> <dim># runs `mise run ci` on GitHub</dim>\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/mod.rs",
    "content": "use clap::Subcommand;\n\nmod bootstrap;\nmod config;\nmod devcontainer;\nmod git_pre_commit;\nmod github_action;\nmod task_docs;\nmod task_stubs;\nmod tool_stub;\n\n/// Generate files for various tools/services\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"gen\", alias = \"g\")]\npub struct Generate {\n    #[clap(subcommand)]\n    command: Commands,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Bootstrap(bootstrap::Bootstrap),\n    Config(config::Config),\n    Devcontainer(devcontainer::Devcontainer),\n    GitPreCommit(git_pre_commit::GitPreCommit),\n    GithubAction(github_action::GithubAction),\n    TaskDocs(task_docs::TaskDocs),\n    TaskStubs(task_stubs::TaskStubs),\n    ToolStub(tool_stub::ToolStub),\n}\n\nimpl Commands {\n    pub async fn run(self) -> eyre::Result<()> {\n        match self {\n            Self::Bootstrap(cmd) => cmd.run().await,\n            Self::Config(cmd) => cmd.run().await,\n            Self::Devcontainer(cmd) => cmd.run().await,\n            Self::GitPreCommit(cmd) => cmd.run().await,\n            Self::GithubAction(cmd) => cmd.run().await,\n            Self::TaskDocs(cmd) => cmd.run().await,\n            Self::TaskStubs(cmd) => cmd.run().await,\n            Self::ToolStub(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl Generate {\n    pub async fn run(self) -> eyre::Result<()> {\n        self.command.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/generate/task_docs.rs",
    "content": "use crate::config::{self, Config, Settings};\nuse crate::{dirs, file};\nuse indexmap::IndexMap;\nuse std::path::PathBuf;\n\n/// Generate documentation for tasks in a project\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TaskDocs {\n    /// inserts the documentation into an existing file\n    ///\n    /// This will look for a special comment, `<!-- mise-tasks -->`, and replace it with the generated documentation.\n    /// It will replace everything between the comment and the next comment, `<!-- /mise-tasks -->` so it can be\n    /// run multiple times on the same file to update the documentation.\n    #[clap(long, short, verbatim_doc_comment)]\n    inject: bool,\n    /// write only an index of tasks, intended for use with `--multi`\n    #[clap(long, short = 'I', verbatim_doc_comment)]\n    index: bool,\n    /// render each task as a separate document, requires `--output` to be a directory\n    #[clap(long, short, verbatim_doc_comment)]\n    multi: bool,\n    /// writes the generated docs to a file/directory\n    #[clap(long, short, verbatim_doc_comment)]\n    output: Option<PathBuf>,\n    /// root directory to search for tasks\n    #[clap(long, short, verbatim_doc_comment, value_hint = clap::ValueHint::DirPath)]\n    root: Option<PathBuf>,\n    #[clap(long, short, verbatim_doc_comment, value_enum, default_value_t)]\n    style: TaskDocsStyle,\n}\n\n#[derive(Debug, Default, Clone, clap::ValueEnum)]\nenum TaskDocsStyle {\n    #[default]\n    #[value()]\n    Simple,\n    #[value()]\n    Detailed,\n}\n\nimpl TaskDocs {\n    pub async fn run(self) -> eyre::Result<()> {\n        let config = Config::get().await?;\n        let dir = dirs::CWD.as_ref().unwrap();\n        // Collect task templates from config hierarchy\n        let templates = if Settings::get().experimental {\n            config\n                .config_files\n                .values()\n                .rev()\n                .flat_map(|cf| cf.task_templates())\n                .collect()\n        } else {\n            IndexMap::new()\n        };\n        let tasks =\n            config::load_tasks_in_dir(&config, dir, &config.config_files, &templates).await?;\n        let visible_tasks: Vec<_> = tasks.iter().filter(|t| !t.hide).collect();\n        if let Some(output) = &self.output {\n            if self.multi {\n                if output.is_dir() {\n                    let mut index = if self.index {\n                        Some(String::from(\"# Tasks\\n\\n\"))\n                    } else {\n                        None\n                    };\n                    for task in &visible_tasks {\n                        let filename = format!(\"{}.md\", task.name.replace([':', '/'], \"-\"));\n                        file::write(\n                            output.join(&filename),\n                            &task.render_markdown(&config).await?,\n                        )?;\n                        if let Some(index) = &mut index {\n                            let desc = if task.description.is_empty() {\n                                String::new()\n                            } else {\n                                format!(\" - {}\", task.description)\n                            };\n                            index.push_str(&format!(\"- [{}](./{filename}){desc}\\n\", task.name));\n                        }\n                    }\n                    if let Some(index) = index {\n                        if visible_tasks\n                            .iter()\n                            .any(|t| t.name.replace([':', '/'], \"-\") == \"index\")\n                        {\n                            warn!(\"task named \\\"index\\\" will be overwritten by index.md\");\n                        }\n                        file::write(output.join(\"index.md\"), &index)?;\n                    }\n                } else {\n                    return Err(eyre::eyre!(\n                        \"`--output` must be a directory when `--multi` is set\"\n                    ));\n                }\n            } else {\n                let mut out = vec![];\n                for task in &visible_tasks {\n                    out.push(task.render_markdown(&config).await?);\n                }\n                let mut doc = String::new();\n                for task in out {\n                    doc.push_str(&task);\n                    doc.push_str(\"\\n\\n\");\n                }\n                if self.inject {\n                    doc = format!(\"\\n{}\\n\", doc.trim());\n                    let mut contents = file::read_to_string(output)?;\n                    let task_placeholder_start = \"<!-- mise-tasks -->\";\n                    let task_placeholder_end = \"<!-- /mise-tasks -->\";\n                    let start = contents.find(task_placeholder_start).unwrap_or(0);\n                    let end = contents[start..]\n                        .find(task_placeholder_end)\n                        .map(|e| e + start)\n                        .unwrap_or(contents.len());\n                    contents.replace_range((start + task_placeholder_start.len())..end, &doc);\n                    file::write(output, &contents)?;\n                } else {\n                    doc = format!(\"{}\\n\", doc.trim());\n                    file::write(output, &doc)?;\n                }\n            }\n        } else {\n            let mut out = vec![];\n            for task in &visible_tasks {\n                out.push(task.render_markdown(&config).await?);\n            }\n            miseprintln!(\"{}\", out.join(\"\\n\\n\").trim());\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise generate task-docs</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/task_stubs.rs",
    "content": "use crate::Result;\nuse crate::config::Config;\nuse crate::file;\nuse crate::task::Task;\nuse clap::ValueHint;\nuse std::path::PathBuf;\nuse xx::file::display_path;\n\n/// Generates shims to run mise tasks\n///\n/// By default, this will build shims like ./bin/<task>. These can be paired with `mise generate bootstrap`\n/// so contributors to a project can execute mise tasks without installing mise into their system.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TaskStubs {\n    /// Directory to create task stubs inside of\n    #[clap(long, short, verbatim_doc_comment, default_value=\"bin\", value_hint=ValueHint::DirPath)]\n    dir: PathBuf,\n\n    /// Path to a mise bin to use when running the task stub.\n    ///\n    /// Use `--mise-bin=./bin/mise` to use a mise bin generated from `mise generate bootstrap`\n    #[clap(long, short, verbatim_doc_comment, default_value = \"mise\")]\n    mise_bin: PathBuf,\n}\n\nimpl TaskStubs {\n    pub async fn run(self) -> eyre::Result<()> {\n        let config = Config::get().await?;\n        for task in config.tasks().await?.values() {\n            let bin = self.dir.join(task.name_to_path());\n            let output = self.generate(task)?;\n            if let Some(parent) = bin.parent() {\n                file::create_dir_all(parent)?;\n            }\n            file::write(&bin, &output)?;\n            file::make_executable(&bin)?;\n            miseprintln!(\"Wrote to {}\", display_path(&bin));\n        }\n        Ok(())\n    }\n\n    fn generate(&self, task: &Task) -> Result<String> {\n        let mise_bin = self.mise_bin.to_string_lossy();\n        let mise_bin = shell_words::quote(&mise_bin);\n        let display_name = &task.display_name;\n        let script = format!(\n            r#\"\n#!/bin/sh\nexec {mise_bin} run {display_name} \"$@\"\n\"#\n        );\n        Ok(script.trim().to_string())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tasks add test -- echo 'running tests'</bold>\n    $ <bold>mise generate task-stubs</bold>\n    $ <bold>./bin/test</bold>\n    running tests\n\"#\n);\n"
  },
  {
    "path": "src/cli/generate/tool_stub.rs",
    "content": "use crate::Result;\nuse crate::backend::asset_matcher::detect_platform_from_url;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::get_filename_from_url;\nuse crate::cli::tool_stub::ToolStubFile;\nuse crate::config::Config;\nuse crate::file::{self, TarFormat, TarOptions};\nuse crate::http::HTTP;\nuse crate::lockfile::PlatformInfo;\nuse crate::minisign;\nuse crate::platform::Platform;\nuse crate::toolset::{ResolveOptions, ToolVersion};\nuse crate::ui::info;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse clap::ValueHint;\nuse color_eyre::eyre::bail;\nuse humansize::{BINARY, format_size};\nuse indexmap::IndexMap;\nuse std::collections::BTreeMap;\nuse std::path::PathBuf;\nuse toml_edit::DocumentMut;\nuse xx::file::display_path;\n\n/// Generate a tool stub for HTTP-based tools\n///\n/// This command generates tool stubs that can automatically download and execute\n/// tools from HTTP URLs. It can detect checksums, file sizes, and binary paths\n/// automatically by downloading and analyzing the tool.\n///\n/// When generating stubs with platform-specific URLs, the command will append new\n/// platforms to existing stub files rather than overwriting them. This allows you\n/// to incrementally build cross-platform tool stubs.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct ToolStub {\n    /// Output file path for the tool stub\n    #[clap(value_hint = ValueHint::FilePath)]\n    pub output: PathBuf,\n\n    /// Binary path within the extracted archive\n    ///\n    /// If not specified and the archive is downloaded, will auto-detect the most likely binary\n    #[clap(long, short)]\n    pub bin: Option<String>,\n\n    /// Wrap stub in a bootstrap script that installs mise if not already present\n    ///\n    /// When enabled, generates a bash script that:\n    /// 1. Checks if mise is installed at the expected path\n    /// 2. If not, downloads and installs mise using the embedded installer\n    /// 3. Executes the tool stub using mise\n    #[clap(long, verbatim_doc_comment)]\n    pub bootstrap: bool,\n\n    /// Specify mise version for the bootstrap script\n    ///\n    /// By default, uses the latest version from the install script.\n    /// Use this to pin to a specific version (e.g., \"2025.1.0\").\n    #[clap(long, verbatim_doc_comment, requires = \"bootstrap\")]\n    pub bootstrap_version: Option<String>,\n\n    /// Fetch checksums and sizes for an existing tool stub file\n    ///\n    /// This reads an existing stub file and fills in any missing checksum/size fields\n    /// by downloading the files. URLs must already be present in the stub.\n    #[clap(long, conflicts_with_all = &[\"url\", \"platform_url\", \"version\", \"bin\", \"platform_bin\", \"skip_download\", \"lock\"])]\n    pub fetch: bool,\n\n    /// HTTP backend type to use\n    #[clap(long, default_value = \"http\")]\n    pub http: String,\n\n    /// Resolve and embed lockfile data (exact version + platform URLs/checksums)\n    /// into an existing stub file for reproducible installs without runtime API calls\n    #[clap(long, conflicts_with_all = &[\"url\", \"platform_url\", \"bin\", \"platform_bin\", \"fetch\", \"skip_download\"])]\n    pub lock: bool,\n\n    /// Platform-specific binary paths in the format platform:path\n    ///\n    /// Examples: --platform-bin windows-x64:tool.exe --platform-bin linux-x64:bin/tool\n    #[clap(long)]\n    pub platform_bin: Vec<String>,\n\n    /// Platform-specific URLs in the format platform:url or just url (auto-detect platform)\n    ///\n    /// When the output file already exists, new platforms will be appended to the existing\n    /// platforms table. Existing platform URLs will be updated if specified again.\n    ///\n    /// If only a URL is provided (without platform:), the platform will be automatically\n    /// detected from the URL filename.\n    ///\n    /// Examples:\n    /// --platform-url linux-x64:https://...\n    /// --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz\n    #[clap(long)]\n    pub platform_url: Vec<String>,\n\n    /// Skip downloading for checksum and binary path detection (faster but less informative)\n    #[clap(long)]\n    pub skip_download: bool,\n\n    /// URL for downloading the tool\n    ///\n    /// Example: https://github.com/owner/repo/releases/download/v2.0.0/tool-linux-x64.tar.gz\n    #[clap(long, short)]\n    pub url: Option<String>,\n\n    /// Version of the tool\n    #[clap(long, default_value = \"latest\")]\n    pub version: String,\n}\n\nimpl ToolStub {\n    pub async fn run(self) -> Result<()> {\n        let stub_content = if self.fetch {\n            self.fetch_checksums().await?\n        } else if self.lock {\n            self.lock_stub().await?\n        } else {\n            self.generate_stub().await?\n        };\n\n        if let Some(parent) = self.output.parent() {\n            file::create_dir_all(parent)?;\n        }\n\n        file::write(&self.output, &stub_content)?;\n        file::make_executable(&self.output)?;\n\n        if self.fetch || self.lock {\n            miseprintln!(\"Updated tool stub: {}\", display_path(&self.output));\n        } else {\n            miseprintln!(\"Generated tool stub: {}\", display_path(&self.output));\n        }\n        Ok(())\n    }\n\n    fn get_tool_name(&self) -> String {\n        self.output\n            .file_name()\n            .and_then(|name| name.to_str())\n            .unwrap_or(\"tool\")\n            .to_string()\n    }\n\n    async fn generate_stub(&self) -> Result<String> {\n        // Validate that either URL or platform URLs are provided\n        if self.url.is_none() && self.platform_url.is_empty() {\n            bail!(\"Either --url or --platform-url must be specified\");\n        }\n\n        // Read existing file if it exists\n        let (existing_content, mut doc) = if self.output.exists() {\n            let content = file::read_to_string(&self.output)?;\n            let toml_content = extract_toml_from_stub(&content);\n\n            let document = toml_content.parse::<DocumentMut>()?;\n            (Some(content), document)\n        } else {\n            (None, DocumentMut::new())\n        };\n\n        // If file exists but we're trying to set a different version, bail\n        if existing_content.is_some() && doc.get(\"version\").is_some() {\n            let existing_version = doc.get(\"version\").and_then(|v| v.as_str()).unwrap_or(\"\");\n            if existing_version != self.version {\n                bail!(\n                    \"Cannot change version of existing tool stub from {} to {}\",\n                    existing_version,\n                    self.version\n                );\n            }\n        }\n\n        // Set or update version only if it's not \"latest\" (which should be the default)\n        if self.version != \"latest\" {\n            doc[\"version\"] = toml_edit::value(&self.version);\n        }\n\n        // Get the stub filename (without path)\n        let stub_filename = self\n            .output\n            .file_stem()\n            .and_then(|s| s.to_str())\n            .unwrap_or(\"\");\n\n        // Update bin if provided and different from stub filename\n        if let Some(bin) = &self.bin\n            && bin != stub_filename\n        {\n            doc[\"bin\"] = toml_edit::value(bin);\n        }\n\n        // We use toml_edit directly to preserve existing content\n\n        // Handle URL or platform-specific URLs\n        if let Some(url) = &self.url {\n            doc[\"url\"] = toml_edit::value(url);\n\n            // Auto-detect checksum and size if not skipped\n            if !self.skip_download {\n                let mpr = MultiProgressReport::get();\n                let (checksum, size, bin_path) = self.analyze_url(url, &mpr).await?;\n                doc[\"checksum\"] = toml_edit::value(&checksum);\n\n                // Create size entry with human-readable comment\n                let mut size_item = toml_edit::value(size as i64);\n                if let Some(value) = size_item.as_value_mut() {\n                    let formatted_comment = format_size_comment(size);\n                    value.decor_mut().set_suffix(formatted_comment);\n                }\n                doc[\"size\"] = size_item;\n\n                if self.bin.is_none()\n                    && let Some(detected_bin) = bin_path.as_ref()\n                {\n                    // Only set bin if it's different from the stub filename\n                    if detected_bin != stub_filename {\n                        doc[\"bin\"] = toml_edit::value(detected_bin);\n                    }\n                }\n            }\n        }\n\n        if !self.platform_url.is_empty() {\n            let mpr = MultiProgressReport::get();\n\n            // Ensure platforms table exists\n            if doc.get(\"platforms\").is_none() {\n                let mut platforms_table = toml_edit::Table::new();\n                platforms_table.set_implicit(true);\n                doc[\"platforms\"] = toml_edit::Item::Table(platforms_table);\n            }\n            let platforms = doc[\"platforms\"].as_table_mut().unwrap();\n\n            // Parse platform-specific bin paths\n            let mut explicit_platform_bins = IndexMap::new();\n            for platform_bin_spec in &self.platform_bin {\n                let (platform, bin_path) = self.parse_platform_bin_spec(platform_bin_spec)?;\n                explicit_platform_bins.insert(platform, bin_path);\n            }\n\n            // Track detected bin paths to see if they're all the same\n            let mut detected_bin_paths = Vec::new();\n\n            for platform_spec in &self.platform_url {\n                let (platform, url) = self.parse_platform_spec(platform_spec)?;\n\n                // Create or get platform table\n                if platforms.get(&platform).is_none() {\n                    platforms[&platform] = toml_edit::table();\n                }\n                let platform_table = platforms[&platform].as_table_mut().unwrap();\n\n                // Set URL\n                platform_table[\"url\"] = toml_edit::value(&url);\n\n                // Set platform-specific bin path if explicitly provided and different from stub filename\n                if let Some(explicit_bin) = explicit_platform_bins.get(&platform)\n                    && explicit_bin != stub_filename\n                {\n                    platform_table[\"bin\"] = toml_edit::value(explicit_bin);\n                }\n\n                // Auto-detect checksum, size, and bin path if not skipped\n                if !self.skip_download {\n                    let (checksum, size, bin_path) = self.analyze_url(&url, &mpr).await?;\n                    platform_table[\"checksum\"] = toml_edit::value(&checksum);\n\n                    // Create size entry with human-readable comment\n                    let mut size_item = toml_edit::value(size as i64);\n                    if let Some(value) = size_item.as_value_mut() {\n                        let formatted_comment = format_size_comment(size);\n                        value.decor_mut().set_suffix(formatted_comment);\n                    }\n                    platform_table[\"size\"] = size_item;\n\n                    // Track detected bin paths\n                    if let Some(ref bp) = bin_path {\n                        detected_bin_paths.push(bp.clone());\n                    }\n\n                    // Set bin path if not explicitly provided and we detected one different from stub filename\n                    if !explicit_platform_bins.contains_key(&platform)\n                        && self.bin.is_none()\n                        && let Some(detected_bin) = bin_path.as_ref()\n                        && detected_bin != stub_filename\n                    {\n                        platform_table[\"bin\"] = toml_edit::value(detected_bin);\n                    }\n                }\n            }\n\n            // Check if we should set a global bin\n            let should_set_global_bin = if self.bin.is_none() && !detected_bin_paths.is_empty() {\n                let first_bin = &detected_bin_paths[0];\n                detected_bin_paths.iter().all(|b| b == first_bin)\n            } else {\n                false\n            };\n\n            if should_set_global_bin {\n                let global_bin = detected_bin_paths[0].clone();\n                // Remove platform-specific bin entries since we'll have a global one\n                for platform_spec in &self.platform_url {\n                    let (platform, _) = self.parse_platform_spec(platform_spec)?;\n                    if let Some(platform_table) = platforms.get_mut(&platform)\n                        && let Some(table) = platform_table.as_table_mut()\n                        && !explicit_platform_bins.contains_key(&platform)\n                    {\n                        table.remove(\"bin\");\n                    }\n                }\n                // Now set the global bin if different from stub filename\n                if global_bin != stub_filename {\n                    doc[\"bin\"] = toml_edit::value(&global_bin);\n                }\n            }\n        }\n\n        let toml_content = doc.to_string();\n\n        // Check if we should use bootstrap format:\n        // 1. If --bootstrap flag is explicitly set\n        // 2. If existing file was a bootstrap stub (preserve format when appending)\n        let use_bootstrap = self.bootstrap\n            || existing_content\n                .as_ref()\n                .map(|c| is_bootstrap_stub(c))\n                .unwrap_or(false);\n\n        if use_bootstrap {\n            self.wrap_with_bootstrap(&toml_content).await\n        } else {\n            let mut content = vec![\n                \"#!/usr/bin/env -S mise tool-stub\".to_string(),\n                \"\".to_string(),\n            ];\n\n            content.push(toml_content);\n\n            Ok(content.join(\"\\n\"))\n        }\n    }\n\n    async fn wrap_with_bootstrap(&self, toml_content: &str) -> Result<String> {\n        // Fetch and verify install.sh (same approach as bootstrap.rs)\n        // Use versioned URL if a specific version is requested\n        let url = if let Some(v) = &self.bootstrap_version {\n            format!(\"https://mise.jdx.dev/v{v}/install.sh\")\n        } else {\n            \"https://mise.jdx.dev/install.sh\".to_string()\n        };\n        let install = HTTP.get_text(&url).await?;\n        let install_sig = HTTP.get_text(format!(\"{url}.minisig\")).await?;\n        minisign::verify(&minisign::MISE_PUB_KEY, install.as_bytes(), &install_sig)?;\n        let install = info::indent_by(install, \"        \");\n\n        // Store TOML in a comment block - mise tool-stub will parse this from the script\n        let commented_toml = toml_content\n            .lines()\n            .map(|line| format!(\"# {line}\"))\n            .collect::<Vec<_>>()\n            .join(\"\\n\");\n\n        Ok(format!(\n            r##\"#!/usr/bin/env bash\nset -eu\n\n# MISE_TOOL_STUB:\n{commented_toml}\n# :MISE_TOOL_STUB\n\n__mise_tool_stub_bootstrap() {{\n    # Check if mise is on PATH first\n    if command -v mise &>/dev/null; then\n        MISE_BIN=\"$(command -v mise)\"\n        return\n    fi\n\n    # Fall back to ~/.local/bin/mise\n    MISE_BIN=\"$HOME/.local/bin/mise\"\n    if [ -f \"$MISE_BIN\" ]; then\n        return\n    fi\n\n    # Install mise to ~/.local/bin\n    install() {{\n        local initial_working_dir=\"$PWD\"\n{install}\n        cd -- \"$initial_working_dir\"\n    }}\n    local MISE_INSTALL_HELP=0\n    install\n}}\n__mise_tool_stub_bootstrap\n\nexec \"$MISE_BIN\" tool-stub \"$0\" \"$@\"\n\"##\n        ))\n    }\n\n    fn parse_platform_spec(&self, spec: &str) -> Result<(String, String)> {\n        // Check if this is a URL first (auto-detect case)\n        if spec.starts_with(\"http://\") || spec.starts_with(\"https://\") {\n            // Format: url (auto-detect platform)\n            let url = spec.to_string();\n\n            if let Some(detected_platform) = detect_platform_from_url(&url) {\n                let platform = detected_platform.to_platform_string();\n                debug!(\"Auto-detected platform '{}' from URL: {}\", platform, url);\n                Ok((platform, url))\n            } else {\n                bail!(\n                    \"Could not auto-detect platform from URL: {}. Please specify explicitly using 'platform:url' format.\",\n                    url\n                );\n            }\n        } else {\n            // Format: platform:url\n            let parts: Vec<&str> = spec.splitn(2, ':').collect();\n            if parts.len() != 2 {\n                bail!(\n                    \"Platform spec must be in format 'platform:url' or just 'url' (for auto-detection). Got: {}\",\n                    spec\n                );\n            }\n\n            let platform = parts[0].to_string();\n            let url = parts[1].to_string();\n            Ok((platform, url))\n        }\n    }\n\n    fn parse_platform_bin_spec(&self, spec: &str) -> Result<(String, String)> {\n        let parts: Vec<&str> = spec.splitn(2, ':').collect();\n        if parts.len() != 2 {\n            bail!(\n                \"Platform bin spec must be in format 'platform:path', got: {}\",\n                spec\n            );\n        }\n\n        let platform = parts[0].to_string();\n        let bin_path = parts[1].to_string();\n\n        Ok((platform, bin_path))\n    }\n\n    async fn analyze_url(\n        &self,\n        url: &str,\n        mpr: &std::sync::Arc<crate::ui::multi_progress_report::MultiProgressReport>,\n    ) -> Result<(String, u64, Option<String>)> {\n        // Create a temporary directory for download and extraction\n        let temp_dir = tempfile::tempdir()?;\n        let filename = get_filename_from_url(url);\n        let archive_path = temp_dir.path().join(&filename);\n\n        // Create one progress reporter for the entire operation\n        let pr = mpr.add(&format!(\"download {filename}\"));\n\n        // Download using mise's HTTP client\n        HTTP.download_file(url, &archive_path, Some(pr.as_ref()))\n            .await?;\n\n        // Read the file to calculate checksum and size\n        let bytes = file::read(&archive_path)?;\n        let size = bytes.len() as u64;\n        let checksum = format!(\"blake3:{}\", blake3::hash(&bytes).to_hex());\n\n        // Detect binary path if this is an archive\n        let bin_path = if TarFormat::from_file_name(&filename).is_archive() {\n            // Update progress message for extraction and reuse the same progress reporter\n            pr.set_message(format!(\"extract {filename}\"));\n            match self\n                .extract_and_find_binary(&archive_path, &temp_dir, &filename, pr.as_ref())\n                .await\n            {\n                Ok(path) => {\n                    pr.finish();\n                    Some(path)\n                }\n                Err(_) => {\n                    pr.finish();\n                    None\n                }\n            }\n        } else {\n            // For single binary files, just use the tool name\n            pr.finish();\n            Some(self.get_tool_name())\n        };\n\n        Ok((checksum, size, bin_path))\n    }\n\n    async fn extract_and_find_binary(\n        &self,\n        archive_path: &std::path::Path,\n        temp_dir: &tempfile::TempDir,\n        _filename: &str,\n        pr: &dyn SingleReport,\n    ) -> Result<String> {\n        // Try to extract and find executables\n        let extracted_dir = temp_dir.path().join(\"extracted\");\n        std::fs::create_dir_all(&extracted_dir)?;\n\n        // Try extraction using mise's built-in extraction logic (reuse the passed progress reporter)\n        let tar_opts = TarOptions {\n            pr: Some(pr),\n            ..TarOptions::new(TarFormat::from_file_name(\n                &archive_path\n                    .file_name()\n                    .unwrap_or_default()\n                    .to_string_lossy(),\n            ))\n        };\n        file::untar(archive_path, &extracted_dir, &tar_opts)?;\n\n        // Check if strip_components would be applied during actual installation\n        let format =\n            TarFormat::from_file_name(&archive_path.file_name().unwrap().to_string_lossy());\n        let will_strip = file::should_strip_components(archive_path, format)?;\n\n        // Find executable files\n        let executables = self.find_executables(&extracted_dir)?;\n        if executables.is_empty() {\n            bail!(\"No executable files found in archive\");\n        }\n\n        // Look for exact filename match only\n        let tool_name = self.get_tool_name();\n        let selected_exe = self.find_exact_binary_match(&executables, &tool_name)?;\n\n        // If strip_components will be applied, remove the first path component\n        if will_strip {\n            let path = std::path::Path::new(&selected_exe);\n            if let Ok(stripped) = path.strip_prefix(path.components().next().unwrap()) {\n                let stripped_str = stripped.to_string_lossy().to_string();\n                // Don't return empty string if stripping removed everything\n                if !stripped_str.is_empty() {\n                    return Ok(stripped_str);\n                }\n            }\n        }\n\n        Ok(selected_exe)\n    }\n\n    fn find_executables(&self, dir: &std::path::Path) -> Result<Vec<String>> {\n        let mut executables = Vec::new();\n\n        for entry in walkdir::WalkDir::new(dir) {\n            let entry = entry?;\n            if entry.file_type().is_file() {\n                let path = entry.path();\n                if file::is_executable(path)\n                    && let Ok(relative_path) = path.strip_prefix(dir)\n                {\n                    executables.push(relative_path.to_string_lossy().to_string());\n                }\n            }\n        }\n\n        Ok(executables)\n    }\n\n    fn find_exact_binary_match(&self, executables: &[String], tool_name: &str) -> Result<String> {\n        if executables.is_empty() {\n            bail!(\"No executable files found in archive\");\n        }\n\n        // Look for exact filename matches (with or without extensions)\n        for exe in executables {\n            let path = std::path::Path::new(exe);\n            if let Some(filename) = path.file_name().and_then(|f| f.to_str()) {\n                // Check exact filename match\n                if filename == tool_name {\n                    return Ok(exe.clone());\n                }\n                // Check filename without extension\n                if let Some(stem) = path.file_stem().and_then(|f| f.to_str())\n                    && stem == tool_name\n                {\n                    return Ok(exe.clone());\n                }\n            }\n        }\n\n        // No exact match found, try to find the most likely binary\n        let selected_exe = self.find_best_binary_match(executables, tool_name)?;\n        Ok(selected_exe)\n    }\n\n    fn find_best_binary_match(&self, executables: &[String], tool_name: &str) -> Result<String> {\n        // Strategy 1: Look for executables in common bin directories\n        let bin_executables: Vec<_> = executables\n            .iter()\n            .filter(|exe| {\n                let path = std::path::Path::new(exe);\n                path.parent()\n                    .and_then(|p| p.file_name())\n                    .and_then(|n| n.to_str())\n                    .map(|n| n == \"bin\" || n == \"sbin\")\n                    .unwrap_or(false)\n            })\n            .collect();\n\n        // If there's exactly one executable in a bin directory, use it\n        if bin_executables.len() == 1 {\n            return Ok(bin_executables[0].clone());\n        }\n\n        // Strategy 2: Look for executables that contain the tool name\n        let name_matches: Vec<_> = executables\n            .iter()\n            .filter(|exe| {\n                let path = std::path::Path::new(exe);\n                path.file_name()\n                    .and_then(|f| f.to_str())\n                    .map(|f| f.to_lowercase().contains(&tool_name.to_lowercase()))\n                    .unwrap_or(false)\n            })\n            .collect();\n\n        // If there's exactly one match containing the tool name, use it\n        if name_matches.len() == 1 {\n            return Ok(name_matches[0].clone());\n        }\n\n        // Strategy 3: If there's only one executable total, use it\n        if executables.len() == 1 {\n            return Ok(executables[0].clone());\n        }\n\n        // No good match found, provide helpful error message\n        let mut exe_list = executables.to_vec();\n        exe_list.sort();\n\n        bail!(\n            \"Could not determine which executable to use for '{}'. Available executables:\\n  {}\\n\\nUse --bin to specify the correct binary path.\",\n            tool_name,\n            exe_list.join(\"\\n  \")\n        );\n    }\n\n    async fn lock_stub(&self) -> Result<String> {\n        if !self.output.exists() {\n            bail!(\n                \"Tool stub file does not exist: {}\",\n                display_path(&self.output)\n            );\n        }\n\n        let mut stub = ToolStubFile::from_file(&self.output)?;\n        let config = Config::get().await?;\n\n        // Allow --version to override the version in the stub for bumping\n        if self.version != \"latest\" {\n            stub.version = self.version.clone();\n        }\n\n        // Create tool request and resolve version\n        let request = stub.to_tool_request(&self.output)?;\n        let backend = request.ba().backend()?;\n        let resolve_opts = ResolveOptions {\n            use_locked_version: false,\n            ..Default::default()\n        };\n        let tv = ToolVersion::resolve(&config, request, &resolve_opts).await?;\n\n        // Resolve lock info for each common platform (including variants)\n        let mut lock_platforms: BTreeMap<String, PlatformInfo> = BTreeMap::new();\n        for p in Platform::common_platforms() {\n            for platform in backend.platform_variants(&p) {\n                let target = PlatformTarget::new(platform);\n                match backend.resolve_lock_info(&tv, &target).await {\n                    Ok(info) if info.url.is_some() => {\n                        lock_platforms.insert(target.to_key(), info);\n                    }\n                    _ => {} // Skip platforms without lock info\n                }\n            }\n        }\n\n        // Read existing stub and update TOML\n        let content = file::read_to_string(&self.output)?;\n        let toml_content = extract_toml_from_stub(&content);\n        let mut doc = toml_content.parse::<DocumentMut>()?;\n\n        // Pin exact version\n        doc[\"version\"] = toml_edit::value(&tv.version);\n\n        // Write [lock.platforms.*] sections\n        doc.remove(\"lock\");\n        let mut lock_table = toml_edit::Table::new();\n        let mut platforms_table = toml_edit::Table::new();\n        for (platform_key, info) in &lock_platforms {\n            let mut pt = toml_edit::Table::new();\n            if let Some(url) = &info.url {\n                pt[\"url\"] = toml_edit::value(url);\n            }\n            if let Some(checksum) = &info.checksum {\n                pt[\"checksum\"] = toml_edit::value(checksum);\n            }\n            platforms_table[platform_key] = toml_edit::Item::Table(pt);\n        }\n        lock_table[\"platforms\"] = toml_edit::Item::Table(platforms_table);\n        doc[\"lock\"] = toml_edit::Item::Table(lock_table);\n\n        // Reconstruct with shebang\n        let toml_content = doc.to_string();\n        Ok(format!(\n            \"#!/usr/bin/env -S mise tool-stub\\n\\n{toml_content}\"\n        ))\n    }\n\n    async fn fetch_checksums(&self) -> Result<String> {\n        // Read the existing stub file\n        if !self.output.exists() {\n            bail!(\n                \"Tool stub file does not exist: {}\",\n                display_path(&self.output)\n            );\n        }\n\n        let content = file::read_to_string(&self.output)?;\n        let toml_content = extract_toml_from_stub(&content);\n        let mut doc = toml_content.parse::<DocumentMut>()?;\n        let mpr = MultiProgressReport::get();\n\n        // Process top-level URL if present\n        if let Some(url) = doc.get(\"url\").and_then(|v| v.as_str()) {\n            // Only fetch if checksum is missing\n            if doc.get(\"checksum\").is_none() {\n                let (checksum, size, _) = self.analyze_url(url, &mpr).await?;\n                doc[\"checksum\"] = toml_edit::value(&checksum);\n\n                // Create size entry with human-readable comment\n                let mut size_item = toml_edit::value(size as i64);\n                if let Some(value) = size_item.as_value_mut() {\n                    let formatted_comment = format_size_comment(size);\n                    value.decor_mut().set_suffix(formatted_comment);\n                }\n                doc[\"size\"] = size_item;\n            }\n        }\n\n        // Process platform-specific URLs\n        if let Some(platforms) = doc.get_mut(\"platforms\").and_then(|p| p.as_table_mut()) {\n            for (platform_name, platform_value) in platforms.iter_mut() {\n                if let Some(platform_table) = platform_value.as_table_mut()\n                    && let Some(url) = platform_table.get(\"url\").and_then(|v| v.as_str())\n                {\n                    // Only fetch if checksum is missing for this platform\n                    if platform_table.get(\"checksum\").is_none() {\n                        match self.analyze_url(url, &mpr).await {\n                            Ok((checksum, size, _)) => {\n                                platform_table[\"checksum\"] = toml_edit::value(&checksum);\n\n                                // Create size entry with human-readable comment\n                                let mut size_item = toml_edit::value(size as i64);\n                                if let Some(value) = size_item.as_value_mut() {\n                                    let formatted_comment = format_size_comment(size);\n                                    value.decor_mut().set_suffix(formatted_comment);\n                                }\n                                platform_table[\"size\"] = size_item;\n                            }\n                            Err(e) => {\n                                // Log error but continue with other platforms\n                                eprintln!(\n                                    \"Warning: Failed to fetch checksum for platform '{platform_name}': {e}\"\n                                );\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        let toml_content = doc.to_string();\n\n        // Check if original was a bootstrap stub and preserve that format\n        if is_bootstrap_stub(&content) {\n            self.wrap_with_bootstrap(&toml_content).await\n        } else {\n            let mut output = vec![\n                \"#!/usr/bin/env -S mise tool-stub\".to_string(),\n                \"\".to_string(),\n            ];\n\n            output.push(toml_content);\n\n            Ok(output.join(\"\\n\"))\n        }\n    }\n}\n\n/// Check if content is a bootstrap stub\nfn is_bootstrap_stub(content: &str) -> bool {\n    content.contains(\"# MISE_TOOL_STUB:\") && content.contains(\"# :MISE_TOOL_STUB\")\n}\n\nfn format_size_comment(bytes: u64) -> String {\n    format!(\" # {}\", format_size(bytes, BINARY))\n}\n\n/// Extract TOML content from a stub file (handles both regular and bootstrap stubs)\nfn extract_toml_from_stub(content: &str) -> String {\n    // Check if this is a bootstrap stub by looking for comment markers\n    if is_bootstrap_stub(content) {\n        // Bootstrap stub: extract TOML between comment markers\n        let start_marker = \"# MISE_TOOL_STUB:\";\n        let end_marker = \"# :MISE_TOOL_STUB\";\n\n        if let (Some(start_pos), Some(end_pos)) =\n            (content.find(start_marker), content.find(end_marker))\n            && start_pos < end_pos\n        {\n            let between = &content[start_pos + start_marker.len()..end_pos];\n            return between\n                .lines()\n                .map(|line| line.strip_prefix(\"# \").unwrap_or(line))\n                .collect::<Vec<_>>()\n                .join(\"\\n\")\n                .trim()\n                .to_string();\n        }\n        String::new()\n    } else {\n        // Regular stub: skip shebang and comments at the start\n        content\n            .lines()\n            .skip_while(|line| line.starts_with('#') || line.trim().is_empty())\n            .collect::<Vec<_>>()\n            .join(\"\\n\")\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    Generate a tool stub for a single URL:\n    $ <bold>mise generate tool-stub ./bin/gh --url \"https://github.com/cli/cli/releases/download/v2.336.0/gh_2.336.0_linux_amd64.tar.gz\"</bold>\n\n    Generate a tool stub with platform-specific URLs:\n    $ <bold>mise generate tool-stub ./bin/rg \\\n        --platform-url linux-x64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-x86_64-unknown-linux-musl.tar.gz \\\n        --platform-url darwin-arm64:https://github.com/BurntSushi/ripgrep/releases/download/14.0.3/ripgrep-14.0.3-aarch64-apple-darwin.tar.gz</bold>\n\n    Append additional platforms to an existing stub:\n    $ <bold>mise generate tool-stub ./bin/rg \\\n        --platform-url linux-x64:https://example.com/rg-linux.tar.gz</bold>\n    $ <bold>mise generate tool-stub ./bin/rg \\\n        --platform-url darwin-arm64:https://example.com/rg-darwin.tar.gz</bold>\n    # The stub now contains both platforms\n\n    Use auto-detection for platform from URL:\n    $ <bold>mise generate tool-stub ./bin/node \\\n        --platform-url https://nodejs.org/dist/v22.17.1/node-v22.17.1-darwin-arm64.tar.gz</bold>\n    # Platform 'macos-arm64' will be auto-detected from the URL\n\n    Generate with platform-specific binary paths:\n    $ <bold>mise generate tool-stub ./bin/tool \\\n        --platform-url linux-x64:https://example.com/tool-linux.tar.gz \\\n        --platform-url windows-x64:https://example.com/tool-windows.zip \\\n        --platform-bin windows-x64:tool.exe</bold>\n\n    Generate without downloading (faster):\n    $ <bold>mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --skip-download</bold>\n\n    Fetch checksums for an existing stub:\n    $ <bold>mise generate tool-stub ./bin/jq --fetch</bold>\n    # This will read the existing stub and download files to fill in any missing checksums/sizes\n\n    Generate a bootstrap stub that installs mise if needed:\n    $ <bold>mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --bootstrap</bold>\n    # The stub will check for mise and install it automatically before running the tool\n\n    Generate a bootstrap stub with a pinned mise version:\n    $ <bold>mise generate tool-stub ./bin/tool --url \"https://example.com/tool.tar.gz\" --bootstrap --bootstrap-version 2025.1.0</bold>\n\n    Lock an existing tool stub with pinned version and platform URLs/checksums:\n    $ <bold>mise generate tool-stub ./bin/node --lock</bold>\n\n    Bump the version in a locked stub:\n    $ <bold>mise generate tool-stub ./bin/node --lock --version 22</bold>\n    # Resolves the latest node 22.x, pins it, and updates platform URLs/checksums\n\"#\n);\n"
  },
  {
    "path": "src/cli/global.rs",
    "content": "use eyre::Result;\n\nuse crate::cli::local::local;\nuse crate::config::Settings;\nuse crate::{\n    cli::args::{BackendArg, ToolArg},\n    config::Config,\n};\n\n/// Sets/gets the global tool version(s)\n///\n/// Displays the contents of global config after writing.\n/// The file is `$HOME/.config/mise/config.toml` by default. It can be changed with `$MISE_GLOBAL_CONFIG_FILE`.\n/// If `$MISE_GLOBAL_CONFIG_FILE` is set to anything that ends in `.toml`, it will be parsed as `mise.toml`.\n/// Otherwise, it will be parsed as a `.tool-versions` file.\n///\n/// Use MISE_ASDF_COMPAT=1 to default the global config to ~/.tool-versions\n///\n/// Use `mise local` to set a tool version locally in the current directory.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true, after_long_help = AFTER_LONG_HELP)]\npub struct Global {\n    /// Tool(s) to add to .tool-versions\n    /// e.g.: node@20\n    /// If this is a single tool with no version, the current value of the global\n    /// .tool-versions will be displayed\n    #[clap(value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    tool: Vec<ToolArg>,\n\n    /// Save fuzzy version to `~/.tool-versions`\n    /// e.g.: `mise global --fuzzy node@20` will save `node 20` to ~/.tool-versions\n    /// this is the default behavior unless MISE_ASDF_COMPAT=1\n    #[clap(long, verbatim_doc_comment, overrides_with = \"pin\")]\n    fuzzy: bool,\n\n    /// Get the path of the global config file\n    #[clap(long)]\n    path: bool,\n\n    /// Save exact version to `~/.tool-versions`\n    /// e.g.: `mise global --pin node@20` will save `node 20.0.0` to ~/.tool-versions\n    #[clap(long, verbatim_doc_comment, overrides_with = \"fuzzy\")]\n    pin: bool,\n\n    /// Remove the plugin(s) from ~/.tool-versions\n    #[clap(long, value_name = \"PLUGIN\", aliases = [\"rm\", \"unset\"])]\n    remove: Option<Vec<BackendArg>>,\n}\n\nimpl Global {\n    pub async fn run(self) -> Result<()> {\n        let settings = Settings::try_get()?;\n        let config = Config::get().await?;\n        local(\n            &config,\n            &settings.global_tools_file(),\n            self.tool,\n            self.remove,\n            self.pin,\n            self.fuzzy,\n            self.path,\n        )\n        .await\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n    # set the current version of node to 20.x\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\n    $ <bold>mise global --fuzzy node@20</bold>\n\n    # set the current version of node to 20.x\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\n    $ <bold>mise global --pin node@20</bold>\n\n    # show the current version of node in ~/.tool-versions\n    $ <bold>mise global node</bold>\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/hook_env.rs",
    "content": "use crate::config::{Config, Settings};\nuse crate::direnv::DirenvDiff;\nuse crate::env::{__MISE_DIFF, PATH_KEY, TERM_WIDTH};\nuse crate::env::{join_paths, split_paths};\nuse crate::env_diff::{EnvDiff, EnvDiffOperation, EnvMap};\nuse crate::file::display_rel_path;\nuse crate::hook_env::{PREV_SESSION, WatchFilePattern};\nuse crate::shell::{ShellType, get_shell};\nuse crate::toolset::Toolset;\nuse crate::{env, hook_env, hooks, watch_files};\nuse console::truncate_str;\nuse eyre::Result;\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse std::collections::{BTreeSet, HashSet};\nuse std::ops::Deref;\nuse std::path::PathBuf;\nuse std::{borrow::Cow, sync::Arc};\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]\n#[clap(rename_all = \"lowercase\")]\npub enum HookReason {\n    Precmd,\n    Chpwd,\n}\n\n/// [internal] called by activate hook to update env vars directory change\n#[derive(Debug, clap::Args)]\n#[clap(hide = true)]\npub struct HookEnv {\n    /// Skip early exit check\n    #[clap(long, short)]\n    force: bool,\n\n    /// Hide warnings such as when a tool is not installed\n    #[clap(long, short)]\n    quiet: bool,\n\n    /// Shell type to generate script for\n    #[clap(long, short)]\n    shell: Option<ShellType>,\n\n    /// Reason for calling hook-env (e.g., \"precmd\", \"chpwd\")\n    #[clap(long, hide = true)]\n    reason: Option<HookReason>,\n\n    /// Show \"mise: <PLUGIN>@<VERSION>\" message when changing directories\n    #[clap(long, hide = true)]\n    status: bool,\n}\n\nimpl HookEnv {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let ts = config.get_toolset().await?;\n        time!(\"hook-env\");\n\n        // Try to use cached watch_files for early exit check if env_cache is enabled\n        // This avoids executing plugins just to get watch_files\n        let watch_files = if Settings::get().env_cache {\n            if let Ok(Some(cached)) = ts.try_load_env_cache_full(&config) {\n                trace!(\"env_cache: using cached watch_files for early exit check\");\n                cached\n                    .watch_files\n                    .iter()\n                    .map(|p| WatchFilePattern::from(p.as_path()))\n                    .collect()\n            } else {\n                config.watch_files().await?\n            }\n        } else {\n            config.watch_files().await?\n        };\n\n        if !self.force && hook_env::should_exit_early(watch_files.clone(), self.reason) {\n            trace!(\"should_exit_early true\");\n            return Ok(());\n        }\n        time!(\"should_exit_early false\");\n        let shell = get_shell(self.shell).expect(\"no shell provided, use `--shell=zsh`\");\n        miseprint!(\"{}\", hook_env::clear_old_env(&*shell))?;\n\n        // Use env_with_path_and_split which handles caching internally\n        let (mut mise_env, user_paths, tool_paths) = ts.env_with_path_and_split(&config).await?;\n        mise_env.remove(&*PATH_KEY);\n\n        // Create config_paths from user_paths for display_status and build_session\n        let config_paths: IndexSet<PathBuf> = user_paths.iter().cloned().collect();\n        self.display_status(&config, ts, &mise_env, &config_paths)\n            .await?;\n\n        let mut diff = EnvDiff::new(&env::PRISTINE_ENV, mise_env.clone());\n        let mut patches = diff.to_patches();\n\n        // For fish shell, filter out PATH operations from diff patches because\n        // fish's PATH handling conflicts with setting PATH multiple times\n        if shell.to_string() == \"fish\" {\n            patches.retain(|p| match p {\n                EnvDiffOperation::Add(k, _)\n                | EnvDiffOperation::Change(k, _)\n                | EnvDiffOperation::Remove(k) => k != &*PATH_KEY,\n            });\n        }\n\n        // Combine paths for __MISE_DIFF tracking (all mise-managed paths)\n        let all_paths: Vec<PathBuf> = user_paths\n            .iter()\n            .chain(tool_paths.iter())\n            .cloned()\n            .collect();\n        diff.path.clone_from(&all_paths); // update __MISE_DIFF with the new paths for the next run\n\n        // Get shell aliases from config\n        let new_aliases: indexmap::IndexMap<String, String> = config\n            .shell_aliases\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect();\n\n        patches.extend(self.build_path_operations(&user_paths, &tool_paths, &__MISE_DIFF.path)?);\n        patches.push(self.build_diff_operation(&diff)?);\n        patches.push(\n            self.build_session_operation(\n                &config,\n                ts,\n                mise_env,\n                new_aliases.clone(),\n                watch_files,\n                &config_paths,\n            )\n            .await?,\n        );\n\n        // Clear the precmd run flag after running once from precmd\n        if self.reason == Some(HookReason::Precmd) && !*env::__MISE_ZSH_PRECMD_RUN {\n            patches.push(EnvDiffOperation::Add(\n                \"__MISE_ZSH_PRECMD_RUN\".into(),\n                \"1\".into(),\n            ));\n        }\n\n        let output = hook_env::build_env_commands(&*shell, &patches);\n        miseprint!(\"{output}\")?;\n\n        // Build and output alias commands\n        let alias_output =\n            hook_env::build_alias_commands(&*shell, &PREV_SESSION.aliases, &new_aliases);\n        miseprint!(\"{alias_output}\")?;\n\n        hooks::run_all_hooks(&config, ts, &*shell).await;\n        watch_files::execute_runs(&config, ts).await;\n\n        Ok(())\n    }\n\n    async fn display_status(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n        cur_env: &EnvMap,\n        config_paths: &IndexSet<PathBuf>,\n    ) -> Result<()> {\n        if self.status || Settings::get().status.show_tools {\n            let prev = &PREV_SESSION.loaded_tools;\n            let cur = ts\n                .list_current_installed_versions(config)\n                .into_iter()\n                .rev()\n                .map(|(_, tv)| format!(\"{}@{}\", tv.short(), tv.version))\n                .collect::<IndexSet<_>>();\n            let removed = prev.difference(&cur).collect::<IndexSet<_>>();\n            let new = cur.difference(prev).collect::<IndexSet<_>>();\n            if !new.is_empty() {\n                let status = new.into_iter().map(|t| format!(\"+{t}\")).rev().join(\" \");\n                info!(\"{}\", format_status(&status));\n            }\n            if !removed.is_empty() {\n                let status = removed.into_iter().map(|t| format!(\"-{t}\")).rev().join(\" \");\n                info!(\"{}\", format_status(&status));\n            }\n        }\n        if self.status || Settings::get().status.show_env {\n            let mut env_diff = EnvDiff::new(&PREV_SESSION.env, cur_env.clone()).to_patches();\n            // TODO: this logic should be in EnvDiff\n            let removed_keys = PREV_SESSION\n                .env\n                .keys()\n                .collect::<IndexSet<_>>()\n                .difference(&cur_env.keys().collect::<IndexSet<_>>())\n                .map(|k| EnvDiffOperation::Remove(k.to_string()))\n                .collect_vec();\n            env_diff.extend(removed_keys);\n            if !env_diff.is_empty() {\n                let env_diff = env_diff.into_iter().map(patch_to_status).join(\" \");\n                info!(\"{}\", truncate_str(&env_diff, TERM_WIDTH.max(60) - 5, \"…\"));\n            }\n            // Use passed config_paths instead of calling config.path_dirs()\n            let old_paths = &PREV_SESSION.config_paths;\n            let removed_paths = old_paths.difference(config_paths).collect::<IndexSet<_>>();\n            let added_paths = config_paths.difference(old_paths).collect::<IndexSet<_>>();\n            if !added_paths.is_empty() {\n                let status = added_paths\n                    .iter()\n                    .map(|p| format!(\"+{}\", display_rel_path(p)))\n                    .join(\" \");\n                info!(\"{}\", format_status(&status));\n            }\n            if !removed_paths.is_empty() {\n                let status = removed_paths\n                    .iter()\n                    .map(|p| format!(\"-{}\", display_rel_path(p)))\n                    .join(\" \");\n                info!(\"{}\", format_status(&status));\n            }\n        }\n        ts.notify_if_versions_missing(config).await;\n        crate::prepare::notify_if_stale(config);\n        Ok(())\n    }\n\n    /// modifies the PATH and optionally DIRENV_DIFF env var if it exists\n    /// user_paths are paths from env._.path config that are prepended (filtered only against user manual additions)\n    /// tool_paths are paths from tool installations that should be filtered if already in original PATH\n    fn build_path_operations(\n        &self,\n        user_paths: &[PathBuf],\n        tool_paths: &[PathBuf],\n        to_remove: &[PathBuf],\n    ) -> Result<Vec<EnvDiffOperation>> {\n        let full = join_paths(&*env::PATH)?.to_string_lossy().to_string();\n        let current_paths: Vec<PathBuf> = split_paths(&full).collect();\n\n        let (pre, post, post_user) = match &*env::__MISE_ORIG_PATH {\n            Some(orig_path) if !Settings::get().activate_aggressive => {\n                let orig_paths: Vec<PathBuf> = split_paths(orig_path).collect();\n                let orig_set: HashSet<_> = orig_paths.iter().collect();\n\n                // Get all mise-managed paths from the previous session\n                // to_remove contains ALL paths that mise added (tool installs, config paths, etc.)\n                let mise_paths_set: HashSet<_> = to_remove.iter().collect();\n\n                // Find paths in current that are not in original and not mise-managed.\n                // Split them into \"pre\" (before the original PATH entries) and \"post_user\"\n                // (after the original PATH entries) to preserve their intended position.\n                // This prevents paths appended after `mise activate` in shell rc from\n                // being moved to the front of PATH.\n                //\n                // Also collect orig paths in their current order to preserve any\n                // reordering done after activation (e.g., by ~/.zlogin which runs\n                // after ~/.zshrc where mise activate is typically placed).\n                let mut pre = Vec::new();\n                let mut post_user = Vec::new();\n                let mut orig_reordered = Vec::new();\n                let mut seen_orig = false;\n                let mut seen_in_current: HashSet<&PathBuf> = HashSet::new();\n                for path in &current_paths {\n                    if orig_set.contains(path) {\n                        seen_orig = true;\n                        orig_reordered.push(path.clone());\n                        seen_in_current.insert(path);\n                        continue;\n                    }\n\n                    // Skip if it's a mise-managed path from previous session\n                    if mise_paths_set.contains(path) {\n                        continue;\n                    }\n\n                    // Place in pre or post_user based on position relative to original PATH\n                    if seen_orig {\n                        post_user.push(path.clone());\n                    } else {\n                        pre.push(path.clone());\n                    }\n                }\n\n                // Append any orig paths that are no longer in current PATH\n                // (to avoid losing paths that may have been temporarily removed)\n                for path in &orig_paths {\n                    if !seen_in_current.contains(path) {\n                        orig_reordered.push(path.clone());\n                    }\n                }\n\n                (pre, orig_reordered, post_user)\n            }\n            _ => (vec![], current_paths, vec![]),\n        };\n\n        // Filter out tool paths that are already in the original PATH (post) or\n        // in the pre paths (user additions). This prevents mise from claiming ownership\n        // of paths that were in the user's original PATH before mise activation, and also\n        // prevents duplicates when paths from previous mise activations are in the current\n        // PATH. When a tool is deactivated, these paths will remain accessible since they're\n        // preserved in the `post` section or `pre` section.\n        // This fixes the issue where system tools (e.g., rustup) become unavailable\n        // after leaving a mise project that uses the same tool.\n        //\n        // IMPORTANT: Only filter tool_paths against __MISE_ORIG_PATH (post).\n        // User-configured paths are filtered separately (only against user manual additions)\n        // to preserve user's intended ordering while avoiding duplicates.\n        //\n        // Use canonicalized paths for comparison to handle symlinks, relative paths,\n        // and other path variants that refer to the same filesystem location.\n        let post_canonical: HashSet<PathBuf> =\n            post.iter().filter_map(|p| p.canonicalize().ok()).collect();\n        let user_additions_set: HashSet<_> = pre.iter().chain(post_user.iter()).collect();\n        let user_additions_canonical: HashSet<PathBuf> = pre\n            .iter()\n            .chain(post_user.iter())\n            .filter_map(|p| p.canonicalize().ok())\n            .collect();\n\n        let tool_paths_filtered: Vec<PathBuf> = tool_paths\n            .iter()\n            .filter(|p| {\n                // Check both the original path and its canonical form\n                // This handles cases where the path doesn't exist yet (can't canonicalize)\n                // or where the canonical form differs from the string representation\n\n                // Filter against post (original PATH)\n                if post.contains(p) {\n                    return false;\n                }\n                if let Ok(canonical) = p.canonicalize()\n                    && post_canonical.contains(&canonical)\n                {\n                    return false;\n                }\n\n                // Also filter against user additions (pre + post_user) to avoid duplicates\n                if user_additions_set.contains(p) {\n                    return false;\n                }\n                if let Ok(canonical) = p.canonicalize()\n                    && user_additions_canonical.contains(&canonical)\n                {\n                    return false;\n                }\n\n                true\n            })\n            .cloned()\n            .collect();\n\n        // Filter user_paths against user additions (pre + post_user) to avoid duplicates\n        // when users manually add paths after mise activation.\n        // IMPORTANT: Do NOT filter against post (__MISE_ORIG_PATH) - this would break\n        // the intended behavior where user-configured paths should take precedence\n        // even if they already exist in the original PATH.\n        let user_paths_filtered: Vec<PathBuf> = user_paths\n            .iter()\n            .filter(|p| {\n                if user_additions_set.contains(p) {\n                    return false;\n                }\n                if let Ok(canonical) = p.canonicalize()\n                    && user_additions_canonical.contains(&canonical)\n                {\n                    return false;\n                }\n                true\n            })\n            .cloned()\n            .collect();\n\n        // Combine paths in the correct order:\n        // pre (user shell prepends) -> user_paths (from config) -> tool_paths -> post (original PATH) -> post_user (user shell appends)\n        let new_path = join_paths(\n            pre.iter()\n                .chain(user_paths_filtered.iter())\n                .chain(tool_paths_filtered.iter())\n                .chain(post.iter())\n                .chain(post_user.iter()),\n        )?\n        .to_string_lossy()\n        .into_owned();\n        let mut ops = vec![EnvDiffOperation::Add(PATH_KEY.to_string(), new_path)];\n\n        // For DIRENV_DIFF, we need to include both filtered user_paths and filtered tool_paths\n        let all_installs: Vec<PathBuf> = user_paths_filtered\n            .iter()\n            .chain(tool_paths_filtered.iter())\n            .cloned()\n            .collect();\n        if let Some(input) = env::DIRENV_DIFF.deref() {\n            match self.update_direnv_diff(input, &all_installs, to_remove) {\n                Ok(Some(op)) => {\n                    ops.push(op);\n                }\n                Err(err) => warn!(\"failed to update DIRENV_DIFF: {:#}\", err),\n                _ => {}\n            }\n        }\n\n        Ok(ops)\n    }\n\n    /// inserts install path to DIRENV_DIFF both for old and new\n    /// this makes direnv think that these paths were added before it ran\n    /// that way direnv will not remove the path when it runs the next time\n    fn update_direnv_diff(\n        &self,\n        input: &str,\n        installs: &[PathBuf],\n        to_remove: &[PathBuf],\n    ) -> Result<Option<EnvDiffOperation>> {\n        let mut diff = DirenvDiff::parse(input)?;\n        if diff.new_path().is_empty() {\n            return Ok(None);\n        }\n        for path in to_remove {\n            diff.remove_path_from_old_and_new(path)?;\n        }\n        for install in installs {\n            diff.add_path_to_old_and_new(install)?;\n        }\n\n        Ok(Some(EnvDiffOperation::Change(\n            \"DIRENV_DIFF\".into(),\n            diff.dump()?,\n        )))\n    }\n\n    fn build_diff_operation(&self, diff: &EnvDiff) -> Result<EnvDiffOperation> {\n        Ok(EnvDiffOperation::Add(\n            \"__MISE_DIFF\".into(),\n            diff.serialize()?,\n        ))\n    }\n\n    async fn build_session_operation(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n        env: EnvMap,\n        aliases: indexmap::IndexMap<String, String>,\n        watch_files: BTreeSet<WatchFilePattern>,\n        config_paths: &IndexSet<PathBuf>,\n    ) -> Result<EnvDiffOperation> {\n        let loaded_tools = if self.status || Settings::get().status.show_tools {\n            ts.list_current_versions()\n                .into_iter()\n                .map(|(_, tv)| format!(\"{}@{}\", tv.short(), tv.version))\n                .collect()\n        } else {\n            Default::default()\n        };\n        let session = hook_env::build_session(\n            config,\n            env,\n            aliases,\n            loaded_tools,\n            watch_files,\n            config_paths.clone(),\n        )\n        .await?;\n        Ok(EnvDiffOperation::Add(\n            \"__MISE_SESSION\".into(),\n            hook_env::serialize(&session)?,\n        ))\n    }\n}\n\nfn patch_to_status(patch: EnvDiffOperation) -> String {\n    match patch {\n        EnvDiffOperation::Add(k, _) => format!(\"+{k}\"),\n        EnvDiffOperation::Change(k, _) => format!(\"~{k}\"),\n        EnvDiffOperation::Remove(k) => format!(\"-{k}\"),\n    }\n}\n\nfn format_status(status: &str) -> Cow<'_, str> {\n    if Settings::get().status.truncate {\n        truncate_str(status, TERM_WIDTH.max(60) - 5, \"…\")\n    } else {\n        status.into()\n    }\n}\n"
  },
  {
    "path": "src/cli/hook_not_found.rs",
    "content": "use crate::exit;\n\nuse eyre::Result;\n\nuse crate::config::{Config, Settings};\nuse crate::shell::ShellType;\nuse crate::toolset::ToolsetBuilder;\n\n/// [internal] called by shell when a command is not found\n#[derive(Debug, clap::Args)]\n#[clap(hide = true)]\npub struct HookNotFound {\n    /// Attempted bin to run\n    #[clap()]\n    bin: String,\n\n    /// Shell type to generate script for\n    #[clap(long, short)]\n    shell: Option<ShellType>,\n}\n\nimpl HookNotFound {\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        let settings = Settings::try_get()?;\n        if settings.not_found_auto_install {\n            let mut ts = ToolsetBuilder::new().build(&config).await?;\n            if ts\n                .install_missing_bin(&mut config, &self.bin)\n                .await?\n                .is_some()\n            {\n                return Ok(());\n            }\n        }\n        exit(127);\n    }\n}\n"
  },
  {
    "path": "src/cli/implode.rs",
    "content": "use std::path::Path;\n\nuse eyre::Result;\n\nuse crate::config::Settings;\nuse crate::file::remove_all;\nuse crate::ui::prompt;\nuse crate::{dirs, env, file};\n\n/// Removes mise CLI and all related data\n///\n/// Skips config directory by default.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment)]\npub struct Implode {\n    /// List directories that would be removed without actually removing them\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    dry_run: bool,\n\n    /// Also remove config directory\n    #[clap(long, verbatim_doc_comment)]\n    config: bool,\n}\n\nimpl Implode {\n    pub fn run(self) -> Result<()> {\n        let mut files = vec![*dirs::STATE, *dirs::DATA, *dirs::CACHE, &*env::MISE_BIN];\n        if self.config {\n            files.push(&dirs::CONFIG);\n        }\n        for f in files.into_iter().filter(|d| d.exists()) {\n            if self.dry_run {\n                miseprintln!(\"rm -rf {}\", f.display());\n            }\n\n            if self.confirm_remove(f)? {\n                if f.is_dir() {\n                    remove_all(f)?;\n                } else {\n                    file::remove_file(f)?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn confirm_remove(&self, f: &Path) -> Result<bool> {\n        let settings = Settings::try_get()?;\n        if self.dry_run {\n            Ok(false)\n        } else if settings.yes {\n            Ok(true)\n        } else {\n            let r = prompt::confirm(format!(\"remove {} ?\", f.display()))?;\n            Ok(r)\n        }\n    }\n}\n"
  },
  {
    "path": "src/cli/install.rs",
    "content": "use std::collections::HashSet;\nuse std::str::FromStr;\nuse std::sync::Arc;\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::config::Settings;\nuse crate::duration::parse_into_timestamp;\nuse crate::hooks::Hooks;\nuse crate::toolset::{InstallOptions, ResolveOptions, ToolRequest, ToolSource, Toolset};\nuse crate::{config, env, exit, hooks};\nuse clap::ValueHint;\nuse eyre::Result;\nuse itertools::Itertools;\nuse jiff::Timestamp;\nuse std::path::PathBuf;\n\n/// Install a tool version\n///\n/// Installs a tool version to `~/.local/share/mise/installs/<PLUGIN>/<VERSION>`\n/// Installing alone will not activate the tools so they won't be in PATH.\n/// To install and/or activate in one command, use `mise use` which will create a `mise.toml` file\n/// in the current directory to activate this tool when inside the directory.\n/// Alternatively, run `mise exec <TOOL>@<VERSION> -- <COMMAND>` to execute a tool without creating config files.\n///\n/// Tools will be installed in parallel. To disable, set `--jobs=1` or `MISE_JOBS=1`\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"i\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Install {\n    /// Tool(s) to install\n    /// e.g.: node@20\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: Option<Vec<ToolArg>>,\n\n    /// Force reinstall even if already installed\n    #[clap(long, short, requires = \"tool\")]\n    force: bool,\n\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    jobs: Option<usize>,\n\n    /// Show what would be installed without actually installing\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    dry_run: bool,\n\n    /// Show installation output\n    ///\n    /// This argument will print plugin output such as download, configuration, and compilation output.\n    #[clap(long, short, action = clap::ArgAction::Count)]\n    verbose: u8,\n\n    /// Only install versions released before this date\n    ///\n    /// Supports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\n    #[clap(long, verbatim_doc_comment)]\n    before: Option<String>,\n\n    /// Like --dry-run but exits with code 1 if there are tools to install\n    ///\n    /// This is useful for scripts to check if tools need to be installed.\n    #[clap(long, verbatim_doc_comment)]\n    dry_run_code: bool,\n\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets --jobs=1\n    #[clap(long, overrides_with = \"jobs\")]\n    raw: bool,\n\n    /// [experimental] Install tool(s) to a shared directory\n    ///\n    /// Installs to the specified directory instead of the default install location.\n    /// May require elevated permissions depending on the path.\n    #[clap(long, verbatim_doc_comment, value_hint = ValueHint::DirPath, conflicts_with = \"system\")]\n    shared: Option<PathBuf>,\n\n    /// [experimental] Install tool(s) to the system-wide shared directory\n    ///\n    /// Installs to /usr/local/share/mise/installs (or MISE_SYSTEM_DATA_DIR/installs).\n    /// May require elevated permissions (e.g. sudo).\n    #[clap(long, verbatim_doc_comment, conflicts_with = \"shared\")]\n    system: bool,\n}\n\nimpl Install {\n    fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    #[async_backtrace::framed]\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        match &self.tool {\n            Some(runtime) => {\n                let original_tool_args = env::TOOL_ARGS.read().unwrap().clone();\n                env::TOOL_ARGS.write().unwrap().clone_from(runtime);\n                self.install_runtimes(config, runtime, original_tool_args)\n                    .await?\n            }\n            None => self.install_missing_runtimes(config).await?,\n        };\n        Ok(())\n    }\n\n    #[async_backtrace::framed]\n    async fn install_runtimes(\n        &self,\n        mut config: Arc<Config>,\n        runtimes: &[ToolArg],\n        original_tool_args: Vec<ToolArg>,\n    ) -> Result<()> {\n        let trs = config.get_tool_request_set().await?;\n\n        // Expand wildcards (e.g., \"pipx:*\") to actual ToolArgs from config\n        let mut has_unmatched_wildcard = false;\n        let expanded_runtimes: Vec<ToolArg> = runtimes\n            .iter()\n            .flat_map(|ta| {\n                if let Some(backend_prefix) = ta.ba.short.strip_suffix(\":*\") {\n                    // Find all tools in config with this backend prefix\n                    let matching: Vec<_> = trs\n                        .tools\n                        .keys()\n                        .filter(|ba| {\n                            ba.short.starts_with(&format!(\"{backend_prefix}:\"))\n                                && ba.tool_name != \"*\"\n                        })\n                        .filter_map(|ba| ToolArg::from_str(&ba.short).ok())\n                        .collect();\n                    if matching.is_empty() {\n                        warn!(\"no tools found in config matching {}\", ta.ba.short);\n                        has_unmatched_wildcard = true;\n                    }\n                    return matching;\n                }\n                vec![ta.clone()]\n            })\n            .collect();\n\n        // If only wildcards were provided and none matched, exit early\n        if expanded_runtimes.is_empty() && has_unmatched_wildcard {\n            return Ok(());\n        }\n\n        let tools: HashSet<String> = expanded_runtimes\n            .iter()\n            .map(|ta| ta.ba.short.clone())\n            .collect();\n        // Collect inactive tool names before trs borrow is consumed\n        let inactive_tools: Vec<String> = expanded_runtimes\n            .iter()\n            .filter(|ta| {\n                trs.sources\n                    .get(ta.ba.as_ref())\n                    .is_none_or(|s| s.is_argument())\n            })\n            .map(|ta| ta.ba.short.clone())\n            .collect();\n        let mut ts: Toolset = trs.filter_by_tool(tools).into();\n        let tool_versions = self.get_requested_tool_versions(&ts, &expanded_runtimes)?;\n        let mut versions = if tool_versions.is_empty() {\n            warn!(\"no runtimes to install\");\n            warn!(\"specify a version with `mise install <PLUGIN>@<VERSION>`\");\n            vec![]\n        } else {\n            ts.install_all_versions(&mut config, tool_versions, &self.install_opts()?)\n                .await?\n        };\n        // In dry-run mode, check if any tools would be installed before filtering\n        if self.is_dry_run() {\n            if self.dry_run_code {\n                let has_work = versions.iter().any(|tv| {\n                    if let Ok(backend) = tv.backend() {\n                        !backend.is_version_installed(&config, tv, true)\n                    } else {\n                        true\n                    }\n                });\n                if has_work {\n                    exit::exit(1);\n                }\n            }\n            return Ok(());\n        }\n\n        // because we may be installing a tool that is not in config, we need to restore the original tool args and reset everything\n        env::TOOL_ARGS\n            .write()\n            .unwrap()\n            .clone_from(&original_tool_args);\n        let config = Config::reset().await?;\n        let ts = config.get_toolset().await?;\n        let current_versions = ts.list_current_versions();\n        // ensure that only current versions are sent to lockfile rebuild\n        versions.retain(|tv| current_versions.iter().any(|(_, cv)| tv == cv));\n\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &versions).await?;\n\n        // Warn about tools that were installed but not in any config file\n        if !inactive_tools.is_empty() {\n            let tool_list = inactive_tools.join(\", \");\n            let use_cmds: Vec<String> = inactive_tools\n                .iter()\n                .map(|t| format!(\"  mise use {t}\"))\n                .collect();\n            warn!(\n                \"{tool_list} installed but not activated — {} not in any config file.\\nTo install and activate, run:\\n{}\",\n                if inactive_tools.len() == 1 {\n                    \"it is\"\n                } else {\n                    \"they are\"\n                },\n                use_cmds.join(\"\\n\"),\n            );\n        }\n\n        Ok(())\n    }\n\n    fn install_opts(&self) -> Result<InstallOptions> {\n        let install_dir = if self.system {\n            Some(env::MISE_SYSTEM_INSTALLS_DIR.clone())\n        } else {\n            self.shared.clone()\n        };\n        Ok(InstallOptions {\n            force: self.force,\n            jobs: self.jobs,\n            raw: self.raw,\n            missing_args_only: false,\n            resolve_options: ResolveOptions {\n                use_locked_version: true,\n                latest_versions: true,\n                before_date: self.get_before_date()?,\n            },\n            dry_run: self.is_dry_run(),\n            locked: Settings::get().locked,\n            install_dir,\n            ..Default::default()\n        })\n    }\n\n    /// Get the before_date from CLI flag or settings\n    fn get_before_date(&self) -> Result<Option<Timestamp>> {\n        if let Some(before) = &self.before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        if let Some(before) = &Settings::get().install_before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        Ok(None)\n    }\n\n    fn get_requested_tool_versions(\n        &self,\n        ts: &Toolset,\n        runtimes: &[ToolArg],\n    ) -> Result<Vec<ToolRequest>> {\n        let mut requests = vec![];\n        for ta in ToolArg::double_tool_condition(runtimes)? {\n            match ta.tvr {\n                // user provided an explicit version\n                Some(tv) => requests.push(tv),\n                None => {\n                    match ts.versions.get(ta.ba.as_ref()) {\n                        // the tool is in config so fetch the params from config\n                        // this may match multiple versions of one tool (e.g.: python)\n                        Some(tvl) => {\n                            for tvr in &tvl.requests {\n                                requests.push(tvr.clone());\n                            }\n                        }\n                        // in this case the user specified a tool which is not in config\n                        // so we default to @latest with no options\n                        None => {\n                            let tvr = ToolRequest::Version {\n                                backend: ta.ba.clone(),\n                                version: \"latest\".into(),\n                                options: ta.ba.opts(),\n                                source: ToolSource::Argument,\n                            };\n                            requests.push(tvr);\n                        }\n                    }\n                }\n            }\n        }\n        Ok(requests)\n    }\n\n    async fn install_missing_runtimes(&self, mut config: Arc<Config>) -> eyre::Result<()> {\n        let trs = measure!(\"get_tool_request_set\", {\n            config.get_tool_request_set().await?\n        });\n\n        // Install plugins from [plugins] config section first\n        // This must happen before checking for missing tools so env-only plugins get installed\n        Toolset::ensure_config_plugins_installed(&config, self.is_dry_run()).await?;\n\n        // Check for tools that don't exist in the registry\n        // These were tracked during build() before being filtered out\n        for ba in &trs.unknown_tools {\n            // This will error with a proper message like \"tool not found in mise tool registry\"\n            ba.backend()?;\n        }\n        let missing = measure!(\"fetching missing runtimes\", {\n            trs.missing_tools(&config)\n                .await\n                .into_iter()\n                .cloned()\n                .collect_vec()\n        });\n        let has_missing = !missing.is_empty();\n        let versions = if missing.is_empty() {\n            measure!(\"run_postinstall_hook\", {\n                info!(\"all tools are installed\");\n                hooks::run_one_hook(\n                    &config,\n                    config.get_toolset().await?,\n                    Hooks::Postinstall,\n                    None,\n                )\n                .await;\n                vec![]\n            })\n        } else {\n            let mut ts = Toolset::from(trs.clone());\n            measure!(\"install_all_versions\", {\n                ts.install_all_versions(&mut config, missing, &self.install_opts()?)\n                    .await?\n            })\n        };\n        if self.is_dry_run() {\n            if self.dry_run_code && has_missing {\n                exit::exit(1);\n            }\n            return Ok(());\n        }\n        measure!(\"rebuild_shims_and_runtime_symlinks\", {\n            let ts = config.get_toolset().await?;\n            config::rebuild_shims_and_runtime_symlinks(&config, ts, &versions).await?;\n        });\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise install node@20.0.0</bold>  # install specific node version\n    $ <bold>mise install node@20</bold>      # install fuzzy node version\n    $ <bold>mise install node</bold>         # install version specified in mise.toml\n    $ <bold>mise install</bold>              # installs everything specified in mise.toml\n\"#\n);\n"
  },
  {
    "path": "src/cli/install_into.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolsetBuilder;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse clap::ValueHint;\nuse eyre::{Result, eyre};\nuse std::{path::PathBuf, sync::Arc};\n\n/// Install a tool version to a specific path\n///\n/// Used for building a tool to a directory for use outside of mise\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct InstallInto {\n    /// Tool to install\n    /// e.g.: node@20\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: ToolArg,\n\n    /// Path to install the tool into\n    #[clap(value_hint = ValueHint::DirPath)]\n    path: PathBuf,\n}\n\nimpl InstallInto {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let ts = Arc::new(\n            ToolsetBuilder::new()\n                .with_args(std::slice::from_ref(&self.tool))\n                .build(&config)\n                .await?,\n        );\n        let mut tv = ts\n            .versions\n            .get(self.tool.ba.as_ref())\n            .ok_or_else(|| eyre!(\"Tool not found\"))?\n            .versions\n            .first()\n            .unwrap()\n            .clone();\n        let backend = tv.backend()?;\n        let mpr = MultiProgressReport::get();\n        let install_ctx = InstallContext {\n            config: config.clone(),\n            ts: ts.clone(),\n            pr: mpr.add(&tv.style()),\n            force: true,\n            dry_run: false,\n            locked: false, // install-into doesn't support locked mode\n        };\n        tv.install_path = Some(self.path.clone());\n        backend.install_version(install_ctx, tv).await?;\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # install node@20.0.0 into ./mynode\n    $ <bold>mise install-into node@20.0.0 ./mynode && ./mynode/bin/node -v</bold>\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/latest.rs",
    "content": "use color_eyre::eyre::{Result, bail};\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::toolset::ToolRequest;\nuse crate::ui::multi_progress_report::MultiProgressReport;\n\n/// Gets the latest available version for a plugin\n///\n/// Supports prefixes such as `node@20` to get the latest version of node 20.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Latest {\n    /// Tool to get the latest version of\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: ToolArg,\n\n    /// The version prefix to use when querying the latest version\n    /// same as the first argument after the \"@\"\n    /// used for asdf compatibility\n    #[clap(hide = true)]\n    asdf_version: Option<String>,\n\n    /// Show latest installed instead of available version\n    #[clap(short, long)]\n    installed: bool,\n}\n\nimpl Latest {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let mut prefix = match self.tool.tvr {\n            None => self.asdf_version,\n            Some(ToolRequest::Version { version, .. }) => Some(version),\n            _ => bail!(\"invalid version: {}\", self.tool.style()),\n        };\n\n        let backend = self.tool.ba.backend()?;\n        let mpr = MultiProgressReport::get();\n        if let Some(plugin) = backend.plugin() {\n            plugin.ensure_installed(&config, &mpr, false, false).await?;\n        }\n        if let Some(v) = prefix {\n            prefix = Some(config.resolve_alias(&backend, &v).await?);\n        }\n\n        let latest_version = if self.installed {\n            backend.latest_installed_version(prefix)?\n        } else {\n            backend.latest_version(&config, prefix).await?\n        };\n        if let Some(version) = latest_version {\n            miseprintln!(\"{}\", version);\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise latest node@20</bold>  # get the latest version of node 20\n    20.0.0\n\n    $ <bold>mise latest node</bold>     # get the latest stable version of node\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/link.rs",
    "content": "use std::path::PathBuf;\n\nuse clap::ValueHint;\nuse color_eyre::eyre::{Result, eyre};\nuse console::style;\nuse eyre::bail;\nuse path_absolutize::Absolutize;\n\nuse crate::file::{make_symlink, remove_all};\nuse crate::{cli::args::ToolArg, config::Config};\nuse crate::{config, file};\n\n/// Symlinks a tool version into mise\n///\n/// Use this for adding installs either custom compiled outside mise or built with a different tool.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"ln\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Link {\n    /// Tool name and version to create a symlink for\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: ToolArg,\n\n    /// The local path to the tool version\n    /// e.g.: ~/.nvm/versions/node/v20.0.0\n    #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)]\n    path: PathBuf,\n\n    /// Overwrite an existing tool version if it exists\n    #[clap(long, short = 'f')]\n    force: bool,\n}\n\nimpl Link {\n    pub async fn run(self) -> Result<()> {\n        let version = match self.tool.tvr {\n            Some(ref tvr) => tvr.version(),\n            None => bail!(\"must provide a version for {}\", self.tool.style()),\n        };\n        let path = self.path.absolutize()?;\n        if !path.exists() {\n            warn!(\n                \"Target path {} does not exist\",\n                style(path.to_string_lossy()).cyan().for_stderr()\n            );\n        }\n        let target = self.tool.ba.installs_path.join(version);\n        if target.exists() {\n            if self.force {\n                remove_all(&target)?;\n            } else {\n                return Err(eyre!(\n                    \"Tool version {} already exists, use {} to overwrite\",\n                    self.tool.style(),\n                    style(\"--force\").yellow().for_stderr()\n                ));\n            }\n        }\n        file::create_dir_all(target.parent().unwrap())?;\n        make_symlink(&path, &target)?;\n\n        let config = Config::reset().await?;\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # build node-20.0.0 with node-build and link it into mise\n    $ <bold>node-build 20.0.0 ~/.nodes/20.0.0</bold>\n    $ <bold>mise link node@20.0.0 ~/.nodes/20.0.0</bold>\n\n    # have mise use the node version provided by Homebrew\n    $ <bold>brew install node</bold>\n    $ <bold>mise link node@brew $(brew --prefix node)</bold>\n    $ <bold>mise use node@brew</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/local.rs",
    "content": "use std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse color_eyre::eyre::{ContextCompat, Result, eyre};\nuse console::style;\nuse itertools::Itertools;\n\nuse crate::config::{Settings, config_file};\nuse crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME};\nuse crate::file::display_path;\nuse crate::{\n    cli::args::{BackendArg, ToolArg},\n    config::Config,\n};\nuse crate::{env, file};\n\n/// Sets/gets tool version in local .tool-versions or mise.toml\n///\n/// Use this to set a tool's version when within a directory\n/// Use `mise global` to set a tool version globally\n/// This uses `.tool-version` by default unless there is a `mise.toml` file or if `MISE_USE_TOML`\n/// is set. A future v2 release of mise will default to using `mise.toml`.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true, alias = \"l\", after_long_help = AFTER_LONG_HELP)]\npub struct Local {\n    /// Tool(s) to add to .tool-versions/mise.toml\n    /// e.g.: node@20\n    /// if this is a single tool with no version,\n    /// the current value of .tool-versions/mise.toml will be displayed\n    #[clap(value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    tool: Vec<ToolArg>,\n\n    /// Recurse up to find a .tool-versions file rather than using the current directory only\n    /// by default this command will only set the tool in the current directory (\"$PWD/.tool-versions\")\n    #[clap(short, long, verbatim_doc_comment)]\n    parent: bool,\n\n    /// Save fuzzy version to `.tool-versions`\n    /// e.g.: `mise local --fuzzy node@20` will save `node 20` to .tool-versions\n    /// This is the default behavior unless MISE_ASDF_COMPAT=1\n    #[clap(long, overrides_with = \"pin\")]\n    fuzzy: bool,\n\n    /// Get the path of the config file\n    #[clap(long)]\n    path: bool,\n\n    /// Save exact version to `.tool-versions`\n    /// e.g.: `mise local --pin node@20` will save `node 20.0.0` to .tool-versions\n    #[clap(long, verbatim_doc_comment, overrides_with = \"fuzzy\")]\n    pin: bool,\n\n    /// Remove the plugin(s) from .tool-versions\n    #[clap(long, value_name = \"PLUGIN\", aliases = [\"rm\", \"unset\"])]\n    remove: Option<Vec<BackendArg>>,\n}\n\nimpl Local {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let path = if self.parent {\n            get_parent_path()?\n        } else {\n            get_path()?\n        };\n        local(\n            &config,\n            &path,\n            self.tool,\n            self.remove,\n            self.pin,\n            self.fuzzy,\n            self.path,\n        )\n        .await\n    }\n}\n\nfn get_path() -> Result<PathBuf> {\n    let cwd = env::current_dir()?;\n    let mise_toml = cwd.join(MISE_DEFAULT_CONFIG_FILENAME.as_str());\n    let tool_versions = cwd.join(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str());\n    if mise_toml.exists() {\n        Ok(mise_toml)\n    } else if tool_versions.exists() {\n        Ok(tool_versions)\n    } else if *env::MISE_USE_TOML {\n        Ok(mise_toml)\n    } else {\n        Ok(tool_versions)\n    }\n}\n\npub fn get_parent_path() -> Result<PathBuf> {\n    let mut filenames = vec![MISE_DEFAULT_CONFIG_FILENAME.as_str()];\n    if !*env::MISE_USE_TOML {\n        filenames.push(MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str());\n    }\n    file::find_up(&env::current_dir()?, &filenames)\n        .wrap_err_with(|| eyre!(\"no {} file found\", filenames.join(\" or \"),))\n}\n\n#[allow(clippy::too_many_arguments)]\npub async fn local(\n    config: &Arc<Config>,\n    path: &Path,\n    runtime: Vec<ToolArg>,\n    remove: Option<Vec<BackendArg>>,\n    pin: bool,\n    fuzzy: bool,\n    show_path: bool,\n) -> Result<()> {\n    deprecated!(\n        \"local\",\n        \"mise local/global are deprecated. Use `mise use` instead.\"\n    );\n    let settings = Settings::try_get()?;\n    let cf = config_file::parse_or_init(path).await?;\n    if show_path {\n        miseprintln!(\"{}\", path.display());\n        return Ok(());\n    }\n\n    if let Some(plugins) = &remove {\n        for plugin in plugins {\n            cf.remove_tool(plugin)?;\n        }\n        let tools = plugins\n            .iter()\n            .map(|r| style(&r.short).blue().for_stderr().to_string())\n            .join(\" \");\n        miseprintln!(\"{} {} {tools}\", style(\"mise\").dim(), display_path(path));\n    }\n\n    if !runtime.is_empty() {\n        let runtimes = ToolArg::double_tool_condition(&runtime)?;\n        if cf.display_runtime(&runtimes)? {\n            return Ok(());\n        }\n        let pin = pin || (settings.asdf_compat && !fuzzy);\n        cf.add_runtimes(config, &runtimes, pin).await?;\n        let tools = runtimes.iter().map(|t| t.style()).join(\" \");\n        miseprintln!(\"{} {} {tools}\", style(\"mise\").dim(), display_path(path));\n    }\n\n    if !runtime.is_empty() || remove.is_some() {\n        trace!(\"saving config file {}\", display_path(path));\n        cf.save()?;\n    } else {\n        miseprint!(\"{}\", cf.dump()?)?;\n    }\n\n    Ok(())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n    # set the current version of node to 20.x for the current directory\n    # will use a precise version (e.g.: 20.0.0) in .tool-versions file\n    $ <bold>mise local node@20</bold>\n\n    # set node to 20.x for the current project (recurses up to find .tool-versions)\n    $ <bold>mise local -p node@20</bold>\n\n    # set the current version of node to 20.x for the current directory\n    # will use a fuzzy version (e.g.: 20) in .tool-versions file\n    $ <bold>mise local --fuzzy node@20</bold>\n\n    # removes node from .tool-versions\n    $ <bold>mise local --remove=node</bold>\n\n    # show the current version of node in .tool-versions\n    $ <bold>mise local node</bold>\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/lock.rs",
    "content": "use std::collections::BTreeSet;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse crate::config::Config;\nuse crate::file::display_path;\nuse crate::lockfile::{self, LockResolutionResult, Lockfile};\nuse crate::platform::Platform;\nuse crate::toolset::Toolset;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::{cli::args::ToolArg, config::Settings};\nuse console::style;\nuse eyre::{Result, bail};\nuse tokio::sync::Semaphore;\nuse tokio::task::JoinSet;\n\n/// A tool to lock for a specific lockfile target.\ntype LockTool = (crate::cli::args::BackendArg, crate::toolset::ToolVersion);\n\n/// Update lockfile checksums and URLs for all specified platforms\n///\n/// Updates checksums and download URLs for all platforms already specified in the lockfile.\n/// If no lockfile exists, shows what would be created based on the current configuration.\n/// This allows you to refresh lockfile data for platforms other than the one you're currently on.\n/// Operates on the lockfile in the current config root. Use TOOL arguments to target specific tools.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Lock {\n    /// Tool(s) to update in lockfile\n    /// e.g.: node python\n    /// If not specified, all tools in lockfile will be updated\n    #[clap(value_name = \"TOOL\", verbatim_doc_comment)]\n    pub tool: Vec<ToolArg>,\n\n    /// Number of jobs to run in parallel\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    pub jobs: Option<usize>,\n\n    /// Show what would be updated without making changes\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    pub dry_run: bool,\n\n    /// Comma-separated list of platforms to target\n    /// e.g.: linux-x64,macos-arm64,windows-x64\n    /// If not specified, all platforms already in lockfile will be updated\n    #[clap(long, short, value_delimiter = ',', verbatim_doc_comment)]\n    pub platform: Vec<String>,\n\n    /// Update mise.local.lock instead of mise.lock\n    /// Use for tools defined in .local.toml configs\n    #[clap(long, verbatim_doc_comment)]\n    pub local: bool,\n}\n\nimpl Lock {\n    pub async fn run(self) -> Result<()> {\n        let settings = Settings::get();\n        if settings.locked {\n            bail!(\n                \"mise lock is disabled in --locked mode\\nhint: Remove --locked or unset MISE_LOCKED=1\"\n            );\n        }\n        let config = Config::get().await?;\n\n        let ts = config.get_toolset().await?;\n\n        // Collect distinct lockfile targets from config files\n        let lockfile_targets = self.get_lockfile_targets(&config);\n        let mut has_lock_targets = false;\n\n        for (lockfile_path, config_paths) in &lockfile_targets {\n            let tools = self.get_tools_to_lock(&config, ts, lockfile_path, config_paths);\n\n            if tools.is_empty() {\n                // `tools` can be empty either because config has no tools, or because a filter excludes all.\n                // For unfiltered runs (`mise lock`), this means \"prune all stale lockfile entries\".\n                let mut lockfile = Lockfile::read(lockfile_path)?;\n                if self.dry_run {\n                    let stale_tools = self.stale_entries_if_pruned(&lockfile, &tools);\n                    self.show_stale_prune_message(lockfile_path, &stale_tools, true)?;\n                    if !stale_tools.is_empty() {\n                        has_lock_targets = true;\n                    }\n                } else {\n                    let pruned_tools = self.prune_stale_entries_if_needed(&mut lockfile, &tools);\n                    if !pruned_tools.is_empty() {\n                        lockfile.write(lockfile_path)?;\n                        self.show_stale_prune_message(lockfile_path, &pruned_tools, false)?;\n                        has_lock_targets = true;\n                    }\n                }\n                continue;\n            }\n            has_lock_targets = true;\n\n            let target_platforms = self.determine_target_platforms(lockfile_path)?;\n\n            miseprintln!(\n                \"{} Targeting {} platform(s) for {}: {}\",\n                style(\"→\").cyan(),\n                target_platforms.len(),\n                style(display_path(lockfile_path)).cyan(),\n                target_platforms\n                    .iter()\n                    .map(|p| p.to_key())\n                    .collect::<Vec<_>>()\n                    .join(\", \")\n            );\n\n            miseprintln!(\n                \"{} Processing {} tool(s): {}\",\n                style(\"→\").cyan(),\n                tools.len(),\n                tools\n                    .iter()\n                    .map(|(ba, tv)| format!(\"{}@{}\", ba.short, tv.version))\n                    .collect::<Vec<_>>()\n                    .join(\", \")\n            );\n\n            if self.dry_run {\n                self.show_dry_run(&tools, &target_platforms)?;\n                if self.is_unfiltered_lock_run() {\n                    let lockfile = Lockfile::read(lockfile_path)?;\n                    let stale_tools = self.stale_entries_if_pruned(&lockfile, &tools);\n                    self.show_stale_prune_message(lockfile_path, &stale_tools, true)?;\n                }\n                continue;\n            }\n\n            // Process tools and update lockfile\n            let mut lockfile = Lockfile::read(lockfile_path)?;\n            self.prune_stale_entries_if_needed(&mut lockfile, &tools);\n            let results = self\n                .process_tools(&settings, &tools, &target_platforms, &mut lockfile)\n                .await?;\n\n            // Save lockfile\n            lockfile.write(lockfile_path)?;\n\n            // Print summary\n            let successful = results.iter().filter(|(_, _, ok)| *ok).count();\n            let skipped = results.len() - successful;\n            miseprintln!(\n                \"{} Updated {} platform entries ({} skipped)\",\n                style(\"✓\").green(),\n                successful,\n                skipped\n            );\n            miseprintln!(\n                \"{} Lockfile written to {}\",\n                style(\"✓\").green(),\n                style(display_path(lockfile_path)).cyan()\n            );\n        }\n\n        if !has_lock_targets {\n            miseprintln!(\"{} No tools configured to lock\", style(\"!\").yellow());\n        }\n\n        Ok(())\n    }\n\n    fn is_unfiltered_lock_run(&self) -> bool {\n        self.tool.is_empty()\n    }\n\n    fn prune_stale_entries_if_needed(\n        &self,\n        lockfile: &mut Lockfile,\n        tools: &[(crate::cli::args::BackendArg, crate::toolset::ToolVersion)],\n    ) -> BTreeSet<String> {\n        if !self.is_unfiltered_lock_run() {\n            return BTreeSet::new();\n        }\n        let (configured_tools, configured_backends) = self.configured_tool_selectors(tools);\n        let stale_tools =\n            self.stale_entries_for_selectors(lockfile, &configured_tools, &configured_backends);\n        if !stale_tools.is_empty() {\n            lockfile.retain_tools_by_short_or_backend(&configured_tools, &configured_backends);\n        }\n        stale_tools\n    }\n\n    fn stale_entries_if_pruned(\n        &self,\n        lockfile: &Lockfile,\n        tools: &[(crate::cli::args::BackendArg, crate::toolset::ToolVersion)],\n    ) -> BTreeSet<String> {\n        if !self.is_unfiltered_lock_run() {\n            return BTreeSet::new();\n        }\n        let (configured_tools, configured_backends) = self.configured_tool_selectors(tools);\n        self.stale_entries_for_selectors(lockfile, &configured_tools, &configured_backends)\n    }\n\n    fn configured_tool_selectors(\n        &self,\n        tools: &[(crate::cli::args::BackendArg, crate::toolset::ToolVersion)],\n    ) -> (BTreeSet<String>, BTreeSet<String>) {\n        let configured_tools: BTreeSet<String> =\n            tools.iter().map(|(ba, _)| ba.short.clone()).collect();\n        let configured_backends: BTreeSet<String> = tools.iter().map(|(ba, _)| ba.full()).collect();\n        (configured_tools, configured_backends)\n    }\n\n    fn stale_entries_for_selectors(\n        &self,\n        lockfile: &Lockfile,\n        configured_tools: &BTreeSet<String>,\n        configured_backends: &BTreeSet<String>,\n    ) -> BTreeSet<String> {\n        lockfile.stale_tool_shorts(configured_tools, configured_backends)\n    }\n\n    fn show_stale_prune_message(\n        &self,\n        lockfile_path: &Path,\n        stale_tools: &BTreeSet<String>,\n        dry_run: bool,\n    ) -> Result<()> {\n        if stale_tools.is_empty() {\n            return Ok(());\n        }\n        let entry_word = if stale_tools.len() == 1 {\n            \"entry\"\n        } else {\n            \"entries\"\n        };\n        let (icon, message) = if dry_run {\n            (style(\"→\").yellow(), \"Dry run - would prune\")\n        } else {\n            (style(\"✓\").green(), \"Pruned\")\n        };\n        miseprintln!(\n            \"{} {} {} stale tool {} from {}: {}\",\n            icon,\n            message,\n            stale_tools.len(),\n            entry_word,\n            style(display_path(lockfile_path)).cyan(),\n            stale_tools.iter().cloned().collect::<Vec<_>>().join(\", \")\n        );\n        Ok(())\n    }\n\n    /// Collect distinct lockfile targets from config files.\n    /// Returns an ordered map of lockfile_path -> list of config paths that contribute to it.\n    fn get_lockfile_targets(&self, config: &Config) -> indexmap::IndexMap<PathBuf, Vec<PathBuf>> {\n        let mut targets: indexmap::IndexMap<PathBuf, Vec<PathBuf>> = indexmap::IndexMap::new();\n        for (path, cf) in config.config_files.iter() {\n            if !cf.source().is_mise_toml() {\n                continue;\n            }\n            let (lockfile_path, is_local) = lockfile::lockfile_path_for_config(path);\n            if self.local && !is_local {\n                continue;\n            }\n            targets.entry(lockfile_path).or_default().push(path.clone());\n        }\n        targets\n    }\n\n    fn determine_target_platforms(&self, lockfile_path: &Path) -> Result<Vec<Platform>> {\n        if !self.platform.is_empty() {\n            // User specified platforms explicitly\n            return Platform::parse_multiple(&self.platform);\n        }\n\n        Ok(lockfile::determine_target_platforms(lockfile_path))\n    }\n\n    /// Collect tools that belong to a given lockfile target.\n    /// Only includes tools whose source config maps to the target lockfile path.\n    fn get_tools_to_lock(\n        &self,\n        config: &Config,\n        ts: &Toolset,\n        target_lockfile_path: &Path,\n        config_paths: &[PathBuf],\n    ) -> Vec<LockTool> {\n        let config_paths_set: BTreeSet<&PathBuf> = config_paths.iter().collect();\n\n        let mut all_tools: Vec<LockTool> = Vec::new();\n        let mut seen: BTreeSet<(String, String)> = BTreeSet::new();\n\n        // First pass: tools from the resolved toolset whose source maps to this lockfile\n        for (backend, tv) in ts.list_current_versions() {\n            if let Some(source_path) = tv.request.source().path() {\n                let (source_lockfile, _) = lockfile::lockfile_path_for_config(source_path);\n                if source_lockfile != target_lockfile_path {\n                    continue;\n                }\n            } else {\n                // Tools without a source path (env vars, CLI args) go to mise.lock only\n                let is_base_lockfile = target_lockfile_path\n                    .file_name()\n                    .and_then(|n| n.to_str())\n                    .is_some_and(|n| n == \"mise.lock\");\n                if !is_base_lockfile {\n                    continue;\n                }\n            }\n            let key = (backend.ba().short.clone(), tv.version.clone());\n            if seen.insert(key) {\n                all_tools.push((backend.ba().as_ref().clone(), tv));\n            }\n        }\n\n        // Second pass: iterate config files matching this lockfile to catch\n        // tools that were overridden by a higher-priority config\n        for (path, cf) in config.config_files.iter() {\n            if !config_paths_set.contains(path) {\n                continue;\n            }\n            if let Ok(trs) = cf.to_tool_request_set() {\n                for (ba, requests, _source) in trs.iter() {\n                    for request in requests {\n                        if let Ok(backend) = ba.backend() {\n                            // Check if the resolved toolset has a matching version\n                            if let Some(resolved_tv) = ts.versions.get(ba.as_ref()) {\n                                for tv in &resolved_tv.versions {\n                                    if tv.request.version() == request.version() {\n                                        let key = (ba.short.clone(), tv.version.clone());\n                                        if seen.insert(key) {\n                                            all_tools.push((ba.as_ref().clone(), tv.clone()));\n                                        }\n                                    }\n                                }\n                            }\n                            // For \"latest\" or prefix requests not yet matched, find the\n                            // best installed version (handles overridden tools)\n                            if request.version() == \"latest\" {\n                                let installed = backend.list_installed_versions();\n                                if let Some(latest_version) = installed.iter().max_by(|a, b| {\n                                    versions::Versioning::new(a).cmp(&versions::Versioning::new(b))\n                                }) {\n                                    let key = (ba.short.clone(), latest_version.clone());\n                                    if seen.insert(key) {\n                                        let tv = crate::toolset::ToolVersion::new(\n                                            request.clone(),\n                                            latest_version.clone(),\n                                        );\n                                        all_tools.push((ba.as_ref().clone(), tv));\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        if self.tool.is_empty() {\n            all_tools\n        } else {\n            let specified: BTreeSet<String> =\n                self.tool.iter().map(|t| t.ba.short.clone()).collect();\n            all_tools\n                .into_iter()\n                .filter(|(ba, _)| specified.contains(&ba.short))\n                .collect()\n        }\n    }\n\n    fn show_dry_run(&self, tools: &[LockTool], platforms: &[Platform]) -> Result<()> {\n        miseprintln!(\"{} Dry run - would update:\", style(\"→\").yellow());\n        for (ba, tv) in tools {\n            let backend = crate::backend::get(ba);\n            for platform in platforms {\n                // Expand platform variants just like process_tools does\n                let variants = if let Some(ref backend) = backend {\n                    backend.platform_variants(platform)\n                } else {\n                    vec![platform.clone()]\n                };\n                for variant in variants {\n                    miseprintln!(\n                        \"  {} {}@{} for {}\",\n                        style(\"✓\").green(),\n                        style(&ba.short).bold(),\n                        tv.version,\n                        style(variant.to_key()).blue()\n                    );\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn process_tools(\n        &self,\n        settings: &Settings,\n        tools: &[LockTool],\n        platforms: &[Platform],\n        lockfile: &mut Lockfile,\n    ) -> Result<Vec<(String, String, bool)>> {\n        let jobs = self.jobs.unwrap_or(settings.jobs);\n        let semaphore = Arc::new(Semaphore::new(jobs));\n        let mut jset: JoinSet<LockResolutionResult> = JoinSet::new();\n        let mut results = Vec::new();\n\n        let mpr = MultiProgressReport::get();\n\n        // Collect all platform variants for each tool/platform combination\n        let mut all_tasks: Vec<(\n            crate::cli::args::BackendArg,\n            crate::toolset::ToolVersion,\n            Platform,\n        )> = Vec::new();\n        for (ba, tv) in tools {\n            let backend = crate::backend::get(ba);\n            for platform in platforms {\n                // Get all variants for this platform from the backend\n                let variants = if let Some(ref backend) = backend {\n                    backend.platform_variants(platform)\n                } else {\n                    vec![platform.clone()]\n                };\n                for variant in variants {\n                    all_tasks.push((ba.clone(), tv.clone(), variant));\n                }\n            }\n        }\n\n        let total_tasks = all_tasks.len();\n        let pr = mpr.add(\"lock\");\n        pr.set_length(total_tasks as u64);\n\n        // Spawn tasks for each tool/platform variant combination\n        for (ba, tv, platform) in all_tasks {\n            let semaphore = semaphore.clone();\n            let backend = crate::backend::get(&ba);\n\n            jset.spawn(async move {\n                let _permit = semaphore.acquire().await;\n                lockfile::resolve_tool_lock_info(ba, tv, platform, backend).await\n            });\n        }\n\n        // Collect all results\n        let mut completed = 0;\n        while let Some(result) = jset.join_next().await {\n            completed += 1;\n            match result {\n                Ok(resolution) => {\n                    let short = resolution.0.clone();\n                    let version = resolution.1.clone();\n                    let platform_key = resolution.3.to_key();\n                    let ok = resolution.4.is_ok();\n                    if let Err(msg) = &resolution.4 {\n                        debug!(\"{msg}\");\n                    }\n                    pr.set_message(format!(\"{}@{} {}\", short, version, platform_key));\n                    pr.set_position(completed);\n                    lockfile::apply_lock_result(lockfile, resolution);\n                    results.push((short, platform_key, ok));\n                }\n                Err(e) => {\n                    warn!(\"Task failed: {}\", e);\n                }\n            }\n        }\n\n        pr.finish_with_message(format!(\"{} platform entries\", total_tasks));\n        Ok(results)\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise lock</bold>                       # update lockfile for all common platforms\n    $ <bold>mise lock node python</bold>           # update only node and python\n    $ <bold>mise lock --platform linux-x64</bold>  # update only linux-x64 platform\n    $ <bold>mise lock --dry-run</bold>             # show what would be updated\n    $ <bold>mise lock --local</bold>               # update mise.local.lock for local configs\n\"#\n);\n\n#[cfg(test)]\nmod tests {\n    use super::Lock;\n    use crate::cli::args::ToolArg;\n    use crate::lockfile::{Lockfile, PlatformInfo};\n    use crate::toolset::{ToolRequest, ToolSource, ToolVersion};\n    use std::collections::BTreeMap;\n    use std::str::FromStr;\n    use std::sync::Arc;\n\n    fn lock_cmd(tool_filters: &[&str]) -> Lock {\n        Lock {\n            tool: tool_filters\n                .iter()\n                .map(|tool| ToolArg::from_str(tool).unwrap())\n                .collect(),\n            jobs: None,\n            dry_run: false,\n            platform: vec![],\n            local: false,\n        }\n    }\n\n    fn lockfile_with_dummy() -> Lockfile {\n        let mut lockfile = Lockfile::default();\n        lockfile.set_platform_info(\n            \"dummy\",\n            \"1.0.0\",\n            Some(\"asdf:dummy\"),\n            &BTreeMap::new(),\n            \"linux-x64\",\n            PlatformInfo {\n                checksum: Some(\"sha256:dummy\".to_string()),\n                ..Default::default()\n            },\n        );\n        lockfile\n    }\n\n    fn lockfile_with_legacy_aqua_jq() -> Lockfile {\n        let mut lockfile = Lockfile::default();\n        lockfile.set_platform_info(\n            \"jq\",\n            \"1.7.1\",\n            Some(\"aqua:jqlang/jq\"),\n            &BTreeMap::new(),\n            \"linux-x64\",\n            PlatformInfo {\n                checksum: Some(\"sha256:jq\".to_string()),\n                ..Default::default()\n            },\n        );\n        lockfile\n    }\n\n    fn configured_tool(\n        backend: &str,\n        version: &str,\n    ) -> (crate::cli::args::BackendArg, ToolVersion) {\n        let ba = crate::cli::args::BackendArg::new(backend.to_string(), Some(backend.to_string()));\n        let request =\n            ToolRequest::new(Arc::new(ba.clone()), version, ToolSource::Argument).unwrap();\n        let tv = ToolVersion::new(request, version.to_string());\n        (ba, tv)\n    }\n\n    #[test]\n    fn test_is_unfiltered_lock_run_without_tool_filter() {\n        let cmd = lock_cmd(&[]);\n        assert!(cmd.is_unfiltered_lock_run());\n    }\n\n    #[test]\n    fn test_is_not_unfiltered_lock_run_with_tool_filter() {\n        let cmd = lock_cmd(&[\"tiny\"]);\n        assert!(!cmd.is_unfiltered_lock_run());\n    }\n\n    #[test]\n    fn test_prune_stale_entries_with_empty_tools_prunes_all_entries() {\n        let cmd = lock_cmd(&[]);\n        let mut lockfile = lockfile_with_dummy();\n        let pruned = cmd.prune_stale_entries_if_needed(&mut lockfile, &[]);\n        assert_eq!(\n            pruned,\n            std::collections::BTreeSet::from([\"dummy\".to_string()])\n        );\n        assert!(lockfile.all_platform_keys().is_empty());\n    }\n\n    #[test]\n    fn test_prune_stale_entries_with_filter_keeps_existing_entries() {\n        let cmd = lock_cmd(&[\"tiny\"]);\n        let mut lockfile = lockfile_with_dummy();\n        let pruned = cmd.prune_stale_entries_if_needed(&mut lockfile, &[]);\n        assert!(pruned.is_empty());\n        assert_eq!(\n            lockfile.all_platform_keys(),\n            std::collections::BTreeSet::from([\"linux-x64\".to_string()])\n        );\n    }\n\n    #[test]\n    fn test_prune_stale_entries_preserves_legacy_keyed_backend_match() {\n        let cmd = lock_cmd(&[]);\n        let mut lockfile = lockfile_with_legacy_aqua_jq();\n        let tools = vec![configured_tool(\"aqua:jqlang/jq\", \"1.7.1\")];\n\n        let pruned = cmd.prune_stale_entries_if_needed(&mut lockfile, &tools);\n        assert!(pruned.is_empty());\n\n        assert_eq!(\n            lockfile.all_platform_keys(),\n            std::collections::BTreeSet::from([\"linux-x64\".to_string()])\n        );\n    }\n}\n"
  },
  {
    "path": "src/cli/ls.rs",
    "content": "use comfy_table::{Attribute, Cell, Color};\nuse eyre::{Result, ensure};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse serde_derive::Serialize;\nuse std::collections::BTreeMap;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse versions::Versioning;\n\nuse crate::backend::Backend;\nuse crate::cli::args::BackendArg;\nuse crate::cli::prune;\nuse crate::config;\nuse crate::config::Config;\nuse crate::env;\nuse crate::runtime_symlinks::is_runtime_symlink;\nuse crate::toolset::{ToolRequestSet, ToolSource, ToolVersion, Toolset};\nuse crate::ui::table::MiseTable;\n\n/// List installed and active tool versions\n///\n/// This command lists tools that mise \"knows about\".\n/// These may be tools that are currently installed, or those\n/// that are in a config file (active) but may or may not be installed.\n///\n/// It's a useful command to get the current state of your tools.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"list\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Ls {\n    /// Only show tool versions from [TOOL]\n    #[clap(conflicts_with = \"tool_flag\")]\n    installed_tool: Option<Vec<BackendArg>>,\n\n    /// Only show tool versions currently specified in a mise.toml\n    #[clap(long, short)]\n    current: bool,\n\n    /// Only show tool versions currently specified in the global mise.toml\n    #[clap(long, short, conflicts_with = \"local\")]\n    global: bool,\n\n    /// Only show tool versions that are installed\n    /// (Hides tools defined in mise.toml but not installed)\n    #[clap(long, short)]\n    installed: bool,\n\n    /// Output in JSON format\n    #[clap(long, short = 'J')]\n    json: bool,\n\n    /// Only show tool versions currently specified in the local mise.toml\n    #[clap(long, short, conflicts_with = \"global\")]\n    local: bool,\n\n    /// Display missing tool versions\n    #[clap(long, short, conflicts_with = \"installed\")]\n    missing: bool,\n\n    /// Don't fetch information such as outdated versions\n    #[clap(long, short, hide = true)]\n    offline: bool,\n\n    #[clap(long = \"plugin\", short = 'p', hide = true)]\n    tool_flag: Option<BackendArg>,\n\n    /// Display all tracked config sources for tools\n    #[clap(long, conflicts_with_all = &[\"current\", \"global\", \"local\", \"prunable\"])]\n    all_sources: bool,\n\n    /// Don't display headers\n    #[clap(long, alias = \"no-headers\", verbatim_doc_comment, conflicts_with_all = &[\"json\"])]\n    no_header: bool,\n\n    /// Display whether a version is outdated\n    #[clap(long)]\n    outdated: bool,\n\n    /// Display versions matching this prefix\n    #[clap(long, requires = \"installed_tool\")]\n    prefix: Option<String>,\n\n    /// List only tools that can be pruned with `mise prune`\n    #[clap(long)]\n    prunable: bool,\n}\n\nimpl Ls {\n    pub async fn run(mut self) -> Result<()> {\n        let config = Config::get().await?;\n        self.installed_tool = self\n            .installed_tool\n            .or_else(|| self.tool_flag.clone().map(|p| vec![p]));\n        self.verify_plugin()?;\n\n        let (mut runtimes, sources_map) = if self.prunable {\n            (self.get_prunable_runtime_list(&config).await?, None)\n        } else if self.all_sources {\n            let (runtimes, sources_map) = self.get_all_sources_runtime_list(&config).await?;\n            (runtimes, Some(sources_map))\n        } else {\n            (self.get_runtime_list(&config).await?, None)\n        };\n        if self.current || self.global || self.local {\n            // TODO: global is a little weird: it will show global versions as the active ones even if\n            // they're overridden locally\n            runtimes.retain(|(_, _, _, source)| !source.is_unknown());\n        }\n        if self.installed {\n            let mut installed_runtimes = vec![];\n            for (ls, p, tv, source) in runtimes {\n                if p.is_version_installed(&config, &tv, true) {\n                    installed_runtimes.push((ls, p, tv, source));\n                }\n            }\n            runtimes = installed_runtimes;\n        }\n        if self.missing {\n            let mut missing_runtimes = vec![];\n            for (ls, p, tv, source) in runtimes {\n                if !p.is_version_installed(&config, &tv, true) {\n                    missing_runtimes.push((ls, p, tv, source));\n                }\n            }\n            runtimes = missing_runtimes;\n        }\n        if let Some(prefix) = &self.prefix {\n            runtimes.retain(|(_, _, tv, _)| tv.version.starts_with(prefix));\n        }\n        if self.json {\n            self.display_json(&config, runtimes, sources_map.as_ref())\n                .await\n        } else {\n            self.display_user(&config, runtimes, sources_map.as_ref())\n                .await\n        }\n    }\n\n    fn verify_plugin(&self) -> Result<()> {\n        if let Some(plugins) = &self.installed_tool {\n            for ba in plugins {\n                if let Some(plugin) = ba.backend()?.plugin() {\n                    ensure!(plugin.is_installed(), \"{ba} is not installed\");\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn display_json(\n        &self,\n        config: &Arc<Config>,\n        runtimes: Vec<RuntimeRow<'_>>,\n        sources_map: Option<&SourcesMap>,\n    ) -> Result<()> {\n        if let Some(plugins) = &self.installed_tool {\n            // only runtimes for 1 plugin\n            let runtimes: Vec<RuntimeRow<'_>> = runtimes\n                .into_iter()\n                .filter(|(_, p, _, _)| plugins.contains(p.ba()))\n                .collect();\n            let mut r = vec![];\n            for row in runtimes {\n                r.push(json_tool_version_from(config, row, sources_map, self.all_sources).await);\n            }\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&r)?);\n            return Ok(());\n        }\n\n        let mut plugins = JSONOutput::new();\n        for (plugin_name, runtimes) in &runtimes\n            .into_iter()\n            .chunk_by(|(_, p, _, _)| p.id().to_string())\n        {\n            let mut r = vec![];\n            for (ls, p, tv, source) in runtimes {\n                r.push(\n                    json_tool_version_from(\n                        config,\n                        (ls, p, tv, source),\n                        sources_map,\n                        self.all_sources,\n                    )\n                    .await,\n                );\n            }\n            plugins.insert(plugin_name.clone(), r);\n        }\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&plugins)?);\n        Ok(())\n    }\n\n    async fn display_user<'a>(\n        &'a self,\n        config: &Arc<Config>,\n        runtimes: Vec<RuntimeRow<'a>>,\n        sources_map: Option<&SourcesMap>,\n    ) -> Result<()> {\n        let mut rows = vec![];\n        for (ls, p, tv, source) in runtimes {\n            let sources = sources_map\n                .and_then(|map| map.get(&source_key(&tv)).cloned())\n                .unwrap_or_default();\n            let has_sources = !sources.is_empty();\n            rows.push(Row {\n                tool: p.clone(),\n                version: if self.all_sources {\n                    version_status_from_sources(config, (ls, p.as_ref(), &tv, has_sources)).await\n                } else {\n                    version_status_from(config, (ls, p.as_ref(), &tv, &source)).await\n                },\n                requested: if self.all_sources || source.is_unknown() {\n                    None\n                } else {\n                    Some(tv.request.version())\n                },\n                source: if self.all_sources || source.is_unknown() {\n                    None\n                } else {\n                    Some(source)\n                },\n                sources,\n            });\n        }\n        let mut table = MiseTable::new(self.no_header, &[\"Tool\", \"Version\", \"Source\", \"Requested\"]);\n        for r in rows {\n            if self.all_sources && !r.sources.is_empty() {\n                for (idx, source_entry) in r.sources.iter().enumerate() {\n                    let row = vec![\n                        if idx == 0 {\n                            r.display_tool()\n                        } else {\n                            Cell::new(\"\")\n                        },\n                        if idx == 0 {\n                            r.display_version()\n                        } else {\n                            Cell::new(\"\")\n                        },\n                        Cell::new(source_entry.source.to_string()),\n                        Cell::new(source_entry.requested.clone()),\n                    ];\n                    table.add_row(row);\n                }\n            } else {\n                let row = vec![\n                    r.display_tool(),\n                    r.display_version(),\n                    r.display_source(),\n                    r.display_requested(),\n                ];\n                table.add_row(row);\n            }\n        }\n        table.truncate(true).print()\n    }\n\n    async fn get_prunable_runtime_list(&self, config: &Arc<Config>) -> Result<Vec<RuntimeRow<'_>>> {\n        let installed_tool = self.installed_tool.clone().unwrap_or_default();\n        Ok(\n            prune::prunable_tools(config, installed_tool.iter().collect())\n                .await?\n                .into_iter()\n                .map(|(p, tv)| (self, p, tv, ToolSource::Unknown))\n                .collect(),\n        )\n    }\n    async fn get_runtime_list(&self, config: &Arc<Config>) -> Result<Vec<RuntimeRow<'_>>> {\n        let mut trs = config.get_tool_request_set().await?.clone();\n        if self.global {\n            trs = trs\n                .iter()\n                .filter(|(.., ts)| match ts {\n                    ToolSource::MiseToml(p) => config::is_global_config(p),\n                    _ => false,\n                })\n                .map(|(fa, tv, ts)| (fa.clone(), tv.clone(), ts.clone()))\n                .collect()\n        } else if self.local {\n            trs = trs\n                .iter()\n                .filter(|(.., ts)| {\n                    matches!(\n                        ts,\n                        ToolSource::MiseToml(p)\n                        | ToolSource::IdiomaticVersionFile(p)\n                        | ToolSource::ToolVersions(p)\n                        if !config::is_global_config(p)\n                    )\n                })\n                .map(|(fa, tv, ts)| (fa.clone(), tv.clone(), ts.clone()))\n                .collect()\n        }\n\n        let mut ts = Toolset::from(trs);\n        ts.resolve(config).await?;\n\n        let rvs: Vec<RuntimeRow<'_>> = ts\n            .list_all_versions(config)\n            .await?\n            .into_iter()\n            .map(|(b, tv)| ((b, tv.version.clone()), tv))\n            .filter(|((b, _), _)| match &self.installed_tool {\n                Some(p) => p.contains(b.ba()),\n                None => true,\n            })\n            .sorted_by_cached_key(|((plugin_name, version), _)| {\n                (\n                    plugin_name.clone(),\n                    Versioning::new(version),\n                    version.clone(),\n                )\n            })\n            .map(|(k, tv)| (self, k.0, tv.clone(), tv.request.source().clone()))\n            // if it isn't installed and it's not specified, don't show it\n            .filter(|(_ls, p, tv, source)| {\n                !source.is_unknown() || p.is_version_installed(config, tv, true)\n            })\n            .filter(|(_ls, p, _, _)| match &self.installed_tool {\n                Some(backend) => backend.contains(p.ba()),\n                None => true,\n            })\n            .collect();\n\n        Ok(rvs)\n    }\n\n    async fn get_all_sources_runtime_list(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<(Vec<RuntimeRow<'_>>, SourcesMap)> {\n        let mut trs = ToolRequestSet::new();\n        for cf in config.get_tracked_config_files().await?.values() {\n            let cf_trs = cf.to_tool_request_set()?;\n            for (_ba, tool_requests, _source) in cf_trs.into_iter() {\n                for tr in tool_requests {\n                    trs.add_version(tr.clone(), tr.source());\n                }\n            }\n        }\n\n        let mut ts = Toolset::from(trs);\n        ts.resolve(config).await?;\n        let sources_map = collect_sources(&ts);\n\n        let rvs: Vec<RuntimeRow<'_>> = ts\n            .list_current_versions()\n            .into_iter()\n            .map(|(b, tv)| ((b, tv.version.clone()), tv))\n            .filter(|((b, _), _)| match &self.installed_tool {\n                Some(p) => p.contains(b.ba()),\n                None => true,\n            })\n            .sorted_by_cached_key(|((plugin_name, version), _)| {\n                (\n                    plugin_name.clone(),\n                    Versioning::new(version),\n                    version.clone(),\n                )\n            })\n            .unique_by(|(_, tv)| tv.tv_pathname())\n            .map(|(k, tv)| (self, k.0, tv.clone(), tv.request.source().clone()))\n            // if it isn't installed and it's not specified, don't show it\n            .filter(|(_ls, p, tv, source)| {\n                !source.is_unknown() || p.is_version_installed(config, tv, true)\n            })\n            .filter(|(_ls, p, _, _)| match &self.installed_tool {\n                Some(backend) => backend.contains(p.ba()),\n                None => true,\n            })\n            .collect();\n\n        Ok((rvs, sources_map))\n    }\n}\n\ntype JSONOutput = IndexMap<String, Vec<JSONToolVersion>>;\ntype SourcesMap = BTreeMap<(String, String), Vec<SourceEntry>>;\n\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct SourceEntry {\n    source: ToolSource,\n    requested: String,\n}\n\n#[derive(Serialize)]\nstruct JSONToolSource {\n    #[serde(flatten)]\n    source: IndexMap<String, String>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    requested_version: Option<String>,\n}\n\n#[derive(Serialize)]\nstruct JSONToolVersion {\n    version: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    requested_version: Option<String>,\n    install_path: PathBuf,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    source: Option<IndexMap<String, String>>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    sources: Option<Vec<JSONToolSource>>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    symlinked_to: Option<PathBuf>,\n    installed: bool,\n    active: bool,\n}\n\ntype RuntimeRow<'a> = (&'a Ls, Arc<dyn Backend>, ToolVersion, ToolSource);\n\nstruct Row {\n    tool: Arc<dyn Backend>,\n    version: VersionStatus,\n    source: Option<ToolSource>,\n    requested: Option<String>,\n    sources: Vec<SourceEntry>,\n}\n\nimpl Row {\n    fn display_tool(&self) -> Cell {\n        Cell::new(&self.tool).fg(Color::Blue)\n    }\n    fn display_version(&self) -> Cell {\n        match &self.version {\n            VersionStatus::Active(version, outdated) => {\n                if *outdated {\n                    Cell::new(format!(\"{version} (outdated)\"))\n                        .fg(Color::Yellow)\n                        .add_attribute(Attribute::Bold)\n                } else {\n                    Cell::new(version).fg(Color::Green)\n                }\n            }\n            VersionStatus::Inactive(version) => Cell::new(version).add_attribute(Attribute::Dim),\n            VersionStatus::Missing(version) => Cell::new(format!(\"{version} (missing)\"))\n                .fg(Color::Red)\n                .add_attribute(Attribute::CrossedOut),\n            VersionStatus::Symlink(version, active) => {\n                let mut cell = Cell::new(format!(\"{version} (symlink)\"));\n                if !*active {\n                    cell = cell.add_attribute(Attribute::Dim);\n                }\n                cell\n            }\n            VersionStatus::Shared(version, active, label) => {\n                let mut cell = Cell::new(format!(\"{version} ({label})\"));\n                if *active {\n                    cell = cell.fg(Color::Cyan);\n                } else {\n                    cell = cell.fg(Color::Cyan).add_attribute(Attribute::Dim);\n                }\n                cell\n            }\n        }\n    }\n    fn display_source(&self) -> Cell {\n        Cell::new(match &self.source {\n            Some(source) => source.to_string(),\n            None => String::new(),\n        })\n    }\n    fn display_requested(&self) -> Cell {\n        Cell::new(match &self.requested {\n            Some(s) => s.clone(),\n            None => String::new(),\n        })\n    }\n}\n\nfn source_key(tv: &ToolVersion) -> (String, String) {\n    (tv.ba().short.to_string(), tv.tv_pathname())\n}\n\nfn collect_sources(ts: &Toolset) -> SourcesMap {\n    let mut sources_map: SourcesMap = BTreeMap::new();\n    for (ba, tvl) in ts.versions.iter() {\n        for tv in &tvl.versions {\n            let key = (ba.short.to_string(), tv.tv_pathname());\n            let entry = SourceEntry {\n                source: tv.request.source().clone(),\n                requested: tv.request.version(),\n            };\n            let entries = sources_map.entry(key).or_default();\n            if !entries.contains(&entry) {\n                entries.push(entry);\n            }\n        }\n    }\n    for entries in sources_map.values_mut() {\n        entries.sort();\n    }\n    sources_map\n}\n\nasync fn json_tool_version_from(\n    config: &Arc<Config>,\n    row: RuntimeRow<'_>,\n    sources_map: Option<&SourcesMap>,\n    all_sources: bool,\n) -> JSONToolVersion {\n    let (ls, p, tv, source) = row;\n    let sources = sources_map\n        .and_then(|map| map.get(&source_key(&tv)))\n        .filter(|entries| !entries.is_empty());\n    let vs: VersionStatus = if all_sources {\n        version_status_from_sources(config, (ls, p.as_ref(), &tv, sources.is_some())).await\n    } else {\n        version_status_from(config, (ls, p.as_ref(), &tv, &source)).await\n    };\n    let install_path = tv.install_path();\n    let sources = sources\n        .map(|entries| {\n            entries\n                .iter()\n                .filter(|entry| !entry.source.is_unknown())\n                .map(|entry| JSONToolSource {\n                    source: entry.source.as_json(),\n                    requested_version: Some(entry.requested.clone()),\n                })\n                .collect::<Vec<_>>()\n        })\n        .filter(|entries| !entries.is_empty());\n    JSONToolVersion {\n        // Check for symlinks directly (separate from upgrade-skip logic in symlink_path)\n        symlinked_to: if install_path.is_symlink() && !is_runtime_symlink(&install_path) {\n            Some(install_path.clone())\n        } else {\n            None\n        },\n        install_path,\n        version: tv.version.clone(),\n        requested_version: if all_sources || source.is_unknown() {\n            None\n        } else {\n            Some(tv.request.version())\n        },\n        source: if all_sources || source.is_unknown() {\n            None\n        } else {\n            Some(source.as_json())\n        },\n        sources: if all_sources { sources } else { None },\n        installed: !matches!(vs, VersionStatus::Missing(_)),\n        active: match &vs {\n            VersionStatus::Active(_, _) => true,\n            VersionStatus::Symlink(_, active) => *active,\n            VersionStatus::Shared(_, active, _) => *active,\n            _ => false,\n        },\n    }\n}\n\n#[derive(Debug)]\nenum VersionStatus {\n    Active(String, bool),\n    Inactive(String),\n    Missing(String),\n    Symlink(String, bool),\n    /// Version from a shared or system install directory\n    Shared(String, bool, &'static str),\n}\n\nasync fn version_status_from(\n    config: &Arc<Config>,\n    (ls, p, tv, source): (&Ls, &dyn Backend, &ToolVersion, &ToolSource),\n) -> VersionStatus {\n    resolve_version_status(config, ls, p, tv, !source.is_unknown()).await\n}\n\nasync fn version_status_from_sources(\n    config: &Arc<Config>,\n    (ls, p, tv, has_sources): (&Ls, &dyn Backend, &ToolVersion, bool),\n) -> VersionStatus {\n    resolve_version_status(config, ls, p, tv, has_sources).await\n}\n\nasync fn resolve_version_status(\n    config: &Arc<Config>,\n    ls: &Ls,\n    p: &dyn Backend,\n    tv: &ToolVersion,\n    active: bool,\n) -> VersionStatus {\n    let install_path = tv.install_path();\n    if install_path.is_symlink() && !is_runtime_symlink(&install_path) {\n        VersionStatus::Symlink(tv.version.clone(), active)\n    } else if !p.is_version_installed(config, tv, true) {\n        VersionStatus::Missing(tv.version.clone())\n    } else {\n        let category = env::install_path_category(&install_path);\n        if category != env::InstallPathCategory::Local {\n            let label = match category {\n                env::InstallPathCategory::System => \"system\",\n                env::InstallPathCategory::Shared => \"shared\",\n                _ => unreachable!(),\n            };\n            return VersionStatus::Shared(tv.version.clone(), active, label);\n        }\n        if active {\n            let outdated = if ls.outdated {\n                p.is_version_outdated(config, tv).await\n            } else {\n                false\n            };\n            VersionStatus::Active(tv.version.clone(), outdated)\n        } else {\n            VersionStatus::Inactive(tv.version.clone())\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise ls</bold>\n    node    20.0.0 ~/src/myapp/.tool-versions latest\n    python  3.11.0 ~/.tool-versions           3.10\n    python  3.10.0\n\n    $ <bold>mise ls --current</bold>\n    node    20.0.0 ~/src/myapp/.tool-versions 20\n    python  3.11.0 ~/.tool-versions           3.11.0\n\n    $ <bold>mise ls --json</bold>\n    {\n      \"node\": [\n        {\n          \"version\": \"20.0.0\",\n          \"install_path\": \"/Users/jdx/.mise/installs/node/20.0.0\",\n          \"source\": {\n            \"type\": \"mise.toml\",\n            \"path\": \"/Users/jdx/mise.toml\"\n          }\n        }\n      ],\n      \"python\": [...]\n    }\n\n    $ <bold>mise ls --all-sources</bold>\n    node    20.0.0  ~/src/myapp/mise.toml  20\n                    ~/.config/mise/config.toml  latest\n\"#\n);\n"
  },
  {
    "path": "src/cli/ls_remote.rs",
    "content": "use std::sync::Arc;\n\nuse eyre::Result;\nuse serde::Serialize;\n\nuse crate::backend::Backend;\nuse crate::cli::args::ToolArg;\nuse crate::toolset::{ToolRequest, tool_request};\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::{backend, config::Config};\n\n/// Output struct for --all --json mode with consistent null handling\n#[derive(Serialize)]\nstruct VersionOutputAll {\n    tool: String,\n    version: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    created_at: Option<String>,\n}\n\n/// List runtime versions available for install.\n///\n/// Note that the results may be cached, run `mise cache clean` to clear the cache and get fresh results.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP, aliases = [\"list-all\", \"list-remote\"]\n)]\npub struct LsRemote {\n    /// Tool to get versions for\n    #[clap(value_name = \"TOOL@VERSION\", required_unless_present = \"all\")]\n    pub plugin: Option<ToolArg>,\n\n    /// The version prefix to use when querying the latest version\n    /// same as the first argument after the \"@\"\n    #[clap(verbatim_doc_comment)]\n    pub prefix: Option<String>,\n\n    /// Show all installed plugins and versions\n    #[clap(long, verbatim_doc_comment, conflicts_with_all = [\"plugin\", \"prefix\"])]\n    pub all: bool,\n\n    /// Output in JSON format (includes version metadata like created_at timestamps when available)\n    #[clap(short = 'J', long, verbatim_doc_comment)]\n    pub json: bool,\n}\n\nimpl LsRemote {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        if let Some(plugin) = self.get_plugin(&config).await? {\n            self.run_single(&config, plugin).await\n        } else {\n            self.run_all(&config).await\n        }\n    }\n\n    async fn run_single(self, config: &Arc<Config>, plugin: Arc<dyn Backend>) -> Result<()> {\n        let prefix = match &self.plugin {\n            Some(tool_arg) => match &tool_arg.tvr {\n                Some(ToolRequest::Version { version: v, .. }) => Some(v.clone()),\n                Some(ToolRequest::Sub {\n                    sub, orig_version, ..\n                }) => Some(tool_request::version_sub(orig_version, sub)),\n                _ => self.prefix.clone(),\n            },\n            _ => self.prefix.clone(),\n        };\n        let matches_prefix = |v: &str| prefix.as_ref().is_none_or(|p| v.starts_with(p));\n\n        let versions: Vec<_> = plugin\n            .list_remote_versions_with_info(config)\n            .await?\n            .into_iter()\n            .filter(|v| matches_prefix(&v.version))\n            .collect();\n\n        if self.json {\n            miseprintln!(\"{}\", serde_json::to_string(&versions)?);\n        } else {\n            for v in versions {\n                miseprintln!(\"{}\", v.version);\n            }\n        }\n        Ok(())\n    }\n\n    async fn run_all(self, config: &Arc<Config>) -> Result<()> {\n        let mut versions = vec![];\n        for b in backend::list() {\n            let tool = b.id().to_string();\n            for v in b.list_remote_versions_with_info(config).await? {\n                versions.push(VersionOutputAll {\n                    tool: tool.clone(),\n                    version: v.version,\n                    created_at: v.created_at,\n                });\n            }\n        }\n        versions.sort_by(|a, b| a.tool.cmp(&b.tool));\n\n        if self.json {\n            miseprintln!(\"{}\", serde_json::to_string(&versions)?);\n        } else {\n            for v in versions {\n                miseprintln!(\"{}@{}\", v.tool, v.version);\n            }\n        }\n        Ok(())\n    }\n\n    async fn get_plugin(&self, config: &Arc<Config>) -> Result<Option<Arc<dyn Backend>>> {\n        match &self.plugin {\n            Some(tool_arg) => {\n                let backend = tool_arg.ba.backend()?;\n                let mpr = MultiProgressReport::get();\n                if let Some(plugin) = backend.plugin() {\n                    plugin.ensure_installed(config, &mpr, false, false).await?;\n                }\n                Ok(Some(backend))\n            }\n            None => Ok(None),\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise ls-remote node</bold>\n    18.0.0\n    20.0.0\n\n    $ <bold>mise ls-remote node@20</bold>\n    20.0.0\n    20.1.0\n\n    $ <bold>mise ls-remote node 20</bold>\n    20.0.0\n    20.1.0\n\n    $ <bold>mise ls-remote github:cli/cli --json</bold>\n    [{\"version\":\"2.62.0\",\"created_at\":\"2024-11-14T15:40:35Z\"},{\"version\":\"2.61.0\",\"created_at\":\"2024-10-23T19:22:15Z\"}]\n\"#\n);\n"
  },
  {
    "path": "src/cli/mcp.rs",
    "content": "use crate::Result;\nuse crate::config::Config;\nuse clap::Parser;\nuse rmcp::{\n    RoleServer, ServiceExt,\n    handler::server::{\n        ServerHandler,\n        tool::{Parameters, ToolRouter},\n    },\n    model::{\n        AnnotateAble, CallToolRequestParam, CallToolResult, Content, ErrorCode, ErrorData,\n        Implementation, ListResourcesResult, ListToolsResult, PaginatedRequestParam,\n        ProtocolVersion, RawResource, ReadResourceRequestParam, ReadResourceResult,\n        ResourceContents, ServerCapabilities, ServerInfo,\n    },\n    schemars::JsonSchema,\n    service::RequestContext,\n    tool, tool_router,\n};\nuse serde::{Deserialize, Serialize};\nuse serde_json::{Value, json};\nuse std::borrow::Cow;\nuse std::collections::HashMap;\n\n/// [experimental] Run Model Context Protocol (MCP) server\n///\n/// This command starts an MCP server that exposes mise functionality\n/// to AI assistants over stdin/stdout using JSON-RPC protocol.\n///\n/// The MCP server provides access to:\n/// - Installed and available tools\n/// - Task definitions and execution\n/// - Environment variables\n/// - Configuration information\n/// - Task execution via the run_task tool\n///\n/// Resources available:\n/// - mise://tools - List all tools (use ?include_inactive=true to include inactive tools)\n/// - mise://tasks - List all tasks with their configurations\n/// - mise://env - List all environment variables\n/// - mise://config - Show configuration files and project root\n///\n/// Tools available:\n/// - install_tool - Install a tool with an optional version (not yet implemented)\n/// - run_task - Execute a mise task with optional arguments\n///\n/// Note: This is primarily intended for integration with AI assistants like Claude,\n/// Cursor, or other tools that support the Model Context Protocol.\n#[derive(Debug, Parser)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Mcp {}\n\n#[derive(Clone)]\nstruct MiseServer {\n    tool_router: ToolRouter<Self>,\n}\n\n/// Parameters for installing a tool\n#[derive(Debug, Serialize, Deserialize, JsonSchema)]\n#[schemars(crate = \"rmcp::schemars\")]\nstruct InstallToolParams {\n    /// Tool name (e.g. \"node\", \"python\", \"go\")\n    tool: String,\n    /// Optional version to install (e.g. \"20\", \"3.12\"). Defaults to latest.\n    #[serde(default)]\n    version: Option<String>,\n}\n\n/// Parameters for running a mise task\n#[derive(Debug, Serialize, Deserialize, JsonSchema)]\n#[schemars(crate = \"rmcp::schemars\")]\nstruct RunTaskParams {\n    /// Name of the task to run\n    task: String,\n    /// Optional arguments to pass to the task\n    #[serde(default)]\n    args: Vec<String>,\n}\n\n#[tool_router]\nimpl MiseServer {\n    fn new() -> Self {\n        Self {\n            tool_router: Self::tool_router(),\n        }\n    }\n\n    /// Install a tool with an optional version\n    #[tool(description = \"Install a tool with an optional version (e.g. node@20, python@3.12)\")]\n    async fn install_tool(\n        &self,\n        Parameters(_params): Parameters<InstallToolParams>,\n    ) -> std::result::Result<CallToolResult, ErrorData> {\n        Ok(CallToolResult::error(vec![Content::text(\n            \"Tool installation not yet implemented\",\n        )]))\n    }\n\n    /// Execute a mise task with optional arguments\n    #[tool(description = \"Execute a mise task with optional arguments\")]\n    async fn run_task(\n        &self,\n        Parameters(RunTaskParams { task, args }): Parameters<RunTaskParams>,\n    ) -> std::result::Result<CallToolResult, ErrorData> {\n        let exe = std::env::current_exe().map_err(|e| ErrorData {\n            code: ErrorCode::INTERNAL_ERROR,\n            message: Cow::Owned(format!(\"Failed to get current exe: {e}\")),\n            data: None,\n        })?;\n\n        let mut cmd_args = vec![\"run\".to_string(), task.clone()];\n        if !args.is_empty() {\n            cmd_args.push(\"--\".to_string());\n            cmd_args.extend(args);\n        }\n\n        let child = tokio::process::Command::new(exe)\n            .args(&cmd_args)\n            .env(\"NO_COLOR\", \"1\")\n            .env(\"MISE_YES\", \"1\")\n            .kill_on_drop(true)\n            .stdin(std::process::Stdio::null())\n            .stdout(std::process::Stdio::piped())\n            .stderr(std::process::Stdio::piped())\n            .spawn()\n            .map_err(|e| ErrorData {\n                code: ErrorCode::INTERNAL_ERROR,\n                message: Cow::Owned(format!(\"Failed to spawn mise run: {e}\")),\n                data: None,\n            })?;\n\n        let output = match crate::config::Settings::get().task_timeout_duration() {\n            Some(timeout) => tokio::time::timeout(timeout, child.wait_with_output())\n                .await\n                .map_err(|_| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Task '{task}' timed out after {timeout:?}\")),\n                    data: None,\n                })?,\n            None => child.wait_with_output().await,\n        }\n        .map_err(|e| ErrorData {\n            code: ErrorCode::INTERNAL_ERROR,\n            message: Cow::Owned(format!(\"Failed to execute mise run: {e}\")),\n            data: None,\n        })?;\n\n        let stdout = String::from_utf8_lossy(&output.stdout);\n        let stderr = String::from_utf8_lossy(&output.stderr);\n\n        if output.status.success() {\n            let text = match (stderr.is_empty(), stdout.is_empty()) {\n                (true, true) => format!(\"Task '{task}' completed successfully\"),\n                (true, false) => stdout.into_owned(),\n                (false, true) => stderr.into_owned(),\n                (false, false) => format!(\"{stderr}\\n{stdout}\"),\n            };\n            Ok(CallToolResult::success(vec![Content::text(text)]))\n        } else {\n            let text = match (stderr.is_empty(), stdout.is_empty()) {\n                (true, true) => format!(\"Task '{task}' failed with no output\"),\n                (false, true) => stderr.into_owned(),\n                (true, false) => stdout.into_owned(),\n                (false, false) => format!(\"{stderr}\\n{stdout}\"),\n            };\n            Ok(CallToolResult::error(vec![Content::text(format!(\n                \"Task '{task}' failed with exit code {}:\\n{text}\",\n                output.status.code().unwrap_or(1),\n            ))]))\n        }\n    }\n}\n\nimpl ServerHandler for MiseServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            protocol_version: ProtocolVersion::V_2025_03_26,\n            capabilities: ServerCapabilities::builder()\n                .enable_resources()\n                .enable_tools()\n                .build(),\n            server_info: Implementation::from_build_env(),\n            instructions: Some(\"Mise MCP server provides access to tools, tasks, environment variables, and configuration\".to_string()),\n        }\n    }\n\n    async fn list_resources(\n        &self,\n        _pagination: Option<PaginatedRequestParam>,\n        _context: RequestContext<RoleServer>,\n    ) -> std::result::Result<ListResourcesResult, ErrorData> {\n        let resources = vec![\n            RawResource::new(\"mise://tools\", \"Installed Tools\".to_string()).no_annotation(),\n            RawResource::new(\"mise://tasks\", \"Available Tasks\".to_string()).no_annotation(),\n            RawResource::new(\"mise://env\", \"Environment Variables\".to_string()).no_annotation(),\n            RawResource::new(\"mise://config\", \"Configuration\".to_string()).no_annotation(),\n        ];\n\n        Ok(ListResourcesResult {\n            resources,\n            next_cursor: None,\n        })\n    }\n\n    async fn read_resource(\n        &self,\n        params: ReadResourceRequestParam,\n        _context: RequestContext<RoleServer>,\n    ) -> std::result::Result<ReadResourceResult, ErrorData> {\n        // Parse URI to extract query parameters\n        // Example: mise://tools?include_inactive=true\n        let url = url::Url::parse(&params.uri).map_err(|e| ErrorData {\n            code: ErrorCode::INVALID_REQUEST,\n            message: Cow::Owned(format!(\"Invalid URI: {e}\")),\n            data: None,\n        })?;\n\n        // Parse query parameters\n        // include_inactive=true will show all installed tools, not just active ones\n        let include_inactive = url\n            .query_pairs()\n            .any(|(key, value)| key == \"include_inactive\" && value == \"true\");\n\n        match (url.scheme(), url.host_str()) {\n            (\"mise\", Some(\"tools\")) => {\n                // Return tool information\n                // By default only shows active tools (those in current .mise.toml)\n                // With ?include_inactive=true, shows all installed tools\n                let config = Config::get().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load config: {e}\")),\n                    data: None,\n                })?;\n\n                // Get tool request set and resolve toolset\n                let trs = config\n                    .get_tool_request_set()\n                    .await\n                    .map_err(|e| ErrorData {\n                        code: ErrorCode::INTERNAL_ERROR,\n                        message: Cow::Owned(format!(\"Failed to get tool request set: {e}\")),\n                        data: None,\n                    })?\n                    .clone();\n\n                let mut ts = crate::toolset::Toolset::from(trs);\n                ts.resolve(&config).await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to resolve toolset: {e}\")),\n                    data: None,\n                })?;\n\n                // Get current versions to determine which are active\n                let current_versions = ts.list_current_versions();\n                let active_versions: std::collections::HashSet<String> = current_versions\n                    .iter()\n                    .map(|(backend, tv)| format!(\"{}@{}\", backend.id(), tv.version))\n                    .collect();\n\n                // Determine which versions to include\n                let versions = if include_inactive {\n                    // Include all versions (active + installed)\n                    ts.list_all_versions(&config).await.map_err(|e| ErrorData {\n                        code: ErrorCode::INTERNAL_ERROR,\n                        message: Cow::Owned(format!(\"Failed to list tool versions: {e}\")),\n                        data: None,\n                    })?\n                } else {\n                    // Only include active versions (current)\n                    current_versions\n                };\n\n                // Group by tool and create JSON output\n                // Output format: { \"node\": [{\"version\": \"20.11.0\", \"active\": true, ...}], ... }\n                let mut tools_map: std::collections::HashMap<String, Vec<Value>> =\n                    std::collections::HashMap::new();\n\n                for (backend, tv) in versions {\n                    let tool_name = backend.id().to_string();\n                    let install_path = tv.install_path();\n                    let installed = install_path.exists();\n                    let version_key = format!(\"{}@{}\", backend.id(), tv.version);\n                    let version_info = json!({\n                        \"version\": tv.version.clone(),\n                        \"requested_version\": tv.request.version(),\n                        \"install_path\": install_path.to_string_lossy(),\n                        \"installed\": installed,\n                        \"active\": active_versions.contains(&version_key),\n                        \"source\": tv.request.source().as_json(),\n                    });\n                    tools_map.entry(tool_name).or_default().push(version_info);\n                }\n\n                let text = serde_json::to_string_pretty(&tools_map).unwrap();\n                let contents = vec![ResourceContents::TextResourceContents {\n                    uri: params.uri.clone(),\n                    mime_type: Some(\"application/json\".to_string()),\n                    text,\n                }];\n\n                Ok(ReadResourceResult { contents })\n            }\n            (\"mise\", Some(\"tasks\")) => {\n                let config = Config::get().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load config: {e}\")),\n                    data: None,\n                })?;\n\n                let tasks = config.tasks().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load tasks: {e}\")),\n                    data: None,\n                })?;\n\n                let task_list: Vec<_> = tasks.iter().map(|(name, task)| {\n                    json!({\n                        \"name\": name,\n                        \"description\": task.description.clone(),\n                        \"aliases\": task.aliases,\n                        \"source\": task.config_source.to_string_lossy(),\n                        \"depends\": task.depends.iter().map(|d| d.task.clone()).collect::<Vec<_>>(),\n                        \"depends_post\": task.depends_post.iter().map(|d| d.task.clone()).collect::<Vec<_>>(),\n                        \"wait_for\": task.wait_for.iter().map(|d| d.task.clone()).collect::<Vec<_>>(),\n                        \"env\": json!({}), // EnvList is not directly iterable, keeping empty for now\n                        \"dir\": task.dir.clone(),\n                        \"hide\": task.hide,\n                        \"raw\": task.raw,\n                        \"interactive\": task.interactive,\n                        \"sources\": task.sources.clone(),\n                        \"outputs\": task.outputs.clone(),\n                        \"shell\": task.shell.clone(),\n                        \"quiet\": task.quiet,\n                        \"silent\": task.silent,\n                        \"tools\": task.tools.clone(),\n                        \"run\": task.run_script_strings(),\n                        \"usage\": task.usage.clone(),\n                    })\n                }).collect();\n\n                let text = serde_json::to_string_pretty(&task_list).unwrap();\n                let contents = vec![ResourceContents::TextResourceContents {\n                    uri: params.uri.clone(),\n                    mime_type: Some(\"application/json\".to_string()),\n                    text,\n                }];\n\n                Ok(ReadResourceResult { contents })\n            }\n            (\"mise\", Some(\"env\")) => {\n                let config = Config::get().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load config: {e}\")),\n                    data: None,\n                })?;\n\n                let env_template = config.env().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load env: {e}\")),\n                    data: None,\n                })?;\n\n                let mut env_map = HashMap::new();\n                for (k, v) in env_template.iter() {\n                    env_map.insert(k.clone(), v.clone());\n                }\n\n                let text = serde_json::to_string_pretty(&env_map).unwrap();\n                let contents = vec![ResourceContents::TextResourceContents {\n                    uri: params.uri.clone(),\n                    mime_type: Some(\"application/json\".to_string()),\n                    text,\n                }];\n\n                Ok(ReadResourceResult { contents })\n            }\n            (\"mise\", Some(\"config\")) => {\n                let config = Config::get().await.map_err(|e| ErrorData {\n                    code: ErrorCode::INTERNAL_ERROR,\n                    message: Cow::Owned(format!(\"Failed to load config: {e}\")),\n                    data: None,\n                })?;\n\n                let config_info = json!({\n                    \"config_files\": config.config_files.keys().collect::<Vec<_>>(),\n                    \"project_root\": config.project_root.as_ref().map(|p| p.to_string_lossy()),\n                });\n\n                let text = serde_json::to_string_pretty(&config_info).unwrap();\n                let contents = vec![ResourceContents::TextResourceContents {\n                    uri: params.uri.clone(),\n                    mime_type: Some(\"application/json\".to_string()),\n                    text,\n                }];\n\n                Ok(ReadResourceResult { contents })\n            }\n            _ => Err(ErrorData {\n                code: ErrorCode::RESOURCE_NOT_FOUND,\n                message: Cow::Owned(format!(\"Unknown resource URI: {}\", params.uri)),\n                data: None,\n            }),\n        }\n    }\n\n    async fn list_tools(\n        &self,\n        _pagination: Option<PaginatedRequestParam>,\n        _context: RequestContext<RoleServer>,\n    ) -> std::result::Result<ListToolsResult, ErrorData> {\n        Ok(ListToolsResult {\n            tools: self.tool_router.list_all(),\n            next_cursor: None,\n        })\n    }\n\n    async fn call_tool(\n        &self,\n        request: CallToolRequestParam,\n        context: RequestContext<RoleServer>,\n    ) -> std::result::Result<CallToolResult, ErrorData> {\n        let tool_call_context =\n            rmcp::handler::server::tool::ToolCallContext::new(self, request, context);\n        self.tool_router.call(tool_call_context).await\n    }\n}\n\nimpl Mcp {\n    pub async fn run(self) -> Result<()> {\n        let settings = crate::config::Settings::get();\n        settings.ensure_experimental(\"mcp\")?;\n\n        eprintln!(\"Starting mise MCP server...\");\n\n        let server = MiseServer::new();\n\n        // Create stdio transport and serve\n        let service = server\n            .serve(rmcp::transport::stdio())\n            .await\n            .map_err(|e| eyre::eyre!(\"Failed to create service: {}\", e))?;\n\n        // Wait for the service to complete\n        service\n            .waiting()\n            .await\n            .map_err(|e| eyre::eyre!(\"Service error: {}\", e))?;\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Start the MCP server (typically used by AI assistant tools)\n    $ <bold>mise mcp</bold>\n\n    # Example integration with Claude Desktop (add to claude_desktop_config.json):\n    {\n      \"mcpServers\": {\n        \"mise\": {\n          \"command\": \"mise\",\n          \"args\": [\"mcp\"],\n          \"env\": {\n            \"MISE_EXPERIMENTAL\": \"1\"\n          }\n        }\n      }\n    }\n\n    # Interactive testing with JSON-RPC commands:\n    $ <bold>echo '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' | mise mcp</bold>\n\n    # Resources you can query:\n    - <bold>mise://tools</bold> - List active tools\n    - <bold>mise://tools?include_inactive=true</bold> - List all installed tools\n    - <bold>mise://tasks</bold> - List all tasks\n    - <bold>mise://env</bold> - List environment variables\n    - <bold>mise://config</bold> - Show configuration info\n\n    # Tools available:\n    - <bold>install_tool</bold> - Install a tool (not yet implemented)\n    - <bold>run_task</bold> - Execute a mise task with optional arguments\n      Example: {\"task\": \"build\", \"args\": [\"--verbose\"]}\n\"#\n);\n"
  },
  {
    "path": "src/cli/mod.rs",
    "content": "use crate::config::{Config, Settings};\nuse crate::exit::exit;\nuse crate::task::TaskOutput;\nuse crate::ui::{self, ctrlc};\nuse crate::{Result, backend};\nuse crate::{cli::args::ToolArg, path::PathExt};\nuse crate::{hook_env as hook_env_module, logger, migrate, shims};\nuse clap::{ArgAction, CommandFactory, Parser, Subcommand};\nuse eyre::bail;\nuse std::path::PathBuf;\n\nmod activate;\npub mod args;\nmod asdf;\npub mod backends;\nmod bin_paths;\nmod cache;\nmod completion;\nmod config;\nmod current;\nmod deactivate;\nmod direnv;\nmod doctor;\nmod en;\nmod env;\npub mod exec;\nmod external;\nmod fmt;\nmod generate;\nmod global;\nmod hook_env;\nmod hook_not_found;\nmod tool_alias;\n\npub use hook_env::HookReason;\npub(crate) mod edit;\nmod implode;\nmod install;\nmod install_into;\nmod latest;\nmod link;\nmod local;\nmod lock;\nmod ls;\nmod ls_remote;\nmod mcp;\nmod outdated;\nmod plugins;\nmod prepare;\nmod prune;\nmod registry;\n#[cfg(debug_assertions)]\nmod render_help;\nmod reshim;\npub mod run;\nmod search;\n#[cfg_attr(not(feature = \"self_update\"), path = \"self_update_stub.rs\")]\npub mod self_update;\nmod set;\nmod settings;\nmod shell;\nmod shell_alias;\nmod sync;\nmod tasks;\nmod test_tool;\nmod tool;\npub mod tool_stub;\nmod trust;\nmod uninstall;\nmod unset;\nmod unuse;\nmod upgrade;\nmod usage;\nmod r#use;\npub mod version;\nmod watch;\nmod r#where;\nmod r#which;\n\n#[derive(clap::ValueEnum, Debug, Clone, strum::Display)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum LevelFilter {\n    Trace,\n    Debug,\n    Info,\n    Warning,\n    Error,\n}\n\n#[derive(clap::Parser)]\n#[clap(name = \"mise\", about, long_about = LONG_ABOUT, after_long_help = AFTER_LONG_HELP, author = \"Jeff Dickey <@jdx>\", arg_required_else_help = true)]\npub struct Cli {\n    #[clap(subcommand)]\n    pub command: Option<Commands>,\n    /// Task to run\n    #[clap(name = \"TASK\", long_help = LONG_TASK_ABOUT)]\n    pub task: Option<String>,\n    /// Task arguments\n    #[clap(allow_hyphen_values = true, hide = true)]\n    pub task_args: Option<Vec<String>>,\n    #[clap(last = true, hide = true)]\n    pub task_args_last: Vec<String>,\n    /// Continue running tasks even if one fails\n    #[clap(long, short = 'c', hide = true, verbatim_doc_comment)]\n    pub continue_on_error: bool,\n    /// Change directory before running command\n    #[clap(short='C', long, global=true, value_name=\"DIR\", value_hint=clap::ValueHint::DirPath)]\n    pub cd: Option<PathBuf>,\n    /// Set the environment for loading `mise.<ENV>.toml`\n    #[clap(short = 'E', long, global = true)]\n    pub env: Option<Vec<String>>,\n    /// Force the operation\n    #[clap(long, short, hide = true)]\n    pub force: bool,\n    /// Set the log output verbosity\n    #[clap(long, short, hide = true, overrides_with = \"prefix\")]\n    pub interleave: bool,\n    /// How many jobs to run in parallel [default: 8]\n    #[clap(long, short, global = true, env = \"MISE_JOBS\")]\n    pub jobs: Option<usize>,\n    /// Dry run, don't actually do anything\n    #[clap(short = 'n', long, hide = true)]\n    pub dry_run: bool,\n    #[clap(long, short, hide = true, overrides_with = \"interleave\")]\n    pub prefix: bool,\n    /// Set the profile (environment)\n    #[clap(short = 'P', long, global = true, hide = true, conflicts_with = \"env\")]\n    pub profile: Option<Vec<String>>,\n    /// Suppress non-error messages\n    #[clap(short = 'q', long, global = true, overrides_with_all = &[\"silent\", \"trace\", \"verbose\", \"debug\", \"log_level\"])]\n    pub quiet: bool,\n    #[clap(long, short, hide = true)]\n    pub shell: Option<String>,\n    /// Tool(s) to run in addition to what is in mise.toml files\n    /// e.g.: node@20 python@3.10\n    #[clap(\n        short,\n        long,\n        hide = true,\n        value_name = \"TOOL@VERSION\",\n        env = \"MISE_QUIET\"\n    )]\n    pub tool: Vec<ToolArg>,\n    /// Show extra output (use -vv for even more)\n    #[clap(short='v', long, global=true, action=ArgAction::Count, overrides_with_all = &[\"quiet\", \"silent\", \"trace\", \"debug\"])]\n    pub verbose: u8,\n    #[clap(long, short = 'V', hide = true)]\n    pub version: bool,\n    /// Answer yes to all confirmation prompts\n    #[clap(short = 'y', long, global = true)]\n    pub yes: bool,\n    /// Sets log level to debug\n    #[clap(long, global = true, hide = true, overrides_with_all = &[\"quiet\", \"trace\", \"verbose\", \"silent\", \"log_level\"])]\n    pub debug: bool,\n    #[clap(long, global = true, hide = true, value_name = \"LEVEL\", value_enum, overrides_with_all = &[\"quiet\", \"trace\", \"verbose\", \"silent\", \"debug\"])]\n    pub log_level: Option<LevelFilter>,\n    /// Do not load any config files\n    ///\n    /// Can also use `MISE_NO_CONFIG=1`\n    #[clap(long)]\n    pub no_config: bool,\n    /// Do not load environment variables from config files\n    ///\n    /// Can also use `MISE_NO_ENV=1`\n    #[clap(long)]\n    pub no_env: bool,\n    /// Do not execute hooks from config files\n    ///\n    /// Can also use `MISE_NO_HOOKS=1`\n    #[clap(long)]\n    pub no_hooks: bool,\n    /// Hides elapsed time after each task completes\n    ///\n    /// Default to always hide with `MISE_TASK_TIMINGS=0`\n    #[clap(long, alias = \"no-timing\", hide = true, verbatim_doc_comment)]\n    pub no_timings: bool,\n    #[clap(long)]\n    pub output: Option<TaskOutput>,\n    /// Read/write directly to stdin/stdout/stderr instead of by line\n    #[clap(long, global = true)]\n    pub raw: bool,\n    /// Require lockfile URLs to be present during installation\n    ///\n    /// Fails if tools don't have pre-resolved URLs in the lockfile for the current platform.\n    /// This prevents API calls to GitHub, aqua registry, etc.\n    /// Can also be enabled via MISE_LOCKED=1 or settings.locked=true\n    #[clap(long, global = true, verbatim_doc_comment)]\n    pub locked: bool,\n    /// Suppress all task output and mise non-error messages\n    #[clap(long, global = true, overrides_with_all = &[\"quiet\", \"trace\", \"verbose\", \"debug\", \"log_level\"])]\n    pub silent: bool,\n    /// Shows elapsed time after each task completes\n    ///\n    /// Default to always show with `MISE_TASK_TIMINGS=1`\n    #[clap(long, alias = \"timing\", verbatim_doc_comment, hide = true)]\n    pub timings: bool,\n    /// Sets log level to trace\n    #[clap(long, global = true, hide = true, overrides_with_all = &[\"quiet\", \"silent\", \"verbose\", \"debug\", \"log_level\"])]\n    pub trace: bool,\n}\n\n#[derive(Subcommand, strum::Display)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum Commands {\n    Activate(activate::Activate),\n    ToolAlias(Box<tool_alias::ToolAlias>),\n    Asdf(asdf::Asdf),\n    Backends(backends::Backends),\n    BinPaths(bin_paths::BinPaths),\n    Cache(cache::Cache),\n    Completion(completion::Completion),\n    Config(config::Config),\n    Current(current::Current),\n    Deactivate(deactivate::Deactivate),\n    Direnv(direnv::Direnv),\n    Doctor(doctor::Doctor),\n    En(en::En),\n    Env(env::Env),\n    Exec(exec::Exec),\n    Fmt(fmt::Fmt),\n    Generate(generate::Generate),\n    Global(global::Global),\n    HookEnv(hook_env::HookEnv),\n    HookNotFound(hook_not_found::HookNotFound),\n    Implode(implode::Implode),\n    Edit(edit::Edit),\n    Install(install::Install),\n    InstallInto(install_into::InstallInto),\n    Latest(latest::Latest),\n    Link(link::Link),\n    Local(local::Local),\n    Lock(lock::Lock),\n    Ls(ls::Ls),\n    LsRemote(ls_remote::LsRemote),\n    Mcp(mcp::Mcp),\n    Outdated(outdated::Outdated),\n    Plugins(plugins::Plugins),\n    Prepare(prepare::Prepare),\n    Prune(prune::Prune),\n    Registry(registry::Registry),\n    #[cfg(debug_assertions)]\n    RenderHelp(render_help::RenderHelp),\n    Reshim(reshim::Reshim),\n    Run(Box<run::Run>),\n    Search(search::Search),\n    #[cfg(feature = \"self_update\")]\n    SelfUpdate(self_update::SelfUpdate),\n    Set(set::Set),\n    Settings(settings::Settings),\n    Shell(shell::Shell),\n    ShellAlias(shell_alias::ShellAlias),\n    Sync(sync::Sync),\n    Tasks(tasks::Tasks),\n    TestTool(test_tool::TestTool),\n    Tool(tool::Tool),\n    ToolStub(tool_stub::ToolStub),\n    Trust(trust::Trust),\n    Uninstall(uninstall::Uninstall),\n    Unset(unset::Unset),\n    Unuse(unuse::Unuse),\n    Upgrade(upgrade::Upgrade),\n    Usage(usage::Usage),\n    Use(r#use::Use),\n    Version(version::Version),\n    Watch(Box<watch::Watch>),\n    Where(r#where::Where),\n    Which(which::Which),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Activate(cmd) => cmd.run(),\n            Self::ToolAlias(cmd) => cmd.run().await,\n            Self::Asdf(cmd) => cmd.run().await,\n            Self::Backends(cmd) => cmd.run().await,\n            Self::BinPaths(cmd) => cmd.run().await,\n            Self::Cache(cmd) => cmd.run(),\n            Self::Completion(cmd) => cmd.run().await,\n            Self::Config(cmd) => cmd.run().await,\n            Self::Current(cmd) => cmd.run().await,\n            Self::Deactivate(cmd) => cmd.run(),\n            Self::Direnv(cmd) => cmd.run().await,\n            Self::Doctor(cmd) => cmd.run().await,\n            Self::En(cmd) => cmd.run().await,\n            Self::Env(cmd) => cmd.run().await,\n            Self::Exec(cmd) => cmd.run().await,\n            Self::Fmt(cmd) => cmd.run(),\n            Self::Generate(cmd) => cmd.run().await,\n            Self::Global(cmd) => cmd.run().await,\n            Self::HookEnv(cmd) => cmd.run().await,\n            Self::HookNotFound(cmd) => cmd.run().await,\n            Self::Implode(cmd) => cmd.run(),\n            Self::Edit(cmd) => cmd.run().await,\n            Self::Install(cmd) => cmd.run().await,\n            Self::InstallInto(cmd) => cmd.run().await,\n            Self::Latest(cmd) => cmd.run().await,\n            Self::Link(cmd) => cmd.run().await,\n            Self::Local(cmd) => cmd.run().await,\n            Self::Lock(cmd) => cmd.run().await,\n            Self::Ls(cmd) => cmd.run().await,\n            Self::LsRemote(cmd) => cmd.run().await,\n            Self::Mcp(cmd) => cmd.run().await,\n            Self::Outdated(cmd) => cmd.run().await,\n            Self::Plugins(cmd) => cmd.run().await,\n            Self::Prepare(cmd) => cmd.run().await,\n            Self::Prune(cmd) => cmd.run().await,\n            Self::Registry(cmd) => cmd.run().await,\n            #[cfg(debug_assertions)]\n            Self::RenderHelp(cmd) => cmd.run(),\n            Self::Reshim(cmd) => cmd.run().await,\n            Self::Run(cmd) => (*cmd).run().await,\n            Self::Search(cmd) => cmd.run().await,\n            #[cfg(feature = \"self_update\")]\n            Self::SelfUpdate(cmd) => cmd.run().await,\n            Self::Set(cmd) => cmd.run().await,\n            Self::Settings(cmd) => cmd.run().await,\n            Self::Shell(cmd) => cmd.run().await,\n            Self::ShellAlias(cmd) => cmd.run().await,\n            Self::Sync(cmd) => cmd.run().await,\n            Self::Tasks(cmd) => cmd.run().await,\n            Self::TestTool(cmd) => cmd.run().await,\n            Self::Tool(cmd) => cmd.run().await,\n            Self::ToolStub(cmd) => cmd.run().await,\n            Self::Trust(cmd) => cmd.run().await,\n            Self::Uninstall(cmd) => cmd.run().await,\n            Self::Unset(cmd) => cmd.run().await,\n            Self::Unuse(cmd) => cmd.run().await,\n            Self::Upgrade(cmd) => cmd.run().await,\n            Self::Usage(cmd) => cmd.run(),\n            Self::Use(cmd) => cmd.run().await,\n            Self::Version(cmd) => cmd.run().await,\n            Self::Watch(cmd) => cmd.run().await,\n            Self::Where(cmd) => cmd.run().await,\n            Self::Which(cmd) => cmd.run().await,\n        }\n    }\n}\n\nfn get_global_flags(cmd: &clap::Command) -> (Vec<String>, Vec<String>) {\n    let mut flags_with_values = Vec::new();\n    let mut boolean_flags = Vec::new();\n\n    for arg in cmd.get_arguments() {\n        let takes_value = matches!(\n            arg.get_action(),\n            clap::ArgAction::Set | clap::ArgAction::Append\n        );\n        let is_bool = matches!(\n            arg.get_action(),\n            clap::ArgAction::SetTrue | clap::ArgAction::SetFalse\n        );\n\n        if takes_value {\n            if let Some(long) = arg.get_long() {\n                flags_with_values.push(format!(\"--{}\", long));\n            }\n            if let Some(short) = arg.get_short() {\n                flags_with_values.push(format!(\"-{}\", short));\n            }\n        } else if is_bool {\n            if let Some(long) = arg.get_long() {\n                boolean_flags.push(format!(\"--{}\", long));\n            }\n            if let Some(short) = arg.get_short() {\n                boolean_flags.push(format!(\"-{}\", short));\n            }\n        }\n    }\n\n    (flags_with_values, boolean_flags)\n}\n\n/// Get all flags (with values and boolean) from both global Cli and Run subcommand\nfn get_all_run_flags(cmd: &clap::Command) -> (Vec<String>, Vec<String>) {\n    // Get global flags from Cli\n    let (mut flags_with_values, mut boolean_flags) = get_global_flags(cmd);\n\n    // Get run-specific flags from Run subcommand\n    if let Some(run_cmd) = cmd.get_subcommands().find(|s| s.get_name() == \"run\") {\n        let (run_vals, run_bools) = get_global_flags(run_cmd);\n        flags_with_values.extend(run_vals);\n        boolean_flags.extend(run_bools);\n    }\n\n    (flags_with_values, boolean_flags)\n}\n\n/// Prefix used to escape flags that should be passed to tasks, not mise\nconst TASK_ARG_ESCAPE_PREFIX: &str = \"\\x00MISE_TASK_ARG\\x00\";\n\n/// Escape flags after task names so clap doesn't parse them as mise flags.\n/// This preserves ::: separators for multi-task handling while preventing\n/// clap from consuming flags like --jobs that appear after task names.\nfn escape_task_args(cmd: &clap::Command, args: &[String]) -> Vec<String> {\n    // If there's already a '--' separator, let clap handle everything normally\n    if args.contains(&\"--\".to_string()) {\n        return args.to_vec();\n    }\n\n    // Find \"run\" position\n    let run_pos = args.iter().position(|a| a == \"run\");\n    let run_pos = match run_pos {\n        Some(pos) => pos,\n        None => return args.to_vec(), // Not a run command\n    };\n\n    let (flags_with_values, _) = get_all_run_flags(cmd);\n\n    // Build result, escaping flags that appear after task names\n    let mut result = args[..=run_pos].to_vec(); // Include up to and including \"run\"\n    let mut in_task_args = false; // true after we've seen a task name\n\n    let mut i = run_pos + 1;\n    while i < args.len() {\n        let arg = &args[i];\n\n        // ::: starts a new task, so reset to looking for task name\n        if arg == \":::\" {\n            result.push(arg.clone());\n            in_task_args = false;\n            i += 1;\n            continue;\n        }\n\n        if !in_task_args {\n            // Looking for task name - skip any mise flags\n            if arg.starts_with('-') {\n                // It's a flag - keep it as-is for mise to parse\n                result.push(arg.clone());\n\n                // Check if this flag takes a value (and needs to consume the next arg)\n                let flag_takes_value = if arg.starts_with(\"--\") {\n                    if arg.contains('=') {\n                        false // --flag=value, no separate value\n                    } else {\n                        flags_with_values.iter().any(|f| f == arg)\n                    }\n                } else if arg.len() > 2 {\n                    // Short flag with embedded value (e.g., -j4), no separate value needed\n                    false\n                } else if arg.len() == 2 {\n                    let flag_name = &arg[..2];\n                    flags_with_values.iter().any(|f| f == flag_name)\n                } else {\n                    false\n                };\n\n                if flag_takes_value && i + 1 < args.len() && !args[i + 1].starts_with('-') {\n                    i += 1;\n                    result.push(args[i].clone());\n                }\n            } else {\n                // Found task name\n                result.push(arg.clone());\n                in_task_args = true;\n            }\n        } else {\n            // In task args - escape flags so clap doesn't parse them\n            if arg.starts_with('-') && arg != \"-\" {\n                // Escape the flag\n                result.push(format!(\"{}{}\", TASK_ARG_ESCAPE_PREFIX, arg));\n            } else {\n                result.push(arg.clone());\n            }\n        }\n\n        i += 1;\n    }\n\n    result\n}\n\n/// Unescape task args that were escaped by escape_task_args\npub fn unescape_task_args(args: &[String]) -> Vec<String> {\n    args.iter()\n        .map(|arg| {\n            if let Some(stripped) = arg.strip_prefix(TASK_ARG_ESCAPE_PREFIX) {\n                stripped.to_string()\n            } else {\n                arg.clone()\n            }\n        })\n        .collect()\n}\n\nfn preprocess_args_for_naked_run(cmd: &clap::Command, args: &[String]) -> Vec<String> {\n    // Check if this might be a naked run (no subcommand)\n    if args.len() < 2 {\n        return args.to_vec();\n    }\n\n    // If there's already a '--' separator, let clap handle everything normally\n    // (user explicitly separated task args)\n    if args.contains(&\"--\".to_string()) {\n        return args.to_vec();\n    }\n\n    let (flags_with_values, _) = get_global_flags(cmd);\n\n    // Skip global flags to find the first non-flag argument (subcommand or task)\n    let mut i = 1;\n    while i < args.len() {\n        let arg = &args[i];\n\n        if !arg.starts_with('-') {\n            // Found first non-flag argument\n            break;\n        }\n\n        // Check if this flag takes a value\n        let flag_takes_value = if arg.starts_with(\"--\") {\n            if arg.contains('=') {\n                // --flag=value format, doesn't consume next arg\n                i += 1;\n                continue;\n            } else {\n                let flag_name = arg.split('=').next().unwrap();\n                flags_with_values.iter().any(|f| f == flag_name)\n            }\n        } else {\n            // Short form: check if it's in flags_with_values list\n            if arg.len() >= 2 {\n                let flag_name = &arg[..2]; // Get -X part\n                flags_with_values.iter().any(|f| f == flag_name)\n            } else {\n                false\n            }\n        };\n\n        if flag_takes_value && i + 1 < args.len() {\n            // Skip both the flag and its value\n            i += 2;\n        } else {\n            // Skip just the flag\n            i += 1;\n        }\n    }\n\n    // No non-flag argument found\n    if i >= args.len() {\n        return args.to_vec();\n    }\n\n    // Extract all known subcommand names and aliases from the clap Command\n    let known_subcommands: Vec<_> = cmd\n        .get_subcommands()\n        .flat_map(|s| std::iter::once(s.get_name()).chain(s.get_all_aliases()))\n        .collect();\n\n    // Check if the first non-flag argument is a known subcommand\n    if known_subcommands.contains(&args[i].as_str()) {\n        return args.to_vec();\n    }\n\n    // Special case: \"help\" should print help, not be treated as a task\n    if args[i] == \"help\" || args[i] == \"-h\" || args[i] == \"--help\" {\n        return args.to_vec();\n    }\n\n    // This is a naked run - inject \"run\" subcommand so clap routes it correctly\n    // Format: [\"mise\", \"-q\", \"task\", \"arg1\"] becomes [\"mise\", \"-q\", \"run\", \"task\", \"arg1\"]\n    // This preserves global flags while making it an explicit run command\n    let mut result = args[..i].to_vec(); // Keep program name + global flags\n    result.push(\"run\".to_string()); // Insert \"run\" subcommand\n    result.extend_from_slice(&args[i..]); // Add task name and args\n    result\n}\n\nimpl Cli {\n    pub async fn run(args: &Vec<String>) -> Result<()> {\n        crate::env::ARGS.write().unwrap().clone_from(args);\n        // Load .miserc.toml early, before MISE_ENV and other early settings are accessed.\n        // This allows setting MISE_ENV in a config file instead of only via env vars.\n        if let Err(err) = crate::config::miserc::init() {\n            warn!(\"Failed to load .miserc.toml: {err}\");\n        }\n        if *crate::env::MISE_TOOL_STUB && args.len() >= 2 {\n            tool_stub::short_circuit_stub(&args[2..]).await?;\n        }\n        // Fast-path for hook-env: exit early if nothing has changed\n        // This avoids expensive backend::load_tools() and config loading\n        if hook_env_module::should_exit_early_fast() {\n            return Ok(());\n        }\n        measure!(\"logger\", { logger::init() });\n        check_working_directory();\n        measure!(\"handle_shim\", { shims::handle_shim().await })?;\n        ctrlc::init();\n        let print_version = version::print_version_if_requested(args)?;\n        let _ = measure!(\"backend::load_tools\", { backend::load_tools().await });\n\n        // Pre-process args to handle naked runs before clap parsing\n        let cmd = Cli::command();\n        let processed_args = preprocess_args_for_naked_run(&cmd, args);\n        // Escape flags after task names so they go to tasks, not mise\n        let processed_args = escape_task_args(&cmd, &processed_args);\n\n        let cli = measure!(\"get_matches_from\", {\n            Cli::parse_from(processed_args.iter())\n        });\n        // Validate --cd path BEFORE Settings processes it and changes the directory\n        validate_cd_path(&cli.cd)?;\n        measure!(\"add_cli_matches\", { Settings::add_cli_matches(&cli) });\n        let _ = measure!(\"settings\", { Settings::try_get() });\n        measure!(\"logger\", { logger::init() });\n        measure!(\"migrate\", { migrate::run().await });\n        if let Err(err) = crate::cache::auto_prune() {\n            warn!(\"auto_prune failed: {err:?}\");\n        }\n\n        debug!(\"ARGS: {}\", &args.join(\" \"));\n        trace!(\"MISE_BIN: {}\", crate::env::MISE_BIN.display_user());\n        if print_version {\n            version::show_latest().await;\n            exit(0);\n        }\n        let cmd = cli.get_command().await?;\n        measure!(\"run {cmd}\", { cmd.run().await })\n    }\n\n    async fn get_command(self) -> Result<Commands> {\n        if let Some(cmd) = self.command {\n            Ok(cmd)\n        } else {\n            if let Some(task) = self.task {\n                // Handle special case: \"help\", \"-h\", or \"--help\" as task should print help\n                if task == \"help\" || task == \"-h\" || task == \"--help\" {\n                    Cli::command().print_help()?;\n                    exit(0);\n                }\n\n                let config = Config::get().await?;\n\n                // Expand :task pattern to match tasks in current directory's config root\n                let task = crate::task::expand_colon_task_syntax(&task, &config)?;\n\n                // For monorepo task patterns (starting with //), we need to load\n                // tasks from the entire monorepo, not just the current hierarchy\n                let tasks = if task.starts_with(\"//\") {\n                    let ctx = crate::task::TaskLoadContext::from_pattern(&task);\n                    config.tasks_with_context(Some(&ctx)).await?\n                } else {\n                    config.tasks().await?\n                };\n                if tasks.iter().any(|(_, t)| t.is_match(&task)) {\n                    return Ok(Commands::Run(Box::new(run::Run {\n                        task,\n                        args: self.task_args.unwrap_or_default(),\n                        args_last: self.task_args_last,\n                        cd: self.cd,\n                        continue_on_error: self.continue_on_error,\n                        dry_run: self.dry_run,\n                        force: self.force,\n                        interleave: self.interleave,\n                        is_linear: false,\n                        jobs: self.jobs,\n                        no_timings: self.no_timings,\n                        output: self.output,\n                        prefix: self.prefix,\n                        shell: self.shell,\n                        quiet: self.quiet,\n                        silent: self.silent,\n                        raw: self.raw,\n                        timings: self.timings,\n                        tmpdir: Default::default(),\n                        tool: Default::default(),\n                        output_handler: None,\n                        context_builder: Default::default(),\n                        executor: None,\n                        no_cache: Default::default(),\n                        timeout: None,\n                        skip_deps: false,\n                        no_prepare: false,\n                        fresh_env: false,\n                    })));\n                } else if let Some(cmd) = external::COMMANDS.get(&task) {\n                    external::execute(\n                        &task.into(),\n                        cmd.clone(),\n                        self.task_args\n                            .unwrap_or_default()\n                            .into_iter()\n                            .chain(self.task_args_last)\n                            .collect(),\n                    )?;\n                    exit(0);\n                }\n            }\n            Cli::command().print_help()?;\n            exit(1)\n        }\n    }\n}\n\nconst LONG_ABOUT: &str =\n    \"mise manages dev tools, env vars, and runs tasks. https://github.com/jdx/mise\";\n\nconst LONG_TASK_ABOUT: &str = r#\"Task to run.\n\nShorthand for `mise tasks run <TASK>`.\"#;\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise install node@20.0.0</bold>       Install a specific node version\n    $ <bold>mise install node@20</bold>           Install a version matching a prefix\n    $ <bold>mise install node</bold>              Install the node version defined in config\n    $ <bold>mise install</bold>                   Install all plugins/tools defined in config\n\n    $ <bold>mise install cargo:ripgrep</bold>     Install something via cargo\n    $ <bold>mise install npm:prettier</bold>      Install something via npm\n\n    $ <bold>mise use node@20</bold>               Use node-20.x in current project\n    $ <bold>mise use -g node@20</bold>            Use node-20.x as default\n    $ <bold>mise use node@latest</bold>           Use latest node in current directory\n\n    $ <bold>mise up --interactive</bold>          Show a menu to upgrade tools\n\n    $ <bold>mise x -- npm install</bold>          `npm install` w/ config loaded into PATH\n    $ <bold>mise x node@20 -- node app.js</bold>  `node app.js` w/ config + node-20.x on PATH\n\n    $ <bold>mise set NODE_ENV=production</bold>   Set NODE_ENV=production in config\n\n    $ <bold>mise run build</bold>                 Run `build` tasks\n    $ <bold>mise watch build</bold>               Run `build` tasks repeatedly when files change\n\n    $ <bold>mise settings</bold>                  Show settings in use\n    $ <bold>mise settings color=0</bold>          Disable color by modifying global config file\n\"#\n);\n\n/// Check if the current working directory exists and warn if not\nfn check_working_directory() {\n    if std::env::current_dir().is_err() {\n        // Try to get the directory path from PWD env var, which might still contain the old path\n        let dir_path = std::env::var(\"PWD\")\n            .or_else(|_| std::env::var(\"OLDPWD\"))\n            .unwrap_or_else(|_| \"(unknown)\".to_string());\n        warn!(\n            \"Current directory does not exist or is not accessible: {}\",\n            dir_path\n        );\n    }\n}\n\n/// Validate the --cd path if provided and return an error if it doesn't exist\nfn validate_cd_path(cd: &Option<PathBuf>) -> Result<()> {\n    if let Some(path) = cd {\n        if !path.exists() {\n            bail!(\n                \"Directory specified with --cd does not exist: {}\\n\\\n                 Please check the path and try again.\",\n                ui::style::epath(path)\n            );\n        }\n        if !path.is_dir() {\n            bail!(\n                \"Path specified with --cd is not a directory: {}\\n\\\n                 Please provide a valid directory path.\",\n                ui::style::epath(path)\n            );\n        }\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_subcommands_are_sorted() {\n        let cmd = Cli::command();\n        // Check all subcommands except watch (which has many watchexec passthrough args)\n        for subcmd in cmd.get_subcommands() {\n            if subcmd.get_name() != \"watch\" {\n                clap_sort::assert_sorted(subcmd);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/cli/outdated.rs",
    "content": "use std::collections::HashSet;\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::toolset::outdated_info::OutdatedInfo;\nuse crate::toolset::{ConfigScope, ResolveOptions, ToolsetBuilder};\nuse crate::ui::table;\nuse eyre::Result;\nuse indexmap::IndexMap;\nuse tabled::settings::Remove;\nuse tabled::settings::location::ByColumnName;\n\n/// Shows outdated tool versions\n///\n/// See `mise upgrade` to upgrade these versions.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Outdated {\n    /// Tool(s) to show outdated versions for\n    /// e.g.: node@20 python@3.10\n    /// If not specified, all tools in global and local configs will be shown\n    #[clap(value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    pub tool: Vec<ToolArg>,\n\n    /// Output in JSON format\n    #[clap(short = 'J', long, verbatim_doc_comment)]\n    pub json: bool,\n\n    /// Compares against the latest versions available, not what matches the current config\n    ///\n    /// For example, if you have `node = \"20\"` in your config by default `mise outdated` will only\n    /// show other 20.x versions, not 21.x or 22.x versions.\n    ///\n    /// Using this flag, if there are 21.x or newer versions it will display those instead of 20.x.\n    #[clap(long, short = 'l', verbatim_doc_comment)]\n    pub bump: bool,\n\n    /// Only show outdated tools defined in local config files\n    ///\n    /// This will only show tools that are defined in project-local mise.toml and\n    /// will skip tools defined in the global config (~/.config/mise/config.toml).\n    #[clap(long, verbatim_doc_comment)]\n    pub local: bool,\n\n    /// Don't show table header\n    #[clap(long)]\n    pub no_header: bool,\n}\n\nimpl Outdated {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let scope = if self.local {\n            ConfigScope::LocalOnly\n        } else {\n            ConfigScope::All\n        };\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .with_scope(scope)\n            .build(&config)\n            .await?;\n        let tool_set = self\n            .tool\n            .iter()\n            .map(|t| t.ba.clone())\n            .collect::<HashSet<_>>();\n        ts.versions\n            .retain(|_, tvl| tool_set.is_empty() || tool_set.contains(&tvl.backend));\n        let outdated = ts\n            .list_outdated_versions(&config, self.bump, &ResolveOptions::default())\n            .await;\n        self.display(outdated).await?;\n        Ok(())\n    }\n\n    async fn display(&self, outdated: Vec<OutdatedInfo>) -> Result<()> {\n        match self.json {\n            true => self.display_json(outdated)?,\n            false => self.display_table(outdated)?,\n        }\n        Ok(())\n    }\n\n    fn display_table(&self, outdated: Vec<OutdatedInfo>) -> Result<()> {\n        if outdated.is_empty() {\n            info!(\"All tools are up to date\");\n            if !self.bump {\n                hint!(\n                    \"outdated_bump\",\n                    r#\"By default, `mise outdated` only shows versions that match your config. Use `mise outdated --bump` to see all new versions.\"#,\n                    \"\"\n                );\n            }\n            return Ok(());\n        }\n        let mut table = tabled::Table::new(outdated);\n        if !self.bump {\n            table.with(Remove::column(ByColumnName::new(\"bump\")));\n        }\n        table::default_style(&mut table, self.no_header);\n        miseprintln!(\"{table}\");\n        Ok(())\n    }\n\n    fn display_json(&self, outdated: Vec<OutdatedInfo>) -> Result<()> {\n        let mut map = IndexMap::new();\n        for o in outdated {\n            map.insert(o.name.to_string(), o);\n        }\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&map)?);\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise outdated</bold>\n    Plugin  Requested  Current  Latest\n    python  3.11       3.11.0   3.11.1\n    node    20         20.0.0   20.1.0\n\n    $ <bold>mise outdated node</bold>\n    Plugin  Requested  Current  Latest\n    node    20         20.0.0   20.1.0\n\n    $ <bold>mise outdated --json</bold>\n    {\"python\": {\"requested\": \"3.11\", \"current\": \"3.11.0\", \"latest\": \"3.11.1\"}, ...}\n\n    $ <bold>mise outdated --local</bold>\n    Plugin  Requested  Current  Latest\n    node    20         20.0.0   20.1.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/plugins/install.rs",
    "content": "use std::sync::Arc;\n\nuse color_eyre::eyre::{Result, bail, eyre};\nuse contracts::ensures;\nuse heck::ToKebabCase;\nuse tokio::{sync::Semaphore, task::JoinSet};\nuse url::Url;\n\nuse crate::config::Config;\nuse crate::dirs;\nuse crate::plugins::Plugin;\nuse crate::plugins::asdf_plugin::AsdfPlugin;\nuse crate::plugins::core::CORE_PLUGINS;\nuse crate::plugins::warn_if_env_plugin_shadows_registry;\nuse crate::toolset::ToolsetBuilder;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::style;\nuse crate::{backend::unalias_backend, config::Settings};\n\n/// Install a plugin\n///\n/// note that mise automatically can install plugins when you install a tool\n/// e.g.: `mise install cmake@3.30` will autoinstall the cmake plugin\n///\n/// This behavior can be modified in ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"i\", \"a\", \"add\"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP\n)]\npub struct PluginsInstall {\n    /// The name of the plugin to install\n    /// e.g.: cmake, poetry\n    /// Can specify multiple plugins: `mise plugins install cmake poetry`\n    #[clap(required_unless_present = \"all\", verbatim_doc_comment)]\n    new_plugin: Option<String>,\n\n    /// The git url of the plugin\n    /// e.g.: https://github.com/mise-plugins/vfox-cmake.git\n    #[clap(help = \"The git url of the plugin\", value_hint = clap::ValueHint::Url, verbatim_doc_comment\n    )]\n    git_url: Option<String>,\n\n    #[clap(hide = true)]\n    rest: Vec<String>,\n\n    /// Install all missing plugins\n    /// This will only install plugins that have matching shorthands.\n    /// i.e.: they don't need the full git repo url\n    #[clap(short, long, conflicts_with_all = [\"new_plugin\", \"force\"], verbatim_doc_comment)]\n    all: bool,\n\n    /// Reinstall even if plugin exists\n    #[clap(short, long, verbatim_doc_comment)]\n    force: bool,\n\n    /// Number of jobs to run in parallel\n    #[clap(long, short, verbatim_doc_comment)]\n    jobs: Option<usize>,\n\n    /// Show installation output\n    #[clap(long, short, action = clap::ArgAction::Count, verbatim_doc_comment)]\n    verbose: u8,\n}\n\nimpl PluginsInstall {\n    pub async fn run(self, config: &Arc<Config>) -> Result<()> {\n        let this = Arc::new(self);\n        if this.all {\n            return this.install_all_missing_plugins(config).await;\n        }\n        let (name, git_url) = get_name_and_url(&this.new_plugin.clone().unwrap(), &this.git_url)?;\n        if git_url.is_some() {\n            this.install_one(config, name, git_url).await?;\n        } else {\n            let is_core = CORE_PLUGINS.contains_key(&name);\n            if is_core {\n                let name = style::eblue(name);\n                bail!(\"{name} is a core plugin and does not need to be installed\");\n            }\n            let mut plugins: Vec<String> = vec![name];\n            if let Some(second) = this.git_url.clone() {\n                plugins.push(second);\n            };\n            plugins.extend(this.rest.clone());\n            this.install_many(config, plugins).await?;\n        }\n\n        Ok(())\n    }\n\n    async fn install_all_missing_plugins(self: Arc<Self>, config: &Arc<Config>) -> Result<()> {\n        let ts = ToolsetBuilder::new().build(config).await?;\n        let missing_plugins = ts.list_missing_plugins();\n        if missing_plugins.is_empty() {\n            warn!(\"all plugins already installed\");\n        }\n        self.install_many(config, missing_plugins).await?;\n        Ok(())\n    }\n\n    async fn install_many(\n        self: Arc<Self>,\n        config: &Arc<Config>,\n        plugins: Vec<String>,\n    ) -> Result<()> {\n        let mut jset: JoinSet<Result<()>> = JoinSet::new();\n        let semaphore = Arc::new(Semaphore::new(self.jobs.unwrap_or(Settings::get().jobs)));\n        for plugin in plugins {\n            let this = self.clone();\n            let config = config.clone();\n            let permit = semaphore.clone().acquire_owned().await?;\n            jset.spawn(async move {\n                let _permit = permit;\n                println!(\"installing {plugin}\");\n                this.install_one(&config, plugin, None).await\n            });\n        }\n        while let Some(result) = jset.join_next().await {\n            match result {\n                Ok(Ok(())) => {}\n                Ok(Err(e)) => {\n                    return Err(e);\n                }\n                Err(e) => {\n                    return Err(eyre!(e));\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn install_one(\n        self: Arc<Self>,\n        config: &Arc<Config>,\n        name: String,\n        git_url: Option<String>,\n    ) -> Result<()> {\n        let path = dirs::PLUGINS.join(name.to_kebab_case());\n        // TODO: detect vfox plugins and use VfoxPlugin instead of always using AsdfPlugin\n        let plugin = AsdfPlugin::new(name.clone(), path.clone());\n        if let Some(url) = git_url {\n            plugin.set_remote_url(url);\n        }\n        if !self.force && plugin.is_installed() {\n            warn!(\"Plugin {name} already installed\");\n            warn!(\"Use --force to install anyway\");\n        } else {\n            let mpr = MultiProgressReport::get();\n            plugin\n                .ensure_installed(config, &mpr, self.force, false)\n                .await?;\n            warn_if_env_plugin_shadows_registry(&name, &path);\n        }\n        Ok(())\n    }\n}\n\n#[ensures(!ret.as_ref().is_ok_and(|(r, _)| r.is_empty()), \"plugin name is empty\")]\nfn get_name_and_url(name: &str, git_url: &Option<String>) -> Result<(String, Option<String>)> {\n    let name = unalias_backend(name);\n    Ok(match git_url {\n        Some(url) => match url.contains(':') {\n            true => (name.to_string(), Some(url.clone())),\n            false => (name.to_string(), None),\n        },\n        None => match name.contains(':') {\n            true => (get_name_from_url(name)?, Some(name.to_string())),\n            false => (name.to_string(), None),\n        },\n    })\n}\n\nfn get_name_from_url(url: &str) -> Result<String> {\n    let url = url.strip_prefix(\"git@\").unwrap_or(url);\n    let url = url.strip_suffix(\".git\").unwrap_or(url);\n    let url = url.strip_suffix(\"/\").unwrap_or(url);\n    let name = if let Ok(Some(name)) = Url::parse(url).map(|u| {\n        u.path_segments()\n            .and_then(|mut s| s.next_back().map(|s| s.to_string()))\n    }) {\n        name\n    } else if let Some(name) = url.split('/').next_back().map(|s| s.to_string()) {\n        name\n    } else {\n        return Err(eyre!(\"could not infer plugin name from url: {}\", url));\n    };\n    let name = name.strip_prefix(\"asdf-\").unwrap_or(&name);\n    let name = name.strip_prefix(\"rtx-\").unwrap_or(name);\n    let name = name.strip_prefix(\"mise-\").unwrap_or(name);\n    let name = name.strip_prefix(\"vfox-\").unwrap_or(name);\n    Ok(unalias_backend(name).to_string())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # install the poetry via shorthand\n    $ <bold>mise plugins install poetry</bold>\n\n    # install the poetry plugin using a specific git url\n    $ <bold>mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git</bold>\n\n    # install the poetry plugin using the git url only\n    # (poetry is inferred from the url)\n    $ <bold>mise plugins install https://github.com/mise-plugins/mise-poetry.git</bold>\n\n    # install the poetry plugin using a specific ref\n    $ <bold>mise plugins install poetry https://github.com/mise-plugins/mise-poetry.git#11d0c1e</bold>\n\"#\n);\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use pretty_assertions::assert_str_eq;\n\n    #[test]\n    fn test_get_name_from_url() {\n        let get_name = |url| get_name_from_url(url).unwrap();\n        assert_str_eq!(get_name(\"nodejs\"), \"node\");\n        assert_str_eq!(\n            get_name(\"https://github.com/mise-plugins/mise-nodejs.git\"),\n            \"node\"\n        );\n        assert_str_eq!(\n            get_name(\"https://github.com/mise-plugins/asdf-nodejs.git\"),\n            \"node\"\n        );\n        assert_str_eq!(\n            get_name(\"https://github.com/mise-plugins/asdf-nodejs/\"),\n            \"node\"\n        );\n        assert_str_eq!(\n            get_name(\"git@github.com:mise-plugins/asdf-nodejs.git\"),\n            \"node\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/cli/plugins/link.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse clap::ValueHint;\nuse color_eyre::eyre::{Result, eyre};\nuse console::style;\nuse path_absolutize::Absolutize;\n\nuse crate::backend::unalias_backend;\nuse crate::file::{make_symlink, remove_all};\nuse crate::{dirs, file};\n\n/// Symlinks a plugin into mise\n///\n/// This is used for developing a plugin.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"ln\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct PluginsLink {\n    /// The name of the plugin\n    /// e.g.: cmake, poetry\n    #[clap(verbatim_doc_comment)]\n    name: String,\n\n    /// The local path to the plugin\n    /// e.g.: ./vfox-cmake\n    #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)]\n    dir: Option<PathBuf>,\n\n    /// Overwrite existing plugin\n    #[clap(long, short = 'f')]\n    force: bool,\n}\n\nimpl PluginsLink {\n    pub async fn run(self) -> Result<()> {\n        let (name, path) = match self.dir {\n            Some(path) => (self.name, path),\n            None => {\n                let path = PathBuf::from(PathBuf::from(&self.name).absolutize()?);\n                let name = get_name_from_path(&path);\n                (name, path)\n            }\n        };\n        let name = unalias_backend(&name);\n        let path = path.absolutize()?;\n        let symlink = dirs::PLUGINS.join(name);\n        if symlink.exists() {\n            if self.force {\n                remove_all(&symlink)?;\n            } else {\n                return Err(eyre!(\n                    \"plugin {} already exists, use --force to overwrite\",\n                    style(&name).blue().for_stderr()\n                ));\n            }\n        }\n        file::create_dir_all(*dirs::PLUGINS)?;\n        make_symlink(&path, &symlink)?;\n\n        Ok(())\n    }\n}\n\nfn get_name_from_path(path: &Path) -> String {\n    let name = path.file_name().unwrap().to_str().unwrap();\n    let name = name.strip_prefix(\"asdf-\").unwrap_or(name);\n    let name = name.strip_prefix(\"rtx-\").unwrap_or(name);\n    let name = name.strip_prefix(\"mise-\").unwrap_or(name);\n    let name = name.strip_prefix(\"vfox-\").unwrap_or(name);\n    unalias_backend(name).to_string()\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # essentially just `ln -s ./vfox-cmake ~/.local/share/mise/plugins/cmake`\n    $ <bold>mise plugins link cmake ./vfox-cmake</bold>\n\n    # infer plugin name as \"cmake\"\n    $ <bold>mise plugins link ./vfox-cmake</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/plugins/ls.rs",
    "content": "use eyre::Result;\nuse std::collections::BTreeMap;\nuse tabled::{Table, Tabled};\n\nuse crate::config::Config;\nuse crate::parallel;\nuse crate::plugins::PluginType;\nuse crate::plugins::core::CORE_PLUGINS;\nuse crate::registry::full_to_url;\nuse crate::toolset::install_state;\nuse crate::ui::table;\n\n/// List installed plugins\n///\n/// Can also show remotely available plugins to install.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"list\", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct PluginsLs {\n    /// List all available remote plugins\n    /// Same as `mise plugins ls-remote`\n    #[clap(short, long, hide = true, verbatim_doc_comment)]\n    pub all: bool,\n\n    /// The built-in plugins only\n    /// Normally these are not shown\n    #[clap(short, long, verbatim_doc_comment, conflicts_with = \"all\", hide = true)]\n    pub core: bool,\n\n    /// Show plugins with available updates\n    /// Checks the remote for newer versions and only displays plugins that are outdated\n    #[clap(short, long, verbatim_doc_comment)]\n    pub outdated: bool,\n\n    /// Show the git url for each plugin\n    /// e.g.: https://github.com/mise-plugins/vfox-cmake.git\n    #[clap(short, long, alias = \"url\", verbatim_doc_comment)]\n    pub urls: bool,\n\n    /// Show the git refs for each plugin\n    /// e.g.: main 1234abc\n    #[clap(long, hide = true, verbatim_doc_comment)]\n    pub refs: bool,\n\n    /// List installed plugins\n    #[clap(long, verbatim_doc_comment, conflicts_with = \"all\", hide = true)]\n    pub user: bool,\n}\n\nimpl PluginsLs {\n    pub async fn run(self, config: &Config) -> Result<()> {\n        let mut plugins: BTreeMap<_, _> = install_state::list_plugins()\n            .iter()\n            .map(|(k, p)| (k.clone(), (*p, None)))\n            .collect();\n\n        if self.core {\n            for p in CORE_PLUGINS.keys() {\n                miseprintln!(\"{p}\");\n            }\n            return Ok(());\n        }\n\n        if self.all {\n            for (name, backends) in &config.shorthands {\n                for full in backends {\n                    let plugin_type = PluginType::from_full(full)?;\n                    plugins.insert(name.clone(), (plugin_type, Some(full_to_url(full))));\n                }\n            }\n        }\n\n        let plugins = plugins\n            .into_iter()\n            .map(|(short, (pt, url))| {\n                let plugin = pt.plugin(short.clone());\n                if let Some(url) = url {\n                    plugin.set_remote_url(url);\n                }\n                (short, plugin)\n            })\n            .collect::<BTreeMap<_, _>>();\n\n        if self.outdated {\n            let installed: Vec<_> = plugins\n                .into_iter()\n                .filter(|(_, p)| p.is_installed())\n                .collect();\n            let results = parallel::parallel(installed, |(name, p)| async move {\n                tokio::task::spawn_blocking(move || {\n                    let local_sha = p.current_sha_short().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let remote_sha = p.remote_sha().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let remote_url = p.get_remote_url().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let abbrev_ref = p.current_abbrev_ref().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    (name, local_sha, remote_sha, remote_url, abbrev_ref)\n                })\n                .await\n                .map_err(|e| eyre::eyre!(e))\n            })\n            .await?;\n            let mut data: Vec<_> = results\n                .into_iter()\n                .filter_map(|(name, local_sha, remote_sha, remote_url, abbrev_ref)| {\n                    let local_sha = local_sha?;\n                    let remote_sha = remote_sha?;\n                    if remote_sha.starts_with(&local_sha) {\n                        return None;\n                    }\n                    Some(OutdatedRow {\n                        plugin: name,\n                        url: remote_url.unwrap_or_default(),\n                        ref_: abbrev_ref.unwrap_or_default(),\n                        local: local_sha,\n                        remote: remote_sha.chars().take(7).collect(),\n                    })\n                })\n                .collect();\n            data.sort_by(|a, b| a.plugin.cmp(&b.plugin));\n            if data.is_empty() {\n                info!(\"All plugins are up to date\");\n            } else {\n                let mut table = Table::new(data);\n                table::default_style(&mut table, false);\n                miseprintln!(\"{table}\");\n            }\n        } else if self.urls || self.refs {\n            let data = plugins\n                .into_iter()\n                .map(|(name, p)| {\n                    let remote_url = p.get_remote_url().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let abbrev_ref = p.current_abbrev_ref().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let sha_short = p.current_sha_short().unwrap_or_else(|e| {\n                        warn!(\"{name}: {e:?}\");\n                        None\n                    });\n                    let mut row = Row {\n                        plugin: name,\n                        url: remote_url.unwrap_or_default(),\n                        ref_: String::new(),\n                        sha: String::new(),\n                    };\n                    if p.is_installed() {\n                        row.ref_ = abbrev_ref.unwrap_or_default();\n                        row.sha = sha_short.unwrap_or_default();\n                    }\n                    row\n                })\n                .collect::<Vec<_>>();\n            let mut table = Table::new(data);\n            table::default_style(&mut table, false);\n            miseprintln!(\"{table}\");\n        } else {\n            hint!(\"registry\", \"see available plugins with\", \"mise registry\");\n            for tool in plugins.values() {\n                miseprintln!(\"{tool}\");\n            }\n        }\n        Ok(())\n    }\n}\n\n#[derive(Tabled)]\n#[tabled(rename_all = \"PascalCase\")]\nstruct Row {\n    plugin: String,\n    url: String,\n    ref_: String,\n    sha: String,\n}\n\n#[derive(Tabled)]\n#[tabled(rename_all = \"PascalCase\")]\nstruct OutdatedRow {\n    plugin: String,\n    url: String,\n    ref_: String,\n    local: String,\n    remote: String,\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise plugins ls</bold>\n    cmake\n    poetry\n\n    $ <bold>mise plugins ls --urls</bold>\n    cmake     https://github.com/mise-plugins/vfox-cmake.git\n    poetry    https://github.com/mise-plugins/vfox-poetry.git\n\"#\n);\n"
  },
  {
    "path": "src/cli/plugins/ls_remote.rs",
    "content": "use console::{Alignment, measure_text_width, pad_str};\nuse eyre::Result;\nuse itertools::Itertools;\n\nuse crate::config::Config;\nuse crate::toolset::install_state;\n\n/// List all available remote plugins\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"list-remote\", \"list-all\"], long_about = LONG_ABOUT, verbatim_doc_comment)]\npub struct PluginsLsRemote {\n    /// Show the git url for each plugin\n    /// e.g.: https://github.com/mise-plugins/mise-poetry.git\n    #[clap(short, long)]\n    pub urls: bool,\n\n    /// Only show the name of each plugin\n    /// by default it will show a \"*\" next to installed plugins\n    #[clap(long)]\n    pub only_names: bool,\n}\n\nimpl PluginsLsRemote {\n    pub async fn run(self, config: &Config) -> Result<()> {\n        let installed_plugins = install_state::list_plugins();\n\n        let shorthands = config.shorthands.iter().sorted().collect_vec();\n        let max_plugin_len = shorthands\n            .iter()\n            .map(|(plugin, _)| measure_text_width(plugin))\n            .max()\n            .unwrap_or(0);\n\n        if shorthands.is_empty() {\n            warn!(\"default shorthands are disabled\");\n        }\n\n        for (plugin, backends) in shorthands {\n            for repo in backends {\n                let installed =\n                    if !self.only_names && installed_plugins.contains_key(plugin.as_str()) {\n                        \"*\"\n                    } else {\n                        \" \"\n                    };\n                let url = if self.urls { repo } else { \"\" };\n                let plugin = pad_str(plugin, max_plugin_len, Alignment::Left, None);\n                miseprintln!(\"{} {}{}\", plugin, installed, url);\n            }\n        }\n\n        Ok(())\n    }\n}\n\nconst LONG_ABOUT: &str = r#\"\nList all available remote plugins\n\nThe full list is here: https://github.com/jdx/mise/blob/main/registry/\n\nExamples:\n\n    $ mise plugins ls-remote\n\"#;\n"
  },
  {
    "path": "src/cli/plugins/mod.rs",
    "content": "use std::sync::Arc;\n\nuse clap::Subcommand;\nuse eyre::Result;\n\nuse crate::config::Config;\n\nmod install;\nmod link;\nmod ls;\nmod ls_remote;\nmod uninstall;\nmod update;\n\n#[derive(Debug, clap::Args)]\n#[clap(about = \"Manage plugins\", visible_alias = \"p\", aliases = [\"plugin\", \"plugin-list\"])]\npub struct Plugins {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    /// list all available remote plugins\n    ///\n    /// same as `mise plugins ls-remote`\n    #[clap(short, long, hide = true)]\n    pub all: bool,\n\n    /// The built-in plugins only\n    /// Normally these are not shown\n    #[clap(short, long, verbatim_doc_comment, conflicts_with = \"all\")]\n    pub core: bool,\n\n    /// Show the git url for each plugin\n    /// e.g.: https://github.com/mise-plugins/vfox-cmake.git\n    #[clap(short, long, alias = \"url\", verbatim_doc_comment)]\n    pub urls: bool,\n\n    /// Show the git refs for each plugin\n    /// e.g.: main 1234abc\n    #[clap(long, hide = true, verbatim_doc_comment)]\n    pub refs: bool,\n\n    /// List installed plugins\n    ///\n    /// This is the default behavior but can be used with --core\n    /// to show core and user plugins\n    #[clap(long, verbatim_doc_comment, conflicts_with = \"all\")]\n    pub user: bool,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Install(install::PluginsInstall),\n    Link(link::PluginsLink),\n    Ls(ls::PluginsLs),\n    LsRemote(ls_remote::PluginsLsRemote),\n    Uninstall(uninstall::PluginsUninstall),\n    Update(update::Update),\n}\n\nimpl Commands {\n    pub async fn run(self, config: &Arc<Config>) -> Result<()> {\n        match self {\n            Self::Install(cmd) => cmd.run(config).await,\n            Self::Link(cmd) => cmd.run().await,\n            Self::Ls(cmd) => cmd.run(config).await,\n            Self::LsRemote(cmd) => cmd.run(config).await,\n            Self::Uninstall(cmd) => cmd.run().await,\n            Self::Update(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl Plugins {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let cmd = self.command.unwrap_or(Commands::Ls(ls::PluginsLs {\n            all: self.all,\n            core: self.core,\n            refs: self.refs,\n            urls: self.urls,\n            user: self.user,\n            outdated: false,\n        }));\n\n        cmd.run(&config).await\n    }\n}\n"
  },
  {
    "path": "src/cli/plugins/uninstall.rs",
    "content": "use eyre::Result;\n\nuse crate::backend::unalias_backend;\nuse crate::toolset::install_state;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::style;\nuse crate::{backend, plugins};\n\n/// Removes a plugin\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_aliases = [\"remove\", \"rm\"], after_long_help = AFTER_LONG_HELP)]\npub struct PluginsUninstall {\n    /// Plugin(s) to remove\n    #[clap(verbatim_doc_comment)]\n    plugin: Vec<String>,\n\n    /// Remove all plugins\n    #[clap(long, short, verbatim_doc_comment, conflicts_with = \"plugin\")]\n    all: bool,\n\n    /// Also remove the plugin's installs, downloads, and cache\n    #[clap(long, short, verbatim_doc_comment)]\n    purge: bool,\n}\n\nimpl PluginsUninstall {\n    pub async fn run(self) -> Result<()> {\n        let mpr = MultiProgressReport::get();\n\n        let plugins = match self.all {\n            true => install_state::list_plugins().keys().cloned().collect(),\n            false => self.plugin.clone(),\n        };\n\n        for plugin_name in plugins {\n            let plugin_name = unalias_backend(&plugin_name);\n            self.uninstall_one(plugin_name, &mpr).await?;\n        }\n        Ok(())\n    }\n\n    async fn uninstall_one(&self, plugin_name: &str, mpr: &MultiProgressReport) -> Result<()> {\n        if let Ok(plugin) = plugins::get(plugin_name) {\n            if plugin.is_installed() {\n                let prefix = format!(\"plugin:{}\", style::eblue(&plugin.name()));\n                let pr = mpr.add(&prefix);\n                plugin.uninstall(pr.as_ref()).await?;\n                if self.purge {\n                    let backend = backend::get(&plugin_name.into()).unwrap();\n                    backend.purge(pr.as_ref())?;\n                }\n                pr.finish_with_message(\"uninstalled\".into());\n            } else {\n                warn!(\"{} is not installed\", style::eblue(plugin_name));\n            }\n        } else {\n            warn!(\"{} is not installed\", style::eblue(plugin_name));\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise plugins uninstall cmake</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/plugins/update.rs",
    "content": "use std::sync::Arc;\n\nuse console::style;\nuse eyre::{Result, WrapErr, eyre};\nuse tokio::{sync::Semaphore, task::JoinSet};\n\nuse crate::config::Settings;\nuse crate::plugins;\nuse crate::toolset::install_state;\nuse crate::ui::multi_progress_report::MultiProgressReport;\n\n/// Updates a plugin to the latest version\n///\n/// note: this updates the plugin itself, not the runtime versions\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_aliases = [\"up\", \"upgrade\"], after_long_help = AFTER_LONG_HELP)]\npub struct Update {\n    /// Plugin(s) to update\n    #[clap()]\n    plugin: Option<Vec<String>>,\n\n    /// Number of jobs to run in parallel\n    /// Default: 4\n    #[clap(long, short, verbatim_doc_comment)]\n    jobs: Option<usize>,\n}\n\nimpl Update {\n    pub async fn run(self) -> Result<()> {\n        let plugins: Vec<_> = match self.plugin {\n            Some(plugins) => plugins\n                .into_iter()\n                .map(|p| match p.split_once('#') {\n                    Some((p, ref_)) => (p.to_string(), Some(ref_.to_string())),\n                    None => (p, None),\n                })\n                .collect(),\n            None => install_state::list_plugins()\n                .keys()\n                .map(|p| (p.clone(), None))\n                .collect::<Vec<_>>(),\n        };\n\n        let settings = Settings::try_get()?;\n        let mut jset: JoinSet<Result<()>> = JoinSet::new();\n        let semaphore = Arc::new(Semaphore::new(self.jobs.unwrap_or(settings.jobs)));\n        for (short, ref_) in plugins {\n            let permit = semaphore.clone().acquire_owned().await?;\n            jset.spawn(async move {\n                let _permit = permit;\n                let plugin = plugins::get(&short)?;\n                let prefix = format!(\"plugin:{}\", style(plugin.name()).blue().for_stderr());\n                let mpr = MultiProgressReport::get();\n                let pr = mpr.add(&prefix);\n                plugin\n                    .update(pr.as_ref(), ref_)\n                    .await\n                    .wrap_err_with(|| format!(\"[{plugin}] plugin update\"))?;\n                Ok(())\n            });\n        }\n\n        while let Some(result) = jset.join_next().await {\n            match result {\n                Ok(Ok(())) => {}\n                Ok(Err(e)) => {\n                    return Err(e);\n                }\n                Err(e) => {\n                    return Err(eyre!(e));\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise plugins update</bold>              # update all plugins\n    $ <bold>mise plugins update cmake</bold>       # update only cmake\n    $ <bold>mise plugins update cmake#beta</bold>  # specify a ref\n\"#\n);\n"
  },
  {
    "path": "src/cli/prepare.rs",
    "content": "use eyre::{Result, bail};\n\nuse crate::config::Config;\nuse crate::prepare::{PrepareEngine, PrepareOptions, PrepareStepResult};\nuse crate::toolset::{InstallOptions, ToolsetBuilder};\n\n/// [experimental] Ensure project dependencies are ready\n///\n/// Runs all applicable prepare steps for the current project.\n/// This checks if dependency lockfiles are newer than installed outputs\n/// (e.g., package-lock.json vs node_modules/) and runs install commands\n/// if needed.\n///\n/// Providers with `auto = true` are automatically invoked before `mise x` and `mise run`\n/// unless skipped with the --no-prepare flag.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"prep\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Prepare {\n    /// Provider to operate on (runs only this provider, or use with --explain)\n    pub provider: Option<String>,\n\n    /// Show why a provider is fresh or stale (requires a provider argument)\n    #[clap(long)]\n    pub explain: bool,\n\n    /// Force run all prepare steps even if outputs are fresh\n    #[clap(long, short)]\n    pub force: bool,\n\n    /// Only check if prepare is needed, don't run commands\n    #[clap(long, short = 'n')]\n    pub dry_run: bool,\n\n    /// Show what prepare steps are available\n    #[clap(long)]\n    pub list: bool,\n\n    /// Run specific prepare rule(s) only\n    #[clap(long)]\n    pub only: Option<Vec<String>>,\n\n    /// Skip specific prepare rule(s)\n    #[clap(long)]\n    pub skip: Option<Vec<String>>,\n}\n\nimpl Prepare {\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        let engine = PrepareEngine::new(&config)?;\n\n        if self.list {\n            self.list_providers(&engine)?;\n            return Ok(());\n        }\n\n        if self.explain {\n            let Some(ref provider_id) = self.provider else {\n                bail!(\"--explain requires a provider argument, e.g.: mise prepare npm --explain\");\n            };\n            return self.explain_provider(&engine, provider_id);\n        }\n\n        // Build and install toolset so tools like npm are available\n        let mut ts = ToolsetBuilder::new()\n            .with_default_to_latest(true)\n            .build(&config)\n            .await?;\n\n        let install_opts = InstallOptions {\n            missing_args_only: false,\n            ..Default::default()\n        };\n        ts.install_missing_versions(&mut config, &install_opts)\n            .await?;\n\n        // Get toolset environment with PATH\n        let env = ts.env_with_path(&config).await?;\n\n        // If a provider is specified as a positional arg, treat it like --only\n        let only = match (&self.provider, &self.only) {\n            (Some(p), None) => Some(vec![p.clone()]),\n            (Some(p), Some(list)) => {\n                let mut combined = list.clone();\n                if !combined.contains(p) {\n                    combined.push(p.clone());\n                }\n                Some(combined)\n            }\n            (None, only) => only.clone(),\n        };\n\n        let opts = PrepareOptions {\n            dry_run: self.dry_run,\n            force: self.force,\n            only,\n            skip: self.skip.unwrap_or_default(),\n            env,\n            ..Default::default()\n        };\n\n        let result = engine.run(opts).await?;\n\n        // Report results\n        for step in &result.steps {\n            match step {\n                PrepareStepResult::Ran(id) => {\n                    miseprintln!(\"Prepared: {}\", id);\n                }\n                PrepareStepResult::WouldRun(id, reason) => {\n                    miseprintln!(\"[dry-run] Would prepare: {} ({})\", id, reason);\n                }\n                PrepareStepResult::Fresh(id) => {\n                    debug!(\"Fresh: {}\", id);\n                }\n                PrepareStepResult::Skipped(id) => {\n                    debug!(\"Skipped: {}\", id);\n                }\n                PrepareStepResult::Failed(id) => {\n                    miseprintln!(\"Failed: {}\", id);\n                }\n            }\n        }\n\n        if !result.had_work() && !self.dry_run {\n            miseprintln!(\"All dependencies are up to date\");\n        }\n\n        Ok(())\n    }\n\n    fn explain_provider(&self, engine: &PrepareEngine, provider_id: &str) -> Result<()> {\n        let Some(provider) = engine.find_provider(provider_id) else {\n            let available = engine\n                .list_providers()\n                .iter()\n                .map(|p| format!(\"  {}\", p.id()))\n                .collect::<Vec<_>>()\n                .join(\"\\n\");\n            bail!(\"Provider '{provider_id}' not found.\\n\\nAvailable providers:\\n{available}\");\n        };\n\n        let freshness = engine.check_provider_freshness(provider)?;\n\n        // Header\n        miseprintln!(\"Provider: {}\", provider.id());\n        miseprintln!(\"Auto: {}\", if provider.is_auto() { \"yes\" } else { \"no\" });\n\n        // Sources\n        let sources = provider.sources();\n        miseprintln!(\"Sources:\");\n        for source in &sources {\n            let exists = source.exists();\n            let marker = if exists { \"+\" } else { \"-\" };\n            miseprintln!(\"  {} {}\", marker, source.display());\n        }\n\n        // Outputs\n        let outputs = provider.outputs();\n        miseprintln!(\"Outputs:\");\n        for output in &outputs {\n            let exists = output.exists();\n            let marker = if exists { \"+\" } else { \"-\" };\n            miseprintln!(\"  {} {}\", marker, output.display());\n        }\n\n        // Command\n        if let Ok(cmd) = provider.prepare_command() {\n            miseprintln!(\"Command: {}\", cmd.description);\n        }\n\n        // Verdict\n        miseprintln!(\"\");\n        if freshness.is_fresh() {\n            miseprintln!(\"Status: fresh ({})\", freshness.reason());\n        } else {\n            miseprintln!(\"Status: stale ({})\", freshness.reason());\n        }\n\n        if !freshness.is_fresh() {\n            bail!(\"provider '{}' is stale\", provider.id());\n        }\n\n        Ok(())\n    }\n\n    fn list_providers(&self, engine: &PrepareEngine) -> Result<()> {\n        let providers = engine.list_providers();\n\n        if providers.is_empty() {\n            miseprintln!(\"No prepare providers found for this project\");\n            return Ok(());\n        }\n\n        miseprintln!(\"Available prepare providers:\");\n        for provider in providers {\n            let sources = provider\n                .sources()\n                .iter()\n                .map(|p| p.display().to_string())\n                .collect::<Vec<_>>()\n                .join(\", \");\n            let outputs = provider\n                .outputs()\n                .iter()\n                .map(|p| p.display().to_string())\n                .collect::<Vec<_>>()\n                .join(\", \");\n\n            miseprintln!(\"  {}\", provider.id());\n            miseprintln!(\"    sources: {}\", sources);\n            miseprintln!(\"    outputs: {}\", outputs);\n        }\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise prepare</bold>              # Run all applicable prepare steps\n    $ <bold>mise prepare npm</bold>          # Run only npm prepare\n    $ <bold>mise prepare npm --explain</bold> # Show why npm is fresh or stale\n    $ <bold>mise prepare --dry-run</bold>    # Show what would run without executing\n    $ <bold>mise prepare --force</bold>      # Force run even if outputs are fresh\n    $ <bold>mise prepare --list</bold>       # List available prepare providers\n    $ <bold>mise prepare --skip npm</bold>   # Skip npm prepare\n\n<bold><underline>Configuration:</underline></bold>\n\n    Configure prepare providers in mise.toml:\n\n    ```toml\n    # Built-in npm provider (auto-detects lockfile)\n    [prepare.npm]\n    auto = true              # Auto-run before mise x/run\n\n    # Custom provider\n    [prepare.codegen]\n    auto = true\n    sources = [\"schema/*.graphql\"]\n    outputs = [\"src/generated/\"]\n    run = \"npm run codegen\"\n\n    [prepare]\n    disable = [\"npm\"]        # Disable specific providers at runtime\n    ```\n\"#\n);\n"
  },
  {
    "path": "src/cli/prune.rs",
    "content": "use std::collections::BTreeMap;\nuse std::sync::Arc;\n\nuse crate::cli::args::{BackendArg, ToolArg};\nuse crate::config::tracking::Tracker;\nuse crate::config::{Config, Settings};\nuse crate::runtime_symlinks;\nuse crate::toolset::{ToolVersion, ToolsetBuilder, get_versions_needed_by_tracked_configs};\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::prompt;\nuse crate::{backend::Backend, config, exit};\nuse console::style;\nuse eyre::Result;\n\nuse super::trust::Trust;\n\n/// Delete unused versions of tools\n///\n/// mise tracks which config files have been used in ~/.local/state/mise/tracked-configs\n/// Versions which are no longer the latest specified in any of those configs are deleted.\n/// Versions installed only with environment variables `MISE_<PLUGIN>_VERSION` will be deleted,\n/// as will versions only referenced on the command line `mise exec <PLUGIN>@<VERSION>`.\n///\n/// You can list prunable tools with `mise ls --prunable`\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Prune {\n    /// Prune only these tools\n    #[clap()]\n    pub installed_tool: Option<Vec<ToolArg>>,\n\n    /// Do not actually delete anything\n    #[clap(long, short = 'n')]\n    pub dry_run: bool,\n\n    /// Prune only tracked and trusted configuration links that point to non-existent configurations\n    #[clap(long)]\n    pub configs: bool,\n\n    /// Like --dry-run but exits with code 1 if there are tools to prune\n    ///\n    /// This is useful for scripts to check if tools need to be pruned.\n    #[clap(long, verbatim_doc_comment)]\n    pub dry_run_code: bool,\n\n    /// Prune only unused versions of tools\n    #[clap(long)]\n    pub tools: bool,\n}\n\nimpl Prune {\n    fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        if self.configs || !self.tools {\n            self.prune_configs()?;\n        }\n        if self.tools || !self.configs {\n            let backends = self\n                .installed_tool\n                .as_ref()\n                .map(|it| it.iter().map(|ta| ta.ba.as_ref()).collect());\n            let tools = backends.unwrap_or_default();\n            let to_delete = prunable_tools(&config, tools).await?;\n            let has_work = !to_delete.is_empty();\n            delete(&config, self.is_dry_run(), to_delete).await?;\n            if self.dry_run_code && has_work {\n                exit::exit(1);\n            }\n            if self.is_dry_run() {\n                return Ok(());\n            }\n            config = Config::reset().await?;\n            let ts = config.get_toolset().await?;\n            config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        }\n        Ok(())\n    }\n\n    fn prune_configs(&self) -> Result<()> {\n        if self.is_dry_run() {\n            info!(\"pruned configuration links {}\", style(\"[dryrun]\").bold());\n        } else {\n            Tracker::clean()?;\n            Trust::clean()?;\n            info!(\"pruned configuration links\");\n        }\n        Ok(())\n    }\n}\n\npub async fn prunable_tools(\n    config: &Arc<Config>,\n    tools: Vec<&BackendArg>,\n) -> Result<Vec<(Arc<dyn Backend>, ToolVersion)>> {\n    let ts = ToolsetBuilder::new().build(config).await?;\n    let mut to_delete = ts\n        .list_installed_versions(config)\n        .await?\n        .into_iter()\n        .map(|(p, tv)| ((tv.ba().short.to_string(), tv.tv_pathname()), (p, tv)))\n        .collect::<BTreeMap<(String, String), (Arc<dyn Backend>, ToolVersion)>>();\n\n    if !tools.is_empty() {\n        to_delete.retain(|_, (_, tv)| tools.contains(&tv.ba()));\n    }\n\n    // Remove versions that are still needed by tracked configs\n    let needed_versions = get_versions_needed_by_tracked_configs(config).await?;\n    for key in needed_versions {\n        to_delete.remove(&key);\n    }\n\n    Ok(to_delete.into_values().collect())\n}\n\npub async fn prune(config: &Arc<Config>, tools: Vec<&BackendArg>, dry_run: bool) -> Result<()> {\n    let to_delete = prunable_tools(config, tools).await?;\n    delete(config, dry_run, to_delete).await\n}\n\nasync fn delete(\n    config: &Arc<Config>,\n    dry_run: bool,\n    to_delete: Vec<(Arc<dyn Backend>, ToolVersion)>,\n) -> Result<()> {\n    let mpr = MultiProgressReport::get();\n    for (p, tv) in to_delete {\n        let mut prefix = tv.style();\n        if dry_run {\n            prefix = format!(\"{} {} \", prefix, style(\"[dryrun]\").bold());\n        }\n        let pr = mpr.add(&prefix);\n        if dry_run || Settings::get().yes || prompt::confirm_with_all(format!(\"remove {} ?\", &tv))?\n        {\n            p.uninstall_version(config, &tv, pr.as_ref(), dry_run)\n                .await?;\n            runtime_symlinks::remove_missing_symlinks(p)?;\n            pr.finish();\n        }\n    }\n    Ok(())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise prune --dry-run</bold>\n    rm -rf ~/.local/share/mise/versions/node/20.0.0\n    rm -rf ~/.local/share/mise/versions/node/20.0.1\n\"#\n);\n"
  },
  {
    "path": "src/cli/registry.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::config::Settings;\nuse crate::registry::{REGISTRY, RegistryTool, tool_enabled};\nuse crate::ui::table::MiseTable;\nuse eyre::{Result, bail};\nuse itertools::Itertools;\nuse serde_derive::Serialize;\n\n/// List available tools to install\n///\n/// This command lists the tools available in the registry as shorthand names.\n///\n/// For example, `poetry` is shorthand for `asdf:mise-plugins/mise-poetry`.\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct Registry {\n    /// Show only the specified tool's full name\n    name: Option<String>,\n\n    /// Show only tools for this backend\n    #[clap(short, long)]\n    backend: Option<BackendType>,\n\n    /// Print all tools with descriptions for shell completions\n    #[clap(long, hide = true)]\n    complete: bool,\n\n    /// Hide aliased tools\n    #[clap(long)]\n    hide_aliased: bool,\n\n    /// Output in JSON format\n    #[clap(long, short = 'J')]\n    json: bool,\n}\n\n#[derive(Serialize)]\nstruct RegistryToolOutput {\n    short: String,\n    backends: Vec<String>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    description: Option<String>,\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    aliases: Vec<String>,\n}\n\nimpl Registry {\n    pub async fn run(self) -> Result<()> {\n        if let Some(name) = &self.name {\n            if let Some(rt) = REGISTRY.get(name.as_str()) {\n                if self.json {\n                    let tool = self.to_output(name, rt);\n                    miseprintln!(\"{}\", serde_json::to_string_pretty(&tool)?);\n                } else {\n                    miseprintln!(\"{}\", self.filter_backends(rt).join(\" \"));\n                }\n            } else {\n                bail!(\"tool not found in registry: {name}\");\n            }\n        } else if self.complete {\n            self.complete()?;\n        } else if self.json {\n            self.display_json()?;\n        } else {\n            self.display_table()?;\n        }\n        Ok(())\n    }\n\n    fn filter_backends(&self, rt: &RegistryTool) -> Vec<&'static str> {\n        if let Some(backend) = &self.backend {\n            rt.backends()\n                .into_iter()\n                .filter(|full| full.starts_with(&format!(\"{backend}:\")))\n                .collect()\n        } else {\n            rt.backends()\n        }\n    }\n\n    fn to_output(&self, short: &str, rt: &RegistryTool) -> RegistryToolOutput {\n        RegistryToolOutput {\n            short: short.to_string(),\n            backends: self\n                .filter_backends(rt)\n                .iter()\n                .map(|s| s.to_string())\n                .collect(),\n            description: rt.description.map(|s| s.to_string()),\n            aliases: rt.aliases.iter().map(|s| s.to_string()).collect(),\n        }\n    }\n\n    fn filtered_tools(&self) -> impl Iterator<Item = (&&'static str, &RegistryTool)> {\n        REGISTRY\n            .iter()\n            .filter(|(short, _)| filter_enabled(short))\n            .filter(|(short, rt)| !self.hide_aliased || **short == rt.short)\n    }\n\n    fn display_table(&self) -> Result<()> {\n        let mut table = MiseTable::new(false, &[\"Tool\", \"Backends\"]);\n        let data = self\n            .filtered_tools()\n            .map(|(short, rt)| (short.to_string(), self.filter_backends(rt).join(\" \")))\n            .filter(|(_, backends)| !backends.is_empty())\n            .sorted_by(|(a, _), (b, _)| a.cmp(b))\n            .map(|(short, backends)| vec![short, backends])\n            .collect_vec();\n        for row in data {\n            table.add_row(row);\n        }\n        table.print()\n    }\n\n    fn complete(&self) -> Result<()> {\n        self.filtered_tools()\n            .map(|(short, rt)| {\n                (\n                    short.to_string(),\n                    rt.description\n                        .or(rt.backends().first().cloned())\n                        .unwrap_or_default(),\n                )\n            })\n            .sorted_by(|(a, _), (b, _)| a.cmp(b))\n            .for_each(|(short, description)| {\n                println!(\n                    \"{}:{}\",\n                    short.replace(\":\", \"\\\\:\"),\n                    description.replace(\":\", \"\\\\:\")\n                );\n            });\n        Ok(())\n    }\n\n    fn display_json(&self) -> Result<()> {\n        let tools: Vec<RegistryToolOutput> = self\n            .filtered_tools()\n            .map(|(short, rt)| self.to_output(short, rt))\n            .filter(|tool| !tool.backends.is_empty())\n            .sorted_by(|a, b| a.short.cmp(&b.short))\n            .collect();\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&tools)?);\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise registry</bold>\n    node    core:node\n    poetry  asdf:mise-plugins/mise-poetry\n    ubi     cargo:ubi-cli\n\n    $ <bold>mise registry poetry</bold>\n    asdf:mise-plugins/mise-poetry\n\"#\n);\n\nfn filter_enabled(short: &str) -> bool {\n    tool_enabled(\n        &Settings::get().enable_tools,\n        &Settings::get().disable_tools,\n        &short.to_string(),\n    )\n}\n"
  },
  {
    "path": "src/cli/render_help.rs",
    "content": "use crate::cli::Cli;\nuse crate::file;\nuse clap::CommandFactory;\nuse eyre::Result;\nuse indoc::formatdoc;\nuse itertools::Itertools;\n\n/// internal command to generate markdown from help\n#[derive(Debug, clap::Args)]\n#[clap(hide = true)]\npub struct RenderHelp {}\n\nimpl RenderHelp {\n    pub fn run(self) -> Result<()> {\n        xx::file::mkdirp(\"docs/.vitepress\")?;\n\n        file::write(\"docs/.vitepress/cli_commands.ts\", render_command_ts())?;\n        if cfg!(windows) {\n            cmd!(\"prettier.cmd\", \"--write\", \"docs/.vitepress/cli_commands.ts\").run()?;\n        } else {\n            cmd!(\"prettier\", \"--write\", \"docs/.vitepress/cli_commands.ts\").run()?;\n        }\n        Ok(())\n    }\n}\n\nfn render_command_ts() -> String {\n    let mut doc = String::new();\n    doc.push_str(&formatdoc! {r#\"\n        // This file is generated by `mise render-help`\n        // Do not edit this file directly\n\n        export type Command = {{\n          hide: boolean,\n          subcommands?: {{\n            [key: string]: Command,\n          }},\n        }};\n        \"#});\n    doc.push_str(\"export const commands: { [key: string]: Command } = {\\n\");\n    let mut cli = Cli::command()\n        .term_width(80)\n        .max_term_width(80)\n        .disable_help_subcommand(true)\n        .disable_help_flag(true);\n    for command in cli\n        .get_subcommands_mut()\n        .sorted_by_cached_key(|c| c.get_name().to_string())\n    {\n        match command.has_subcommands() {\n            true => {\n                let name = command.get_name().to_string();\n                doc.push_str(&format!(\n                    \"  \\\"{}\\\": {{\\n    hide: {},\\n    subcommands: {{\\n\",\n                    name,\n                    command.is_hide_set()\n                ));\n                for subcommand in command.get_subcommands_mut() {\n                    let output = format!(\n                        \"      \\\"{}\\\": {{\\n        hide: {},\\n      }},\\n\",\n                        subcommand.get_name(),\n                        subcommand.is_hide_set()\n                    );\n                    doc.push_str(&output);\n                }\n                doc.push_str(\"    },\\n  },\\n\");\n            }\n            false => {\n                let output = format!(\n                    \"  \\\"{}\\\": {{\\n    hide: {},\\n  }},\\n\",\n                    command.get_name(),\n                    command.is_hide_set()\n                );\n                doc.push_str(&output);\n            }\n        }\n    }\n    doc.push_str(\"};\\n\");\n    doc\n}\n"
  },
  {
    "path": "src/cli/reshim.rs",
    "content": "use eyre::Result;\n\nuse crate::config::Config;\nuse crate::shims;\nuse crate::toolset::ToolsetBuilder;\n\n/// Creates new shims based on bin paths from currently installed tools.\n///\n/// This creates new shims in ~/.local/share/mise/shims for CLIs that have been added.\n/// mise will try to do this automatically for commands like `npm i -g` but there are\n/// other ways to install things (like using yarn or pnpm for node) that mise does\n/// not know about and so it will be necessary to call this explicitly.\n///\n/// If you think mise should automatically call this for a particular command, please\n/// open an issue on the mise repo. You can also setup a shell function to reshim\n/// automatically (it's really fast so you don't need to worry about overhead):\n///\n///     npm() {\n///       command npm \"$@\"\n///       mise reshim\n///     }\n///\n/// Note that this creates shims for _all_ installed tools, not just the ones that are\n/// currently active in mise.toml.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Reshim {\n    #[clap(hide = true)]\n    pub plugin: Option<String>,\n    #[clap(hide = true)]\n    pub version: Option<String>,\n\n    /// Removes all shims before reshimming\n    #[clap(long, short)]\n    pub force: bool,\n}\n\nimpl Reshim {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let ts = ToolsetBuilder::new().build(&config).await?;\n\n        shims::reshim(&config, &ts, self.force).await\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise reshim</bold>\n    $ <bold>~/.local/share/mise/shims/node -v</bold>\n    v20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/run.rs",
    "content": "use crate::errors::Error;\nuse std::iter::once;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse super::args::ToolArg;\nuse crate::cli::{Cli, unescape_task_args};\nuse crate::config::{Config, Settings};\nuse crate::duration;\nuse crate::env;\nuse crate::file::display_path;\nuse crate::prepare::{PrepareEngine, PrepareOptions};\nuse crate::task::has_any_args_defined;\nuse crate::task::task_helpers::task_needs_permit;\nuse crate::task::task_list::{get_task_lists, resolve_depends};\nuse crate::task::task_output::TaskOutput;\nuse crate::task::task_output_handler::OutputHandler;\nuse crate::task::{Deps, Task};\nuse crate::toolset::{InstallOptions, ToolsetBuilder};\nuse crate::ui::{ctrlc, info, style};\nuse clap::{CommandFactory, ValueHint};\nuse eyre::{Result, bail, eyre};\nuse itertools::Itertools;\nuse tokio::sync::Mutex;\n\n/// Run task(s)\n///\n/// This command will run a task, or multiple tasks in parallel.\n/// Tasks may have dependencies on other tasks or on source files.\n/// If source is configured on a task, it will only run if the source\n/// files have changed.\n///\n/// Tasks can be defined in mise.toml or as standalone scripts.\n/// In mise.toml, tasks take this form:\n///\n///     [tasks.build]\n///     run = \"npm run build\"\n///     sources = [\"src/**/*.ts\"]\n///     outputs = [\"dist/**/*.js\"]\n///\n/// Alternatively, tasks can be defined as standalone scripts.\n/// These must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\n/// `.config/mise/tasks`.\n/// The name of the script will be the name of the tasks.\n///\n///     $ cat .mise/tasks/build<<EOF\n///     #!/usr/bin/env bash\n///     npm run build\n///     EOF\n///     $ mise run build\n#[derive(clap::Args)]\n#[clap(visible_alias = \"r\", verbatim_doc_comment, disable_help_flag = true, after_long_help = AFTER_LONG_HELP)]\npub struct Run {\n    /// Tasks to run\n    /// Can specify multiple tasks by separating with `:::`\n    /// e.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\n    #[clap(\n        allow_hyphen_values = true,\n        verbatim_doc_comment,\n        default_value = \"default\"\n    )]\n    pub task: String,\n\n    /// Arguments to pass to the tasks. Use \":::\" to separate tasks.\n    #[clap(allow_hyphen_values = true)]\n    pub args: Vec<String>,\n\n    /// Arguments to pass to the tasks. Use \":::\" to separate tasks.\n    #[clap(allow_hyphen_values = true, hide = true, last = true)]\n    pub args_last: Vec<String>,\n\n    /// Continue running tasks even if one fails\n    #[clap(long, short = 'c', verbatim_doc_comment)]\n    pub continue_on_error: bool,\n\n    /// Change to this directory before executing the command\n    #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)]\n    pub cd: Option<PathBuf>,\n\n    /// Force the tasks to run even if outputs are up to date\n    #[clap(long, short, verbatim_doc_comment)]\n    pub force: bool,\n\n    /// Print directly to stdout/stderr instead of by line\n    /// Defaults to true if --jobs == 1\n    /// Configure with `task.output` config or `MISE_TASK_OUTPUT` env var\n    #[clap(\n        long,\n        short,\n        verbatim_doc_comment,\n        hide = true,\n        overrides_with = \"prefix\"\n    )]\n    pub interleave: bool,\n\n    /// Number of tasks to run in parallel\n    /// [default: 4]\n    /// Configure with `jobs` config or `MISE_JOBS` env var\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    pub jobs: Option<usize>,\n\n    /// Don't actually run the task(s), just print them in order of execution\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    pub dry_run: bool,\n\n    /// Change how tasks information is output when running tasks\n    ///\n    /// - `prefix` - Print stdout/stderr by line, prefixed with the task's label\n    /// - `interleave` - Print directly to stdout/stderr instead of by line\n    /// - `replacing` - Stdout is replaced each time, stderr is printed as is\n    /// - `timed` - Only show stdout lines if they are displayed for more than 1 second\n    /// - `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n    /// - `quiet` - Don't show extra output\n    /// - `silent` - Don't show any output including stdout and stderr from the task except for errors\n    #[clap(short, long, verbatim_doc_comment, env = \"MISE_TASK_OUTPUT\")]\n    pub output: Option<TaskOutput>,\n\n    /// Print stdout/stderr by line, prefixed with the task's label\n    /// Defaults to true if --jobs > 1\n    /// Configure with `task.output` config or `MISE_TASK_OUTPUT` env var\n    #[clap(\n        long,\n        short,\n        verbatim_doc_comment,\n        hide = true,\n        overrides_with = \"interleave\"\n    )]\n    pub prefix: bool,\n\n    /// Don't show extra output\n    #[clap(long, short, verbatim_doc_comment, env = \"MISE_QUIET\")]\n    pub quiet: bool,\n\n    /// Read/write directly to stdin/stdout/stderr instead of by line\n    /// Redactions are not applied with this option\n    /// Configure with `raw` config or `MISE_RAW` env var\n    #[clap(long, short, verbatim_doc_comment)]\n    pub raw: bool,\n\n    /// Shell to use to run toml tasks\n    ///\n    /// Defaults to `sh -c -o errexit -o pipefail` on unix, and `cmd /c` on Windows\n    /// Can also be set with the setting `MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS` or `MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS`\n    /// Or it can be overridden with the `shell` property on a task.\n    #[clap(long, short, verbatim_doc_comment)]\n    pub shell: Option<String>,\n\n    /// Don't show any output except for errors\n    #[clap(long, short = 'S', verbatim_doc_comment, env = \"MISE_SILENT\")]\n    pub silent: bool,\n\n    /// Tool(s) to run in addition to what is in mise.toml files\n    /// e.g.: node@20 python@3.10\n    #[clap(short, long, value_name = \"TOOL@VERSION\")]\n    pub tool: Vec<ToolArg>,\n\n    #[clap(skip)]\n    pub is_linear: bool,\n\n    /// Bypass the environment cache and recompute the environment\n    #[clap(long)]\n    pub fresh_env: bool,\n\n    /// Do not use cache on remote tasks\n    #[clap(long, verbatim_doc_comment, env = \"MISE_TASK_REMOTE_NO_CACHE\")]\n    pub no_cache: bool,\n\n    /// Skip automatic dependency preparation\n    #[clap(long)]\n    pub no_prepare: bool,\n\n    /// Hides elapsed time after each task completes\n    ///\n    /// Default to always hide with `MISE_TASK_TIMINGS=0`\n    #[clap(long, alias = \"no-timing\", verbatim_doc_comment)]\n    pub no_timings: bool,\n\n    /// Run only the specified tasks skipping all dependencies\n    #[clap(long, verbatim_doc_comment, env = \"MISE_TASK_SKIP_DEPENDS\")]\n    pub skip_deps: bool,\n\n    /// Timeout for the task to complete\n    /// e.g.: 30s, 5m\n    #[clap(long, verbatim_doc_comment)]\n    pub timeout: Option<String>,\n\n    /// Shows elapsed time after each task completes\n    ///\n    /// Default to always show with `MISE_TASK_TIMINGS=1`\n    #[clap(long, alias = \"timing\", verbatim_doc_comment, hide = true)]\n    pub timings: bool,\n\n    #[clap(skip)]\n    pub tmpdir: PathBuf,\n\n    #[clap(skip)]\n    pub output_handler: Option<OutputHandler>,\n\n    #[clap(skip)]\n    pub context_builder: crate::task::task_context_builder::TaskContextBuilder,\n\n    #[clap(skip)]\n    pub executor: Option<crate::task::task_executor::TaskExecutor>,\n}\n\nimpl Run {\n    pub async fn run(mut self) -> Result<()> {\n        // Check help flags before doing any work\n        if self.task == \"-h\" {\n            self.get_clap_command().print_help()?;\n            return Ok(());\n        }\n        if self.task == \"--help\" {\n            self.get_clap_command().print_long_help()?;\n            return Ok(());\n        }\n\n        // Unescape task args early so we can check for help flags\n        self.args = unescape_task_args(&self.args);\n\n        // Temporarily unset cache key to force fresh env computation\n        if self.fresh_env {\n            env::reset_env_cache_key();\n        }\n\n        // Check if --help or -h is in the task args BEFORE toolset/prepare\n        // NOTE: Only check self.args, not self.args_last, because args_last contains\n        // arguments after explicit -- which should always be passed through to the task\n        let has_help_in_task_args =\n            self.args.contains(&\"--help\".to_string()) || self.args.contains(&\"-h\".to_string());\n\n        let mut config = Config::get().await?;\n\n        // Handle task help early to avoid unnecessary toolset/prepare work\n        if has_help_in_task_args {\n            // Build args list to get the task (filter out --help/-h for task lookup)\n            let args = once(self.task.clone())\n                .chain(\n                    self.args\n                        .iter()\n                        .filter(|a| *a != \"--help\" && *a != \"-h\")\n                        .cloned(),\n                )\n                .collect_vec();\n\n            let task_list = get_task_lists(&config, &args, false, false).await?;\n\n            if let Some(task) = task_list.first() {\n                // Get usage spec to check if task has defined args/flags\n                let spec = task.parse_usage_spec_for_display(&config).await?;\n\n                if has_any_args_defined(&spec) {\n                    // Task has usage args/flags defined, render help using usage library\n                    println!(\"{}\", usage::docs::cli::render_help(&spec, &spec.cmd, true));\n                } else {\n                    // Task has no usage defined, show basic task info\n                    display_task_help(task)?;\n                }\n                return Ok(());\n            } else {\n                // No task found, show run command help\n                self.get_clap_command().print_long_help()?;\n                return Ok(());\n            }\n        }\n\n        // Build and install toolset so tools like npm are available for prepare\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .with_default_to_latest(true)\n            .build(&config)\n            .await?;\n\n        let opts = InstallOptions {\n            jobs: self.jobs,\n            raw: self.raw,\n            missing_args_only: !Settings::get().task.run_auto_install,\n            skip_auto_install: !Settings::get().task.run_auto_install\n                || !Settings::get().auto_install,\n            ..Default::default()\n        };\n        let _ = ts.install_missing_versions(&mut config, &opts).await?;\n\n        if !self.skip_deps {\n            self.skip_deps = Settings::get().task.skip_depends;\n        }\n\n        time!(\"run init\");\n        let tmpdir = tempfile::tempdir()?;\n        self.tmpdir = tmpdir.path().to_path_buf();\n\n        // Build args list - don't include args_last yet, they'll be added after task resolution\n        let args = once(self.task.clone())\n            .chain(self.args.clone())\n            .collect_vec();\n\n        let mut task_list = get_task_lists(&config, &args, true, self.skip_deps).await?;\n\n        // Args after -- go directly to tasks (no prefix)\n        if !self.args_last.is_empty() {\n            for task in &mut task_list {\n                task.args.extend(self.args_last.clone());\n            }\n        }\n        time!(\"run get_task_lists\");\n\n        // Resolve transitive dependencies once upfront so we can:\n        // 1. Discover prepare providers from monorepo subdirectory configs\n        // 2. Reuse the resolved list for execution (avoiding duplicate work)\n        let resolved_tasks = resolve_depends(&config, task_list).await?;\n\n        // Run auto-enabled prepare steps (unless --no-prepare)\n        if !self.no_prepare {\n            let env = ts.env_with_path(&config).await?;\n            let mut engine = PrepareEngine::new(&config)?;\n\n            // Collect subdirectory config files from all resolved tasks\n            let subdir_configs: Vec<_> = resolved_tasks\n                .iter()\n                .filter_map(|task| task.cf.clone())\n                .collect();\n            if !subdir_configs.is_empty() {\n                engine.add_config_files(subdir_configs);\n            }\n\n            engine\n                .run(PrepareOptions {\n                    auto_only: true, // Only run providers with auto=true\n                    env,\n                    ..Default::default()\n                })\n                .await?;\n        }\n\n        // Apply global timeout for entire run if configured\n        let timeout = if let Some(timeout_str) = &self.timeout {\n            Some(duration::parse_duration(timeout_str)?)\n        } else {\n            Settings::get().task_timeout_duration()\n        };\n\n        if let Some(timeout) = timeout {\n            tokio::time::timeout(timeout, self.parallelize_tasks(config, resolved_tasks))\n                .await\n                .map_err(|_| eyre!(\"mise run timed out after {:?}\", timeout))??\n        } else {\n            self.parallelize_tasks(config, resolved_tasks).await?\n        }\n\n        time!(\"run done\");\n        Ok(())\n    }\n\n    fn get_clap_command(&self) -> clap::Command {\n        Cli::command()\n            .get_subcommands()\n            .find(|s| s.get_name() == \"run\")\n            .unwrap()\n            .clone()\n    }\n\n    async fn parallelize_tasks(mut self, mut config: Arc<Config>, tasks: Vec<Task>) -> Result<()> {\n        time!(\"parallelize_tasks start\");\n\n        // Step 1: Prepare tasks (resolve dependencies, fetch, validate)\n        let tasks = self.prepare_tasks(&config, tasks).await?;\n        let num_tasks = tasks.all().count();\n\n        // Step 2: Setup output handler and validate tasks\n        self.setup_output_and_validate(&tasks)?;\n        self.output = Some(self.output(None));\n\n        // Step 3: Install tools needed by tasks\n        self.install_task_tools(&mut config, &tasks).await?;\n\n        // Step 4: Create TaskExecutor after tool installation\n        self.setup_executor()?;\n\n        // Disable exit-on-ctrl-c so tasks can handle SIGINT gracefully\n        ctrlc::exit_on_ctrl_c(false);\n\n        let timer = std::time::Instant::now();\n        let this = Arc::new(self);\n        let config = config.clone();\n\n        // Step 4: Initialize scheduler and run tasks\n        let mut scheduler = crate::task::task_scheduler::Scheduler::new(this.jobs());\n        let main_deps = Arc::new(Mutex::new(tasks));\n\n        // Pump deps leaves into scheduler\n        let mut main_done_rx = scheduler.pump_deps(main_deps.clone()).await;\n        let spawn_context = scheduler.spawn_context(config.clone());\n        scheduler\n            .run_loop(\n                &mut main_done_rx,\n                main_deps.clone(),\n                || this.is_stopping(),\n                this.continue_on_error,\n                |task, deps_for_remove| {\n                    let this = this.clone();\n                    let spawn_context = spawn_context.clone();\n                    async move {\n                        Self::spawn_sched_job(this, task, deps_for_remove, spawn_context).await\n                    }\n                },\n            )\n            .await?;\n\n        scheduler.join_all(this.continue_on_error).await?;\n\n        // Step 5: Display results and handle failures\n        let results_display = crate::task::task_results_display::TaskResultsDisplay::new(\n            this.output_handler.clone().unwrap(),\n            this.executor.as_ref().unwrap().failed_tasks.clone(),\n            this.continue_on_error,\n            this.timings(),\n        );\n        results_display.display_results(num_tasks, timer);\n        time!(\"parallelize_tasks done\");\n\n        Ok(())\n    }\n\n    async fn spawn_sched_job(\n        this: Arc<Self>,\n        task: Task,\n        deps_for_remove: Arc<Mutex<Deps>>,\n        ctx: crate::task::task_scheduler::SpawnContext,\n    ) -> Result<()> {\n        // If we're already stopping due to a previous failure and not in\n        // continue-on-error mode, do not launch this task unless it's a\n        // post-dependency (cleanup task that should run even on failure).\n        if this.is_stopping() && !this.continue_on_error {\n            let mut deps = deps_for_remove.lock().await;\n            if !deps.is_runnable_post_dep(&task) {\n                trace!(\n                    \"aborting spawn before start (not continue-on-error): {} {}\",\n                    task.name,\n                    task.args.join(\" \")\n                );\n                deps.remove(&task);\n                return Ok(());\n            }\n            drop(deps);\n        }\n        let needs_permit = task_needs_permit(&task);\n        let permit_opt = if needs_permit {\n            let wait_start = std::time::Instant::now();\n            let p = Some(ctx.semaphore.clone().acquire_owned().await?);\n            trace!(\n                \"semaphore acquired for {} after {}ms\",\n                task.name,\n                wait_start.elapsed().as_millis()\n            );\n            // If a failure occurred while we were waiting for a permit and we're not\n            // in continue-on-error mode, skip launching this task unless it's a\n            // post-dependency (cleanup task). This prevents subsequently queued\n            // tasks from running after failure, while still allowing cleanup.\n            if this.is_stopping() && !this.continue_on_error {\n                let mut deps = deps_for_remove.lock().await;\n                if !deps.is_runnable_post_dep(&task) {\n                    trace!(\n                        \"aborting spawn after failure (not continue-on-error): {} {}\",\n                        task.name,\n                        task.args.join(\" \")\n                    );\n                    // Remove from deps so the scheduler can drain and not hang\n                    deps.remove(&task);\n                    return Ok(());\n                }\n                drop(deps);\n            }\n            p\n        } else {\n            trace!(\"no semaphore needed for orchestrator task: {}\", task.name);\n            None\n        };\n\n        ctx.in_flight\n            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);\n        let in_flight_c = ctx.in_flight.clone();\n        trace!(\"running task: {task}\");\n        // Mark task as executed synchronously before spawning so that the\n        // scheduler's failure-cleanup path (which checks is_runnable_post_dep)\n        // always sees the parent in `executed` — avoiding a race where a\n        // concurrent task fails between spawn and first poll.\n        deps_for_remove.lock().await.mark_executed(&task);\n        ctx.jset.lock().await.spawn(async move {\n            let _permit = permit_opt;\n            let completed = deps_for_remove.lock().await.handled_task_keys();\n            let result = this\n                .run_task_sched(&task, &ctx.config, ctx.sched_tx.clone(), completed)\n                .await;\n            if let Err(err) = &result {\n                let status = Error::get_exit_status(err);\n                if !this.is_stopping() && status.is_none() {\n                    let prefix = task.estyled_prefix();\n                    if Settings::get().verbose {\n                        this.eprint(&task, &prefix, &format!(\"{} {err:?}\", style::ered(\"ERROR\")));\n                    } else {\n                        this.eprint(&task, &prefix, &format!(\"{} {err}\", style::ered(\"ERROR\")));\n                        let mut current_err = err.source();\n                        while let Some(e) = current_err {\n                            this.eprint(&task, &prefix, &format!(\"{} {e}\", style::ered(\"ERROR\")));\n                            current_err = e.source();\n                        }\n                    };\n                }\n                this.add_failed_task(task.clone(), status);\n            }\n            if let Some(oh) = &this.output_handler\n                && oh.output(None) == TaskOutput::KeepOrder\n            {\n                oh.keep_order_state.lock().unwrap().on_task_finished(&task);\n            }\n            deps_for_remove.lock().await.remove(&task);\n            trace!(\"deps removed: {} {}\", task.name, task.args.join(\" \"));\n            in_flight_c.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);\n            result\n        });\n\n        Ok(())\n    }\n\n    // ============================================================================\n    // High-level workflow methods\n    // ============================================================================\n\n    /// Prepare tasks: fetch remote tasks and create dependency graph\n    /// Dependencies should already be resolved via resolve_depends() before calling this.\n    async fn prepare_tasks(&mut self, config: &Arc<Config>, mut tasks: Vec<Task>) -> Result<Deps> {\n        let fetcher = crate::task::task_fetcher::TaskFetcher::new(self.no_cache);\n        fetcher.fetch_tasks(&mut tasks).await?;\n        let mut tasks = Deps::new(config, tasks).await?;\n        tasks.mark_ambiguous_prefixes();\n        self.is_linear = tasks.is_linear();\n        Ok(tasks)\n    }\n\n    /// Initialize output handler and validate tasks\n    fn setup_output_and_validate(&mut self, tasks: &Deps) -> Result<()> {\n        // Initialize OutputHandler AFTER is_linear is determined\n        let output_config = crate::task::task_output_handler::OutputHandlerConfig {\n            prefix: self.prefix,\n            interleave: self.interleave,\n            output: self.output,\n            silent: self.silent,\n            quiet: self.quiet,\n            raw: self.raw,\n            is_linear: self.is_linear,\n            jobs: self.jobs,\n        };\n        self.output_handler = Some(OutputHandler::new(output_config));\n\n        // Spawn timed output task if needed\n        if self.output(None) == TaskOutput::Timed {\n            let timed_outputs = self.output_handler.as_ref().unwrap().timed_outputs.clone();\n            tokio::spawn(async move {\n                let mut interval = tokio::time::interval(Duration::from_millis(100));\n                loop {\n                    {\n                        let mut outputs = timed_outputs.lock().unwrap();\n                        for (prefix, out) in outputs.clone() {\n                            let (time, line) = out;\n                            if time.elapsed().unwrap().as_secs() >= 1 {\n                                if console::colors_enabled() {\n                                    prefix_println!(prefix, \"{line}\\x1b[0m\");\n                                } else {\n                                    prefix_println!(prefix, \"{line}\");\n                                }\n                                outputs.shift_remove(&prefix);\n                            }\n                        }\n                    }\n                    interval.tick().await;\n                }\n            });\n        }\n\n        // Validate and initialize task output\n        for task in tasks.all() {\n            self.validate_task(task)?;\n            self.output_handler.as_mut().unwrap().init_task(task);\n        }\n\n        Ok(())\n    }\n\n    /// Create TaskExecutor after tool installation to ensure caches are populated\n    fn setup_executor(&mut self) -> Result<()> {\n        let executor_config = crate::task::task_executor::TaskExecutorConfig {\n            force: self.force,\n            cd: self.cd.clone(),\n            shell: self.shell.clone(),\n            tool: self.tool.clone(),\n            timings: self.timings,\n            continue_on_error: self.continue_on_error,\n            dry_run: self.dry_run,\n            skip_deps: self.skip_deps,\n        };\n        self.executor = Some(crate::task::task_executor::TaskExecutor::new(\n            self.context_builder.clone(),\n            self.output_handler.clone().unwrap(),\n            executor_config,\n        ));\n\n        Ok(())\n    }\n\n    /// Collect and install all tools needed by tasks\n    async fn install_task_tools(&self, config: &mut Arc<Config>, tasks: &Deps) -> Result<()> {\n        let installer = crate::task::task_tool_installer::TaskToolInstaller::new(\n            &self.context_builder,\n            &self.tool,\n        );\n        installer.install_tools(config, tasks).await\n    }\n\n    // ============================================================================\n    // Helper methods\n    // ============================================================================\n\n    fn eprint(&self, task: &Task, prefix: &str, line: &str) {\n        self.output_handler\n            .as_ref()\n            .unwrap()\n            .eprint(task, prefix, line);\n    }\n\n    fn output(&self, task: Option<&Task>) -> TaskOutput {\n        self.output_handler.as_ref().unwrap().output(task)\n    }\n\n    fn jobs(&self) -> usize {\n        self.output_handler.as_ref().unwrap().jobs()\n    }\n\n    fn is_stopping(&self) -> bool {\n        self.executor\n            .as_ref()\n            .map(|e| e.is_stopping())\n            .unwrap_or(false)\n    }\n\n    async fn run_task_sched(\n        &self,\n        task: &Task,\n        config: &Arc<Config>,\n        sched_tx: Arc<tokio::sync::mpsc::UnboundedSender<(Task, Arc<Mutex<Deps>>)>>,\n        completed_tasks: std::collections::HashSet<crate::task::TaskKey>,\n    ) -> Result<()> {\n        self.executor\n            .as_ref()\n            .expect(\"executor must be initialized before running tasks\")\n            .run_task_sched(task, config, sched_tx, completed_tasks)\n            .await\n    }\n\n    fn add_failed_task(&self, task: Task, status: Option<i32>) {\n        if let Some(executor) = &self.executor {\n            executor.add_failed_task(task, status);\n        }\n    }\n\n    fn validate_task(&self, task: &Task) -> Result<()> {\n        use crate::file;\n        use crate::ui;\n        if let Some(path) = &task.file\n            && path.exists()\n            && !file::is_executable(path)\n        {\n            let dp = crate::file::display_path(path);\n            let msg = format!(\"Script `{dp}` is not executable. Make it executable?\");\n            if ui::confirm(msg)? {\n                file::make_executable(path)?;\n            } else {\n                bail!(\"`{dp}` is not executable\")\n            }\n        }\n        Ok(())\n    }\n\n    fn timings(&self) -> bool {\n        !self.quiet(None) && !self.no_timings\n    }\n\n    fn quiet(&self, task: Option<&Task>) -> bool {\n        self.output_handler.as_ref().unwrap().quiet(task)\n    }\n}\n\nfn display_task_help(task: &Task) -> Result<()> {\n    let name = if task.display_name.is_empty() {\n        &task.name\n    } else {\n        &task.display_name\n    };\n    info::inline_section(\"Task\", name)?;\n    if !task.aliases.is_empty() {\n        info::inline_section(\"Aliases\", task.aliases.join(\", \"))?;\n    }\n    if !task.description.is_empty() {\n        info::inline_section(\"Description\", &task.description)?;\n    }\n    info::inline_section(\"Source\", display_path(&task.config_source))?;\n    if !task.depends.is_empty() {\n        info::inline_section(\"Depends on\", task.depends.iter().join(\", \"))?;\n    }\n    let run = task.run();\n    if !run.is_empty() {\n        info::section(\"Run\", run.iter().map(|e| e.to_string()).join(\"\\n\"))?;\n    }\n    miseprintln!();\n    miseprintln!(\"This task does not accept any arguments.\");\n    let hint = if task.file.is_some() {\n        \"To define arguments, add #USAGE comments to the script file.\"\n    } else {\n        \"To define arguments, add a `usage` field to the task definition in the config file.\"\n    };\n    miseprintln!(\"{hint}\");\n    miseprintln!(\"See https://mise.jdx.dev/tasks/task-configuration.html for more information.\");\n    Ok(())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Runs the \"lint\" tasks. This needs to either be defined in mise.toml\n    # or as a standalone script. See the project README for more information.\n    $ <bold>mise run lint</bold>\n\n    # Forces the \"build\" tasks to run even if its sources are up-to-date.\n    $ <bold>mise run --force build</bold>\n\n    # Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n    # This forces `--jobs=1` to prevent interleaving of output.\n    $ <bold>mise run --raw test</bold>\n\n    # Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n    $ <bold>mise run lint ::: test ::: check</bold>\n\n    # Execute multiple tasks each with their own arguments.\n    $ <bold>mise run cmd1 arg1 arg2 ::: cmd2 arg1 arg2</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/search.rs",
    "content": "use std::sync::LazyLock as Lazy;\n\nuse clap::ValueEnum;\nuse demand::DemandOption;\nuse demand::Select;\nuse eyre::Result;\nuse eyre::bail;\nuse eyre::eyre;\nuse fuzzy_matcher::FuzzyMatcher;\nuse fuzzy_matcher::skim::SkimMatcherV2;\nuse itertools::Itertools;\nuse xx::regex;\n\nuse crate::registry::RegistryTool;\nuse crate::{\n    config::Settings,\n    registry::{REGISTRY, tool_enabled},\n    ui::table::MiseTable,\n};\n\nstatic FUZZY_MATCHER: Lazy<SkimMatcherV2> =\n    Lazy::new(|| SkimMatcherV2::default().use_cache(true).smart_case());\n\n#[derive(Debug, Clone, ValueEnum)]\npub enum MatchType {\n    Equal,\n    Contains,\n    Fuzzy,\n}\n\n/// Search for tools in the registry\n///\n/// This command searches a tool in the registry.\n///\n/// By default, it will show all tools that fuzzy match the search term. For\n/// non-fuzzy matches, use the `--match-type` flag.\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct Search {\n    /// The tool to search for\n    name: Option<String>,\n\n    /// Show interactive search\n    #[clap(long, short, conflicts_with_all = &[\"match_type\", \"no_header\"])]\n    interactive: bool,\n\n    /// Match type: equal, contains, or fuzzy\n    #[clap(long, short, value_enum, default_value = \"fuzzy\")]\n    match_type: MatchType,\n\n    /// Don't display headers\n    #[clap(long, alias = \"no-headers\")]\n    no_header: bool,\n}\n\nimpl Search {\n    pub async fn run(self) -> Result<()> {\n        if self.interactive {\n            self.interactive()?;\n        } else {\n            self.display_table()?;\n        }\n        Ok(())\n    }\n\n    fn interactive(&self) -> Result<()> {\n        let tools = self.get_tools();\n        let theme = crate::ui::theme::get_theme();\n        let mut s = Select::new(\"Tool\")\n            .description(\"Search a tool\")\n            .filtering(true)\n            .filterable(true)\n            .theme(&theme);\n        for t in tools.iter() {\n            let short = t.0.as_str();\n            let description = get_description(t.1);\n            s = s.option(\n                DemandOption::new(short)\n                    .label(short)\n                    .description(&description),\n            );\n        }\n        match s.run() {\n            Ok(_) => Ok(()),\n            Err(err) => {\n                if err.kind() == std::io::ErrorKind::Interrupted {\n                    // user interrupted, exit gracefully\n                    Ok(())\n                } else {\n                    Err(eyre!(err))\n                }\n            }\n        }\n    }\n\n    fn display_table(&self) -> Result<()> {\n        let tools = self\n            .get_matches()\n            .into_iter()\n            .map(|(short, description)| vec![short, description])\n            .collect_vec();\n        if tools.is_empty() {\n            bail!(\"tool {} not found in registry\", self.name.as_ref().unwrap());\n        }\n\n        let mut table = MiseTable::new(self.no_header, &[\"Tool\", \"Description\"]);\n        for row in tools {\n            table.add_row(row);\n        }\n        table.print()\n    }\n\n    fn get_matches(&self) -> Vec<(String, String)> {\n        self.get_tools()\n            .iter()\n            .filter_map(|(short, rt)| {\n                let name = self.name.as_deref().unwrap_or(\"\");\n                if name.is_empty() {\n                    Some((0, short, rt))\n                } else {\n                    match self.match_type {\n                        MatchType::Equal => {\n                            if *short == name {\n                                Some((0, short, rt))\n                            } else {\n                                None\n                            }\n                        }\n                        MatchType::Contains => {\n                            if short.contains(name) {\n                                Some((0, short, rt))\n                            } else {\n                                None\n                            }\n                        }\n                        MatchType::Fuzzy => FUZZY_MATCHER\n                            .fuzzy_match(&short.to_lowercase(), name.to_lowercase().as_str())\n                            .map(|score| (score, short, rt)),\n                    }\n                }\n            })\n            .sorted_by_key(|(score, _short, _rt)| -1 * *score)\n            .map(|(_score, short, rt)| (short.to_string(), get_description(rt)))\n            .collect()\n    }\n\n    fn get_tools(&self) -> Vec<(String, &'static RegistryTool)> {\n        REGISTRY\n            .iter()\n            .filter(|(short, _)| filter_enabled(short))\n            .map(|(short, rt)| (short.to_string(), rt))\n            .sorted_by(|(a, _), (b, _)| a.cmp(b))\n            .collect_vec()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise search jq</bold>\n    Tool  Description\n    jq    Command-line JSON processor. https://github.com/jqlang/jq\n    jqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\n    jiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\n    gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\n\n    $ <bold>mise search --interactive</bold>\n    Tool\n    Search a tool\n    ❯ jq    Command-line JSON processor. https://github.com/jqlang/jq\n      jqp   A TUI playground to experiment with jq. https://github.com/noahgorstein/jqp\n      jiq   jid on jq - interactive JSON query tool using jq expressions. https://github.com/fiatjaf/jiq\n      gojq  Pure Go implementation of jq. https://github.com/itchyny/gojq\n    /jq \n    esc clear filter • enter confirm\n\"#\n);\n\nfn filter_enabled(short: &str) -> bool {\n    tool_enabled(\n        &Settings::get().enable_tools,\n        &Settings::get().disable_tools,\n        &short.to_string(),\n    )\n}\n\nfn get_description(tool: &RegistryTool) -> String {\n    let description = tool.description.unwrap_or_default();\n    let backend = get_backends(tool.backends())\n        .iter()\n        .filter(|b| !Settings::get().disable_backends.contains(b))\n        .map(|b| b.to_string())\n        .next()\n        .unwrap_or_default();\n    if description.is_empty() {\n        backend.to_string()\n    } else {\n        format!(\"{description}. {backend}\")\n    }\n}\n\nfn get_backends(backends: Vec<&'static str>) -> Vec<String> {\n    if backends.is_empty() {\n        return vec![\"\".to_string()];\n    }\n    backends\n        .iter()\n        .map(|backend| {\n            let prefix = backend.split(':').next().unwrap_or(\"\");\n            let slug = backend.split(':').next_back().unwrap_or(\"\");\n            let slug = regex!(r\"^(.*?)\\[.*\\]$\").replace_all(slug, \"$1\");\n            match prefix {\n                \"core\" => format!(\"https://mise.jdx.dev/lang/{slug}.html\"),\n                \"cargo\" => format!(\"https://crates.io/crates/{slug}\"),\n                \"go\" => format!(\"https://pkg.go.dev/{slug}\"),\n                \"pipx\" => format!(\"https://pypi.org/project/{slug}\"),\n                \"npm\" => format!(\"https://www.npmjs.com/package/{slug}\"),\n                _ => format!(\"https://github.com/{slug}\"),\n            }\n        })\n        .collect()\n}\n"
  },
  {
    "path": "src/cli/self_update.rs",
    "content": "use color_eyre::Result;\nuse color_eyre::eyre::bail;\nuse console::style;\nuse self_update::backends::github::Update;\nuse self_update::{Status, cargo_crate_version};\n\nuse crate::cli::version::{ARCH, OS};\nuse crate::config::Settings;\nuse crate::env;\nuse std::collections::BTreeMap;\nuse std::fs;\n#[cfg(target_os = \"macos\")]\nuse std::path::Path;\nuse std::path::PathBuf;\n\n#[derive(Debug, Default, serde::Deserialize)]\nstruct InstructionsToml {\n    message: Option<String>,\n    #[serde(flatten)]\n    commands: BTreeMap<String, String>,\n}\n\nfn read_instructions_file(path: &PathBuf) -> Option<String> {\n    let body = fs::read_to_string(path).ok()?;\n    let parsed: InstructionsToml = toml::from_str(&body).ok()?;\n    if let Some(msg) = parsed.message {\n        return Some(msg);\n    }\n    if let Some((_k, v)) = parsed.commands.into_iter().next() {\n        return Some(v);\n    }\n    None\n}\n\npub fn upgrade_instructions_text() -> Option<String> {\n    if let Some(path) = &*env::MISE_SELF_UPDATE_INSTRUCTIONS\n        && let Some(msg) = read_instructions_file(path)\n    {\n        return Some(msg);\n    }\n    None\n}\n\n/// Appends self-update guidance and packaging instructions (if any) to a message.\npub fn append_self_update_instructions(mut message: String) -> String {\n    if SelfUpdate::is_available() {\n        message.push_str(\"\\nRun `mise self-update` to update mise\");\n    }\n    if let Some(instructions) = upgrade_instructions_text() {\n        message.push('\\n');\n        message.push_str(&instructions);\n    }\n    message\n}\n\n/// Updates mise itself.\n///\n/// Uses the GitHub Releases API to find the latest release and binary.\n/// By default, this will also update any installed plugins.\n/// Uses the `GITHUB_API_TOKEN` environment variable if set for higher rate limits.\n///\n/// This command is not available if mise is installed via a package manager.\n#[derive(Debug, Default, clap::Args)]\n#[clap(verbatim_doc_comment)]\npub struct SelfUpdate {\n    /// Update to a specific version\n    version: Option<String>,\n\n    /// Update even if already up to date\n    #[clap(long, short)]\n    force: bool,\n\n    /// Skip confirmation prompt\n    #[clap(long, short)]\n    yes: bool,\n\n    /// Disable auto-updating plugins\n    #[clap(long)]\n    no_plugins: bool,\n}\n\nimpl SelfUpdate {\n    pub async fn run(self) -> Result<()> {\n        if !Self::is_available() && !self.force {\n            if let Some(instructions) = upgrade_instructions_text() {\n                warn!(\"{}\", instructions);\n            }\n            bail!(\"mise is installed via a package manager, cannot update\");\n        }\n        let status = self.do_update()?;\n\n        if status.updated() {\n            let version = status.version().to_string();\n            let styled_version = style(&version).bright().yellow();\n            miseprintln!(\"Updated mise to {styled_version}\");\n            #[cfg(windows)]\n            if let Err(e) = Self::update_mise_shim(&version).await {\n                warn!(\"Failed to update mise-shim.exe: {e}\");\n            }\n        } else {\n            miseprintln!(\"mise is already up to date\");\n        }\n        if !self.no_plugins {\n            cmd!(&*env::MISE_BIN, \"plugins\", \"update\").run()?;\n        }\n\n        Ok(())\n    }\n\n    fn do_update(&self) -> Result<Status> {\n        // Use block_in_place to allow self_update's blocking HTTP calls\n        // to work within mise's async runtime\n        tokio::task::block_in_place(|| self.do_update_blocking())\n    }\n\n    fn do_update_blocking(&self) -> Result<Status> {\n        let mut update = Update::configure();\n        if let Some(token) = &*env::GITHUB_TOKEN {\n            update.auth_token(token);\n        }\n        #[cfg(windows)]\n        let bin_path_in_archive = \"mise/bin/mise.exe\";\n        #[cfg(not(windows))]\n        let bin_path_in_archive = \"mise/bin/mise\";\n        update\n            .repo_owner(\"jdx\")\n            .repo_name(\"mise\")\n            .bin_name(\"mise\")\n            .current_version(cargo_crate_version!())\n            .bin_path_in_archive(bin_path_in_archive);\n\n        let settings = Settings::try_get();\n        let v = self\n            .version\n            .clone()\n            .map_or_else(\n                || -> Result<String> { Ok(update.build()?.get_latest_release()?.version) },\n                Ok,\n            )\n            .map(|v| format!(\"v{v}\"))?;\n\n        // Check if already up to date (unless --force is specified)\n        let current_version = format!(\"v{}\", cargo_crate_version!());\n        if !self.force && v == current_version {\n            return Ok(Status::UpToDate(current_version));\n        }\n\n        let target = format!(\"{}-{}\", *OS, *ARCH);\n        #[cfg(target_env = \"musl\")]\n        let target = format!(\"{target}-musl\");\n        // Always set target_version_tag to ensure we download the correct release\n        // (fixes semver mismatch across year boundaries, e.g. 2025.x -> 2026.x)\n        update.target_version_tag(&v);\n        #[cfg(windows)]\n        let target = format!(\"mise-{v}-{target}.zip\");\n        #[cfg(not(windows))]\n        let target = format!(\"mise-{v}-{target}.tar.gz\");\n        let status = update\n            .verifying_keys([*include_bytes!(\"../../zipsign.pub\")])\n            .show_download_progress(true)\n            .target(&target)\n            .no_confirm(settings.is_ok_and(|s| s.yes) || self.yes)\n            .build()?\n            .update()?;\n\n        // Verify macOS binary signature after update\n        #[cfg(target_os = \"macos\")]\n        if status.updated() {\n            Self::verify_macos_signature(&env::MISE_BIN)?;\n        }\n\n        Ok(status)\n    }\n\n    #[cfg(windows)]\n    async fn update_mise_shim(version: &str) -> Result<()> {\n        use crate::http::HTTP;\n        use std::io::Read;\n\n        let version = version.strip_prefix('v').unwrap_or(version);\n        let archive_name = format!(\"mise-v{version}-{}-{}.zip\", *OS, *ARCH);\n        let url =\n            format!(\"https://github.com/jdx/mise/releases/download/v{version}/{archive_name}\",);\n        debug!(\"Downloading mise-shim.exe from {url}\");\n\n        let temp_dir = tempfile::tempdir()?;\n        // Use the real archive name so zipsign context matches the release signature\n        let zip_path = temp_dir.path().join(&archive_name);\n        HTTP.download_file(&url, &zip_path, None).await?;\n\n        // Verify the archive signature using the same key as the main update\n        Self::verify_zip_signature(&zip_path)?;\n\n        let file = fs::File::open(&zip_path)?;\n        let mut archive = zip::ZipArchive::new(file)?;\n\n        let mut shim_entry = match archive.by_name(\"mise/bin/mise-shim.exe\") {\n            Ok(entry) => entry,\n            Err(_) => {\n                warn!(\"mise-shim.exe not found in release archive, skipping\");\n                return Ok(());\n            }\n        };\n\n        let dest = env::MISE_BIN\n            .parent()\n            .expect(\"MISE_BIN should have a parent directory\")\n            .join(\"mise-shim.exe\");\n\n        // Write to a temp file first, then rename for atomic replacement\n        let mut buf = Vec::new();\n        shim_entry.read_to_end(&mut buf)?;\n        let temp_shim = temp_dir.path().join(\"mise-shim.exe\");\n        fs::write(&temp_shim, &buf)?;\n        if fs::rename(&temp_shim, &dest).is_err() {\n            // Fallback for cross-filesystem moves\n            fs::copy(&temp_shim, &dest)?;\n        }\n\n        debug!(\"Updated mise-shim.exe at {}\", dest.display());\n        Ok(())\n    }\n\n    #[cfg(windows)]\n    fn verify_zip_signature(path: &std::path::Path) -> Result<()> {\n        let context = path\n            .file_name()\n            .and_then(|s| s.to_str())\n            .map(|s| s.as_bytes())\n            .ok_or_else(|| color_eyre::eyre::eyre!(\"non-UTF8 archive path\"))?;\n\n        let keys = zipsign_api::verify::collect_keys(\n            [*include_bytes!(\"../../zipsign.pub\")].into_iter().map(Ok),\n        )\n        .map_err(|e| color_eyre::eyre::eyre!(\"failed to load verification keys: {e}\"))?;\n\n        let mut file = fs::File::open(path)?;\n        zipsign_api::verify::verify_zip(&mut file, &keys, Some(context))\n            .map_err(|e| color_eyre::eyre::eyre!(\"zip signature verification failed: {e}\"))?;\n\n        debug!(\"Verified zip signature for {}\", path.display());\n        Ok(())\n    }\n\n    pub fn is_available() -> bool {\n        if let Some(b) = *env::MISE_SELF_UPDATE_AVAILABLE {\n            return b;\n        }\n        let has_disable = env::MISE_SELF_UPDATE_DISABLED_PATH.is_some();\n        let has_instructions = env::MISE_SELF_UPDATE_INSTRUCTIONS.is_some();\n        !(has_disable || has_instructions)\n    }\n\n    #[cfg(target_os = \"macos\")]\n    fn verify_macos_signature(binary_path: &Path) -> Result<()> {\n        use std::process::Command;\n\n        debug!(\n            \"Verifying macOS code signature for: {}\",\n            binary_path.display()\n        );\n\n        // Check if codesign is available\n        let codesign_check = Command::new(\"which\").arg(\"codesign\").output();\n\n        if codesign_check.is_err() || !codesign_check.unwrap().status.success() {\n            warn!(\"codesign command not found in PATH, skipping binary signature verification\");\n            warn!(\"This is unusual on macOS - consider verifying your system installation\");\n            return Ok(());\n        }\n\n        // Verify signature and identifier in one step using --test-requirement\n        let output = Command::new(\"codesign\")\n            .args([\n                \"--verify\",\n                \"--deep\",\n                \"--strict\",\n                \"-R=identifier \\\"dev.jdx.mise\\\"\",\n            ])\n            .arg(binary_path)\n            .output()?;\n\n        if !output.status.success() {\n            let stderr = String::from_utf8_lossy(&output.stderr);\n            bail!(\n                \"macOS binary signature verification failed (invalid signature or incorrect identifier): {}\",\n                stderr.trim()\n            );\n        }\n\n        debug!(\"macOS binary signature verified successfully\");\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/self_update_stub.rs",
    "content": "use std::collections::BTreeMap;\nuse std::fs;\nuse std::path::PathBuf;\n\nuse crate::env;\n\npub struct SelfUpdate {}\n\nimpl SelfUpdate {\n    pub fn is_available() -> bool {\n        false\n    }\n}\n\n#[derive(Debug, Default, serde::Deserialize)]\nstruct InstructionsToml {\n    message: Option<String>,\n    #[serde(flatten)]\n    commands: BTreeMap<String, String>,\n}\n\nfn read_instructions_file(path: &PathBuf) -> Option<String> {\n    let body = fs::read_to_string(path).ok()?;\n    let parsed: InstructionsToml = toml::from_str(&body).ok()?;\n    if let Some(msg) = parsed.message {\n        return Some(msg);\n    }\n    if let Some((_k, v)) = parsed.commands.into_iter().next() {\n        return Some(v);\n    }\n    None\n}\n\npub fn upgrade_instructions_text() -> Option<String> {\n    if let Some(path) = &*env::MISE_SELF_UPDATE_INSTRUCTIONS {\n        if let Some(msg) = read_instructions_file(path) {\n            return Some(msg);\n        }\n    }\n    None\n}\n\npub fn append_self_update_instructions(mut message: String) -> String {\n    if let Some(instructions) = upgrade_instructions_text() {\n        message.push('\\n');\n        message.push_str(&instructions);\n    }\n    message\n}\n"
  },
  {
    "path": "src/cli/set.rs",
    "content": "use std::io::Read as _;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse super::args::EnvVarArg;\nuse crate::agecrypt;\nuse crate::config::config_file::ConfigFile;\nuse crate::config::config_file::mise_toml::MiseToml;\nuse crate::config::env_directive::EnvDirective;\nuse crate::config::{Config, ConfigPathOptions, Settings, resolve_target_config_path};\nuse crate::env::{self};\nuse crate::file::display_path;\nuse crate::ui::table;\nuse demand::Input;\nuse eyre::{Result, bail, eyre};\nuse tabled::Tabled;\n\n/// Set environment variables in mise.toml\n///\n/// By default, this command modifies `mise.toml` in the current directory.\n/// If multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\n/// the lowest precedence file (`mise.toml`) will be used.\n/// See https://mise.jdx.dev/configuration.html#target-file-for-write-operations\n///\n/// Use `-E <env>` to create/modify environment-specific config files like `mise.<env>.toml`.\n#[derive(Debug, clap::Args)]\n#[clap(aliases = [\"ev\", \"env-vars\"], verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Set {\n    /// Environment variable(s) to set\n    /// e.g.: NODE_ENV=production\n    #[clap(value_name = \"ENV_VAR\", verbatim_doc_comment)]\n    env_vars: Option<Vec<EnvVarArg>>,\n\n    /// Create/modify an environment-specific config file like .mise.<env>.toml\n    #[clap(short = 'E', long, overrides_with_all = &[\"global\", \"file\"])]\n    env: Option<String>,\n\n    /// Set the environment variable in the global config file\n    #[clap(short, long, verbatim_doc_comment, overrides_with_all = &[\"file\", \"env\"])]\n    global: bool,\n\n    /// [experimental] Encrypt the value with age before storing\n    #[clap(long, requires = \"env_vars\")]\n    age_encrypt: bool,\n\n    /// [experimental] Age identity file for encryption\n    ///\n    /// Defaults to ~/.config/mise/age.txt if it exists\n    #[clap(long, value_name = \"PATH\", requires = \"age_encrypt\", value_hint = clap::ValueHint::FilePath)]\n    age_key_file: Option<PathBuf>,\n\n    /// [experimental] Age recipient (x25519 public key) for encryption\n    ///\n    /// Can be used multiple times. Requires --age-encrypt.\n    #[clap(long, value_name = \"RECIPIENT\", requires = \"age_encrypt\")]\n    age_recipient: Vec<String>,\n\n    /// [experimental] SSH recipient (public key or path) for age encryption\n    ///\n    /// Can be used multiple times. Requires --age-encrypt.\n    #[clap(long, value_name = \"PATH_OR_PUBKEY\", requires = \"age_encrypt\")]\n    age_ssh_recipient: Vec<String>,\n\n    /// Render completions\n    #[clap(long, hide = true)]\n    complete: bool,\n\n    /// The TOML file to update\n    ///\n    /// Can be a file path or directory. If a directory is provided, will create/use mise.toml in that directory.\n    /// Defaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`.\n    #[clap(long, verbatim_doc_comment, required = false, value_hint = clap::ValueHint::AnyPath)]\n    file: Option<PathBuf>,\n\n    /// Show raw values instead of redacting secrets\n    #[clap(long)]\n    no_redact: bool,\n\n    /// Prompt for environment variable values\n    #[clap(long)]\n    prompt: bool,\n\n    /// Remove the environment variable from config file\n    ///\n    /// Can be used multiple times.\n    #[clap(long, value_name = \"ENV_KEY\", verbatim_doc_comment, visible_aliases = [\"rm\", \"unset\"], hide = true)]\n    remove: Option<Vec<String>>,\n\n    /// Read the value from stdin (for multiline input)\n    ///\n    /// When using --stdin, provide a single key without a value.\n    /// The value will be read from stdin until EOF.\n    #[clap(long, conflicts_with = \"prompt\", requires = \"env_vars\")]\n    stdin: bool,\n}\n\nimpl Set {\n    /// Decrypt a value if it's encrypted, otherwise return it as-is\n    async fn decrypt_value_if_needed(\n        key: &str,\n        value: &str,\n        directive: Option<&EnvDirective>,\n    ) -> Result<String> {\n        // If we have an Age directive, use the specialized decryption\n        if let Some(EnvDirective::Age { .. }) = directive {\n            agecrypt::decrypt_age_directive(directive.unwrap())\n                .await\n                .map_err(|e| eyre!(\"[experimental] Failed to decrypt {}: {}\", key, e))\n        }\n        // Not encrypted, return as-is\n        else {\n            Ok(value.to_string())\n        }\n    }\n    pub async fn run(mut self) -> Result<()> {\n        if self.complete {\n            return self.complete().await;\n        }\n        match (&self.remove, &self.env_vars) {\n            (None, None) => {\n                return self.list_all().await;\n            }\n            (None, Some(env_vars))\n                if env_vars.iter().all(|ev| ev.value.is_none()) && !self.prompt && !self.stdin =>\n            {\n                return self.get().await;\n            }\n            _ => {}\n        }\n\n        let filename = self.filename()?;\n        let mut mise_toml = get_mise_toml(&filename)?;\n\n        if let Some(env_names) = &self.remove {\n            for name in env_names {\n                mise_toml.remove_env(name)?;\n            }\n        }\n\n        if let Some(env_vars) = &self.env_vars\n            && env_vars.len() == 1\n            && env_vars[0].value.is_none()\n            && !self.prompt\n            && !self.stdin\n        {\n            let key = &env_vars[0].key;\n            // Use Config's centralized env loading which handles decryption\n            let full_config = Config::get().await?;\n            let env = full_config.env().await?;\n            match env.get(key) {\n                Some(value) => {\n                    miseprintln!(\"{value}\");\n                }\n                None => bail!(\"Environment variable {key} not found\"),\n            }\n            return Ok(());\n        }\n\n        if let Some(mut env_vars) = self.env_vars.take() {\n            // Prompt for values if requested\n            if self.prompt {\n                let theme = crate::ui::theme::get_theme();\n                for ev in &mut env_vars {\n                    if ev.value.is_none() {\n                        let prompt_msg = format!(\"Enter value for {}\", ev.key);\n                        let value = Input::new(&prompt_msg)\n                            .password(self.age_encrypt) // Mask input if encrypting\n                            .theme(&theme)\n                            .run()?;\n                        ev.value = Some(value);\n                    }\n                }\n            }\n\n            // Read value from stdin if requested\n            if self.stdin {\n                if env_vars.len() != 1 {\n                    bail!(\"--stdin requires exactly one environment variable key\");\n                }\n                let ev = &mut env_vars[0];\n                if ev.value.is_some() {\n                    bail!(\n                        \"--stdin reads the value from stdin; do not provide a value with KEY=VALUE syntax\"\n                    );\n                }\n                let mut value = String::new();\n                std::io::stdin().read_to_string(&mut value)?;\n                // Strip a single trailing newline (matches `gh secret set` behavior)\n                if value.ends_with(\"\\r\\n\") {\n                    value.truncate(value.len() - 2);\n                } else if value.ends_with('\\n') {\n                    value.truncate(value.len() - 1);\n                }\n                ev.value = Some(value);\n            }\n\n            // Handle age encryption if requested\n            if self.age_encrypt {\n                Settings::get().ensure_experimental(\"age encryption\")?;\n                // Collect recipients once before the loop to avoid repeated I/O\n                let recipients = self.collect_age_recipients().await?;\n                for ev in env_vars {\n                    match ev.value {\n                        Some(value) => {\n                            let age_directive =\n                                agecrypt::create_age_directive(ev.key.clone(), &value, &recipients)\n                                    .await?;\n                            if let crate::config::env_directive::EnvDirective::Age {\n                                value: encrypted_value,\n                                format,\n                                ..\n                            } = age_directive\n                            {\n                                mise_toml.update_env_age(&ev.key, &encrypted_value, format)?;\n                            }\n                        }\n                        None => bail!(\"{} has no value\", ev.key),\n                    }\n                }\n            } else {\n                for ev in env_vars {\n                    match ev.value {\n                        Some(value) => mise_toml.update_env(&ev.key, value)?,\n                        None => bail!(\"{} has no value\", ev.key),\n                    }\n                }\n            }\n        }\n        mise_toml.save()\n    }\n\n    async fn complete(&self) -> Result<()> {\n        let config = Config::get().await?;\n        for ev in self.cur_env(&config).await? {\n            println!(\"{}\", ev.key);\n        }\n        Ok(())\n    }\n\n    async fn list_all(self) -> Result<()> {\n        let config = Config::get().await?;\n        // Ensure env_results (and thus env-based redactions) are loaded\n        // even when --file or -E bypasses env_with_sources() in cur_env().\n        if !self.no_redact {\n            let _ = config.env_results().await?;\n        }\n        let mut env = self.cur_env(&config).await?;\n        if !self.no_redact {\n            for row in &mut env {\n                row.value = config.redact(&row.value);\n            }\n        }\n        let mut table = tabled::Table::new(env);\n        table::default_style(&mut table, false);\n        miseprintln!(\"{table}\");\n        Ok(())\n    }\n\n    async fn get(self) -> Result<()> {\n        // Determine config file path before moving env_vars\n        let config_path = if let Some(file) = &self.file {\n            Some(file.clone())\n        } else if self.env.is_some() {\n            Some(self.filename()?)\n        } else if !self.global {\n            // Check for local config file when no specific file or environment is specified\n            // Check for mise.toml in current directory first\n            let cwd = env::current_dir()?;\n            let mise_toml = cwd.join(\"mise.toml\");\n            if mise_toml.exists() {\n                Some(mise_toml)\n            } else {\n                // Fall back to .mise.toml if mise.toml doesn't exist\n                let dot_mise_toml = cwd.join(\".mise.toml\");\n                if dot_mise_toml.exists() {\n                    Some(dot_mise_toml)\n                } else {\n                    None // Fall back to global config if no local config exists\n                }\n            }\n        } else {\n            None\n        };\n\n        let filter = self.env_vars.unwrap();\n\n        // Handle global config case first\n        if config_path.is_none() {\n            let config = Config::get().await?;\n            let env_with_sources = config.env_with_sources().await?;\n            // env_with_sources already contains decrypted values\n            for eva in filter {\n                if let Some((value, _source)) = env_with_sources.get(&eva.key) {\n                    miseprintln!(\"{value}\");\n                } else {\n                    bail!(\"Environment variable {} not found\", eva.key);\n                }\n            }\n            return Ok(());\n        }\n\n        // Get the config to access directives directly\n        let config = MiseToml::from_file(&config_path.unwrap()).unwrap_or_default();\n\n        // For local configs, check directives directly\n        let env_entries = config.env_entries()?;\n        for eva in filter {\n            match env_entries.iter().find_map(|ev| match ev {\n                EnvDirective::Val(k, v, _) if k == &eva.key => Some((v.clone(), Some(ev))),\n                EnvDirective::Age {\n                    key: k, value: v, ..\n                } if k == &eva.key => Some((v.clone(), Some(ev))),\n                _ => None,\n            }) {\n                Some((value, directive)) => {\n                    // this does not obey strict=false, since we want to fail if the decryption fails\n                    let decrypted =\n                        Self::decrypt_value_if_needed(&eva.key, &value, directive).await?;\n                    miseprintln!(\"{decrypted}\");\n                }\n                None => bail!(\"Environment variable {} not found\", eva.key),\n            }\n        }\n        Ok(())\n    }\n\n    async fn cur_env(&self, config: &Arc<Config>) -> Result<Vec<Row>> {\n        let redact = !self.no_redact;\n        let rows = if let Some(file) = &self.file {\n            let mise_toml = MiseToml::from_file(file).unwrap_or_default();\n            Self::rows_from_directives(mise_toml.env_entries()?, file, redact)\n        } else if self.env.is_some() {\n            // When -E flag is used, read from the environment-specific file\n            let filename = self.filename()?;\n            let mise_toml = MiseToml::from_file(&filename).unwrap_or_default();\n            Self::rows_from_directives(mise_toml.env_entries()?, &filename, redact)\n        } else {\n            config\n                .env_with_sources()\n                .await?\n                .iter()\n                .map(|(key, (value, source))| Row {\n                    key: key.clone(),\n                    value: value.clone(),\n                    source: display_path(source),\n                })\n                .collect()\n        };\n        Ok(rows)\n    }\n\n    fn rows_from_directives(\n        directives: Vec<EnvDirective>,\n        source: &Path,\n        redact: bool,\n    ) -> Vec<Row> {\n        directives\n            .into_iter()\n            .filter_map(|ed| match ed {\n                EnvDirective::Val(key, value, opts) => Some(Row {\n                    key,\n                    value: if redact && opts.redact.unwrap_or(false) {\n                        \"[redacted]\".to_string()\n                    } else {\n                        value\n                    },\n                    source: display_path(source),\n                }),\n                EnvDirective::Age {\n                    key,\n                    value,\n                    options,\n                    ..\n                } => Some(Row {\n                    key,\n                    // Age defaults to redacting unless explicitly redact=false\n                    value: if redact && options.redact != Some(false) {\n                        \"[redacted]\".to_string()\n                    } else {\n                        value\n                    },\n                    source: display_path(source),\n                }),\n                _ => None,\n            })\n            .collect()\n    }\n\n    fn filename(&self) -> Result<PathBuf> {\n        let opts = ConfigPathOptions {\n            global: self.global,\n            path: self.file.clone(),\n            env: self.env.clone(),\n            cwd: None,                // Use current working directory\n            prefer_toml: true,        // mise set only works with TOML files\n            prevent_home_local: true, // When in HOME, use global config\n        };\n        resolve_target_config_path(opts)\n    }\n\n    async fn collect_age_recipients(&self) -> Result<Vec<Box<dyn age::Recipient + Send>>> {\n        use age::Recipient;\n\n        let mut recipients: Vec<Box<dyn Recipient + Send>> = Vec::new();\n\n        // Add x25519 recipients from command line\n        for recipient_str in &self.age_recipient {\n            if let Some(recipient) = agecrypt::parse_recipient(recipient_str)? {\n                recipients.push(recipient);\n            }\n        }\n\n        // Add SSH recipients from command line\n        for ssh_arg in &self.age_ssh_recipient {\n            let path = Path::new(ssh_arg);\n            if path.exists() {\n                // It's a file path\n                recipients.push(agecrypt::load_ssh_recipient_from_path(path).await?);\n            } else {\n                // Try to parse as a direct SSH public key\n                if let Some(recipient) = agecrypt::parse_recipient(ssh_arg)? {\n                    recipients.push(recipient);\n                }\n            }\n        }\n\n        // If no recipients were provided, use defaults\n        if recipients.is_empty()\n            && (self.age_recipient.is_empty()\n                && self.age_ssh_recipient.is_empty()\n                && self.age_key_file.is_none())\n        {\n            recipients = agecrypt::load_recipients_from_defaults().await?;\n        }\n\n        // Load recipients from key file if specified\n        if let Some(key_file) = &self.age_key_file {\n            let key_file_recipients = agecrypt::load_recipients_from_key_file(key_file).await?;\n            recipients.extend(key_file_recipients);\n        }\n\n        if recipients.is_empty() {\n            bail!(\n                \"[experimental] No age recipients provided. Use --age-recipient, --age-ssh-recipient, or --age-key-file\"\n            );\n        }\n\n        Ok(recipients)\n    }\n}\n\nfn get_mise_toml(filename: &Path) -> Result<MiseToml> {\n    let path = env::current_dir()?.join(filename);\n    let mise_toml = if path.exists() {\n        MiseToml::from_file(&path)?\n    } else {\n        MiseToml::init(&path)\n    };\n\n    Ok(mise_toml)\n}\n\n#[derive(Tabled, Debug, Clone)]\nstruct Row {\n    key: String,\n    value: String,\n    source: String,\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise set NODE_ENV=production</bold>\n\n    $ <bold>mise set NODE_ENV</bold>\n    production\n\n    $ <bold>mise set -E staging NODE_ENV=staging</bold>\n    # creates or modifies mise.staging.toml\n\n    $ <bold>mise set</bold>\n    key       value       source\n    NODE_ENV  production  ~/.config/mise/config.toml\n\n    $ <bold>mise set --prompt PASSWORD</bold>\n    Enter value for PASSWORD: [hidden input]\n\n    <bold><underline>Multiline Values (--stdin):</underline></bold>\n\n    $ <bold>cat private.key | mise set --stdin MY_KEY</bold>\n\n    $ <bold>printf \"line1\\nline2\" | mise set --stdin MY_KEY</bold>\n\n    <bold><underline>[experimental] Age Encryption:</underline></bold>\n\n    $ <bold>mise set --age-encrypt API_KEY=secret</bold>\n\n    $ <bold>mise set --age-encrypt --prompt API_KEY</bold>\n    Enter value for API_KEY: [hidden input]\n\"#\n);\n"
  },
  {
    "path": "src/cli/settings/add.rs",
    "content": "use eyre::{Result, eyre};\n\nuse crate::cli::settings::set::set;\n\n/// Adds a setting to the configuration file\n///\n/// Used with an array setting, this will append the value to the array.\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct SettingsAdd {\n    /// The setting to set\n    #[clap()]\n    pub setting: String,\n    /// The value to set (optional if provided as KEY=VALUE)\n    pub value: Option<String>,\n    /// Use the local config file instead of the global one\n    #[clap(long, short)]\n    pub local: bool,\n}\n\nimpl SettingsAdd {\n    pub fn run(self) -> Result<()> {\n        match self.value {\n            Some(value) => set(&self.setting, &value, true, self.local),\n            None => {\n                let (key, value) = self.setting.split_once('=').ok_or_else(|| {\n                    eyre!(\n                        \"Usage: mise settings add <KEY>=<VALUE> or mise settings add <KEY> <VALUE>\"\n                    )\n                })?;\n                set(key, value, true, self.local)\n            }\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise settings add disable_hints python_multi</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/settings/get.rs",
    "content": "use crate::config;\nuse crate::config::Settings;\nuse eyre::bail;\n\n/// Show a current setting\n///\n/// This is the contents of a single entry in ~/.config/mise/config.toml\n///\n/// Note that aliases are also stored in this file\n/// but managed separately with `mise tool-alias get`\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct SettingsGet {\n    /// The setting to show\n    pub setting: String,\n    /// Use the local config file instead of the global one\n    #[clap(long, short)]\n    pub local: bool,\n}\n\nimpl SettingsGet {\n    pub fn run(self) -> eyre::Result<()> {\n        let settings = if self.local {\n            let partial = Settings::parse_settings_file(&config::local_toml_config_path())\n                .unwrap_or_default();\n            Settings::partial_as_dict(&partial)?\n        } else {\n            Settings::get().as_dict()?\n        };\n        let mut value = toml::Value::Table(settings);\n        let mut key = Some(self.setting.as_str());\n        while let Some(k) = key {\n            let k = k\n                .split_once('.')\n                .map(|(a, b)| (a, Some(b)))\n                .unwrap_or((k, None));\n            if let Some(v) = value.as_table().and_then(|t| t.get(k.0)) {\n                key = k.1;\n                value = v.clone()\n            } else {\n                bail!(\"Unknown setting: {}\", self.setting);\n            }\n        }\n        match value {\n            toml::Value::String(s) => miseprintln!(\"{s}\"),\n            value => miseprintln!(\"{value}\"),\n        }\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise settings get idiomatic_version_file</bold>\n    true\n\"#\n);\n"
  },
  {
    "path": "src/cli/settings/ls.rs",
    "content": "use crate::config;\nuse crate::config::settings::{SETTINGS_META, SettingsPartial, SettingsType};\nuse crate::config::{ALL_TOML_CONFIG_FILES, Settings};\nuse crate::file::display_path;\nuse crate::ui::table;\nuse eyre::Result;\nuse std::path::{Path, PathBuf};\nuse tabled::{Table, Tabled};\n\n/// Show current settings\n///\n/// This is the contents of ~/.config/mise/config.toml\n///\n/// Note that aliases are also stored in this file\n/// but managed separately with `mise tool-alias`\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct SettingsLs {\n    /// Name of setting\n    pub setting: Option<String>,\n\n    /// List all settings\n    #[clap(long, short)]\n    all: bool,\n\n    /// Output in JSON format\n    #[clap(long, short = 'J', group = \"output\")]\n    json: bool,\n\n    /// Use the local config file instead of the global one\n    #[clap(long, short, global = true)]\n    pub local: bool,\n\n    /// Output in TOML format\n    #[clap(long, short = 'T', group = \"output\")]\n    toml: bool,\n\n    /// Print all settings with descriptions for shell completions\n    #[clap(long, hide = true)]\n    complete: bool,\n\n    /// Output in JSON format with sources\n    #[clap(long, group = \"output\")]\n    json_extended: bool,\n}\n\nfn settings_type_to_string(st: &SettingsType) -> String {\n    match st {\n        SettingsType::Bool => \"boolean\".to_string(),\n        SettingsType::BoolOrString => \"boolean | string\".to_string(),\n        SettingsType::String => \"string\".to_string(),\n        SettingsType::Integer => \"number\".to_string(),\n        SettingsType::Duration => \"number\".to_string(),\n        SettingsType::Path => \"string\".to_string(),\n        SettingsType::Url => \"string\".to_string(),\n        SettingsType::ListString => \"array\".to_string(),\n        SettingsType::ListPath => \"array\".to_string(),\n        SettingsType::SetString => \"array\".to_string(),\n        SettingsType::IndexMap => \"object\".to_string(),\n    }\n}\n\nimpl SettingsLs {\n    pub fn run(self) -> Result<()> {\n        if self.complete {\n            return self.complete();\n        }\n        let mut rows: Vec<Row> = if self.local {\n            let source = config::local_toml_config_path();\n            let partial = Settings::parse_settings_file(&source).unwrap_or_default();\n            Row::from_partial(&partial, &source)?\n        } else {\n            let mut rows = vec![];\n            if self.all {\n                for (k, v) in Settings::get().as_dict()? {\n                    rows.extend(Row::from_toml(k.to_string(), v, None));\n                }\n            }\n            rows.extend(ALL_TOML_CONFIG_FILES.iter().rev().flat_map(|source| {\n                match Settings::parse_settings_file(source) {\n                    Ok(partial) => match Row::from_partial(&partial, source) {\n                        Ok(rows) => rows,\n                        Err(e) => {\n                            warn!(\"Error parsing {}: {}\", display_path(source), e);\n                            vec![]\n                        }\n                    },\n                    Err(e) => {\n                        warn!(\"Error parsing {}: {}\", display_path(source), e);\n                        vec![]\n                    }\n                }\n            }));\n            rows\n        };\n        if let Some(key) = &self.setting {\n            rows.retain(|r| &r.key == key || r.key.starts_with(&format!(\"{key}.\")));\n        }\n        for k in Settings::hidden_configs() {\n            rows.retain(|r| &r.key != k || r.key.starts_with(&format!(\"{k}.\")));\n        }\n        if self.json {\n            self.print_json(rows)?;\n        } else if self.json_extended {\n            self.print_json_extended(rows)?;\n        } else if self.toml {\n            self.print_toml(rows)?;\n        } else {\n            let mut table = Table::new(rows);\n            table::default_style(&mut table, false);\n            miseprintln!(\"{}\", table.to_string());\n        }\n        Ok(())\n    }\n\n    fn complete(&self) -> Result<()> {\n        for (k, sm) in SETTINGS_META.iter() {\n            println!(\"{k}:{}\", sm.description.replace(\":\", \"\\\\:\"));\n        }\n        Ok(())\n    }\n\n    fn print_json(&self, rows: Vec<Row>) -> Result<()> {\n        let mut table = serde_json::Map::new();\n        for row in rows {\n            if let Some((key, subkey)) = row.key.split_once('.') {\n                let subtable = table\n                    .entry(key)\n                    .or_insert_with(|| serde_json::Value::Object(serde_json::Map::new()));\n                let subtable = subtable.as_object_mut().unwrap();\n                subtable.insert(subkey.to_string(), toml_value_to_json_value(row.toml_value));\n            } else {\n                table.insert(row.key, toml_value_to_json_value(row.toml_value));\n            }\n        }\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&table)?);\n        Ok(())\n    }\n\n    fn print_json_extended(&self, rows: Vec<Row>) -> Result<()> {\n        let mut table = serde_json::Map::new();\n        for row in rows {\n            let mut entry = serde_json::Map::new();\n            entry.insert(\n                \"value\".to_string(),\n                toml_value_to_json_value(row.toml_value),\n            );\n            entry.insert(\"type\".to_string(), row.type_.into());\n            if let Some(description) = row.description {\n                entry.insert(\"description\".to_string(), description.into());\n            }\n            if let Some(source) = row.source {\n                entry.insert(\"source\".to_string(), source.to_string_lossy().into());\n            }\n            if let Some((key, subkey)) = row.key.split_once('.') {\n                let subtable = table\n                    .entry(key)\n                    .or_insert_with(|| serde_json::Value::Object(serde_json::Map::new()));\n                let subtable = subtable.as_object_mut().unwrap();\n                subtable.insert(subkey.to_string(), entry.into());\n            } else {\n                table.insert(row.key, entry.into());\n            }\n        }\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&table)?);\n        Ok(())\n    }\n\n    fn print_toml(&self, rows: Vec<Row>) -> Result<()> {\n        let mut table = toml::Table::new();\n        for row in rows {\n            if let Some((key, subkey)) = row.key.split_once('.') {\n                let subtable = table\n                    .entry(key)\n                    .or_insert_with(|| toml::Value::Table(toml::Table::new()));\n                let subtable = subtable.as_table_mut().unwrap();\n                subtable.insert(subkey.to_string(), row.toml_value);\n                continue;\n            } else {\n                table.insert(row.key, row.toml_value);\n            }\n        }\n        miseprintln!(\"{}\", toml::to_string(&table)?);\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise settings ls</bold>\n    idiomatic_version_file = false\n    ...\n\n    $ <bold>mise settings ls python</bold>\n    default_packages_file = \"~/.default-python-packages\"\n    ...\n\"#\n);\n\n#[derive(Debug, Tabled)]\n#[tabled(rename_all = \"PascalCase\")]\nstruct Row {\n    key: String,\n    value: String,\n    #[tabled(display = \"Self::display_option_path\")]\n    source: Option<PathBuf>,\n    #[tabled(skip)]\n    toml_value: toml::Value,\n    #[tabled(skip)]\n    description: Option<String>,\n    #[tabled(skip)]\n    type_: String,\n}\n\nimpl Row {\n    fn display_option_path(o: &Option<PathBuf>) -> String {\n        o.as_ref().map(display_path).unwrap_or_default()\n    }\n\n    fn from_partial(p: &SettingsPartial, source: &Path) -> Result<Vec<Self>> {\n        let rows = Settings::partial_as_dict(p)?\n            .into_iter()\n            .flat_map(|(k, v)| Self::from_toml(k.to_string(), v, Some(source.to_path_buf())))\n            .collect();\n        Ok(rows)\n    }\n\n    fn from_toml(k: String, v: toml::Value, source: Option<PathBuf>) -> Vec<Self> {\n        let mut rows = vec![];\n        if let Some(table) = v.as_table() {\n            if !table.is_empty() {\n                rows.reserve(table.len());\n                let meta = SETTINGS_META.get(k.as_str());\n                let desc = meta.map(|sm| sm.description.to_string());\n                let type_str = meta\n                    .map(|sm| settings_type_to_string(&sm.type_))\n                    .unwrap_or_default();\n\n                for (subkey, subvalue) in table {\n                    rows.push(Row {\n                        key: format!(\"{k}.{subkey}\"),\n                        value: subvalue.to_string(),\n                        type_: type_str.clone(),\n                        source: source.clone(),\n                        toml_value: subvalue.clone(),\n                        description: desc.clone(),\n                    });\n                }\n            }\n        } else {\n            let meta = SETTINGS_META.get(k.as_str());\n            rows.push(Row {\n                key: k.clone(),\n                value: v.to_string(),\n                type_: meta\n                    .map(|sm| settings_type_to_string(&sm.type_))\n                    .unwrap_or_default(),\n                source,\n                toml_value: v,\n                description: meta.map(|sm| sm.description.to_string()),\n            });\n        }\n        rows\n    }\n}\n\nfn toml_value_to_json_value(v: toml::Value) -> serde_json::Value {\n    match v {\n        toml::Value::String(s) => s.into(),\n        toml::Value::Integer(i) => i.into(),\n        toml::Value::Boolean(b) => b.into(),\n        toml::Value::Float(f) => f.into(),\n        toml::Value::Table(t) => {\n            let mut table = serde_json::Map::new();\n            for (k, v) in t {\n                table.insert(k, toml_value_to_json_value(v));\n            }\n            table.into()\n        }\n        toml::Value::Array(a) => a.into_iter().map(toml_value_to_json_value).collect(),\n        v => v.to_string().into(),\n    }\n}\n"
  },
  {
    "path": "src/cli/settings/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nmod add;\nmod get;\nmod ls;\nmod set;\nmod unset;\n\n#[derive(Debug, clap::Args)]\n#[clap(about = \"Manage settings\", after_long_help = AFTER_LONG_HELP)]\npub struct Settings {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    #[clap(flatten)]\n    ls: ls::SettingsLs,\n\n    /// Setting value to set\n    #[clap(conflicts_with = \"all\")]\n    value: Option<String>,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Add(add::SettingsAdd),\n    Get(get::SettingsGet),\n    #[clap(visible_alias = \"list\")]\n    Ls(ls::SettingsLs),\n    Set(set::SettingsSet),\n    Unset(unset::SettingsUnset),\n}\n\nimpl Commands {\n    pub fn run(self) -> Result<()> {\n        match self {\n            Self::Add(cmd) => cmd.run(),\n            Self::Get(cmd) => cmd.run(),\n            Self::Ls(cmd) => cmd.run(),\n            Self::Set(cmd) => cmd.run(),\n            Self::Unset(cmd) => cmd.run(),\n        }\n    }\n}\n\nimpl Settings {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self.command.unwrap_or_else(|| {\n            if let Some(value) = self.value {\n                Commands::Set(set::SettingsSet {\n                    setting: self.ls.setting.unwrap(),\n                    value: Some(value),\n                    local: self.ls.local,\n                })\n            } else if let Some(setting) = self.ls.setting {\n                if let Some((setting, value)) = setting.split_once('=') {\n                    Commands::Set(set::SettingsSet {\n                        setting: setting.to_string(),\n                        value: Some(value.to_string()),\n                        local: self.ls.local,\n                    })\n                } else {\n                    Commands::Get(get::SettingsGet {\n                        setting,\n                        local: self.ls.local,\n                    })\n                }\n            } else {\n                Commands::Ls(self.ls)\n            }\n        });\n\n        cmd.run()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n    # list all settings\n    $ <bold>mise settings</bold>\n\n    # get the value of the setting \"always_keep_download\"\n    $ <bold>mise settings always_keep_download</bold>\n\n    # set the value of the setting \"always_keep_download\" to \"true\"\n    $ <bold>mise settings always_keep_download=true</bold>\n\n    # set the value of the setting \"node.mirror_url\" to \"https://npm.taobao.org/mirrors/node\"\n    $ <bold>mise settings node.mirror_url https://npm.taobao.org/mirrors/node</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/settings/set.rs",
    "content": "use eyre::{Result, bail, eyre};\nuse toml_edit::DocumentMut;\n\nuse crate::config::settings::{SETTINGS_META, SettingsFile, SettingsType, parse_url_replacements};\nuse crate::toml::dedup_toml_array;\nuse crate::{config, duration, file};\n\n/// Add/update a setting\n///\n/// This modifies the contents of ~/.config/mise/config.toml by default.\n/// With `--local`, modifies the local config file instead.\n/// See https://mise.jdx.dev/configuration.html#target-file-for-write-operations\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"create\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct SettingsSet {\n    /// The setting to set\n    #[clap()]\n    pub setting: String,\n    /// The value to set (optional if provided as KEY=VALUE)\n    pub value: Option<String>,\n    /// Use the local config file instead of the global one\n    #[clap(long, short)]\n    pub local: bool,\n}\n\nimpl SettingsSet {\n    pub fn run(self) -> Result<()> {\n        match self.value {\n            Some(value) => set(&self.setting, &value, false, self.local),\n            None => {\n                let (key, value) = self.setting.split_once('=').ok_or_else(|| {\n                    eyre!(\n                        \"Usage: mise settings set <KEY>=<VALUE> or mise settings set <KEY> <VALUE>\"\n                    )\n                })?;\n                set(key, value, false, self.local)\n            }\n        }\n    }\n}\n\npub fn set(mut key: &str, value: &str, add: bool, local: bool) -> Result<()> {\n    let meta = match SETTINGS_META.get(key) {\n        Some(meta) => meta,\n        None => {\n            bail!(\"Unknown setting: {}\", key);\n        }\n    };\n\n    let value = match meta.type_ {\n        SettingsType::Bool => parse_bool(value)?,\n        SettingsType::Integer => parse_i64(value)?,\n        SettingsType::Duration => parse_duration(value)?,\n        SettingsType::Url | SettingsType::Path | SettingsType::String => value.into(),\n        SettingsType::ListString => parse_list_by_comma(value)?,\n        SettingsType::ListPath => parse_list_by_colon(value)?,\n        SettingsType::SetString => parse_set_by_comma(value)?,\n        SettingsType::IndexMap => parse_indexmap_by_json(value)?,\n        SettingsType::BoolOrString => parse_bool(value).unwrap_or_else(|_| value.into()),\n    };\n\n    let path = if local {\n        config::local_toml_config_path()\n    } else {\n        config::global_config_path()\n    };\n    file::create_dir_all(path.parent().unwrap())?;\n    let raw = file::read_to_string(&path).unwrap_or_default();\n    let mut config: DocumentMut = raw.parse()?;\n    if !config.contains_key(\"settings\") {\n        config[\"settings\"] = toml_edit::Item::Table(toml_edit::Table::new());\n    }\n    if let Some(mut settings) = config[\"settings\"].as_table_mut() {\n        if let Some((parent_key, child_key)) = key.split_once('.') {\n            key = child_key;\n            settings = settings\n                .entry(parent_key)\n                .or_insert({\n                    let mut t = toml_edit::Table::new();\n                    t.set_implicit(true);\n                    toml_edit::Item::Table(t)\n                })\n                .as_table_mut()\n                .unwrap();\n        }\n\n        let value = match settings.get(key).map(|c| c.as_array()) {\n            Some(Some(array)) if add => {\n                let mut new_array = array.clone();\n                new_array.extend(value.as_array().unwrap().iter().cloned());\n                match meta.type_ {\n                    SettingsType::SetString => dedup_toml_array(&new_array).into(),\n                    _ => new_array.into(),\n                }\n            }\n            _ => value,\n        };\n        settings.insert(key, value.into());\n\n        // validate\n        let _: SettingsFile = toml::from_str(&config.to_string())?;\n\n        file::write(path, config.to_string())?;\n    }\n    Ok(())\n}\n\nfn parse_list_by_comma(value: &str) -> Result<toml_edit::Value> {\n    if value.is_empty() || value == \"[]\" {\n        return Ok(toml_edit::Array::new().into());\n    }\n    Ok(value.split(',').map(|s| s.trim().to_string()).collect())\n}\n\nfn parse_list_by_colon(value: &str) -> Result<toml_edit::Value> {\n    if value.is_empty() || value == \"[]\" {\n        return Ok(toml_edit::Array::new().into());\n    }\n    Ok(value.split(':').map(|s| s.trim().to_string()).collect())\n}\n\nfn parse_set_by_comma(value: &str) -> Result<toml_edit::Value> {\n    if value.is_empty() || value == \"[]\" {\n        return Ok(toml_edit::Array::new().into());\n    }\n    let array: toml_edit::Array = value.split(',').map(|s| s.trim().to_string()).collect();\n    Ok(dedup_toml_array(&array).into())\n}\n\nfn parse_bool(value: &str) -> Result<toml_edit::Value> {\n    match value.to_lowercase().as_str() {\n        \"1\" | \"true\" | \"yes\" | \"y\" => Ok(true.into()),\n        \"0\" | \"false\" | \"no\" | \"n\" => Ok(false.into()),\n        _ => Err(eyre!(\"{} must be true or false\", value)),\n    }\n}\n\nfn parse_i64(value: &str) -> Result<toml_edit::Value> {\n    match value.parse::<i64>() {\n        Ok(value) => Ok(value.into()),\n        Err(_) => Err(eyre!(\"{} must be a number\", value)),\n    }\n}\n\nfn parse_duration(value: &str) -> Result<toml_edit::Value> {\n    duration::parse_duration(value)?;\n    Ok(value.into())\n}\n\nfn parse_indexmap_by_json(value: &str) -> Result<toml_edit::Value> {\n    let index_map = parse_url_replacements(value)\n        .map_err(|e| eyre!(\"Failed to parse JSON for IndexMap: {}\", e))?;\n    Ok(toml_edit::Value::InlineTable({\n        let mut table = toml_edit::InlineTable::new();\n        for (k, v) in index_map {\n            table.insert(&k, toml_edit::Value::String(toml_edit::Formatted::new(v)));\n        }\n        table\n    }))\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise settings idiomatic_version_file=true</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/settings/unset.rs",
    "content": "use eyre::Result;\nuse toml_edit::DocumentMut;\n\nuse crate::config::settings::SettingsFile;\nuse crate::{config, file};\n\n/// Clears a setting\n///\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"rm\", \"remove\", \"delete\", \"del\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct SettingsUnset {\n    /// The setting to remove\n    pub key: String,\n\n    /// Use the local config file instead of the global one\n    #[clap(long, short)]\n    pub local: bool,\n}\n\nimpl SettingsUnset {\n    pub fn run(self) -> Result<()> {\n        unset(&self.key, self.local)\n    }\n}\n\npub fn unset(mut key: &str, local: bool) -> Result<()> {\n    let path = if local {\n        config::local_toml_config_path()\n    } else {\n        config::global_config_path()\n    };\n    let raw = file::read_to_string(&path)?;\n    let mut config: DocumentMut = raw.parse()?;\n    if let Some(mut settings) = config[\"settings\"].as_table_mut() {\n        if let Some((parent_key, child_key)) = key.split_once('.') {\n            key = child_key;\n            settings = settings\n                .entry(parent_key)\n                .or_insert({\n                    let mut t = toml_edit::Table::new();\n                    t.set_implicit(true);\n                    toml_edit::Item::Table(t)\n                })\n                .as_table_mut()\n                .unwrap();\n        }\n        settings.remove(key);\n        // validate\n        let _: SettingsFile = toml::from_str(&config.to_string())?;\n\n        file::write(&path, config.to_string())?;\n    }\n    Ok(())\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise settings unset idiomatic_version_file</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/shell.rs",
    "content": "use color_eyre::eyre::{Result, eyre};\nuse console::style;\nuse heck::ToShoutySnakeCase;\nuse indoc::formatdoc;\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::env;\nuse crate::shell::get_shell;\nuse crate::toolset::{InstallOptions, ToolSource, ToolsetBuilder};\n\n/// Sets a tool version for the current session.\n///\n/// Only works in a session where mise is already activated.\n///\n/// This works by setting environment variables for the current shell session\n/// such as `MISE_NODE_VERSION=20` which is \"eval\"ed as a shell function created by `mise activate`.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"sh\", after_long_help = AFTER_LONG_HELP)]\npub struct Shell {\n    /// Tool(s) to use\n    #[clap(value_name = \"TOOL@VERSION\", required = true)]\n    tool: Vec<ToolArg>,\n\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    jobs: Option<usize>,\n\n    /// Removes a previously set version\n    #[clap(long, short)]\n    unset: bool,\n\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets --jobs=1\n    #[clap(long, overrides_with = \"jobs\")]\n    raw: bool,\n}\n\nimpl Shell {\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        if !env::is_activated() {\n            err_inactive()?;\n        }\n\n        let shell = get_shell(None).expect(\"no shell detected\");\n\n        if self.unset {\n            for ta in &self.tool {\n                let op = shell.unset_env(&format!(\n                    \"MISE_{}_VERSION\",\n                    ta.ba.short.to_shouty_snake_case()\n                ));\n                print!(\"{op}\");\n            }\n            return Ok(());\n        }\n\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .build(&config)\n            .await?;\n        let opts = InstallOptions {\n            force: false,\n            jobs: self.jobs,\n            raw: self.raw,\n            ..Default::default()\n        };\n        let (_, missing) = ts.install_missing_versions(&mut config, &opts).await?;\n        ts.notify_missing_versions(missing);\n\n        for (p, tv) in ts.list_current_installed_versions(&config) {\n            let source = &ts.versions.get(p.ba().as_ref()).unwrap().source;\n            if matches!(source, ToolSource::Argument) {\n                let k = format!(\"MISE_{}_VERSION\", p.id().to_shouty_snake_case());\n                let op = shell.set_env(&k, &tv.version);\n                print!(\"{op}\");\n            }\n        }\n\n        Ok(())\n    }\n}\n\nfn err_inactive() -> Result<()> {\n    Err(eyre!(formatdoc!(\n        r#\"\n                mise is not activated in this shell session.\n                Please run `{}` first in your shell rc file.\n                \"#,\n        style(\"mise activate\").yellow()\n    )))\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise shell node@20</bold>\n    $ <bold>node -v</bold>\n    v20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/shell_alias/get.rs",
    "content": "use color_eyre::eyre::{Result, eyre};\n\nuse crate::config::Config;\n\n/// Show the command for a shell alias\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ShellAliasGet {\n    /// The alias to show\n    #[clap(name = \"shell_alias\")]\n    pub alias: String,\n}\n\nimpl ShellAliasGet {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        match config.shell_aliases.get(&self.alias) {\n            Some((command, _path)) => {\n                miseprintln!(\"{command}\");\n                Ok(())\n            }\n            None => Err(eyre!(\"Unknown shell alias: {}\", &self.alias)),\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise shell-alias get ll</bold>\n    ls -la\n\"#\n);\n"
  },
  {
    "path": "src/cli/shell_alias/ls.rs",
    "content": "use eyre::Result;\nuse tabled::Tabled;\n\nuse crate::config::Config;\nuse crate::ui::table;\n\n/// List shell aliases\n///\n/// Shows the shell aliases that are set in the current directory.\n/// These are defined in `mise.toml` under the `[shell_alias]` section.\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"list\", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ShellAliasLs {\n    /// Don't show table header\n    #[clap(long)]\n    pub no_header: bool,\n}\n\nimpl ShellAliasLs {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let rows = config\n            .shell_aliases\n            .iter()\n            .map(|(name, (command, _path))| Row {\n                alias: name.clone(),\n                command: command.clone(),\n            })\n            .collect::<Vec<_>>();\n        let mut table = tabled::Table::new(rows);\n        table::default_style(&mut table, self.no_header);\n        miseprintln!(\"{table}\");\n        Ok(())\n    }\n}\n\n#[derive(Tabled)]\nstruct Row {\n    alias: String,\n    command: String,\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise shell-alias ls</bold>\n    alias    command\n    ll       ls -la\n    gs       git status\n\"#\n);\n"
  },
  {
    "path": "src/cli/shell_alias/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nmod get;\nmod ls;\nmod set;\nmod unset;\n\n#[derive(Debug, clap::Args)]\n#[clap(name = \"shell-alias\", about = \"Manage shell aliases.\")]\npub struct ShellAlias {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    /// Don't show table header\n    #[clap(long)]\n    pub no_header: bool,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Get(get::ShellAliasGet),\n    Ls(ls::ShellAliasLs),\n    Set(set::ShellAliasSet),\n    Unset(unset::ShellAliasUnset),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Get(cmd) => cmd.run().await,\n            Self::Ls(cmd) => cmd.run().await,\n            Self::Set(cmd) => cmd.run().await,\n            Self::Unset(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl ShellAlias {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self.command.unwrap_or(Commands::Ls(ls::ShellAliasLs {\n            no_header: self.no_header,\n        }));\n\n        cmd.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/shell_alias/set.rs",
    "content": "use eyre::{Result, eyre};\n\nuse crate::config::Config;\nuse crate::config::config_file::ConfigFile;\n\n/// Add/update a shell alias\n///\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"add\", \"create\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ShellAliasSet {\n    /// The alias name\n    #[clap(name = \"shell_alias\")]\n    pub alias: String,\n    /// The command to run (optional if provided as ALIAS=COMMAND)\n    pub command: Option<String>,\n}\n\nimpl ShellAliasSet {\n    pub async fn run(self) -> Result<()> {\n        let (alias, command) = match self.command {\n            Some(v) => (self.alias, v),\n            None => {\n                let (k, v) = self.alias.split_once('=').ok_or_else(|| {\n                    eyre!(\"Usage: mise shell-alias set <ALIAS>=<COMMAND> or mise shell-alias set <ALIAS> <COMMAND>\")\n                })?;\n                (k.to_string(), v.to_string())\n            }\n        };\n        let mut global_config = Config::get().await?.global_config()?;\n        global_config.set_shell_alias(&alias, &command)?;\n        global_config.save()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise shell-alias set ll \"ls -la\"</bold>\n    $ <bold>mise shell-alias set gs \"git status\"</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/shell_alias/unset.rs",
    "content": "use eyre::Result;\n\nuse crate::config::Config;\nuse crate::config::config_file::ConfigFile;\n\n/// Removes a shell alias\n///\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"rm\", \"remove\", \"delete\", \"del\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ShellAliasUnset {\n    /// The alias to remove\n    #[clap(name = \"shell_alias\")]\n    pub alias: String,\n}\n\nimpl ShellAliasUnset {\n    pub async fn run(self) -> Result<()> {\n        let mut global_config = Config::get().await?.global_config()?;\n        global_config.remove_shell_alias(&self.alias)?;\n        global_config.save()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise shell-alias unset ll</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/sync/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nmod node;\nmod python;\nmod ruby;\n\n#[derive(Debug, clap::Args)]\n#[clap(about = \"Synchronize tools from other version managers with mise\")]\npub struct Sync {\n    #[clap(subcommand)]\n    command: Commands,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Node(node::SyncNode),\n    Python(python::SyncPython),\n    Ruby(ruby::SyncRuby),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Node(cmd) => cmd.run().await,\n            Self::Python(cmd) => cmd.run().await,\n            Self::Ruby(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl Sync {\n    pub async fn run(self) -> Result<()> {\n        self.command.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/sync/node.rs",
    "content": "use std::path::PathBuf;\n\nuse eyre::Result;\nuse itertools::sorted;\n\nuse crate::{backend, config, dirs, file};\nuse crate::{config::Config, config::Settings};\n\n/// Symlinks all tool versions from an external tool into mise\n///\n/// For example, use this to import all Homebrew node installs into mise\n///\n/// This won't overwrite any existing installs but will overwrite any existing symlinks\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct SyncNode {\n    #[clap(flatten)]\n    _type: SyncNodeType,\n}\n\n#[derive(Debug, clap::Args)]\n#[group(required = true, multiple = true)]\npub struct SyncNodeType {\n    /// Get tool versions from Homebrew\n    #[clap(long)]\n    brew: bool,\n\n    /// Get tool versions from nodenv\n    #[clap(long)]\n    nodenv: bool,\n\n    /// Get tool versions from nvm\n    #[clap(long)]\n    nvm: bool,\n}\n\nimpl SyncNode {\n    pub async fn run(self) -> Result<()> {\n        if self._type.brew {\n            self.run_brew().await?;\n        }\n        if self._type.nvm {\n            self.run_nvm().await?;\n        }\n        if self._type.nodenv {\n            self.run_nodenv().await?;\n        }\n        let config = Config::reset().await?;\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        Ok(())\n    }\n\n    async fn run_brew(&self) -> Result<()> {\n        let node = backend::get(&\"node\".into()).unwrap();\n\n        let brew_prefix = PathBuf::from(cmd!(\"brew\", \"--prefix\").read()?).join(\"opt\");\n        let installed_versions_path = dirs::INSTALLS.join(\"node\");\n\n        file::remove_symlinks_with_target_prefix(&installed_versions_path, &brew_prefix)?;\n\n        let subdirs = file::dir_subdirs(&brew_prefix)?;\n        for entry in sorted(subdirs) {\n            if entry.starts_with(\".\") {\n                continue;\n            }\n            if !entry.starts_with(\"node@\") {\n                continue;\n            }\n            let v = entry.trim_start_matches(\"node@\");\n            if node.create_symlink(v, &brew_prefix.join(&entry))?.is_some() {\n                miseprintln!(\"Synced node@{} from Homebrew\", v);\n            }\n        }\n        Ok(())\n    }\n\n    async fn run_nvm(&self) -> Result<()> {\n        let node = backend::get(&\"node\".into()).unwrap();\n        let settings = Settings::get();\n\n        let nvm_versions_path = file::replace_path(&settings.node.nvm_dir)\n            .join(\"versions\")\n            .join(\"node\");\n        let installed_versions_path = dirs::INSTALLS.join(\"node\");\n\n        let removed =\n            file::remove_symlinks_with_target_prefix(&installed_versions_path, &nvm_versions_path)?;\n        if !removed.is_empty() {\n            debug!(\"Removed symlinks: {removed:?}\");\n        }\n\n        let mut created = vec![];\n        let subdirs = file::dir_subdirs(&nvm_versions_path)?;\n        for entry in sorted(subdirs) {\n            if entry.starts_with(\".\") {\n                continue;\n            }\n            let v = entry.trim_start_matches('v');\n            let symlink = node.create_symlink(v, &nvm_versions_path.join(&entry))?;\n            if let Some(symlink) = symlink {\n                created.push(symlink);\n                miseprintln!(\"Synced node@{} from nvm\", v);\n            } else {\n                info!(\"Skipping node@{v} from nvm because it already exists in mise\");\n            }\n        }\n        if !created.is_empty() {\n            debug!(\"Created symlinks: {created:?}\");\n        }\n        Ok(())\n    }\n\n    async fn run_nodenv(&self) -> Result<()> {\n        let node = backend::get(&\"node\".into()).unwrap();\n        let settings = Settings::get();\n\n        let nodenv_versions_path = file::replace_path(&settings.node.nodenv_root).join(\"versions\");\n        let installed_versions_path = dirs::INSTALLS.join(\"node\");\n\n        file::remove_symlinks_with_target_prefix(&installed_versions_path, &nodenv_versions_path)?;\n\n        let subdirs = file::dir_subdirs(&nodenv_versions_path)?;\n        for v in sorted(subdirs) {\n            if v.starts_with(\".\") {\n                continue;\n            }\n            if node\n                .create_symlink(&v, &nodenv_versions_path.join(&v))?\n                .is_some()\n            {\n                miseprintln!(\"Synced node@{} from nodenv\", v);\n            }\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>brew install node@18 node@20</bold>\n    $ <bold>mise sync node --brew</bold>\n    $ <bold>mise use -g node@18</bold> - uses Homebrew-provided node\n\"#\n);\n"
  },
  {
    "path": "src/cli/sync/python.rs",
    "content": "use eyre::Result;\nuse itertools::sorted;\nuse std::env::consts::{ARCH, OS};\n\nuse crate::{backend, config, dirs, env, file};\nuse crate::{config::Config, env::PYENV_ROOT};\n\n/// Symlinks all tool versions from an external tool into mise\n///\n/// For example, use this to import all pyenv installs into mise\n///\n/// This won't overwrite any existing installs but will overwrite any existing symlinks\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct SyncPython {\n    /// Get tool versions from pyenv\n    #[clap(long)]\n    pyenv: bool,\n\n    /// Sync tool versions with uv (2-way sync)\n    #[clap(long)]\n    uv: bool,\n}\n\nimpl SyncPython {\n    pub async fn run(self) -> Result<()> {\n        if self.pyenv {\n            self.pyenv().await?;\n        }\n        if self.uv {\n            self.uv().await?;\n        }\n        let config = Config::get().await?;\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        Ok(())\n    }\n\n    async fn pyenv(&self) -> Result<()> {\n        let python = backend::get(&\"python\".into()).unwrap();\n\n        let pyenv_versions_path = PYENV_ROOT.join(\"versions\");\n        let installed_python_versions_path = dirs::INSTALLS.join(\"python\");\n\n        file::remove_symlinks_with_target_prefix(\n            &installed_python_versions_path,\n            &pyenv_versions_path,\n        )?;\n\n        let subdirs = file::dir_subdirs(&pyenv_versions_path)?;\n        for v in sorted(subdirs) {\n            if v.starts_with(\".\") {\n                continue;\n            }\n            python.create_symlink(&v, &pyenv_versions_path.join(&v))?;\n            miseprintln!(\"Synced python@{} from pyenv\", v);\n        }\n        Ok(())\n    }\n\n    async fn uv(&self) -> Result<()> {\n        let python = backend::get(&\"python\".into()).unwrap();\n        let uv_versions_path = &*env::UV_PYTHON_INSTALL_DIR;\n        let installed_python_versions_path = dirs::INSTALLS.join(\"python\");\n\n        file::remove_symlinks_with_target_prefix(\n            &installed_python_versions_path,\n            uv_versions_path,\n        )?;\n\n        let subdirs = file::dir_subdirs(uv_versions_path)?;\n        for name in sorted(subdirs) {\n            if name.starts_with(\".\") {\n                continue;\n            }\n            // name is like cpython-3.13.1-macos-aarch64-none\n            let v = name.split('-').nth(1).unwrap();\n            if python\n                .create_symlink(v, &uv_versions_path.join(&name))?\n                .is_some()\n            {\n                miseprintln!(\"Synced python@{v} from uv to mise\");\n            }\n        }\n\n        let subdirs = file::dir_subdirs(&installed_python_versions_path)?;\n        for v in sorted(subdirs) {\n            if v.starts_with(\".\") {\n                continue;\n            }\n            let src = installed_python_versions_path.join(&v);\n            if src.is_symlink() {\n                continue;\n            }\n            // ~/.local/share/uv/python/cpython-3.10.16-macos-aarch64-none\n            // ~/.local/share/uv/python/cpython-3.13.0-linux-x86_64-gnu\n            let os = OS;\n            let arch = if cfg!(target_arch = \"x86_64\") {\n                \"x86_64-gnu\"\n            } else if cfg!(target_arch = \"aarch64\") {\n                \"aarch64-none\"\n            } else {\n                ARCH\n            };\n            let dst = uv_versions_path.join(format!(\"cpython-{v}-{os}-{arch}\"));\n            if !dst.exists() {\n                if !uv_versions_path.exists() {\n                    file::create_dir_all(uv_versions_path)?;\n                }\n                // TODO: uv doesn't support symlinked dirs\n                // https://github.com/astral-sh/uv/blob/e65a273f1b6b7c3ab129d902e93adeda4da20636/crates/uv-python/src/managed.rs#L196\n                file::clone_dir(&src, &dst)?;\n                miseprintln!(\"Synced python@{v} from mise to uv\");\n            }\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>pyenv install 3.11.0</bold>\n    $ <bold>mise sync python --pyenv</bold>\n    $ <bold>mise use -g python@3.11.0</bold> - uses pyenv-provided python\n    \n    $ <bold>uv python install 3.11.0</bold>\n    $ <bold>mise install python@3.10.0</bold>\n    $ <bold>mise sync python --uv</bold>\n    $ <bold>mise x python@3.11.0 -- python -V</bold> - uses uv-provided python\n    $ <bold>uv run -p 3.10.0 -- python -V</bold> - uses mise-provided python\n\"#\n);\n"
  },
  {
    "path": "src/cli/sync/ruby.rs",
    "content": "use std::path::PathBuf;\n\nuse eyre::Result;\nuse itertools::sorted;\n\nuse crate::{\n    backend,\n    config::{self, Config},\n    dirs, file,\n};\n\n/// Symlinks all ruby tool versions from an external tool into mise\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct SyncRuby {\n    #[clap(flatten)]\n    _type: SyncRubyType,\n}\n\n#[derive(Debug, clap::Args)]\n#[group(required = true, multiple = true)]\npub struct SyncRubyType {\n    /// Get tool versions from Homebrew\n    #[clap(long)]\n    brew: bool,\n}\n\nimpl SyncRuby {\n    pub async fn run(self) -> Result<()> {\n        if self._type.brew {\n            self.run_brew().await?;\n        }\n        let config = Config::reset().await?;\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        Ok(())\n    }\n\n    async fn run_brew(&self) -> Result<()> {\n        let ruby = backend::get(&\"ruby\".into()).unwrap();\n\n        let brew_prefix = PathBuf::from(cmd!(\"brew\", \"--prefix\").read()?).join(\"opt\");\n        let installed_versions_path = dirs::INSTALLS.join(\"ruby\");\n\n        file::remove_symlinks_with_target_prefix(&installed_versions_path, &brew_prefix)?;\n\n        let subdirs = file::dir_subdirs(&brew_prefix)?;\n        for entry in sorted(subdirs) {\n            if entry.starts_with(\".\") {\n                continue;\n            }\n            if !entry.starts_with(\"ruby@\") {\n                continue;\n            }\n            let v = entry.trim_start_matches(\"ruby@\");\n            if ruby.create_symlink(v, &brew_prefix.join(&entry))?.is_some() {\n                miseprintln!(\"Synced ruby@{} from Homebrew\", v);\n            }\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>brew install ruby</bold>\n    $ <bold>mise sync ruby --brew</bold>\n    $ <bold>mise use -g ruby</bold> - Use the latest version of Ruby installed by Homebrew\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/add.rs",
    "content": "use crate::config::config_file;\nuse crate::task::Task;\nuse crate::{config, file};\nuse eyre::Result;\nuse std::path::MAIN_SEPARATOR_STR;\nuse toml_edit::Item;\n\n/// Create a new task\n///\n/// Adds a task to the local mise.toml file.\n/// See https://mise.jdx.dev/configuration.html#target-file-for-write-operations\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksAdd {\n    /// Tasks name to add\n    #[clap()]\n    task: String,\n\n    #[clap(last = true)]\n    run: Vec<String>,\n\n    /// Other names for the task\n    #[clap(long, short)]\n    alias: Vec<String>,\n    /// Add dependencies to the task\n    #[clap(long, short)]\n    depends: Vec<String>,\n    /// Run the task in a specific directory\n    #[clap(long, short = 'D')]\n    dir: Option<String>,\n    /// Create a file task instead of a toml task\n    #[clap(long, short)]\n    file: bool,\n    /// Hide the task from `mise tasks` and completions\n    #[clap(long, short = 'H')]\n    hide: bool,\n    /// Do not print the command before running\n    #[clap(long, short)]\n    quiet: bool,\n    /// Directly connect stdin/stdout/stderr\n    #[clap(long, short)]\n    raw: bool,\n    /// Glob patterns of files this task uses as input\n    #[clap(long, short)]\n    sources: Vec<String>,\n    /// Wait for these tasks to complete if they are to run\n    #[clap(long, short)]\n    wait_for: Vec<String>,\n\n    /// Dependencies to run after the task runs\n    #[clap(long)]\n    depends_post: Vec<String>,\n    /// Description of the task\n    #[clap(long)]\n    description: Option<String>,\n    /// Glob patterns of files this task creates, to skip if they are not modified\n    #[clap(long)]\n    outputs: Vec<String>,\n    /// Command to run on windows\n    #[clap(long)]\n    run_windows: Option<String>,\n    /// Run the task in a specific shell\n    #[clap(long)]\n    shell: Option<String>,\n    /// Do not print the command or its output\n    #[clap(long)]\n    silent: bool,\n    // TODO\n    // env: Vec<String>,\n    // tools: Vec<String>,\n}\n\nimpl TasksAdd {\n    pub async fn run(self) -> Result<()> {\n        if self.file {\n            let mut path = Task::task_dir()\n                .await\n                .join(self.task.replace(':', MAIN_SEPARATOR_STR));\n            if path.is_dir() {\n                path = path.join(\"_default\");\n            }\n            let mut lines = vec![format!(\n                \"#!/usr/bin/env {}\",\n                self.shell.clone().unwrap_or(\"bash\".into())\n            )];\n            if !self.depends.is_empty() {\n                lines.push(\"#MISE depends=[\\\"\".to_string() + &self.depends.join(\"\\\", \\\"\") + \"\\\"]\");\n            }\n            if !self.depends_post.is_empty() {\n                lines.push(\n                    \"#MISE depends_post=[\\\"\".to_string()\n                        + &self.depends_post.join(\"\\\", \\\"\")\n                        + \"\\\"]\",\n                );\n            }\n            if !self.wait_for.is_empty() {\n                lines\n                    .push(\"#MISE wait_for=[\\\"\".to_string() + &self.wait_for.join(\"\\\", \\\"\") + \"\\\"]\");\n            }\n            if !self.alias.is_empty() {\n                lines.push(\"#MISE alias=[\\\"\".to_string() + &self.alias.join(\"\\\", \\\"\") + \"\\\"]\");\n            }\n            if let Some(description) = &self.description {\n                lines.push(\"#MISE description=\\\"\".to_string() + description + \"\\\"\");\n            }\n            if let Some(dir) = &self.dir {\n                lines.push(\"#MISE dir=\".to_string() + dir);\n            }\n            if self.hide {\n                lines.push(\"#MISE hide=true\".to_string());\n            }\n            if self.raw {\n                lines.push(\"#MISE raw=true\".to_string());\n            }\n            if !self.sources.is_empty() {\n                lines.push(\"#MISE sources=[\\\"\".to_string() + &self.sources.join(\"\\\", \\\"\") + \"\\\"]\");\n            }\n            if !self.outputs.is_empty() {\n                lines.push(\"#MISE outputs=[\\\"\".to_string() + &self.outputs.join(\"\\\", \\\"\") + \"\\\"]\");\n            }\n            if self.quiet {\n                lines.push(\"#MISE quiet=true\".to_string());\n            }\n            if self.silent {\n                lines.push(\"#MISE silent=true\".to_string());\n            }\n            lines.push(\"set -euxo pipefail\".into());\n            lines.push(\"\".into());\n            if !self.run.is_empty() {\n                lines.push(self.run.join(\" \"));\n                lines.push(\"\".into());\n            }\n            file::create_dir_all(path.parent().unwrap())?;\n            file::write(&path, lines.join(\"\\n\"))?;\n            file::make_executable(&path)?;\n        } else {\n            let path = config::local_toml_config_path();\n            let mut doc: toml_edit::DocumentMut =\n                file::read_to_string(&path).unwrap_or_default().parse()?;\n            let tasks = doc\n                .entry(\"tasks\")\n                .or_insert_with(|| {\n                    let mut table = toml_edit::Table::new();\n                    table.set_implicit(true);\n                    Item::Table(table)\n                })\n                .as_table_mut()\n                .unwrap();\n            let mut task = toml_edit::Table::new();\n            if !self.depends.is_empty() {\n                let mut depends = toml_edit::Array::new();\n                for dep in &self.depends {\n                    depends.push(dep);\n                }\n                task.insert(\"depends\", Item::Value(depends.into()));\n            }\n            if !self.depends_post.is_empty() {\n                let mut depends_post = toml_edit::Array::new();\n                for dep in &self.depends_post {\n                    depends_post.push(dep);\n                }\n                task.insert(\"depends_post\", Item::Value(depends_post.into()));\n            }\n            if !self.wait_for.is_empty() {\n                let mut wait_for = toml_edit::Array::new();\n                for dep in &self.wait_for {\n                    wait_for.push(dep);\n                }\n                task.insert(\"wait_for\", Item::Value(wait_for.into()));\n            }\n            if let Some(description) = &self.description {\n                task.insert(\"description\", description.clone().into());\n            }\n            if !self.alias.is_empty() {\n                let mut alias = toml_edit::Array::new();\n                for a in &self.alias {\n                    alias.push(a);\n                }\n                task.insert(\"alias\", Item::Value(alias.into()));\n            }\n            if let Some(dir) = &self.dir {\n                task.insert(\"dir\", dir.clone().into());\n            }\n            if self.hide {\n                task.insert(\"hide\", true.into());\n            }\n            if self.raw {\n                task.insert(\"raw\", true.into());\n            }\n            if !self.sources.is_empty() {\n                let mut sources = toml_edit::Array::new();\n                for source in &self.sources {\n                    sources.push(source);\n                }\n                task.insert(\"sources\", Item::Value(sources.into()));\n            }\n            if !self.outputs.is_empty() {\n                let mut outputs = toml_edit::Array::new();\n                for output in &self.outputs {\n                    outputs.push(output);\n                }\n                task.insert(\"outputs\", Item::Value(outputs.into()));\n            }\n            if let Some(shell) = &self.shell {\n                task.insert(\"shell\", shell.clone().into());\n            }\n            if self.quiet {\n                task.insert(\"quiet\", true.into());\n            }\n            if self.silent {\n                task.insert(\"silent\", true.into());\n            }\n            if !self.run.is_empty() {\n                task.insert(\"run\", shell_words::join(&self.run).into());\n            }\n            tasks.insert(&self.task, Item::Table(task));\n            file::write(&path, doc.to_string())?;\n            config_file::trust(&config_file::config_trust_root(&path))?;\n        }\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tasks add pre-commit --depends \"test\" --depends \"render\" -- echo pre-commit</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/deps.rs",
    "content": "use std::sync::Arc;\n\nuse crate::config::Config;\nuse crate::task::{Deps, GetMatchingExt, Task, build_task_ref_map};\nuse crate::ui::style::{self};\nuse crate::ui::tree::print_tree;\nuse console::style;\nuse eyre::{Result, eyre};\nuse itertools::Itertools;\nuse petgraph::dot::Dot;\n\n/// Display a tree visualization of a dependency graph\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksDeps {\n    /// Tasks to show dependencies for\n    /// Can specify multiple tasks by separating with spaces\n    /// e.g.: mise tasks deps lint test check\n    #[clap(verbatim_doc_comment)]\n    pub tasks: Option<Vec<String>>,\n\n    /// Display dependencies in DOT format\n    #[clap(long, alias = \"dot\", verbatim_doc_comment)]\n    pub dot: bool,\n\n    /// Show hidden tasks\n    #[clap(long, verbatim_doc_comment)]\n    pub hidden: bool,\n}\n\nimpl TasksDeps {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let tasks = if self.tasks.is_none() {\n            self.get_all_tasks(&config).await?\n        } else {\n            self.get_task_lists(&config).await?\n        };\n\n        if self.dot {\n            self.print_deps_dot(&config, tasks).await?;\n        } else {\n            self.print_deps_tree(&config, tasks).await?;\n        }\n\n        Ok(())\n    }\n\n    async fn get_all_tasks(&self, config: &Arc<Config>) -> Result<Vec<Task>> {\n        // Use TaskLoadContext::all() to load tasks from entire monorepo\n        let ctx = crate::task::TaskLoadContext::all();\n        Ok(config\n            .tasks_with_context(Some(&ctx))\n            .await?\n            .values()\n            .filter(|t| self.hidden || !t.hide)\n            .cloned()\n            .collect())\n    }\n\n    async fn get_task_lists(&self, config: &Arc<Config>) -> Result<Vec<Task>> {\n        // Expand all task names first\n        let task_names: Vec<String> = self\n            .tasks\n            .as_ref()\n            .unwrap_or(&vec![])\n            .iter()\n            .map(|t| crate::task::expand_colon_task_syntax(t, config))\n            .collect::<Result<Vec<_>>>()?;\n\n        // Load monorepo tasks once with combined context for all monorepo patterns\n        let monorepo_patterns: Vec<&str> = task_names\n            .iter()\n            .filter(|t| t.starts_with(\"//\"))\n            .map(|s| s.as_str())\n            .collect();\n        let monorepo_tasks = if !monorepo_patterns.is_empty() {\n            let ctx = crate::task::TaskLoadContext::from_patterns(monorepo_patterns.into_iter());\n            Some(config.tasks_with_context(Some(&ctx)).await?)\n        } else {\n            None\n        };\n\n        // Load non-monorepo tasks once (only if needed)\n        let has_regular = task_names.iter().any(|t| !t.starts_with(\"//\"));\n        let regular_tasks = if has_regular {\n            Some(config.tasks().await?)\n        } else {\n            None\n        };\n\n        // Build task ref maps once (not per-task)\n        let monorepo_ref_map = monorepo_tasks\n            .as_ref()\n            .map(|t| build_task_ref_map(t.iter()));\n        let regular_ref_map = regular_tasks.as_ref().map(|t| build_task_ref_map(t.iter()));\n\n        // Look up each task from the appropriate cache\n        let mut tasks = vec![];\n        for task_name in &task_names {\n            let (all_tasks, ref_map) = if task_name.starts_with(\"//\") {\n                (\n                    monorepo_tasks.as_ref().unwrap(),\n                    monorepo_ref_map.as_ref().unwrap(),\n                )\n            } else {\n                (\n                    regular_tasks.as_ref().unwrap(),\n                    regular_ref_map.as_ref().unwrap(),\n                )\n            };\n\n            let matching = ref_map.get_matching(task_name).ok();\n            let task = matching.and_then(|m| m.first().cloned().cloned());\n\n            match task {\n                Some(task) => {\n                    tasks.push(task.clone());\n                }\n                None => {\n                    return Err(self.err_no_task(task_name, all_tasks));\n                }\n            }\n        }\n        Ok(tasks)\n    }\n\n    ///\n    /// Print dependencies as a tree\n    ///\n    /// Example:\n    /// ```\n    /// task1\n    /// ├─ task2\n    /// │  └─ task3\n    /// └─ task4\n    /// task5\n    /// ```\n    ///\n    async fn print_deps_tree(&self, config: &Arc<Config>, tasks: Vec<Task>) -> Result<()> {\n        let deps = Deps::new(config, tasks.clone()).await?;\n        // filter out nodes that are not selected\n        let start_indexes = deps.graph.node_indices().filter(|&idx| {\n            let task = &deps.graph[idx];\n            tasks.iter().any(|t| t.name == task.name)\n        });\n        // iterate over selected graph nodes and print tree\n        for idx in start_indexes {\n            print_tree(&(&deps.graph, idx))?;\n        }\n        Ok(())\n    }\n\n    ///\n    /// Print dependencies in DOT format\n    ///\n    /// Example:\n    /// ```\n    /// digraph {\n    ///  1 [label = \"task1\"]\n    ///  2 [label = \"task2\"]\n    ///  3 [label = \"task3\"]\n    ///  4 [label = \"task4\"]\n    ///  5 [label = \"task5\"]\n    ///  1 -> 2 [ ]\n    ///  2 -> 3 [ ]\n    ///  1 -> 4 [ ]\n    /// }\n    /// ```\n    //\n    async fn print_deps_dot(&self, config: &Arc<Config>, tasks: Vec<Task>) -> Result<()> {\n        let deps = Deps::new(config, tasks).await?;\n        miseprintln!(\n            \"{:?}\",\n            Dot::with_attr_getters(\n                &deps.graph,\n                &[\n                    petgraph::dot::Config::NodeNoLabel,\n                    petgraph::dot::Config::EdgeNoLabel\n                ],\n                &|_, _| String::new(),\n                &|_, nr| format!(\"label = \\\"{}\\\"\", nr.1.name),\n            ),\n        );\n        Ok(())\n    }\n\n    fn err_no_task(\n        &self,\n        t: &str,\n        all_tasks: &std::collections::BTreeMap<String, Task>,\n    ) -> eyre::Report {\n        let task_names = all_tasks\n            .values()\n            .map(|v| v.display_name.clone())\n            .map(style::ecyan)\n            .join(\", \");\n        let t = style(&t).yellow().for_stderr();\n        eyre!(\"no tasks named `{t}` found. Available tasks: {task_names}\")\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Show dependencies for all tasks\n    $ <bold>mise tasks deps</bold>\n\n    # Show dependencies for the \"lint\", \"test\" and \"check\" tasks\n    $ <bold>mise tasks deps lint test check</bold>\n\n    # Show dependencies in DOT format\n    $ <bold>mise tasks deps --dot</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/edit.rs",
    "content": "use crate::config::Config;\nuse crate::task::Task;\nuse crate::{dirs, env, file};\nuse eyre::Result;\nuse indoc::formatdoc;\nuse std::path::MAIN_SEPARATOR_STR;\n\n/// Edit a task with $EDITOR\n///\n/// The task will be created as a standalone script if it does not already exist.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksEdit {\n    /// Task to edit\n    #[clap()]\n    task: String,\n\n    /// Display the path to the task instead of editing it\n    #[clap(long, short, verbatim_doc_comment)]\n    path: bool,\n}\n\nimpl TasksEdit {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let cwd = dirs::CWD.clone().unwrap_or_default();\n        let project_root = config.project_root.clone().unwrap_or(cwd);\n        let path = Task::task_dir()\n            .await\n            .join(self.task.replace(':', MAIN_SEPARATOR_STR));\n\n        let task = if let Some(task) = config.tasks_with_aliases().await?.get(&self.task).cloned() {\n            task\n        } else {\n            Task::from_path(&config, &path, path.parent().unwrap(), &project_root)\n                .await\n                .or_else(|_| Task::new(&path, path.parent().unwrap(), &project_root))?\n        };\n        let file = &task.config_source;\n        if !file.exists() {\n            file::create_dir_all(file.parent().unwrap())?;\n            file::write(file, default_task())?;\n            file::make_executable(file)?;\n        }\n        if self.path {\n            miseprintln!(\"{}\", file.display());\n        } else {\n            cmd!(&*env::EDITOR, &file).run()?;\n        }\n\n        Ok(())\n    }\n}\n\nfn default_task() -> String {\n    formatdoc!(\n        r#\"#!/usr/bin/env bash\n        set -euxo pipefail\n\n        \"#\n    )\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tasks edit build</bold>\n    $ <bold>mise tasks edit test</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/info.rs",
    "content": "use std::sync::Arc;\n\nuse eyre::{Result, bail};\nuse itertools::Itertools;\nuse serde_json::json;\n\nuse crate::config::Config;\nuse crate::file::display_path;\nuse crate::task::Task;\nuse crate::task::task_fetcher::TaskFetcher;\nuse crate::task::task_source_checker::task_cwd;\nuse crate::ui::info;\n\n/// Get information about a task\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksInfo {\n    /// Name of the task to get information about\n    #[clap(verbatim_doc_comment)]\n    pub task: String,\n    /// Output in JSON format\n    #[clap(short = 'J', long, verbatim_doc_comment)]\n    pub json: bool,\n}\n\nimpl TasksInfo {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n\n        let task_name = crate::task::expand_colon_task_syntax(&self.task, &config)?;\n\n        let tasks = if task_name.starts_with(\"//\") {\n            let ctx = crate::task::TaskLoadContext::from_pattern(&task_name);\n            config.tasks_with_context(Some(&ctx)).await?\n        } else {\n            config.tasks().await?\n        };\n\n        let tasks_with_aliases = crate::task::build_task_ref_map(tasks.iter());\n\n        use crate::task::GetMatchingExt;\n        let matching = tasks_with_aliases.get_matching(&task_name).ok();\n        let task = matching.and_then(|m| m.first().cloned().cloned());\n\n        if let Some(task) = task {\n            // Resolve remote task files before displaying task info\n            let mut tasks = vec![task.clone()];\n            // always pass no_cache=false as the command doesn't take no-cache argument\n            // MISE_TASK_REMOTE_NO_CACHE env var is still respected if set\n            TaskFetcher::new(false).fetch_tasks(&mut tasks).await?;\n            let task = &tasks[0];\n\n            if self.json {\n                self.display_json(&config, task).await?;\n            } else {\n                self.display(&config, task).await?;\n            }\n        } else {\n            bail!(\n                \"Task not found: {}, use `mise tasks ls --all --hidden` to list all tasks\",\n                self.task\n            );\n        }\n\n        Ok(())\n    }\n\n    async fn display(&self, config: &Arc<Config>, task: &Task) -> Result<()> {\n        info::inline_section(\"Task\", &task.display_name)?;\n        if !task.aliases.is_empty() {\n            info::inline_section(\"Aliases\", task.aliases.join(\", \"))?;\n        }\n        info::inline_section(\"Description\", &task.description)?;\n        info::inline_section(\"Source\", display_path(&task.config_source))?;\n        let mut properties = vec![];\n        if task.hide {\n            properties.push(\"hide\");\n        }\n        if task.raw {\n            properties.push(\"raw\");\n        }\n        if task.interactive {\n            properties.push(\"interactive\");\n        }\n        if !properties.is_empty() {\n            info::inline_section(\"Properties\", properties.join(\", \"))?;\n        }\n        if !task.depends.is_empty() {\n            info::inline_section(\"Depends on\", task.depends.iter().join(\", \"))?;\n        }\n        if !task.depends_post.is_empty() {\n            info::inline_section(\"Depends post\", task.depends_post.iter().join(\", \"))?;\n        }\n        if let Some(dir) = &task.dir {\n            info::inline_section(\"Directory\", display_path(dir))?;\n        }\n        if !task.sources.is_empty() {\n            info::inline_section(\"Sources\", task.sources.join(\", \"))?;\n        }\n        let root = task_cwd(task, config).await?;\n        let outputs = task.outputs.paths(task, &root);\n        if !outputs.is_empty() {\n            info::inline_section(\"Outputs\", outputs.join(\", \"))?;\n        }\n        if let Some(file) = &task.file {\n            info::inline_section(\"File\", display_path(file))?;\n        }\n        let run = task.run();\n        if !run.is_empty() {\n            info::section(\"Run\", run.iter().map(|e| e.to_string()).join(\"\\n\"))?;\n        }\n        if !task.env.is_empty() {\n            let env_display = task\n                .env\n                .0\n                .iter()\n                .map(|directive| directive.to_string())\n                .collect::<Vec<_>>()\n                .join(\"\\n\");\n            info::section(\"Environment Variables\", env_display)?;\n        }\n        let spec = task.parse_usage_spec_for_display(config).await?;\n        if !spec.is_empty() {\n            info::section(\"Usage Spec\", &spec)?;\n        }\n        Ok(())\n    }\n\n    async fn display_json(&self, config: &Arc<Config>, task: &Task) -> Result<()> {\n        let spec = task.parse_usage_spec_for_display(config).await?;\n        let o = json!({\n            \"name\": task.display_name,\n            \"aliases\": task.aliases,\n            \"description\": task.description,\n            \"source\": task.config_source,\n            \"depends\": task.depends,\n            \"depends_post\": task.depends_post,\n            \"wait_for\": task.wait_for,\n            \"env\": task.env.0.iter().map(|d| d.to_string()).collect::<Vec<_>>(),\n            \"dir\": task.dir,\n            \"hide\": task.hide,\n            \"raw\": task.raw,\n            \"interactive\": task.interactive,\n            \"sources\": task.sources,\n            \"outputs\": task.outputs,\n            \"shell\": task.shell,\n            \"quiet\": task.quiet,\n            \"silent\": task.silent,\n            \"tools\": task.tools,\n            \"run\": task.run(),\n            \"file\": task.file,\n            \"usage_spec\": spec,\n        });\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&o)?);\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tasks info</bold>\n    Name: test\n    Aliases: t\n    Description: Test the application\n    Source: ~/src/myproj/mise.toml\n\n    $ <bold>mise tasks info test --json</bold>\n    {\n      \"name\": \"test\",\n      \"aliases\": \"t\",\n      \"description\": \"Test the application\",\n      \"source\": \"~/src/myproj/mise.toml\",\n      \"depends\": [],\n      \"env\": {},\n      \"dir\": null,\n      \"hide\": false,\n      \"raw\": false,\n      \"sources\": [],\n      \"outputs\": [],\n      \"run\": [\n        \"echo \\\"testing!\\\"\"\n      ],\n      \"file\": null,\n      \"usage_spec\": {}\n    }\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/ls.rs",
    "content": "use std::sync::Arc;\n\nuse crate::config::Config;\nuse crate::file::display_rel_path;\nuse crate::task::Task;\nuse crate::task::task_fetcher::TaskFetcher;\nuse crate::ui::table::MiseTable;\nuse comfy_table::{Attribute, Cell, Row};\nuse eyre::Result;\nuse itertools::Itertools;\nuse serde_json::json;\n\n/// List available tasks to execute\n/// These may be included from the config file or from the project's .mise/tasks directory\n/// mise will merge all tasks from all parent directories into this list.\n///\n/// So if you have global tasks in `~/.config/mise/tasks/*` and project-specific tasks in\n/// ~/myproject/.mise/tasks/*, then they'll both be available but the project-specific\n/// tasks will override the global ones if they have the same name.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksLs {\n    /// Only show global tasks\n    #[clap(\n        short,\n        long,\n        global = true,\n        overrides_with = \"local\",\n        verbatim_doc_comment\n    )]\n    pub global: bool,\n\n    /// Output in JSON format\n    #[clap(short = 'J', global = true, long, verbatim_doc_comment)]\n    pub json: bool,\n\n    /// Only show non-global tasks\n    #[clap(\n        short,\n        long,\n        global = true,\n        overrides_with = \"global\",\n        verbatim_doc_comment\n    )]\n    pub local: bool,\n\n    /// Show all columns\n    #[clap(short = 'x', long, global = true, verbatim_doc_comment)]\n    pub extended: bool,\n\n    /// Load all tasks from the entire monorepo, including sibling directories.\n    /// By default, only tasks from the current directory hierarchy are loaded.\n    #[clap(long, global = true, verbatim_doc_comment)]\n    pub all: bool,\n\n    /// Display tasks for usage completion\n    #[clap(long, hide = true)]\n    pub complete: bool,\n\n    /// Show hidden tasks\n    #[clap(long, global = true, verbatim_doc_comment)]\n    pub hidden: bool,\n\n    /// Do not print table header\n    #[clap(long, alias = \"no-headers\", global = true, verbatim_doc_comment)]\n    pub no_header: bool,\n\n    /// Sort by column. Default is name.\n    #[clap(long, global = true, value_name = \"COLUMN\", verbatim_doc_comment)]\n    pub sort: Option<SortColumn>,\n\n    /// Sort order. Default is asc.\n    #[clap(long, global = true, verbatim_doc_comment)]\n    pub sort_order: Option<SortOrder>,\n\n    #[clap(long, global = true, hide = true)]\n    pub usage: bool,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]\npub enum SortColumn {\n    Name,\n    Alias,\n    Description,\n    Source,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]\npub enum SortOrder {\n    Asc,\n    Desc,\n}\n\nimpl TasksLs {\n    pub async fn run(self) -> Result<()> {\n        use crate::task::TaskLoadContext;\n\n        let config = Config::get().await?;\n\n        // Create context based on --all flag or when generating completions/usage specs\n        // to ensure monorepo tasks (e.g., `//app:task`) are available for autocomplete.\n        let ctx = if self.all || self.complete || self.usage {\n            Some(TaskLoadContext::all())\n        } else {\n            None\n        };\n\n        let tasks = config\n            .tasks_with_context(ctx.as_ref())\n            .await?\n            .values()\n            .filter(|t| self.hidden || !t.hide)\n            .filter(|t| !self.local || !t.global)\n            .filter(|t| !self.global || t.global)\n            .cloned()\n            .sorted_by(|a, b| self.sort(a, b))\n            .collect::<Vec<Task>>();\n\n        // Resolve remote task files before any operation that may need them\n        let mut tasks = tasks;\n        // always pass no_cache=false as the command doesn't take no-cache argument\n        // MISE_TASK_REMOTE_NO_CACHE env var is still respected if set\n        TaskFetcher::new(false).fetch_tasks(&mut tasks).await?;\n\n        if self.complete {\n            return self.complete(tasks);\n        } else if self.usage {\n            self.display_usage(&config, tasks).await?;\n        } else if self.json {\n            self.display_json(tasks)?;\n        } else {\n            self.display(tasks)?;\n        }\n        Ok(())\n    }\n\n    fn complete(&self, tasks: Vec<Task>) -> Result<()> {\n        for t in tasks {\n            let name = t.display_name.replace(\":\", \"\\\\:\");\n            let description = t.description.replace(\":\", \"\\\\:\");\n            calm_io::stdoutln!(\"{name}:{description}\")?;\n        }\n        Ok(())\n    }\n\n    fn display(&self, tasks: Vec<Task>) -> Result<()> {\n        let mut table = MiseTable::new(\n            self.no_header,\n            if self.extended {\n                &[\"Name\", \"Aliases\", \"Source\", \"Description\"]\n            } else {\n                &[\"Name\", \"Description\"]\n            },\n        );\n        for task in tasks {\n            table.add_row(self.task_to_row(&task));\n        }\n        table.print()\n    }\n\n    async fn display_usage(&self, config: &Arc<Config>, tasks: Vec<Task>) -> Result<()> {\n        let mut usage = usage::Spec::default();\n        for task in tasks {\n            let mut task_spec = task.parse_usage_spec_for_display(config).await?;\n            for (name, complete) in task_spec.complete {\n                task_spec.cmd.complete.insert(name, complete);\n            }\n            // Ensure that completions after -- work.\n            task_spec.cmd.args.push(\n                usage::SpecArgBuilder::new()\n                    .name(\"-- ARGS_LAST\")\n                    .help(\"Arguments to pass to the tasks. Use \\\":::\\\" to separate tasks.\")\n                    .hide(true)\n                    .var(true)\n                    .build(),\n            );\n            usage\n                .cmd\n                .subcommands\n                .insert(task.display_name.clone(), task_spec.cmd);\n        }\n        miseprintln!(\"{}\", usage.to_string());\n        Ok(())\n    }\n\n    fn display_json(&self, tasks: Vec<Task>) -> Result<()> {\n        let array_items = tasks\n            .into_iter()\n            .map(|task| {\n                json!({\n                  \"name\": task.display_name,\n                  \"aliases\": task.aliases,\n                  \"description\": task.description,\n                  \"source\": task.config_source,\n                  \"depends\": task.depends,\n                  \"depends_post\": task.depends_post,\n                  \"wait_for\": task.wait_for,\n                  \"env\": task.env.0.iter().map(|d| d.to_string()).collect::<Vec<_>>(),\n                  \"dir\": task.dir,\n                  \"hide\": task.hide,\n                  \"global\": task.global,\n                  \"raw\": task.raw,\n                  \"interactive\": task.interactive,\n                  \"sources\": task.sources,\n                  \"outputs\": task.outputs,\n                  \"shell\": task.shell,\n                  \"quiet\": task.quiet,\n                  \"silent\": task.silent,\n                  \"tools\": task.tools,\n                  \"usage\": task.usage,\n                  \"timeout\": task.timeout,\n                  \"run\": task.run_script_strings(),\n                  \"args\": task.args,\n                  \"file\": task.file\n                })\n            })\n            .collect::<serde_json::Value>();\n        miseprintln!(\"{}\", serde_json::to_string_pretty(&array_items)?);\n        Ok(())\n    }\n\n    fn sort(&self, a: &Task, b: &Task) -> std::cmp::Ordering {\n        let cmp = match self.sort.unwrap_or(SortColumn::Name) {\n            SortColumn::Alias => a.aliases.join(\", \").cmp(&b.aliases.join(\", \")),\n            SortColumn::Description => a.description.cmp(&b.description),\n            SortColumn::Source => a.config_source.cmp(&b.config_source),\n            _ => a.name.cmp(&b.name),\n        };\n\n        match self.sort_order.unwrap_or(SortOrder::Asc) {\n            SortOrder::Desc => cmp.reverse(),\n            _ => cmp,\n        }\n    }\n\n    fn task_to_row(&self, task: &Task) -> Row {\n        let mut row = vec![Cell::new(&task.display_name).add_attribute(Attribute::Bold)];\n        if self.extended {\n            row.push(Cell::new(task.aliases.join(\", \")));\n            row.push(Cell::new(display_rel_path(&task.config_source)));\n        }\n        row.push(Cell::new(&task.description).add_attribute(Attribute::Dim));\n        row.into()\n    }\n}\n\n// TODO: fill this out\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tasks ls</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tasks/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nuse crate::cli::run;\n\nmod add;\nmod deps;\nmod edit;\nmod info;\nmod ls;\nmod validate;\n\n/// Manage tasks\n#[derive(clap::Args)]\n#[clap(visible_alias = \"t\", alias = \"task\", verbatim_doc_comment)]\npub struct Tasks {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    /// Task name to get info of\n    task: Option<String>,\n\n    #[clap(flatten)]\n    ls: ls::TasksLs,\n}\n\n#[derive(Subcommand)]\nenum Commands {\n    Add(Box<add::TasksAdd>),\n    Deps(deps::TasksDeps),\n    Edit(edit::TasksEdit),\n    Info(info::TasksInfo),\n    Ls(ls::TasksLs),\n    Run(Box<run::Run>),\n    Validate(validate::TasksValidate),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Add(cmd) => (*cmd).run().await,\n            Self::Deps(cmd) => cmd.run().await,\n            Self::Edit(cmd) => cmd.run().await,\n            Self::Info(cmd) => cmd.run().await,\n            Self::Ls(cmd) => cmd.run().await,\n            Self::Run(cmd) => (*cmd).run().await,\n            Self::Validate(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl Tasks {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self\n            .command\n            .or(self.task.map(|t| {\n                Commands::Info(info::TasksInfo {\n                    task: t,\n                    json: self.ls.json,\n                })\n            }))\n            .unwrap_or(Commands::Ls(self.ls));\n\n        cmd.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/tasks/validate.rs",
    "content": "use std::collections::{BTreeMap, HashMap};\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\nuse crate::config::Config;\nuse crate::duration;\nuse crate::file;\nuse crate::task::Task;\nuse crate::task::task_fetcher::TaskFetcher;\nuse crate::ui::style;\nuse console::style as console_style;\nuse eyre::{Result, eyre};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse serde::Serialize;\n\n/// Validate tasks for common errors and issues\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TasksValidate {\n    /// Tasks to validate\n    /// If not specified, validates all tasks\n    #[clap(verbatim_doc_comment)]\n    pub tasks: Option<Vec<String>>,\n\n    /// Only show errors (skip warnings)\n    #[clap(long, verbatim_doc_comment)]\n    pub errors_only: bool,\n\n    /// Output validation results in JSON format\n    #[clap(long, verbatim_doc_comment)]\n    pub json: bool,\n}\n\n#[derive(Debug, Clone, Serialize, PartialEq, Eq)]\n#[serde(rename_all = \"lowercase\")]\nenum Severity {\n    Error,\n    Warning,\n}\n\n#[derive(Debug, Clone, Serialize)]\nstruct ValidationIssue {\n    task: String,\n    severity: Severity,\n    category: String,\n    message: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    details: Option<String>,\n}\n\n#[derive(Debug, Serialize)]\nstruct ValidationResults {\n    tasks_validated: usize,\n    errors: usize,\n    warnings: usize,\n    issues: Vec<ValidationIssue>,\n}\n\nimpl TasksValidate {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n\n        // Resolve all remote task files before validation\n        // so we can properly validate remote tasks and circular dependencies\n        let mut resolved_tasks: Vec<Task> = config.tasks().await?.values().cloned().collect();\n        // always no_cache=false as the command doesn't take no-cache argument\n        // MISE_TASK_REMOTE_NO_CACHE env var is still respected if set\n        TaskFetcher::new(false)\n            .fetch_tasks(&mut resolved_tasks)\n            .await?;\n        let all_tasks: BTreeMap<String, Task> = resolved_tasks\n            .into_iter()\n            .map(|t| (t.name.clone(), t))\n            .collect();\n\n        // Filter tasks to validate\n        let tasks = if let Some(ref task_names) = self.tasks {\n            self.get_specific_tasks(&all_tasks, task_names).await?\n        } else {\n            self.get_all_tasks(&all_tasks)\n        };\n\n        // Run validation\n        let mut issues = Vec::new();\n        for task in &tasks {\n            issues.extend(self.validate_task(task, &all_tasks, &config).await);\n        }\n\n        // Filter by severity if needed\n        if self.errors_only {\n            issues.retain(|i| i.severity == Severity::Error);\n        }\n\n        let results = ValidationResults {\n            tasks_validated: tasks.len(),\n            errors: issues\n                .iter()\n                .filter(|i| i.severity == Severity::Error)\n                .count(),\n            warnings: issues\n                .iter()\n                .filter(|i| i.severity == Severity::Warning)\n                .count(),\n            issues,\n        };\n\n        // Output results\n        if self.json {\n            self.output_json(&results)?;\n        } else {\n            self.output_human(&results)?;\n        }\n\n        // Exit with error if there are errors\n        if results.errors > 0 {\n            return Err(eyre!(\"Validation failed with {} error(s)\", results.errors));\n        }\n\n        Ok(())\n    }\n\n    fn get_all_tasks(&self, all_tasks: &BTreeMap<String, Task>) -> Vec<Task> {\n        all_tasks.values().cloned().collect()\n    }\n\n    async fn get_specific_tasks(\n        &self,\n        all_tasks: &BTreeMap<String, Task>,\n        task_names: &[String],\n    ) -> Result<Vec<Task>> {\n        let mut tasks = Vec::new();\n        for name in task_names {\n            // Check if task exists by name, display_name, or alias\n            match all_tasks\n                .get(name)\n                .or_else(|| all_tasks.values().find(|t| &t.display_name == name))\n                .or_else(|| {\n                    all_tasks\n                        .values()\n                        .find(|t| t.aliases.contains(&name.to_string()))\n                })\n                .cloned()\n            {\n                Some(task) => tasks.push(task),\n                None => {\n                    return Err(eyre!(\n                        \"Task '{}' not found. Available tasks: {}\",\n                        name,\n                        all_tasks.keys().map(style::ecyan).join(\", \")\n                    ));\n                }\n            }\n        }\n        Ok(tasks)\n    }\n\n    async fn validate_task(\n        &self,\n        task: &Task,\n        all_tasks: &BTreeMap<String, Task>,\n        config: &Arc<Config>,\n    ) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // 1. Validate circular dependencies\n        issues.extend(self.validate_circular_dependencies(task, all_tasks));\n\n        // 2. Validate missing task references\n        issues.extend(self.validate_missing_references(task, all_tasks));\n\n        // 3. Validate usage spec parsing\n        issues.extend(self.validate_usage_spec(task, config).await);\n\n        // 4. Validate timeout format\n        issues.extend(self.validate_timeout(task));\n\n        // 5. Validate alias conflicts\n        issues.extend(self.validate_aliases(task, all_tasks));\n\n        // 6. Validate file existence\n        issues.extend(self.validate_file_existence(task));\n\n        // 7. Validate directory template\n        issues.extend(self.validate_directory(task, config).await);\n\n        // 8. Validate shell command\n        issues.extend(self.validate_shell(task));\n\n        // 9. Validate source globs\n        issues.extend(self.validate_source_patterns(task));\n\n        // 10. Validate output patterns\n        issues.extend(self.validate_output_patterns(task));\n\n        // 11. Validate run entries\n        issues.extend(self.validate_run_entries(task, all_tasks));\n\n        issues\n    }\n\n    fn validate_circular_dependencies(\n        &self,\n        task: &Task,\n        all_tasks: &BTreeMap<String, Task>,\n    ) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        match task.all_depends(all_tasks) {\n            Ok(_) => {}\n            Err(e) => {\n                let err_msg = e.to_string();\n                if err_msg.contains(\"circular dependency\") {\n                    issues.push(ValidationIssue {\n                        task: task.name.clone(),\n                        severity: Severity::Error,\n                        category: \"circular-dependency\".to_string(),\n                        message: \"Circular dependency detected\".to_string(),\n                        details: Some(err_msg),\n                    });\n                }\n            }\n        }\n\n        issues\n    }\n\n    /// Check if a task exists by name, display_name, or alias\n    fn task_exists(all_tasks: &BTreeMap<String, Task>, task_name: &str) -> bool {\n        all_tasks.contains_key(task_name)\n            || all_tasks.values().any(|t| t.display_name == task_name)\n            || all_tasks\n                .values()\n                .any(|t| t.aliases.contains(&task_name.to_string()))\n    }\n\n    fn validate_missing_references(\n        &self,\n        task: &Task,\n        all_tasks: &BTreeMap<String, Task>,\n    ) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // Check all dependency types\n        let all_deps = task\n            .depends\n            .iter()\n            .map(|d| (\"depends\", &d.task))\n            .chain(task.depends_post.iter().map(|d| (\"depends_post\", &d.task)))\n            .chain(task.wait_for.iter().map(|d| (\"wait_for\", &d.task)));\n\n        for (dep_type, dep_name) in all_deps {\n            // Skip pattern wildcards for now (they're resolved at runtime)\n            if dep_name.contains('*') || dep_name.contains('?') {\n                continue;\n            }\n\n            // Check if task exists\n            if !Self::task_exists(all_tasks, dep_name) {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"missing-dependency\".to_string(),\n                    message: format!(\"Dependency '{}' not found\", dep_name),\n                    details: Some(format!(\n                        \"Referenced in '{}' but no matching task exists\",\n                        dep_type\n                    )),\n                });\n            }\n        }\n\n        issues\n    }\n\n    async fn validate_usage_spec(&self, task: &Task, config: &Arc<Config>) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // Try to parse the usage spec\n        match task.parse_usage_spec_for_display(config).await {\n            Ok(_spec) => {\n                // Successfully parsed\n            }\n            Err(e) => {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Warning,\n                    category: \"usage-parse-error\".to_string(),\n                    message: \"Failed to parse usage specification\".to_string(),\n                    details: Some(format!(\"{:#}\", e)),\n                });\n            }\n        }\n\n        // If task has explicit usage field, validate it's not empty\n        if !task.usage.is_empty() {\n            // Check if usage contains common USAGE directive errors\n            if task.usage.contains(\"#USAGE\") || task.usage.contains(\"# USAGE\") {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Warning,\n                    category: \"usage-directive\".to_string(),\n                    message: \"Usage field contains directive markers\".to_string(),\n                    details: Some(\n                        \"The 'usage' field should contain the spec directly, not #USAGE directives\"\n                            .to_string(),\n                    ),\n                });\n            }\n        }\n\n        issues\n    }\n\n    fn validate_timeout(&self, task: &Task) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        if let Some(ref timeout) = task.timeout {\n            // Try to parse as duration\n            if let Err(e) = duration::parse_duration(timeout) {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"invalid-timeout\".to_string(),\n                    message: format!(\"Invalid timeout format: '{}'\", timeout),\n                    details: Some(format!(\"Parse error: {}\", e)),\n                });\n            }\n        }\n\n        issues\n    }\n\n    fn validate_aliases(\n        &self,\n        task: &Task,\n        all_tasks: &BTreeMap<String, Task>,\n    ) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // Build a map of aliases to tasks\n        let mut alias_map: HashMap<String, Vec<String>> = HashMap::new();\n        for t in all_tasks.values() {\n            for alias in &t.aliases {\n                alias_map\n                    .entry(alias.clone())\n                    .or_default()\n                    .push(t.name.clone());\n            }\n        }\n\n        // Check for conflicts - only report once for the first task alphabetically\n        for alias in &task.aliases {\n            if let Some(tasks) = alias_map.get(alias)\n                && tasks.len() > 1\n            {\n                // Only report the conflict for the first task (alphabetically) to avoid duplicates\n                let mut sorted_tasks = tasks.clone();\n                sorted_tasks.sort();\n                if sorted_tasks[0] == task.name {\n                    issues.push(ValidationIssue {\n                        task: task.name.clone(),\n                        severity: Severity::Error,\n                        category: \"alias-conflict\".to_string(),\n                        message: format!(\"Alias '{}' is used by multiple tasks\", alias),\n                        details: Some(format!(\"Tasks: {}\", tasks.join(\", \"))),\n                    });\n                }\n            }\n\n            // Check if alias conflicts with a task name\n            if all_tasks.contains_key(alias) {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"alias-conflict\".to_string(),\n                    message: format!(\"Alias '{}' conflicts with task name\", alias),\n                    details: Some(format!(\"A task named '{}' already exists\", alias)),\n                });\n            }\n        }\n\n        issues\n    }\n\n    fn validate_file_existence(&self, task: &Task) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        if let Some(ref file) = task.file {\n            if !file.exists() {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"missing-file\".to_string(),\n                    message: format!(\"Task file not found: {}\", file::display_path(file)),\n                    details: None,\n                });\n            } else if !file::is_executable(file) {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Warning,\n                    category: \"not-executable\".to_string(),\n                    message: format!(\"Task file is not executable: {}\", file::display_path(file)),\n                    details: Some(format!(\"Run: chmod +x {}\", file::display_path(file))),\n                });\n            }\n        }\n\n        issues\n    }\n\n    async fn validate_directory(&self, task: &Task, config: &Arc<Config>) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        if let Some(ref dir) = task.dir {\n            // Try to render the directory template\n            if dir.contains(\"{{\") || dir.contains(\"{%\") {\n                // Contains template syntax - try to render it\n                match task.dir(config).await {\n                    Ok(rendered_dir) => {\n                        if let Some(rendered) = rendered_dir\n                            && !rendered.exists()\n                        {\n                            issues.push(ValidationIssue {\n                                task: task.name.clone(),\n                                severity: Severity::Warning,\n                                category: \"missing-directory\".to_string(),\n                                message: format!(\n                                    \"Task directory does not exist: {}\",\n                                    file::display_path(&rendered)\n                                ),\n                                details: Some(format!(\"Template: {}\", dir)),\n                            });\n                        }\n                    }\n                    Err(e) => {\n                        issues.push(ValidationIssue {\n                            task: task.name.clone(),\n                            severity: Severity::Error,\n                            category: \"invalid-directory-template\".to_string(),\n                            message: \"Failed to render directory template\".to_string(),\n                            details: Some(format!(\"Template: {}, Error: {:#}\", dir, e)),\n                        });\n                    }\n                }\n            } else {\n                // Static path - check if it exists\n                let dir_path = PathBuf::from(dir);\n                if dir_path.is_absolute() && !dir_path.exists() {\n                    issues.push(ValidationIssue {\n                        task: task.name.clone(),\n                        severity: Severity::Warning,\n                        category: \"missing-directory\".to_string(),\n                        message: format!(\"Task directory does not exist: {}\", dir),\n                        details: None,\n                    });\n                }\n            }\n        }\n\n        issues\n    }\n\n    fn validate_shell(&self, task: &Task) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        if let Some(ref shell) = task.shell {\n            // Parse shell command (could be \"bash -c\" or just \"bash\")\n            let shell_parts: Vec<&str> = shell.split_whitespace().collect();\n            if let Some(shell_cmd) = shell_parts.first() {\n                // Check if it's an absolute path\n                let shell_path = PathBuf::from(shell_cmd);\n                if shell_path.is_absolute() && !shell_path.exists() {\n                    issues.push(ValidationIssue {\n                        task: task.name.clone(),\n                        severity: Severity::Error,\n                        category: \"invalid-shell\".to_string(),\n                        message: format!(\"Shell command not found: {}\", shell_cmd),\n                        details: Some(format!(\"Full shell: {}\", shell)),\n                    });\n                }\n            }\n        }\n\n        issues\n    }\n\n    fn validate_source_patterns(&self, task: &Task) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        for source in &task.sources {\n            // Try to compile as glob pattern\n            if let Err(e) = globset::GlobBuilder::new(source).build() {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"invalid-glob-pattern\".to_string(),\n                    message: format!(\"Invalid source glob pattern: '{}'\", source),\n                    details: Some(format!(\"{}\", e)),\n                });\n            }\n        }\n\n        issues\n    }\n\n    fn validate_output_patterns(&self, task: &Task) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // Validate output patterns if they exist\n        let paths = task.outputs.patterns();\n        for path in paths {\n            // Try to compile as glob pattern\n            if let Err(e) = globset::GlobBuilder::new(&path).build() {\n                issues.push(ValidationIssue {\n                    task: task.name.clone(),\n                    severity: Severity::Error,\n                    category: \"invalid-glob-pattern\".to_string(),\n                    message: format!(\"Invalid output glob pattern: '{}'\", path),\n                    details: Some(format!(\"{}\", e)),\n                });\n            }\n        }\n\n        issues\n    }\n\n    fn validate_run_entries(\n        &self,\n        task: &Task,\n        all_tasks: &BTreeMap<String, Task>,\n    ) -> Vec<ValidationIssue> {\n        let mut issues = Vec::new();\n\n        // Validate run entries\n        for entry in task.run() {\n            match entry {\n                crate::task::RunEntry::Script(script) => {\n                    // Check if script is empty\n                    if script.trim().is_empty() {\n                        issues.push(ValidationIssue {\n                            task: task.name.clone(),\n                            severity: Severity::Warning,\n                            category: \"empty-script\".to_string(),\n                            message: \"Task contains empty script entry\".to_string(),\n                            details: None,\n                        });\n                    }\n                }\n                crate::task::RunEntry::SingleTask { task: task_name } => {\n                    // Check if referenced task exists (by name, display_name, or alias)\n                    if !Self::task_exists(all_tasks, task_name) {\n                        issues.push(ValidationIssue {\n                            task: task.name.clone(),\n                            severity: Severity::Error,\n                            category: \"missing-task-reference\".to_string(),\n                            message: format!(\n                                \"Task '{}' referenced in run entry not found\",\n                                task_name\n                            ),\n                            details: None,\n                        });\n                    }\n                }\n                crate::task::RunEntry::TaskGroup { tasks } => {\n                    // Check if all tasks in group exist (by name, display_name, or alias)\n                    for task_name in tasks {\n                        if !Self::task_exists(all_tasks, task_name) {\n                            issues.push(ValidationIssue {\n                                task: task.name.clone(),\n                                severity: Severity::Error,\n                                category: \"missing-task-reference\".to_string(),\n                                message: format!(\"Task '{}' in task group not found\", task_name),\n                                details: Some(\"Referenced in parallel task group\".to_string()),\n                            });\n                        }\n                    }\n                }\n            }\n        }\n\n        // Check if task has no run entries and no file\n        // Allow tasks with dependencies but no run entries (meta/group tasks)\n        if task.run().is_empty()\n            && task.file.is_none()\n            && task.depends.is_empty()\n            && task.depends_post.is_empty()\n        {\n            issues.push(ValidationIssue {\n                task: task.name.clone(),\n                severity: Severity::Error,\n                category: \"no-execution\".to_string(),\n                message: \"Task has no executable content\".to_string(),\n                details: Some(\n                    \"Task must have either 'run', 'run_windows', 'file', or 'depends' defined\"\n                        .to_string(),\n                ),\n            });\n        }\n\n        issues\n    }\n\n    fn output_json(&self, results: &ValidationResults) -> Result<()> {\n        let json = serde_json::to_string_pretty(results)?;\n        miseprintln!(\"{}\", json);\n        Ok(())\n    }\n\n    fn output_human(&self, results: &ValidationResults) -> Result<()> {\n        if results.issues.is_empty() {\n            miseprintln!(\n                \"{}\",\n                console_style(format!(\n                    \"✓ All {} task(s) validated successfully\",\n                    results.tasks_validated\n                ))\n                .green()\n            );\n            return Ok(());\n        }\n\n        // Group issues by task\n        let mut issues_by_task: IndexMap<String, Vec<&ValidationIssue>> = IndexMap::new();\n        for issue in &results.issues {\n            issues_by_task\n                .entry(issue.task.clone())\n                .or_insert_with(Vec::new)\n                .push(issue);\n        }\n\n        // Print summary\n        miseprintln!(\n            \"\\n{} task(s) validated with {} issue(s):\\n\",\n            console_style(results.tasks_validated).bold(),\n            console_style(results.errors + results.warnings).bold()\n        );\n\n        if results.errors > 0 {\n            miseprintln!(\n                \"  {} {}\",\n                console_style(\"✗\").red().bold(),\n                console_style(format!(\"{} error(s)\", results.errors))\n                    .red()\n                    .bold()\n            );\n        }\n        if results.warnings > 0 {\n            miseprintln!(\n                \"  {} {}\",\n                console_style(\"⚠\").yellow().bold(),\n                console_style(format!(\"{} warning(s)\", results.warnings))\n                    .yellow()\n                    .bold()\n            );\n        }\n\n        miseprintln!();\n\n        // Print issues grouped by task\n        for (task_name, task_issues) in issues_by_task {\n            miseprintln!(\n                \"{} {}\",\n                console_style(\"Task:\").bold(),\n                console_style(&task_name).cyan()\n            );\n\n            for issue in task_issues {\n                let severity_icon = match issue.severity {\n                    Severity::Error => console_style(\"✗\").red().bold(),\n                    Severity::Warning => console_style(\"⚠\").yellow().bold(),\n                };\n\n                miseprintln!(\n                    \"  {} {} [{}]\",\n                    severity_icon,\n                    console_style(&issue.message).bold(),\n                    console_style(&issue.category).dim()\n                );\n\n                if let Some(ref details) = issue.details {\n                    for line in details.lines() {\n                        miseprintln!(\"      {}\", console_style(line).dim());\n                    }\n                }\n            }\n\n            miseprintln!();\n        }\n\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Validate all tasks\n    $ <bold>mise tasks validate</bold>\n\n    # Validate specific tasks\n    $ <bold>mise tasks validate build test</bold>\n\n    # Output results as JSON\n    $ <bold>mise tasks validate --json</bold>\n\n    # Only show errors (skip warnings)\n    $ <bold>mise tasks validate --errors-only</bold>\n\n<bold><underline>Validation Checks:</underline></bold>\n\nThe validate command performs the following checks:\n\n  • <bold>Circular Dependencies</bold>: Detects dependency cycles\n  • <bold>Missing References</bold>: Finds references to non-existent tasks\n  • <bold>Usage Spec Parsing</bold>: Validates #USAGE directives and specs\n  • <bold>Timeout Format</bold>: Checks timeout values are valid durations\n  • <bold>Alias Conflicts</bold>: Detects duplicate aliases across tasks\n  • <bold>File Existence</bold>: Verifies file-based tasks exist\n  • <bold>Directory Templates</bold>: Validates directory paths and templates\n  • <bold>Shell Commands</bold>: Checks shell executables exist\n  • <bold>Glob Patterns</bold>: Validates source and output patterns\n  • <bold>Run Entries</bold>: Ensures tasks reference valid dependencies\n\"#\n);\n"
  },
  {
    "path": "src/cli/test_tool.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::file::display_path;\nuse crate::registry::{REGISTRY, RegistryTool};\nuse crate::tera::get_tera;\nuse crate::toolset::{InstallOptions, ToolsetBuilder};\nuse crate::ui::time;\nuse crate::{dirs, env, file};\nuse eyre::{Result, bail, eyre};\nuse std::path::{Path, PathBuf};\nuse std::{collections::BTreeSet, sync::Arc};\n\n/// Test a tool installs and executes\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct TestTool {\n    /// Tool(s) to test\n    #[clap(required_unless_present_any = [\"all\", \"all_config\"])]\n    pub tools: Option<Vec<ToolArg>>,\n    /// Test every tool specified in registry/\n    #[clap(long, short, conflicts_with = \"tools\", conflicts_with = \"all_config\")]\n    pub all: bool,\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    pub jobs: Option<usize>,\n    /// Test all tools specified in config files\n    #[clap(long, conflicts_with = \"tools\", conflicts_with = \"all\")]\n    pub all_config: bool,\n    /// Also test tools not defined in registry/, guessing how to test it\n    #[clap(long)]\n    pub include_non_defined: bool,\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets --jobs=1\n    #[clap(long, overrides_with = \"jobs\")]\n    pub raw: bool,\n}\n\nimpl TestTool {\n    pub async fn run(self) -> Result<()> {\n        let mut errored = vec![];\n        self.github_summary(vec![\n            \"Tool\".to_string(),\n            \"Duration\".to_string(),\n            \"Status\".to_string(),\n        ])?;\n        self.github_summary(vec![\n            \"---\".to_string(),\n            \"---\".to_string(),\n            \"---\".to_string(),\n        ])?;\n        let mut config = Config::get().await?;\n\n        let target_tools = self.get_target_tools(&config).await?;\n        for (i, (tool, rt)) in target_tools.into_iter().enumerate() {\n            if *env::TEST_TRANCHE_COUNT > 0 && (i % *env::TEST_TRANCHE_COUNT) != *env::TEST_TRANCHE\n            {\n                continue;\n            }\n            let (cmd, expected) = if let Some(test) = &rt.test {\n                (test.0.to_string(), test.1)\n            } else if self.include_non_defined {\n                (format!(\"{} --version\", tool.short), \"__TODO__\")\n            } else {\n                continue;\n            };\n            let start = std::time::Instant::now();\n            match self.test(&mut config, &tool, &cmd, expected).await {\n                Ok(_) => {\n                    info!(\"{}: OK\", tool.short);\n                    self.github_summary(vec![\n                        tool.short.clone(),\n                        time::format_duration(start.elapsed()).to_string(),\n                        \":white_check_mark:\".to_string(),\n                    ])?;\n                }\n                Err(err) => {\n                    error!(\"{}: {:?}\", tool.short, err);\n                    errored.push(tool.short.clone());\n                    self.github_summary(vec![\n                        tool.short.clone(),\n                        time::format_duration(start.elapsed()).to_string(),\n                        \":x:\".to_string(),\n                    ])?;\n                }\n            };\n        }\n        if let Ok(github_summary) = env::var(\"GITHUB_STEP_SUMMARY\") {\n            let mut content: String = \"\\n\".into();\n            if !errored.is_empty() {\n                content.push_str(&format!(\"**Failed Tools**: {}\\n\", errored.join(\", \")));\n            }\n            file::append(github_summary, content)?;\n        }\n        if !errored.is_empty() {\n            bail!(\"tools failed: {}\", errored.join(\", \"));\n        }\n        Ok(())\n    }\n\n    async fn get_target_tools(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<(ToolArg, &RegistryTool)>> {\n        if let Some(tools) = &self.tools {\n            let mut targets = Vec::new();\n            let mut not_found = Vec::new();\n            for tool_arg in tools {\n                if let Some(rt) = REGISTRY.get(tool_arg.short.as_str()) {\n                    targets.push((tool_arg.clone(), rt));\n                } else {\n                    not_found.push(tool_arg.short.clone());\n                }\n            }\n            if !not_found.is_empty() {\n                bail!(\"tools not found: {}\", not_found.join(\", \"));\n            }\n            Ok(targets)\n        } else if self.all {\n            REGISTRY\n                .iter()\n                .filter(|(short, rt)| rt.short == **short) // Filter out aliases\n                .map(|(short, rt)| short.parse().map(|s| (s, rt)))\n                .collect()\n        } else if self.all_config {\n            let ts = ToolsetBuilder::new().build(config).await?;\n            let config_tools = ts\n                .versions\n                .keys()\n                .map(|t| t.short.clone())\n                .collect::<BTreeSet<_>>();\n            let mut targets = Vec::new();\n            for tool in config_tools {\n                if let Some(rt) = REGISTRY.get(tool.as_str()) {\n                    targets.push((tool.parse()?, rt));\n                }\n            }\n            Ok(targets)\n        } else {\n            unreachable!()\n        }\n    }\n\n    fn github_summary(&self, parts: Vec<String>) -> Result<()> {\n        if let Ok(github_summary) = env::var(\"GITHUB_STEP_SUMMARY\") {\n            file::append(github_summary, format!(\"| {} |\\n\", parts.join(\" | \")))?;\n        }\n        Ok(())\n    }\n\n    async fn test(\n        &self,\n        config: &mut Arc<Config>,\n        tool: &ToolArg,\n        cmd: &str,\n        expected: &str,\n    ) -> Result<()> {\n        // First, clean all backend data by removing directories\n        let pr = crate::ui::multi_progress_report::MultiProgressReport::get()\n            .add(&format!(\"cleaning {}\", tool.short));\n\n        let mut cleaned_any = false;\n\n        // Remove entire installs directory for this tool\n        if tool.ba.installs_path.exists() {\n            info!(\n                \"Removing installs directory: {}\",\n                tool.ba.installs_path.display()\n            );\n            file::remove_all(&tool.ba.installs_path)?;\n            cleaned_any = true;\n        }\n\n        // Clear cache directory (contains metadata)\n        if tool.ba.cache_path.exists() {\n            info!(\"Removing cache directory: {}\", tool.ba.cache_path.display());\n            file::remove_all(&tool.ba.cache_path)?;\n            cleaned_any = true;\n        }\n\n        // Clear downloads directory\n        if tool.ba.downloads_path.exists() {\n            info!(\n                \"Removing downloads directory: {}\",\n                tool.ba.downloads_path.display()\n            );\n            file::remove_all(&tool.ba.downloads_path)?;\n            cleaned_any = true;\n        }\n\n        pr.finish();\n\n        // Reset the config to clear in-memory backend metadata caches if we cleaned anything\n        if cleaned_any {\n            *config = Config::reset().await?;\n        }\n\n        let mut args = vec![tool.clone()];\n        args.extend(\n            tool.ba\n                .backend()?\n                .get_all_dependencies(false)?\n                .into_iter()\n                .map(|ba| ba.to_string().parse())\n                .collect::<Result<Vec<ToolArg>>>()?,\n        );\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&args)\n            .with_default_to_latest(true)\n            .build(config)\n            .await?;\n        let opts = InstallOptions {\n            missing_args_only: false,\n            jobs: self.jobs,\n            raw: self.raw,\n            ..Default::default()\n        };\n        let (_, missing) = ts.install_missing_versions(config, &opts).await?;\n        ts.notify_missing_versions(missing);\n        let tv = if let Some(tv) = ts\n            .versions\n            .get(tool.ba.as_ref())\n            .and_then(|tvl| tvl.versions.first())\n        {\n            tv.clone()\n        } else {\n            warn!(\"no versions found for {tool}\");\n            return Ok(());\n        };\n        let backend = tv.backend()?;\n        let env = ts.env_with_path(config).await?;\n        let mut which_parts = cmd.split_whitespace().collect::<Vec<_>>();\n        let cmd = which_parts.remove(0);\n        let mut which_cmd = backend\n            .which(config, &tv, cmd)\n            .await?\n            .unwrap_or(PathBuf::from(cmd));\n        if cfg!(windows) && which_cmd == Path::new(\"which\") {\n            which_cmd = PathBuf::from(\"where\");\n        }\n        let cmd = format!(\"{} {}\", which_cmd.display(), which_parts.join(\" \"));\n        info!(\"$ {cmd}\");\n        let mut cmd = if cfg!(windows) {\n            cmd!(\"cmd\", \"/C\", cmd)\n        } else {\n            cmd!(\"sh\", \"-c\", cmd)\n        };\n        cmd = cmd.stdout_capture();\n        for (k, v) in env.iter() {\n            cmd = cmd.env(k, v);\n        }\n        let res = cmd.unchecked().run()?;\n        match res.status.code() {\n            Some(0) => {}\n            Some(code) => {\n                if code == 127 {\n                    // Show captured stdout (which may include stderr via 2>&1)\n                    // to help diagnose dynamic linker or missing library errors\n                    if let Ok(stdout) = String::from_utf8(res.stdout.clone()) {\n                        let stdout = stdout.trim();\n                        if !stdout.is_empty() {\n                            info!(\"command output:\\n{stdout}\");\n                        }\n                    }\n                    let bin_dirs = backend.list_bin_paths(config, &tv).await?;\n                    for bin_dir in &bin_dirs {\n                        let bins = file::ls(bin_dir)?\n                            .into_iter()\n                            .filter(|p| file::is_executable(p))\n                            .map(|p| p.file_name().unwrap().to_string_lossy().to_string())\n                            .collect::<Vec<_>>();\n                        info!(\n                            \"available bins in {}\\n{}\",\n                            display_path(bin_dir),\n                            bins.join(\"\\n\")\n                        );\n                    }\n                }\n                return Err(eyre!(\"command failed: exit code {}\", code));\n            }\n            None => return Err(eyre!(\"command failed: terminated by signal\")),\n        }\n        let mut ctx = config.tera_ctx.clone();\n        ctx.insert(\"version\", &tv.version);\n        let mut tera = get_tera(dirs::CWD.as_ref().map(|d| d.as_path()));\n        let expected = tera.render_str(expected, &ctx)?;\n        let stdout = String::from_utf8(res.stdout)?;\n        miseprintln!(\"{}\", stdout.trim_end());\n        if !stdout.contains(&expected) {\n            return Err(eyre!(\n                \"expected output not found: {expected}, got: {stdout}\"\n            ));\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise test-tool ripgrep</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool.rs",
    "content": "use crate::backend::SecurityFeature;\nuse crate::ui::style;\nuse eyre::Result;\nuse itertools::Itertools;\nuse serde_derive::Serialize;\n\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::toolset::{ToolSource, ToolVersionOptions, ToolsetBuilder};\nuse crate::ui::table;\n\n/// Gets information about a tool\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Tool {\n    /// Tool name to get information about\n    tool: BackendArg,\n    /// Output in JSON format\n    #[clap(long, short = 'J')]\n    json: bool,\n\n    #[clap(flatten)]\n    filter: ToolInfoFilter,\n}\n\n#[derive(Debug, Clone, clap::Args)]\n#[group(multiple = false)]\npub struct ToolInfoFilter {\n    /// Only show active versions\n    #[clap(long)]\n    active: bool,\n\n    /// Only show backend field\n    #[clap(long)]\n    backend_: bool,\n\n    /// Only show config source\n    #[clap(long)]\n    config_source: bool,\n\n    /// Only show description field\n    #[clap(long)]\n    description: bool,\n\n    /// Only show installed versions\n    #[clap(long)]\n    installed: bool,\n\n    /// Only show requested versions\n    #[clap(long)]\n    requested: bool,\n\n    /// Only show tool options\n    #[clap(long)]\n    tool_options: bool,\n}\n\nimpl Tool {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let mut ts = ToolsetBuilder::new().build(&config).await?;\n        ts.resolve(&config).await?;\n        let tvl = ts.versions.get(&self.tool);\n        let tv = tvl.map(|tvl| tvl.versions.first().unwrap());\n        let ba = tv.map(|tv| tv.ba()).unwrap_or_else(|| &self.tool);\n\n        // Check if the backend exists and fail if it doesn't\n        let backend = match ba.backend() {\n            Ok(b) => Some(b),\n            Err(e) => {\n                // If no versions are configured for this tool, it's likely invalid\n                if tvl.is_none() {\n                    return Err(e);\n                }\n                None\n            }\n        };\n\n        let (description, security) = if let Some(backend) = &backend {\n            (backend.description().await, backend.security_info().await)\n        } else {\n            (None, vec![])\n        };\n        let info = ToolInfo {\n            backend: ba.full(),\n            description,\n            installed_versions: ts\n                .list_installed_versions(&config)\n                .await?\n                .into_iter()\n                .filter(|(b, _)| b.ba().as_ref() == ba)\n                .map(|(_, tv)| tv.version)\n                .unique()\n                .collect::<Vec<_>>(),\n            active_versions: tvl.map(|tvl| {\n                tvl.versions\n                    .iter()\n                    .map(|tv| tv.version.clone())\n                    .collect::<Vec<_>>()\n            }),\n            requested_versions: tvl.map(|tvl| {\n                tvl.requests\n                    .iter()\n                    .map(|tr| tr.version())\n                    .collect::<Vec<_>>()\n            }),\n            config_source: tvl.map(|tvl| tvl.source.clone()),\n            tool_options: ba.opts(),\n            security,\n        };\n\n        if self.json {\n            self.output_json(info)\n        } else {\n            self.output_user(info)\n        }\n    }\n\n    fn output_json(&self, info: ToolInfo) -> Result<()> {\n        if self.filter.backend_ {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info.backend)?);\n        } else if self.filter.description {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info.description)?);\n        } else if self.filter.installed {\n            miseprintln!(\n                \"{}\",\n                serde_json::to_string_pretty(&info.installed_versions)?\n            );\n        } else if self.filter.active {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info.active_versions)?);\n        } else if self.filter.requested {\n            miseprintln!(\n                \"{}\",\n                serde_json::to_string_pretty(&info.requested_versions)?\n            );\n        } else if self.filter.config_source {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info.config_source)?);\n        } else if self.filter.tool_options {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info.tool_options)?);\n        } else {\n            miseprintln!(\"{}\", serde_json::to_string_pretty(&info)?);\n        }\n        Ok(())\n    }\n\n    fn output_user(&self, info: ToolInfo) -> Result<()> {\n        if self.filter.backend_ {\n            miseprintln!(\"{}\", info.backend);\n        } else if self.filter.description {\n            if let Some(description) = info.description {\n                miseprintln!(\"{}\", description);\n            } else {\n                miseprintln!(\"[none]\");\n            }\n        } else if self.filter.installed {\n            let active_set = info\n                .active_versions\n                .as_ref()\n                .map(|v| v.iter().collect::<std::collections::HashSet<_>>())\n                .unwrap_or_default();\n            let installed_with_bold = info\n                .installed_versions\n                .iter()\n                .map(|v| {\n                    if active_set.contains(v) {\n                        style::nbold(v).to_string()\n                    } else {\n                        v.to_string()\n                    }\n                })\n                .join(\" \");\n            miseprintln!(\"{}\", installed_with_bold);\n        } else if self.filter.active {\n            if let Some(active_versions) = info.active_versions {\n                miseprintln!(\"{}\", active_versions.join(\" \"));\n            } else {\n                miseprintln!(\"[none]\");\n            }\n        } else if self.filter.requested {\n            if let Some(requested_versions) = info.requested_versions {\n                miseprintln!(\"{}\", requested_versions.join(\" \"));\n            } else {\n                miseprintln!(\"[none]\");\n            }\n        } else if self.filter.config_source {\n            if let Some(config_source) = info.config_source {\n                miseprintln!(\"{}\", config_source);\n            } else {\n                miseprintln!(\"[none]\");\n            }\n        } else if self.filter.tool_options {\n            if info.tool_options.is_empty() {\n                miseprintln!(\"[none]\");\n            } else {\n                for (k, v) in info.tool_options.opts {\n                    miseprintln!(\"{k}={v:?}\");\n                }\n            }\n        } else {\n            let mut table = vec![];\n            table.push((\"Backend:\", info.backend));\n            if let Some(description) = info.description {\n                table.push((\"Description:\", description));\n            }\n            // Bold currently active versions within the installed list for clarity\n            let active_set = info\n                .active_versions\n                .as_ref()\n                .map(|v| v.iter().collect::<std::collections::HashSet<_>>())\n                .unwrap_or_default();\n            let installed_with_bold = info\n                .installed_versions\n                .iter()\n                .map(|v| {\n                    if active_set.contains(v) {\n                        style::nbold(v).to_string()\n                    } else {\n                        v.to_string()\n                    }\n                })\n                .join(\" \");\n            table.push((\"Installed Versions:\", installed_with_bold));\n            if let Some(active_versions) = info.active_versions {\n                table.push((\n                    \"Active Version:\",\n                    style::nbold(active_versions.join(\" \")).to_string(),\n                ));\n            }\n            if let Some(requested_versions) = info.requested_versions {\n                table.push((\"Requested Version:\", requested_versions.join(\" \")));\n            }\n            if let Some(config_source) = info.config_source {\n                table.push((\"Config Source:\", config_source.to_string()));\n            }\n            if info.tool_options.is_empty() {\n                table.push((\"Tool Options:\", \"[none]\".to_string()));\n            } else {\n                table.push((\n                    \"Tool Options:\",\n                    info.tool_options\n                        .opts\n                        .into_iter()\n                        .map(|(k, v)| format!(\"{k}={v:?}\"))\n                        .join(\",\"),\n                ));\n            }\n            if info.security.is_empty() {\n                table.push((\"Security:\", \"[none]\".to_string()));\n            } else {\n                let security_str = info\n                    .security\n                    .iter()\n                    .map(|f| match f {\n                        SecurityFeature::Checksum { algorithm } => {\n                            if let Some(alg) = algorithm {\n                                format!(\"checksum ({})\", alg)\n                            } else {\n                                \"checksum\".to_string()\n                            }\n                        }\n                        SecurityFeature::GithubAttestations { .. } => {\n                            \"github_attestations\".to_string()\n                        }\n                        SecurityFeature::Slsa { level } => {\n                            if let Some(l) = level {\n                                format!(\"slsa (level {})\", l)\n                            } else {\n                                \"slsa\".to_string()\n                            }\n                        }\n                        SecurityFeature::Cosign => \"cosign\".to_string(),\n                        SecurityFeature::Minisign { .. } => \"minisign\".to_string(),\n                        SecurityFeature::Gpg => \"gpg\".to_string(),\n                    })\n                    .join(\", \");\n                table.push((\"Security:\", security_str));\n            }\n            let mut table = tabled::Table::new(table);\n            table::default_style(&mut table, true);\n            miseprintln!(\"{table}\");\n        }\n\n        Ok(())\n    }\n}\n\n#[derive(Serialize)]\nstruct ToolInfo {\n    backend: String,\n    description: Option<String>,\n    installed_versions: Vec<String>,\n    requested_versions: Option<Vec<String>>,\n    active_versions: Option<Vec<String>>,\n    config_source: Option<ToolSource>,\n    tool_options: ToolVersionOptions,\n    security: Vec<SecurityFeature>,\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tool node</bold>\n    Backend:            core\n    Installed Versions: 20.0.0 22.0.0\n    Active Version:     20.0.0\n    Requested Version:  20\n    Config Source:      ~/.config/mise/mise.toml\n    Tool Options:       [none]\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool_alias/get.rs",
    "content": "use color_eyre::eyre::{Result, eyre};\n\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\n\n/// Show an alias for a plugin\n///\n/// This is the contents of a tool_alias.<PLUGIN> entry in ~/.config/mise/config.toml\n///\n#[derive(Debug, clap::Args)]\n#[clap(after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ToolAliasGet {\n    /// The plugin to show the alias for\n    pub plugin: BackendArg,\n    /// The alias to show\n    pub alias: String,\n}\n\nimpl ToolAliasGet {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        match config.all_aliases.get(&self.plugin.short) {\n            Some(alias) => match alias.versions.get(&self.alias) {\n                Some(alias) => {\n                    miseprintln!(\"{alias}\");\n                    Ok(())\n                }\n                None => Err(eyre!(\"Unknown alias: {}\", &self.alias)),\n            },\n            None => Err(eyre!(\"Unknown plugin: {}\", &self.plugin)),\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tool-alias get node lts-hydrogen</bold>\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool_alias/ls.rs",
    "content": "use eyre::Result;\nuse itertools::Itertools;\nuse tabled::Tabled;\n\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::ui::table;\n\n/// List tool version aliases\n/// Shows the aliases that can be specified.\n/// These can come from user config or from plugins in `bin/list-aliases`.\n///\n/// For user config, aliases are defined like the following in `~/.config/mise/config.toml`:\n///\n///     [tool_alias.node.versions]\n///     lts = \"22.0.0\"\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"list\", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ToolAliasLs {\n    /// Show aliases for <TOOL>\n    #[clap()]\n    pub tool: Option<BackendArg>,\n\n    /// Don't show table header\n    #[clap(long)]\n    pub no_header: bool,\n}\n\nimpl ToolAliasLs {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let rows = config\n            .all_aliases\n            .iter()\n            .filter(|(short, _)| {\n                self.tool.is_none() || self.tool.as_ref().is_some_and(|f| &f.short == *short)\n            })\n            .sorted_by(|(a, _), (b, _)| a.cmp(b))\n            .flat_map(|(short, aliases)| {\n                aliases\n                    .versions\n                    .iter()\n                    .filter(|(from, _to)| short != \"node\" || !from.starts_with(\"lts/\"))\n                    .map(|(from, to)| Row {\n                        tool: short.clone(),\n                        alias: from.clone(),\n                        version: to.clone(),\n                    })\n                    .collect::<Vec<_>>()\n            })\n            .collect::<Vec<_>>();\n        let mut table = tabled::Table::new(rows);\n        table::default_style(&mut table, self.no_header);\n        miseprintln!(\"{table}\");\n        Ok(())\n    }\n}\n\n#[derive(Tabled)]\nstruct Row {\n    tool: String,\n    alias: String,\n    version: String,\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tool-alias ls</bold>\n    node  lts-jod      22\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool_alias/mod.rs",
    "content": "use clap::Subcommand;\nuse eyre::Result;\n\nuse crate::cli::args::BackendArg;\n\nmod get;\nmod ls;\nmod set;\nmod unset;\n\n#[derive(Debug, clap::Args)]\n#[clap(\n    name = \"tool-alias\",\n    about = \"Manage tool version aliases.\",\n    alias = \"alias\",\n    alias = \"aliases\"\n)]\npub struct ToolAlias {\n    #[clap(subcommand)]\n    command: Option<Commands>,\n\n    /// filter aliases by plugin\n    #[clap(short, long)]\n    pub plugin: Option<BackendArg>,\n\n    /// Don't show table header\n    #[clap(long)]\n    pub no_header: bool,\n}\n\n#[derive(Debug, Subcommand)]\nenum Commands {\n    Get(get::ToolAliasGet),\n    Ls(ls::ToolAliasLs),\n    Set(set::ToolAliasSet),\n    Unset(unset::ToolAliasUnset),\n}\n\nimpl Commands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Get(cmd) => cmd.run().await,\n            Self::Ls(cmd) => cmd.run().await,\n            Self::Set(cmd) => cmd.run().await,\n            Self::Unset(cmd) => cmd.run().await,\n        }\n    }\n}\n\nimpl ToolAlias {\n    pub async fn run(self) -> Result<()> {\n        let cmd = self.command.unwrap_or(Commands::Ls(ls::ToolAliasLs {\n            tool: self.plugin,\n            no_header: self.no_header,\n        }));\n\n        cmd.run().await\n    }\n}\n"
  },
  {
    "path": "src/cli/tool_alias/set.rs",
    "content": "use eyre::Result;\n\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::config::config_file::ConfigFile;\n\n/// Add/update an alias for a backend/plugin\n///\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"add\", \"create\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ToolAliasSet {\n    /// The backend/plugin to set the alias for\n    pub plugin: BackendArg,\n    /// The alias to set\n    pub alias: String,\n    /// The value to set the alias to\n    pub value: Option<String>,\n}\n\nimpl ToolAliasSet {\n    pub async fn run(self) -> Result<()> {\n        let mut global_config = Config::get().await?.global_config()?;\n        match &self.value {\n            None => global_config.set_backend_alias(&self.plugin, &self.alias)?,\n            Some(val) => global_config.set_alias(&self.plugin, &self.alias, val)?,\n        }\n        global_config.save()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tool-alias set maven asdf:mise-plugins/mise-maven</bold>\n    $ <bold>mise tool-alias set node lts-jod 22.0.0</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool_alias/unset.rs",
    "content": "use eyre::Result;\n\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::config::config_file::ConfigFile;\n\n/// Clears an alias for a backend/plugin\n///\n/// This modifies the contents of ~/.config/mise/config.toml\n#[derive(Debug, clap::Args)]\n#[clap(visible_aliases = [\"rm\", \"remove\", \"delete\", \"del\"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]\npub struct ToolAliasUnset {\n    /// The backend/plugin to remove the alias from\n    pub plugin: BackendArg,\n    /// The alias to remove\n    pub alias: Option<String>,\n}\n\nimpl ToolAliasUnset {\n    pub async fn run(self) -> Result<()> {\n        let mut global_config = Config::get().await?.global_config()?;\n        match self.alias {\n            None => {\n                global_config.remove_backend_alias(&self.plugin)?;\n            }\n            Some(ref alias) => {\n                global_config.remove_alias(&self.plugin, alias)?;\n            }\n        }\n        global_config.save()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise tool-alias unset maven</bold>\n    $ <bold>mise tool-alias unset node lts-jod</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/tool_stub.rs",
    "content": "use std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\n\nuse crate::backend::static_helpers::lookup_platform_key;\nuse crate::config::Config;\nuse crate::dirs;\nuse crate::file;\nuse crate::hash;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::{InstallOptions, ToolRequest, ToolSource, ToolVersionOptions};\nuse clap::Parser;\nuse color_eyre::eyre::{Result, bail, eyre};\nuse eyre::ensure;\nuse serde::{Deserialize, Deserializer};\nuse toml::Value;\n\n#[derive(Debug, Deserialize)]\npub struct ToolStubFile {\n    #[serde(default = \"default_version\")]\n    pub version: String,\n    pub bin: Option<String>,  // defaults to filename if not specified\n    pub tool: Option<String>, // explicit tool name override\n    #[serde(default)]\n    pub install_env: indexmap::IndexMap<String, String>,\n    #[serde(default)]\n    pub os: Option<Vec<String>>,\n    pub lock: Option<ToolStubLock>,\n    #[serde(flatten, deserialize_with = \"deserialize_tool_stub_options\")]\n    pub opts: indexmap::IndexMap<String, toml::Value>,\n    #[serde(skip)]\n    pub tool_name: String,\n}\n\n#[derive(Debug, Deserialize)]\npub struct ToolStubLock {\n    pub platforms: BTreeMap<String, ToolStubLockPlatform>,\n}\n\n#[derive(Debug, Deserialize)]\npub struct ToolStubLockPlatform {\n    pub url: Option<String>,\n    pub checksum: Option<String>,\n}\n\n// Custom deserializer that keeps TOML values native, converting scalars to strings\nfn deserialize_tool_stub_options<'de, D>(\n    deserializer: D,\n) -> Result<indexmap::IndexMap<String, toml::Value>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let value = Value::deserialize(deserializer)?;\n    let mut opts = indexmap::IndexMap::new();\n\n    if let Value::Table(table) = value {\n        for (key, val) in table {\n            // Skip known special fields that are handled separately\n            if matches!(\n                key.as_str(),\n                \"version\" | \"bin\" | \"tool\" | \"install_env\" | \"os\" | \"lock\"\n            ) {\n                continue;\n            }\n\n            let stored_value = match val {\n                Value::String(_) | Value::Table(_) | Value::Array(_) => val,\n                // Convert scalar values (ints, bools, floats) to strings\n                _ => Value::String(val.to_string().trim_matches('\"').to_string()),\n            };\n\n            opts.insert(key, stored_value);\n        }\n    }\n\n    Ok(opts)\n}\n\nfn default_version() -> String {\n    \"latest\".to_string()\n}\n\nfn has_http_backend_config(opts: &indexmap::IndexMap<String, toml::Value>) -> bool {\n    // Check for top-level url\n    if opts.contains_key(\"url\") {\n        return true;\n    }\n\n    // Check for platform-specific configs with urls\n    for (key, value) in opts {\n        if key.starts_with(\"platforms\") {\n            // Check if the value is a table containing url keys\n            if let toml::Value::Table(table) = value {\n                for (_, v) in table {\n                    if let toml::Value::Table(inner) = v\n                        && inner.contains_key(\"url\")\n                    {\n                        return true;\n                    }\n                }\n            } else if let toml::Value::String(s) = value\n                && s.contains(\"url\")\n            {\n                return true;\n            }\n        }\n    }\n\n    false\n}\n\n/// Extract TOML content from a bootstrap script's comment block\n/// Looks for content between `# MISE_TOOL_STUB:` and `# :MISE_TOOL_STUB` markers\nfn extract_toml_from_bootstrap(content: &str) -> Option<String> {\n    let start_marker = \"# MISE_TOOL_STUB:\";\n    let end_marker = \"# :MISE_TOOL_STUB\";\n\n    let start_pos = content.find(start_marker)?;\n    let end_pos = content.find(end_marker)?;\n\n    if start_pos >= end_pos {\n        return None;\n    }\n\n    // Extract content between markers (skip the start marker line)\n    let between = &content[start_pos + start_marker.len()..end_pos];\n\n    // Remove leading `# ` from each line to get the original TOML\n    let toml = between\n        .lines()\n        .map(|line| line.strip_prefix(\"# \").unwrap_or(line))\n        .collect::<Vec<_>>()\n        .join(\"\\n\");\n\n    Some(toml.trim().to_string())\n}\n\nimpl ToolStubFile {\n    pub fn from_file(path: &Path) -> Result<Self> {\n        let content = file::read_to_string(path)?;\n        let stub_name = path\n            .file_name()\n            .and_then(|name| name.to_str())\n            .ok_or_else(|| eyre!(\"Invalid stub file name\"))?\n            .to_string();\n\n        // Check if this is a bootstrap script with embedded TOML\n        let toml_content = if let Some(toml) = extract_toml_from_bootstrap(&content) {\n            toml\n        } else {\n            content\n        };\n\n        let mut stub: ToolStubFile = toml::from_str(&toml_content)?;\n\n        // Determine tool name from tool field or derive from stub name\n        // If no tool is specified, default to HTTP backend if HTTP config is present\n        let tool_name = stub\n            .tool\n            .clone()\n            .or_else(|| {\n                stub.opts\n                    .get(\"tool\")\n                    .and_then(|v| v.as_str())\n                    .map(|s| s.to_string())\n            })\n            .unwrap_or_else(|| {\n                if has_http_backend_config(&stub.opts) {\n                    format!(\"http:{stub_name}\")\n                } else {\n                    stub_name.to_string()\n                }\n            });\n\n        // Set bin to filename if not specified\n        if stub.bin.is_none() {\n            stub.bin = Some(stub_name.to_string());\n        }\n\n        stub.tool_name = tool_name;\n\n        Ok(stub)\n    }\n\n    // Create a ToolRequest directly using ToolVersionOptions\n    pub fn to_tool_request(&self, stub_path: &Path) -> Result<ToolRequest> {\n        use crate::cli::args::BackendArg;\n\n        let mut backend_arg = BackendArg::from(&self.tool_name);\n        let source = ToolSource::ToolStub(stub_path.to_path_buf());\n\n        // Create ToolVersionOptions from our fields\n        let mut opts = self.opts.clone();\n        opts.shift_remove(\"tool\"); // Remove tool field since it's handled separately\n\n        // Add bin field if present\n        if let Some(bin) = &self.bin {\n            opts.insert(\"bin\".to_string(), toml::Value::String(bin.clone()));\n        }\n\n        let options = ToolVersionOptions {\n            os: self.os.clone(),\n            install_env: self.install_env.clone(),\n            opts,\n        };\n\n        // Set options on the BackendArg so they're available to the backend\n        backend_arg.set_opts(Some(options.clone()));\n\n        // For HTTP backend with \"latest\" version, use URL+checksum hash as version for stability\n        let version = if self.tool_name.starts_with(\"http:\") && self.version == \"latest\" {\n            if let Some(url) = lookup_platform_key(&options, \"url\")\n                .or_else(|| options.get(\"url\").map(|s| s.to_string()))\n            {\n                // Include checksum in hash calculation for better version stability\n                let checksum = lookup_platform_key(&options, \"checksum\")\n                    .or_else(|| options.get(\"checksum\").map(|s| s.to_string()))\n                    .unwrap_or_default();\n                let hash_input = format!(\"{url}:{checksum}\");\n                // Use first 8 chars of URL+checksum hash as version\n                format!(\"url-{}\", &hash::hash_to_str(&hash_input)[..8])\n            } else {\n                self.version.clone()\n            }\n        } else {\n            self.version.clone()\n        };\n\n        ToolRequest::new_opts(backend_arg.into(), &version, options, source)\n    }\n}\n\n// Cache just stores the binary path as a raw string\n// The mtime is already encoded in the cache key, so no need to store it\n\nstruct BinPathCache;\n\nimpl BinPathCache {\n    fn cache_key(stub_path: &Path) -> Result<String> {\n        let path_str = stub_path.to_string_lossy();\n        let mtime = stub_path.metadata()?.modified()?;\n        let mtime_str = format!(\n            \"{:?}\",\n            mtime\n                .duration_since(std::time::UNIX_EPOCH)\n                .unwrap_or_default()\n                .as_secs()\n        );\n        Ok(hash::hash_to_str(&format!(\"{path_str}:{mtime_str}\")))\n    }\n\n    fn cache_file_path(cache_key: &str) -> PathBuf {\n        dirs::CACHE.join(\"tool-stubs\").join(cache_key)\n    }\n\n    fn load(cache_key: &str) -> Option<PathBuf> {\n        let cache_path = Self::cache_file_path(cache_key);\n        if !cache_path.exists() {\n            return None;\n        }\n\n        match file::read_to_string(&cache_path) {\n            Ok(content) => {\n                let bin_path = PathBuf::from(content.trim());\n                // Verify the cached binary still exists\n                if bin_path.exists() {\n                    Some(bin_path)\n                } else {\n                    // Clean up stale cache (missing binary)\n                    let _ = file::remove_file(&cache_path);\n                    None\n                }\n            }\n            Err(_) => None,\n        }\n    }\n\n    fn save(bin_path: &Path, cache_key: &str) -> Result<()> {\n        let cache_path = Self::cache_file_path(cache_key);\n\n        if let Some(parent) = cache_path.parent() {\n            file::create_dir_all(parent)?;\n        }\n\n        file::write(&cache_path, bin_path.to_string_lossy().as_bytes())?;\n        Ok(())\n    }\n}\n\nfn find_tool_version(\n    toolset: &crate::toolset::Toolset,\n    config: &std::sync::Arc<Config>,\n    tool_name: &str,\n) -> Option<crate::toolset::ToolVersion> {\n    for (_backend, tv) in toolset.list_current_installed_versions(config) {\n        if tv.ba().short == tool_name {\n            return Some(tv);\n        }\n    }\n    None\n}\n\nfn find_single_subdirectory(install_path: &Path) -> Option<PathBuf> {\n    let Ok(entries) = std::fs::read_dir(install_path) else {\n        return None;\n    };\n\n    let dirs: Vec<_> = entries\n        .filter_map(|entry| entry.ok())\n        .filter(|entry| entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false))\n        .collect();\n\n    if dirs.len() == 1 {\n        Some(dirs[0].path())\n    } else {\n        None\n    }\n}\n\nfn try_find_bin_in_path(base_path: &Path, bin: &str) -> Option<PathBuf> {\n    let bin_path = base_path.join(bin);\n    if bin_path.exists() && crate::file::is_executable(&bin_path) {\n        Some(bin_path)\n    } else {\n        None\n    }\n}\n\nfn list_executable_files(dir_path: &Path) -> Vec<String> {\n    list_executable_files_recursive(dir_path, dir_path)\n}\n\nfn list_executable_files_recursive(base_path: &Path, current_path: &Path) -> Vec<String> {\n    let Ok(entries) = std::fs::read_dir(current_path) else {\n        return Vec::new();\n    };\n\n    let mut result = Vec::new();\n\n    for entry in entries.filter_map(|e| e.ok()) {\n        let path = entry.path();\n        let filename = entry.file_name();\n        let filename_str = filename.to_string_lossy();\n\n        // Skip hidden files (starting with .)\n        if filename_str.starts_with('.') {\n            continue;\n        }\n\n        if path.is_dir() {\n            // Recursively search subdirectories\n            let subdir_files = list_executable_files_recursive(base_path, &path);\n            result.extend(subdir_files);\n        } else if path.is_file() && crate::file::is_executable(&path) {\n            // Get the relative path from the base directory\n            if let Ok(relative_path) = path.strip_prefix(base_path) {\n                result.push(relative_path.to_string_lossy().to_string());\n            }\n        }\n    }\n\n    result\n}\n\nfn resolve_bin_with_path(\n    toolset: &crate::toolset::Toolset,\n    config: &std::sync::Arc<Config>,\n    bin: &str,\n    tool_name: &str,\n) -> Option<PathBuf> {\n    let tv = find_tool_version(toolset, config, tool_name)?;\n    let install_path = tv.install_path();\n\n    // Try direct path first\n    if let Some(bin_path) = try_find_bin_in_path(&install_path, bin) {\n        return Some(bin_path);\n    }\n\n    // If direct path doesn't work, try skipping a single top-level directory\n    // This handles cases where the tarball has a single top-level directory\n    let subdir_path = find_single_subdirectory(&install_path)?;\n    try_find_bin_in_path(&subdir_path, bin)\n}\n\nasync fn resolve_bin_simple(\n    toolset: &crate::toolset::Toolset,\n    config: &std::sync::Arc<Config>,\n    bin: &str,\n) -> Result<Option<PathBuf>> {\n    if let Some((backend, tv)) = toolset.which(config, bin).await {\n        backend.which(config, &tv, bin).await\n    } else {\n        Ok(None)\n    }\n}\n\nfn is_bin_path(bin: &str) -> bool {\n    bin.contains('/') || bin.contains('\\\\')\n}\n\n#[derive(Debug)]\nenum BinPathError {\n    ToolNotFound(String),\n    BinNotFound {\n        tool_name: String,\n        bin: String,\n        available_bins: Vec<String>,\n    },\n}\n\nfn resolve_platform_specific_bin(stub: &ToolStubFile, stub_path: &Path) -> String {\n    // Try to find platform-specific bin field first\n    let platform_key = get_current_platform_key();\n\n    // Check for platform-specific bin field: platforms.{platform}.bin\n    if let Some(toml::Value::Table(platforms)) = stub.opts.get(\"platforms\")\n        && let Some(toml::Value::Table(platform)) = platforms.get(&platform_key)\n        && let Some(toml::Value::String(bin)) = platform.get(\"bin\")\n    {\n        return bin.clone();\n    }\n\n    // Fall back to global bin field\n    if let Some(bin) = &stub.bin {\n        return bin.to_string();\n    }\n\n    // Finally, fall back to stub filename (without extension)\n    stub_path\n        .file_stem()\n        .and_then(|s| s.to_str())\n        .unwrap_or(&stub.tool_name)\n        .to_string()\n}\n\nfn get_current_platform_key() -> String {\n    use crate::config::Settings;\n    let settings = Settings::get();\n    format!(\"{}-{}\", settings.os(), settings.arch())\n}\n\nasync fn find_cached_or_resolve_bin_path(\n    toolset: &crate::toolset::Toolset,\n    config: &std::sync::Arc<Config>,\n    stub: &ToolStubFile,\n    stub_path: &Path,\n) -> Result<Result<PathBuf, BinPathError>> {\n    // Generate cache key from file path and mtime\n    let cache_key = BinPathCache::cache_key(stub_path)?;\n\n    // Try to load from cache first\n    if let Some(bin_path) = BinPathCache::load(&cache_key) {\n        return Ok(Ok(bin_path));\n    }\n\n    // Cache miss - resolve the binary path\n    let bin = resolve_platform_specific_bin(stub, stub_path);\n    let bin_path = if is_bin_path(&bin) {\n        resolve_bin_with_path(toolset, config, &bin, &stub.tool_name)\n    } else {\n        resolve_bin_simple(toolset, config, &bin).await?\n    };\n\n    if let Some(bin_path) = bin_path {\n        // Cache the result\n        if let Err(e) = BinPathCache::save(&bin_path, &cache_key) {\n            // Don't fail if caching fails, just log it\n            crate::warn!(\"Failed to cache binary path: {e}\");\n        }\n\n        return Ok(Ok(bin_path));\n    }\n\n    // Determine the specific error\n    if is_bin_path(&bin) {\n        // For path-based bins, check if the tool exists first\n        if let Some(tv) = find_tool_version(toolset, config, &stub.tool_name) {\n            let install_path = tv.install_path();\n            // List all executable files recursively from the install path\n            let available_bins = list_executable_files(&install_path);\n\n            Ok(Err(BinPathError::BinNotFound {\n                tool_name: stub.tool_name.clone(),\n                bin: bin.to_string(),\n                available_bins,\n            }))\n        } else {\n            Ok(Err(BinPathError::ToolNotFound(stub.tool_name.clone())))\n        }\n    } else {\n        // For simple bin names, first check if the tool itself exists\n        if let Some(tv) = find_tool_version(toolset, config, &stub.tool_name) {\n            // Tool exists, list its available executables\n            let available_bins = list_executable_files(&tv.install_path());\n            Ok(Err(BinPathError::BinNotFound {\n                tool_name: stub.tool_name.clone(),\n                bin: bin.to_string(),\n                available_bins,\n            }))\n        } else {\n            // Tool doesn't exist\n            Ok(Err(BinPathError::ToolNotFound(stub.tool_name.clone())))\n        }\n    }\n}\n\nasync fn execute_with_tool_request(\n    stub: &ToolStubFile,\n    config: &mut std::sync::Arc<Config>,\n    args: Vec<String>,\n    stub_path: &Path,\n) -> Result<()> {\n    // Use direct ToolRequest creation with ToolVersionOptions\n    let tool_request = stub.to_tool_request(stub_path)?;\n\n    // Create a toolset directly and add the tool request with its options\n    let source = ToolSource::ToolStub(stub_path.to_path_buf());\n    let mut toolset = crate::toolset::Toolset::new(source);\n    toolset.add_version(tool_request);\n\n    // Resolve the toolset to populate current versions\n    toolset.resolve(config).await?;\n\n    // Inject lock data from stub into tool versions\n    // The toolset contains only the single tool from this stub, so apply to all versions\n    if let Some(lock) = &stub.lock {\n        for (_ba, tvl) in toolset.versions.iter_mut() {\n            for tv in &mut tvl.versions {\n                for (platform_key, lock_platform) in &lock.platforms {\n                    let pi = PlatformInfo {\n                        url: lock_platform.url.clone(),\n                        checksum: lock_platform.checksum.clone(),\n                        ..Default::default()\n                    };\n                    tv.lock_platforms.insert(platform_key.clone(), pi);\n                }\n            }\n        }\n    }\n\n    // Ensure we have current versions after resolving\n    ensure!(\n        !toolset.list_current_versions().is_empty(),\n        \"No current versions found after resolving toolset\"\n    );\n\n    // Install the tool if it's missing\n    let install_opts = InstallOptions {\n        force: false,\n        jobs: None,\n        raw: false,\n        missing_args_only: false,\n        resolve_options: Default::default(),\n        ..Default::default()\n    };\n\n    let (_, missing) = toolset\n        .install_missing_versions(config, &install_opts)\n        .await?;\n    toolset.notify_missing_versions(missing);\n\n    // Find the binary path using cache\n    match find_cached_or_resolve_bin_path(&toolset, &*config, stub, stub_path).await? {\n        Ok(bin_path) => {\n            // Get the environment with proper PATH from toolset\n            let mut env = toolset.env_with_path(config).await?;\n            let mut path_env = crate::path_env::PathEnv::from_iter(crate::env::PATH.clone());\n            for p in toolset.list_paths(config).await {\n                path_env.add(p);\n            }\n\n            if let Some((backend, _tv)) = toolset.list_current_installed_versions(config).first() {\n                let btp = backend\n                    .dependency_toolset(config)\n                    .await?\n                    .list_paths(config)\n                    .await;\n                for p in btp {\n                    path_env.add(p);\n                }\n            }\n            env.insert(crate::env::PATH_KEY.to_string(), path_env.to_string());\n\n            crate::cli::exec::exec_program(bin_path, args, env)\n        }\n        Err(e) => match e {\n            BinPathError::ToolNotFound(tool_name) => {\n                bail!(\"Tool '{}' not found\", tool_name);\n            }\n            BinPathError::BinNotFound {\n                tool_name,\n                bin,\n                available_bins,\n            } => {\n                if available_bins.is_empty() {\n                    bail!(\n                        \"Tool '{}' does not have an executable named '{}'\",\n                        tool_name,\n                        bin\n                    );\n                } else {\n                    bail!(\n                        \"Tool '{}' does not have an executable named '{}'. Available executables: {}\",\n                        tool_name,\n                        bin,\n                        available_bins.join(\", \")\n                    );\n                }\n            }\n        },\n    }\n}\n\n/// Execute a tool stub\n///\n/// Tool stubs are executable files containing TOML configuration that specify\n/// which tool to run and how to run it. They provide a convenient way to create\n/// portable, self-contained executables that automatically manage tool installation\n/// and execution.\n///\n/// A tool stub consists of:\n/// - A shebang line: #!/usr/bin/env -S mise tool-stub\n/// - TOML configuration specifying the tool, version, and options\n/// - Optional comments describing the tool's purpose\n///\n/// Example stub file:\n///   #!/usr/bin/env -S mise tool-stub\n///   # Node.js v20 development environment\n///   \n///   tool = \"node\"\n///   version = \"20.0.0\"\n///   bin = \"node\"\n///\n/// The stub will automatically install the specified tool version if missing\n/// and execute it with any arguments passed to the stub.\n///\n/// For more information, see: https://mise.jdx.dev/dev-tools/tool-stubs.html\n#[derive(Debug, Parser)]\n#[clap(disable_help_flag = true, disable_version_flag = true)]\npub struct ToolStub {\n    /// Path to the TOML tool stub file to execute\n    ///\n    /// The stub file must contain TOML configuration specifying the tool\n    /// and version to run. At minimum, it should specify a 'version' field.\n    /// Other common fields include 'tool', 'bin', and backend-specific options.\n    #[clap(value_name = \"FILE\")]\n    pub file: PathBuf,\n\n    /// Arguments to pass to the tool\n    ///\n    /// All arguments after the stub file path will be forwarded to the\n    /// underlying tool. Use '--' to separate mise arguments from tool arguments\n    /// if needed.\n    #[clap(trailing_var_arg = true, allow_hyphen_values = true)]\n    pub args: Vec<String>,\n}\n\nimpl ToolStub {\n    pub async fn run(self) -> Result<()> {\n        // Ignore clap parsing and use raw args from env::ARGS to avoid version flag interception\n        let file_str = self.file.to_string_lossy();\n\n        // Find our file in the global args and take everything after it\n        let args = {\n            let global_args = crate::env::ARGS.read().unwrap();\n            let file_str_ref: &str = file_str.as_ref();\n            if let Some(file_pos) = global_args.iter().position(|arg| arg == file_str_ref) {\n                global_args.get(file_pos + 1..).unwrap_or(&[]).to_vec()\n            } else {\n                vec![]\n            }\n        }; // Drop the lock before await\n\n        let stub = ToolStubFile::from_file(&self.file)?;\n        let mut config = Config::get().await?;\n\n        return execute_with_tool_request(&stub, &mut config, args, &self.file).await;\n    }\n}\n\npub(crate) async fn short_circuit_stub(args: &[String]) -> Result<()> {\n    // Early return if no args or not enough args for a stub\n    if args.is_empty() {\n        return Ok(());\n    }\n\n    // Check if the first argument looks like a tool stub file path\n    let potential_stub_path = std::path::Path::new(&args[0]);\n\n    // Only proceed if it's an existing file with a reasonable extension\n    if !potential_stub_path.exists() {\n        return Ok(());\n    }\n\n    // Generate cache key from file path and mtime\n    let cache_key = BinPathCache::cache_key(potential_stub_path)?;\n\n    // Check if we have a cached binary path\n    if let Some(bin_path) = BinPathCache::load(&cache_key) {\n        let args = args[1..].to_vec();\n        return crate::cli::exec::exec_program(bin_path, args, BTreeMap::new());\n    }\n\n    // No cache hit, return Ok(()) to continue with normal processing\n    Ok(())\n}\n"
  },
  {
    "path": "src/cli/trust.rs",
    "content": "use std::path::PathBuf;\n\nuse crate::config::config_file::config_trust_root;\nuse crate::config::{\n    ALL_CONFIG_FILES, DEFAULT_CONFIG_FILENAMES, Settings, config_file, config_files_in_dir,\n    is_global_config,\n};\nuse crate::file::{display_path, remove_file};\nuse crate::{config, dirs, env, file};\nuse clap::ValueHint;\nuse eyre::Result;\nuse itertools::Itertools;\n\n/// Marks a config file as trusted\n///\n/// This means mise will parse the file with potentially dangerous\n/// features enabled.\n///\n/// This includes:\n/// - environment variables\n/// - templates\n/// - `path:` plugin versions\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Trust {\n    /// The config file to trust\n    #[clap(value_hint = ValueHint::FilePath, verbatim_doc_comment)]\n    config_file: Option<PathBuf>,\n\n    /// Trust all config files in the current directory and its parents\n    #[clap(long, short, verbatim_doc_comment, conflicts_with_all = &[\"ignore\", \"untrust\"])]\n    all: bool,\n\n    /// Do not trust this config and ignore it in the future\n    #[clap(long, conflicts_with = \"untrust\")]\n    ignore: bool,\n\n    /// Show the trusted status of config files from the current directory and its parents.\n    /// Does not trust or untrust any files.\n    #[clap(long, verbatim_doc_comment)]\n    show: bool,\n\n    /// No longer trust this config, will prompt in the future\n    #[clap(long)]\n    untrust: bool,\n}\n\nimpl Trust {\n    pub async fn run(mut self) -> Result<()> {\n        if self.show {\n            return self.show();\n        }\n        if self.untrust {\n            self.untrust()\n        } else if self.ignore {\n            self.ignore()\n        } else if self.all {\n            while let Some(p) = self.get_next_untrusted() {\n                self.config_file = Some(p);\n                self.trust()?;\n            }\n            Ok(())\n        } else {\n            self.trust()\n        }\n    }\n    pub fn clean() -> Result<()> {\n        if dirs::TRUSTED_CONFIGS.is_dir() {\n            for path in file::ls(&dirs::TRUSTED_CONFIGS)? {\n                if !path.exists() {\n                    remove_file(&path)?;\n                }\n            }\n        }\n        if dirs::IGNORED_CONFIGS.is_dir() {\n            for path in file::ls(&dirs::IGNORED_CONFIGS)? {\n                if !path.exists() {\n                    remove_file(&path)?;\n                }\n            }\n        }\n        Ok(())\n    }\n    fn untrust(&self) -> Result<()> {\n        let path = match self.config_file() {\n            Some(filename) => filename,\n            None => match self.get_next() {\n                Some(path) => path,\n                None => {\n                    warn!(\"No trusted config files found.\");\n                    return Ok(());\n                }\n            },\n        };\n        let cfr = config_trust_root(&path);\n        config_file::untrust(&cfr)?;\n        let cfr = cfr.canonicalize()?;\n        info!(\"untrusted {}\", cfr.display());\n\n        let trusted_via_settings = Settings::get()\n            .trusted_config_paths()\n            .any(|p| cfr.starts_with(p));\n        if trusted_via_settings {\n            warn!(\"{cfr:?} is trusted via settings so it will still be trusted.\");\n        }\n\n        Ok(())\n    }\n    fn ignore(&self) -> Result<()> {\n        let path = match self.config_file() {\n            Some(filename) => filename,\n            None => match self.get_next() {\n                Some(path) => path,\n                None => {\n                    warn!(\"No trusted config files found.\");\n                    return Ok(());\n                }\n            },\n        };\n        let cfr = config_trust_root(&path);\n        config_file::add_ignored(cfr.clone())?;\n        let cfr = cfr.canonicalize()?;\n        info!(\"ignored {}\", cfr.display());\n\n        let trusted_via_settings = Settings::get()\n            .trusted_config_paths()\n            .any(|p| cfr.starts_with(p));\n        if trusted_via_settings {\n            warn!(\"{cfr:?} is trusted via settings so it will still be trusted.\");\n        }\n        Ok(())\n    }\n    fn trust(&self) -> Result<()> {\n        let path = match self.config_file() {\n            Some(filename) => config_trust_root(&filename),\n            None => match self.get_next_untrusted() {\n                Some(path) => path,\n                None => {\n                    warn!(\"No untrusted config files found.\");\n                    return Ok(());\n                }\n            },\n        };\n        config_file::trust(&path)?;\n        let cfr = path.canonicalize()?;\n        info!(\"trusted {}\", cfr.display());\n        Ok(())\n    }\n\n    fn config_file(&self) -> Option<PathBuf> {\n        self.config_file.as_ref().map(|config_file| {\n            if config_file.is_dir() {\n                config_files_in_dir(config_file)\n                    .last()\n                    .cloned()\n                    .unwrap_or(config_file.join(&*env::MISE_DEFAULT_CONFIG_FILENAME))\n            } else {\n                config_file.clone()\n            }\n        })\n    }\n\n    fn get_next(&self) -> Option<PathBuf> {\n        ALL_CONFIG_FILES.first().cloned()\n    }\n    fn get_next_untrusted(&self) -> Option<PathBuf> {\n        config::load_config_paths(&DEFAULT_CONFIG_FILENAMES, true)\n            .into_iter()\n            .filter(|p| !is_global_config(p))\n            .map(|p| config_trust_root(&p))\n            .unique()\n            .find(|ctr| !config_file::is_trusted(ctr))\n    }\n\n    fn show(&self) -> Result<()> {\n        let trusted = config::load_config_paths(&DEFAULT_CONFIG_FILENAMES, true)\n            .into_iter()\n            .filter(|p| !is_global_config(p))\n            .map(|p| config_trust_root(&p))\n            .unique()\n            .map(|p| (display_path(&p), config_file::is_trusted(&p)))\n            .rev()\n            .collect::<Vec<_>>();\n        if trusted.is_empty() {\n            info!(\"No trusted config files found.\");\n        }\n        for (dp, trusted) in trusted {\n            if trusted {\n                miseprintln!(\"{dp}: trusted\");\n            } else {\n                miseprintln!(\"{dp}: untrusted\");\n            }\n        }\n        Ok(())\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # trusts ~/some_dir/mise.toml\n    $ <bold>mise trust ~/some_dir/mise.toml</bold>\n\n    # trusts mise.toml in the current or parent directory\n    $ <bold>mise trust</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/uninstall.rs",
    "content": "use std::sync::Arc;\n\nuse console::style;\nuse eyre::{Result, bail, eyre};\nuse itertools::Itertools;\n\nuse crate::backend::Backend;\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::toolset::{ToolRequest, ToolSource, ToolVersion, ToolsetBuilder};\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::{config, dirs, exit, file};\n\n/// Removes installed tool versions\n///\n/// This only removes the installed version, it does not modify mise.toml.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Uninstall {\n    /// Tool(s) to remove\n    #[clap(value_name = \"INSTALLED_TOOL@VERSION\", required_unless_present = \"all\")]\n    installed_tool: Vec<ToolArg>,\n\n    /// Delete all installed versions\n    #[clap(long, short)]\n    all: bool,\n\n    /// Do not actually delete anything\n    #[clap(long, short = 'n')]\n    dry_run: bool,\n\n    /// Like --dry-run but exits with code 1 if there are tools to uninstall\n    ///\n    /// This is useful for scripts to check if tools need to be uninstalled.\n    #[clap(long, verbatim_doc_comment)]\n    dry_run_code: bool,\n}\n\nimpl Uninstall {\n    fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let tool_versions = if self.installed_tool.is_empty() && self.all {\n            self.get_all_tool_versions(&config).await?\n        } else {\n            self.get_requested_tool_versions(&config).await?\n        };\n        let tool_versions = tool_versions\n            .into_iter()\n            .unique_by(|(_, tv)| (tv.request.ba().short.clone(), tv.version.clone()))\n            .collect::<Vec<_>>();\n        if !self.all && tool_versions.len() > self.installed_tool.len() {\n            bail!(\"multiple tools specified, use --all to uninstall all versions\");\n        }\n\n        let mpr = MultiProgressReport::get();\n        let mut has_work = false;\n        for (plugin, tv) in tool_versions {\n            if !plugin.is_version_installed(&config, &tv, true) {\n                warn!(\"{} is not installed\", tv.style());\n                continue;\n            }\n\n            has_work = true;\n            let pr = mpr.add(&tv.style());\n            if let Err(err) = plugin\n                .uninstall_version(&config, &tv, pr.as_ref(), self.is_dry_run())\n                .await\n            {\n                error!(\"{err}\");\n                return Err(eyre!(err).wrap_err(format!(\"failed to uninstall {tv}\")));\n            }\n            if self.is_dry_run() {\n                pr.finish_with_message(\"uninstalled (dry-run)\".into());\n            } else {\n                pr.finish_with_message(\"uninstalled\".into());\n            }\n        }\n\n        if self.is_dry_run() {\n            if self.dry_run_code && has_work {\n                exit::exit(1);\n            }\n            return Ok(());\n        }\n\n        file::touch_dir(&dirs::DATA)?;\n        let config = Config::reset().await?;\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n\n        Ok(())\n    }\n\n    async fn get_all_tool_versions(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<(Arc<dyn Backend>, ToolVersion)>> {\n        let ts = ToolsetBuilder::new().build(config).await?;\n        let tool_versions = ts\n            .list_installed_versions(config)\n            .await?\n            .into_iter()\n            .collect::<Vec<_>>();\n        Ok(tool_versions)\n    }\n    async fn get_requested_tool_versions(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<(Arc<dyn Backend>, ToolVersion)>> {\n        let runtimes = ToolArg::double_tool_condition(&self.installed_tool)?;\n        let mut tool_versions = Vec::new();\n        for ta in runtimes {\n            let backend = ta.ba.backend()?;\n            let query = ta.tvr.as_ref().map(|tvr| tvr.version()).unwrap_or_default();\n            let installed_versions = backend.list_installed_versions();\n            let exact_match = installed_versions.iter().find(|v| v == &&query);\n            let matches = match exact_match {\n                Some(m) => vec![m],\n                None => installed_versions\n                    .iter()\n                    .filter(|v| v.starts_with(&query))\n                    .collect_vec(),\n            };\n            let mut tvs = matches\n                .into_iter()\n                .map(|v| {\n                    let tvr = ToolRequest::new(backend.ba().clone(), v, ToolSource::Unknown)?;\n                    let tv = ToolVersion::new(tvr, v.into());\n                    Ok((backend.clone(), tv))\n                })\n                .collect::<Result<Vec<_>>>()?;\n            if let Some(tvr) = &ta.tvr {\n                tvs.push((\n                    backend.clone(),\n                    tvr.resolve(config, &Default::default()).await?,\n                ));\n            }\n            if tvs.is_empty() {\n                warn!(\n                    \"no versions found for {}\",\n                    style(&backend).blue().for_stderr()\n                );\n            }\n            tool_versions.extend(tvs);\n        }\n        Ok(tool_versions)\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # will uninstall specific version\n    $ <bold>mise uninstall node@18.0.0</bold>\n\n    # will uninstall the current node version (if only one version is installed)\n    $ <bold>mise uninstall node</bold>\n\n    # will uninstall all installed versions of node\n    $ <bold>mise uninstall --all node@18.0.0</bold> # will uninstall all node versions\n\"#\n);\n"
  },
  {
    "path": "src/cli/unset.rs",
    "content": "use std::path::PathBuf;\n\nuse eyre::Result;\n\nuse crate::config::config_file::ConfigFile;\nuse crate::config::config_file::mise_toml::MiseToml;\nuse crate::{config, env};\n\n/// Remove environment variable(s) from the config file.\n///\n/// By default, this command modifies `mise.toml` in the current directory.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Unset {\n    /// Environment variable(s) to remove\n    /// e.g.: NODE_ENV\n    #[clap(verbatim_doc_comment, value_name = \"ENV_KEY\")]\n    keys: Vec<String>,\n\n    /// Specify a file to use instead of `mise.toml`\n    #[clap(short, long, value_hint = clap::ValueHint::FilePath)]\n    file: Option<PathBuf>,\n\n    /// Use the global config file\n    #[clap(short, long, overrides_with = \"file\")]\n    global: bool,\n}\n\nconst AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Remove NODE_ENV from the current directory's config\n    $ <bold>mise unset NODE_ENV</bold>\n\n    # Remove NODE_ENV from the global config\n    $ <bold>mise unset NODE_ENV -g</bold>\n\"#\n);\n\nimpl Unset {\n    pub async fn run(self) -> Result<()> {\n        let filename = if let Some(file) = &self.file {\n            file.clone()\n        } else if self.global {\n            config::global_config_path()\n        } else {\n            config::top_toml_config().unwrap_or(env::MISE_DEFAULT_CONFIG_FILENAME.clone().into())\n        };\n\n        let mut config = MiseToml::from_file(&filename).unwrap_or_default();\n\n        for name in self.keys.iter() {\n            config.remove_env(name)?;\n        }\n\n        config.save()\n    }\n}\n"
  },
  {
    "path": "src/cli/unuse.rs",
    "content": "use std::{path::PathBuf, sync::Arc};\n\nuse crate::cli::args::ToolArg;\nuse crate::cli::prune::prune;\nuse crate::config::config_file::ConfigFile;\nuse crate::config::{Config, config_file};\nuse crate::file::display_path;\nuse crate::{config, env};\nuse eyre::Result;\nuse itertools::Itertools;\nuse path_absolutize::Absolutize;\n\n/// Removes installed tool versions from mise.toml\n///\n/// By default, this will use the `mise.toml` file that has the tool defined.\n/// If multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\n/// the lowest precedence file (`mise.toml`) will be used.\n/// See https://mise.jdx.dev/configuration.html#target-file-for-write-operations\n///\n/// In the following order:\n///   - If `--global` is set, it will use the global config file.\n///   - If `--path` is set, it will use the config file at the given path.\n///   - If `--env` is set, it will use `mise.<env>.toml`.\n///   - If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n///   - If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n///   - Otherwise just \"mise.toml\" or global config if cwd is home directory.\n///\n/// Will also prune the installed version if no other configurations are using it.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_aliases = [\"rm\", \"remove\"], after_long_help = AFTER_LONG_HELP)]\npub struct Unuse {\n    /// Tool(s) to remove\n    #[clap(value_name = \"INSTALLED_TOOL@VERSION\", required = true)]\n    installed_tool: Vec<ToolArg>,\n\n    /// Create/modify an environment-specific config file like .mise.<env>.toml\n    #[clap(long, short, overrides_with_all = & [\"global\", \"path\"])]\n    env: Option<String>,\n\n    /// Use the global config file (`~/.config/mise/config.toml`) instead of the local one\n    #[clap(short, long, overrides_with_all = & [\"path\", \"env\"])]\n    global: bool,\n\n    /// Specify a path to a config file or directory\n    ///\n    /// If a directory is specified, it will look for a config file in that directory following\n    /// the rules above.\n    #[clap(short, long, overrides_with_all = & [\"global\", \"env\"], value_hint = clap::ValueHint::FilePath)]\n    path: Option<PathBuf>,\n\n    /// Do not also prune the installed version\n    #[clap(long)]\n    no_prune: bool,\n}\n\nimpl Unuse {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let cf = self.get_config_file(&config).await?;\n        let tools = cf.to_tool_request_set()?.tools;\n        let mut removed: Vec<&ToolArg> = vec![];\n        for ta in &self.installed_tool {\n            if let Some(tool_requests) = tools.get(ta.ba.as_ref()) {\n                let should_remove = if let Some(v) = &ta.version {\n                    tool_requests.iter().any(|tv| &tv.version() == v)\n                } else {\n                    true\n                };\n                // TODO: this won't work properly for unusing a specific version in of multiple in a config\n                if should_remove {\n                    removed.push(ta);\n                    cf.remove_tool(&ta.ba)?;\n                }\n            }\n        }\n        if removed.is_empty() {\n            debug!(\"no tools to remove\");\n        } else {\n            cf.save()?;\n            let removals = removed.iter().join(\", \");\n            info!(\"removed: {removals} from {}\", display_path(cf.get_path()));\n        }\n\n        if !self.no_prune {\n            prune(\n                &config,\n                self.installed_tool\n                    .iter()\n                    .map(|ta| ta.ba.as_ref())\n                    .collect(),\n                false,\n            )\n            .await?;\n            let config = Config::reset().await?;\n            let ts = config.get_toolset().await?;\n            config::rebuild_shims_and_runtime_symlinks(&config, ts, &[]).await?;\n        }\n\n        Ok(())\n    }\n\n    async fn get_config_file(&self, config: &Config) -> Result<Arc<dyn ConfigFile>> {\n        let cwd = env::current_dir()?;\n        let path = if self.global {\n            config::global_config_path()\n        } else if let Some(p) = &self.path {\n            let from_dir = config::config_file_from_dir(p).absolutize()?.to_path_buf();\n            if from_dir.starts_with(&cwd) {\n                from_dir\n            } else {\n                p.clone()\n            }\n        } else if let Some(env) = &self.env {\n            let p = cwd.join(format!(\".mise.{env}.toml\"));\n            if p.exists() {\n                p\n            } else {\n                cwd.join(format!(\"mise.{env}.toml\"))\n            }\n        } else if env::in_home_dir() {\n            config::global_config_path()\n        } else {\n            for cf in config.config_files.values() {\n                if cf\n                    .to_tool_request_set()?\n                    .tools\n                    .keys()\n                    .any(|ba| self.installed_tool.iter().any(|ta| &ta.ba == ba))\n                {\n                    return config_file::parse(cf.get_path()).await;\n                }\n            }\n            config::local_toml_config_path()\n        };\n        config_file::parse_or_init(&path).await\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # will uninstall specific version\n    $ <bold>mise unuse node@18.0.0</bold>\n\n    # will uninstall specific version from global config\n    $ <bold>mise unuse -g node@18.0.0</bold>\n\n    # will uninstall specific version from .mise.local.toml\n    $ <bold>mise unuse --env local node@20</bold>\n\n    # will uninstall specific version from .mise.staging.toml\n    $ <bold>mise unuse --env staging node@20</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/upgrade.rs",
    "content": "use std::sync::Arc;\n\nuse crate::backend::pipx::PIPXBackend;\nuse crate::cli::args::ToolArg;\nuse crate::config::{Config, Settings, config_file};\nuse crate::duration::parse_into_timestamp;\nuse crate::file::display_path;\nuse crate::toolset::outdated_info::OutdatedInfo;\nuse crate::toolset::{\n    ConfigScope, InstallOptions, ResolveOptions, ToolVersion, ToolsetBuilder,\n    get_versions_needed_by_tracked_configs,\n};\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{config, exit, runtime_symlinks, ui};\nuse console::Term;\nuse demand::DemandOption;\nuse eyre::{Context, Result, eyre};\nuse jiff::Timestamp;\n\n/// Upgrades outdated tools\n///\n/// By default, this keeps the range specified in mise.toml. So if you have node@20 set, it will\n/// upgrade to the latest 20.x.x version available. See the `--bump` flag to use the latest version\n/// and bump the version in mise.toml.\n///\n/// This will update mise.lock if it is enabled, see https://mise.jdx.dev/configuration/settings.html#lockfile\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"up\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Upgrade {\n    /// Tool(s) to upgrade\n    /// e.g.: node@20 python@3.10\n    /// If not specified, all current tools will be upgraded\n    #[clap(value_name = \"INSTALLED_TOOL@VERSION\", verbatim_doc_comment)]\n    tool: Vec<ToolArg>,\n\n    /// Display multiselect menu to choose which tools to upgrade\n    #[clap(long, short, verbatim_doc_comment, conflicts_with = \"tool\")]\n    interactive: bool,\n\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    jobs: Option<usize>,\n\n    /// Upgrades to the latest version available, bumping the version in mise.toml\n    ///\n    /// For example, if you have `node = \"20.0.0\"` in your mise.toml but 22.1.0 is the latest available,\n    /// this will install 22.1.0 and set `node = \"22.1.0\"` in your config.\n    ///\n    /// It keeps the same precision as what was there before, so if you instead had `node = \"20\"`, it\n    /// would change your config to `node = \"22\"`.\n    #[clap(long, short = 'l', verbatim_doc_comment)]\n    bump: bool,\n\n    /// Just print what would be done, don't actually do it\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    dry_run: bool,\n\n    /// Tool(s) to exclude from upgrading\n    /// e.g.: go python\n    #[clap(long, short = 'x', value_name = \"INSTALLED_TOOL\", verbatim_doc_comment)]\n    exclude: Vec<ToolArg>,\n\n    /// Only upgrade to versions released before this date\n    ///\n    /// Supports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\n    /// This can be useful for reproducibility or security purposes.\n    ///\n    /// This only affects fuzzy version matches like \"20\" or \"latest\".\n    /// Explicitly pinned versions like \"22.5.0\" are not filtered.\n    #[clap(long, verbatim_doc_comment)]\n    before: Option<String>,\n\n    /// Like --dry-run but exits with code 1 if there are outdated tools\n    ///\n    /// This is useful for scripts to check if tools need to be upgraded.\n    #[clap(long, verbatim_doc_comment)]\n    dry_run_code: bool,\n\n    /// Only upgrade tools defined in local config files\n    ///\n    /// This will only upgrade tools that are defined in project-local mise.toml and\n    /// will skip tools defined in the global config (~/.config/mise/config.toml).\n    #[clap(long, verbatim_doc_comment)]\n    local: bool,\n\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets --jobs=1\n    #[clap(long, overrides_with = \"jobs\")]\n    raw: bool,\n}\n\nimpl Upgrade {\n    fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    fn scope(&self) -> ConfigScope {\n        if self.local {\n            ConfigScope::LocalOnly\n        } else {\n            ConfigScope::All\n        }\n    }\n\n    pub async fn run(self) -> Result<()> {\n        let mut config = Config::get().await?;\n        let ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .with_scope(self.scope())\n            .build(&config)\n            .await?;\n        // Compute before_date once to ensure consistency when using relative durations\n        let before_date = self.get_before_date()?;\n        let opts = ResolveOptions {\n            use_locked_version: false,\n            latest_versions: true,\n            before_date,\n        };\n        // Filter tools to check before doing expensive version lookups\n        let filter_tools = if !self.interactive && !self.tool.is_empty() {\n            Some(self.tool.as_slice())\n        } else {\n            None\n        };\n        let exclude_tools = if !self.exclude.is_empty() {\n            Some(self.exclude.as_slice())\n        } else {\n            None\n        };\n        let mut outdated = ts\n            .list_outdated_versions_filtered(&config, self.bump, &opts, filter_tools, exclude_tools)\n            .await;\n        if self.interactive && !outdated.is_empty() {\n            outdated = self.get_interactive_tool_set(&outdated)?;\n        }\n        if outdated.is_empty() {\n            info!(\"All tools are up to date\");\n            if !self.bump {\n                hint!(\n                    \"outdated_bump\",\n                    r#\"By default, `mise upgrade` only upgrades versions that match your config. Use `mise upgrade --bump` to upgrade all new versions.\"#,\n                    \"\"\n                );\n            }\n        } else {\n            self.upgrade(&mut config, outdated, before_date).await?;\n        }\n\n        Ok(())\n    }\n\n    async fn upgrade(\n        &self,\n        config: &mut Arc<Config>,\n        outdated: Vec<OutdatedInfo>,\n        before_date: Option<Timestamp>,\n    ) -> Result<()> {\n        let mpr = MultiProgressReport::get();\n        let mut ts = ToolsetBuilder::new()\n            .with_args(&self.tool)\n            .with_scope(self.scope())\n            .build(config)\n            .await?;\n\n        let mut outdated_with_config_files: Vec<(&OutdatedInfo, Arc<dyn config_file::ConfigFile>)> =\n            vec![];\n        for o in outdated.iter() {\n            if let (Some(path), Some(_bump)) = (o.source.path(), &o.bump) {\n                match config_file::parse(path).await {\n                    Ok(cf) => outdated_with_config_files.push((o, cf)),\n                    Err(e) => warn!(\"failed to parse {}: {e}\", display_path(path)),\n                }\n            }\n        }\n        let config_file_updates = outdated_with_config_files\n            .iter()\n            .filter(|(o, cf)| {\n                if let Ok(trs) = cf.to_tool_request_set()\n                    && let Some(versions) = trs.tools.get(o.tool_request.ba())\n                    && versions.len() != 1\n                {\n                    warn!(\"upgrading multiple versions with --bump is not yet supported\");\n                    return false;\n                }\n                true\n            })\n            .collect::<Vec<_>>();\n\n        // Determine which old versions should be uninstalled after upgrade\n        // Skip uninstall when current == latest (channel-based versions that update in-place)\n        let to_remove: Vec<_> = outdated\n            .iter()\n            .filter_map(|o| {\n                o.current.as_ref().and_then(|current| {\n                    // Skip if current and latest version strings are identical\n                    // This handles channels like \"nightly\", \"stable\", \"beta\" that update in-place\n                    if &o.latest == current {\n                        return None;\n                    }\n                    Some((o, current.clone()))\n                })\n            })\n            .collect();\n\n        if self.is_dry_run() {\n            for (o, current) in &to_remove {\n                miseprintln!(\"Would uninstall {}@{}\", o.name, current);\n            }\n            for o in &outdated {\n                miseprintln!(\"Would install {}@{}\", o.name, o.latest);\n            }\n            for (o, cf) in &config_file_updates {\n                miseprintln!(\n                    \"Would bump {}@{} in {}\",\n                    o.name,\n                    o.tool_request.version(),\n                    display_path(cf.get_path())\n                );\n            }\n            if self.dry_run_code {\n                exit::exit(1);\n            }\n            return Ok(());\n        }\n\n        let opts = InstallOptions {\n            reason: \"upgrade\".to_string(),\n            force: false,\n            jobs: self.jobs,\n            raw: self.raw,\n            resolve_options: ResolveOptions {\n                use_locked_version: false,\n                latest_versions: true,\n                before_date,\n            },\n            ..Default::default()\n        };\n\n        // Collect all tool requests for parallel installation\n        let tool_requests: Vec<_> = outdated.iter().map(|o| o.tool_request.clone()).collect();\n\n        // Install all tools in parallel\n        let (successful_versions, install_error) =\n            match ts.install_all_versions(config, tool_requests, &opts).await {\n                Ok(versions) => (versions, eyre::Result::Ok(())),\n                Err(e) => match e.downcast_ref::<crate::errors::Error>() {\n                    Some(crate::errors::Error::InstallFailed {\n                        successful_installations,\n                        ..\n                    }) => (successful_installations.clone(), eyre::Result::Err(e)),\n                    _ => (vec![], eyre::Result::Err(e)),\n                },\n            };\n\n        // Only update config files for tools that were successfully installed\n        for (o, cf) in config_file_updates {\n            if successful_versions\n                .iter()\n                .any(|v| v.ba() == o.tool_version.ba())\n            {\n                if let Err(e) =\n                    cf.replace_versions(o.tool_request.ba(), vec![o.tool_request.clone()])\n                {\n                    return Err(eyre!(\"Failed to update config for {}: {}\", o.name, e));\n                }\n\n                if let Err(e) = cf.save() {\n                    return Err(eyre!(\"Failed to save config for {}: {}\", o.name, e));\n                }\n            }\n        }\n\n        // Reset config after upgrades so tracked configs resolve with new versions\n        *config = Config::reset().await?;\n\n        // Rebuild symlinks BEFORE getting versions needed by tracked configs\n        // This ensures \"latest\" symlinks point to the new versions, not the old ones\n        runtime_symlinks::rebuild(config)\n            .await\n            .wrap_err(\"failed to rebuild runtime symlinks\")?;\n\n        // Get versions needed by tracked configs AFTER upgrade\n        // This ensures we don't uninstall versions still needed by other projects\n        let versions_needed_by_tracked = get_versions_needed_by_tracked_configs(config).await?;\n\n        // Only uninstall old versions of tools that were successfully upgraded\n        // and are not needed by any tracked config\n        for (o, tv) in to_remove {\n            if successful_versions\n                .iter()\n                .any(|v| v.ba() == o.tool_version.ba())\n            {\n                // Check if this version is still needed by another tracked config\n                let version_key = (\n                    o.tool_version.ba().short.to_string(),\n                    o.tool_version.tv_pathname(),\n                );\n                if versions_needed_by_tracked.contains(&version_key) {\n                    debug!(\n                        \"Keeping {}@{} because it's still needed by a tracked config\",\n                        o.name, tv\n                    );\n                    continue;\n                }\n\n                let pr = mpr.add(&format!(\"uninstall {}@{}\", o.name, tv));\n                if let Err(e) = self\n                    .uninstall_old_version(config, &o.tool_version, pr.as_ref())\n                    .await\n                {\n                    warn!(\"Failed to uninstall old version of {}: {}\", o.name, e);\n                }\n            }\n        }\n\n        let ts = config.get_toolset().await?;\n        config::rebuild_shims_and_runtime_symlinks(config, ts, &successful_versions).await?;\n\n        if successful_versions.iter().any(|v| v.short() == \"python\") {\n            PIPXBackend::reinstall_all(config)\n                .await\n                .unwrap_or_else(|err| {\n                    warn!(\"failed to reinstall pipx tools: {err}\");\n                });\n        }\n\n        Self::print_summary(&outdated, &successful_versions)?;\n\n        install_error\n    }\n\n    async fn uninstall_old_version(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        tv.backend()?\n            .uninstall_version(config, tv, pr, self.dry_run)\n            .await\n            .wrap_err_with(|| format!(\"failed to uninstall {tv}\"))?;\n        pr.finish();\n        Ok(())\n    }\n\n    fn print_summary(outdated: &[OutdatedInfo], successful_versions: &[ToolVersion]) -> Result<()> {\n        let upgraded: Vec<_> = outdated\n            .iter()\n            .filter(|o| {\n                successful_versions\n                    .iter()\n                    .any(|v| v.ba() == o.tool_version.ba() && v.version == o.latest)\n            })\n            .collect();\n        if !upgraded.is_empty() {\n            let s = if upgraded.len() == 1 { \"\" } else { \"s\" };\n            miseprintln!(\"\\nUpgraded {} tool{}:\", upgraded.len(), s);\n            for o in &upgraded {\n                let from = o.current.as_deref().unwrap_or(\"(none)\");\n                miseprintln!(\"  {} {} → {}\", o.name, from, o.latest);\n            }\n        }\n        Ok(())\n    }\n\n    fn get_interactive_tool_set(&self, outdated: &Vec<OutdatedInfo>) -> Result<Vec<OutdatedInfo>> {\n        ui::ctrlc::show_cursor_after_ctrl_c();\n        let theme = crate::ui::theme::get_theme();\n        let mut ms = demand::MultiSelect::new(\"mise upgrade\")\n            .description(\"Select tools to upgrade\")\n            .filterable(true)\n            .theme(&theme);\n        for out in outdated {\n            ms = ms.option(DemandOption::new(out.clone()));\n        }\n        match ms.run() {\n            Ok(selected) => Ok(selected.into_iter().collect()),\n            Err(e) => {\n                Term::stderr().show_cursor()?;\n                Err(eyre!(e))\n            }\n        }\n    }\n\n    /// Get the before_date from CLI flag or settings\n    fn get_before_date(&self) -> Result<Option<Timestamp>> {\n        // CLI flag takes precedence over settings\n        if let Some(before) = &self.before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        // Fall back to settings\n        if let Some(before) = &Settings::get().install_before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        Ok(None)\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Upgrades node to the latest version matching the range in mise.toml\n    $ <bold>mise upgrade node</bold>\n\n    # Upgrades node to the latest version and bumps the version in mise.toml\n    $ <bold>mise upgrade node --bump</bold>\n\n    # Upgrades all tools to the latest versions\n    $ <bold>mise upgrade</bold>\n\n    # Upgrades all tools to the latest versions and bumps the version in mise.toml\n    $ <bold>mise upgrade --bump</bold>\n\n    # Just print what would be done, don't actually do it\n    $ <bold>mise upgrade --dry-run</bold>\n\n    # Upgrades node and python to the latest versions\n    $ <bold>mise upgrade node python</bold>\n\n    # Upgrade all tools except go\n    $ <bold>mise upgrade --exclude go</bold>\n\n    # Show a multiselect menu to choose which tools to upgrade\n    $ <bold>mise upgrade --interactive</bold>\n\n    # Only upgrade tools defined in local mise.toml, not global ones\n    $ <bold>mise upgrade --local</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/usage.rs",
    "content": "use crate::cli::Cli;\nuse clap::CommandFactory;\nuse clap::builder::Resettable;\nuse eyre::Result;\n\n/// Generate a usage CLI spec\n///\n/// See https://usage.jdx.dev for more information on this specification.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, hide = true)]\npub struct Usage {}\n\nimpl Usage {\n    pub fn run(self) -> Result<()> {\n        let cli = Cli::command().version(Resettable::Reset);\n        let mut spec: usage::Spec = cli.into();\n\n        // Enable \"naked\" task completions: `mise foo` completes like `mise run foo`\n        spec.default_subcommand = Some(\"run\".to_string());\n\n        let run = spec.cmd.subcommands.get_mut(\"run\").unwrap();\n        run.args = vec![];\n        run.mounts.push(usage::SpecMount {\n            run: \"mise tasks --usage\".to_string(),\n        });\n        // Enable completions after ::: separator for multi-task invocations\n        run.restart_token = Some(\":::\".to_string());\n\n        let tasks = spec.cmd.subcommands.get_mut(\"tasks\").unwrap();\n        let tasks_run = tasks.subcommands.get_mut(\"run\").unwrap();\n        tasks_run.mounts.push(usage::SpecMount {\n            run: \"mise tasks --usage\".to_string(),\n        });\n        tasks_run.restart_token = Some(\":::\".to_string());\n\n        let min_version = r#\"min_usage_version \"2.11\"\"#;\n        let extra = include_str!(\"../assets/mise-extra.usage.kdl\").trim();\n        println!(\"{min_version}\\n{}\\n{extra}\", spec.to_string().trim());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/cli/use.rs",
    "content": "use std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse console::{Term, style};\nuse eyre::{Result, bail, eyre};\nuse itertools::Itertools;\nuse jiff::Timestamp;\nuse path_absolutize::Absolutize;\n\nuse crate::cli::args::{BackendArg, ToolArg};\nuse crate::config::config_file::ConfigFile;\nuse crate::config::{Config, ConfigPathOptions, Settings, config_file, resolve_target_config_path};\nuse crate::duration::parse_into_timestamp;\nuse crate::file::display_path;\nuse crate::registry::REGISTRY;\nuse crate::toolset::{\n    ConfigScope, InstallOptions, ResolveOptions, ToolRequest, ToolSource, ToolVersion,\n    ToolsetBuilder,\n};\nuse crate::ui::ctrlc;\nuse crate::{config, env, exit, file};\n\n/// Installs a tool and adds the version to mise.toml.\n///\n/// This will install the tool version if it is not already installed.\n/// By default, this will use a `mise.toml` file in the current directory.\n/// If multiple config files exist (e.g., both `mise.toml` and `mise.local.toml`),\n/// the lowest precedence file (`mise.toml`) will be used.\n/// See https://mise.jdx.dev/configuration.html#target-file-for-write-operations\n///\n/// In the following order:\n///   - If `--global` is set, it will use the global config file.\n///   - If `--path` is set, it will use the config file at the given path.\n///   - If `--env` is set, it will use `mise.<env>.toml`.\n///   - If `MISE_DEFAULT_CONFIG_FILENAME` is set, it will use that instead.\n///   - If `MISE_OVERRIDE_CONFIG_FILENAMES` is set, it will the first from that list.\n///   - Otherwise just \"mise.toml\" or global config if cwd is home directory.\n///\n/// Use the `--global` flag to use the global config file instead.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"u\", after_long_help = AFTER_LONG_HELP)]\npub struct Use {\n    /// Tool(s) to add to config file\n    ///\n    /// e.g.: node@20, cargo:ripgrep@latest npm:prettier@3\n    /// If no version is specified, it will default to @latest\n    ///\n    /// Tool options can be set with this syntax:\n    ///\n    ///     mise use ubi:BurntSushi/ripgrep[exe=rg]\n    #[clap(value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    tool: Vec<ToolArg>,\n\n    /// Create/modify an environment-specific config file like .mise.<env>.toml\n    #[clap(long, short, overrides_with_all = & [\"global\", \"path\"])]\n    env: Option<String>,\n\n    /// Force reinstall even if already installed\n    #[clap(long, short, requires = \"tool\")]\n    force: bool,\n\n    /// Use the global config file (`~/.config/mise/config.toml`) instead of the local one\n    #[clap(short, long, overrides_with_all = & [\"path\", \"env\"])]\n    global: bool,\n\n    /// Number of jobs to run in parallel\n    /// [default: 4]\n    #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    jobs: Option<usize>,\n\n    /// Perform a dry run, showing what would be installed and modified without making changes\n    #[clap(long, short = 'n', verbatim_doc_comment)]\n    dry_run: bool,\n\n    /// Specify a path to a config file or directory\n    ///\n    /// If a directory is specified, it will look for a config file in that directory following\n    /// the rules above.\n    #[clap(short, long, overrides_with_all = & [\"global\", \"env\"], value_hint = clap::ValueHint::FilePath)]\n    path: Option<PathBuf>,\n\n    /// Only install versions released before this date\n    ///\n    /// Supports absolute dates like \"2024-06-01\" and relative durations like \"90d\" or \"1y\".\n    #[clap(long, verbatim_doc_comment)]\n    before: Option<String>,\n\n    /// Like --dry-run but exits with code 1 if there are changes to make\n    ///\n    /// This is useful for scripts to check if tools need to be added or removed.\n    #[clap(long, verbatim_doc_comment)]\n    dry_run_code: bool,\n\n    /// Save fuzzy version to config file\n    ///\n    /// e.g.: `mise use --fuzzy node@20` will save 20 as the version\n    /// this is the default behavior unless `MISE_PIN=1`\n    #[clap(long, verbatim_doc_comment, overrides_with = \"pin\")]\n    fuzzy: bool,\n\n    /// Save exact version to config file\n    /// e.g.: `mise use --pin node@20` will save 20.0.0 as the version\n    /// Set `MISE_PIN=1` to make this the default behavior\n    ///\n    /// Consider using mise.lock as a better alternative to pinning in mise.toml:\n    /// https://mise.jdx.dev/configuration/settings.html#lockfile\n    #[clap(long, verbatim_doc_comment, overrides_with = \"fuzzy\")]\n    pin: bool,\n\n    /// Directly pipe stdin/stdout/stderr from plugin to user\n    /// Sets `--jobs=1`\n    #[clap(long, overrides_with = \"jobs\")]\n    raw: bool,\n\n    /// Remove the plugin(s) from config file\n    #[clap(long, value_name = \"PLUGIN\", aliases = [\"rm\", \"unset\"])]\n    remove: Vec<BackendArg>,\n}\n\nimpl Use {\n    fn is_dry_run(&self) -> bool {\n        self.dry_run || self.dry_run_code\n    }\n\n    pub async fn run(mut self) -> Result<()> {\n        if self.tool.is_empty() && self.remove.is_empty() {\n            self.tool = vec![self.tool_selector()?];\n        }\n        env::TOOL_ARGS.write().unwrap().clone_from(&self.tool);\n        let mut config = Config::get().await?;\n        let scope = if self.global {\n            ConfigScope::GlobalOnly\n        } else {\n            ConfigScope::All\n        };\n        let mut ts = ToolsetBuilder::new()\n            .with_scope(scope)\n            .build(&config)\n            .await?;\n        let cf = self.get_config_file().await?;\n        let mut resolve_options = ResolveOptions {\n            latest_versions: false,\n            use_locked_version: true,\n            before_date: self.get_before_date()?,\n        };\n        let versions: Vec<_> = self\n            .tool\n            .iter()\n            .cloned()\n            .map(|t| match t.tvr {\n                Some(tvr) => {\n                    if tvr.version() == \"latest\" && !Settings::get().locked {\n                        // user specified `@latest` so we should resolve the latest version\n                        // TODO: this should only happen on this tool, not all of them\n                        resolve_options.latest_versions = true;\n                        resolve_options.use_locked_version = false;\n                    }\n                    Ok(tvr)\n                }\n                None => ToolRequest::new(\n                    t.ba,\n                    \"latest\",\n                    ToolSource::MiseToml(cf.get_path().to_path_buf()),\n                ),\n            })\n            .collect::<Result<_>>()?;\n        let mut versions = ts\n            .install_all_versions(\n                &mut config,\n                versions.clone(),\n                &InstallOptions {\n                    reason: \"use\".to_string(),\n                    force: self.force,\n                    jobs: self.jobs,\n                    raw: self.raw,\n                    dry_run: self.is_dry_run(),\n                    resolve_options,\n                    ..Default::default()\n                },\n            )\n            .await?;\n\n        let pin = self.pin || !self.fuzzy && (Settings::get().pin || Settings::get().asdf_compat);\n\n        for (ba, tvl) in &versions.iter().chunk_by(|tv| tv.ba()) {\n            let versions: Vec<_> = tvl\n                .into_iter()\n                .map(|tv| {\n                    let mut request = tv.request.clone();\n                    if pin\n                        && let ToolRequest::Version {\n                            version: _version,\n                            source,\n                            options,\n                            backend,\n                        } = request\n                    {\n                        request = ToolRequest::Version {\n                            version: tv.version.clone(),\n                            source,\n                            options,\n                            backend,\n                        };\n                    }\n                    request\n                })\n                .collect();\n            cf.replace_versions(ba, versions)?;\n        }\n\n        if self.global {\n            self.warn_if_hidden(&config, cf.get_path()).await;\n        }\n        for plugin_name in &self.remove {\n            cf.remove_tool(plugin_name)?;\n        }\n\n        if !self.is_dry_run() {\n            cf.save()?;\n            for tv in &mut versions {\n                // update the source so the lockfile is updated correctly\n                tv.request.set_source(cf.source());\n            }\n\n            let config = Config::reset().await?;\n            let ts = config.get_toolset().await?;\n            config::rebuild_shims_and_runtime_symlinks(&config, ts, &versions).await?;\n        }\n\n        self.render_success_message(cf.as_ref(), &versions, &self.remove)?;\n        Ok(())\n    }\n\n    async fn get_config_file(&self) -> Result<Arc<dyn ConfigFile>> {\n        let cwd = env::current_dir()?;\n\n        // Handle special case for --path that needs absolutize logic for compatibility\n        let path = if let Some(p) = &self.path {\n            let from_dir = config::config_file_from_dir(p).absolutize()?.to_path_buf();\n            if from_dir.starts_with(&cwd) {\n                from_dir\n            } else {\n                p.clone()\n            }\n        } else {\n            let opts = ConfigPathOptions {\n                global: self.global,\n                path: None, // handled above\n                env: self.env.clone(),\n                cwd: Some(cwd),\n                prefer_toml: false, // mise use supports .tool-versions and other formats\n                prevent_home_local: true, // When in HOME, use global config\n            };\n            resolve_target_config_path(opts)?\n        };\n\n        config_file::parse_or_init(&path).await\n    }\n\n    async fn warn_if_hidden(&self, config: &Arc<Config>, global: &Path) {\n        let ts = ToolsetBuilder::new()\n            .build(config)\n            .await\n            .unwrap_or_default();\n        let warn = |targ: &ToolArg, p| {\n            let plugin = &targ.ba;\n            let p = display_path(p);\n            let global = display_path(global);\n            warn!(\"{plugin} is defined in {p} which overrides the global config ({global})\");\n        };\n        for targ in &self.tool {\n            if let Some(tv) = ts.versions.get(targ.ba.as_ref())\n                && let ToolSource::MiseToml(p) | ToolSource::ToolVersions(p) = &tv.source\n                && !file::same_file(p, global)\n            {\n                warn(targ, p);\n            }\n        }\n    }\n\n    fn render_success_message(\n        &self,\n        cf: &dyn ConfigFile,\n        versions: &[ToolVersion],\n        remove: &[BackendArg],\n    ) -> Result<()> {\n        let path = display_path(cf.get_path());\n\n        if self.is_dry_run() {\n            let mut messages = vec![];\n\n            if !versions.is_empty() {\n                let tools = versions.iter().map(|t| t.style()).join(\", \");\n                messages.push(format!(\"add: {tools}\"));\n            }\n\n            if !remove.is_empty() {\n                let tools_to_remove = remove.iter().map(|r| r.to_string()).join(\", \");\n                messages.push(format!(\"remove: {tools_to_remove}\"));\n            }\n\n            if !messages.is_empty() {\n                miseprintln!(\n                    \"{} would update {} ({})\",\n                    style(\"mise\").green(),\n                    style(&path).cyan().for_stderr(),\n                    messages.join(\", \")\n                );\n                if self.dry_run_code {\n                    exit::exit(1);\n                }\n            }\n        } else {\n            if !versions.is_empty() {\n                let tools = versions.iter().map(|t| t.style()).join(\", \");\n                miseprintln!(\n                    \"{} {} tools: {tools}\",\n                    style(\"mise\").green(),\n                    style(&path).cyan().for_stderr(),\n                );\n            }\n            if !remove.is_empty() {\n                let tools_to_remove = remove.iter().map(|r| r.to_string()).join(\", \");\n                miseprintln!(\n                    \"{} {} removed: {tools_to_remove}\",\n                    style(\"mise\").green(),\n                    style(&path).cyan().for_stderr(),\n                );\n            }\n        }\n        Ok(())\n    }\n\n    fn tool_selector(&self) -> Result<ToolArg> {\n        if !console::user_attended_stderr() {\n            bail!(\"No tool specified and not running interactively\");\n        }\n        let theme = crate::ui::theme::get_theme();\n        let mut s = demand::Select::new(\"Tools\")\n            .description(\"Select a tool to install\")\n            .filtering(true)\n            .filterable(true)\n            .theme(&theme);\n        for rt in REGISTRY.values().unique_by(|r| r.short) {\n            if let Some(backend) = rt.backends().first() {\n                // TODO: populate registry with descriptions from aqua and other sources\n                // TODO: use the backend from the lockfile if available\n                let description = rt.description.unwrap_or(backend);\n                s = s.option(demand::DemandOption::new(rt).description(description));\n            }\n        }\n        ctrlc::show_cursor_after_ctrl_c();\n        match s.run() {\n            Ok(rt) => rt.short.parse(),\n            Err(err) => {\n                Term::stderr().show_cursor()?;\n                Err(eyre!(err))\n            }\n        }\n    }\n\n    /// Get the before_date from CLI flag or settings\n    fn get_before_date(&self) -> Result<Option<Timestamp>> {\n        if let Some(before) = &self.before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        if let Some(before) = &Settings::get().install_before {\n            return Ok(Some(parse_into_timestamp(before)?));\n        }\n        Ok(None)\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n    \n    # run with no arguments to use the interactive selector\n    $ <bold>mise use</bold>\n\n    # set the current version of node to 20.x in mise.toml of current directory\n    # will write the fuzzy version (e.g.: 20)\n    $ <bold>mise use node@20</bold>\n\n    # set the current version of node to 20.x in ~/.config/mise/config.toml\n    # will write the precise version (e.g.: 20.0.0)\n    $ <bold>mise use -g --pin node@20</bold>\n\n    # sets .mise.local.toml (which is intended not to be committed to a project)\n    $ <bold>mise use --env local node@20</bold>\n\n    # sets .mise.staging.toml (which is used if MISE_ENV=staging)\n    $ <bold>mise use --env staging node@20</bold>\n\"#\n);\n"
  },
  {
    "path": "src/cli/version.rs",
    "content": "use std::time::Duration;\n\nuse console::style;\nuse eyre::Result;\nuse std::sync::LazyLock as Lazy;\nuse versions::Versioning;\n\nuse crate::build_time::BUILD_TIME;\nuse crate::cli::self_update::SelfUpdate;\nuse crate::file::modified_duration;\nuse crate::ui::style;\nuse crate::{dirs, duration, env, file};\n\n/// Display the version of mise\n///\n/// Displays the version, os, architecture, and the date of the build.\n///\n/// If the version is out of date, it will display a warning.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, visible_alias = \"v\", after_long_help = AFTER_LONG_HELP)]\npub struct Version {\n    /// Print the version information in JSON format\n    #[clap(short = 'J', long)]\n    json: bool,\n}\n\nimpl Version {\n    pub async fn run(self) -> Result<()> {\n        if self.json {\n            self.json().await?\n        } else {\n            show_version()?;\n            show_latest().await;\n        }\n        Ok(())\n    }\n\n    async fn json(&self) -> Result<()> {\n        let json = serde_json::json!({\n            \"version\": *VERSION,\n            \"latest\": get_latest_version(duration::DAILY).await,\n            \"os\": *OS,\n            \"arch\": *ARCH,\n            \"build_time\": BUILD_TIME.to_string(),\n        });\n        println!(\"{}\", serde_json::to_string_pretty(&json)?);\n        Ok(())\n    }\n}\n\npub static OS: Lazy<String> = Lazy::new(|| env::consts::OS.into());\npub static ARCH: Lazy<String> = Lazy::new(|| {\n    match env::consts::ARCH {\n        \"x86_64\" => \"x64\",\n        \"aarch64\" => \"arm64\",\n        _ => env::consts::ARCH,\n    }\n    .to_string()\n});\n\npub static VERSION_PLAIN: Lazy<String> = Lazy::new(|| {\n    let mut v = V.to_string();\n    if cfg!(debug_assertions) {\n        v.push_str(\"-DEBUG\");\n    };\n    v\n});\n\npub static VERSION: Lazy<String> = Lazy::new(|| {\n    let build_time = BUILD_TIME.format(\"%Y-%m-%d\");\n    let v = &*VERSION_PLAIN;\n    format!(\"{v} {os}-{arch} ({build_time})\", os = *OS, arch = *ARCH)\n});\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise version</bold>\n    $ <bold>mise --version</bold>\n    $ <bold>mise -v</bold>\n    $ <bold>mise -V</bold>\n\"#\n);\n\npub static V: Lazy<Versioning> = Lazy::new(|| Versioning::new(env!(\"CARGO_PKG_VERSION\")).unwrap());\n\npub fn print_version_if_requested(args: &[String]) -> std::io::Result<bool> {\n    if args.len() == 2 && !*crate::env::IS_RUNNING_AS_SHIM {\n        let cmd = &args[1].to_lowercase();\n        if cmd == \"version\" || cmd == \"-v\" || cmd == \"--version\" || cmd == \"v\" {\n            show_version()?;\n            return Ok(true);\n        }\n    }\n    debug!(\"Version: {}\", *VERSION);\n    Ok(false)\n}\n\nfn show_version() -> std::io::Result<()> {\n    if console::user_attended() {\n        let banner = style::nred(\n            r#\"\n              _                                        __              \n   ____ ___  (_)_______        ___  ____        ____  / /___ _________\n  / __ `__ \\/ / ___/ _ \\______/ _ \\/ __ \\______/ __ \\/ / __ `/ ___/ _ \\\n / / / / / / (__  )  __/_____/  __/ / / /_____/ /_/ / / /_/ / /__/  __/\n/_/ /_/ /_/_/____/\\___/      \\___/_/ /_/     / .___/_/\\__,_/\\___/\\___/\n                                            /_/\"#\n                .trim_start_matches(\"\\n\"),\n        );\n        let jdx = style::nbright(\"by @jdx\");\n        miseprintln!(\"{banner}                 {jdx}\");\n    }\n    miseprintln!(\"{}\", *VERSION);\n    Ok(())\n}\n\npub async fn show_latest() {\n    if ci_info::is_ci() && !cfg!(test) {\n        return;\n    }\n    if let Some(latest) = check_for_new_version(duration::DAILY).await {\n        warn!(\"mise version {} available\", latest);\n        if SelfUpdate::is_available() {\n            let cmd = style(\"mise self-update\").bright().yellow().for_stderr();\n            warn!(\"To update, run {}\", cmd);\n        } else if let Some(instructions) = crate::cli::self_update::upgrade_instructions_text() {\n            warn!(\"{}\", instructions);\n        }\n    }\n}\n\npub async fn check_for_new_version(cache_duration: Duration) -> Option<String> {\n    if let Some(latest) = get_latest_version(cache_duration)\n        .await\n        .and_then(Versioning::new)\n        && *V < latest\n    {\n        return Some(latest.to_string());\n    }\n    None\n}\n\nasync fn get_latest_version(duration: Duration) -> Option<String> {\n    let version_file_path = dirs::CACHE.join(\"latest-version\");\n    if let Ok(metadata) = modified_duration(&version_file_path)\n        && metadata < duration\n        && let Some(version) = file::read_to_string(&version_file_path)\n            .ok()\n            .map(|s| s.trim().to_string())\n            .and_then(Versioning::new)\n        && *V <= version\n    {\n        return Some(version.to_string());\n    }\n    let _ = file::create_dir_all(*dirs::CACHE);\n    let version = get_latest_version_call().await;\n    let _ = file::write(version_file_path, version.clone().unwrap_or_default());\n    version\n}\n\n#[cfg(test)]\nasync fn get_latest_version_call() -> Option<String> {\n    Some(\"0.0.0\".to_string())\n}\n\n#[cfg(not(test))]\nasync fn get_latest_version_call() -> Option<String> {\n    let url = \"https://mise.jdx.dev/VERSION\";\n    debug!(\"checking mise version from {}\", url);\n    match crate::http::HTTP_VERSION_CHECK.get_text(url).await {\n        Ok(text) => {\n            debug!(\"got version {text}\");\n            Some(text.trim().to_string())\n        }\n        Err(err) => {\n            debug!(\"failed to check for version: {:#?}\", err);\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "src/cli/watch.rs",
    "content": "use crate::Result;\nuse crate::cli::Cli;\nuse crate::cli::args::BackendArg;\nuse crate::cmd;\nuse crate::config::Config;\nuse crate::env;\nuse crate::exit::exit;\nuse crate::toolset::ToolsetBuilder;\nuse clap::{CommandFactory, ValueEnum, ValueHint};\nuse console::style;\nuse eyre::bail;\nuse itertools::Itertools;\nuse std::cmp::PartialEq;\nuse std::iter::once;\nuse std::path::PathBuf;\n\n/// Run task(s) and watch for changes to rerun it\n///\n/// This command uses the `watchexec` tool to watch for changes to files and rerun the specified task(s).\n/// It must be installed for this command to work, but you can install it with `mise use -g watchexec@latest`.\n///\n/// For more advanced process management (daemon management, auto-restart, readiness checks,\n/// cron scheduling), see mise's sister project: https://pitchfork.jdx.dev\n#[derive(Debug, clap::Args)]\n#[clap(visible_alias = \"w\", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Watch {\n    /// Tasks to run\n    /// Can specify multiple tasks by separating with `:::`\n    /// e.g.: `mise run task1 arg1 arg2 ::: task2 arg1 arg2`\n    #[clap(allow_hyphen_values = true, verbatim_doc_comment)]\n    task: Option<String>,\n\n    /// Tasks to run\n    #[clap(short, long, verbatim_doc_comment, hide = true)]\n    task_flag: Vec<String>,\n\n    /// Task and arguments to run\n    #[clap(allow_hyphen_values = true, trailing_var_arg = true)]\n    args: Vec<String>,\n\n    /// Files to watch\n    /// Defaults to sources from the task(s)\n    #[clap(short, long, verbatim_doc_comment, hide = true)]\n    glob: Vec<String>,\n\n    /// Run only the specified tasks skipping all dependencies\n    #[clap(long, verbatim_doc_comment)]\n    pub skip_deps: bool,\n\n    #[clap(flatten)]\n    watchexec: WatchexecArgs,\n}\n\nimpl Watch {\n    pub async fn run(self) -> Result<()> {\n        if let Some(task) = &self.task {\n            if task == \"-h\" {\n                self.get_clap_command().print_help()?;\n                return Ok(());\n            }\n            if task == \"--help\" {\n                self.get_clap_command().print_long_help()?;\n                return Ok(());\n            }\n        }\n        let config = Config::get().await?;\n        let ts = ToolsetBuilder::new().build(&config).await?;\n        if let Err(err) = which::which(\"watchexec\") {\n            let watchexec: BackendArg = \"watchexec\".into();\n            if !ts.versions.contains_key(&watchexec) {\n                eprintln!(\"{}: {}\", style(\"Error\").red().bold(), err);\n                eprintln!(\"{}: Install watchexec with:\", style(\"Hint\").bold());\n                eprintln!(\"  mise use -g watchexec@latest\");\n                exit(1);\n            }\n        }\n        let args = once(self.task)\n            .flatten()\n            .chain(self.task_flag.iter().cloned())\n            .chain(self.args.iter().cloned())\n            .collect::<Vec<_>>();\n        if args.is_empty() {\n            bail!(\"No tasks specified\");\n        }\n        let tasks = crate::task::task_list::get_task_lists(&config, &args, false, false).await?;\n        let mut args = vec![];\n        if let Some(delay_run) = self.watchexec.delay_run {\n            args.push(\"--delay-run\".to_string());\n            args.push(delay_run);\n        }\n        if let Some(poll) = self.watchexec.poll {\n            args.push(\"--poll\".to_string());\n            args.push(poll);\n        }\n        if let Some(signal) = self.watchexec.signal {\n            args.push(\"--signal\".to_string());\n            args.push(signal);\n        }\n        if let Some(stop_signal) = self.watchexec.stop_signal {\n            args.push(\"--stop-signal\".to_string());\n            args.push(stop_signal);\n        }\n        if self.watchexec.stop_timeout != \"10s\" {\n            args.push(\"--stop-timeout\".to_string());\n            args.push(self.watchexec.stop_timeout);\n        }\n        if self.watchexec.debounce != \"50ms\" {\n            args.push(\"--debounce\".to_string());\n            args.push(self.watchexec.debounce);\n        }\n        if self.watchexec.stdin_quit {\n            args.push(\"--stdin-quit\".to_string());\n        }\n        if self.watchexec.no_vcs_ignore {\n            args.push(\"--no-vcs-ignore\".to_string());\n        }\n        if self.watchexec.no_project_ignore {\n            args.push(\"--no-project-ignore\".to_string());\n        }\n        if self.watchexec.no_global_ignore {\n            args.push(\"--no-global-ignore\".to_string());\n        }\n        if self.watchexec.no_default_ignore {\n            args.push(\"--no-default-ignore\".to_string());\n        }\n        if self.watchexec.no_discover_ignore {\n            args.push(\"--no-discover-ignore\".to_string());\n        }\n        if self.watchexec.ignore_nothing {\n            args.push(\"--ignore-nothing\".to_string());\n        }\n        if self.watchexec.postpone {\n            args.push(\"--postpone\".to_string());\n        }\n        if let Some(screen_clear) = self.watchexec.screen_clear {\n            args.push(\"--clear\".to_string());\n            if let ClearMode::Reset = screen_clear {\n                args.push(\"reset\".to_string());\n            }\n        }\n        if self.watchexec.restart {\n            args.push(\"--restart\".to_string());\n        }\n        if self.watchexec.on_busy_update != OnBusyUpdate::DoNothing {\n            args.push(\"--on-busy-update\".to_string());\n            args.push(self.watchexec.on_busy_update.to_string());\n        }\n        if !self.watchexec.signal_map.is_empty() {\n            for signal_map in &self.watchexec.signal_map {\n                args.push(\"--map-signal\".to_string());\n                args.push(signal_map.to_string());\n            }\n        }\n        if !self.watchexec.recursive_paths.is_empty() {\n            for path in &self.watchexec.recursive_paths {\n                args.push(\"--watch\".to_string());\n                args.push(path.to_string_lossy().to_string());\n            }\n        }\n        if !self.watchexec.non_recursive_paths.is_empty() {\n            for path in &self.watchexec.non_recursive_paths {\n                args.push(\"--watch-non-recursive\".to_string());\n                args.push(path.to_string_lossy().to_string());\n            }\n        }\n        if !self.watchexec.filter_extensions.is_empty() {\n            for ext in &self.watchexec.filter_extensions {\n                args.push(\"--exts\".to_string());\n                args.push(ext.to_string());\n            }\n        }\n        if !self.watchexec.filter_patterns.is_empty() {\n            for pattern in &self.watchexec.filter_patterns {\n                args.push(\"--filter\".to_string());\n                args.push(pattern.to_string());\n            }\n        }\n        if let Some(watch_file) = &self.watchexec.watch_file {\n            args.push(\"--watch-file\".to_string());\n            args.push(watch_file.to_string_lossy().to_string());\n        }\n        let globs = if self.glob.is_empty() {\n            tasks\n                .iter()\n                .flat_map(|t| t.sources.clone())\n                .collect::<Vec<_>>()\n        } else {\n            self.glob.clone()\n        };\n        if !globs.is_empty() {\n            args.push(\"-f\".to_string());\n            args.extend(itertools::intersperse(globs, \"-f\".to_string()).collect::<Vec<_>>());\n        }\n        args.extend([\n            \"--\".to_string(),\n            env::MISE_BIN.to_string_lossy().to_string(),\n            \"run\".to_string(),\n        ]);\n        if self.skip_deps {\n            args.push(\"--skip-deps\".to_string());\n        }\n        let task_args = itertools::intersperse(\n            tasks.iter().map(|t| {\n                let mut args = vec![t.name.to_string()];\n                args.extend(t.args.iter().map(|a| a.to_string()));\n                args\n            }),\n            vec![\":::\".to_string()],\n        )\n        .flatten()\n        .collect_vec();\n        for arg in task_args {\n            args.push(arg);\n        }\n        debug!(\"$ watchexec {}\", args.join(\" \"));\n        let mut cmd = cmd::cmd(\"watchexec\", &args);\n        for (k, v) in ts.env_with_path(&config).await? {\n            cmd = cmd.env(k, v);\n        }\n\n        // Save terminal state before running watchexec, because --clear=reset\n        // sends a full terminal reset (RIS) which can corrupt terminal settings\n        // (e.g. disabling echo) if watchexec is interrupted with Ctrl+C.\n        #[cfg(unix)]\n        let saved_termios = nix::sys::termios::tcgetattr(std::io::stdin()).ok();\n\n        let result = cmd.run();\n\n        #[cfg(unix)]\n        if let Some(termios) = saved_termios {\n            let _ = nix::sys::termios::tcsetattr(\n                std::io::stdin(),\n                nix::sys::termios::SetArg::TCSANOW,\n                &termios,\n            );\n        }\n\n        result?;\n        Ok(())\n    }\n\n    fn get_clap_command(&self) -> clap::Command {\n        Cli::command()\n            .get_subcommands()\n            .find(|s| s.get_name() == \"watch\")\n            .unwrap()\n            .clone()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise watch build</bold>\n    Runs the \"build\" tasks. Will re-run the tasks when any of its sources change.\n    Uses \"sources\" from the tasks definition to determine which files to watch.\n\n    $ <bold>mise watch build --glob src/**/*.rs</bold>\n    Runs the \"build\" tasks but specify the files to watch with a glob pattern.\n    This overrides the \"sources\" from the tasks definition.\n\n    $ <bold>mise watch build --clear</bold>\n    Extra arguments are passed to watchexec. See `watchexec --help` for details.\n\n    $ <bold>mise watch serve --watch src --exts rs --restart</bold>\n    Starts an api server, watching for changes to \"*.rs\" files in \"./src\" and kills/restarts the server when they change.\n\"#\n);\n\n//region watchexec\nconst OPTSET_FILTERING: &str = \"Filtering\";\nconst OPTSET_COMMAND: &str = \"Command\";\nconst OPTSET_DEBUGGING: &str = \"Debugging\";\nconst OPTSET_OUTPUT: &str = \"Output\";\n\n#[derive(Debug, clap::Args)]\npub struct WatchexecArgs {\n    /// Watch a specific file or directory\n    ///\n    /// By default, Watchexec watches the current directory.\n    ///\n    /// When watching a single file, it's often better to watch the containing directory instead,\n    /// and filter on the filename. Some editors may replace the file with a new one when saving,\n    /// and some platforms may not detect that or further changes.\n    ///\n    /// Upon starting, Watchexec resolves a \"project origin\" from the watched paths. See the help\n    /// for '--project-origin' for more information.\n    ///\n    /// This option can be specified multiple times to watch multiple files or directories.\n    ///\n    /// The special value '/dev/null', provided as the only path watched, will cause Watchexec to\n    /// not watch any paths. Other event sources (like signals or key events) may still be used.\n    #[arg(\n\t\tshort = 'w',\n\t\tlong = \"watch\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_hint = ValueHint::AnyPath,\n\t\tvalue_name = \"PATH\",\n    )]\n    pub recursive_paths: Vec<PathBuf>,\n\n    /// Watch a specific directory, non-recursively\n    ///\n    /// Unlike '-w', folders watched with this option are not recursed into.\n    ///\n    /// This option can be specified multiple times to watch multiple directories non-recursively.\n    #[arg(\n\t\tshort = 'W',\n\t\tlong = \"watch-non-recursive\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_hint = ValueHint::AnyPath,\n\t\tvalue_name = \"PATH\",\n    )]\n    pub non_recursive_paths: Vec<PathBuf>,\n\n    /// Watch files and directories from a file\n    ///\n    /// Each line in the file will be interpreted as if given to '-w'.\n    ///\n    /// For more complex uses (like watching non-recursively), use the argfile capability: build a\n    /// file containing command-line options and pass it to watchexec with `@path/to/argfile`.\n    ///\n    /// The special value '-' will read from STDIN; this in incompatible with '--stdin-quit'.\n    #[arg(\n\t\tshort = 'F',\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_hint = ValueHint::AnyPath,\n\t\tvalue_name = \"PATH\",\n    )]\n    pub watch_file: Option<PathBuf>,\n\n    /// Clear screen before running command\n    ///\n    /// If this doesn't completely clear the screen, try '--clear=reset'.\n    #[arg(\n\t\tshort = 'c',\n\t\tlong = \"clear\",\n\t\thelp_heading = OPTSET_OUTPUT,\n\t\tnum_args = 0..=1,\n\t\tdefault_missing_value = \"clear\",\n\t\tvalue_name = \"MODE\",\n    )]\n    pub screen_clear: Option<ClearMode>,\n\n    /// What to do when receiving events while the command is running\n    ///\n    /// Default is to 'do-nothing', which ignores events while the command is running, so that\n    /// changes that occur due to the command are ignored, like compilation outputs. You can also\n    /// use 'queue' which will run the command once again when the current run has finished if any\n    /// events occur while it's running, or 'restart', which terminates the running command and starts\n    /// a new one. Finally, there's 'signal', which only sends a signal; this can be useful with\n    /// programs that can reload their configuration without a full restart.\n    ///\n    /// The signal can be specified with the '--signal' option.\n    #[arg(\n        short,\n        long,\n        default_value = \"do-nothing\",\n        hide_default_value = true,\n        value_name = \"MODE\"\n    )]\n    pub on_busy_update: OnBusyUpdate,\n\n    /// Restart the process if it's still running\n    ///\n    /// This is a shorthand for '--on-busy-update=restart'.\n    #[arg(\n\t\tshort,\n\t\tlong,\n\t\tconflicts_with_all = [\"on_busy_update\"],\n    )]\n    pub restart: bool,\n\n    /// Send a signal to the process when it's still running\n    ///\n    /// Specify a signal to send to the process when it's still running. This implies\n    /// '--on-busy-update=signal'; otherwise the signal used when that mode is 'restart' is\n    /// controlled by '--stop-signal'.\n    ///\n    /// See the long documentation for '--stop-signal' for syntax.\n    ///\n    /// Signals are not supported on Windows at the moment, and will always be overridden to 'kill'.\n    /// See '--stop-signal' for more on Windows \"signals\".\n    #[arg(\n\t\tshort,\n\t\tlong,\n\t\tconflicts_with_all = [\"restart\"],\n\t\tvalue_name = \"SIGNAL\"\n    )]\n    pub signal: Option<String>,\n\n    /// Signal to send to stop the command\n    ///\n    /// This is used by 'restart' and 'signal' modes of '--on-busy-update' (unless '--signal' is\n    /// provided). The restart behaviour is to send the signal, wait for the command to exit, and if\n    /// it hasn't exited after some time (see '--timeout-stop'), forcefully terminate it.\n    ///\n    /// The default on unix is \"SIGTERM\".\n    ///\n    /// Input is parsed as a full signal name (like \"SIGTERM\"), a short signal name (like \"TERM\"),\n    /// or a signal number (like \"15\"). All input is case-insensitive.\n    ///\n    /// On Windows this option is technically supported but only supports the \"KILL\" event, as\n    /// Watchexec cannot yet deliver other events. Windows doesn't have signals as such; instead it\n    /// has termination (here called \"KILL\" or \"STOP\") and \"CTRL+C\", \"CTRL+BREAK\", and \"CTRL+CLOSE\"\n    /// events. For portability the unix signals \"SIGKILL\", \"SIGINT\", \"SIGTERM\", and \"SIGHUP\" are\n    /// respectively mapped to these.\n    #[arg(long, value_name = \"SIGNAL\")]\n    pub stop_signal: Option<String>,\n\n    /// Time to wait for the command to exit gracefully\n    ///\n    /// This is used by the 'restart' mode of '--on-busy-update'. After the graceful stop signal\n    /// is sent, Watchexec will wait for the command to exit. If it hasn't exited after this time,\n    /// it is forcefully terminated.\n    ///\n    /// Takes a unit-less value in seconds, or a time span value such as \"5min 20s\".\n    /// Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n    ///\n    /// The default is 10 seconds. Set to 0 to immediately force-kill the command.\n    ///\n    /// This has no practical effect on Windows as the command is always forcefully terminated; see\n    /// '--stop-signal' for why.\n    #[arg(\n        long,\n        default_value = \"10s\",\n        hide_default_value = true,\n        value_name = \"TIMEOUT\"\n    )]\n    pub stop_timeout: String,\n\n    /// Translate signals from the OS to signals to send to the command\n    ///\n    /// Takes a pair of signal names, separated by a colon, such as \"TERM:INT\" to map SIGTERM to\n    /// SIGINT. The first signal is the one received by watchexec, and the second is the one sent to\n    /// the command. The second can be omitted to discard the first signal, such as \"TERM:\" to\n    /// not do anything on SIGTERM.\n    ///\n    /// If SIGINT or SIGTERM are mapped, then they no longer quit Watchexec. Besides making it hard\n    /// to quit Watchexec itself, this is useful to send pass a Ctrl-C to the command without also\n    /// terminating Watchexec and the underlying program with it, e.g. with \"INT:INT\".\n    ///\n    /// This option can be specified multiple times to map multiple signals.\n    ///\n    /// Signal syntax is case-insensitive for short names (like \"TERM\", \"USR2\") and long names (like\n    /// \"SIGKILL\", \"SIGHUP\"). Signal numbers are also supported (like \"15\", \"31\"). On Windows, the\n    /// forms \"STOP\", \"CTRL+C\", and \"CTRL+BREAK\" are also supported to receive, but Watchexec cannot\n    /// yet deliver other \"signals\" than a STOP.\n    #[arg(long = \"map-signal\", value_name = \"SIGNAL:SIGNAL\")]\n    pub signal_map: Vec<String>,\n\n    /// Time to wait for new events before taking action\n    ///\n    /// When an event is received, Watchexec will wait for up to this amount of time before handling\n    /// it (such as running the command). This is essential as what you might perceive as a single\n    /// change may actually emit many events, and without this behaviour, Watchexec would run much\n    /// too often. Additionally, it's not infrequent that file writes are not atomic, and each write\n    /// may emit an event, so this is a good way to avoid running a command while a file is\n    /// partially written.\n    ///\n    /// An alternative use is to set a high value (like \"30min\" or longer), to save power or\n    /// bandwidth on intensive tasks, like an ad-hoc backup script. In those use cases, note that\n    /// every accumulated event will build up in memory.\n    ///\n    /// Takes a unit-less value in milliseconds, or a time span value such as \"5sec 20ms\".\n    /// Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n    ///\n    /// The default is 50 milliseconds. Setting to 0 is highly discouraged.\n    #[arg(\n        long,\n        short,\n        default_value = \"50ms\",\n        hide_default_value = true,\n        value_name = \"TIMEOUT\"\n    )]\n    pub debounce: String,\n\n    /// Exit when stdin closes\n    ///\n    /// This watches the stdin file descriptor for EOF, and exits Watchexec gracefully when it is\n    /// closed. This is used by some process managers to avoid leaving zombie processes around.\n    #[arg(long)]\n    pub stdin_quit: bool,\n\n    /// Don't load gitignores\n    ///\n    /// Among other VCS exclude files, like for Mercurial, Subversion, Bazaar, DARCS, Fossil. Note\n    /// that Watchexec will detect which of these is in use, if any, and only load the relevant\n    /// files. Both global (like '~/.gitignore') and local (like '.gitignore') files are considered.\n    ///\n    /// This option is useful if you want to watch files that are ignored by Git.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n    )]\n    pub no_vcs_ignore: bool,\n\n    /// Don't load project-local ignores\n    ///\n    /// This disables loading of project-local ignore files, like '.gitignore' or '.ignore' in the\n    /// watched project. This is contrasted with '--no-vcs-ignore', which disables loading of Git\n    /// and other VCS ignore files, and with '--no-global-ignore', which disables loading of global\n    /// or user ignore files, like '~/.gitignore' or '~/.config/watchexec/ignore'.\n    ///\n    /// Supported project ignore files:\n    ///\n    ///   - Git: .gitignore at project root and child directories, .git/info/exclude, and the file pointed to by `core.excludesFile` in .git/config.\n    ///   - Mercurial: .hgignore at project root and child directories.\n    ///   - Bazaar: .bzrignore at project root.\n    ///   - Darcs: _darcs/prefs/boring\n    ///   - Fossil: .fossil-settings/ignore-glob\n    ///   - Ripgrep/Watchexec/generic: .ignore at project root and child directories.\n    ///\n    /// VCS ignore files (Git, Mercurial, Bazaar, Darcs, Fossil) are only used if the corresponding\n    /// VCS is discovered to be in use for the project/origin. For example, a .bzrignore in a Git\n    /// repository will be discarded.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tverbatim_doc_comment,\n    )]\n    pub no_project_ignore: bool,\n\n    /// Don't load global ignores\n    ///\n    /// This disables loading of global or user ignore files, like '~/.gitignore',\n    /// '~/.config/watchexec/ignore', or '%APPDATA%\\Bazzar\\2.0\\ignore'. Contrast with\n    /// '--no-vcs-ignore' and '--no-project-ignore'.\n    ///\n    /// Supported global ignore files\n    ///\n    ///   - Git (if core.excludesFile is set): the file at that path\n    ///   - Git (otherwise): the first found of $XDG_CONFIG_HOME/git/ignore, %APPDATA%/.gitignore, %USERPROFILE%/.gitignore, $HOME/.config/git/ignore, $HOME/.gitignore.\n    ///   - Bazaar: the first found of %APPDATA%/Bazzar/2.0/ignore, $HOME/.bazaar/ignore.\n    ///   - Watchexec: the first found of $XDG_CONFIG_HOME/watchexec/ignore, %APPDATA%/watchexec/ignore, %USERPROFILE%/.watchexec/ignore, $HOME/.watchexec/ignore.\n    ///\n    /// Like for project files, Git and Bazaar global files will only be used for the corresponding\n    /// VCS as used in the project.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tverbatim_doc_comment,\n    )]\n    pub no_global_ignore: bool,\n\n    /// Don't use internal default ignores\n    ///\n    /// Watchexec has a set of default ignore patterns, such as editor swap files, `*.pyc`, `*.pyo`,\n    /// `.DS_Store`, `.bzr`, `_darcs`, `.fossil-settings`, `.git`, `.hg`, `.pijul`, `.svn`, and\n    /// Watchexec log files.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n    )]\n    pub no_default_ignore: bool,\n\n    /// Don't discover ignore files at all\n    ///\n    /// This is a shorthand for '--no-global-ignore', '--no-vcs-ignore', '--no-project-ignore', but\n    /// even more efficient as it will skip all the ignore discovery mechanisms from the get go.\n    ///\n    /// Note that default ignores are still loaded, see '--no-default-ignore'.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n    )]\n    pub no_discover_ignore: bool,\n\n    /// Don't ignore anything at all\n    ///\n    /// This is a shorthand for '--no-discover-ignore', '--no-default-ignore'.\n    ///\n    /// Note that ignores explicitly loaded via other command line options, such as '--ignore' or\n    /// '--ignore-file', will still be used.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_FILTERING,\n    )]\n    pub ignore_nothing: bool,\n\n    /// Wait until first change before running command\n    ///\n    /// By default, Watchexec will run the command once immediately. With this option, it will\n    /// instead wait until an event is detected before running the command as normal.\n    #[arg(long, short)]\n    pub postpone: bool,\n\n    /// Sleep before running the command\n    ///\n    /// This option will cause Watchexec to sleep for the specified amount of time before running\n    /// the command, after an event is detected. This is like using \"sleep 5 && command\" in a shell,\n    /// but portable and slightly more efficient.\n    ///\n    /// Takes a unit-less value in seconds, or a time span value such as \"2min 5s\".\n    /// Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n    #[arg(long, value_name = \"DURATION\")]\n    pub delay_run: Option<String>,\n\n    /// Poll for filesystem changes\n    ///\n    /// By default, and where available, Watchexec uses the operating system's native file system\n    /// watching capabilities. This option disables that and instead uses a polling mechanism, which\n    /// is less efficient but can work around issues with some file systems (like network shares) or\n    /// edge cases.\n    ///\n    /// Optionally takes a unit-less value in milliseconds, or a time span value such as \"2s 500ms\",\n    /// to use as the polling interval. If not specified, the default is 30 seconds.\n    /// Providing a unit-less value is deprecated and will warn; it will be an error in the future.\n    ///\n    /// Aliased as '--force-poll'.\n    #[arg(\n\t\tlong,\n\t\talias = \"force-poll\",\n\t\tnum_args = 0..=1,\n\t\tdefault_missing_value = \"30s\",\n\t\tvalue_name = \"INTERVAL\",\n    )]\n    pub poll: Option<String>,\n\n    /// Use a different shell\n    ///\n    /// By default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix-likes,\n    /// and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec\n    /// detects is the running shell.\n    ///\n    /// With this option, you can override that and use a different shell, for example one with more\n    /// features or one which has your custom aliases and functions.\n    ///\n    /// If the value has spaces, it is parsed as a command line, and the first word used as the\n    /// shell program, with the rest as arguments to the shell.\n    ///\n    /// The command is run with the '-c' flag (except for 'cmd' on Windows, where it's '/C').\n    ///\n    /// The special value 'none' can be used to disable shell use entirely. In that case, the\n    /// command provided to Watchexec will be parsed, with the first word being the executable and\n    /// the rest being the arguments, and executed directly. Note that this parsing is rudimentary,\n    /// and may not work as expected in all cases.\n    ///\n    /// Using 'none' is a little more efficient and can enable a stricter interpretation of the\n    /// input, but it also means that you can't use shell features like globbing, redirection,\n    /// control flow, logic, or pipes.\n    ///\n    /// Examples:\n    ///\n    /// Use without shell:\n    ///\n    ///   $ watchexec -n -- zsh -x -o shwordsplit scr\n    ///\n    /// Use with powershell core:\n    ///\n    ///   $ watchexec --shell=pwsh -- Test-Connection localhost\n    ///\n    /// Use with CMD.exe:\n    ///\n    ///   $ watchexec --shell=cmd -- dir\n    ///\n    /// Use with a different unix shell:\n    ///\n    ///   $ watchexec --shell=bash -- 'echo $BASH_VERSION'\n    ///\n    /// Use with a unix shell and options:\n    ///\n    ///   $ watchexec --shell='zsh -x -o shwordsplit' -- scr\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_COMMAND,\n\t\tvalue_name = \"SHELL\",\n    )]\n    pub shell: Option<String>,\n\n    /// Shorthand for '--shell=none'\n    #[arg(\n\t\tshort = 'n',\n\t\thelp_heading = OPTSET_COMMAND,\n    )]\n    pub no_shell: bool,\n\n    /// Configure event emission\n    ///\n    /// Watchexec can emit event information when running a command, which can be used by the child\n    /// process to target specific changed files.\n    ///\n    /// One thing to take care with is assuming inherent behaviour where there is only chance.\n    /// Notably, it could appear as if the `RENAMED` variable contains both the original and the new\n    /// path being renamed. In previous versions, it would even appear on some platforms as if the\n    /// original always came before the new. However, none of this was true. It's impossible to\n    /// reliably and portably know which changed path is the old or new, \"half\" renames may appear\n    /// (only the original, only the new), \"unknown\" renames may appear (change was a rename, but\n    /// whether it was the old or new isn't known), rename events might split across two debouncing\n    /// boundaries, and so on.\n    ///\n    /// This option controls where that information is emitted. It defaults to 'none', which doesn't\n    /// emit event information at all. The other options are 'environment' (deprecated), 'stdio',\n    /// 'file', 'json-stdio', and 'json-file'.\n    ///\n    /// The 'stdio' and 'file' modes are text-based: 'stdio' writes absolute paths to the stdin of\n    /// the command, one per line, each prefixed with `create:`, `remove:`, `rename:`, `modify:`,\n    /// or `other:`, then closes the handle; 'file' writes the same thing to a temporary file, and\n    /// its path is given with the $WATCHEXEC_EVENTS_FILE environment variable.\n    ///\n    /// There are also two JSON modes, which are based on JSON objects and can represent the full\n    /// set of events Watchexec handles. Here's an example of a folder being created on Linux:\n    ///\n    /// ```json\n    ///   {\n    ///     \"tags\": [\n    ///       {\n    ///         \"kind\": \"path\",\n    ///         \"absolute\": \"/home/user/your/new-folder\",\n    ///         \"filetype\": \"dir\"\n    ///       },\n    ///       {\n    ///         \"kind\": \"fs\",\n    ///         \"simple\": \"create\",\n    ///         \"full\": \"Create(Folder)\"\n    ///       },\n    ///       {\n    ///         \"kind\": \"source\",\n    ///         \"source\": \"filesystem\",\n    ///       }\n    ///     ],\n    ///     \"metadata\": {\n    ///       \"notify-backend\": \"inotify\"\n    ///     }\n    ///   }\n    /// ```\n    ///\n    /// The fields are as follows:\n    ///\n    ///   - `tags`, structured event data.\n    ///   - `tags[].kind`, which can be:\n    ///     * 'path', along with:\n    ///       + `absolute`, an absolute path.\n    ///       + `filetype`, a file type if known ('dir', 'file', 'symlink', 'other').\n    ///     * 'fs':\n    ///       + `simple`, the \"simple\" event type ('access', 'create', 'modify', 'remove', or 'other').\n    ///       + `full`, the \"full\" event type, which is too complex to fully describe here, but looks like 'General(Precise(Specific))'.\n    ///     * 'source', along with:\n    ///       + `source`, the source of the event ('filesystem', 'keyboard', 'mouse', 'os', 'time', 'internal').\n    ///     * 'keyboard', along with:\n    ///       + `keycode`. Currently only the value 'eof' is supported.\n    ///     * 'process', for events caused by processes:\n    ///       + `pid`, the process ID.\n    ///     * 'signal', for signals sent to Watchexec:\n    ///       + `signal`, the normalised signal name ('hangup', 'interrupt', 'quit', 'terminate', 'user1', 'user2').\n    ///     * 'completion', for when a command ends:\n    ///       + `disposition`, the exit disposition ('success', 'error', 'signal', 'stop', 'exception', 'continued').\n    ///       + `code`, the exit, signal, stop, or exception code.\n    ///   - `metadata`, additional information about the event.\n    ///\n    /// The 'json-stdio' mode will emit JSON events to the standard input of the command, one per\n    /// line, then close stdin. The 'json-file' mode will create a temporary file, write the\n    /// events to it, and provide the path to the file with the $WATCHEXEC_EVENTS_FILE\n    /// environment variable.\n    ///\n    /// Finally, the 'environment' mode was the default until 2.0. It sets environment variables\n    /// with the paths of the affected files, for filesystem events:\n    ///\n    /// $WATCHEXEC_COMMON_PATH is set to the longest common path of all of the below variables,\n    /// and so should be prepended to each path to obtain the full/real path. Then:\n    ///\n    ///   - $WATCHEXEC_CREATED_PATH is set when files/folders were created\n    ///   - $WATCHEXEC_REMOVED_PATH is set when files/folders were removed\n    ///   - $WATCHEXEC_RENAMED_PATH is set when files/folders were renamed\n    ///   - $WATCHEXEC_WRITTEN_PATH is set when files/folders were modified\n    ///   - $WATCHEXEC_META_CHANGED_PATH is set when files/folders' metadata were modified\n    ///   - $WATCHEXEC_OTHERWISE_CHANGED_PATH is set for every other kind of pathed event\n    ///\n    /// Multiple paths are separated by the system path separator, ';' on Windows and ':' on unix.\n    /// Within each variable, paths are deduplicated and sorted in binary order (i.e. neither\n    /// Unicode nor locale aware).\n    ///\n    /// This is the legacy mode, is deprecated, and will be removed in the future. The environment\n    /// is a very restricted space, while also limited in what it can usefully represent. Large\n    /// numbers of files will either cause the environment to be truncated, or may error or crash\n    /// the process entirely. The $WATCHEXEC_COMMON_PATH is also unintuitive, as demonstrated by the\n    /// multiple confused queries that have landed in my inbox over the years.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_COMMAND,\n\t\tverbatim_doc_comment,\n\t\tdefault_value = \"none\",\n\t\thide_default_value = true,\n\t\tvalue_name = \"MODE\",\n\t\trequired_if_eq(\"only_emit_events\", \"true\"),\n    )]\n    pub emit_events_to: EmitEvents,\n\n    /// Only emit events to stdout, run no commands.\n    ///\n    /// This is a convenience option for using Watchexec as a file watcher, without running any\n    /// commands. It is almost equivalent to using `cat` as the command, except that it will not\n    /// spawn a new process for each event.\n    ///\n    /// This option requires `--emit-events-to` to be set, and restricts the available modes to\n    /// `stdio` and `json-stdio`, modifying their behaviour to write to stdout instead of the stdin\n    /// of the command.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n\t\tconflicts_with_all = [\"manual\"],\n    )]\n    pub only_emit_events: bool,\n\n    /// Add env vars to the command\n    ///\n    /// This is a convenience option for setting environment variables for the command, without\n    /// setting them for the Watchexec process itself.\n    ///\n    /// Use key=value syntax. Multiple variables can be set by repeating the option.\n    #[arg(\n\t\tlong,\n\t\tshort = 'E',\n\t\thelp_heading = OPTSET_COMMAND,\n\t\tvalue_name = \"KEY=VALUE\",\n    )]\n    pub env: Vec<String>,\n\n    /// Configure how the process is wrapped\n    ///\n    /// By default, Watchexec will run the command in a process group in Unix, and in a Job Object\n    /// in Windows.\n    ///\n    /// Some Unix programs prefer running in a session, while others do not work in a process group.\n    ///\n    /// Use 'group' to use a process group, 'session' to use a process session, and 'none' to run\n    /// the command directly. On Windows, either of 'group' or 'session' will use a Job Object.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_COMMAND,\n\t\tvalue_name = \"MODE\",\n\t\tdefault_value = \"group\",\n    )]\n    pub wrap_process: WrapMode,\n\n    /// Alert when commands start and end\n    ///\n    /// With this, Watchexec will emit a desktop notification when a command starts and ends, on\n    /// supported platforms. On unsupported platforms, it may silently do nothing, or log a warning.\n    #[arg(\n\t\tshort = 'N',\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n    )]\n    pub notify: bool,\n\n    /// When to use terminal colours\n    ///\n    /// Setting the environment variable `NO_COLOR` to any value is equivalent to `--color=never`.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n\t\tdefault_value = \"auto\",\n\t\tvalue_name = \"MODE\",\n\t\talias = \"colour\",\n    )]\n    pub color: ColourMode,\n\n    /// Print how long the command took to run\n    ///\n    /// This may not be exactly accurate, as it includes some overhead from Watchexec itself. Use\n    /// the `time` utility, high-precision timers, or benchmarking tools for more accurate results.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n    )]\n    pub timings: bool,\n\n    /// Don't print starting and stopping messages\n    ///\n    /// By default Watchexec will print a message when the command starts and stops. This option\n    /// disables this behaviour, so only the command's output, warnings, and errors will be printed.\n    #[arg(\n\t\tshort,\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n    )]\n    pub quiet: bool,\n\n    /// Ring the terminal bell on command completion\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_OUTPUT,\n    )]\n    pub bell: bool,\n\n    /// Set the project origin\n    ///\n    /// Watchexec will attempt to discover the project's \"origin\" (or \"root\") by searching for a\n    /// variety of markers, like files or directory patterns. It does its best but sometimes gets it\n    /// it wrong, and you can override that with this option.\n    ///\n    /// The project origin is used to determine the path of certain ignore files, which VCS is being\n    /// used, the meaning of a leading '/' in filtering patterns, and maybe more in the future.\n    ///\n    /// When set, Watchexec will also not bother searching, which can be significantly faster.\n    #[arg(\n\t\tlong,\n\t\tvalue_hint = ValueHint::DirPath,\n\t\tvalue_name = \"DIRECTORY\",\n    )]\n    pub project_origin: Option<PathBuf>,\n\n    /// Set the working directory\n    ///\n    /// By default, the working directory of the command is the working directory of Watchexec. You\n    /// can change that with this option. Note that paths may be less intuitive to use with this.\n    #[arg(\n\t\tlong,\n\t\tvalue_hint = ValueHint::DirPath,\n\t\tvalue_name = \"DIRECTORY\",\n    )]\n    pub workdir: Option<PathBuf>,\n\n    /// Filename extensions to filter to\n    ///\n    /// This is a quick filter to only emit events for files with the given extensions. Extensions\n    /// can be given with or without the leading dot (e.g. 'js' or '.js'). Multiple extensions can\n    /// be given by repeating the option or by separating them with commas.\n    #[arg(\n\t\tlong = \"exts\",\n\t\tshort = 'e',\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_delimiter = ',',\n\t\tvalue_name = \"EXTENSIONS\",\n    )]\n    pub filter_extensions: Vec<String>,\n\n    /// Filename patterns to filter to\n    ///\n    /// Provide a glob-like filter pattern, and only events for files matching the pattern will be\n    /// emitted. Multiple patterns can be given by repeating the option. Events that are not from\n    /// files (e.g. signals, keyboard events) will pass through untouched.\n    #[arg(\n\t\tlong = \"filter\",\n\t\tshort = 'f',\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_name = \"PATTERN\",\n    )]\n    pub filter_patterns: Vec<String>,\n\n    /// Files to load filters from\n    ///\n    /// Provide a path to a file containing filters, one per line. Empty lines and lines starting\n    /// with '#' are ignored. Uses the same pattern format as the '--filter' option.\n    ///\n    /// This can also be used via the $WATCHEXEC_FILTER_FILES environment variable.\n    #[arg(\n\t\tlong = \"filter-file\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_delimiter = env::PATH_ENV_SEP,\n\t\tvalue_hint = ValueHint::FilePath,\n\t\tvalue_name = \"PATH\",\n\t\tenv = \"WATCHEXEC_FILTER_FILES\",\n\t\thide_env = true,\n    )]\n    pub filter_files: Vec<PathBuf>,\n\n    /// [experimental] Filter programs.\n    ///\n    /// /!\\ This option is EXPERIMENTAL and may change and/or vanish without notice.\n    ///\n    /// Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given\n    /// an event in the same format as described in '--emit-events-to' and must return a boolean.\n    /// Invalid programs will make watchexec fail to start; use '-v' to see program runtime errors.\n    ///\n    /// In addition to the jaq stdlib, watchexec adds some custom filter definitions:\n    ///\n    ///   - 'path | file_meta' returns file metadata or null if the file does not exist.\n    ///\n    ///   - 'path | file_size' returns the size of the file at path, or null if it does not exist.\n    ///\n    ///   - 'path | file_read(bytes)' returns a string with the first n bytes of the file at path.\n    ///     If the file is smaller than n bytes, the whole file is returned. There is no filter to\n    ///     read the whole file at once to encourage limiting the amount of data read and processed.\n    ///\n    ///   - 'string | hash', and 'path | file_hash' return the hash of the string or file at path.\n    ///     No guarantee is made about the algorithm used: treat it as an opaque value.\n    ///\n    ///   - 'any | kv_store(key)', 'kv_fetch(key)', and 'kv_clear' provide a simple key-value store.\n    ///     Data is kept in memory only, there is no persistence. Consistency is not guaranteed.\n    ///\n    ///   - 'any | printout', 'any | printerr', and 'any | log(level)' will print or log any given\n    ///     value to stdout, stderr, or the log (levels = error, warn, info, debug, trace), and\n    ///     pass the value through (so '[1] | log(\"debug\") | .[]' will produce a '1' and log '[1]').\n    ///\n    /// All filtering done with such programs, and especially those using kv or filesystem access,\n    /// is much slower than the other filtering methods. If filtering is too slow, events will back\n    /// up and stall watchexec. Take care when designing your filters.\n    ///\n    /// If the argument to this option starts with an '@', the rest of the argument is taken to be\n    /// the path to a file containing a jaq program.\n    ///\n    /// Jaq programs are run in order, after all other filters, and short-circuit: if a filter (jaq\n    /// or not) rejects an event, execution stops there, and no other filters are run. Additionally,\n    /// they stop after outputting the first value, so you'll want to use 'any' or 'all' when\n    /// iterating, otherwise only the first item will be processed, which can be quite confusing!\n    ///\n    /// Find user-contributed programs or submit your own useful ones at\n    /// <https://github.com/watchexec/watchexec/discussions/592>.\n    ///\n    /// ## Examples:\n    ///\n    /// Regexp ignore filter on paths:\n    ///\n    ///   'all(.tags[] | select(.kind == \"path\"); .absolute | test(\"[.]test[.]js$\")) | not'\n    ///\n    /// Pass any event that creates a file:\n    ///\n    ///   'any(.tags[] | select(.kind == \"fs\"); .simple == \"create\")'\n    ///\n    /// Pass events that touch executable files:\n    ///\n    ///   'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | metadata | .executable)'\n    ///\n    /// Ignore files that start with shebangs:\n    ///\n    ///   'any(.tags[] | select(.kind == \"path\" && .filetype == \"file\"); .absolute | read(2) == \"#!\") | not'\n    #[arg(\n\t\tlong = \"filter-prog\",\n\t\tshort = 'J',\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_name = \"EXPRESSION\",\n    )]\n    pub filter_programs: Vec<String>,\n\n    /// Filename patterns to filter out\n    ///\n    /// Provide a glob-like filter pattern, and events for files matching the pattern will be\n    /// excluded. Multiple patterns can be given by repeating the option. Events that are not from\n    /// files (e.g. signals, keyboard events) will pass through untouched.\n    #[arg(\n\t\tlong = \"ignore\",\n\t\tshort = 'i',\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_name = \"PATTERN\",\n    )]\n    pub ignore_patterns: Vec<String>,\n\n    /// Files to load ignores from\n    ///\n    /// Provide a path to a file containing ignores, one per line. Empty lines and lines starting\n    /// with '#' are ignored. Uses the same pattern format as the '--ignore' option.\n    ///\n    /// This can also be used via the $WATCHEXEC_IGNORE_FILES environment variable.\n    #[arg(\n\t\tlong = \"ignore-file\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tvalue_delimiter = env::PATH_ENV_SEP,\n\t\tvalue_hint = ValueHint::FilePath,\n\t\tvalue_name = \"PATH\",\n\t\tenv = \"WATCHEXEC_IGNORE_FILES\",\n\t\thide_env = true,\n    )]\n    pub ignore_files: Vec<PathBuf>,\n\n    /// Filesystem events to filter to\n    ///\n    /// This is a quick filter to only emit events for the given types of filesystem changes. Choose\n    /// from 'access', 'create', 'remove', 'rename', 'modify', 'metadata'. Multiple types can be\n    /// given by repeating the option or by separating them with commas. By default, this is all\n    /// types except for 'access'.\n    ///\n    /// This may apply filtering at the kernel level when possible, which can be more efficient, but\n    /// may be more confusing when reading the logs.\n    #[arg(\n\t\tlong = \"fs-events\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tdefault_value = \"create,remove,rename,modify,metadata\",\n\t\tvalue_delimiter = ',',\n\t\thide_default_value = true,\n\t\tvalue_name = \"EVENTS\",\n    )]\n    pub filter_fs_events: Vec<FsEvent>,\n\n    /// Don't emit fs events for metadata changes\n    ///\n    /// This is a shorthand for '--fs-events create,remove,rename,modify'. Using it alongside the\n    /// '--fs-events' option is non-sensical and not allowed.\n    #[arg(\n\t\tlong = \"no-meta\",\n\t\thelp_heading = OPTSET_FILTERING,\n\t\tconflicts_with = \"filter_fs_events\",\n    )]\n    pub filter_fs_meta: bool,\n\n    /// Print events that trigger actions\n    ///\n    /// This prints the events that triggered the action when handling it (after debouncing), in a\n    /// human readable form. This is useful for debugging filters.\n    ///\n    /// Use '-vvv' instead when you need more diagnostic information.\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_DEBUGGING,\n    )]\n    pub print_events: bool,\n\n    /// Show the manual page\n    ///\n    /// This shows the manual page for Watchexec, if the output is a terminal and the 'man' program\n    /// is available. If not, the manual page is printed to stdout in ROFF format (suitable for\n    /// writing to a watchexec.1 file).\n    #[arg(\n\t\tlong,\n\t\thelp_heading = OPTSET_DEBUGGING,\n    )]\n    pub manual: bool,\n    // /// Change to this directory before executing the command\n    // #[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)]\n    // pub cd: Option<PathBuf>,\n    //\n    // /// Don't actually run the task(s), just print them in order of execution\n    // #[clap(long, short = 'n', verbatim_doc_comment)]\n    // pub dry_run: bool,\n    //\n    // /// Force the tasks to run even if outputs are up to date\n    // #[clap(long, short, verbatim_doc_comment)]\n    // pub force: bool,\n    //\n    // /// Print stdout/stderr by line, prefixed with the tasks's label\n    // /// Defaults to true if --jobs > 1\n    // /// Configure with `task.output` config or `MISE_TASK_OUTPUT` env var\n    // #[clap(long, short, verbatim_doc_comment, overrides_with = \"interleave\")]\n    // pub prefix: bool,\n    //\n    // /// Print directly to stdout/stderr instead of by line\n    // /// Defaults to true if --jobs == 1\n    // /// Configure with `task.output` config or `MISE_TASK_OUTPUT` env var\n    // #[clap(long, short, verbatim_doc_comment, overrides_with = \"prefix\")]\n    // pub interleave: bool,\n    //\n    // /// Tool(s) to also add\n    // /// e.g.: node@20 python@3.10\n    // #[clap(short, long, value_name = \"TOOL@VERSION\")]\n    // pub tool: Vec<ToolArg>,\n    //\n    // /// Number of tasks to run in parallel\n    // /// [default: 4]\n    // /// Configure with `jobs` config or `MISE_JOBS` env var\n    // #[clap(long, short, env = \"MISE_JOBS\", verbatim_doc_comment)]\n    // pub jobs: Option<usize>,\n    //\n    // /// Read/write directly to stdin/stdout/stderr instead of by line\n    // /// Configure with `raw` config or `MISE_RAW` env var\n    // #[clap(long, short, verbatim_doc_comment)]\n    // pub raw: bool,\n}\n\n#[derive(Clone, Copy, Debug, Default, ValueEnum)]\npub enum EmitEvents {\n    #[default]\n    Environment,\n    Stdio,\n    File,\n    JsonStdio,\n    JsonFile,\n    None,\n}\n\n#[derive(Clone, Copy, Debug, Default, ValueEnum, PartialEq, strum::Display)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum OnBusyUpdate {\n    #[default]\n    Queue,\n    DoNothing,\n    Restart,\n    Signal,\n}\n\n#[derive(Clone, Copy, Debug, Default, ValueEnum)]\npub enum WrapMode {\n    #[default]\n    Group,\n    Session,\n    None,\n}\n\n#[derive(Clone, Copy, Debug, Default, ValueEnum)]\npub enum ClearMode {\n    #[default]\n    Clear,\n    Reset,\n}\n\n#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]\npub enum FsEvent {\n    Access,\n    Create,\n    Remove,\n    Rename,\n    Modify,\n    Metadata,\n}\n\n#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]\n#[clap(rename_all = \"lower\")]\npub enum ShellCompletion {\n    Bash,\n    Elvish,\n    Fish,\n    Nu,\n    PowerShell,\n    Zsh,\n}\n\n#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]\npub enum ColourMode {\n    Auto,\n    Always,\n    Never,\n}\n//endregion\n"
  },
  {
    "path": "src/cli/where.rs",
    "content": "use eyre::Result;\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::errors::Error;\nuse crate::toolset::ToolsetBuilder;\n\n/// Display the installation path for a tool\n///\n/// The tool must be installed for this to work.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Where {\n    /// Tool(s) to look up\n    /// e.g.: ruby@3\n    /// if \"@<PREFIX>\" is specified, it will show the latest installed version\n    /// that matches the prefix\n    /// otherwise, it will show the current, active installed version\n    #[clap(required = true, value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    tool: ToolArg,\n\n    /// the version prefix to use when querying the latest version\n    /// same as the first argument after the \"@\"\n    /// used for asdf compatibility\n    #[clap(hide = true, verbatim_doc_comment)]\n    asdf_version: Option<String>,\n}\n\nimpl Where {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        let tvr = match self.tool.tvr {\n            Some(tvr) => tvr,\n            None => match self.asdf_version {\n                Some(version) => self.tool.with_version(&version).tvr.unwrap(),\n                None => {\n                    let ts = ToolsetBuilder::new().build(&config).await?;\n                    ts.versions\n                        .get(self.tool.ba.as_ref())\n                        .and_then(|tvr| tvr.requests.first().cloned())\n                        .unwrap_or_else(|| self.tool.with_version(\"latest\").tvr.unwrap())\n                }\n            },\n        };\n\n        let tv = tvr.resolve(&config, &Default::default()).await?;\n\n        if tv.backend()?.is_version_installed(&config, &tv, true) {\n            miseprintln!(\"{}\", tv.install_path().to_string_lossy());\n            Ok(())\n        } else {\n            Err(Error::VersionNotInstalled(\n                Box::new(tv.ba().clone()),\n                tv.version,\n            ))?\n        }\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    # Show the latest installed version of node\n    # If it is is not installed, errors\n    $ <bold>mise where node@20</bold>\n    /home/jdx/.local/share/mise/installs/node/20.0.0\n\n    # Show the current, active install directory of node\n    # Errors if node is not referenced in any .tool-version file\n    $ <bold>mise where node</bold>\n    /home/jdx/.local/share/mise/installs/node/20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cli/which.rs",
    "content": "use std::sync::Arc;\n\nuse crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::dirs::SHIMS;\nuse crate::file;\nuse crate::toolset::{Toolset, ToolsetBuilder};\nuse eyre::{Result, bail};\nuse itertools::Itertools;\n\n/// Shows the path that a tool's bin points to.\n///\n/// Use this to figure out what version of a tool is currently active.\n#[derive(Debug, clap::Args)]\n#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]\npub struct Which {\n    /// The bin to look up\n    #[clap(required_unless_present = \"complete\")]\n    pub bin_name: Option<String>,\n\n    /// Use a specific tool@version\n    /// e.g.: `mise which npm --tool=node@20`\n    #[clap(short, long, value_name = \"TOOL@VERSION\", verbatim_doc_comment)]\n    pub tool: Option<ToolArg>,\n\n    #[clap(long, hide = true)]\n    pub complete: bool,\n\n    /// Show the plugin name instead of the path\n    #[clap(long, conflicts_with = \"version\")]\n    pub plugin: bool,\n\n    /// Show the version instead of the path\n    #[clap(long, conflicts_with = \"plugin\")]\n    pub version: bool,\n}\n\nimpl Which {\n    pub async fn run(self) -> Result<()> {\n        let config = Config::get().await?;\n        if self.complete {\n            return self.complete(&config).await;\n        }\n        let ts = self.get_toolset(&config).await?;\n\n        let bin_name = self.bin_name.clone().unwrap();\n        match ts.which(&config, &bin_name).await {\n            Some((p, tv)) => {\n                if self.version {\n                    miseprintln!(\"{}\", tv.version);\n                } else if self.plugin {\n                    miseprintln!(\"{p}\");\n                } else {\n                    let path = p.which(&config, &tv, &bin_name).await?;\n                    miseprintln!(\"{}\", path.unwrap().display());\n                }\n                Ok(())\n            }\n            None => {\n                if self.has_shim(&bin_name) {\n                    bail!(\n                        \"{bin_name} is a mise bin however it is not currently active. Use `mise use` to activate it in this directory.\"\n                    )\n                } else {\n                    bail!(\"{bin_name} is not a mise bin. Perhaps you need to install it first.\",)\n                }\n            }\n        }\n    }\n    async fn complete(&self, config: &Arc<Config>) -> Result<()> {\n        let ts = self.get_toolset(config).await?;\n        let bins = ts\n            .list_paths(config)\n            .await\n            .into_iter()\n            .flat_map(|p| file::ls(&p).unwrap_or_default())\n            .map(|p| p.file_name().unwrap().to_string_lossy().to_string())\n            .unique()\n            .sorted()\n            .collect_vec();\n        for bin in bins {\n            println!(\"{bin}\");\n        }\n        Ok(())\n    }\n    async fn get_toolset(&self, config: &Arc<Config>) -> Result<Toolset> {\n        let mut tsb = ToolsetBuilder::new();\n        if let Some(tool) = &self.tool {\n            tsb = tsb.with_args(std::slice::from_ref(tool));\n        }\n        let ts = tsb.build(config).await?;\n        Ok(ts)\n    }\n    fn has_shim(&self, shim: &str) -> bool {\n        SHIMS.join(shim).exists()\n    }\n}\n\nstatic AFTER_LONG_HELP: &str = color_print::cstr!(\n    r#\"<bold><underline>Examples:</underline></bold>\n\n    $ <bold>mise which node</bold>\n    /home/username/.local/share/mise/installs/node/20.0.0/bin/node\n\n    $ <bold>mise which node --plugin</bold>\n    node\n\n    $ <bold>mise which node --version</bold>\n    20.0.0\n\"#\n);\n"
  },
  {
    "path": "src/cmd.rs",
    "content": "use std::collections::HashSet;\nuse std::ffi::{OsStr, OsString};\nuse std::fmt::{Debug, Display, Formatter};\nuse std::io::{BufRead, BufReader, Write};\nuse std::path::{Path, PathBuf};\nuse std::process::{Command, ExitStatus, Stdio};\nuse std::sync::atomic::{AtomicU8, Ordering};\nuse std::sync::mpsc::channel;\nuse std::sync::{Arc, Condvar, Mutex, MutexGuard, RwLock};\nuse std::thread;\nuse std::time::Duration;\n\nuse crate::redactions::Redactor;\nuse color_eyre::Result;\nuse duct::{Expression, IntoExecutablePath};\nuse eyre::{Context, bail};\n#[cfg(not(any(test, target_os = \"windows\")))]\nuse signal_hook::consts::{SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2};\n#[cfg(not(any(test, target_os = \"windows\")))]\nuse signal_hook::iterator::Signals;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::config::Settings;\nuse crate::env;\nuse crate::env::PATH_KEY;\nuse crate::errors::Error::ScriptFailed;\nuse crate::file::display_path;\nuse crate::path_env::PathEnv;\nuse crate::ui::progress_report::SingleReport;\n\n/// Create a command with any number of of positional arguments\n///\n/// may be different types (anything that implements [`Into<OsString>`](https://doc.rust-lang.org/std/convert/trait.From.html)).\n/// See also the [`cmd`](fn.cmd.html) function, which takes a collection of arguments.\n///\n/// # Example\n///\n/// ```\n///     use std::path::Path;\n///     use mise::cmd;\n///\n///     let arg1 = \"foo\";\n///     let arg2 = \"bar\".to_owned();\n///     let arg3 = Path::new(\"baz\");\n///\n///     let output = cmd!(\"echo\", arg1, arg2, arg3).read();\n///\n///     assert_eq!(\"foo bar baz\", output.unwrap());\n/// ```\n#[macro_export]\nmacro_rules! cmd {\n    ( $program:expr $(, $arg:expr )* $(,)? ) => {\n        {\n            use std::ffi::OsString;\n            let args: std::vec::Vec<OsString> = std::vec![$( Into::<OsString>::into($arg) ),*];\n            $crate::cmd::cmd($program, args)\n        }\n    };\n}\n\n/// Create a command with any number of of positional arguments, which may be\n/// different types (anything that implements\n/// [`Into<OsString>`](https://doc.rust-lang.org/std/convert/trait.From.html)).\n/// See also the [`cmd`](fn.cmd.html) function, which takes a collection of\n/// arguments.\n///\n/// # Example\n///\n/// ```\n///     use std::path::Path;\n///     use mise::cmd;\n///\n///     let arg1 = \"foo\";\n///     let arg2 = \"bar\".to_owned();\n///     let arg3 = Path::new(\"baz\");\n///\n///     let output = cmd!(\"echo\", arg1, arg2, arg3).read();\n///\n///     assert_eq!(\"foo bar baz\", output.unwrap());\n/// ```\npub fn cmd<T, U>(program: T, args: U) -> Expression\nwhere\n    T: IntoExecutablePath,\n    U: IntoIterator,\n    U::Item: Into<OsString>,\n{\n    let program = program.to_executable();\n    let args: Vec<OsString> = args.into_iter().map(Into::<OsString>::into).collect();\n\n    let display_name = program.to_string_lossy();\n    let display_args = args\n        .iter()\n        .map(|s| s.to_string_lossy())\n        .collect::<Vec<_>>()\n        .join(\" \");\n    let display_command = [display_name.into(), display_args].join(\" \");\n    debug!(\"$ {display_command}\");\n\n    duct::cmd(program, args)\n}\n\npub struct CmdLineRunner<'a> {\n    cmd: Command,\n    pr: Option<&'a dyn SingleReport>,\n    pr_arc: Option<Arc<Box<dyn SingleReport>>>,\n    stdin: Option<String>,\n    redactor: Redactor,\n    raw: bool,\n    pass_signals: bool,\n    on_stdout: Option<Box<dyn Fn(String) + Send + 'a>>,\n    on_stderr: Option<Box<dyn Fn(String) + Send + 'a>>,\n    timeout: Option<Duration>,\n}\n\nconst GUARD_RUNNING: u8 = 0;\nconst GUARD_CANCELLED: u8 = 1;\nconst GUARD_TIMED_OUT: u8 = 2;\n\nfn wait_for_cancel_or_deadline<'a>(\n    cvar: &'a Condvar,\n    mut guard: MutexGuard<'a, bool>,\n    deadline: std::time::Instant,\n) -> (MutexGuard<'a, bool>, bool) {\n    loop {\n        if *guard {\n            return (guard, true);\n        }\n        let remaining = deadline.saturating_duration_since(std::time::Instant::now());\n        if remaining.is_zero() {\n            return (guard, false);\n        }\n        let (g, result) = cvar.wait_timeout(guard, remaining).unwrap();\n        guard = g;\n        if result.timed_out() {\n            return (guard, false);\n        }\n    }\n}\n\nstruct TimeoutGuard {\n    state: Arc<AtomicU8>,\n    cancel: Arc<(Mutex<bool>, Condvar)>,\n    timeout: Duration,\n}\n\nimpl TimeoutGuard {\n    fn new(timeout: Duration, pid: u32) -> Self {\n        let state = Arc::new(AtomicU8::new(GUARD_RUNNING));\n        let cancel = Arc::new((Mutex::new(false), Condvar::new()));\n        let state_clone = state.clone();\n        let cancel_clone = cancel.clone();\n        thread::spawn(move || {\n            let (lock, cvar) = &*cancel_clone;\n            let guard = lock.lock().unwrap();\n            let deadline = std::time::Instant::now() + timeout;\n            let (guard, cancelled) = wait_for_cancel_or_deadline(cvar, guard, deadline);\n            if cancelled {\n                return;\n            }\n            if state_clone\n                .compare_exchange(\n                    GUARD_RUNNING,\n                    GUARD_TIMED_OUT,\n                    Ordering::AcqRel,\n                    Ordering::Acquire,\n                )\n                .is_err()\n            {\n                return;\n            }\n            #[cfg(unix)]\n            {\n                let pid = nix::unistd::Pid::from_raw(pid as i32);\n                let _ = nix::sys::signal::kill(pid, nix::sys::signal::Signal::SIGTERM);\n                drop(guard);\n                let guard = lock.lock().unwrap();\n                let grace_deadline = std::time::Instant::now() + Duration::from_secs(5);\n                let (_guard, cancelled) = wait_for_cancel_or_deadline(cvar, guard, grace_deadline);\n                if !cancelled {\n                    let _ = nix::sys::signal::kill(pid, nix::sys::signal::Signal::SIGKILL);\n                }\n            }\n            #[cfg(windows)]\n            {\n                drop(guard);\n                // TODO: Windows lacks graceful shutdown parity with Unix.\n                // Currently force-kills immediately via taskkill /F with no grace period.\n                // Consider using GenerateConsoleCtrlEvent for CTRL_C_EVENT before force kill.\n                let _ = Command::new(\"taskkill\")\n                    .args([\"/F\", \"/PID\", &pid.to_string()])\n                    .stdout(Stdio::null())\n                    .stderr(Stdio::null())\n                    .status();\n            }\n        });\n        Self {\n            state,\n            cancel,\n            timeout,\n        }\n    }\n\n    fn cancel(&self) {\n        self.state\n            .compare_exchange(\n                GUARD_RUNNING,\n                GUARD_CANCELLED,\n                Ordering::AcqRel,\n                Ordering::Acquire,\n            )\n            .ok();\n        let (lock, cvar) = &*self.cancel;\n        *lock.lock().unwrap() = true;\n        cvar.notify_one();\n    }\n\n    fn timed_out(&self) -> Option<Duration> {\n        (self.state.load(Ordering::Acquire) == GUARD_TIMED_OUT).then_some(self.timeout)\n    }\n}\n\nimpl Drop for TimeoutGuard {\n    fn drop(&mut self) {\n        self.cancel();\n    }\n}\n\nstatic OUTPUT_LOCK: Mutex<()> = Mutex::new(());\n\nstatic RUNNING_PIDS: Lazy<Mutex<HashSet<u32>>> = Lazy::new(Default::default);\n\nimpl<'a> CmdLineRunner<'a> {\n    pub fn new<P: AsRef<OsStr>>(program: P) -> Self {\n        let mut cmd = Command::new(program);\n        cmd.stdin(Stdio::null());\n        cmd.stdout(Stdio::piped());\n        cmd.stderr(Stdio::piped());\n\n        Self {\n            cmd,\n            pr: None,\n            pr_arc: None,\n            stdin: None,\n            redactor: Default::default(),\n            raw: false,\n            pass_signals: false,\n            on_stdout: None,\n            on_stderr: None,\n            timeout: None,\n        }\n    }\n\n    #[cfg(unix)]\n    pub fn kill_all(signal: nix::sys::signal::Signal) {\n        let pids = RUNNING_PIDS.lock().unwrap();\n        for pid in pids.iter() {\n            let pid = *pid as i32;\n            trace!(\"{signal}: {pid}\");\n            if let Err(e) = nix::sys::signal::kill(nix::unistd::Pid::from_raw(pid), signal) {\n                debug!(\"Failed to kill cmd {pid}: {e}\");\n            }\n        }\n    }\n\n    #[cfg(windows)]\n    pub fn kill_all() {\n        let pids = RUNNING_PIDS.lock().unwrap();\n        for pid in pids.iter() {\n            if let Err(e) = Command::new(\"taskkill\")\n                .arg(\"/F\")\n                .arg(\"/T\")\n                .arg(\"/PID\")\n                .arg(pid.to_string())\n                .spawn()\n            {\n                warn!(\"Failed to kill cmd {pid}: {e}\");\n            }\n        }\n    }\n\n    pub fn stdin<T: Into<Stdio>>(mut self, cfg: T) -> Self {\n        self.cmd.stdin(cfg);\n        self\n    }\n\n    pub fn stdout<T: Into<Stdio>>(mut self, cfg: T) -> Self {\n        self.cmd.stdout(cfg);\n        self\n    }\n\n    pub fn stderr<T: Into<Stdio>>(mut self, cfg: T) -> Self {\n        self.cmd.stderr(cfg);\n        self\n    }\n\n    pub fn redact(mut self, redactions: impl IntoIterator<Item = String>) -> Self {\n        self.redactor = self.redactor.with_additional(redactions);\n        self\n    }\n\n    pub fn with_on_stdout<F: Fn(String) + Send + 'a>(mut self, on_stdout: F) -> Self {\n        self.on_stdout = Some(Box::new(on_stdout));\n        self\n    }\n\n    pub fn with_on_stderr<F: Fn(String) + Send + 'a>(mut self, on_stderr: F) -> Self {\n        self.on_stderr = Some(Box::new(on_stderr));\n        self\n    }\n\n    pub fn current_dir<P: AsRef<Path>>(mut self, dir: P) -> Self {\n        self.cmd.current_dir(dir);\n        self\n    }\n\n    pub fn env_clear(mut self) -> Self {\n        self.cmd.env_clear();\n        self\n    }\n\n    pub fn env<K, V>(mut self, key: K, val: V) -> Self\n    where\n        K: AsRef<OsStr>,\n        V: AsRef<OsStr>,\n    {\n        self.cmd.env(key, val);\n        self\n    }\n    pub fn envs<I, K, V>(mut self, vars: I) -> Self\n    where\n        I: IntoIterator<Item = (K, V)>,\n        K: AsRef<OsStr>,\n        V: AsRef<OsStr>,\n    {\n        self.cmd.envs(vars);\n        self\n    }\n\n    pub fn prepend_path(mut self, paths: Vec<PathBuf>) -> eyre::Result<Self> {\n        let existing = self\n            .get_env(&PATH_KEY)\n            .map(|c| c.to_owned())\n            .unwrap_or_else(|| env::var_os(&*PATH_KEY).unwrap());\n        let mut path_env = PathEnv::from_iter(env::split_paths(&existing));\n        for p in paths {\n            path_env.add(p);\n        }\n        self.cmd.env(&*PATH_KEY, path_env.join());\n        Ok(self)\n    }\n\n    fn get_env(&self, key: &str) -> Option<&OsStr> {\n        for (k, v) in self.cmd.get_envs() {\n            if k == key {\n                return v;\n            }\n        }\n        None\n    }\n\n    pub fn opt_args<S: AsRef<OsStr>>(mut self, arg: &str, values: Option<Vec<S>>) -> Self {\n        if let Some(values) = values {\n            for value in values {\n                self.cmd.arg(arg);\n                self.cmd.arg(value);\n            }\n        }\n        self\n    }\n\n    pub fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {\n        self.cmd.arg(arg.as_ref());\n        self\n    }\n\n    pub fn args<I, S>(mut self, args: I) -> Self\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd.args(args);\n        self\n    }\n\n    pub fn with_pr(mut self, pr: &'a dyn SingleReport) -> Self {\n        self.pr = Some(pr);\n        self\n    }\n    pub fn with_pr_arc(mut self, pr: Arc<Box<dyn SingleReport>>) -> Self {\n        self.pr_arc = Some(pr);\n        self\n    }\n    pub fn raw(mut self, raw: bool) -> Self {\n        self.raw = raw;\n        self\n    }\n\n    pub fn with_pass_signals(&mut self) -> &mut Self {\n        self.pass_signals = true;\n        self\n    }\n\n    pub fn with_timeout(mut self, timeout: Duration) -> Self {\n        self.timeout = Some(timeout);\n        self\n    }\n\n    pub fn stdin_string(mut self, input: impl Into<String>) -> Self {\n        self.cmd.stdin(Stdio::piped());\n        self.stdin = Some(input.into());\n        self\n    }\n\n    #[allow(clippy::readonly_write_lock)]\n    pub fn execute(mut self) -> Result<()> {\n        static RAW_LOCK: RwLock<()> = RwLock::new(());\n        let read_lock = RAW_LOCK.read().unwrap();\n        debug!(\"$ {self}\");\n        if Settings::get().raw || self.raw {\n            drop(read_lock);\n            let _write_lock = RAW_LOCK.write().unwrap();\n            return self.execute_raw();\n        }\n        let mut cp = self\n            .spawn_with_etxtbsy_retry()\n            .wrap_err_with(|| format!(\"failed to execute command: {self}\"))?;\n        let id = cp.id();\n        RUNNING_PIDS.lock().unwrap().insert(id);\n        trace!(\"Started process: {id} for {}\", self.get_program());\n        let (tx, rx) = channel();\n        if let Some(stdout) = cp.stdout.take() {\n            thread::spawn({\n                let name = self.to_string();\n                let tx = tx.clone();\n                move || {\n                    for line in BufReader::new(stdout).lines() {\n                        match line {\n                            Ok(line) => {\n                                let _ = tx.send(ChildProcessOutput::Stdout(line));\n                            }\n                            Err(e) => warn!(\"Failed to read stdout for {name}: {e}\"),\n                        }\n                    }\n                }\n            });\n        }\n        if let Some(stderr) = cp.stderr.take() {\n            thread::spawn({\n                let name = self.to_string();\n                let tx = tx.clone();\n                move || {\n                    for line in BufReader::new(stderr).lines() {\n                        match line {\n                            Ok(line) => {\n                                let _ = tx.send(ChildProcessOutput::Stderr(line));\n                            }\n                            Err(e) => warn!(\"Failed to read stderr for {name}: {e}\"),\n                        }\n                    }\n                }\n            });\n        }\n        if let Some(text) = self.stdin.take() {\n            let mut stdin = cp.stdin.take().unwrap();\n            thread::spawn(move || {\n                stdin.write_all(text.as_bytes()).unwrap();\n            });\n        }\n        #[cfg(not(any(test, target_os = \"windows\")))]\n        let mut sighandle = None;\n        #[cfg(not(any(test, target_os = \"windows\")))]\n        if self.pass_signals {\n            let mut signals =\n                Signals::new([SIGINT, SIGTERM, SIGTERM, SIGHUP, SIGQUIT, SIGUSR1, SIGUSR2])?;\n            sighandle = Some(signals.handle());\n            let tx = tx.clone();\n            thread::spawn(move || {\n                for sig in &mut signals {\n                    let _ = tx.send(ChildProcessOutput::Signal(sig));\n                }\n            });\n        }\n        thread::spawn(move || {\n            let status = cp.wait().unwrap();\n            #[cfg(not(any(test, target_os = \"windows\")))]\n            if let Some(sighandle) = sighandle {\n                sighandle.close();\n            }\n            let _ = tx.send(ChildProcessOutput::ExitStatus(status));\n        });\n\n        let timeout_guard = self.timeout.map(|t| TimeoutGuard::new(t, id));\n\n        let mut combined_output = vec![];\n        let mut status = None;\n        for line in rx {\n            match line {\n                ChildProcessOutput::Stdout(line) => {\n                    let line = self.redactor.redact(&line);\n                    self.on_stdout(line.clone());\n                    combined_output.push((line, OutputSource::Stdout));\n                }\n                ChildProcessOutput::Stderr(line) => {\n                    let line = self.redactor.redact(&line);\n                    self.on_stderr(line.clone());\n                    combined_output.push((line, OutputSource::Stderr));\n                }\n                ChildProcessOutput::ExitStatus(s) => {\n                    status = Some(s);\n                }\n                #[cfg(not(any(test, windows)))]\n                ChildProcessOutput::Signal(sig) => {\n                    if sig != SIGINT {\n                        debug!(\"Received signal {sig}, forwarding to {id}\");\n                        let pid = nix::unistd::Pid::from_raw(id as i32);\n                        let sig = nix::sys::signal::Signal::try_from(sig).unwrap();\n                        // Ignore errors — the child may have already exited\n                        // (e.g., killed by TimeoutGuard or exited naturally).\n                        let _ = nix::sys::signal::kill(pid, sig);\n                    }\n                }\n            }\n        }\n        // Removed after rx loop drains (not inside ExitStatus arm) so kill_all\n        // can still reach this PID while output is being processed.\n        RUNNING_PIDS.lock().unwrap().remove(&id);\n        if let Some(g) = &timeout_guard {\n            g.cancel();\n        }\n\n        let status = status.unwrap();\n\n        if !status.success() {\n            if let Some(duration) = timeout_guard.as_ref().and_then(|g| g.timed_out()) {\n                bail!(\"timed out after {duration:?}\");\n            }\n            self.on_error(combined_output, status)?;\n        }\n\n        Ok(())\n    }\n\n    fn execute_raw(mut self) -> Result<()> {\n        let mut cp = self.spawn_with_etxtbsy_retry()?;\n        let timeout_guard = self.timeout.map(|t| TimeoutGuard::new(t, cp.id()));\n        let status = cp.wait()?;\n        if let Some(g) = &timeout_guard {\n            g.cancel();\n        }\n        if !status.success() {\n            if let Some(duration) = timeout_guard.as_ref().and_then(|g| g.timed_out()) {\n                bail!(\"timed out after {duration:?}\");\n            }\n            return self.on_error(vec![], status);\n        }\n        Ok(())\n    }\n\n    /// Retry spawning a process if it fails with ETXTBSY (Text file busy).\n    /// This can happen on Linux when executing a binary that was just written/extracted,\n    /// as the file descriptor may not be fully closed yet.\n    fn spawn_with_etxtbsy_retry(&mut self) -> std::io::Result<std::process::Child> {\n        let mut attempt = 0;\n        loop {\n            match self.cmd.spawn() {\n                Ok(child) => return Ok(child),\n                Err(err) if Self::is_etxtbsy(&err) && attempt < 3 => {\n                    attempt += 1;\n                    trace!(\"retrying spawn after ETXTBSY (attempt {}/3)\", attempt);\n                    // Exponential backoff: 50ms, 100ms, 200ms\n                    std::thread::sleep(std::time::Duration::from_millis(50 * (1 << (attempt - 1))));\n                }\n                Err(err) => return Err(err),\n            }\n        }\n    }\n\n    #[cfg(unix)]\n    fn is_etxtbsy(err: &std::io::Error) -> bool {\n        err.raw_os_error() == Some(nix::errno::Errno::ETXTBSY as i32)\n    }\n\n    #[cfg(not(unix))]\n    fn is_etxtbsy(_err: &std::io::Error) -> bool {\n        false\n    }\n\n    fn on_stdout(&self, line: String) {\n        let _lock = OUTPUT_LOCK.lock().unwrap();\n        if let Some(on_stdout) = &self.on_stdout {\n            on_stdout(line);\n            return;\n        }\n        if let Some(pr) = self\n            .pr\n            .or(self.pr_arc.as_ref().map(|arc| arc.as_ref().as_ref()))\n        {\n            if !line.trim().is_empty() {\n                pr.set_message(line)\n            }\n        } else {\n            let mut stdout = std::io::stdout().lock();\n            let _ = if console::colors_enabled() {\n                writeln!(stdout, \"{line}\\x1b[0m\")\n            } else {\n                writeln!(stdout, \"{line}\")\n            };\n        }\n    }\n\n    fn on_stderr(&self, line: String) {\n        let _lock = OUTPUT_LOCK.lock().unwrap();\n        if let Some(on_stderr) = &self.on_stderr {\n            on_stderr(line);\n            return;\n        }\n        match self\n            .pr\n            .or(self.pr_arc.as_ref().map(|arc| arc.as_ref().as_ref()))\n        {\n            Some(pr) => {\n                if !line.trim().is_empty() {\n                    pr.println(line)\n                }\n            }\n            None => {\n                let mut stderr = std::io::stderr().lock();\n                let _ = if console::colors_enabled_stderr() {\n                    writeln!(stderr, \"{line}\\x1b[0m\")\n                } else {\n                    writeln!(stderr, \"{line}\")\n                };\n            }\n        }\n    }\n\n    fn on_error(&self, output: Vec<(String, OutputSource)>, status: ExitStatus) -> Result<()> {\n        match self\n            .pr\n            .or(self.pr_arc.as_ref().map(|arc| arc.as_ref().as_ref()))\n        {\n            Some(pr) => {\n                error!(\"{} failed\", self.get_program());\n                if self.on_stdout.is_none() {\n                    // Stdout was hidden behind the progress indicator\n                    // (pr.set_message) so replay it on failure. Only replay\n                    // stdout — stderr was already printed during execution\n                    // via pr.println.\n                    let stdout_only: String = output\n                        .into_iter()\n                        .filter(|(_, source)| matches!(source, OutputSource::Stdout))\n                        .map(|(line, _)| line)\n                        .collect::<Vec<_>>()\n                        .join(\"\\n\");\n                    if !stdout_only.trim().is_empty() {\n                        pr.println(stdout_only);\n                    }\n                }\n            }\n            None => {\n                // eprintln!(\"{}\", output);\n            }\n        }\n        Err(ScriptFailed(self.get_program(), Some(status)))?\n    }\n\n    fn get_program(&self) -> String {\n        display_path(PathBuf::from(self.cmd.get_program()))\n    }\n\n    fn get_args(&self) -> Vec<String> {\n        self.cmd\n            .get_args()\n            .map(|s| s.to_string_lossy().to_string())\n            .collect::<Vec<_>>()\n    }\n}\n\nimpl Display for CmdLineRunner<'_> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let args = self.get_args().join(\" \");\n        write!(f, \"{} {args}\", self.get_program())\n    }\n}\n\nimpl Debug for CmdLineRunner<'_> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let args = self.get_args().join(\" \");\n        write!(f, \"{} {args}\", self.get_program())\n    }\n}\n\n/// Tracks whether an output line came from stdout or stderr,\n/// so on_error can decide which lines need replaying.\nenum OutputSource {\n    Stdout,\n    Stderr,\n}\n\nenum ChildProcessOutput {\n    Stdout(String),\n    Stderr(String),\n    ExitStatus(ExitStatus),\n    #[cfg(not(any(test, target_os = \"windows\")))]\n    Signal(i32),\n}\n\n/// Run a command asynchronously with `kill_on_drop(true)` so that timeouts\n/// (via `tokio::time::timeout`) actually terminate the subprocess.\n///\n/// This variant **clears** the environment and sets only the provided `env` —\n/// use it for backends that pass a full env from `dependency_env()`.\npub async fn cmd_read_async<I, K, V>(program: &str, args: &[&str], env: I) -> Result<String>\nwhere\n    I: IntoIterator<Item = (K, V)>,\n    K: AsRef<OsStr>,\n    V: AsRef<OsStr>,\n{\n    let display_args = args.join(\" \");\n    debug!(\"$ {program} {display_args}\");\n\n    let output = tokio::process::Command::new(program)\n        .args(args)\n        .env_clear()\n        .envs(env)\n        .stdin(Stdio::null())\n        .stdout(Stdio::piped())\n        .stderr(Stdio::piped())\n        .kill_on_drop(true)\n        .output()\n        .await\n        .wrap_err_with(|| format!(\"failed to execute command: {program} {display_args}\"))?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        bail!(\n            \"{program} {display_args} failed: exit code {}\\n{}\",\n            output.status.code().unwrap_or(-1),\n            stderr.trim()\n        );\n    }\n\n    let stdout = String::from_utf8(output.stdout)\n        .wrap_err_with(|| format!(\"{program} produced invalid UTF-8 output\"))?;\n    Ok(stdout.trim_end().to_string())\n}\n\n/// Like [`cmd_read_async`] but **inherits** the current process environment,\n/// only adding the provided extra variables on top.\n///\n/// Use this for core plugins that need the ambient PATH / locale / etc.\npub async fn cmd_read_async_inherited_env<I, K, V>(\n    program: &str,\n    args: &[&str],\n    extra_env: I,\n) -> Result<String>\nwhere\n    I: IntoIterator<Item = (K, V)>,\n    K: AsRef<OsStr>,\n    V: AsRef<OsStr>,\n{\n    let display_args = args.join(\" \");\n    debug!(\"$ {program} {display_args}\");\n\n    let output = tokio::process::Command::new(program)\n        .args(args)\n        .envs(extra_env)\n        .stdin(Stdio::null())\n        .stdout(Stdio::piped())\n        .stderr(Stdio::piped())\n        .kill_on_drop(true)\n        .output()\n        .await\n        .wrap_err_with(|| format!(\"failed to execute command: {program} {display_args}\"))?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        bail!(\n            \"{program} {display_args} failed: exit code {}\\n{}\",\n            output.status.code().unwrap_or(-1),\n            stderr.trim()\n        );\n    }\n\n    let stdout = String::from_utf8(output.stdout)\n        .wrap_err_with(|| format!(\"{program} produced invalid UTF-8 output\"))?;\n    Ok(stdout.trim_end().to_string())\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    #[tokio::test]\n    async fn test_cmd() {\n        let _config = Config::get().await.unwrap();\n        let output = cmd!(\"echo\", \"foo\", \"bar\").read().unwrap();\n        assert_eq!(\"foo bar\", output);\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/config_root.rs",
    "content": "use std::collections::HashMap;\nuse std::path::{Path, PathBuf};\nuse std::sync::{LazyLock as Lazy, Mutex};\n\nuse path_absolutize::Absolutize;\nuse xx::regex;\n\nuse crate::config::is_global_config;\nuse crate::env;\n\nstatic CONFIG_ROOT_CACHE: Lazy<Mutex<HashMap<PathBuf, PathBuf>>> =\n    Lazy::new(|| Mutex::new(HashMap::new()));\n\npub fn reset() {\n    CONFIG_ROOT_CACHE.lock().unwrap().clear();\n}\n\npub fn config_root(path: &Path) -> PathBuf {\n    if is_global_config(path) {\n        return env::MISE_GLOBAL_CONFIG_ROOT.to_path_buf();\n    }\n    let path = path\n        .absolutize()\n        .map(|p| p.to_path_buf())\n        .unwrap_or_else(|_| path.to_path_buf());\n    if let Some(cached) = CONFIG_ROOT_CACHE.lock().unwrap().get(&path).cloned() {\n        return cached;\n    }\n    let parts = path\n        .components()\n        .map(|c| c.as_os_str().to_string_lossy().to_string())\n        .collect::<Vec<_>>();\n    let filename = parts.last().map(|p| p.as_str()).unwrap_or_default();\n    let parent = parts\n        .iter()\n        .nth_back(1)\n        .map(|p| p.as_str())\n        .unwrap_or_default();\n    let grandparent = parts\n        .iter()\n        .nth_back(2)\n        .map(|p| p.as_str())\n        .unwrap_or_default();\n    let great_grandparent = parts\n        .iter()\n        .nth_back(3)\n        .map(|p| p.as_str())\n        .unwrap_or_default();\n    let parent_path = || path.parent().unwrap().to_path_buf();\n    let grandparent_path = || parent_path().parent().unwrap().to_path_buf();\n    let great_grandparent_path = || grandparent_path().parent().unwrap().to_path_buf();\n    let great_great_grandparent_path = || great_grandparent_path().parent().unwrap().to_path_buf();\n    let is_mise_dir = |d: &str| d == \"mise\" || d == \".mise\";\n    let is_config_filename = |f: &str| {\n        f == \"config.toml\" || f == \"config.local.toml\" || regex!(r\"config\\..+\\.toml\").is_match(f)\n    };\n    let out = if parent == \"conf.d\" && is_mise_dir(grandparent) {\n        if great_grandparent == \".config\" {\n            great_great_grandparent_path()\n        } else {\n            great_grandparent_path()\n        }\n    } else if is_mise_dir(parent) && is_config_filename(filename) {\n        if grandparent == \".config\" {\n            great_grandparent_path()\n        } else {\n            grandparent_path()\n        }\n    } else if parent == \".config\" {\n        grandparent_path()\n    } else {\n        parent_path()\n    };\n    CONFIG_ROOT_CACHE.lock().unwrap().insert(path, out.clone());\n    out\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_config_root() {\n        for p in &[\n            \"/foo/bar/.config/mise/conf.d/config.toml\",\n            \"/foo/bar/.config/mise/conf.d/foo.toml\",\n            \"/foo/bar/.config/mise/config.local.toml\",\n            \"/foo/bar/.config/mise/config.toml\",\n            \"/foo/bar/.config/mise.local.toml\",\n            \"/foo/bar/.config/mise.toml\",\n            \"/foo/bar/.mise.env.toml\",\n            \"/foo/bar/.mise.local.toml\",\n            \"/foo/bar/.mise.toml\",\n            \"/foo/bar/.mise/conf.d/config.toml\",\n            \"/foo/bar/.mise/conf.d/foo.toml\",\n            \"/foo/bar/.mise/config.local.toml\",\n            \"/foo/bar/.mise/config.toml\",\n            \"/foo/bar/.tool-versions\",\n            \"/foo/bar/mise.env.toml\",\n            \"/foo/bar/mise.local.toml\",\n            \"/foo/bar/mise.toml\",\n            \"/foo/bar/mise/config.local.toml\",\n            \"/foo/bar/mise/config.toml\",\n            \"/foo/bar/.config/mise/config.env.toml\",\n            \"/foo/bar/.config/mise.env.toml\",\n            \"/foo/bar/.mise/config.env.toml\",\n            \"/foo/bar/.mise.env.toml\",\n        ] {\n            println!(\"{p}\");\n            assert_eq!(config_root(Path::new(p)), PathBuf::from(\"/foo/bar\"));\n        }\n    }\n\n    #[test]\n    fn test_config_root_mise_dir() {\n        for p in &[\n            \"/foo/mise/.config/mise/conf.d/config.toml\",\n            \"/foo/mise/.config/mise/conf.d/foo.toml\",\n            \"/foo/mise/.config/mise/config.local.toml\",\n            \"/foo/mise/.config/mise/config.toml\",\n            \"/foo/mise/.config/mise.local.toml\",\n            \"/foo/mise/.config/mise.toml\",\n            \"/foo/mise/.mise.env.toml\",\n            \"/foo/mise/.mise.local.toml\",\n            \"/foo/mise/.mise.toml\",\n            \"/foo/mise/.mise/conf.d/config.toml\",\n            \"/foo/mise/.mise/conf.d/foo.toml\",\n            \"/foo/mise/.mise/config.local.toml\",\n            \"/foo/mise/.mise/config.toml\",\n            \"/foo/mise/.tool-versions\",\n            \"/foo/mise/mise.env.toml\",\n            \"/foo/mise/mise.local.toml\",\n            \"/foo/mise/mise.toml\",\n            \"/foo/mise/mise/config.local.toml\",\n            \"/foo/mise/mise/config.toml\",\n            \"/foo/mise/.config/mise/config.env.toml\",\n            \"/foo/mise/.config/mise.env.toml\",\n            \"/foo/mise/.mise/config.env.toml\",\n            \"/foo/mise/.mise.env.toml\",\n        ] {\n            println!(\"{p}\");\n            assert_eq!(config_root(Path::new(p)), PathBuf::from(\"/foo/mise\"));\n        }\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/diagnostic.rs",
    "content": "#![allow(unused_assignments)] // Fields are read by miette's derive macros at runtime\n\nuse crate::file::display_path;\nuse miette::{Diagnostic, NamedSource, SourceSpan};\nuse std::fmt;\nuse std::path::{Path, PathBuf};\nuse thiserror::Error;\n\n/// A TOML parsing error with source location information for rich display.\n#[derive(Debug, Error, Diagnostic)]\n#[error(\"Invalid TOML in config file: {}\", path.display())]\n#[diagnostic(code(mise::config::parse_error))]\npub struct TomlParseError {\n    path: PathBuf,\n    #[source_code]\n    src: NamedSource<String>,\n    #[label(\"{message}\")]\n    span: SourceSpan,\n    message: String,\n}\n\n/// A diagnostic error that stores pre-rendered miette output.\n/// This allows miette's fancy formatting to be preserved when wrapped in eyre.\n#[derive(Debug)]\npub struct MiseDiagnostic {\n    /// Short description for Display\n    message: String,\n    /// Pre-rendered miette output for rich display\n    rendered: String,\n}\n\nimpl fmt::Display for MiseDiagnostic {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.message)\n    }\n}\n\nimpl std::error::Error for MiseDiagnostic {}\n\nimpl MiseDiagnostic {\n    /// Create a new diagnostic from any miette Diagnostic\n    pub fn new<D: Diagnostic + Send + Sync + 'static>(diagnostic: D) -> Self {\n        let message = diagnostic.to_string();\n        let rendered = format!(\"{:?}\", miette::Report::new(diagnostic));\n        MiseDiagnostic { message, rendered }\n    }\n\n    /// Get the pre-rendered miette output\n    pub fn render(&self) -> &str {\n        &self.rendered\n    }\n}\n\n/// Create an eyre error from a toml::de::Error with rich source context.\npub fn toml_parse_error(err: &toml::de::Error, source: &str, path: &Path) -> eyre::Report {\n    let message = err.message().to_string();\n\n    // Get the byte span from toml error\n    let span = err\n        .span()\n        .map(|r| SourceSpan::from((r.start, r.end.saturating_sub(r.start))))\n        .unwrap_or_else(|| SourceSpan::from((0, 0)));\n\n    let diagnostic = TomlParseError {\n        path: path.to_path_buf(),\n        src: NamedSource::new(display_path(path), source.to_string()),\n        span,\n        message,\n    };\n\n    eyre::Report::new(MiseDiagnostic::new(diagnostic))\n}\n"
  },
  {
    "path": "src/config/config_file/idiomatic_version/mod.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::backend::BackendList;\nuse crate::cli::args::BackendArg;\nuse crate::config::config_file::ConfigFile;\nuse crate::toolset::{ToolRequest, ToolRequestSet, ToolSource};\n\nuse super::ConfigFileType;\n\npub mod package_json;\n\n#[derive(Debug, Clone)]\npub struct IdiomaticVersionFile {\n    path: PathBuf,\n    tools: ToolRequestSet,\n}\n\nimpl IdiomaticVersionFile {\n    #[allow(dead_code)]\n    #[cfg(test)]\n    pub fn init(path: PathBuf) -> Self {\n        Self {\n            path,\n            tools: ToolRequestSet::new(),\n        }\n    }\n\n    pub async fn parse(path: PathBuf, plugins: BackendList) -> Result<Self> {\n        let source = ToolSource::IdiomaticVersionFile(path.clone());\n        let mut tools = ToolRequestSet::new();\n\n        for plugin in plugins {\n            match plugin.parse_idiomatic_file(&path).await {\n                Ok(versions) => {\n                    for v in versions {\n                        let tr = ToolRequest::new(plugin.ba().clone(), &v, source.clone())?;\n                        tools.add_version(tr, &source);\n                    }\n                }\n                Err(e) => {\n                    trace!(\"skipping {} for {}: {}\", path.display(), plugin.id(), e);\n                    continue;\n                }\n            }\n        }\n\n        Ok(Self { tools, path })\n    }\n}\n\nimpl ConfigFile for IdiomaticVersionFile {\n    fn config_type(&self) -> ConfigFileType {\n        ConfigFileType::IdiomaticVersion(vec![])\n    }\n\n    fn get_path(&self) -> &Path {\n        self.path.as_path()\n    }\n\n    #[cfg_attr(coverage_nightly, coverage(off))]\n    fn remove_tool(&self, _fa: &BackendArg) -> Result<()> {\n        unimplemented!()\n    }\n\n    #[cfg_attr(coverage_nightly, coverage(off))]\n    fn replace_versions(\n        &self,\n        _plugin_name: &BackendArg,\n        _versions: Vec<ToolRequest>,\n    ) -> Result<()> {\n        unimplemented!()\n    }\n\n    #[cfg_attr(coverage_nightly, coverage(off))]\n    fn save(&self) -> Result<()> {\n        unimplemented!()\n    }\n\n    #[cfg_attr(coverage_nightly, coverage(off))]\n    fn dump(&self) -> Result<String> {\n        unimplemented!()\n    }\n\n    fn source(&self) -> ToolSource {\n        ToolSource::IdiomaticVersionFile(self.path.clone())\n    }\n\n    fn to_tool_request_set(&self) -> Result<ToolRequestSet> {\n        Ok(self.tools.clone())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::backend::{Backend, VersionInfo};\n    use crate::cli::args::{BackendArg, BackendResolution};\n    use crate::config::Config;\n    use crate::install_context::InstallContext;\n    use crate::toolset::ToolVersion;\n    use async_trait::async_trait;\n    use std::sync::Arc;\n\n    #[derive(Debug)]\n    struct MockBackend {\n        ba: Arc<BackendArg>,\n        fail: bool,\n        version: Option<String>,\n    }\n\n    impl MockBackend {\n        fn new(short: &str, fail: bool, version: Option<String>) -> Self {\n            let ba = BackendArg::new_raw(\n                short.to_string(),\n                None,\n                short.to_string(),\n                None,\n                BackendResolution::new(false),\n            );\n            Self {\n                ba: Arc::new(ba),\n                fail,\n                version,\n            }\n        }\n    }\n\n    #[async_trait]\n    impl Backend for MockBackend {\n        fn ba(&self) -> &Arc<BackendArg> {\n            &self.ba\n        }\n\n        async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n            Ok(vec![])\n        }\n\n        async fn install_version_(\n            &self,\n            _ctx: &InstallContext,\n            _tv: ToolVersion,\n        ) -> Result<ToolVersion> {\n            unimplemented!()\n        }\n\n        async fn parse_idiomatic_file(&self, _path: &Path) -> Result<Vec<String>> {\n            if self.fail {\n                eyre::bail!(\"mock error\");\n            }\n            if let Some(v) = &self.version {\n                Ok(vec![v.clone()])\n            } else {\n                Ok(vec![])\n            }\n        }\n    }\n\n    #[tokio::test]\n    async fn test_idiomatic_parse_error_propagation() {\n        let _config = Config::get().await.unwrap();\n        let path = PathBuf::from(\".tool-versions\");\n        let backend1 = Arc::new(MockBackend::new(\"node\", true, None));\n        let backend2 = Arc::new(MockBackend::new(\n            \"python\",\n            false,\n            Some(\"3.10.0\".to_string()),\n        ));\n        let plugins: BackendList = vec![backend1, backend2];\n\n        let result = IdiomaticVersionFile::parse(path, plugins).await;\n\n        assert!(result.is_ok(), \"Should not propagate error from backend1\");\n\n        let file = result.unwrap();\n        let trs = file.to_tool_request_set().unwrap();\n        let tools: Vec<_> = trs.into_iter().collect();\n        assert_eq!(tools.len(), 1);\n        let (ba, versions, _) = &tools[0];\n        assert_eq!(ba.short, \"python\");\n        assert_eq!(versions[0].version(), \"3.10.0\");\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/idiomatic_version/package_json.rs",
    "content": "use crate::file;\nuse eyre::Result;\nuse serde::Deserialize;\nuse serde::de::Deserializer;\nuse std::path::Path;\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct PackageJsonData {\n    dev_engines: Option<DevEngines>,\n    package_manager: Option<String>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct DevEngines {\n    #[serde(default, deserialize_with = \"deserialize_one_or_first\")]\n    runtime: Option<DevEngine>,\n    #[serde(default, deserialize_with = \"deserialize_one_or_first\")]\n    package_manager: Option<DevEngine>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\nstruct DevEngine {\n    name: Option<String>,\n    version: Option<String>,\n}\n\n/// Deserialize a field that may be a single object or an array (take the first element).\n/// The npm devEngines spec allows both forms.\nfn deserialize_one_or_first<'de, D>(\n    deserializer: D,\n) -> std::result::Result<Option<DevEngine>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    #[derive(Deserialize)]\n    #[serde(untagged)]\n    enum OneOrMany {\n        One(DevEngine),\n        Many(Vec<DevEngine>),\n    }\n\n    match Option::<OneOrMany>::deserialize(deserializer)? {\n        None => Ok(None),\n        Some(OneOrMany::One(engine)) => Ok(Some(engine)),\n        Some(OneOrMany::Many(engines)) => Ok(engines.into_iter().next()),\n    }\n}\n\nimpl PackageJsonData {\n    fn parse(path: &Path) -> Result<Self> {\n        let contents = file::read_to_string(path)?;\n        let pkg: PackageJsonData = serde_json::from_str(&contents)?;\n        Ok(pkg)\n    }\n\n    /// Extract a runtime version for the given tool name.\n    fn runtime_version(&self, tool_name: &str) -> Option<String> {\n        self.dev_engines\n            .as_ref()\n            .and_then(|de| de.runtime.as_ref())\n            .filter(|r| r.name.as_deref() == Some(tool_name))\n            .and_then(|r| r.version.as_deref())\n            .map(simplify_semver)\n            .filter(|v| !v.is_empty())\n    }\n\n    /// Extract a package manager version for the given tool name.\n    /// Checks devEngines.packageManager first, then falls back to the packageManager field.\n    fn package_manager_version(&self, tool_name: &str) -> Option<String> {\n        // Try devEngines.packageManager first\n        self.dev_engines\n            .as_ref()\n            .and_then(|de| de.package_manager.as_ref())\n            .filter(|pm| pm.name.as_deref() == Some(tool_name))\n            .and_then(|pm| pm.version.as_deref())\n            .map(simplify_semver)\n            .filter(|v| !v.is_empty())\n            .or_else(|| {\n                // Fall back to packageManager field (e.g. \"pnpm@9.1.0+sha256.abc\")\n                let pm_field = self.package_manager.as_deref()?;\n                let (name, rest) = pm_field.split_once('@')?;\n                if name != tool_name {\n                    return None;\n                }\n                // Strip +sha... suffix\n                let version = rest.split('+').next().unwrap_or(rest).trim();\n                if version.is_empty() {\n                    return None;\n                }\n                Some(version.to_string())\n            })\n    }\n}\n\n/// Simplify a semver range to a mise-compatible version prefix.\n///\n/// Strips range operators (>=, ^, ~) and trailing `.0` components to produce\n/// a prefix that mise can match against. For exact versions, returns as-is.\n/// Upper-bound operators (`<`, `<=`) are ignored since they don't indicate\n/// a version to install.\n///\n/// # TODO\n/// This doesn't handle all edge cases correctly. For example, `^20.0.1` should not\n/// match `20.0.0`, but our simplified approach strips it to `20` which would match.\n/// Full semver range support may be added in the future.\nfn simplify_semver(input: &str) -> String {\n    let input = input.trim();\n    if input == \"*\" || input == \"x\" {\n        return \"latest\".to_string();\n    }\n\n    // Upper-bound operators don't indicate a version to install\n    if input.starts_with('<') || input.starts_with(\"<=\") {\n        return String::new();\n    }\n\n    // Strip leading range operators\n    let version = input\n        .trim_start_matches(\">=\")\n        .trim_start_matches('>')\n        .trim_start_matches('^')\n        .trim_start_matches('~')\n        .trim_start_matches('=')\n        .trim();\n\n    if version.is_empty() {\n        return \"latest\".to_string();\n    }\n\n    // Replace wildcard segments (x, *) with truncation\n    // e.g. \"18.x\" -> \"18\", \"18.2.*\" -> \"18.2\"\n    let parts: Vec<&str> = version\n        .split('.')\n        .take_while(|p| *p != \"x\" && *p != \"*\")\n        .collect();\n    if parts.is_empty() {\n        return \"latest\".to_string();\n    }\n    if parts.len() < version.split('.').count() {\n        // Had wildcard segments, return truncated prefix\n        return parts.join(\".\");\n    }\n\n    let had_operator = version != input;\n\n    // Only strip trailing .0 components when a range operator was present,\n    // since ranges imply prefix matching. Exact versions are kept as-is.\n    if had_operator {\n        let trimmed: Vec<&str> = match parts.as_slice() {\n            [major, \"0\", \"0\"] => vec![major],\n            [major, minor, \"0\"] => vec![major, minor],\n            _ => parts,\n        };\n        trimmed.join(\".\")\n    } else {\n        version.to_string()\n    }\n}\n\npub fn parse(path: &Path, tool_name: &str) -> Result<Vec<String>> {\n    let pkg = PackageJsonData::parse(path)?;\n    // We ignore unknown tools in package.json\n    let v = match tool_name {\n        \"node\" | \"deno\" => pkg.runtime_version(tool_name),\n        \"bun\" => pkg\n            .runtime_version(tool_name)\n            .or_else(|| pkg.package_manager_version(tool_name)),\n        \"npm\" | \"yarn\" | \"pnpm\" => pkg.package_manager_version(tool_name),\n        _ => None,\n    };\n    if let Some(v) = v {\n        Ok(vec![v])\n    } else {\n        Ok(vec![])\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fs;\n    use tempfile::tempdir;\n\n    #[test]\n    fn test_simplify_semver() {\n        assert_eq!(simplify_semver(\">=18.0.0\"), \"18\");\n        assert_eq!(simplify_semver(\"^20.0.0\"), \"20\");\n        assert_eq!(simplify_semver(\"~18.2.0\"), \"18.2\");\n        assert_eq!(simplify_semver(\"9.1.0\"), \"9.1.0\");\n        assert_eq!(simplify_semver(\"9.1.2\"), \"9.1.2\");\n        assert_eq!(simplify_semver(\"18\"), \"18\");\n        assert_eq!(simplify_semver(\"*\"), \"latest\");\n        assert_eq!(simplify_semver(\"x\"), \"latest\");\n        assert_eq!(simplify_semver(\">= 18.0.0\"), \"18\");\n        assert_eq!(simplify_semver(\"^18.2.0\"), \"18.2\");\n        assert_eq!(simplify_semver(\"~18.0.0\"), \"18\");\n        assert_eq!(simplify_semver(\"=18.0.0\"), \"18\");\n    }\n\n    #[test]\n    fn test_parse_package_json() {\n        let dir = tempdir().unwrap();\n        let path = dir.path().join(\"package.json\");\n        fs::write(\n            &path,\n            r#\"{\n                \"devEngines\": {\n                    \"packageManager\": {\n                        \"name\": \"yarn\",\n                        \"version\": \"1.22.19\"\n                    },\n                    \"runtime\": {\n                        \"name\": \"node\",\n                        \"version\": \"20.0.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n\n        assert_eq!(parse(&path, \"yarn\").unwrap(), vec![\"1.22.19\".to_string()]);\n        assert_eq!(parse(&path, \"node\").unwrap(), vec![\"20.0.0\".to_string()]);\n    }\n\n    #[test]\n    fn test_bun_logic() {\n        let dir = tempdir().unwrap();\n        let path = dir.path().join(\"package.json\");\n        fs::write(\n            &path,\n            r#\"{\n                \"packageManager\": \"bun@1.0.0\"\n            }\"#,\n        )\n        .unwrap();\n\n        assert_eq!(parse(&path, \"bun\").unwrap(), vec![\"1.0.0\".to_string()]);\n        assert_eq!(parse(&path, \"node\").unwrap(), Vec::<String>::new());\n    }\n\n    #[test]\n    fn test_simplify_semver_upper_bound() {\n        assert_eq!(simplify_semver(\"<18.0.0\"), \"\");\n        assert_eq!(simplify_semver(\"<=18.0.0\"), \"\");\n    }\n\n    #[test]\n    fn test_simplify_semver_wildcards() {\n        assert_eq!(simplify_semver(\"18.x\"), \"18\");\n        assert_eq!(simplify_semver(\"18.*\"), \"18\");\n        assert_eq!(simplify_semver(\"18.2.x\"), \"18.2\");\n        assert_eq!(simplify_semver(\"18.2.*\"), \"18.2\");\n    }\n\n    #[test]\n    fn test_runtime_version() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": {\n                        \"name\": \"node\",\n                        \"version\": \">=20.0.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"node\"), Some(\"20\".to_string()));\n        assert_eq!(pkg.runtime_version(\"bun\"), None);\n    }\n\n    #[test]\n    fn test_runtime_version_bun() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": {\n                        \"name\": \"bun\",\n                        \"version\": \"^1.0.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"bun\"), Some(\"1\".to_string()));\n        assert_eq!(pkg.runtime_version(\"node\"), None);\n    }\n\n    #[test]\n    fn test_runtime_version_array_form() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": [\n                        { \"name\": \"node\", \"version\": \">=22.0.0\" },\n                        { \"name\": \"bun\", \"version\": \">=1.0.0\" }\n                    ]\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"node\"), Some(\"22\".to_string()));\n    }\n\n    #[test]\n    fn test_runtime_version_missing_name() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": {\n                        \"version\": \">=20.0.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"node\"), None);\n    }\n\n    #[test]\n    fn test_package_manager_version_dev_engines() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"packageManager\": {\n                        \"name\": \"pnpm\",\n                        \"version\": \">=9.0.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.package_manager_version(\"pnpm\"), Some(\"9\".to_string()));\n        assert_eq!(pkg.package_manager_version(\"yarn\"), None);\n    }\n\n    #[test]\n    fn test_package_manager_version_field() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"packageManager\": \"pnpm@9.1.0+sha256.abcdef\"\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(\n            pkg.package_manager_version(\"pnpm\"),\n            Some(\"9.1.0\".to_string())\n        );\n        assert_eq!(pkg.package_manager_version(\"yarn\"), None);\n    }\n\n    #[test]\n    fn test_package_manager_version_no_hash() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"packageManager\": \"yarn@4.1.0\"\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(\n            pkg.package_manager_version(\"yarn\"),\n            Some(\"4.1.0\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_dev_engines_overrides_package_manager_field() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"packageManager\": {\n                        \"name\": \"pnpm\",\n                        \"version\": \"^10.0.0\"\n                    }\n                },\n                \"packageManager\": \"pnpm@9.1.0\"\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.package_manager_version(\"pnpm\"), Some(\"10\".to_string()));\n    }\n\n    #[test]\n    fn test_missing_fields() {\n        let pkg: PackageJsonData = serde_json::from_str(r#\"{}\"#).unwrap();\n        assert_eq!(pkg.runtime_version(\"node\"), None);\n        assert_eq!(pkg.package_manager_version(\"pnpm\"), None);\n    }\n\n    #[test]\n    fn test_empty_dev_engines() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {}\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"node\"), None);\n        assert_eq!(pkg.package_manager_version(\"pnpm\"), None);\n    }\n\n    #[test]\n    fn test_bun_as_package_manager() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"packageManager\": \"bun@1.2.0\"\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"bun\"), None);\n        assert_eq!(\n            pkg.package_manager_version(\"bun\"),\n            Some(\"1.2.0\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_deno_dev_engines() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": {\n                        \"name\": \"deno\",\n                        \"version\": \"1.40.0\"\n                    }\n                }\n            }\"#,\n        )\n        .unwrap();\n        assert_eq!(pkg.runtime_version(\"deno\"), Some(\"1.40.0\".to_string()));\n    }\n\n    #[test]\n    fn test_engines_field_ignored() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"engines\": {\n                    \"node\": \">=18.0.0\",\n                    \"pnpm\": \"9.0.0\"\n                }\n            }\"#,\n        )\n        .unwrap();\n        // Should ignore engines field\n        assert_eq!(pkg.runtime_version(\"node\"), None);\n        assert_eq!(pkg.package_manager_version(\"pnpm\"), None);\n    }\n\n    #[test]\n    fn test_engines_field_does_not_interfere() {\n        let pkg: PackageJsonData = serde_json::from_str(\n            r#\"{\n                \"devEngines\": {\n                    \"runtime\": {\n                        \"name\": \"node\",\n                        \"version\": \"20.0.0\"\n                    }\n                },\n                \"engines\": {\n                    \"node\": \"18.0.0\"\n                }\n            }\"#,\n        )\n        .unwrap();\n        // Should ignore engines and pick devEngines\n        assert_eq!(pkg.runtime_version(\"node\"), Some(\"20.0.0\".to_string()));\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/min_version.rs",
    "content": "use std::fmt;\nuse versions::Versioning;\n#[derive(Debug, Clone, Default, PartialEq, Eq)]\npub struct MinVersionSpec {\n    hard: Option<Versioning>,\n    soft: Option<Versioning>,\n}\n\nimpl MinVersionSpec {\n    pub fn new(hard: Option<Versioning>, soft: Option<Versioning>) -> Option<Self> {\n        if hard.is_none() && soft.is_none() {\n            None\n        } else {\n            Some(Self { hard, soft })\n        }\n    }\n\n    pub fn hard(&self) -> Option<&Versioning> {\n        self.hard.as_ref()\n    }\n\n    pub fn set_hard(&mut self, version: Versioning) {\n        self.hard = Some(version);\n    }\n\n    pub fn soft(&self) -> Option<&Versioning> {\n        self.soft.as_ref()\n    }\n\n    pub fn set_soft(&mut self, version: Versioning) {\n        self.soft = Some(version);\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.hard.is_none() && self.soft.is_none()\n    }\n\n    pub fn hard_violation(&self, current: &Versioning) -> Option<&Versioning> {\n        self.hard().filter(|required| current < *required)\n    }\n\n    pub fn soft_violation(&self, current: &Versioning) -> Option<&Versioning> {\n        self.soft().filter(|recommended| current < *recommended)\n    }\n\n    pub fn merge_with(&mut self, other: &Self) {\n        if self.hard.is_none() {\n            self.hard = other.hard.clone();\n        }\n        if self.soft.is_none() {\n            self.soft = other.soft.clone();\n        }\n    }\n}\n\nimpl fmt::Display for MinVersionSpec {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match (self.hard.as_ref(), self.soft.as_ref()) {\n            (Some(h), None) => write!(f, \"{}\", h),\n            (None, Some(s)) => write!(f, \"{}\", s),\n            (Some(h), Some(s)) => write!(f, \"hard={}, soft={}\", h, s),\n            (None, None) => write!(f, \"\"),\n        }\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/mise_toml.rs",
    "content": "use eyre::{WrapErr, eyre};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse once_cell::sync::OnceCell;\nuse serde::de::Visitor;\nuse serde::{Deserializer, de};\nuse serde_derive::Deserialize;\nuse std::fmt::{Debug, Formatter};\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::{\n    collections::{BTreeMap, HashMap},\n    sync::{Mutex, MutexGuard},\n};\nuse tera::Context as TeraContext;\nuse tera::Value as TeraValue;\nuse toml_edit::{Array, DocumentMut, InlineTable, Item, Key, Value, table, value};\nuse versions::Versioning;\n\nuse crate::cli::args::{BackendArg, ToolVersionType};\nuse crate::config::config_file::{ConfigFile, TaskConfig, config_trust_root, trust, trust_check};\nuse crate::config::config_file::{config_root, toml::deserialize_arr};\nuse crate::config::env_directive::{AgeFormat, EnvDirective, EnvDirectiveOptions, RequiredValue};\nuse crate::config::settings::SettingsPartial;\nuse crate::config::{Alias, AliasMap, Config};\nuse crate::env_diff::EnvMap;\nuse crate::file::{create_dir_all, display_path};\nuse crate::hooks::{Hook, HookDef, Hooks};\nuse crate::prepare::PrepareConfig;\nuse crate::redactions::Redactions;\nuse crate::registry::REGISTRY;\nuse crate::task::{Task, TaskTemplate};\nuse crate::tera::{BASE_CONTEXT, get_tera};\nuse crate::toolset::{ToolRequest, ToolRequestSet, ToolSource, ToolVersionOptions};\nuse crate::watch_files::WatchFile;\nuse crate::{env, file};\n\nuse super::diagnostic::toml_parse_error;\nuse super::{ConfigFileType, min_version::MinVersionSpec};\n\n/// Convert a `toml::Value` to a `toml_edit::Value` for serialization.\nfn toml_value_to_edit(v: toml::Value) -> Value {\n    match v {\n        toml::Value::String(s) => Value::from(s),\n        toml::Value::Integer(i) => Value::from(i),\n        toml::Value::Float(f) => Value::from(f),\n        toml::Value::Boolean(b) => Value::from(b),\n        toml::Value::Datetime(dt) => {\n            // Parse the datetime string back into a toml_edit datetime\n            dt.to_string()\n                .parse::<toml_edit::Datetime>()\n                .map(Value::from)\n                .unwrap_or_else(|_| Value::from(dt.to_string()))\n        }\n        toml::Value::Array(arr) => {\n            let mut edit_arr = Array::new();\n            for item in arr {\n                edit_arr.push(toml_value_to_edit(item));\n            }\n            Value::Array(edit_arr)\n        }\n        toml::Value::Table(table) => {\n            let mut edit_table = InlineTable::new();\n            for (k, v) in table {\n                edit_table.insert(k, toml_value_to_edit(v));\n            }\n            Value::InlineTable(edit_table)\n        }\n    }\n}\n\n#[derive(Default, Deserialize)]\npub struct MiseToml {\n    #[serde(rename = \"_\")]\n    custom: Option<toml::Value>,\n    #[serde(default, deserialize_with = \"deserialize_min_version\")]\n    min_version: Option<MinVersionSpec>,\n    #[serde(skip)]\n    context: TeraContext,\n    #[serde(skip)]\n    path: PathBuf,\n    #[serde(default, alias = \"dotenv\", deserialize_with = \"deserialize_arr\")]\n    env_file: Vec<String>,\n    #[serde(default)]\n    env: EnvList,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    env_path: Vec<String>,\n    #[serde(default)]\n    alias: AliasMap,\n    #[serde(default)]\n    tool_alias: AliasMap,\n    #[serde(default)]\n    shell_alias: IndexMap<String, String>,\n    #[serde(skip)]\n    doc: Mutex<OnceCell<DocumentMut>>,\n    #[serde(default)]\n    hooks: IndexMap<Hooks, HookDef>,\n    #[serde(default)]\n    tools: Mutex<IndexMap<BackendArg, MiseTomlToolList>>,\n    #[serde(default)]\n    plugins: HashMap<String, String>,\n    #[serde(default)]\n    redactions: Redactions,\n    #[serde(default)]\n    task_config: TaskConfig,\n    #[serde(default)]\n    tasks: Tasks,\n    #[serde(default)]\n    task_templates: TaskTemplates,\n    #[serde(default)]\n    watch_files: Vec<WatchFile>,\n    #[serde(default)]\n    prepare: Option<PrepareConfig>,\n    #[serde(default)]\n    vars: EnvList,\n    #[serde(default)]\n    settings: SettingsPartial,\n    /// Marks this config as a monorepo root, enabling target path syntax for tasks\n    #[serde(default)]\n    experimental_monorepo_root: Option<bool>,\n    /// Configuration for monorepo task discovery\n    #[serde(default)]\n    monorepo: Option<MonorepoConfig>,\n}\n\n#[derive(Debug, Default, Clone)]\npub struct MiseTomlToolList(Vec<MiseTomlTool>);\n\n#[derive(Debug, Clone)]\npub struct MiseTomlTool {\n    pub tt: ToolVersionType,\n    pub options: Option<ToolVersionOptions>,\n}\n\n#[derive(Debug, Default, Clone)]\npub struct Tasks(pub BTreeMap<String, Task>);\n\n#[derive(Debug, Default, Clone)]\npub struct TaskTemplates(pub IndexMap<String, TaskTemplate>);\n\n#[derive(Debug, Default, Clone)]\npub struct EnvList(pub(crate) Vec<EnvDirective>);\n\n/// Configuration for [monorepo] section in mise.toml\n#[derive(Debug, Default, Clone, Deserialize)]\npub struct MonorepoConfig {\n    /// Explicit list of config roots for monorepo task discovery.\n    /// Supports single-level glob patterns (*).\n    #[serde(default)]\n    pub config_roots: Vec<String>,\n}\n\nimpl EnvList {\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\nimpl MiseToml {\n    fn enforce_min_version_fallback(body: &str) -> eyre::Result<()> {\n        if let Ok(val) = toml::from_str::<toml::Value>(body)\n            && let Some(min_val) = val.get(\"min_version\")\n        {\n            let mut hard_req: Option<versions::Versioning> = None;\n            let mut soft_req: Option<versions::Versioning> = None;\n            match min_val {\n                toml::Value::String(s) => {\n                    hard_req = versions::Versioning::new(s);\n                }\n                toml::Value::Table(t) => {\n                    if let Some(toml::Value::String(s)) = t.get(\"hard\") {\n                        hard_req = versions::Versioning::new(s);\n                    }\n                    if let Some(toml::Value::String(s)) = t.get(\"soft\") {\n                        soft_req = versions::Versioning::new(s);\n                    }\n                }\n                _ => {}\n            }\n            if let Some(spec) =\n                crate::config::config_file::min_version::MinVersionSpec::new(hard_req, soft_req)\n            {\n                crate::config::Config::enforce_min_version_spec(&spec)?;\n            }\n        }\n        Ok(())\n    }\n    fn contains_template_syntax(input: &str) -> bool {\n        input.contains(\"{{\") || input.contains(\"{%\") || input.contains(\"{#\")\n    }\n\n    pub fn init(path: &Path) -> Self {\n        let mut context = BASE_CONTEXT.clone();\n        context.insert(\n            \"config_root\",\n            config_root::config_root(path).to_str().unwrap(),\n        );\n        let mut rf = Self {\n            path: path.to_path_buf(),\n            context,\n            ..Default::default()\n        };\n        rf.update_context_env(env::PRISTINE_ENV.clone());\n        rf\n    }\n\n    pub fn from_file(path: &Path) -> eyre::Result<Self> {\n        let body = file::read_to_string(path)?;\n        Self::from_str(&body, path)\n    }\n\n    pub fn from_str(body: &str, path: &Path) -> eyre::Result<Self> {\n        trust_check(path)?;\n        trace!(\"parsing: {}\", display_path(path));\n        let des = toml::Deserializer::parse(body).map_err(|e| toml_parse_error(&e, body, path))?;\n        let de_res = serde_ignored::deserialize(des, |p| {\n            warn!(\"unknown field in {}: {p}\", display_path(path));\n        });\n        let mut rf: MiseToml = match de_res {\n            Ok(rf) => rf,\n            Err(err) => {\n                Self::enforce_min_version_fallback(body)?;\n                return Err(toml_parse_error(&err, body, path));\n            }\n        };\n        rf.context = BASE_CONTEXT.clone();\n        rf.context.insert(\n            \"config_root\",\n            config_root::config_root(path).to_str().unwrap(),\n        );\n        rf.update_context_env(env::PRISTINE_ENV.clone());\n        rf.path = path.to_path_buf();\n        let project_root = rf.project_root().map(|p| p.to_path_buf());\n        for task in rf.tasks.0.values_mut() {\n            task.config_source.clone_from(&rf.path);\n            task.config_root = project_root.clone();\n        }\n        // trace!(\"{}\", rf.dump()?);\n        Ok(rf)\n    }\n\n    fn doc(&self) -> eyre::Result<DocumentMut> {\n        self.doc\n            .lock()\n            .unwrap()\n            .get_or_try_init(|| {\n                let body = file::read_to_string(&self.path).unwrap_or_default();\n                Ok(body.parse()?)\n            })\n            .cloned()\n    }\n\n    fn doc_mut(&self) -> eyre::Result<MutexGuard<'_, OnceCell<DocumentMut>>> {\n        self.doc()?;\n        Ok(self.doc.lock().unwrap())\n    }\n\n    pub fn set_backend_alias(&mut self, fa: &BackendArg, to: &str) -> eyre::Result<()> {\n        self.doc_mut()?\n            .get_mut()\n            .unwrap()\n            .entry(\"tool_alias\")\n            .or_insert_with(table)\n            .as_table_like_mut()\n            .unwrap()\n            .insert(&fa.short, value(to));\n        Ok(())\n    }\n\n    pub fn set_alias(&mut self, fa: &BackendArg, from: &str, to: &str) -> eyre::Result<()> {\n        self.tool_alias\n            .entry(fa.short.to_string())\n            .or_default()\n            .versions\n            .insert(from.into(), to.into());\n        self.doc_mut()?\n            .get_mut()\n            .unwrap()\n            .entry(\"tool_alias\")\n            .or_insert_with(table)\n            .as_table_like_mut()\n            .unwrap()\n            .entry(&fa.to_string())\n            .or_insert_with(table)\n            .as_table_like_mut()\n            .unwrap()\n            .entry(\"versions\")\n            .or_insert_with(table)\n            .as_table_like_mut()\n            .unwrap()\n            .insert(from, value(to));\n        Ok(())\n    }\n\n    pub fn remove_backend_alias(&mut self, fa: &BackendArg) -> eyre::Result<()> {\n        let mut doc = self.doc_mut()?;\n        let doc = doc.get_mut().unwrap();\n        // Remove from both tool_alias and deprecated alias sections\n        for section in [\"tool_alias\", \"alias\"] {\n            if let Some(aliases) = doc.get_mut(section).and_then(|v| v.as_table_mut()) {\n                aliases.remove(&fa.short);\n                if aliases.is_empty() {\n                    doc.as_table_mut().remove(section);\n                }\n            }\n        }\n        Ok(())\n    }\n\n    pub fn remove_alias(&mut self, fa: &BackendArg, from: &str) -> eyre::Result<()> {\n        // Remove from both tool_alias and deprecated alias in memory\n        for alias_map in [&mut self.tool_alias, &mut self.alias] {\n            if let Some(aliases) = alias_map.get_mut(&fa.short) {\n                aliases.versions.shift_remove(from);\n                if aliases.versions.is_empty() && aliases.backend.is_none() {\n                    alias_map.shift_remove(&fa.short);\n                }\n            }\n        }\n        let mut doc = self.doc_mut()?;\n        let doc = doc.get_mut().unwrap();\n        // Remove from both tool_alias and deprecated alias sections in doc\n        for section in [\"tool_alias\", \"alias\"] {\n            if let Some(aliases) = doc.get_mut(section).and_then(|v| v.as_table_mut()) {\n                if let Some(alias) = aliases\n                    .get_mut(&fa.to_string())\n                    .and_then(|v| v.as_table_mut())\n                {\n                    if let Some(versions) = alias.get_mut(\"versions\").and_then(|v| v.as_table_mut())\n                    {\n                        versions.remove(from);\n                        if versions.is_empty() {\n                            alias.remove(\"versions\");\n                        }\n                    }\n                    if alias.is_empty() {\n                        aliases.remove(&fa.to_string());\n                    }\n                }\n                if aliases.is_empty() {\n                    doc.as_table_mut().remove(section);\n                }\n            }\n        }\n        Ok(())\n    }\n\n    pub fn set_shell_alias(&mut self, name: &str, command: &str) -> eyre::Result<()> {\n        self.shell_alias.insert(name.into(), command.into());\n        self.doc_mut()?\n            .get_mut()\n            .unwrap()\n            .entry(\"shell_alias\")\n            .or_insert_with(table)\n            .as_table_like_mut()\n            .unwrap()\n            .insert(name, value(command));\n        Ok(())\n    }\n\n    pub fn remove_shell_alias(&mut self, name: &str) -> eyre::Result<()> {\n        self.shell_alias.shift_remove(name);\n        let mut doc = self.doc_mut()?;\n        let doc = doc.get_mut().unwrap();\n        if let Some(shell_alias) = doc.get_mut(\"shell_alias\").and_then(|v| v.as_table_mut()) {\n            shell_alias.remove(name);\n            if shell_alias.is_empty() {\n                doc.as_table_mut().remove(\"shell_alias\");\n            }\n        }\n        Ok(())\n    }\n\n    pub fn update_env<V: Into<Value>>(&mut self, key: &str, value: V) -> eyre::Result<()> {\n        let mut doc = self.doc_mut()?;\n        let mut env_tbl = doc\n            .get_mut()\n            .unwrap()\n            .entry(\"env\")\n            .or_insert_with(table)\n            .as_table_mut()\n            .unwrap();\n        let key_parts = key.split('.').collect_vec();\n        for (i, k) in key_parts.iter().enumerate() {\n            if i == key_parts.len() - 1 {\n                let k = get_key_with_decor(env_tbl, k);\n                env_tbl.insert_formatted(&k, toml_edit::value(value));\n                break;\n            } else if !env_tbl.contains_key(k) {\n                env_tbl.insert_formatted(&Key::from(*k), toml_edit::table());\n            }\n            env_tbl = env_tbl.get_mut(k).unwrap().as_table_mut().unwrap();\n        }\n        Ok(())\n    }\n\n    pub fn update_env_age(\n        &mut self,\n        key: &str,\n        value: &str,\n        format: Option<AgeFormat>,\n    ) -> eyre::Result<()> {\n        let mut doc = self.doc_mut()?;\n        let mut env_tbl = doc\n            .get_mut()\n            .unwrap()\n            .entry(\"env\")\n            .or_insert_with(table)\n            .as_table_mut()\n            .unwrap();\n\n        // Create the age inline table\n        let mut outer_table = InlineTable::new();\n\n        // Check if we need the complex format or can use simplified form\n        match format {\n            Some(AgeFormat::Zstd) => {\n                // Non-default format, use full form: {age = {value = \"...\", format = \"zstd\"}}\n                let mut age_table = InlineTable::new();\n                age_table.insert(\"value\", value.into());\n                age_table.insert(\"format\", \"zstd\".into());\n                outer_table.insert(\"age\", Value::InlineTable(age_table));\n            }\n            Some(AgeFormat::Raw) | None => {\n                // Default format or no format, use simplified form: {age = \"...\"}\n                outer_table.insert(\"age\", value.into());\n            }\n        }\n\n        let key_parts = key.split('.').collect_vec();\n        for (i, k) in key_parts.iter().enumerate() {\n            if i == key_parts.len() - 1 {\n                let k = get_key_with_decor(env_tbl, k);\n                env_tbl\n                    .insert_formatted(&k, toml_edit::Item::Value(Value::InlineTable(outer_table)));\n                break;\n            } else if !env_tbl.contains_key(k) {\n                env_tbl.insert_formatted(&Key::from(*k), toml_edit::table());\n            }\n            env_tbl = env_tbl.get_mut(k).unwrap().as_table_mut().unwrap();\n        }\n        Ok(())\n    }\n\n    pub fn remove_env(&mut self, key: &str) -> eyre::Result<()> {\n        let mut doc = self.doc_mut()?;\n        let env_tbl = doc\n            .get_mut()\n            .unwrap()\n            .entry(\"env\")\n            .or_insert_with(table)\n            .as_table_mut()\n            .unwrap();\n        env_tbl.remove(key);\n        Ok(())\n    }\n\n    // Merge base OS env vars with env sections from this file,\n    // so they are available for templating.\n    // Note this only merges regular key-value variables; referenced files are not resolved.\n    fn update_context_env(&mut self, mut base_env: EnvMap) {\n        let env_vars = self\n            .env\n            .0\n            .iter()\n            .filter_map(|e| match e {\n                EnvDirective::Val(key, value, _) => Some((key.clone(), value.clone())),\n                _ => None,\n            })\n            .collect::<IndexMap<_, _>>();\n        base_env.extend(env_vars);\n        self.context.insert(\"env\", &base_env);\n    }\n\n    fn parse_template(&self, input: &str) -> eyre::Result<String> {\n        self.parse_template_with_context(&self.context, input)\n    }\n\n    fn parse_template_with_context(\n        &self,\n        context: &TeraContext,\n        input: &str,\n    ) -> eyre::Result<String> {\n        if !Self::contains_template_syntax(input) {\n            return Ok(input.to_string());\n        }\n        let dir = self.path.parent();\n        let output = get_tera(dir).render_str(input, context).wrap_err_with(|| {\n            let p = display_path(&self.path);\n            eyre!(\"failed to parse template {input} in {p}\")\n        })?;\n        Ok(output)\n    }\n}\n\nimpl ConfigFile for MiseToml {\n    fn config_type(&self) -> ConfigFileType {\n        ConfigFileType::MiseToml\n    }\n\n    fn get_path(&self) -> &Path {\n        self.path.as_path()\n    }\n\n    fn min_version(&self) -> Option<&MinVersionSpec> {\n        self.min_version.as_ref()\n    }\n\n    fn plugins(&self) -> eyre::Result<HashMap<String, String>> {\n        self.plugins\n            .clone()\n            .into_iter()\n            .map(|(k, v)| {\n                let v = self.parse_template(&v)?;\n                Ok((k, v))\n            })\n            .collect()\n    }\n\n    fn env_entries(&self) -> eyre::Result<Vec<EnvDirective>> {\n        let env_entries = self.env.0.iter().cloned();\n        let path_entries = self\n            .env_path\n            .iter()\n            .map(|p| EnvDirective::Path(p.clone(), Default::default()))\n            .collect_vec();\n        let env_files = self\n            .env_file\n            .iter()\n            .map(|p| EnvDirective::File(p.clone(), Default::default()))\n            .collect_vec();\n        let all = path_entries\n            .into_iter()\n            .chain(env_files)\n            .chain(env_entries)\n            .collect::<Vec<_>>();\n        Ok(all)\n    }\n\n    fn vars_entries(&self) -> eyre::Result<Vec<EnvDirective>> {\n        Ok(self.vars.0.clone())\n    }\n\n    fn tasks(&self) -> Vec<&Task> {\n        self.tasks.0.values().collect()\n    }\n\n    fn task_templates(&self) -> IndexMap<String, TaskTemplate> {\n        self.task_templates.0.clone()\n    }\n\n    fn remove_tool(&self, fa: &BackendArg) -> eyre::Result<()> {\n        let mut tools = self.tools.lock().unwrap();\n        tools.shift_remove(fa);\n        let mut doc = self.doc_mut()?;\n        let doc = doc.get_mut().unwrap();\n        if let Some(tools) = doc.get_mut(\"tools\")\n            && let Some(tools) = tools.as_table_like_mut()\n        {\n            tools.remove(&fa.to_string());\n            if tools.is_empty() {\n                doc.as_table_mut().remove(\"tools\");\n            }\n        }\n        Ok(())\n    }\n\n    fn replace_versions(&self, ba: &BackendArg, versions: Vec<ToolRequest>) -> eyre::Result<()> {\n        trace!(\"replacing versions {ba:?} {versions:?}\");\n        let mut tools = self.tools.lock().unwrap();\n        let is_tools_sorted = is_tools_sorted(&tools); // was it previously sorted (if so we'll keep it sorted)\n        let existing = tools.entry(ba.clone()).or_default();\n        let output_empty_opts = |opts: &ToolVersionOptions| {\n            if opts.os.is_some() || !opts.install_env.is_empty() {\n                return false;\n            }\n            if let Some(reg_ba) = REGISTRY.get(ba.short.as_str()).and_then(|b| b.ba())\n                && reg_ba.opts.as_ref().is_some_and(|o| o == opts)\n            {\n                // in this case the options specified are the same as in the registry so output no options and rely on the defaults\n                return true;\n            }\n            opts.is_empty()\n        };\n        existing.0 = versions\n            .iter()\n            .map(|tr| MiseTomlTool::from(tr.clone()))\n            .collect();\n        trace!(\"done replacing versions\");\n        let mut doc = self.doc_mut()?;\n        trace!(\"got doc\");\n        let tools = doc\n            .get_mut()\n            .unwrap()\n            .entry(\"tools\")\n            .or_insert_with(table)\n            .as_table_mut()\n            .unwrap();\n\n        // create a key from the short name preserving any decorations like prefix/suffix if the key already exists\n        let key = get_key_with_decor(tools, ba.short.as_str());\n\n        // if a short name is used like \"node\", make sure we remove any long names like \"core:node\"\n        if ba.short != ba.full() {\n            tools.remove(&ba.full());\n        }\n\n        if versions.len() == 1 {\n            let options = versions[0].options();\n            if output_empty_opts(&options) {\n                tools.insert_formatted(&key, value(versions[0].version()));\n            } else {\n                let mut table = InlineTable::new();\n                table.insert(\"version\", versions[0].version().into());\n                for (k, v) in options.opts {\n                    table.insert(k, toml_value_to_edit(v));\n                }\n                if let Some(os) = options.os {\n                    let mut arr = Array::new();\n                    for o in os {\n                        arr.push(Value::from(o));\n                    }\n                    table.insert(\"os\", Value::Array(arr));\n                }\n                if !options.install_env.is_empty() {\n                    let mut env = InlineTable::new();\n                    for (k, v) in options.install_env {\n                        env.insert(k, v.into());\n                    }\n                    table.insert(\"install_env\", env.into());\n                }\n                tools.insert_formatted(&key, table.into());\n            }\n        } else {\n            let mut arr = Array::new();\n            for tr in versions {\n                let v = tr.version();\n                if output_empty_opts(&tr.options()) {\n                    arr.push(v.to_string());\n                } else {\n                    let mut table = InlineTable::new();\n                    table.insert(\"version\", v.to_string().into());\n                    for (k, v) in tr.options().opts {\n                        table.insert(k, toml_value_to_edit(v.clone()));\n                    }\n                    arr.push(table);\n                }\n            }\n            tools.insert_formatted(&key, Item::Value(Value::Array(arr)));\n        }\n\n        if is_tools_sorted {\n            tools.sort_values();\n        }\n\n        Ok(())\n    }\n\n    fn save(&self) -> eyre::Result<()> {\n        let contents = self.dump()?;\n        if let Some(parent) = self.path.parent() {\n            create_dir_all(parent)?;\n        }\n        file::write(&self.path, contents)?;\n        trust(&config_trust_root(&self.path))?;\n        Ok(())\n    }\n\n    fn dump(&self) -> eyre::Result<String> {\n        Ok(self.doc()?.to_string())\n    }\n\n    fn source(&self) -> ToolSource {\n        ToolSource::MiseToml(self.path.clone())\n    }\n\n    fn to_tool_request_set(&self) -> eyre::Result<ToolRequestSet> {\n        let source = ToolSource::MiseToml(self.path.clone());\n        let mut trs = ToolRequestSet::new();\n        let tools = self.tools.lock().unwrap();\n        let mut context = self.context.clone();\n        if let Some(config) = Config::maybe_get()\n            && let Some(env_results) = config.env_results_cached()\n        {\n            let mut env_vars: EnvMap =\n                if let Some(TeraValue::Object(existing_env)) = context.get(\"env\") {\n                    existing_env\n                        .iter()\n                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))\n                        .collect()\n                } else {\n                    env::PRISTINE_ENV.clone()\n                };\n            for key in &env_results.env_remove {\n                env_vars.remove(key);\n            }\n            env_vars.extend(\n                env_results\n                    .env\n                    .iter()\n                    .map(|(k, (v, _))| (k.clone(), v.clone())),\n            );\n            context.insert(\"env\", &env_vars);\n        }\n        if context.get(\"vars\").is_none()\n            && let Some(config) = Config::maybe_get()\n        {\n            if let Some(vars_results) = config.vars_results_cached() {\n                let vars = vars_results\n                    .vars\n                    .iter()\n                    .map(|(k, (v, _))| (k.clone(), v.clone()))\n                    .collect::<IndexMap<_, _>>();\n                context.insert(\"vars\", &vars);\n            } else if !config.vars.is_empty() {\n                context.insert(\"vars\", &config.vars);\n            }\n        }\n        for (ba, tvp) in tools.iter() {\n            for tool in &tvp.0 {\n                let version = self.parse_template_with_context(&context, &tool.tt.to_string())?;\n                let tvr = if let Some(mut options) = tool.options.clone() {\n                    // Add placeholder for version since it's not available at config load time\n                    // This preserves {{ version }} in the output for install-time rendering\n                    let mut opts_context = context.clone();\n                    opts_context.insert(\"version\", \"{{ version }}\");\n                    for v in options.opts.values_mut() {\n                        if let toml::Value::String(s) = v {\n                            *s = self.parse_template_with_context(&opts_context, s)?;\n                        }\n                    }\n                    let mut ba = ba.clone();\n                    // Start with cached options but filter out install-time-only options\n                    // when config provides its own options. This allows:\n                    // - Changing url/asset_pattern/checksum without reinstall issues\n                    // - Preserving post-install options like bin_path for binary discovery\n                    let mut ba_opts = ba.opts().clone();\n                    let install_time_keys =\n                        crate::backend::install_time_option_keys_for_type(&ba.backend_type());\n                    if !install_time_keys.is_empty() {\n                        ba_opts.opts.retain(|k, _| {\n                            // Keep option if it's NOT an install-time-only key\n                            // Also filter platform-specific variants (platforms.X.key)\n                            !install_time_keys.contains(k)\n                                && !install_time_keys.iter().any(|itk| {\n                                    k.starts_with(\"platforms.\") && k.ends_with(&format!(\".{itk}\"))\n                                })\n                        });\n                    }\n                    ba_opts.merge(&options.opts);\n                    // Re-apply registry defaults for install-time keys not overridden by user.\n                    // The filtering above strips both stale install-state cache AND registry\n                    // defaults. We want to keep registry defaults while discarding stale cache.\n                    if let Some(rt) = crate::registry::REGISTRY.get(ba.short.as_str()) {\n                        let full = ba.full();\n                        // Get structured options from registry (table-format backends)\n                        let mut registry_opts = rt.backend_options(&full);\n                        // Also parse inline options from [key=val,...] in the full string\n                        if let Some(start) = full.rfind('[')\n                            && full.ends_with(']')\n                        {\n                            let inline = crate::toolset::parse_tool_options(\n                                &full[start + 1..full.len() - 1],\n                            );\n                            for (k, v) in inline.opts {\n                                registry_opts.opts.entry(k).or_insert(v);\n                            }\n                        }\n                        for (k, v) in registry_opts.opts {\n                            ba_opts.opts.entry(k).or_insert(v);\n                        }\n                    }\n                    // Copy os and install_env from config (not cached)\n                    ba_opts.os = options.os.clone();\n                    ba_opts.install_env = options.install_env.clone();\n                    ba.set_opts(Some(ba_opts.clone()));\n                    ToolRequest::new_opts(ba.into(), &version, ba_opts, source.clone())?\n                } else {\n                    ToolRequest::new(ba.clone().into(), &version, source.clone())?\n                };\n                trs.add_version(tvr, &source);\n            }\n        }\n        Ok(trs)\n    }\n\n    fn aliases(&self) -> eyre::Result<AliasMap> {\n        // Emit deprecation warning if [alias] is used\n        if !self.alias.is_empty() {\n            deprecated!(\n                \"alias\",\n                \"[alias] is deprecated, use [tool_alias] instead in {}\",\n                display_path(&self.path)\n            );\n        }\n\n        // Merge alias and tool_alias, with tool_alias taking precedence\n        let mut combined: AliasMap = self.alias.clone();\n        for (k, v) in &self.tool_alias {\n            combined.insert(k.clone(), v.clone());\n        }\n\n        combined\n            .iter()\n            .map(|(k, v)| {\n                let versions = v\n                    .clone()\n                    .versions\n                    .into_iter()\n                    .map(|(k, v)| {\n                        let v = self.parse_template(&v)?;\n                        Ok::<(String, String), eyre::Report>((k, v))\n                    })\n                    .collect::<eyre::Result<IndexMap<_, _>>>()?;\n                Ok((\n                    k.clone(),\n                    Alias {\n                        backend: v.backend.clone(),\n                        versions,\n                    },\n                ))\n            })\n            .collect()\n    }\n\n    fn shell_aliases(&self) -> eyre::Result<IndexMap<String, String>> {\n        self.shell_alias\n            .iter()\n            .map(|(k, v)| {\n                let v = self.parse_template(v)?;\n                Ok((k.clone(), v))\n            })\n            .collect()\n    }\n\n    fn task_config(&self) -> &TaskConfig {\n        &self.task_config\n    }\n\n    fn experimental_monorepo_root(&self) -> Option<bool> {\n        self.experimental_monorepo_root\n    }\n\n    fn monorepo(&self) -> Option<&MonorepoConfig> {\n        self.monorepo.as_ref()\n    }\n\n    fn redactions(&self) -> &Redactions {\n        &self.redactions\n    }\n\n    fn watch_files(&self) -> eyre::Result<Vec<WatchFile>> {\n        self.watch_files\n            .iter()\n            .map(|wf| {\n                Ok(WatchFile {\n                    patterns: wf\n                        .patterns\n                        .iter()\n                        .map(|p| self.parse_template(p))\n                        .collect::<eyre::Result<Vec<String>>>()?,\n                    run: wf\n                        .run\n                        .as_ref()\n                        .map(|r| self.parse_template(r))\n                        .transpose()?,\n                    task: wf\n                        .task\n                        .as_ref()\n                        .map(|t| self.parse_template(t))\n                        .transpose()?,\n                })\n            })\n            .collect()\n    }\n\n    fn hooks(&self) -> eyre::Result<Vec<Hook>> {\n        Ok(self\n            .hooks\n            .iter()\n            .map(|(hook_type, def)| {\n                let mut hooks = def.clone().into_hooks(*hook_type);\n                for hook in hooks.iter_mut() {\n                    hook.script = self.parse_template(&hook.script)?;\n                    if let Some(shell) = &hook.shell {\n                        hook.shell = Some(self.parse_template(shell)?);\n                    }\n                    if let Some(task_name) = &hook.task_name {\n                        hook.task_name = Some(self.parse_template(task_name)?);\n                    }\n                }\n                eyre::Ok(hooks)\n            })\n            .collect::<eyre::Result<Vec<_>>>()?\n            .into_iter()\n            .flatten()\n            .collect())\n    }\n\n    fn prepare_config(&self) -> Option<PrepareConfig> {\n        self.prepare.clone()\n    }\n}\n\n/// Returns a [`toml_edit::Key`] from the given `key`.\n/// Preserves any surrounding whitespace (e.g. comments) if the key already exists in the provided [`toml_edit::Table`].\nfn get_key_with_decor(table: &toml_edit::Table, key: &str) -> Key {\n    let mut key = Key::from(key);\n    if let Some((k, _)) = table.get_key_value(&key) {\n        if let Some(prefix) = k.leaf_decor().prefix() {\n            key.leaf_decor_mut().set_prefix(prefix.clone());\n        }\n        if let Some(suffix) = k.leaf_decor().suffix() {\n            key.leaf_decor_mut().set_suffix(suffix.clone());\n        }\n    }\n    key\n}\n\nimpl Debug for MiseToml {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let tools = self.to_tool_request_set().unwrap().to_string();\n        let title = format!(\"MiseToml({}): {tools}\", &display_path(&self.path));\n        let mut d = f.debug_struct(&title);\n        if let Some(min_version) = &self.min_version {\n            d.field(\"min_version\", &min_version.to_string());\n        }\n        if !self.env_file.is_empty() {\n            d.field(\"env_file\", &self.env_file);\n        }\n        if let Ok(env) = self.env_entries()\n            && !env.is_empty()\n        {\n            d.field(\"env\", &env);\n        }\n        if !self.alias.is_empty() {\n            d.field(\"alias\", &self.alias);\n        }\n        if !self.plugins.is_empty() {\n            d.field(\"plugins\", &self.plugins);\n        }\n        if self.task_config.includes.is_some() {\n            d.field(\"task_config\", &self.task_config);\n        }\n        d.finish()\n    }\n}\n\nimpl Clone for MiseToml {\n    fn clone(&self) -> Self {\n        Self {\n            custom: self.custom.clone(),\n            min_version: self.min_version.clone(),\n            context: self.context.clone(),\n            path: self.path.clone(),\n            env_file: self.env_file.clone(),\n            env: self.env.clone(),\n            env_path: self.env_path.clone(),\n            alias: self.alias.clone(),\n            tool_alias: self.tool_alias.clone(),\n            shell_alias: self.shell_alias.clone(),\n            doc: Mutex::new(self.doc.lock().unwrap().clone()),\n            hooks: self.hooks.clone(),\n            tools: Mutex::new(self.tools.lock().unwrap().clone()),\n            redactions: self.redactions.clone(),\n            plugins: self.plugins.clone(),\n            tasks: self.tasks.clone(),\n            task_templates: self.task_templates.clone(),\n            task_config: self.task_config.clone(),\n            settings: self.settings.clone(),\n            watch_files: self.watch_files.clone(),\n            prepare: self.prepare.clone(),\n            vars: self.vars.clone(),\n            experimental_monorepo_root: self.experimental_monorepo_root,\n            monorepo: self.monorepo.clone(),\n        }\n    }\n}\n\nimpl From<ToolRequest> for MiseTomlTool {\n    fn from(tr: ToolRequest) -> Self {\n        match tr {\n            ToolRequest::Version {\n                version,\n                options,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::Version(version),\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n            ToolRequest::Path {\n                path,\n                options,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::Path(path),\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n            ToolRequest::Prefix {\n                prefix,\n                options,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::Prefix(prefix),\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n            ToolRequest::Ref {\n                ref_,\n                ref_type,\n                options,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::Ref(ref_, ref_type),\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n            ToolRequest::Sub {\n                sub,\n                options,\n                orig_version,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::Sub { sub, orig_version },\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n            ToolRequest::System {\n                options,\n                backend: _backend,\n                source: _source,\n            } => Self {\n                tt: ToolVersionType::System,\n                options: if options.is_empty() {\n                    None\n                } else {\n                    Some(options)\n                },\n            },\n        }\n    }\n}\n\nfn deserialize_min_version<'de, D>(deserializer: D) -> Result<Option<MinVersionSpec>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    struct MinVersionVisitor;\n\n    impl<'de> Visitor<'de> for MinVersionVisitor {\n        type Value = Option<MinVersionSpec>;\n\n        fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n            formatter.write_str(\"string or table for min_version\")\n        }\n\n        fn visit_none<E>(self) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            Ok(None)\n        }\n\n        fn visit_unit<E>(self) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            Ok(None)\n        }\n\n        fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>\n        where\n            D: Deserializer<'de>,\n        {\n            deserializer.deserialize_any(self)\n        }\n\n        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            let version = Versioning::new(v)\n                .ok_or_else(|| versions::Error::IllegalVersioning(v.to_string()))\n                .map_err(E::custom)?;\n            Ok(MinVersionSpec::new(Some(version), None))\n        }\n\n        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>\n        where\n            E: serde::de::Error,\n        {\n            self.visit_str(&v)\n        }\n\n        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>\n        where\n            M: de::MapAccess<'de>,\n        {\n            let mut hard: Option<Versioning> = None;\n            let mut soft: Option<Versioning> = None;\n            while let Some(key) = map.next_key::<String>()? {\n                match key.as_str() {\n                    \"hard\" => {\n                        if hard.is_some() {\n                            return Err(de::Error::duplicate_field(\"hard\"));\n                        }\n                        let value: String = map.next_value()?;\n                        let version = Versioning::new(&value)\n                            .ok_or_else(|| versions::Error::IllegalVersioning(value.clone()))\n                            .map_err(de::Error::custom)?;\n                        hard = Some(version);\n                    }\n                    \"soft\" => {\n                        if soft.is_some() {\n                            return Err(de::Error::duplicate_field(\"soft\"));\n                        }\n                        let value: String = map.next_value()?;\n                        let version = Versioning::new(&value)\n                            .ok_or_else(|| versions::Error::IllegalVersioning(value.clone()))\n                            .map_err(de::Error::custom)?;\n                        soft = Some(version);\n                    }\n                    other => {\n                        return Err(de::Error::unknown_field(other, &[\"hard\", \"soft\"]));\n                    }\n                }\n            }\n            Ok(MinVersionSpec::new(hard, soft))\n        }\n    }\n\n    deserializer.deserialize_option(MinVersionVisitor)\n}\n\nimpl<'de> de::Deserialize<'de> for EnvList {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct EnvManVisitor;\n\n        impl<'de> Visitor<'de> for EnvManVisitor {\n            type Value = EnvList;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"env table or array of env tables\")\n            }\n\n            fn visit_seq<S>(self, mut seq: S) -> std::result::Result<Self::Value, S::Error>\n            where\n                S: de::SeqAccess<'de>,\n            {\n                let mut env = vec![];\n                while let Some(list) = seq.next_element::<EnvList>()? {\n                    env.extend(list.0);\n                }\n                Ok(EnvList(env))\n            }\n\n            fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                let mut env = vec![];\n                while let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"_\" | \"mise\" => {\n                            #[derive(Deserialize)]\n                            #[serde(untagged)]\n                            enum MiseTomlEnvDirective {\n                                Single {\n                                    #[serde(alias = \"path\")]\n                                    value: String,\n                                    #[serde(flatten)]\n                                    options: EnvDirectiveOptions,\n                                },\n                                Multiple {\n                                    #[serde(alias = \"value\", alias = \"path\", alias = \"paths\")]\n                                    values: Vec<String>,\n                                    #[serde(flatten)]\n                                    options: EnvDirectiveOptions,\n                                },\n                            }\n\n                            impl FromStr for MiseTomlEnvDirective {\n                                type Err = String;\n                                fn from_str(s: &str) -> Result<Self, Self::Err> {\n                                    Ok(MiseTomlEnvDirective::Single {\n                                        value: s.to_string(),\n                                        options: Default::default(),\n                                    })\n                                }\n                            }\n\n                            struct EnvDirectivePythonVenv {\n                                path: String,\n                                create: bool,\n                                python: Option<String>,\n                                uv_create_args: Option<Vec<String>>,\n                                python_create_args: Option<Vec<String>>,\n                            }\n\n                            #[derive(Deserialize, Default)]\n                            #[serde(deny_unknown_fields)]\n                            struct EnvDirectivePython {\n                                #[serde(default)]\n                                venv: Option<EnvDirectivePythonVenv>,\n                            }\n\n                            #[derive(Deserialize)]\n                            struct EnvDirectives {\n                                #[serde(default, deserialize_with = \"deserialize_arr\")]\n                                path: Vec<MiseTomlEnvDirective>,\n                                #[serde(default, deserialize_with = \"deserialize_arr\")]\n                                file: Vec<MiseTomlEnvDirective>,\n                                #[serde(default, deserialize_with = \"deserialize_arr\")]\n                                source: Vec<MiseTomlEnvDirective>,\n                                #[serde(default)]\n                                python: EnvDirectivePython,\n                                #[serde(flatten)]\n                                other: BTreeMap<String, toml::Value>,\n                            }\n\n                            impl<'de> de::Deserialize<'de> for EnvDirectivePythonVenv {\n                                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n                                where\n                                    D: Deserializer<'de>,\n                                {\n                                    struct EnvDirectivePythonVenvVisitor;\n\n                                    impl<'de> Visitor<'de> for EnvDirectivePythonVenvVisitor {\n                                        type Value = EnvDirectivePythonVenv;\n                                        fn expecting(\n                                            &self,\n                                            formatter: &mut Formatter,\n                                        ) -> std::fmt::Result\n                                        {\n                                            formatter.write_str(\"python venv directive\")\n                                        }\n\n                                        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n                                        where\n                                            E: de::Error,\n                                        {\n                                            Ok(EnvDirectivePythonVenv {\n                                                path: v.into(),\n                                                create: false,\n                                                python: None,\n                                                uv_create_args: None,\n                                                python_create_args: None,\n                                            })\n                                        }\n\n                                        fn visit_map<M>(\n                                            self,\n                                            mut map: M,\n                                        ) -> Result<Self::Value, M::Error>\n                                        where\n                                            M: de::MapAccess<'de>,\n                                        {\n                                            let mut path = None;\n                                            let mut create = false;\n                                            let mut python = None;\n                                            let mut uv_create_args = None;\n                                            let mut python_create_args = None;\n                                            while let Some(key) = map.next_key::<String>()? {\n                                                match key.as_str() {\n                                                    \"path\" => {\n                                                        path = Some(map.next_value()?);\n                                                    }\n                                                    \"create\" => {\n                                                        create = map.next_value()?;\n                                                    }\n                                                    \"python\" => {\n                                                        python = Some(map.next_value()?);\n                                                    }\n                                                    \"uv_create_args\" => {\n                                                        uv_create_args = Some(map.next_value()?);\n                                                    }\n                                                    \"python_create_args\" => {\n                                                        python_create_args =\n                                                            Some(map.next_value()?);\n                                                    }\n                                                    _ => {\n                                                        return Err(de::Error::unknown_field(\n                                                            &key,\n                                                            &[\"path\", \"create\"],\n                                                        ));\n                                                    }\n                                                }\n                                            }\n                                            let path = path\n                                                .ok_or_else(|| de::Error::missing_field(\"path\"))?;\n                                            Ok(EnvDirectivePythonVenv {\n                                                path,\n                                                create,\n                                                python,\n                                                uv_create_args,\n                                                python_create_args,\n                                            })\n                                        }\n                                    }\n\n                                    const FIELDS: &[&str] = &[\"path\", \"create\"];\n                                    deserializer.deserialize_struct(\n                                        \"PythonVenv\",\n                                        FIELDS,\n                                        EnvDirectivePythonVenvVisitor,\n                                    )\n                                }\n                            }\n\n                            fn flatten_directives<F>(\n                                directives: Vec<MiseTomlEnvDirective>,\n                                constructor: F,\n                            ) -> impl Iterator<Item = EnvDirective>\n                            where\n                                F: Fn(String, EnvDirectiveOptions) -> EnvDirective + 'static,\n                            {\n                                directives.into_iter().flat_map(move |d| match d {\n                                    MiseTomlEnvDirective::Single { value, options } => {\n                                        vec![constructor(value, options)]\n                                    }\n                                    MiseTomlEnvDirective::Multiple { values, options } => values\n                                        .into_iter()\n                                        .map(|v| constructor(v, options.clone()))\n                                        .collect(),\n                                })\n                            }\n\n                            let directives = map.next_value::<EnvDirectives>()?;\n                            // TODO: parse these in the order they're defined somehow\n                            env.extend(flatten_directives(directives.path, EnvDirective::Path));\n                            env.extend(flatten_directives(directives.file, EnvDirective::File));\n                            env.extend(flatten_directives(directives.source, EnvDirective::Source));\n                            for (key, mut value) in directives.other {\n                                let mut opts = EnvDirectiveOptions::default();\n                                if let Some(table) = value.as_table_mut()\n                                    && let Some(tools) = table.remove(\"tools\")\n                                {\n                                    opts.tools = tools.as_bool().unwrap_or(false);\n                                }\n                                env.push(EnvDirective::Module(key, value, opts));\n                            }\n                            if let Some(venv) = directives.python.venv {\n                                env.push(EnvDirective::PythonVenv {\n                                    path: venv.path,\n                                    create: venv.create,\n                                    python: venv.python,\n                                    uv_create_args: venv.uv_create_args,\n                                    python_create_args: venv.python_create_args,\n                                    options: EnvDirectiveOptions {\n                                        tools: true,\n                                        redact: Some(false),\n                                        required: RequiredValue::False,\n                                    },\n                                });\n                            }\n                        }\n                        _ => {\n                            #[derive(Deserialize)]\n                            #[serde(untagged)]\n                            pub enum PrimitiveVal {\n                                Str(String),\n                                Int(i64),\n                                Bool(bool),\n                            }\n                            #[derive(Deserialize)]\n                            #[serde(untagged)]\n                            enum Val {\n                                AgeComplex {\n                                    age: AgeComplexVal,\n                                },\n                                AgeWithOptions {\n                                    age: String,\n                                    #[serde(flatten)]\n                                    options: EnvDirectiveOptions,\n                                },\n                                Map {\n                                    value: PrimitiveVal,\n                                    #[serde(flatten)]\n                                    options: EnvDirectiveOptions,\n                                },\n                                OptionsOnly {\n                                    #[serde(flatten)]\n                                    options: EnvDirectiveOptions,\n                                },\n                                Primitive(PrimitiveVal),\n                            }\n\n                            #[derive(Deserialize)]\n                            struct AgeComplexVal {\n                                value: String,\n                                #[serde(default)]\n                                format: Option<AgeFormat>,\n                                #[serde(flatten)]\n                                options: EnvDirectiveOptions,\n                            }\n                            let val_result = map.next_value::<Val>()?;\n\n                            // Handle Age variants separately since they create different directive types\n                            match &val_result {\n                                Val::AgeComplex { age } => {\n                                    let directive = EnvDirective::Age {\n                                        key: key.clone(),\n                                        value: age.value.clone(),\n                                        format: age.format.clone(),\n                                        options: age.options.clone(),\n                                    };\n                                    env.push(directive);\n                                    continue;\n                                }\n                                Val::AgeWithOptions { age, options } => {\n                                    let directive = EnvDirective::Age {\n                                        key: key.clone(),\n                                        value: age.clone(),\n                                        format: None, // Default format for simplified syntax with options\n                                        options: options.clone(),\n                                    };\n                                    env.push(directive);\n                                    continue;\n                                }\n                                _ => {}\n                            }\n\n                            let (value, options) = match val_result {\n                                Val::Primitive(p) => (Some(p), EnvDirectiveOptions::default()),\n                                Val::Map { value, options } => (Some(value), options),\n                                Val::OptionsOnly { options } => (None, options),\n                                Val::AgeComplex { .. } | Val::AgeWithOptions { .. } => {\n                                    unreachable!() // Already handled above\n                                }\n                            };\n\n                            // Validate that required cannot be used with any value\n                            if options.required.is_required() {\n                                match &value {\n                                    Some(_) => {\n                                        return Err(serde::de::Error::custom(format!(\n                                            \"Environment variable '{}' cannot have both 'value' and 'required'. The 'required' flag means the variable must be defined elsewhere (in the environment or a later config file). Remove either the 'value' field or the 'required' flag.\",\n                                            key\n                                        )));\n                                    }\n                                    None => {\n                                        // Required without a value is valid - it means the variable must be defined elsewhere\n                                    }\n                                }\n                            }\n                            let directive = match value {\n                                Some(PrimitiveVal::Str(s)) => EnvDirective::Val(key, s, options),\n                                Some(PrimitiveVal::Int(i)) => {\n                                    EnvDirective::Val(key, i.to_string(), options)\n                                }\n                                Some(PrimitiveVal::Bool(true)) => {\n                                    EnvDirective::Val(key, \"true\".to_string(), options)\n                                }\n                                Some(PrimitiveVal::Bool(false)) => EnvDirective::Rm(key, options),\n                                None => {\n                                    // No value provided - this creates a required variable that must be defined elsewhere\n                                    if !options.required.is_required() {\n                                        return Err(serde::de::Error::custom(format!(\n                                            \"Environment variable '{}' has no value. Either provide a value or set required=true to indicate it must be defined elsewhere.\",\n                                            key\n                                        )));\n                                    }\n                                    // For required variables without a value, we create a Required directive\n                                    EnvDirective::Required(key, options)\n                                }\n                            };\n                            env.push(directive);\n                        }\n                    }\n                }\n                Ok(EnvList(env))\n            }\n        }\n\n        deserializer.deserialize_any(EnvManVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for MiseTomlToolList {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct MiseTomlToolListVisitor;\n\n        impl<'de> Visitor<'de> for MiseTomlToolListVisitor {\n            type Value = MiseTomlToolList;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"tool list\")\n            }\n\n            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                let tt: ToolVersionType = v\n                    .parse()\n                    .map_err(|e| de::Error::custom(format!(\"invalid tool: {e}\")))?;\n                Ok(MiseTomlToolList(vec![MiseTomlTool { tt, options: None }]))\n            }\n\n            fn visit_seq<S>(self, mut seq: S) -> std::result::Result<Self::Value, S::Error>\n            where\n                S: de::SeqAccess<'de>,\n            {\n                let mut tools = vec![];\n                while let Some(tool) = seq.next_element::<MiseTomlTool>()? {\n                    tools.push(tool);\n                }\n                Ok(MiseTomlToolList(tools))\n            }\n\n            fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                let mut options: ToolVersionOptions = Default::default();\n                let mut tt: Option<ToolVersionType> = None;\n                while let Some((k, v)) = map.next_entry::<String, toml::Value>()? {\n                    match k.as_str() {\n                        \"version\" => {\n                            tt = Some(v.as_str().unwrap().parse().map_err(de::Error::custom)?);\n                        }\n                        \"path\" | \"prefix\" | \"ref\" => {\n                            tt = Some(\n                                format!(\"{k}:{}\", v.as_str().unwrap())\n                                    .parse()\n                                    .map_err(de::Error::custom)?,\n                            );\n                        }\n                        \"os\" => match v {\n                            toml::Value::Array(s) => {\n                                options.os = Some(\n                                    s.iter().map(|v| v.as_str().unwrap().to_string()).collect(),\n                                );\n                            }\n                            toml::Value::String(s) => {\n                                // Convert {{version}} to {version} for backend templating\n                                let s = s.replace(\"{{version}}\", \"{version}\");\n                                options.opts.insert(k, toml::Value::String(s));\n                            }\n                            _ => {\n                                return Err(de::Error::custom(\"os must be a string or array\"));\n                            }\n                        },\n                        \"install_env\" => match v {\n                            toml::Value::Table(env) => {\n                                for (k, v) in env {\n                                    match v {\n                                        toml::Value::Boolean(v) => {\n                                            options.install_env.insert(k, v.to_string());\n                                        }\n                                        toml::Value::Integer(v) => {\n                                            options.install_env.insert(k, v.to_string());\n                                        }\n                                        toml::Value::String(v) => {\n                                            options.install_env.insert(k, v);\n                                        }\n                                        _ => {\n                                            return Err(de::Error::custom(\"invalid value type\"));\n                                        }\n                                    }\n                                }\n                            }\n                            _ => {\n                                return Err(de::Error::custom(\"env must be a table\"));\n                            }\n                        },\n                        _ => {\n                            // Store values as native toml::Value\n                            match v {\n                                toml::Value::String(s) => {\n                                    // Convert {{version}} to {version} for backend templating\n                                    let s = s.replace(\"{{version}}\", \"{version}\");\n                                    options.opts.insert(k, toml::Value::String(s));\n                                }\n                                toml::Value::Table(_) | toml::Value::Array(_) => {\n                                    // Keep tables and arrays as native TOML\n                                    options.opts.insert(k, v);\n                                }\n                                _ => {\n                                    // Convert scalar values (ints, bools, floats) to strings\n                                    options.opts.insert(\n                                        k,\n                                        toml::Value::String(\n                                            v.to_string().trim_matches('\"').to_string(),\n                                        ),\n                                    );\n                                }\n                            }\n                        }\n                    }\n                }\n                if let Some(tt) = tt {\n                    Ok(MiseTomlToolList(vec![MiseTomlTool {\n                        tt,\n                        options: Some(options),\n                    }]))\n                } else {\n                    Err(de::Error::custom(\"missing version\"))\n                }\n            }\n        }\n\n        deserializer.deserialize_any(MiseTomlToolListVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for MiseTomlTool {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct MiseTomlToolVisitor;\n\n        impl<'de> Visitor<'de> for MiseTomlToolVisitor {\n            type Value = MiseTomlTool;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"tool definition\")\n            }\n\n            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                let tt: ToolVersionType = v\n                    .parse()\n                    .map_err(|e| de::Error::custom(format!(\"invalid tool: {e}\")))?;\n                Ok(MiseTomlTool { tt, options: None })\n            }\n\n            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                let mut options: ToolVersionOptions = Default::default();\n                let mut tt = ToolVersionType::System;\n                while let Some((k, v)) = map.next_entry::<String, toml::Value>()? {\n                    match k.as_str() {\n                        \"version\" => {\n                            tt = v.as_str().unwrap().parse().map_err(de::Error::custom)?;\n                        }\n                        \"path\" | \"prefix\" | \"ref\" => {\n                            tt = format!(\"{k}:{}\", v.as_str().unwrap())\n                                .parse()\n                                .map_err(de::Error::custom)?;\n                        }\n                        \"os\" => match v {\n                            toml::Value::Array(s) => {\n                                options.os = Some(\n                                    s.iter().map(|v| v.as_str().unwrap().to_string()).collect(),\n                                );\n                            }\n                            toml::Value::String(s) => {\n                                // Convert {{version}} to {version} for backend templating\n                                let s = s.replace(\"{{version}}\", \"{version}\");\n                                options.opts.insert(k, toml::Value::String(s));\n                            }\n                            _ => {\n                                return Err(de::Error::custom(\"os must be a string or array\"));\n                            }\n                        },\n                        \"install_env\" => match v {\n                            toml::Value::Table(env) => {\n                                for (k, v) in env {\n                                    match v {\n                                        toml::Value::Boolean(v) => {\n                                            options.install_env.insert(k, v.to_string());\n                                        }\n                                        toml::Value::Integer(v) => {\n                                            options.install_env.insert(k, v.to_string());\n                                        }\n                                        toml::Value::String(v) => {\n                                            options.install_env.insert(k, v);\n                                        }\n                                        _ => {\n                                            return Err(de::Error::custom(\"invalid value type\"));\n                                        }\n                                    }\n                                }\n                            }\n                            _ => {\n                                return Err(de::Error::custom(\"env must be a table\"));\n                            }\n                        },\n                        _ => {\n                            // Store values as native toml::Value\n                            match v {\n                                toml::Value::String(s) => {\n                                    // Convert {{version}} to {version} for backend templating\n                                    let s = s.replace(\"{{version}}\", \"{version}\");\n                                    options.opts.insert(k, toml::Value::String(s));\n                                }\n                                toml::Value::Table(_) | toml::Value::Array(_) => {\n                                    // Keep tables and arrays as native TOML\n                                    options.opts.insert(k, v);\n                                }\n                                _ => {\n                                    // Convert scalar values (ints, bools, floats) to strings\n                                    options.opts.insert(\n                                        k,\n                                        toml::Value::String(\n                                            v.to_string().trim_matches('\"').to_string(),\n                                        ),\n                                    );\n                                }\n                            }\n                        }\n                    }\n                }\n                Ok(MiseTomlTool {\n                    tt,\n                    options: Some(options),\n                })\n            }\n        }\n\n        deserializer.deserialize_any(MiseTomlToolVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for Tasks {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct TasksVisitor;\n\n        impl<'de> Visitor<'de> for TasksVisitor {\n            type Value = Tasks;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"task, string, or array of strings\")\n            }\n\n            fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                struct TaskDef(Task);\n                impl<'de> de::Deserialize<'de> for TaskDef {\n                    fn deserialize<D>(deserializer: D) -> std::result::Result<TaskDef, D::Error>\n                    where\n                        D: de::Deserializer<'de>,\n                    {\n                        struct TaskDefVisitor;\n                        impl<'de> Visitor<'de> for TaskDefVisitor {\n                            type Value = TaskDef;\n                            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                                formatter.write_str(\"task definition\")\n                            }\n\n                            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n                            where\n                                E: de::Error,\n                            {\n                                Ok(TaskDef(Task {\n                                    run: vec![crate::task::RunEntry::Script(v.to_string())],\n                                    ..Default::default()\n                                }))\n                            }\n\n                            fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>\n                            where\n                                S: de::SeqAccess<'de>,\n                            {\n                                let mut run = vec![];\n                                while let Some(s) = seq.next_element::<crate::task::RunEntry>()? {\n                                    run.push(s);\n                                }\n                                Ok(TaskDef(Task {\n                                    run,\n                                    ..Default::default()\n                                }))\n                            }\n\n                            fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>\n                            where\n                                M: de::MapAccess<'de>,\n                            {\n                                let t = de::Deserialize::deserialize(\n                                    de::value::MapAccessDeserializer::new(map),\n                                )?;\n                                Ok(TaskDef(t))\n                            }\n                        }\n                        deserializer.deserialize_any(TaskDefVisitor)\n                    }\n                }\n                let mut tasks = BTreeMap::new();\n                while let Some(name) = map.next_key::<String>()? {\n                    let mut task = map.next_value::<TaskDef>()?.0;\n                    task.name.clone_from(&name);\n                    tasks.insert(name, task);\n                }\n                Ok(Tasks(tasks))\n            }\n        }\n\n        deserializer.deserialize_any(TasksVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for TaskTemplates {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct TaskTemplatesVisitor;\n\n        impl<'de> Visitor<'de> for TaskTemplatesVisitor {\n            type Value = TaskTemplates;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"map of task template names to template definitions\")\n            }\n\n            fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                let mut templates = IndexMap::new();\n                while let Some(name) = map.next_key::<String>()? {\n                    let template: TaskTemplate = map.next_value()?;\n                    templates.insert(name, template);\n                }\n                Ok(TaskTemplates(templates))\n            }\n        }\n\n        deserializer.deserialize_any(TaskTemplatesVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for BackendArg {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct BackendArgVisitor;\n\n        impl Visitor<'_> for BackendArgVisitor {\n            type Value = BackendArg;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"backend argument\")\n            }\n\n            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                Ok(v.into())\n            }\n        }\n\n        deserializer.deserialize_any(BackendArgVisitor)\n    }\n}\n\nimpl<'de> de::Deserialize<'de> for Alias {\n    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>\n    where\n        D: de::Deserializer<'de>,\n    {\n        struct AliasVisitor;\n\n        impl<'de> Visitor<'de> for AliasVisitor {\n            type Value = Alias;\n            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n                formatter.write_str(\"alias\")\n            }\n\n            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                Ok(Alias {\n                    backend: Some(v.to_string()),\n                    ..Default::default()\n                })\n            }\n\n            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>\n            where\n                M: de::MapAccess<'de>,\n            {\n                let mut backend = None;\n                let mut versions = IndexMap::new();\n                while let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"backend\" => {\n                            backend = Some(map.next_value()?);\n                        }\n                        \"versions\" => {\n                            versions = map.next_value()?;\n                        }\n                        _ => {\n                            deprecated!(\n                                \"TOOL_VERSION_ALIASES\",\n                                \"tool version aliases should be `alias.<TOOL>.versions.<FROM> = <TO>`, not `alias.<TOOL>.<FROM> = <TO>`\"\n                            );\n                            versions.insert(key, map.next_value()?);\n                        }\n                    }\n                }\n                Ok(Alias { backend, versions })\n            }\n        }\n\n        deserializer.deserialize_any(AliasVisitor)\n    }\n}\n\nfn is_tools_sorted(tools: &IndexMap<BackendArg, MiseTomlToolList>) -> bool {\n    let mut last = None;\n    for k in tools.keys() {\n        if let Some(last) = last\n            && k < last\n        {\n            return false;\n        }\n        last = Some(k);\n    }\n    true\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use std::sync::Arc;\n\n    use indoc::formatdoc;\n    use insta::{assert_debug_snapshot, assert_snapshot};\n    use test_log::test;\n\n    use crate::dirs;\n    use crate::file;\n    use crate::test::replace_path;\n    use crate::toolset::ToolRequest;\n    use crate::{config::Config, dirs::CWD};\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_fixture() {\n        let _config = Config::get().await.unwrap();\n        let cf = MiseToml::from_file(&dirs::HOME.join(\"fixtures/.mise.toml\")).unwrap();\n\n        assert_debug_snapshot!(cf.env_entries().unwrap());\n        assert_debug_snapshot!(cf.plugins().unwrap());\n        assert_snapshot!(replace_path(&format!(\n            \"{:#?}\",\n            cf.to_tool_request_set().unwrap()\n        )));\n        assert_debug_snapshot!(cf.alias);\n\n        assert_snapshot!(replace_path(&format!(\"{:#?}\", &cf)));\n    }\n\n    #[tokio::test]\n    async fn test_env() {\n        let _config = Config::get().await.unwrap();\n        let p = CWD.as_ref().unwrap().join(\".test.mise.toml\");\n        file::write(\n            &p,\n            formatdoc! {r#\"\n        min_version = \"2024.1.1\"\n        [env]\n        foo=\"bar\"\n        foo2='qux\\nquux'\n        foo3=\"qux\\nquux\"\n        \"#},\n        )\n        .unwrap();\n        let cf = MiseToml::from_file(&p).unwrap();\n        let dump = cf.dump().unwrap();\n        let env = parse_env(file::read_to_string(&p).unwrap());\n\n        assert_debug_snapshot!(env, @r#\"\"foo=bar\\nfoo2=qux\\\\nquux\\nfoo3=qux\\nquux\"\"#);\n        let cf: Box<dyn ConfigFile> = Box::new(cf);\n        with_settings!({\n            assert_snapshot!(dump);\n            assert_snapshot!(cf);\n            assert_debug_snapshot!(cf);\n        });\n    }\n\n    #[tokio::test]\n    async fn test_env_var_in_tool() {\n        let _config = Config::get().await.unwrap();\n        let p = CWD.as_ref().unwrap().join(\".test.mise.toml\");\n        file::write(\n            &p,\n            r#\"\n        [env]\n        TERRAFORM_VERSION = '1.0.0'\n        JQ_PREFIX = '1.6'\n\n        [tools]\n        terraform = \"{{env.TERRAFORM_VERSION}}\"\n        jq = { prefix = \"{{ env.JQ_PREFIX }}\" }\n        \"#,\n        )\n        .unwrap();\n        let cf = MiseToml::from_file(&p).unwrap();\n        assert_snapshot!(replace_path(&format!(\n            \"{:#?}\",\n            cf.to_tool_request_set().unwrap().tools\n        )));\n    }\n\n    #[tokio::test]\n    async fn test_env_source_var_in_tool() {\n        let cwd = CWD.as_ref().unwrap();\n        let script = cwd.join(\"set-go-version.sh\");\n        let config_file = cwd.join(\".test.mise.toml\");\n\n        file::write(&script, \"export MY_GO_VERSION=\\\"1.2.3\\\"\\n\").unwrap();\n        file::write(\n            &config_file,\n            r#\"\n        [env]\n        _.source = \"./set-go-version.sh\"\n\n        [tools]\n        go = \"{{env.MY_GO_VERSION}}\"\n        \"#,\n        )\n        .unwrap();\n\n        let config = Config::reset().await.unwrap();\n        let trs = config.get_tool_request_set().await.unwrap();\n        let go_req = trs\n            .tools\n            .iter()\n            .find(|(ba, _)| ba.short == \"go\")\n            .and_then(|(_, reqs)| reqs.first())\n            .unwrap();\n\n        assert_eq!(go_req.version(), \"1.2.3\");\n\n        file::remove_file(&config_file).unwrap();\n        file::remove_file(&script).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_env_array_valid() {\n        let _config = Config::get().await.unwrap();\n        let env = parse_env(formatdoc! {r#\"\n        [[env]]\n        foo=\"bar\"\n\n        [[env]]\n        bar=\"baz\"\n\n        [[env]]\n        foo2='qux\\nquux'\n        bar2=\"qux\\nquux\"\n        \"#});\n\n        assert_snapshot!(env, @r\"\n        foo=bar\n        bar=baz\n        foo2=qux\\nquux\n        bar2=qux\n        quux\n        \");\n    }\n\n    #[tokio::test]\n    async fn test_path_dirs() {\n        let _config = Config::get().await.unwrap();\n        let env = parse_env(formatdoc! {r#\"\n            env_path=[\"/foo\", \"./bar\"]\n            [env]\n            foo=\"bar\"\n            \"#});\n\n        assert_snapshot!(env, @r#\"\n        _.path = \"/foo\"\n        _.path = \"./bar\"\n        foo=bar\n        \"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            env_path=\"./bar\"\n            \"#});\n        assert_snapshot!(env, @r#\"_.path = \"./bar\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            [env]\n            _.path = \"./bar\"\n            \"#});\n        assert_debug_snapshot!(env, @r#\"\"_.path = \\\"./bar\\\"\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            [env]\n            _.path = [\"/foo\", \"./bar\"]\n            \"#});\n        assert_snapshot!(env, @r#\"\n        _.path = \"/foo\"\n        _.path = \"./bar\"\n        \"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            [[env]]\n            _.path = \"/foo\"\n            [[env]]\n            _.path = \"./bar\"\n            \"#});\n        assert_snapshot!(env, @r#\"\n        _.path = \"/foo\"\n        _.path = \"./bar\"\n        \"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            env_path = \"/foo\"\n            [env]\n            _.path = \"./bar\"\n            \"#});\n        assert_snapshot!(env, @r#\"\n        _.path = \"/foo\"\n        _.path = \"./bar\"\n        \"#);\n    }\n\n    #[tokio::test]\n    async fn test_env_file() {\n        let _config = Config::get().await.unwrap();\n        let env = parse_env(formatdoc! {r#\"\n            env_file = \".env\"\n            \"#});\n\n        assert_debug_snapshot!(env, @r#\"\"_.file = \\\".env\\\"\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            env_file=[\".env\", \".env2\"]\n            \"#});\n        assert_debug_snapshot!(env, @r#\"\"_.file = \\\".env\\\"\\n_.file = \\\".env2\\\"\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            [env]\n            _.file = \".env\"\n            \"#});\n        assert_debug_snapshot!(env, @r#\"\"_.file = \\\".env\\\"\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            [env]\n            _.file = [\".env\", \".env2\"]\n            \"#});\n        assert_debug_snapshot!(env, @r#\"\"_.file = \\\".env\\\"\\n_.file = \\\".env2\\\"\"\"#);\n\n        let env = parse_env(formatdoc! {r#\"\n            dotenv = \".env\"\n            [env]\n            _.file = \".env2\"\n            \"#});\n        assert_debug_snapshot!(env, @r#\"\"_.file = \\\".env\\\"\\n_.file = \\\".env2\\\"\"\"#);\n    }\n\n    #[tokio::test]\n    async fn test_set_alias() {\n        let _config = Config::get().await.unwrap();\n        let p = CWD.as_ref().unwrap().join(\".test.mise.toml\");\n        file::write(\n            &p,\n            formatdoc! {r#\"\n            [tool_alias.node.versions]\n            16 = \"16.0.0\"\n            18 = \"18.0.0\"\n        \"#},\n        )\n        .unwrap();\n        let mut cf = MiseToml::from_file(&p).unwrap();\n        let node = \"node\".into();\n        let python = \"python\".into();\n        cf.set_alias(&node, \"18\", \"18.0.1\").unwrap();\n        cf.set_alias(&node, \"20\", \"20.0.0\").unwrap();\n        cf.set_alias(&python, \"3.10\", \"3.10.0\").unwrap();\n\n        assert_debug_snapshot!(cf.tool_alias);\n        let cf: Box<dyn ConfigFile> = Box::new(cf);\n        assert_snapshot!(cf);\n        file::remove_file(&p).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_remove_alias() {\n        let _config = Config::get().await.unwrap();\n        let p = CWD.as_ref().unwrap().join(\".test.mise.toml\");\n        file::write(\n            &p,\n            formatdoc! {r#\"\n            [alias.node.versions]\n            16 = \"16.0.0\"\n            18 = \"18.0.0\"\n\n            [alias.python.versions]\n            \"3.10\" = \"3.10.0\"\n            \"#},\n        )\n        .unwrap();\n        let mut cf = MiseToml::from_file(&p).unwrap();\n        let node = \"node\".into();\n        let python = \"python\".into();\n        cf.remove_alias(&node, \"16\").unwrap();\n        cf.remove_alias(&python, \"3.10\").unwrap();\n\n        assert_debug_snapshot!(cf.alias);\n        let cf: Box<dyn ConfigFile> = Box::new(cf);\n        assert_snapshot!(cf.dump().unwrap());\n        assert_snapshot!(cf);\n        assert_debug_snapshot!(cf);\n        file::remove_file(&p).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_replace_versions() {\n        let _config = Config::get().await.unwrap();\n        let p = PathBuf::from(\"/tmp/.mise.toml\");\n        file::write(\n            &p,\n            formatdoc! {r#\"\n            [tools]\n            node = [\"16.0.0\", \"18.0.0\"]\n            \"#},\n        )\n        .unwrap();\n        let cf = MiseToml::from_file(&p).unwrap();\n        let node = \"node\".into();\n        cf.replace_versions(\n            &node,\n            vec![\n                ToolRequest::new(Arc::new(\"node\".into()), \"16.0.1\", ToolSource::Unknown).unwrap(),\n                ToolRequest::new(Arc::new(\"node\".into()), \"18.0.1\", ToolSource::Unknown).unwrap(),\n            ],\n        )\n        .unwrap();\n\n        assert_debug_snapshot!(cf.to_toolset().unwrap());\n        let cf: Box<dyn ConfigFile> = Box::new(cf);\n        assert_snapshot!(cf.dump().unwrap());\n        assert_snapshot!(cf);\n        assert_debug_snapshot!(cf);\n        file::remove_all(&p).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_remove_plugin() {\n        let _config = Config::get().await.unwrap();\n        let p = PathBuf::from(\"/tmp/.mise.toml\");\n        file::write(\n            &p,\n            formatdoc! {r#\"\n            [tools]\n            node = [\"16.0.0\", \"18.0.0\"]\n            \"#},\n        )\n        .unwrap();\n        let cf = MiseToml::from_file(&p).unwrap();\n        cf.remove_tool(&\"node\".into()).unwrap();\n\n        assert_debug_snapshot!(cf.to_toolset().unwrap());\n        let cf: Box<dyn ConfigFile> = Box::new(cf);\n        assert_snapshot!(cf.dump().unwrap());\n        assert_snapshot!(cf);\n        assert_debug_snapshot!(cf);\n    }\n\n    #[test]\n    fn test_env_entries() {\n        let toml = formatdoc! {r#\"\n        [env]\n        foo1=\"1\"\n        rm=false\n        _.path=\"/foo\"\n        foo2=\"2\"\n        _.file=\".env\"\n        foo3=\"3\"\n        \"#};\n        assert_snapshot!(parse_env(toml), @r#\"\n        foo1=1\n        unset rm\n        _.path = \"/foo\"\n        _.file = \".env\"\n        foo2=2\n        foo3=3\n        \"#);\n    }\n\n    #[test]\n    fn test_env_arr() {\n        let toml = formatdoc! {r#\"\n        [[env]]\n        foo1=\"1\"\n        rm=false\n        _.path=\"/foo\"\n        foo2=\"2\"\n        _.file=\".env\"\n        foo3=\"3\"\n        _.source=\"/baz1\"\n\n        [[env]]\n        foo4=\"4\"\n        rm=false\n        _.file=\".env2\"\n        foo5=\"5\"\n        _.path=\"/bar\"\n        foo6=\"6\"\n        _.source=\"/baz2\"\n        \"#};\n        assert_snapshot!(parse_env(toml), @r#\"\n        foo1=1\n        unset rm\n        _.path = \"/foo\"\n        _.file = \".env\"\n        _.source = \"/baz1\"\n        foo2=2\n        foo3=3\n        foo4=4\n        unset rm\n        _.path = \"/bar\"\n        _.file = \".env2\"\n        _.source = \"/baz2\"\n        foo5=5\n        foo6=6\n        \"#);\n    }\n\n    fn parse(s: String) -> MiseToml {\n        let p = CWD.as_ref().unwrap().join(\".test.mise.toml\");\n        file::write(&p, s).unwrap();\n        let cfg = MiseToml::from_file(&p).unwrap();\n        file::remove_file(&p).unwrap();\n\n        cfg\n    }\n\n    fn parse_env(toml: String) -> String {\n        parse(toml).env_entries().unwrap().into_iter().join(\"\\n\")\n    }\n\n    #[tokio::test]\n    async fn test_table_syntax_preserves_registry_defaults() {\n        // Test for #8039: table syntax like `ansible = { version = \"latest\" }`\n        // should preserve registry defaults (e.g. uvx=false, pipx_args=--include-deps)\n        let _config = Config::get().await.unwrap();\n        let cf = parse(formatdoc! {r#\"\n            [tools]\n            ansible = {{ version = \"latest\" }}\n        \"#});\n        let trs = cf.to_tool_request_set().unwrap();\n        let tools = trs.tools;\n        // Find the ansible tool request\n        let ansible_requests = tools\n            .iter()\n            .find(|(ba, _)| ba.short == \"ansible\")\n            .map(|(_, reqs)| reqs)\n            .expect(\"ansible should be in tool request set\");\n        let opts = ansible_requests[0].options();\n        assert_eq!(\n            opts.get(\"uvx\"),\n            Some(\"false\"),\n            \"registry default uvx=false should be preserved with table syntax\"\n        );\n        assert_eq!(\n            opts.get(\"pipx_args\"),\n            Some(\"--include-deps\"),\n            \"registry default pipx_args=--include-deps should be preserved with table syntax\"\n        );\n\n        // Also verify that user-provided options override registry defaults\n        let cf2 = parse(formatdoc! {r#\"\n            [tools]\n            ansible = {{ version = \"latest\", uvx = \"true\" }}\n        \"#});\n        let trs2 = cf2.to_tool_request_set().unwrap();\n        let ansible2 = trs2\n            .tools\n            .iter()\n            .find(|(ba, _)| ba.short == \"ansible\")\n            .map(|(_, reqs)| reqs)\n            .expect(\"ansible should be in tool request set\");\n        let opts2 = ansible2[0].options();\n        assert_eq!(\n            opts2.get(\"uvx\"),\n            Some(\"true\"),\n            \"user-provided uvx=true should override registry default uvx=false\"\n        );\n        assert_eq!(\n            opts2.get(\"pipx_args\"),\n            Some(\"--include-deps\"),\n            \"non-overridden registry default pipx_args should still be preserved\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/mod.rs",
    "content": "use std::ffi::OsStr;\nuse std::fmt::{Debug, Display};\nuse std::hash::Hash;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Mutex, Once};\nuse std::{\n    collections::{HashMap, HashSet},\n    sync::Arc,\n};\n\nuse crate::cli::args::{BackendArg, ToolArg};\nuse crate::config::config_file::min_version::MinVersionSpec;\nuse crate::config::config_file::mise_toml::{MiseToml, MonorepoConfig};\nuse crate::config::env_directive::EnvDirective;\nuse crate::config::{AliasMap, Settings, settings};\nuse crate::errors::Error::UntrustedConfig;\nuse crate::file::display_path;\nuse crate::hash::hash_to_str;\nuse crate::hooks::Hook;\nuse crate::prepare::PrepareConfig;\nuse crate::redactions::Redactions;\nuse crate::task::{Task, TaskTemplate};\nuse crate::toolset::{ToolRequest, ToolRequestSet, ToolSource, ToolVersionList, Toolset};\nuse crate::ui::{prompt, style};\nuse crate::watch_files::WatchFile;\nuse crate::{\n    backend::{self, Backend},\n    config, dirs, env, file, hash,\n};\nuse eyre::{Result, eyre};\nuse idiomatic_version::IdiomaticVersionFile;\nuse indexmap::IndexMap;\nuse serde_derive::Deserialize;\nuse std::sync::LazyLock as Lazy;\nuse tool_versions::ToolVersions;\n\nuse super::Config;\n\npub mod config_root;\npub mod diagnostic;\npub mod idiomatic_version;\npub mod min_version;\npub mod mise_toml;\npub mod toml;\npub mod tool_versions;\n\n#[derive(Debug, PartialEq)]\npub enum ConfigFileType {\n    MiseToml,\n    ToolVersions,\n    IdiomaticVersion(Vec<Arc<dyn Backend>>),\n}\n\npub trait ConfigFile: Debug + Send + Sync {\n    fn get_path(&self) -> &Path;\n    fn min_version(&self) -> Option<&MinVersionSpec> {\n        None\n    }\n    /// gets the project directory for the config\n    /// if it's a global/system config, returns None\n    /// files like ~/src/foo/.mise/config.toml will return ~/src/foo\n    /// and ~/src/foo/.mise.config.toml will return None\n    fn project_root(&self) -> Option<PathBuf> {\n        let p = self.get_path();\n        if config::is_global_config(p) {\n            return None;\n        }\n        match p.parent() {\n            Some(dir) => match dir {\n                dir if dir.starts_with(*dirs::CONFIG) => None,\n                dir if dir.starts_with(*dirs::SYSTEM_CONFIG) => None,\n                dir if dir == *dirs::HOME => None,\n                _ => Some(config_root::config_root(p)),\n            },\n            None => None,\n        }\n    }\n    fn config_type(&self) -> ConfigFileType;\n    fn config_root(&self) -> PathBuf {\n        config_root::config_root(self.get_path())\n    }\n    fn plugins(&self) -> Result<HashMap<String, String>> {\n        Ok(Default::default())\n    }\n    fn env_entries(&self) -> Result<Vec<EnvDirective>> {\n        Ok(Default::default())\n    }\n    fn vars_entries(&self) -> Result<Vec<EnvDirective>> {\n        Ok(Default::default())\n    }\n    fn tasks(&self) -> Vec<&Task> {\n        Default::default()\n    }\n    fn remove_tool(&self, ba: &BackendArg) -> eyre::Result<()>;\n    fn replace_versions(&self, ba: &BackendArg, versions: Vec<ToolRequest>) -> eyre::Result<()>;\n    fn save(&self) -> eyre::Result<()>;\n    fn dump(&self) -> eyre::Result<String>;\n    fn source(&self) -> ToolSource;\n    fn to_toolset(&self) -> eyre::Result<Toolset> {\n        Ok(self.to_tool_request_set()?.into())\n    }\n    fn to_tool_request_set(&self) -> eyre::Result<ToolRequestSet>;\n    fn aliases(&self) -> eyre::Result<AliasMap> {\n        Ok(Default::default())\n    }\n\n    fn shell_aliases(&self) -> eyre::Result<IndexMap<String, String>> {\n        Ok(Default::default())\n    }\n\n    fn task_config(&self) -> &TaskConfig {\n        static DEFAULT_TASK_CONFIG: Lazy<TaskConfig> = Lazy::new(TaskConfig::default);\n        &DEFAULT_TASK_CONFIG\n    }\n\n    fn task_templates(&self) -> IndexMap<String, TaskTemplate> {\n        IndexMap::new()\n    }\n\n    fn experimental_monorepo_root(&self) -> Option<bool> {\n        None\n    }\n\n    fn monorepo(&self) -> Option<&MonorepoConfig> {\n        None\n    }\n\n    fn redactions(&self) -> &Redactions {\n        static DEFAULT_REDACTIONS: Lazy<Redactions> = Lazy::new(Redactions::default);\n        &DEFAULT_REDACTIONS\n    }\n\n    fn watch_files(&self) -> Result<Vec<WatchFile>> {\n        Ok(Default::default())\n    }\n\n    fn hooks(&self) -> Result<Vec<Hook>> {\n        Ok(Default::default())\n    }\n\n    fn prepare_config(&self) -> Option<PrepareConfig> {\n        None\n    }\n}\n\nimpl dyn ConfigFile {\n    pub async fn add_runtimes(\n        &self,\n        config: &Arc<Config>,\n        tools: &[ToolArg],\n        pin: bool,\n    ) -> eyre::Result<()> {\n        // TODO: this has become a complete mess and could probably be greatly simplified\n        let mut ts = self.to_toolset()?.to_owned();\n        ts.resolve(config).await?;\n        trace!(\"resolved toolset\");\n        let mut plugins_to_update = HashMap::new();\n        for ta in tools {\n            if let Some(tv) = &ta.tvr {\n                plugins_to_update\n                    .entry(ta.ba.clone())\n                    .or_insert_with(Vec::new)\n                    .push(tv);\n            }\n        }\n        trace!(\"plugins to update: {plugins_to_update:?}\");\n        for (ba, versions) in &plugins_to_update {\n            let mut tvl = ToolVersionList::new(\n                ba.clone(),\n                ts.source.clone().unwrap_or(ToolSource::Argument),\n            );\n            for tv in versions {\n                tvl.requests.push((*tv).clone());\n            }\n            ts.versions.insert(ba.clone(), tvl);\n        }\n        trace!(\"resolving toolset 2\");\n        ts.resolve(config).await?;\n        trace!(\"resolved toolset 2\");\n        for (ba, versions) in plugins_to_update {\n            let mut new = vec![];\n            for tr in versions {\n                let mut tr = tr.clone();\n                if pin {\n                    let tv = tr.resolve(config, &Default::default()).await?;\n                    if let ToolRequest::Version {\n                        version: _version,\n                        source,\n                        options,\n                        backend,\n                    } = tr\n                    {\n                        tr = ToolRequest::Version {\n                            version: tv.version,\n                            source,\n                            options,\n                            backend,\n                        };\n                    }\n                }\n                new.push(tr);\n            }\n            trace!(\"replacing versions {new:?}\");\n            self.replace_versions(&ba, new)?;\n        }\n        trace!(\"done adding runtimes\");\n\n        Ok(())\n    }\n\n    /// this is for `mise local|global TOOL` which will display the version instead of setting it\n    /// it's only valid to use a single tool in this case\n    /// returns \"true\" if the tool was displayed which means the CLI should exit\n    pub fn display_runtime(&self, runtimes: &[ToolArg]) -> eyre::Result<bool> {\n        // in this situation we just print the current version in the config file\n        if runtimes.len() == 1 && runtimes[0].tvr.is_none() {\n            let fa = &runtimes[0].ba;\n            let tvl = self\n                .to_toolset()?\n                .versions\n                .get(fa)\n                .ok_or_else(|| {\n                    eyre!(\n                        \"no version set for {} in {}\",\n                        fa.to_string(),\n                        display_path(self.get_path())\n                    )\n                })?\n                .requests\n                .iter()\n                .map(|tvr| tvr.version())\n                .collect::<Vec<_>>();\n            miseprintln!(\"{}\", tvl.join(\" \"));\n            return Ok(true);\n        }\n        // check for something like `mise local node python@latest` which is invalid\n        if runtimes.iter().any(|r| r.tvr.is_none()) {\n            return Err(eyre!(\n                \"invalid input, specify a version for each tool. Or just specify one tool to print the current version\"\n            ));\n        }\n        Ok(false)\n    }\n}\n\nasync fn init(path: &Path) -> Arc<dyn ConfigFile> {\n    match detect_config_file_type(path).await {\n        Some(ConfigFileType::MiseToml) => Arc::new(MiseToml::init(path)),\n        Some(ConfigFileType::ToolVersions) => Arc::new(ToolVersions::init(path)),\n        Some(ConfigFileType::IdiomaticVersion(backends)) => Arc::new(\n            IdiomaticVersionFile::parse(path.to_path_buf(), backends)\n                .await\n                .expect(\"failed to parse idiomatic version file\"),\n        ),\n        _ => panic!(\"Unknown config file type: {}\", path.display()),\n    }\n}\n\npub async fn parse_or_init(path: &Path) -> eyre::Result<Arc<dyn ConfigFile>> {\n    let path = if path.is_dir() {\n        path.join(&*env::MISE_DEFAULT_CONFIG_FILENAME)\n    } else {\n        path.into()\n    };\n    let cf = match path.exists() {\n        true => parse(&path).await?,\n        false => init(&path).await,\n    };\n    Ok(cf)\n}\n\npub async fn parse(path: &Path) -> Result<Arc<dyn ConfigFile>> {\n    if let Ok(settings) = Settings::try_get()\n        && settings.paranoid\n    {\n        trust_check(path)?;\n    }\n    match detect_config_file_type(path).await {\n        Some(ConfigFileType::MiseToml) => Ok(Arc::new(MiseToml::from_file(path)?)),\n        Some(ConfigFileType::ToolVersions) => Ok(Arc::new(ToolVersions::from_file(path)?)),\n        Some(ConfigFileType::IdiomaticVersion(backends)) => Ok(Arc::new(\n            IdiomaticVersionFile::parse(path.to_path_buf(), backends).await?,\n        )),\n        #[allow(clippy::box_default)]\n        _ => Ok(Arc::new(MiseToml::default())),\n    }\n}\n\npub fn config_trust_root(path: &Path) -> PathBuf {\n    if settings::is_loaded() && Settings::get().paranoid {\n        path.to_path_buf()\n    } else {\n        config_root::config_root(path)\n    }\n}\n\npub fn trust_check(path: &Path) -> eyre::Result<()> {\n    static MUTEX: Mutex<()> = Mutex::new(());\n    let _lock = MUTEX.lock().unwrap(); // Prevent multiple checks at once so we don't prompt multiple times for the same path\n    let config_root = config_trust_root(path);\n    let default_cmd = String::new();\n    let args = env::ARGS.read().unwrap();\n    let cmd = args.get(1).unwrap_or(&default_cmd).as_str();\n    if is_trusted(&config_root) || is_trusted(path) || cmd == \"trust\" || cfg!(test) {\n        return Ok(());\n    }\n    if cmd != \"hook-env\" && !is_ignored(&config_root) && !is_ignored(path) {\n        let ans = (settings::is_loaded() && Settings::get().yes)\n            || prompt::confirm_with_all(format!(\n                \"{} config files in {} are not trusted. Trust them?\",\n                style::eyellow(\"mise\"),\n                style::epath(&config_root)\n            ))?;\n        if ans {\n            trust(&config_root)?;\n            return Ok(());\n        } else if console::user_attended_stderr() {\n            add_ignored(config_root.to_path_buf())?;\n        }\n    }\n    Err(UntrustedConfig(path.into()))?\n}\n\npub fn is_trusted(path: &Path) -> bool {\n    let canonicalized_path = match path.canonicalize() {\n        Ok(p) => p,\n        Err(err) => {\n            debug!(\"trust canonicalize: {err}\");\n            return false;\n        }\n    };\n    if is_ignored(canonicalized_path.as_path()) {\n        return false;\n    }\n    if IS_TRUSTED\n        .lock()\n        .unwrap()\n        .contains(canonicalized_path.as_path())\n    {\n        return true;\n    }\n    if config::is_global_config(path) {\n        add_trusted(canonicalized_path.to_path_buf());\n        return true;\n    }\n    let settings = Settings::get();\n    for p in settings.trusted_config_paths() {\n        if canonicalized_path.starts_with(p) {\n            add_trusted(canonicalized_path.to_path_buf());\n            return true;\n        }\n    }\n\n    // Check if this path is within a trusted monorepo root\n    // Monorepo roots are marked with a special marker file when trusted\n    if settings.experimental\n        && let Some(parent) = canonicalized_path.parent()\n    {\n        let mut current = parent;\n        while let Some(dir) = current.parent() {\n            let monorepo_marker = with_appended_extension(&trust_path(dir), \"monorepo\");\n            if monorepo_marker.exists() {\n                add_trusted(canonicalized_path.to_path_buf());\n                return true;\n            }\n            current = dir;\n        }\n    }\n    if settings.paranoid {\n        let trusted = trust_file_hash(path).unwrap_or_else(|e| {\n            warn!(\"trust_file_hash: {e}\");\n            false\n        });\n        if !trusted {\n            return false;\n        }\n    } else if cfg!(test) || ci_info::is_ci() {\n        // in tests/CI we trust everything\n        return true;\n    } else if !trust_path(path).exists() {\n        // the file isn't trusted, and we're not on a CI system where we generally assume we can\n        // trust config files\n        return false;\n    }\n    add_trusted(canonicalized_path.to_path_buf());\n    true\n}\n\nstatic IS_TRUSTED: Lazy<Mutex<HashSet<PathBuf>>> = Lazy::new(|| Mutex::new(HashSet::new()));\nstatic IS_IGNORED: Lazy<Mutex<HashSet<PathBuf>>> = Lazy::new(|| Mutex::new(HashSet::new()));\n\nfn add_trusted(path: PathBuf) {\n    IS_TRUSTED.lock().unwrap().insert(path);\n}\npub fn add_ignored(path: PathBuf) -> Result<()> {\n    let path = path.canonicalize()?;\n    file::create_dir_all(&*dirs::IGNORED_CONFIGS)?;\n    file::make_symlink_or_file(&path, &ignore_path(&path))?;\n    IS_IGNORED.lock().unwrap().insert(path);\n    Ok(())\n}\npub fn rm_ignored(path: PathBuf) -> Result<()> {\n    let path = path.canonicalize()?;\n    let ignore_path = ignore_path(&path);\n    if ignore_path.exists() {\n        file::remove_file(&ignore_path)?;\n    }\n    IS_IGNORED.lock().unwrap().remove(&path);\n    Ok(())\n}\npub fn is_ignored(path: &Path) -> bool {\n    static ONCE: Once = Once::new();\n    ONCE.call_once(|| {\n        if !dirs::IGNORED_CONFIGS.exists() {\n            return;\n        }\n        let mut is_ignored = IS_IGNORED.lock().unwrap();\n        for entry in file::ls(&dirs::IGNORED_CONFIGS).unwrap_or_default() {\n            if let Ok(canonicalized_path) = entry.canonicalize() {\n                is_ignored.insert(canonicalized_path);\n            }\n        }\n    });\n    if let Ok(path) = path.canonicalize() {\n        env::MISE_IGNORED_CONFIG_PATHS\n            .iter()\n            .any(|p| path.starts_with(p))\n            || IS_IGNORED.lock().unwrap().contains(&path)\n    } else {\n        debug!(\"is_ignored: path canonicalize failed\");\n        true\n    }\n}\n\npub fn trust(path: &Path) -> Result<()> {\n    rm_ignored(path.to_path_buf())?;\n    let hashed_path = trust_path(path);\n    if !hashed_path.exists() {\n        file::create_dir_all(hashed_path.parent().unwrap())?;\n        file::make_symlink_or_file(path.canonicalize()?.as_path(), &hashed_path)?;\n    }\n    if Settings::get().paranoid {\n        let trust_hash_path = with_appended_extension(&hashed_path, \"hash\");\n        let hash = hash::file_hash_sha256(path, None)?;\n        file::write(trust_hash_path, hash)?;\n    }\n    Ok(())\n}\n\n/// Marks a trusted config as a monorepo root, allowing all descendant configs to be trusted\npub fn mark_as_monorepo_root(path: &Path) -> Result<()> {\n    let config_root = config_trust_root(path);\n    let hashed_path = trust_path(&config_root);\n    let monorepo_marker = with_appended_extension(&hashed_path, \"monorepo\");\n    if !monorepo_marker.exists() {\n        file::create_dir_all(monorepo_marker.parent().unwrap())?;\n        file::write(&monorepo_marker, \"\")?;\n    }\n    Ok(())\n}\n\npub fn untrust(path: &Path) -> eyre::Result<()> {\n    rm_ignored(path.to_path_buf())?;\n    let hashed_path = trust_path(path);\n    if hashed_path.exists() {\n        file::remove_file(&hashed_path)?;\n    }\n    let hash_path = with_appended_extension(&hashed_path, \"hash\");\n    if hash_path.exists() {\n        file::remove_file(&hash_path)?;\n    }\n    let monorepo_path = with_appended_extension(&hashed_path, \"monorepo\");\n    if monorepo_path.exists() {\n        file::remove_file(&monorepo_path)?;\n    }\n    Ok(())\n}\n\n/// generates a path like ~/.mise/trusted-configs/dir-file-3e8b8c44c3.toml\nfn trust_path(path: &Path) -> PathBuf {\n    dirs::TRUSTED_CONFIGS.join(hashed_path_filename(path))\n}\n\nfn ignore_path(path: &Path) -> PathBuf {\n    dirs::IGNORED_CONFIGS.join(hashed_path_filename(path))\n}\n\n/// Appends an extension to a path without replacing existing dots in the filename.\n/// Unlike `Path::with_extension`, this preserves the full filename.\n/// e.g. \"foo-bar.toml-abc123\" + \"hash\" → \"foo-bar.toml-abc123.hash\"\n///\n/// NOTE: This changes the filename convention for .hash and .monorepo files.\n/// Existing files from prior versions will not be found, requiring a one-time\n/// re-trust of previously trusted configs after upgrade.\nfn with_appended_extension(path: &Path, ext: &str) -> PathBuf {\n    let mut os_string = path.as_os_str().to_owned();\n    os_string.push(\".\");\n    os_string.push(ext);\n    PathBuf::from(os_string)\n}\n\n/// creates the filename portion of trust/ignore files, e.g.:\nfn hashed_path_filename(path: &Path) -> String {\n    let canonicalized_path = path.canonicalize().unwrap();\n    let hash = hash_to_str(&canonicalized_path);\n    let trunc_str = |s: &OsStr| {\n        let mut s = s.to_str().unwrap().to_string();\n        s = s.chars().take(20).collect();\n        s\n    };\n    let trust_path = dirs::TRUSTED_CONFIGS.join(hash_to_str(&hash));\n    if trust_path.exists() {\n        return trust_path\n            .file_name()\n            .unwrap()\n            .to_string_lossy()\n            .to_string();\n    }\n    let parent = canonicalized_path\n        .parent()\n        .map(|p| p.to_path_buf())\n        .unwrap_or_default()\n        .file_name()\n        .map(trunc_str);\n    let filename = canonicalized_path.file_name().map(trunc_str);\n    [parent, filename, Some(hash)]\n        .into_iter()\n        .flatten()\n        .collect::<Vec<_>>()\n        .join(\"-\")\n}\n\nfn trust_file_hash(path: &Path) -> eyre::Result<bool> {\n    let trust_path = trust_path(path);\n    let trust_hash_path = with_appended_extension(&trust_path, \"hash\");\n    if !trust_hash_path.exists() {\n        return Ok(false);\n    }\n    let hash = file::read_to_string(&trust_hash_path)?;\n    let actual = hash::file_hash_sha256(path, None)?;\n    Ok(hash == actual)\n}\n\nasync fn filename_is_idiomatic(file_name: String) -> Option<Vec<Arc<dyn Backend>>> {\n    let mut backends = vec![];\n    for b in backend::list() {\n        match b.idiomatic_filenames().await {\n            Ok(filenames) if filenames.contains(&file_name) => backends.push(b),\n            Err(e) => debug!(\"idiomatic_filenames failed for {}: {:?}\", b, e),\n            _ => {}\n        }\n    }\n    if backends.is_empty() {\n        None\n    } else {\n        Some(backends)\n    }\n}\n\nasync fn detect_config_file_type(path: &Path) -> Option<ConfigFileType> {\n    match path\n        .file_name()\n        .and_then(|f| f.to_str())\n        .unwrap_or(\"mise.toml\")\n    {\n        f if env::MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES\n            .as_ref()\n            .is_some_and(|o| o.contains(f)) =>\n        {\n            Some(ConfigFileType::ToolVersions)\n        }\n        f if env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str() == f => {\n            Some(ConfigFileType::ToolVersions)\n        }\n        f if env::MISE_OVERRIDE_CONFIG_FILENAMES.contains(f) => Some(ConfigFileType::MiseToml),\n        f if env::MISE_DEFAULT_CONFIG_FILENAME.as_str() == f => Some(ConfigFileType::MiseToml),\n        f => {\n            if let Some(backends) = filename_is_idiomatic(f.to_string()).await {\n                Some(ConfigFileType::IdiomaticVersion(backends))\n            } else if f.ends_with(\".toml\") {\n                Some(ConfigFileType::MiseToml)\n            } else {\n                None\n            }\n        }\n    }\n}\n\nimpl Display for dyn ConfigFile {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let toolset = self.to_toolset().unwrap().to_string();\n        write!(f, \"{}: {toolset}\", &display_path(self.get_path()))\n    }\n}\n\nimpl PartialEq for dyn ConfigFile {\n    fn eq(&self, other: &Self) -> bool {\n        self.get_path() == other.get_path()\n    }\n}\n\nimpl Eq for dyn ConfigFile {}\n\nimpl Hash for dyn ConfigFile {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.get_path().hash(state);\n    }\n}\n\n#[derive(Clone, Debug, Default, Deserialize)]\npub struct TaskConfig {\n    pub includes: Option<Vec<String>>,\n    pub dir: Option<String>,\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_detect_config_file_type() {\n        env::set_var(\"MISE_EXPERIMENTAL\", \"true\");\n        assert!(matches!(\n            detect_config_file_type(Path::new(\"/foo/bar/.nvmrc\")).await,\n            Some(ConfigFileType::IdiomaticVersion(_))\n        ));\n        assert!(matches!(\n            detect_config_file_type(Path::new(\"/foo/bar/.ruby-version\")).await,\n            Some(ConfigFileType::IdiomaticVersion(_))\n        ));\n        assert_eq!(\n            detect_config_file_type(Path::new(\"/foo/bar/.test-tool-versions\")).await,\n            Some(ConfigFileType::ToolVersions)\n        );\n        assert_eq!(\n            detect_config_file_type(Path::new(\"/foo/bar/mise.toml\")).await,\n            Some(ConfigFileType::MiseToml)\n        );\n        assert!(matches!(\n            detect_config_file_type(Path::new(\"/foo/bar/rust-toolchain.toml\")).await,\n            Some(ConfigFileType::IdiomaticVersion(_))\n        ));\n    }\n\n    #[test]\n    fn test_with_appended_extension() {\n        let path = Path::new(\"/tmp/trusted/infra-mise.toml-a1b2c3d4e5f67890\");\n        let result = with_appended_extension(path, \"hash\");\n        assert_eq!(\n            result,\n            Path::new(\"/tmp/trusted/infra-mise.toml-a1b2c3d4e5f67890.hash\")\n        );\n\n        let result2 = with_appended_extension(path, \"monorepo\");\n        assert_eq!(\n            result2,\n            Path::new(\"/tmp/trusted/infra-mise.toml-a1b2c3d4e5f67890.monorepo\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/toml.rs",
    "content": "use crate::Result;\nuse std::collections::BTreeMap;\nuse std::fmt::Formatter;\nuse std::str::FromStr;\n\nuse serde::{Deserialize, de};\n\nuse crate::config::config_file::mise_toml::EnvList;\n\npub struct TomlParser<'a> {\n    table: &'a toml::Value,\n}\n\nimpl<'a> TomlParser<'a> {\n    pub fn new(table: &'a toml::Value) -> Self {\n        Self { table }\n    }\n\n    pub fn parse_str<T>(&self, key: &str) -> Option<T>\n    where\n        T: From<String>,\n    {\n        self.table\n            .get(key)\n            .and_then(|value| value.as_str())\n            .map(|value| value.to_string().into())\n    }\n    pub fn parse_bool(&self, key: &str) -> Option<bool> {\n        self.table.get(key).and_then(|value| value.as_bool())\n    }\n    pub fn parse_array<T>(&self, key: &str) -> Option<Vec<T>>\n    where\n        T: From<String>,\n    {\n        self.table\n            .get(key)\n            .and_then(|value| value.as_array())\n            .map(|array| {\n                array\n                    .iter()\n                    .filter_map(|value| value.as_str().map(|v| v.to_string().into()))\n                    .collect::<Vec<T>>()\n            })\n    }\n    pub fn parse_table(&self, key: &str) -> Option<BTreeMap<String, toml::Value>> {\n        self.table\n            .get(key)\n            .and_then(|value| value.as_table())\n            .map(|table| {\n                table\n                    .iter()\n                    .map(|(key, value)| (key.clone(), value.clone()))\n                    .collect::<BTreeMap<String, toml::Value>>()\n            })\n    }\n\n    pub fn parse_env(&self, key: &str) -> Result<Option<EnvList>> {\n        self.table\n            .get(key)\n            .map(|value| {\n                EnvList::deserialize(value.clone())\n                    .map_err(|e| eyre::eyre!(\"failed to parse env: {}\", e))\n            })\n            .transpose()\n    }\n}\n\npub struct TrackingTomlParser<'a> {\n    inner: TomlParser<'a>,\n    table: &'a toml::Value,\n    parsed_keys: std::collections::BTreeSet<String>,\n}\n\nimpl<'a> TrackingTomlParser<'a> {\n    pub fn new(table: &'a toml::Value) -> Self {\n        Self {\n            inner: TomlParser::new(table),\n            table,\n            parsed_keys: std::collections::BTreeSet::new(),\n        }\n    }\n\n    fn record(&mut self, key: &str) {\n        self.parsed_keys.insert(key.to_string());\n    }\n\n    #[cfg(test)]\n    pub fn parsed_keys(&self) -> impl Iterator<Item = &str> {\n        self.parsed_keys.iter().map(|s| s.as_str())\n    }\n\n    pub fn unparsed_keys(&self) -> Vec<String> {\n        if let Some(table) = self.table.as_table() {\n            table\n                .keys()\n                .filter(|k| !self.parsed_keys.contains(k.as_str()))\n                .cloned()\n                .collect()\n        } else {\n            vec![]\n        }\n    }\n\n    pub fn parse_str<T>(&mut self, key: &str) -> Option<T>\n    where\n        T: From<String>,\n    {\n        self.record(key);\n        self.inner.parse_str::<T>(key)\n    }\n\n    pub fn parse_bool(&mut self, key: &str) -> Option<bool> {\n        self.record(key);\n        self.inner.parse_bool(key)\n    }\n\n    pub fn parse_array<T>(&mut self, key: &str) -> Option<Vec<T>>\n    where\n        T: From<String>,\n    {\n        self.record(key);\n        self.inner.parse_array::<T>(key)\n    }\n\n    pub fn parse_table(&mut self, key: &str) -> Option<BTreeMap<String, toml::Value>> {\n        self.record(key);\n        self.inner.parse_table(key)\n    }\n\n    pub fn parse_env(&mut self, key: &str) -> Result<Option<EnvList>> {\n        self.record(key);\n        self.inner.parse_env(key)\n    }\n\n    pub fn get_raw(&mut self, key: &str) -> Option<&'a toml::Value> {\n        self.record(key);\n        self.table.get(key)\n    }\n}\n\npub fn deserialize_arr<'de, D, C, T>(deserializer: D) -> std::result::Result<C, D::Error>\nwhere\n    D: de::Deserializer<'de>,\n    C: FromIterator<T> + Deserialize<'de>,\n    T: FromStr + Deserialize<'de>,\n    <T as FromStr>::Err: std::fmt::Display,\n{\n    struct ArrVisitor<C, T>(std::marker::PhantomData<(C, T)>);\n\n    impl<'de, C, T> de::Visitor<'de> for ArrVisitor<C, T>\n    where\n        C: FromIterator<T> + Deserialize<'de>,\n        T: FromStr + Deserialize<'de>,\n        <T as FromStr>::Err: std::fmt::Display,\n    {\n        type Value = C;\n        fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {\n            formatter.write_str(\"a string, a map, or a list of strings/maps\")\n        }\n\n        fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>\n        where\n            E: de::Error,\n        {\n            let v = v.parse().map_err(de::Error::custom)?;\n            Ok(std::iter::once(v).collect())\n        }\n\n        fn visit_map<M>(self, map: M) -> std::result::Result<Self::Value, M::Error>\n        where\n            M: de::MapAccess<'de>,\n        {\n            let item = T::deserialize(de::value::MapAccessDeserializer::new(map))?;\n            Ok(std::iter::once(item).collect())\n        }\n\n        fn visit_seq<S>(self, seq: S) -> std::result::Result<Self::Value, S::Error>\n        where\n            S: de::SeqAccess<'de>,\n        {\n            #[derive(Deserialize)]\n            #[serde(untagged)]\n            enum StringOrValue<T> {\n                String(String),\n                Value(T),\n            }\n            let mut seq = seq;\n            std::iter::from_fn(|| seq.next_element::<StringOrValue<T>>().transpose())\n                .map(|element| match element {\n                    Ok(StringOrValue::String(s)) => s.parse().map_err(de::Error::custom),\n                    Ok(StringOrValue::Value(v)) => Ok(v),\n                    Err(e) => Err(e),\n                })\n                .collect()\n        }\n    }\n\n    deserializer.deserialize_any(ArrVisitor(std::marker::PhantomData))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serde::Deserialize;\n    use std::str::FromStr;\n\n    #[test]\n    fn test_parse_arr() {\n        let toml = r#\"arr = [\"1\", \"2\", \"3\"]\"#;\n        let table = toml::from_str(toml).unwrap();\n        let parser = TomlParser::new(&table);\n        let arr = parser.parse_array::<String>(\"arr\");\n        assert_eq!(arr.unwrap().join(\":\"), \"1:2:3\");\n    }\n\n    #[test]\n    fn test_parse_table() {\n        let toml = r#\"table = {foo = \"bar\", baz = \"qux\", num = 123}\"#;\n        let table = toml::from_str(toml).unwrap();\n        let parser = TomlParser::new(&table);\n        let table = parser.parse_table(\"table\").unwrap();\n        assert_eq!(table.len(), 3);\n        assert_eq!(table.get(\"foo\").unwrap().as_str().unwrap(), \"bar\");\n        assert_eq!(table.get(\"baz\").unwrap().as_str().unwrap(), \"qux\");\n        assert_eq!(table.get(\"num\").unwrap().as_integer().unwrap(), 123);\n    }\n\n    #[derive(Deserialize, Debug, PartialEq, Eq)]\n    #[serde(untagged)]\n    enum TestItem {\n        String(String),\n        Object { a: String, b: i64 },\n    }\n\n    impl FromStr for TestItem {\n        type Err = String;\n\n        fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {\n            Ok(TestItem::String(s.to_string()))\n        }\n    }\n\n    #[derive(Deserialize, Debug, PartialEq)]\n    struct TestStruct {\n        #[serde(default, deserialize_with = \"deserialize_arr\")]\n        arr: Vec<TestItem>,\n    }\n\n    #[test]\n    fn test_deserialize_arr_string() {\n        let toml_str = r#\"arr = \"hello\"\"#;\n        let expected = TestStruct {\n            arr: vec![TestItem::String(\"hello\".to_string())],\n        };\n        let actual: TestStruct = toml::from_str(toml_str).unwrap();\n        assert_eq!(actual, expected);\n    }\n\n    #[test]\n    fn test_deserialize_arr_string_list() {\n        let toml_str = r#\"arr = [\"hello\", \"world\"]\"#;\n        let expected = TestStruct {\n            arr: vec![\n                TestItem::String(\"hello\".to_string()),\n                TestItem::String(\"world\".to_string()),\n            ],\n        };\n        let actual: TestStruct = toml::from_str(toml_str).unwrap();\n        assert_eq!(actual, expected);\n    }\n\n    #[test]\n    fn test_deserialize_arr_map() {\n        let toml_str = r#\"arr = { a = \"foo\", b = 123 }\"#;\n        let expected = TestStruct {\n            arr: vec![TestItem::Object {\n                a: \"foo\".to_string(),\n                b: 123,\n            }],\n        };\n        let actual: TestStruct = toml::from_str(toml_str).unwrap();\n        assert_eq!(actual, expected);\n    }\n\n    #[test]\n    fn test_deserialize_arr_map_list() {\n        let toml_str = r#\"\n        arr = [\n            { a = \"foo\", b = 123 },\n            { a = \"bar\", b = 456 },\n        ]\n        \"#;\n        let expected = TestStruct {\n            arr: vec![\n                TestItem::Object {\n                    a: \"foo\".to_string(),\n                    b: 123,\n                },\n                TestItem::Object {\n                    a: \"bar\".to_string(),\n                    b: 456,\n                },\n            ],\n        };\n        let actual: TestStruct = toml::from_str(toml_str).unwrap();\n        assert_eq!(actual, expected);\n    }\n\n    #[test]\n    fn test_deserialize_arr_mixed_list() {\n        let toml_str = r#\"\n        arr = [\n            \"hello\",\n            { a = \"foo\", b = 123 },\n        ]\n        \"#;\n        let expected = TestStruct {\n            arr: vec![\n                TestItem::String(\"hello\".to_string()),\n                TestItem::Object {\n                    a: \"foo\".to_string(),\n                    b: 123,\n                },\n            ],\n        };\n        let actual: TestStruct = toml::from_str(toml_str).unwrap();\n        assert_eq!(actual, expected);\n    }\n}\n"
  },
  {
    "path": "src/config/config_file/tool_versions.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::{\n    fmt::{Display, Formatter},\n    sync::{Arc, Mutex},\n};\n\nuse console::{Alignment, measure_text_width, pad_str};\nuse eyre::Result;\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse tera::Context;\n\nuse crate::cli::args::BackendArg;\nuse crate::config::config_file::ConfigFile;\nuse crate::file;\nuse crate::file::display_path;\nuse crate::tera::{BASE_CONTEXT, get_tera};\nuse crate::toolset::{ToolRequest, ToolRequestSet, ToolSource};\n\nuse super::ConfigFileType;\n\n// python 3.11.0 3.10.0\n// shellcheck 0.9.0\n// shfmt 3.6.0\n\n/// represents asdf's .tool-versions file\n#[derive(Debug, Default)]\npub struct ToolVersions {\n    context: Context,\n    path: PathBuf,\n    pre: String,\n    plugins: Mutex<IndexMap<BackendArg, ToolVersionPlugin>>,\n    tools: Mutex<ToolRequestSet>,\n}\n\n#[derive(Debug, Clone)]\nstruct ToolVersionPlugin {\n    orig_name: String,\n    versions: Vec<String>,\n    post: String,\n}\n\nimpl ToolVersions {\n    pub fn init(filename: &Path) -> ToolVersions {\n        let mut context = BASE_CONTEXT.clone();\n        context.insert(\"config_root\", filename.parent().unwrap().to_str().unwrap());\n        ToolVersions {\n            context,\n            tools: Mutex::new(ToolRequestSet::new()),\n            path: filename.to_path_buf(),\n            ..Default::default()\n        }\n    }\n\n    pub fn from_file(path: &Path) -> Result<Self> {\n        trace!(\"parsing tool-versions: {}\", path.display());\n        Self::parse_str(&file::read_to_string(path)?, path.to_path_buf())\n    }\n\n    pub fn parse_str(s: &str, path: PathBuf) -> Result<Self> {\n        let mut cf = Self::init(&path);\n        let dir = path.parent();\n        let s = get_tera(dir).render_str(s, &cf.context)?;\n        for line in s.lines() {\n            if !line.trim_start().starts_with('#') {\n                break;\n            }\n            cf.pre.push_str(line);\n            cf.pre.push('\\n');\n        }\n\n        cf.plugins = Mutex::new(Self::parse_plugins(&s));\n        cf.populate_toolset()?;\n        trace!(\"{cf}\");\n        Ok(cf)\n    }\n\n    fn parse_plugins(input: &str) -> IndexMap<BackendArg, ToolVersionPlugin> {\n        let mut plugins: IndexMap<BackendArg, ToolVersionPlugin> = IndexMap::new();\n        for line in input.lines() {\n            if line.trim_start().starts_with('#') {\n                if let Some(prev) = &mut plugins.values_mut().last() {\n                    prev.post.push_str(line);\n                    prev.post.push('\\n');\n                }\n                continue;\n            }\n            let (line, post) = line.split_once('#').unwrap_or((line, \"\"));\n            let mut parts = line.split_whitespace();\n            if let Some(plugin) = parts.next() {\n                // handle invalid trailing colons in `.tool-versions` files\n                // note that this method will cause the colons to be removed\n                // permanently if saving the file again, but I think that's fine\n                let orig_plugin = plugin.trim_end_matches(':');\n                let ba = orig_plugin.into();\n\n                let tvp = ToolVersionPlugin {\n                    orig_name: orig_plugin.to_string(),\n                    versions: parts.map(|v| v.to_string()).collect(),\n                    post: match post {\n                        \"\" => String::from(\"\\n\"),\n                        _ => [\" #\", post, \"\\n\"].join(\"\"),\n                    },\n                };\n                plugins.insert(ba, tvp);\n            }\n        }\n        plugins\n    }\n\n    fn add_version(\n        &self,\n        plugins: &mut IndexMap<BackendArg, ToolVersionPlugin>,\n        fa: &BackendArg,\n        version: String,\n    ) {\n        get_or_create_plugin(plugins, fa).versions.push(version);\n    }\n\n    fn populate_toolset(&self) -> eyre::Result<()> {\n        let source = ToolSource::ToolVersions(self.path.clone());\n        for (ba, tvp) in &*self.plugins.lock().unwrap() {\n            for version in &tvp.versions {\n                let tvr = ToolRequest::new(Arc::new(ba.clone()), version, source.clone())?;\n                self.tools.lock().unwrap().add_version(tvr, &source)\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl Display for ToolVersions {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        let plugins = &self\n            .plugins\n            .lock()\n            .unwrap()\n            .iter()\n            .map(|(p, v)| format!(\"{}@{}\", p, v.versions.join(\"|\")))\n            .collect_vec();\n        write!(\n            f,\n            \"ToolVersions({}): {}\",\n            display_path(&self.path),\n            plugins.join(\", \")\n        )\n    }\n}\n\nimpl ConfigFile for ToolVersions {\n    fn config_type(&self) -> ConfigFileType {\n        ConfigFileType::ToolVersions\n    }\n\n    fn get_path(&self) -> &Path {\n        self.path.as_path()\n    }\n\n    fn remove_tool(&self, fa: &BackendArg) -> Result<()> {\n        self.plugins.lock().unwrap().shift_remove(fa);\n        Ok(())\n    }\n\n    fn replace_versions(&self, fa: &BackendArg, versions: Vec<ToolRequest>) -> eyre::Result<()> {\n        let mut plugins = self.plugins.lock().unwrap();\n        get_or_create_plugin(&mut plugins, fa).versions.clear();\n        for tr in versions {\n            if !tr.options().is_empty() {\n                warn!(\"tool options are not supported in .tool-versions files\");\n            }\n            self.add_version(&mut plugins, fa, tr.version());\n        }\n        Ok(())\n    }\n\n    fn save(&self) -> Result<()> {\n        let s = self.dump()?;\n        file::write(&self.path, s)\n    }\n\n    fn dump(&self) -> eyre::Result<String> {\n        let mut s = self.pre.clone();\n\n        let plugins = self.plugins.lock().unwrap();\n        let max_plugin_len = plugins\n            .keys()\n            .map(|p| measure_text_width(&p.to_string()))\n            .max()\n            .unwrap_or_default();\n        for (_, tv) in &*plugins {\n            let mut plugin = tv.orig_name.to_string();\n            if plugin == \"node\" {\n                plugin = \"nodejs\".into();\n            } else if plugin == \"go\" {\n                plugin = \"golang\".into();\n            }\n            let plugin = pad_str(&plugin, max_plugin_len, Alignment::Left, None);\n            s.push_str(&format!(\"{} {}{}\", plugin, tv.versions.join(\" \"), tv.post));\n        }\n\n        Ok(s.trim_end().to_string() + \"\\n\")\n    }\n\n    fn source(&self) -> ToolSource {\n        ToolSource::ToolVersions(self.path.clone())\n    }\n\n    fn to_tool_request_set(&self) -> eyre::Result<ToolRequestSet> {\n        Ok(self.tools.lock().unwrap().clone())\n    }\n}\n\nfn get_or_create_plugin<'a>(\n    plugins: &'a mut IndexMap<BackendArg, ToolVersionPlugin>,\n    fa: &BackendArg,\n) -> &'a mut ToolVersionPlugin {\n    plugins\n        .entry(fa.clone())\n        .or_insert_with(|| ToolVersionPlugin {\n            orig_name: fa.short.to_string(),\n            versions: vec![],\n            post: \"\".into(),\n        })\n}\n\nimpl Clone for ToolVersions {\n    fn clone(&self) -> Self {\n        Self {\n            context: self.context.clone(),\n            path: self.path.clone(),\n            pre: self.pre.clone(),\n            plugins: Mutex::new(self.plugins.lock().unwrap().clone()),\n            tools: Mutex::new(self.tools.lock().unwrap().clone()),\n        }\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/file.rs",
    "content": "use crate::config::{Config, env_directive::EnvResults};\nuse crate::file::display_path;\nuse crate::{Result, file, sops};\nuse eyre::{WrapErr, bail, eyre};\nuse indexmap::IndexMap;\nuse rops::file::format::{JsonFileFormat, YamlFileFormat};\nuse std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\n// use indexmap so source is after value for `mise env --json` output\ntype EnvMap = IndexMap<String, String>;\n\n#[derive(serde::Serialize, serde::Deserialize)]\nstruct Env<V> {\n    #[serde(default = \"IndexMap::new\")]\n    sops: IndexMap<String, V>,\n    #[serde(flatten)]\n    env: IndexMap<String, V>,\n}\n\nimpl EnvResults {\n    #[allow(clippy::too_many_arguments)]\n    pub async fn file(\n        config: &Arc<Config>,\n        ctx: &mut tera::Context,\n        tera: &mut tera::Tera,\n        r: &mut EnvResults,\n        normalize_path: fn(&Path, PathBuf) -> PathBuf,\n        source: &Path,\n        config_root: &Path,\n        input: String,\n    ) -> Result<IndexMap<PathBuf, EnvMap>> {\n        let mut out = IndexMap::new();\n        let s = r.parse_template(ctx, tera, source, &input)?;\n        for p in xx::file::glob(normalize_path(config_root, s.into())).unwrap_or_default() {\n            let env = out.entry(p.clone()).or_insert_with(IndexMap::new);\n            let parse_template = |s: String| r.parse_template(ctx, tera, source, &s);\n            let ext = p\n                .extension()\n                .map(|e| e.to_string_lossy().to_string())\n                .unwrap_or_default();\n            *env = match ext.as_str() {\n                \"json\" => Self::json(config, &p, parse_template).await?,\n                \"yaml\" => Self::yaml(config, &p, parse_template).await?,\n                \"toml\" => Self::toml(&p).await?,\n                _ => Self::dotenv(&p).await?,\n            };\n        }\n        Ok(out)\n    }\n\n    async fn json<PT>(config: &Arc<Config>, p: &Path, parse_template: PT) -> Result<EnvMap>\n    where\n        PT: FnMut(String) -> Result<String>,\n    {\n        let errfn = || eyre!(\"failed to parse json file: {}\", display_path(p));\n        if let Ok(raw) = file::read_to_string(p) {\n            let mut f: Env<serde_json::Value> = serde_json::from_str(&raw).wrap_err_with(errfn)?;\n            if !f.sops.is_empty() {\n                let decrypted =\n                    sops::decrypt::<_, JsonFileFormat>(config, &raw, parse_template, \"json\")\n                        .await?;\n                if !decrypted.is_empty() {\n                    f = serde_json::from_str(&decrypted).wrap_err_with(errfn)?;\n                } else {\n                    return Ok(EnvMap::new());\n                }\n            }\n            f.env\n                .into_iter()\n                .map(|(k, v)| {\n                    Ok((\n                        k,\n                        match v {\n                            serde_json::Value::String(s) => s,\n                            serde_json::Value::Number(n) => n.to_string(),\n                            serde_json::Value::Bool(b) => b.to_string(),\n                            _ => bail!(\"unsupported json value: {v:?}\"),\n                        },\n                    ))\n                })\n                .collect()\n        } else {\n            Ok(EnvMap::new())\n        }\n    }\n\n    async fn yaml<PT>(config: &Arc<Config>, p: &Path, parse_template: PT) -> Result<EnvMap>\n    where\n        PT: FnMut(String) -> Result<String>,\n    {\n        let errfn = || eyre!(\"failed to parse yaml file: {}\", display_path(p));\n        if let Ok(raw) = file::read_to_string(p) {\n            let mut f: Env<serde_yaml::Value> = serde_yaml::from_str(&raw).wrap_err_with(errfn)?;\n            if !f.sops.is_empty() {\n                let decrypted =\n                    sops::decrypt::<_, YamlFileFormat>(config, &raw, parse_template, \"yaml\")\n                        .await?;\n                if !decrypted.is_empty() {\n                    f = serde_yaml::from_str(&decrypted).wrap_err_with(errfn)?;\n                } else {\n                    return Ok(EnvMap::new());\n                }\n            }\n            f.env\n                .into_iter()\n                .map(|(k, v)| {\n                    Ok((\n                        k,\n                        match v {\n                            serde_yaml::Value::String(s) => s,\n                            serde_yaml::Value::Number(n) => n.to_string(),\n                            serde_yaml::Value::Bool(b) => b.to_string(),\n                            _ => bail!(\"unsupported yaml value: {v:?}\"),\n                        },\n                    ))\n                })\n                .collect()\n        } else {\n            Ok(EnvMap::new())\n        }\n    }\n\n    async fn toml(p: &Path) -> Result<EnvMap> {\n        let errfn = || eyre!(\"failed to parse toml file: {}\", display_path(p));\n        // sops does not support toml yet, so no need to parse sops\n        if let Ok(raw) = file::read_to_string(p) {\n            toml::from_str::<Env<toml::Value>>(&raw)\n                .wrap_err_with(errfn)?\n                .env\n                .into_iter()\n                .map(|(k, v)| {\n                    Ok((\n                        k,\n                        match v {\n                            toml::Value::String(s) => s,\n                            toml::Value::Integer(n) => n.to_string(),\n                            toml::Value::Boolean(b) => b.to_string(),\n                            _ => bail!(\"unsupported toml value: {v:?}\"),\n                        },\n                    ))\n                })\n                .collect()\n        } else {\n            Ok(EnvMap::new())\n        }\n    }\n\n    async fn dotenv(p: &Path) -> Result<EnvMap> {\n        let errfn = || eyre!(\"failed to parse dotenv file: {}\", display_path(p));\n        let mut env = EnvMap::new();\n        if let Ok(dotenv) = dotenvy::from_path_iter(p) {\n            for item in dotenv {\n                let (k, v) = item.wrap_err_with(errfn)?;\n                env.insert(k, v);\n            }\n        }\n        Ok(env)\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/mod.rs",
    "content": "use crate::config::config_file::trust_check;\nuse crate::dirs;\nuse crate::env;\nuse crate::env_diff::EnvMap;\nuse crate::file::display_path;\nuse crate::path_env::PathEnv;\nuse crate::tera::{get_tera, tera_exec};\nuse eyre::{Context, eyre};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse serde_json::Value;\nuse std::borrow::Cow;\nuse std::collections::{BTreeMap, BTreeSet, HashMap};\nuse std::fmt::{Debug, Display, Formatter};\nuse std::path::{Path, PathBuf};\nuse std::{cmp::PartialEq, sync::Arc};\n\nuse super::{Config, Settings};\n\nmod file;\nmod module;\nmod path;\nmod source;\npub(crate) mod venv;\n\n#[derive(Debug, Clone, Default, PartialEq)]\npub enum RequiredValue {\n    #[default]\n    False,\n    True,\n    Help(String),\n}\n\nimpl RequiredValue {\n    pub fn is_required(&self) -> bool {\n        !matches!(self, RequiredValue::False)\n    }\n\n    pub fn help_text(&self) -> Option<&str> {\n        match self {\n            RequiredValue::Help(text) => Some(text.as_str()),\n            _ => None,\n        }\n    }\n}\n\nimpl<'de> serde::Deserialize<'de> for RequiredValue {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        use serde::de::{self, Visitor};\n        use std::fmt;\n\n        struct RequiredVisitor;\n\n        impl<'de> Visitor<'de> for RequiredVisitor {\n            type Value = RequiredValue;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a boolean or a string\")\n            }\n\n            fn visit_bool<E>(self, value: bool) -> Result<RequiredValue, E>\n            where\n                E: de::Error,\n            {\n                Ok(if value {\n                    RequiredValue::True\n                } else {\n                    RequiredValue::False\n                })\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<RequiredValue, E>\n            where\n                E: de::Error,\n            {\n                Ok(RequiredValue::Help(value.to_string()))\n            }\n\n            fn visit_string<E>(self, value: String) -> Result<RequiredValue, E>\n            where\n                E: de::Error,\n            {\n                Ok(RequiredValue::Help(value))\n            }\n        }\n\n        deserializer.deserialize_any(RequiredVisitor)\n    }\n}\n\nimpl serde::Serialize for RequiredValue {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        match self {\n            RequiredValue::False => serializer.serialize_bool(false),\n            RequiredValue::True => serializer.serialize_bool(true),\n            RequiredValue::Help(text) => serializer.serialize_str(text),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]\npub struct EnvDirectiveOptions {\n    #[serde(default)]\n    pub(crate) tools: bool,\n    #[serde(default)]\n    pub(crate) redact: Option<bool>,\n    #[serde(default)]\n    pub(crate) required: RequiredValue,\n}\n\n#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]\npub enum EnvDirective {\n    /// simple key/value pair\n    Val(String, String, EnvDirectiveOptions),\n    /// remove a key\n    Rm(String, EnvDirectiveOptions),\n    /// Required variable that must be defined elsewhere\n    Required(String, EnvDirectiveOptions),\n    /// dotenv file\n    File(String, EnvDirectiveOptions),\n    /// add a path to the PATH\n    Path(String, EnvDirectiveOptions),\n    /// run a bash script and apply the resulting env diff\n    Source(String, EnvDirectiveOptions),\n    /// [experimental] age-encrypted value\n    Age {\n        key: String,\n        value: String,\n        format: Option<AgeFormat>,\n        options: EnvDirectiveOptions,\n    },\n    PythonVenv {\n        path: String,\n        create: bool,\n        python: Option<String>,\n        uv_create_args: Option<Vec<String>>,\n        python_create_args: Option<Vec<String>>,\n        options: EnvDirectiveOptions,\n    },\n    Module(String, toml::Value, EnvDirectiveOptions),\n}\n\nimpl EnvDirective {\n    pub fn options(&self) -> &EnvDirectiveOptions {\n        match self {\n            EnvDirective::Val(_, _, opts)\n            | EnvDirective::Rm(_, opts)\n            | EnvDirective::Required(_, opts)\n            | EnvDirective::File(_, opts)\n            | EnvDirective::Path(_, opts)\n            | EnvDirective::Source(_, opts)\n            | EnvDirective::Age { options: opts, .. }\n            | EnvDirective::PythonVenv { options: opts, .. }\n            | EnvDirective::Module(_, _, opts) => opts,\n        }\n    }\n}\n\nimpl From<(String, String)> for EnvDirective {\n    fn from((k, v): (String, String)) -> Self {\n        Self::Val(k, v, Default::default())\n    }\n}\n\nimpl From<(String, i64)> for EnvDirective {\n    fn from((k, v): (String, i64)) -> Self {\n        (k, v.to_string()).into()\n    }\n}\n\nimpl Display for EnvDirective {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            EnvDirective::Val(k, v, _) => write!(f, \"{k}={v}\"),\n            EnvDirective::Rm(k, _) => write!(f, \"unset {k}\"),\n            EnvDirective::Required(k, _) => write!(f, \"{k} (required)\"),\n            EnvDirective::File(path, _) => write!(f, \"_.file = \\\"{}\\\"\", display_path(path)),\n            EnvDirective::Path(path, _) => write!(f, \"_.path = \\\"{}\\\"\", display_path(path)),\n            EnvDirective::Source(path, _) => write!(f, \"_.source = \\\"{}\\\"\", display_path(path)),\n            EnvDirective::Age { key, format, .. } => {\n                write!(f, \"{key} (age-encrypted\")?;\n                if let Some(fmt) = format {\n                    let fmt_str = match fmt {\n                        AgeFormat::Zstd => \"zstd\",\n                        AgeFormat::Raw => \"raw\",\n                    };\n                    write!(f, \", {fmt_str}\")?;\n                }\n                write!(f, \")\")\n            }\n            EnvDirective::Module(name, _, _) => write!(f, \"module {name}\"),\n            EnvDirective::PythonVenv {\n                path,\n                create,\n                python,\n                uv_create_args,\n                python_create_args,\n                ..\n            } => {\n                write!(f, \"python venv path={}\", display_path(path))?;\n                if *create {\n                    write!(f, \" create\")?;\n                }\n                if let Some(python) = python {\n                    write!(f, \" python={python}\")?;\n                }\n                if let Some(args) = uv_create_args {\n                    write!(f, \" uv_create_args={args:?}\")?;\n                }\n                if let Some(args) = python_create_args {\n                    write!(f, \" python_create_args={args:?}\")?;\n                }\n                Ok(())\n            }\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]\npub enum AgeFormat {\n    #[serde(rename = \"zstd\")]\n    Zstd,\n    #[serde(rename = \"raw\")]\n    #[default]\n    Raw,\n}\n\n#[derive(Default, Clone)]\npub struct EnvResults {\n    pub env: IndexMap<String, (String, PathBuf)>,\n    pub vars: IndexMap<String, (String, PathBuf)>,\n    pub env_remove: BTreeSet<String>,\n    pub env_files: Vec<PathBuf>,\n    pub env_paths: Vec<PathBuf>,\n    pub env_scripts: Vec<PathBuf>,\n    pub redactions: Vec<String>,\n    pub tool_add_paths: Vec<PathBuf>,\n    /// Files to watch for cache invalidation (from modules and _.source directives)\n    pub watch_files: Vec<PathBuf>,\n    /// True if any directive declared cacheable=false or is a dynamic module\n    pub has_uncacheable: bool,\n}\n\n#[derive(Debug, Clone, Default)]\npub enum ToolsFilter {\n    ToolsOnly,\n    #[default]\n    NonToolsOnly,\n    Both,\n}\n\npub struct EnvResolveOptions {\n    pub vars: bool,\n    pub tools: ToolsFilter,\n    pub warn_on_missing_required: bool,\n}\n\nimpl EnvResults {\n    pub async fn resolve(\n        config: &Arc<Config>,\n        mut ctx: tera::Context,\n        initial: &EnvMap,\n        input: Vec<(EnvDirective, PathBuf)>,\n        resolve_opts: EnvResolveOptions,\n    ) -> eyre::Result<Self> {\n        // trace!(\"resolve: input: {:#?}\", &input);\n        let mut env = initial\n            .iter()\n            .map(|(k, v)| (k.clone(), (v.clone(), None)))\n            .collect::<IndexMap<_, _>>();\n        let mut r = Self {\n            env: Default::default(),\n            vars: Default::default(),\n            env_remove: BTreeSet::new(),\n            env_files: Vec::new(),\n            env_paths: Vec::new(),\n            env_scripts: Vec::new(),\n            redactions: Vec::new(),\n            tool_add_paths: Vec::new(),\n            watch_files: Vec::new(),\n            has_uncacheable: false,\n        };\n        let normalize_path = |config_root: &Path, p: PathBuf| {\n            let p = p.strip_prefix(\"./\").unwrap_or(&p);\n            match p.strip_prefix(\"~/\") {\n                Ok(p) => dirs::HOME.join(p),\n                _ if p.is_relative() => config_root.join(p),\n                _ => p.to_path_buf(),\n            }\n        };\n        let mut paths: Vec<(PathBuf, PathBuf)> = Vec::new();\n        let last_python_venv = input.iter().rev().find_map(|(d, _)| match d {\n            EnvDirective::PythonVenv { .. } => Some(d),\n            _ => None,\n        });\n        let filtered_input = input\n            .iter()\n            .fold(Vec::new(), |mut acc, (directive, source)| {\n                // Filter directives based on tools setting\n                let should_include = match &resolve_opts.tools {\n                    ToolsFilter::ToolsOnly => directive.options().tools,\n                    ToolsFilter::NonToolsOnly => !directive.options().tools,\n                    ToolsFilter::Both => true,\n                };\n\n                if !should_include {\n                    return acc;\n                }\n\n                if let Some(d) = &last_python_venv\n                    && matches!(directive, EnvDirective::PythonVenv { .. })\n                    && **d != *directive\n                {\n                    // skip venv directives if it's not the last one\n                    return acc;\n                }\n                acc.push((directive.clone(), source.clone()));\n                acc\n            });\n\n        // Save filtered_input for validation after processing\n        let filtered_input_for_validation = filtered_input.clone();\n\n        for (directive, source) in filtered_input {\n            let mut tera = get_tera(source.parent());\n            tera.register_function(\n                \"exec\",\n                tera_exec(\n                    source.parent().map(|d| d.to_path_buf()),\n                    env.iter()\n                        .map(|(k, (v, _))| (k.clone(), v.clone()))\n                        .collect(),\n                ),\n            );\n            // trace!(\n            //     \"resolve: directive: {:?}, source: {:?}\",\n            //     &directive,\n            //     &source\n            // );\n            let config_root = crate::config::config_file::config_root::config_root(&source);\n            ctx.insert(\"cwd\", &*dirs::CWD);\n            ctx.insert(\"config_root\", &config_root);\n            let env_vars = env\n                .iter()\n                .map(|(k, (v, _))| (k.clone(), v.clone()))\n                .collect::<EnvMap>();\n            ctx.insert(\"env\", &env_vars);\n\n            let mut vars: EnvMap = if let Some(Value::Object(existing_vars)) = ctx.get(\"vars\") {\n                existing_vars\n                    .iter()\n                    .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))\n                    .collect()\n            } else {\n                EnvMap::new()\n            };\n\n            vars.extend(r.vars.iter().map(|(k, (v, _))| (k.clone(), v.clone())));\n\n            ctx.insert(\"vars\", &vars);\n            let redact = directive.options().redact;\n            // trace!(\"resolve: ctx.get('env'): {:#?}\", &ctx.get(\"env\"));\n            match directive {\n                EnvDirective::Val(k, v, _opts) => {\n                    let v = r.parse_template(&ctx, &mut tera, &source, &v)?;\n\n                    if resolve_opts.vars {\n                        r.vars.insert(k, (v, source.clone()));\n                    } else {\n                        r.env_remove.remove(&k);\n                        // trace!(\"resolve: inserting {:?}={:?} from {:?}\", &k, &v, &source);\n                        if redact.unwrap_or(false) {\n                            r.redactions.push(k.clone());\n                        }\n                        env.insert(k, (v, Some(source.clone())));\n                    }\n                }\n                EnvDirective::Rm(k, _opts) => {\n                    env.shift_remove(&k);\n                    r.env_remove.insert(k);\n                }\n                EnvDirective::Required(_k, _opts) => {\n                    // Required directives don't set any value - they only validate during validation phase\n                    // The actual value must come from the initial environment or a later config file\n                }\n                EnvDirective::Age {\n                    key: ref k,\n                    ref options,\n                    ..\n                } => {\n                    // Decrypt age-encrypted value\n                    let res = crate::agecrypt::decrypt_age_directive(&directive).await;\n                    let decrypted_v = match res {\n                        Ok(decrypted_v) => {\n                            // Parse as template after decryption\n                            r.parse_template(&ctx, &mut tera, &source, &decrypted_v)?\n                        }\n                        Err(e) if Settings::get().age.strict => {\n                            return Err(e)\n                                .wrap_err(eyre!(\"[experimental] Failed to decrypt {}\", k));\n                        }\n                        Err(e) => {\n                            debug!(\n                                \"[experimental] Age decryption failed for {} but continuing in non-strict mode: {}\",\n                                k, e\n                            );\n                            // continue to the next directive\n                            continue;\n                        }\n                    };\n\n                    if resolve_opts.vars {\n                        r.vars.insert(k.clone(), (decrypted_v, source.clone()));\n                    } else {\n                        r.env_remove.remove(k);\n                        // Handle redaction for age-encrypted values\n                        // We're already in the EnvDirective::Age match arm, so we know this is an Age directive\n\n                        // For age-encrypted values, we default to redacting for security\n                        // With nullable redact, we can now distinguish between:\n                        // - None: not specified (default for age is to redact for security)\n                        // - Some(true): explicitly redact\n                        // - Some(false): explicitly don't redact\n                        debug!(\"Age directive {}: redact = {:?}\", k, options.redact);\n                        match options.redact {\n                            Some(false) => {\n                                // User explicitly set redact = false - don't redact\n                                debug!(\n                                    \"Age directive {}: NOT redacting (explicit redact = false)\",\n                                    k\n                                );\n                            }\n                            Some(true) | None => {\n                                // Either explicitly redact or use age default (redact for security)\n                                debug!(\n                                    \"Age directive {}: redacting (redact = {:?})\",\n                                    k, options.redact\n                                );\n                                r.redactions.push(k.clone());\n                            }\n                        }\n                        env.insert(k.clone(), (decrypted_v, Some(source.clone())));\n                    }\n                }\n                EnvDirective::Path(input_str, _opts) => {\n                    let path = Self::path(&mut ctx, &mut tera, &mut r, &source, input_str).await?;\n                    paths.push((path.clone(), source.clone()));\n                    // Don't modify PATH in env - just add to env_paths\n                    // This allows consumers to control PATH ordering\n                }\n                EnvDirective::File(input, _opts) => {\n                    let files = Self::file(\n                        config,\n                        &mut ctx,\n                        &mut tera,\n                        &mut r,\n                        normalize_path,\n                        &source,\n                        &config_root,\n                        input,\n                    )\n                    .await?;\n                    for (f, new_env) in files {\n                        r.env_files.push(f.clone());\n                        for (k, v) in new_env {\n                            if resolve_opts.vars {\n                                r.vars.insert(k, (v, f.clone()));\n                            } else {\n                                if redact.unwrap_or(false) {\n                                    r.redactions.push(k.clone());\n                                }\n                                env.insert(k, (v, Some(f.clone())));\n                            }\n                        }\n                    }\n                }\n                EnvDirective::Source(input, _opts) => {\n                    let files = Self::source(\n                        &mut ctx,\n                        &mut tera,\n                        &mut paths,\n                        &mut r,\n                        normalize_path,\n                        &source,\n                        &config_root,\n                        &env_vars,\n                        input,\n                    )?;\n                    for (f, new_env) in files {\n                        r.env_scripts.push(f.clone());\n                        for (k, v) in new_env {\n                            if resolve_opts.vars {\n                                r.vars.insert(k, (v, f.clone()));\n                            } else {\n                                if redact.unwrap_or(false) {\n                                    r.redactions.push(k.clone());\n                                }\n                                env.insert(k, (v, Some(f.clone())));\n                            }\n                        }\n                    }\n                }\n                EnvDirective::PythonVenv {\n                    path,\n                    create,\n                    python,\n                    uv_create_args,\n                    python_create_args,\n                    options: _opts,\n                } => {\n                    Self::venv(\n                        config,\n                        &mut ctx,\n                        &mut tera,\n                        &mut env,\n                        &mut r,\n                        normalize_path,\n                        &source,\n                        &config_root,\n                        env_vars,\n                        path,\n                        create,\n                        python,\n                        uv_create_args,\n                        python_create_args,\n                    )\n                    .await?;\n                }\n                EnvDirective::Module(name, value, _opts) => {\n                    let mut env_map: IndexMap<String, String> = env\n                        .iter()\n                        .map(|(k, (v, _))| (k.clone(), v.clone()))\n                        .collect();\n                    // Incorporate _.path entries accumulated so far into PATH\n                    // so that cmd.exec in the plugin can find tools on PATH.\n                    if !paths.is_empty() {\n                        let existing_path =\n                            env_map.get(&*env::PATH_KEY).cloned().unwrap_or_default();\n                        let mut path_env = PathEnv::from_path_str(&existing_path);\n                        for (p, path_source) in &paths {\n                            let config_root =\n                                crate::config::config_file::config_root::config_root(path_source);\n                            for s in env::split_paths(p) {\n                                path_env.add(normalize_path(&config_root, s));\n                            }\n                        }\n                        env_map.insert(env::PATH_KEY.to_string(), path_env.to_string());\n                    }\n                    Self::module(&mut r, config, source, name, &value, redact, env_map).await?;\n                }\n            };\n        }\n        let env_vars = env\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect::<HashMap<_, _>>();\n        ctx.insert(\"env\", &env_vars);\n        for (k, (v, source)) in env {\n            if let Some(source) = source {\n                r.env.insert(k, (v, source));\n            }\n        }\n        // trace!(\"resolve: paths: {:#?}\", &paths);\n        // trace!(\"resolve: ctx.env: {:#?}\", &ctx.get(\"env\"));\n        for (source, paths) in &paths.iter().chunk_by(|(_, source)| source) {\n            // Use the computed config_root (project root for nested configs) for path resolution\n            // to be consistent with other env directives like _.source and _.file\n            let config_root = crate::config::config_file::config_root::config_root(source);\n            let paths = paths.map(|(p, _)| p).collect_vec();\n            let mut paths = paths\n                .iter()\n                .rev()\n                .flat_map(|path| env::split_paths(path))\n                .map(|s| normalize_path(&config_root, s))\n                .collect::<Vec<_>>();\n            // r.env_paths is already reversed and paths should prepend r.env_paths\n            paths.reverse();\n            paths.extend(r.env_paths);\n            r.env_paths = paths;\n        }\n\n        // Validate required environment variables\n        Self::validate_required_env_vars(\n            &filtered_input_for_validation,\n            initial,\n            &r,\n            resolve_opts.warn_on_missing_required,\n        )?;\n\n        Ok(r)\n    }\n\n    fn validate_required_env_vars(\n        input: &[(EnvDirective, PathBuf)],\n        initial: &EnvMap,\n        env_results: &EnvResults,\n        warn_mode: bool,\n    ) -> eyre::Result<()> {\n        let mut required_vars = Vec::new();\n\n        // Collect all required environment variables with their options\n        for (directive, source) in input {\n            match directive {\n                EnvDirective::Val(key, _, options) if options.required.is_required() => {\n                    required_vars.push((key.clone(), source.clone(), options.required.clone()));\n                }\n                EnvDirective::Required(key, options) => {\n                    required_vars.push((key.clone(), source.clone(), options.required.clone()));\n                }\n                _ => {}\n            }\n        }\n\n        // Check if required variables are defined\n        for (var_name, declaring_source, required_value) in required_vars {\n            // Variable must be defined either:\n            // 1. In the initial environment (before mise runs), OR\n            // 2. In a config file processed later than the one declaring it as required\n            let is_predefined = initial.contains_key(&var_name);\n\n            let is_defined_later = if let Some((_, var_source)) = env_results.env.get(&var_name) {\n                // Check if the variable comes from a different config file\n                var_source != &declaring_source\n            } else {\n                false\n            };\n\n            if !is_predefined && !is_defined_later {\n                let base_message = format!(\n                    \"Required environment variable '{}' is not defined. It must be set before mise runs or in a later config file. (Required in: {})\",\n                    var_name,\n                    display_path(declaring_source)\n                );\n\n                let message = if let Some(help) = required_value.help_text() {\n                    format!(\"{}\\nHelp: {}\", base_message, help)\n                } else {\n                    base_message\n                };\n\n                if warn_mode {\n                    warn!(\"{}\", message);\n                } else {\n                    return Err(eyre!(\"{}\", message));\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn parse_template(\n        &self,\n        ctx: &tera::Context,\n        tera: &mut tera::Tera,\n        path: &Path,\n        input: &str,\n    ) -> eyre::Result<String> {\n        let mut output = input.to_string();\n\n        // Step 1: Tera template expansion\n        if input.contains(\"{{\") || input.contains(\"{%\") || input.contains(\"{#\") {\n            trust_check(path)?;\n            output = tera\n                .render_str(input, ctx)\n                .wrap_err_with(|| eyre!(\"failed to parse template: '{input}'\"))?;\n        }\n\n        // Step 2: Shell-style $VAR expansion\n        if output.contains('$') {\n            debug_assert!(\n                !env!(\"CARGO_PKG_VERSION\").starts_with(\"2026.7\"),\n                \"change env_shell_expand default to true and remove this warning\"\n            );\n            match Settings::get().env_shell_expand {\n                Some(true) => {\n                    let env_vars: BTreeMap<String, String> = ctx\n                        .get(\"env\")\n                        .and_then(|v| serde_json::from_value(v.clone()).ok())\n                        .unwrap_or_default();\n                    let before_expand = output.clone();\n                    let mut missing_vars = Vec::new();\n                    output = shellexpand::env_with_context_no_errors(&output, |var| match env_vars\n                        .get(var)\n                    {\n                        Some(v) => Some(Cow::Borrowed(v.as_str())),\n                        None => {\n                            missing_vars.push(var.to_string());\n                            None\n                        }\n                    })\n                    .into_owned();\n                    for var in missing_vars {\n                        // Don't warn if the user provided a default via ${VAR:-...} or ${VAR-...}\n                        if !before_expand.contains(&format!(\"${{{var}:-\"))\n                            && !before_expand.contains(&format!(\"${{{var}-\"))\n                        {\n                            warn_once!(\n                                \"env var '{var}' is not defined and will be left unexpanded. \\\n                                 Use ${{{var}:-}} to default to an empty string and suppress \\\n                                 this warning.\"\n                            );\n                        }\n                    }\n                }\n                Some(false) => {}\n                None => {\n                    warn_once!(\n                        \"env value contains '$' which will be expanded in a future release. \\\n                         Set `env_shell_expand = true` to opt in or `env_shell_expand = false` to \\\n                         keep current behavior and suppress this warning.\"\n                    );\n                }\n            }\n        }\n\n        Ok(output)\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.env.is_empty()\n            && self.vars.is_empty()\n            && self.env_remove.is_empty()\n            && self.env_files.is_empty()\n            && self.env_paths.is_empty()\n            && self.env_scripts.is_empty()\n            && self.tool_add_paths.is_empty()\n    }\n}\n\nimpl Debug for EnvResults {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let mut ds = f.debug_struct(\"EnvResults\");\n        if !self.env.is_empty() {\n            ds.field(\"env\", &self.env.keys().collect::<Vec<_>>());\n        }\n        if !self.vars.is_empty() {\n            ds.field(\"vars\", &self.vars.keys().collect::<Vec<_>>());\n        }\n        if !self.env_remove.is_empty() {\n            ds.field(\"env_remove\", &self.env_remove);\n        }\n        if !self.env_files.is_empty() {\n            ds.field(\"env_files\", &self.env_files);\n        }\n        if !self.env_paths.is_empty() {\n            ds.field(\"env_paths\", &self.env_paths);\n        }\n        if !self.env_scripts.is_empty() {\n            ds.field(\"env_scripts\", &self.env_scripts);\n        }\n        if !self.tool_add_paths.is_empty() {\n            ds.field(\"tool_add_paths\", &self.tool_add_paths);\n        }\n        ds.finish()\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/module.rs",
    "content": "use crate::Result;\nuse crate::config::Config;\nuse crate::config::env_directive::EnvResults;\nuse crate::dirs;\nuse crate::plugins::Plugin;\nuse crate::plugins::vfox_plugin::VfoxPlugin;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse heck::ToKebabCase;\nuse indexmap::IndexMap;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse toml::Value;\n\nimpl EnvResults {\n    pub async fn module(\n        r: &mut EnvResults,\n        config: &Arc<Config>,\n        source: PathBuf,\n        name: String,\n        value: &Value,\n        redact: Option<bool>,\n        env: IndexMap<String, String>,\n    ) -> Result<()> {\n        let path = dirs::PLUGINS.join(name.to_kebab_case());\n        let plugin = VfoxPlugin::new(name, path.clone());\n        plugin\n            .ensure_installed(config, &MultiProgressReport::get(), false, false)\n            .await?;\n        if let Some(response) = plugin.mise_env(value, &env).await? {\n            // Track cacheability\n            if !response.cacheable {\n                r.has_uncacheable = true;\n            }\n\n            // Add plugin directory to watch files for cache invalidation\n            // This ensures cache invalidates when plugin is updated\n            r.watch_files.push(path);\n\n            // Add watch files for cache invalidation\n            // Absolutize relative paths to ensure consistent cache validation\n            // regardless of which directory mise is run from\n            let cwd = std::env::current_dir().unwrap_or_default();\n            for watch_file in response.watch_files {\n                if watch_file.is_absolute() {\n                    r.watch_files.push(watch_file);\n                } else {\n                    r.watch_files.push(cwd.join(watch_file));\n                }\n            }\n\n            // Add env vars\n            // User's explicit redact setting takes priority, otherwise use plugin's preference\n            let should_redact = redact.unwrap_or(response.redact);\n            for (k, v) in response.env {\n                if should_redact {\n                    r.redactions.push(k.clone());\n                }\n                r.env.insert(k, (v, source.clone()));\n            }\n        }\n        if let Some(path) = plugin.mise_path(value, &env).await? {\n            for p in path {\n                r.env_paths.push(p.into());\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/path.rs",
    "content": "use crate::config::env_directive::EnvResults;\nuse crate::result;\nuse std::path::{Path, PathBuf};\n\nimpl EnvResults {\n    pub async fn path(\n        ctx: &mut tera::Context,\n        tera: &mut tera::Tera,\n        r: &mut EnvResults,\n        source: &Path,\n        input: String,\n    ) -> result::Result<PathBuf> {\n        r.parse_template(ctx, tera, source, &input)\n            .map(PathBuf::from)\n    }\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use super::*;\n    use crate::config::{\n        Config,\n        env_directive::{EnvDirective, EnvResolveOptions, ToolsFilter},\n    };\n    use crate::env_diff::EnvMap;\n    use crate::tera::BASE_CONTEXT;\n    use crate::test::replace_path;\n    use insta::assert_debug_snapshot;\n\n    #[tokio::test]\n    async fn test_env_path() {\n        let mut env = EnvMap::new();\n        env.insert(\"A\".to_string(), \"1\".to_string());\n        env.insert(\"B\".to_string(), \"2\".to_string());\n        let config = Config::get().await.unwrap();\n        let results = EnvResults::resolve(\n            &config,\n            BASE_CONTEXT.clone(),\n            &env,\n            vec![\n                (\n                    EnvDirective::Path(\"/path/1\".into(), Default::default()),\n                    PathBuf::from(\"/config\"),\n                ),\n                (\n                    EnvDirective::Path(\"/path/2\".into(), Default::default()),\n                    PathBuf::from(\"/config\"),\n                ),\n                (\n                    EnvDirective::Path(\"~/foo/{{ env.A }}\".into(), Default::default()),\n                    Default::default(),\n                ),\n                (\n                    EnvDirective::Path(\n                        \"./rel/{{ env.A }}:./rel2/{{env.B}}\".into(),\n                        Default::default(),\n                    ),\n                    Default::default(),\n                ),\n            ],\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::NonToolsOnly,\n                warn_on_missing_required: false,\n            },\n        )\n        .await\n        .unwrap();\n        assert_debug_snapshot!(\n            results.env_paths.into_iter().map(|p| replace_path(&p.display().to_string())).collect::<Vec<_>>(),\n            @r#\"\n        [\n            \"~/foo/1\",\n            \"~/rel2/2\",\n            \"~/rel/1\",\n            \"/path/1\",\n            \"/path/2\",\n        ]\n        \"#\n        );\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/source.rs",
    "content": "use crate::Result;\nuse crate::config::env_directive::EnvResults;\nuse crate::env;\nuse crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffOptions, EnvMap};\nuse indexmap::IndexMap;\nuse std::path::{Path, PathBuf};\n\nimpl EnvResults {\n    #[allow(clippy::too_many_arguments)]\n    pub fn source(\n        ctx: &mut tera::Context,\n        tera: &mut tera::Tera,\n        paths: &mut Vec<(PathBuf, PathBuf)>,\n        r: &mut EnvResults,\n        normalize_path: fn(&Path, PathBuf) -> PathBuf,\n        source: &Path,\n        config_root: &Path,\n        env_vars: &EnvMap,\n        input: String,\n    ) -> Result<IndexMap<PathBuf, IndexMap<String, String>>> {\n        let mut out = IndexMap::new();\n        let s = r.parse_template(ctx, tera, source, &input)?;\n        let orig_path = env_vars.get(&*env::PATH_KEY).cloned().unwrap_or_default();\n        let mut env_diff_opts = EnvDiffOptions::default();\n        env_diff_opts.ignore_keys.shift_remove(&*env::PATH_KEY); // allow modifying PATH\n        for p in xx::file::glob(normalize_path(config_root, s.into())).unwrap_or_default() {\n            if !p.exists() {\n                continue;\n            }\n            let env = out.entry(p.clone()).or_insert_with(IndexMap::new);\n            let env_diff =\n                EnvDiff::from_bash_script(&p, config_root, env_vars.clone(), &env_diff_opts)?;\n            for p in env_diff.to_patches() {\n                match p {\n                    EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => {\n                        if k == *env::PATH_KEY {\n                            // TODO: perhaps deal with path removals as well\n                            if let Some(new_path) = v.strip_suffix(&orig_path) {\n                                for p in env::split_paths(new_path) {\n                                    paths.push((p, source.to_path_buf()));\n                                }\n                            }\n                        } else {\n                            r.env_remove.remove(&k);\n                            env.insert(k.clone(), v.clone());\n                        }\n                    }\n                    EnvDiffOperation::Remove(k) => {\n                        env.shift_remove(&k);\n                        r.env_remove.insert(k);\n                    }\n                }\n            }\n        }\n        Ok(out)\n    }\n}\n"
  },
  {
    "path": "src/config/env_directive/venv.rs",
    "content": "use crate::Result;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::config_file::trust_check;\nuse crate::config::env_directive::EnvResults;\nuse crate::config::{Config, Settings};\nuse crate::env_diff::EnvMap;\nuse crate::file::{display_path, which_no_shims};\nuse crate::lock_file::LockFile;\nuse crate::toolset::Toolset;\nuse crate::{backend, plugins};\nuse indexmap::IndexMap;\nuse std::collections::{HashMap, HashSet};\nuse std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\n#[derive(Clone, Debug)]\npub struct Venv {\n    pub venv_path: PathBuf,\n    pub env: HashMap<String, String>,\n}\n\npub(crate) fn load_venv(\n    venv_root: &Path,\n    extra_env: impl IntoIterator<Item = (String, String)>,\n) -> Venv {\n    #[cfg(windows)]\n    let venv_bin_dir = \"Scripts\";\n    #[cfg(not(windows))]\n    let venv_bin_dir = \"bin\";\n\n    let mut env = HashMap::new();\n    env.extend(extra_env);\n    env.insert(\n        \"VIRTUAL_ENV\".to_string(),\n        venv_root.to_string_lossy().to_string(),\n    );\n    Venv {\n        venv_path: venv_root.join(venv_bin_dir),\n        env,\n    }\n}\n\nfn build_uv_venv_command<'a>(\n    uv_bin: PathBuf,\n    venv: &'a Path,\n    python_path: Option<&'a str>,\n    python: Option<&'a str>,\n    uv_create_args: Option<Vec<String>>,\n) -> CmdLineRunner<'a> {\n    info!(\"creating venv with uv at: {}\", display_path(venv));\n    let extra = uv_create_args\n        .or(Settings::get().python.uv_venv_create_args.clone())\n        .unwrap_or_default();\n    let mut cmd = CmdLineRunner::new(uv_bin).args([\"venv\", &venv.to_string_lossy()]);\n\n    cmd = match (python_path, python) {\n        // The selected mise managed python tool path from env._.python.venv.python or first in list\n        (Some(python_path), _) => cmd.args([\"--python\", python_path]),\n        // User specified in env._.python.venv.python but it's not in mise tools, so pass version number to uv\n        (_, Some(python)) => cmd.args([\"--python\", python]),\n        // Default to whatever uv wants to use\n        _ => cmd,\n    };\n    cmd.args(extra)\n}\n\nfn build_stdlib_venv_command<'a>(\n    venv: &'a Path,\n    python_path: Option<&'a str>,\n    python: Option<&'a str>,\n    python_create_args: Option<Vec<String>>,\n) -> CmdLineRunner<'a> {\n    info!(\"creating venv with stdlib at: {}\", display_path(venv));\n    let extra = python_create_args\n        .or(Settings::get().python.venv_create_args.clone())\n        .unwrap_or_default();\n\n    let bin = match (python_path, python) {\n        // The selected mise managed python tool path from env._.python.venv.python or first in list\n        (Some(python_path), _) => python_path.to_string(),\n        // User specified in env._.python.venv.python but it's not in mise tools, so try to find it on path\n        (_, Some(python)) => format!(\"python{python}\"),\n        // Default to whatever python3 points to on path\n        _ => \"python3\".to_string(),\n    };\n\n    CmdLineRunner::new(bin)\n        .args([\"-m\", \"venv\", &venv.to_string_lossy()])\n        .args(extra)\n}\n\n#[allow(clippy::too_many_arguments)]\npub(crate) async fn create_python_venv(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    venv: &Path,\n    env_vars: EnvMap,\n    python: Option<&str>,\n    uv_create_args: Option<Vec<String>>,\n    python_create_args: Option<Vec<String>>,\n    require_uv: bool,\n) -> Result<bool> {\n    let ba = BackendArg::from(\"python\");\n    let tv = ts.versions.get(&ba).and_then(|tv| {\n        // if a python version is specified, check if that version is installed\n        // otherwise use the first since that's what `python3` will refer to\n        if let Some(v) = python {\n            tv.versions.iter().find(|t| t.version.starts_with(v))\n        } else {\n            tv.versions.first()\n        }\n    });\n    let python_path = tv.map(|tv| {\n        plugins::core::python::python_path(tv)\n            .to_string_lossy()\n            .to_string()\n    });\n    let installed = if let Some(tv) = tv {\n        let backend = backend::get(&ba).unwrap();\n        backend.is_version_installed(config, tv, false)\n    } else {\n        // if no version is specified, we're assuming python3 is provided outside of mise so return \"true\" here\n        true\n    };\n    if !installed {\n        warn_once!(\n            \"no venv found at: {p}\\n\\n\\\n            mise will automatically create the venv once all requested python versions are installed.\\n\\\n            To install the missing python versions and create the venv, please run:\\n\\\n            `mise install`\",\n            p = display_path(venv)\n        );\n        return Ok(false);\n    }\n\n    let uv_bin = ts\n        .which_bin(config, \"uv\")\n        .await\n        .or_else(|| which_no_shims(\"uv\"));\n\n    if require_uv && uv_bin.is_none() {\n        warn_once!(\n            \"uv is required to create the venv at {p} but is not installed\",\n            p = display_path(venv)\n        );\n        return Ok(false);\n    }\n\n    let use_uv = require_uv || (!Settings::get().python.venv_stdlib && uv_bin.is_some());\n    let cmd = if use_uv {\n        build_uv_venv_command(\n            uv_bin.unwrap(),\n            venv,\n            python_path.as_deref(),\n            python,\n            uv_create_args,\n        )\n    } else {\n        build_stdlib_venv_command(venv, python_path.as_deref(), python, python_create_args)\n    }\n    .envs(env_vars);\n    cmd.execute()?;\n    // Mark venv as stale so prepare knows to run\n    crate::prepare::mark_output_stale(venv.to_path_buf());\n    Ok(true)\n}\n\nimpl EnvResults {\n    #[allow(clippy::too_many_arguments)]\n    pub async fn venv(\n        config: &Arc<Config>,\n        ctx: &mut tera::Context,\n        tera: &mut tera::Tera,\n        env: &mut IndexMap<String, (String, Option<PathBuf>)>,\n        r: &mut EnvResults,\n        normalize_path: fn(&Path, PathBuf) -> PathBuf,\n        source: &Path,\n        config_root: &Path,\n        env_vars: EnvMap,\n        path: String,\n        create: bool,\n        python: Option<String>,\n        uv_create_args: Option<Vec<String>>,\n        python_create_args: Option<Vec<String>>,\n    ) -> Result<()> {\n        trace!(\"python venv: {} create={create}\", display_path(&path));\n        trust_check(source)?;\n        let venv = r.parse_template(ctx, tera, source, &path)?;\n        let venv = normalize_path(config_root, venv.into());\n        let venv_lock = LockFile::new(&venv).lock()?;\n        if !venv.exists() && create {\n            // TODO: the toolset stuff doesn't feel like it's in the right place here\n            // TODO: in fact this should probably be moved to execute at the same time as src/uv.rs runs in ts.env() instead of config.env()\n            // Build a toolset with only Python and UV tools to avoid circular dependency deadlock.\n            // When all tools are resolved (including go:* tools), those tools may need to access\n            // the environment via dependency_toolset(), which tries to call config.env() again,\n            // creating a circular wait since we're already in the middle of resolving the venv\n            // directive as part of config.env().\n            // By filtering to only Python/UV BEFORE resolution, we avoid resolving unrelated tools\n            // that have their own dependencies and environment requirements.\n            let trs = config.get_tool_request_set().await?;\n            let mut filter = HashSet::new();\n            filter.insert(\"python\".to_string());\n            filter.insert(\"uv\".to_string());\n            let filtered_trs = trs.filter_by_tool(filter);\n\n            // Convert the filtered tool request set to a toolset and resolve only these tools\n            let mut ts: Toolset = filtered_trs.into();\n            // Ignore resolution errors for venv creation - if tools aren't available, we'll warn below\n            let _ = ts.resolve(config).await;\n            create_python_venv(\n                config,\n                &ts,\n                &venv,\n                env_vars,\n                python.as_deref(),\n                uv_create_args,\n                python_create_args,\n                false,\n            )\n            .await?;\n        }\n        drop(venv_lock);\n        if venv.exists() {\n            let Venv {\n                venv_path,\n                env: venv_env,\n            } = load_venv(&venv, HashMap::new());\n            r.env_paths.insert(0, venv_path);\n            for (k, v) in venv_env {\n                env.insert(k, (v, Some(source.to_path_buf())));\n            }\n        } else if !create {\n            // The create \"no venv found\" warning is handled elsewhere\n            warn_once!(\n                \"no venv found at: {p}\nTo create a virtualenv manually, run:\npython -m venv {p}\",\n                p = display_path(&venv)\n            );\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use super::*;\n    use crate::config::env_directive::{\n        EnvDirective, EnvDirectiveOptions, EnvResolveOptions, ToolsFilter,\n    };\n    use crate::tera::BASE_CONTEXT;\n    use crate::test::replace_path;\n    use insta::assert_debug_snapshot;\n\n    #[tokio::test]\n    async fn test_venv_path() {\n        let env = EnvMap::new();\n        let config = Config::get().await.unwrap();\n        let results = EnvResults::resolve(\n            &config,\n            BASE_CONTEXT.clone(),\n            &env,\n            vec![\n                (\n                    EnvDirective::PythonVenv {\n                        path: \"/\".into(),\n                        create: false,\n                        python: None,\n                        uv_create_args: None,\n                        python_create_args: None,\n                        options: EnvDirectiveOptions {\n                            tools: true,\n                            redact: Some(false),\n                            required: crate::config::env_directive::RequiredValue::False,\n                        },\n                    },\n                    Default::default(),\n                ),\n                (\n                    EnvDirective::PythonVenv {\n                        path: \"./\".into(),\n                        create: false,\n                        python: None,\n                        uv_create_args: None,\n                        python_create_args: None,\n                        options: EnvDirectiveOptions {\n                            tools: true,\n                            redact: Some(false),\n                            required: crate::config::env_directive::RequiredValue::False,\n                        },\n                    },\n                    Default::default(),\n                ),\n            ],\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::ToolsOnly,\n                warn_on_missing_required: false,\n            },\n        )\n        .await\n        .unwrap();\n        // expect order to be reversed as it processes directives from global to dir specific\n        assert_debug_snapshot!(\n            results.env_paths.into_iter().map(|p| replace_path(&p.display().to_string())).collect::<Vec<_>>(),\n            @r#\"\n        [\n            \"~/bin\",\n        ]\n        \"#\n        );\n    }\n}\n"
  },
  {
    "path": "src/config/miserc.rs",
    "content": "//! Early initialization settings from .miserc.toml\n//!\n//! This module handles loading settings that need to be known before the main\n//! config files are parsed. The primary use case is setting MISE_ENV, which\n//! determines which environment-specific config files (e.g., mise.development.toml)\n//! to load.\n\nuse std::collections::BTreeSet;\nuse std::path::{Path, PathBuf};\nuse std::sync::OnceLock;\n\nuse eyre::Result;\n\nuse crate::config::settings::MisercSettings;\nuse crate::dirs;\nuse crate::env;\nuse crate::file;\n\nstatic MISERC: OnceLock<MisercSettings> = OnceLock::new();\n\n/// Initialize miserc settings by loading .miserc.toml files.\n/// This must be called early in the initialization process, before\n/// MISE_ENV or other early settings are accessed.\npub fn init() -> Result<()> {\n    let settings = load_miserc_settings()?;\n    let _ = MISERC.set(settings);\n    Ok(())\n}\n\n/// Get the loaded miserc settings, or default if not initialized.\npub fn get() -> &'static MisercSettings {\n    MISERC.get_or_init(|| load_miserc_settings().unwrap_or_default())\n}\n\n/// Get the MISE_ENV value from miserc, if set.\npub fn get_env() -> Option<&'static Vec<String>> {\n    get().env.as_ref()\n}\n\n/// Get the ceiling_paths value from miserc, if set.\npub fn get_ceiling_paths() -> Option<&'static BTreeSet<PathBuf>> {\n    get().ceiling_paths.as_ref()\n}\n\n/// Get the ignored_config_paths value from miserc, if set.\npub fn get_ignored_config_paths() -> Option<&'static BTreeSet<PathBuf>> {\n    get().ignored_config_paths.as_ref()\n}\n\n/// Get the override_config_filenames value from miserc, if set.\npub fn get_override_config_filenames() -> Option<&'static Vec<String>> {\n    get().override_config_filenames.as_ref()\n}\n\n/// Get the override_tool_versions_filenames value from miserc, if set.\npub fn get_override_tool_versions_filenames() -> Option<&'static Vec<String>> {\n    get().override_tool_versions_filenames.as_ref()\n}\n\n/// Load and merge all miserc settings files.\n/// Precedence (highest to lowest):\n/// 1. Local .miserc.toml and .config/miserc.toml (closest to cwd wins)\n/// 2. Global ~/.config/mise/miserc.toml\n/// 3. System /etc/mise/miserc.toml\nfn load_miserc_settings() -> Result<MisercSettings> {\n    let mut merged = MisercSettings::default();\n\n    // Load in reverse precedence order so later loads override earlier ones\n    let files = find_miserc_files();\n\n    for path in files.into_iter().rev() {\n        if let Ok(content) = file::read_to_string(&path) {\n            match toml::from_str::<MisercSettings>(&content) {\n                Ok(settings) => {\n                    merge_settings(&mut merged, settings);\n                }\n                Err(e) => {\n                    warn!(\"Failed to parse {}: {}\", path.display(), e);\n                }\n            }\n        }\n    }\n\n    Ok(merged)\n}\n\n/// Merge source settings into target, where source values override target.\nfn merge_settings(target: &mut MisercSettings, source: MisercSettings) {\n    if source.env.is_some() {\n        target.env = source.env;\n    }\n    if source.ceiling_paths.is_some() {\n        target.ceiling_paths = source.ceiling_paths;\n    }\n    if source.ignored_config_paths.is_some() {\n        target.ignored_config_paths = source.ignored_config_paths;\n    }\n    if source.override_config_filenames.is_some() {\n        target.override_config_filenames = source.override_config_filenames;\n    }\n    if source.override_tool_versions_filenames.is_some() {\n        target.override_tool_versions_filenames = source.override_tool_versions_filenames;\n    }\n}\n\n/// Find all miserc.toml files in order of precedence (highest first).\nfn find_miserc_files() -> Vec<PathBuf> {\n    let mut files = Vec::new();\n\n    // Local hierarchy: .miserc.toml and .config/miserc.toml in cwd and ancestors\n    // Use raw std::env to avoid depending on our lazy statics\n    if let Ok(cwd) = std::env::current_dir() {\n        // Walk up the directory tree, but stop at home or root\n        let home: &Path = &dirs::HOME;\n        for dir in cwd.ancestors() {\n            let path = dir.join(\".miserc.toml\");\n            if path.is_file() {\n                files.push(path);\n            }\n            // Stop at home directory to avoid searching too far\n            if dir == home || dir.parent().is_none() {\n                break;\n            }\n            let path = dir.join(\".config\").join(\"miserc.toml\");\n            if path.is_file() {\n                files.push(path);\n            }\n        }\n    }\n\n    // Global: ~/.config/mise/miserc.toml\n    let global_path = dirs::CONFIG.join(\"miserc.toml\");\n    if global_path.is_file() {\n        files.push(global_path);\n    }\n\n    // System: /etc/mise/miserc.toml (or MISE_SYSTEM_CONFIG_DIR)\n    let system_dir = env::MISE_SYSTEM_CONFIG_DIR.clone();\n    let system_path = system_dir.join(\"miserc.toml\");\n    if system_path.is_file() {\n        files.push(system_path);\n    }\n\n    files\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_merge_settings() {\n        let mut target = MisercSettings {\n            env: Some(vec![\"base\".to_string()]),\n            ..Default::default()\n        };\n\n        let source = MisercSettings {\n            env: Some(vec![\"override\".to_string()]),\n            ..Default::default()\n        };\n\n        merge_settings(&mut target, source);\n\n        assert_eq!(target.env, Some(vec![\"override\".to_string()]));\n    }\n\n    #[test]\n    fn test_parse_miserc() {\n        let content = r#\"\nenv = [\"development\", \"local\"]\nceiling_paths = [\"/home/user\"]\n\"#;\n        let settings: MisercSettings = toml::from_str(content).unwrap();\n        assert_eq!(\n            settings.env,\n            Some(vec![\"development\".to_string(), \"local\".to_string()])\n        );\n        assert!(settings.ceiling_paths.is_some());\n    }\n}\n"
  },
  {
    "path": "src/config/mod.rs",
    "content": "use dashmap::DashMap;\nuse eyre::{Context, Result, bail, eyre};\nuse indexmap::{IndexMap, IndexSet};\nuse itertools::Itertools;\npub use settings::Settings;\nuse std::collections::{BTreeMap, BTreeSet, HashMap};\nuse std::env::join_paths;\nuse std::fmt::{Debug, Formatter};\nuse std::iter::once;\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::sync::{Arc, Mutex, RwLock};\nuse std::time::{Duration, SystemTime};\nuse tokio::{sync::OnceCell, task::JoinSet};\nuse walkdir::WalkDir;\n\nuse crate::backend::ABackend;\nuse crate::cli::args::BackendArg;\nuse crate::cli::version;\nuse crate::config::config_file::idiomatic_version::IdiomaticVersionFile;\nuse crate::config::config_file::min_version::MinVersionSpec;\nuse crate::config::config_file::mise_toml::{MiseToml, Tasks};\nuse crate::config::config_file::{ConfigFile, config_trust_root};\nuse crate::config::env_directive::{EnvResolveOptions, EnvResults, ToolsFilter};\nuse crate::config::tracking::Tracker;\nuse crate::env::{MISE_DEFAULT_CONFIG_FILENAME, MISE_DEFAULT_TOOL_VERSIONS_FILENAME};\nuse crate::file::display_path;\nuse crate::shorthands::{Shorthands, get_shorthands};\nuse crate::task::task_file_providers::TaskFileProvidersBuilder;\nuse crate::task::{Task, TaskTemplate};\nuse crate::tera::take_tera_accessed_files;\nuse crate::toolset::env_cache::{CachedNonToolEnv, compute_settings_hash, get_file_mtime};\nuse crate::toolset::{\n    ToolRequestSet, ToolRequestSetBuilder, ToolVersion, ToolVersionOptions, Toolset, install_state,\n};\nuse crate::ui::style;\nuse crate::{backend, dirs, env, file, lockfile, registry, runtime_symlinks, shims, timeout};\n\npub mod config_file;\npub mod env_directive;\npub mod miserc;\npub mod settings;\npub mod tracking;\n\nuse crate::env_diff::EnvMap;\nuse crate::hook_env::WatchFilePattern;\nuse crate::hooks::Hook;\nuse crate::plugins::PluginType;\nuse crate::redactions::Redactor;\nuse crate::tera::BASE_CONTEXT;\nuse crate::watch_files::WatchFile;\nuse crate::wildcard::Wildcard;\n\ntype AliasMap = IndexMap<String, Alias>;\npub(crate) type ConfigMap = IndexMap<PathBuf, Arc<dyn ConfigFile>>;\npub type EnvWithSources = IndexMap<String, (String, PathBuf)>;\n\npub struct Config {\n    pub config_files: ConfigMap,\n    pub project_root: Option<PathBuf>,\n    pub all_aliases: AliasMap,\n    pub repo_urls: HashMap<String, String>,\n    pub vars: IndexMap<String, String>,\n    pub tera_ctx: tera::Context,\n    pub shorthands: Shorthands,\n    pub shell_aliases: EnvWithSources,\n    /// Files accessed by tera template functions (read_file, hash_file, etc.)\n    /// during shell alias template rendering, used to watch for changes in hook-env.\n    pub tera_files: Vec<PathBuf>,\n    aliases: AliasMap,\n    env: OnceCell<EnvResults>,\n    env_with_sources: OnceCell<EnvWithSources>,\n    hooks: OnceCell<Vec<(PathBuf, Hook)>>,\n    tasks_cache: Arc<DashMap<crate::task::TaskLoadContext, Arc<BTreeMap<String, Task>>>>,\n    tool_request_set: OnceCell<ToolRequestSet>,\n    toolset: OnceCell<Toolset>,\n    vars_loader: Option<Arc<Config>>,\n    vars_results: OnceCell<EnvResults>,\n}\n\n#[derive(Debug, Clone, Default)]\npub struct Alias {\n    pub backend: Option<String>,\n    pub versions: IndexMap<String, String>,\n}\n\nstatic _CONFIG: RwLock<Option<Arc<Config>>> = RwLock::new(None);\nstatic _REDACTOR: Lazy<Mutex<Redactor>> = Lazy::new(Default::default);\n\npub fn is_loaded() -> bool {\n    _CONFIG.read().unwrap().is_some()\n}\n\nimpl Config {\n    pub async fn get() -> Result<Arc<Self>> {\n        if let Some(config) = &*_CONFIG.read().unwrap() {\n            return Ok(config.clone());\n        }\n        measure!(\"load config\", { Self::load().await })\n    }\n    pub fn maybe_get() -> Option<Arc<Self>> {\n        _CONFIG.read().unwrap().as_ref().cloned()\n    }\n    pub fn get_() -> Arc<Self> {\n        (*_CONFIG.read().unwrap()).clone().unwrap()\n    }\n    pub async fn reset() -> Result<Arc<Self>> {\n        backend::reset().await?;\n        timeout::run_with_timeout_async(\n            async || {\n                _CONFIG.write().unwrap().take();\n                *GLOBAL_CONFIG_FILES.lock().unwrap() = None;\n                *SYSTEM_CONFIG_FILES.lock().unwrap() = None;\n                GLOB_RESULTS.lock().unwrap().clear();\n                crate::task::reset();\n                Ok(())\n            },\n            Duration::from_secs(5),\n        )\n        .await?;\n        Config::load().await\n    }\n\n    #[async_backtrace::framed]\n    pub async fn load() -> Result<Arc<Self>> {\n        backend::load_tools().await?;\n        let idiomatic_files = measure!(\"config::load idiomatic_files\", {\n            load_idiomatic_filenames().await\n        });\n        let config_filenames = idiomatic_files\n            .keys()\n            .chain(DEFAULT_CONFIG_FILENAMES.iter())\n            .cloned()\n            .collect_vec();\n        let config_paths = measure!(\"config::load config_paths\", {\n            load_config_paths(&config_filenames, false)\n        });\n        trace!(\"config_paths: {config_paths:?}\");\n        let config_files = measure!(\"config::load config_files\", {\n            load_all_config_files(&config_paths, &idiomatic_files).await?\n        });\n\n        let mut config = Self {\n            tera_ctx: BASE_CONTEXT.clone(),\n            config_files,\n            env: OnceCell::new(),\n            env_with_sources: OnceCell::new(),\n            shorthands: get_shorthands(&Settings::get()),\n            hooks: OnceCell::new(),\n            tasks_cache: Arc::new(DashMap::new()),\n            tool_request_set: OnceCell::new(),\n            toolset: OnceCell::new(),\n            all_aliases: Default::default(),\n            aliases: Default::default(),\n            project_root: Default::default(),\n            repo_urls: Default::default(),\n            shell_aliases: Default::default(),\n            tera_files: Default::default(),\n            vars: Default::default(),\n            vars_loader: None,\n            vars_results: OnceCell::new(),\n        };\n        let vars_config = Arc::new(Self {\n            tera_ctx: config.tera_ctx.clone(),\n            config_files: config.config_files.clone(),\n            env: OnceCell::new(),\n            env_with_sources: OnceCell::new(),\n            shorthands: config.shorthands.clone(),\n            hooks: OnceCell::new(),\n            tasks_cache: Arc::new(DashMap::new()),\n            tool_request_set: OnceCell::new(),\n            toolset: OnceCell::new(),\n            all_aliases: config.all_aliases.clone(),\n            aliases: config.aliases.clone(),\n            project_root: config.project_root.clone(),\n            repo_urls: config.repo_urls.clone(),\n            shell_aliases: config.shell_aliases.clone(),\n            tera_files: config.tera_files.clone(),\n            vars: config.vars.clone(),\n            vars_loader: None,\n            vars_results: OnceCell::new(),\n        });\n        let vars_results = measure!(\"config::load vars_results\", {\n            let results = load_vars(&vars_config).await?;\n            vars_config.vars_results.set(results.clone()).ok();\n            config.vars_results.set(results.clone()).ok();\n            config.vars_loader = Some(vars_config.clone());\n            results\n        });\n        let vars: IndexMap<String, String> = vars_results\n            .vars\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect();\n        config.tera_ctx.insert(\"vars\", &vars);\n\n        config.vars = vars;\n        config.aliases = load_aliases(&config.config_files)?;\n        // Clear any previously tracked files before loading shell aliases\n        let _ = take_tera_accessed_files();\n        config.shell_aliases = load_shell_aliases(&config.config_files)?;\n        config.tera_files = take_tera_accessed_files();\n        config.project_root = get_project_root(&config.config_files);\n        config.repo_urls = load_plugins(&config.config_files)?;\n        measure!(\"config::load validate\", {\n            config.validate()?;\n        });\n\n        config.all_aliases = measure!(\"config::load all_aliases\", { config.load_all_aliases() });\n\n        measure!(\"config::load redactions\", {\n            config.add_redactions(\n                config.redaction_keys(),\n                &config.vars.clone().into_iter().collect(),\n            );\n        });\n\n        if log::log_enabled!(log::Level::Trace) {\n            trace!(\"config: {config:#?}\");\n        } else if log::log_enabled!(log::Level::Debug) {\n            for p in config.config_files.keys() {\n                debug!(\"config: {}\", display_path(p));\n            }\n        }\n\n        time!(\"load done\");\n\n        measure!(\"config::load install_state\", {\n            for (plugin, url) in &config.repo_urls {\n                // check plugin type, fallback to asdf\n                let (mut plugin_type, has_explicit_prefix) = match plugin {\n                    p if p.starts_with(\"vfox:\") => (PluginType::Vfox, true),\n                    p if p.starts_with(\"vfox-backend:\") => (PluginType::VfoxBackend, true),\n                    p if p.starts_with(\"asdf:\") => (PluginType::Asdf, true),\n                    _ => (PluginType::Asdf, false),\n                };\n                // keep backward compatibility for vfox plugins, but only if no explicit prefix\n                if !has_explicit_prefix && url.contains(\"vfox-\") {\n                    plugin_type = PluginType::Vfox;\n                }\n\n                let plugin = plugin\n                    .strip_prefix(\"vfox:\")\n                    .or_else(|| plugin.strip_prefix(\"vfox-backend:\"))\n                    .or_else(|| plugin.strip_prefix(\"asdf:\"))\n                    .unwrap_or(plugin);\n\n                install_state::add_plugin(plugin, plugin_type).await?;\n            }\n        });\n\n        measure!(\"config::load remove_aliased_tools\", {\n            for short in config\n                .all_aliases\n                .iter()\n                .filter(|(_, a)| a.backend.is_some())\n                .map(|(s, _)| s)\n                .chain(config.repo_urls.keys())\n            {\n                // we need to remove aliased tools so they get re-added with updated \"full\" values\n                backend::remove(short);\n            }\n        });\n\n        let config = Arc::new(config);\n        config.env_results().await?;\n        *_CONFIG.write().unwrap() = Some(config.clone());\n        Ok(config)\n    }\n    pub fn env_maybe(&self) -> Option<IndexMap<String, String>> {\n        self.env_with_sources.get().map(|env| {\n            env.iter()\n                .map(|(k, (v, _))| (k.clone(), v.clone()))\n                .collect()\n        })\n    }\n    pub async fn env(self: &Arc<Self>) -> eyre::Result<IndexMap<String, String>> {\n        Ok(self\n            .env_with_sources()\n            .await?\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect())\n    }\n    pub async fn env_with_sources(self: &Arc<Self>) -> eyre::Result<&EnvWithSources> {\n        self.env_with_sources\n            .get_or_try_init(async || {\n                let mut env = self.env_results().await?.env.clone();\n                for env_file in Settings::get().env_files() {\n                    match dotenvy::from_path_iter(&env_file) {\n                        Ok(iter) => {\n                            for item in iter {\n                                let (k, v) = item.unwrap_or_else(|err| {\n                                    warn!(\"env_file: {err}\");\n                                    Default::default()\n                                });\n                                env.insert(k, (v, env_file.clone()));\n                            }\n                        }\n                        Err(err) => trace!(\"env_file: {err}\"),\n                    }\n                }\n                Ok(env)\n            })\n            .await\n    }\n    pub async fn env_results(self: &Arc<Self>) -> Result<&EnvResults> {\n        self.env\n            .get_or_try_init(|| async { self.load_env().await })\n            .await\n    }\n\n    pub async fn vars_results(self: &Arc<Self>) -> Result<&EnvResults> {\n        if let Some(loader) = &self.vars_loader\n            && let Some(results) = loader.vars_results.get()\n        {\n            return Ok(results);\n        }\n        self.vars_results\n            .get_or_try_init(|| async move { load_vars(self).await })\n            .await\n    }\n\n    pub fn env_results_cached(&self) -> Option<&EnvResults> {\n        self.env.get()\n    }\n    pub fn vars_results_cached(&self) -> Option<&EnvResults> {\n        self.vars_results.get()\n    }\n    pub async fn path_dirs(self: &Arc<Self>) -> eyre::Result<&Vec<PathBuf>> {\n        Ok(&self.env_results().await?.env_paths)\n    }\n    pub async fn get_tool_request_set(self: &Arc<Self>) -> eyre::Result<&ToolRequestSet> {\n        self.tool_request_set\n            .get_or_try_init(async || ToolRequestSetBuilder::new().build(self).await)\n            .await\n    }\n\n    pub async fn get_toolset(self: &Arc<Self>) -> Result<&Toolset> {\n        self.toolset\n            .get_or_try_init(|| async {\n                let mut ts = Toolset::from(self.get_tool_request_set().await?.clone());\n                ts.resolve(self).await?;\n                Ok(ts)\n            })\n            .await\n    }\n\n    pub async fn get_tool_opts(\n        self: &Arc<Self>,\n        backend_arg: &Arc<BackendArg>,\n    ) -> Result<Option<ToolVersionOptions>> {\n        let trs = self.get_tool_request_set().await?;\n        // Try matching by resolved full name first for aliased tools.\n        // e.g., ba.short=\"treesize\" resolves to full=\"gitlab:FBibonne/treesize\"\n        // while the config entry has short=\"gitlab-f-bibonne-treesize\" with api_url set.\n        // We check the resolved name first because the direct short match might find\n        // a CLI-created tool request without options.\n        let full = backend_arg.full();\n        let resolved_ba = BackendArg::new(full, None);\n        let tool_request = trs\n            .iter()\n            .find(|tr| tr.0.short == resolved_ba.short)\n            .or_else(|| trs.iter().find(|tr| tr.0.short == backend_arg.short));\n        Ok(tool_request.and_then(|tr| tr.1.first().map(|req| req.options())))\n    }\n\n    pub fn get_repo_url(&self, plugin_name: &str) -> Option<String> {\n        let plugin_name = self\n            .all_aliases\n            .get(plugin_name)\n            .and_then(|a| a.backend.clone())\n            .or_else(|| self.repo_urls.get(plugin_name).cloned())\n            .unwrap_or(plugin_name.to_string());\n        let plugin_name = plugin_name.strip_prefix(\"asdf:\").unwrap_or(&plugin_name);\n        let plugin_name = plugin_name.strip_prefix(\"vfox:\").unwrap_or(plugin_name);\n\n        if let Some(url) = self\n            .repo_urls\n            .keys()\n            .find(|k| k.ends_with(&format!(\":{plugin_name}\")))\n            .and_then(|k| self.repo_urls.get(k))\n        {\n            return Some(url.clone());\n        }\n\n        self.shorthands\n            .get(plugin_name)\n            .map(|full| registry::full_to_url(&full[0]))\n            .or_else(|| {\n                if plugin_name.starts_with(\"https://\") || plugin_name.split('/').count() == 2 {\n                    Some(registry::full_to_url(plugin_name))\n                } else {\n                    None\n                }\n            })\n    }\n\n    pub fn is_monorepo(&self) -> bool {\n        find_monorepo_root(&self.config_files).is_some()\n    }\n\n    pub async fn tasks(&self) -> Result<Arc<BTreeMap<String, Task>>> {\n        self.tasks_with_context(None).await\n    }\n\n    pub async fn tasks_with_context(\n        &self,\n        ctx: Option<&crate::task::TaskLoadContext>,\n    ) -> Result<Arc<BTreeMap<String, Task>>> {\n        // Use the entire context as cache key\n        // Default context (None) becomes TaskLoadContext::default()\n        let cache_key = ctx.cloned().unwrap_or_default();\n\n        // Check if already cached\n        if let Some(cached) = self.tasks_cache.get(&cache_key) {\n            return Ok(cached.value().clone());\n        }\n\n        // Not cached, load tasks\n        let tasks = measure!(\"config::load_all_tasks_with_context\", {\n            self.load_all_tasks_with_context(ctx).await?\n        });\n        let tasks_arc = Arc::new(tasks);\n\n        // Insert into cache\n        self.tasks_cache.insert(cache_key, tasks_arc.clone());\n\n        Ok(tasks_arc)\n    }\n\n    pub async fn tasks_with_aliases(&self) -> Result<BTreeMap<String, Task>> {\n        let tasks = self.tasks().await?;\n        Ok(tasks\n            .iter()\n            .flat_map(|(_, t)| {\n                t.aliases\n                    .iter()\n                    .map(|a| (a.to_string(), t.clone()))\n                    .chain(once((t.name.clone(), t.clone())))\n                    .collect::<Vec<_>>()\n            })\n            .collect())\n    }\n\n    pub async fn resolve_alias(&self, backend: &ABackend, v: &str) -> Result<String> {\n        if let Some(plugin_aliases) = self.all_aliases.get(&backend.ba().short)\n            && let Some(alias) = plugin_aliases.versions.get(v)\n        {\n            return Ok(alias.clone());\n        }\n        if let Some(alias) = backend.get_aliases()?.get(v) {\n            return Ok(alias.clone());\n        }\n        Ok(v.to_string())\n    }\n\n    fn load_all_aliases(&self) -> AliasMap {\n        let mut aliases: AliasMap = self.aliases.clone();\n        let plugin_aliases: Vec<_> = backend::list()\n            .into_iter()\n            .map(|backend| {\n                let aliases = backend.get_aliases().unwrap_or_else(|err| {\n                    warn!(\"get_aliases: {err}\");\n                    BTreeMap::new()\n                });\n                (backend.ba().clone(), aliases)\n            })\n            .collect();\n        for (ba, plugin_aliases) in plugin_aliases {\n            for (from, to) in plugin_aliases {\n                aliases\n                    .entry(ba.short.to_string())\n                    .or_default()\n                    .versions\n                    .insert(from, to);\n            }\n        }\n\n        for (short, plugin_aliases) in &self.aliases {\n            let alias = aliases.entry(short.clone()).or_default();\n            if let Some(full) = &plugin_aliases.backend {\n                alias.backend = Some(full.clone());\n            }\n            for (from, to) in &plugin_aliases.versions {\n                alias.versions.insert(from.clone(), to.clone());\n            }\n        }\n\n        aliases\n    }\n\n    async fn load_all_tasks_with_context(\n        &self,\n        ctx: Option<&crate::task::TaskLoadContext>,\n    ) -> Result<BTreeMap<String, Task>> {\n        let config = Config::get().await?;\n        time!(\"load_all_tasks\");\n\n        // Collect all task templates from config hierarchy (experimental feature)\n        let templates = if Settings::get().experimental {\n            collect_task_templates(&config.config_files)\n        } else {\n            IndexMap::new()\n        };\n\n        let local_tasks = load_local_tasks_with_context(&config, ctx, &templates).await?;\n        let global_tasks = load_global_tasks(&config, &templates).await?;\n        let mut tasks: BTreeMap<String, Task> = local_tasks\n            .into_iter()\n            .chain(global_tasks)\n            .rev()\n            .inspect(|t| {\n                trace!(\n                    \"loaded task {} – {}\",\n                    &t.name,\n                    display_path(&t.config_source)\n                )\n            })\n            .map(|t| (t.name.clone(), t))\n            .collect();\n        let all_tasks = tasks.clone();\n        for task in tasks.values_mut() {\n            task.display_name = task.display_name(&all_tasks);\n        }\n        time!(\"load_all_tasks {count}\", count = tasks.len(),);\n        Ok(tasks)\n    }\n\n    pub async fn get_tracked_config_files(&self) -> Result<ConfigMap> {\n        let mut config_files: ConfigMap = ConfigMap::default();\n        for path in Tracker::list_all()?.into_iter() {\n            // Pre-check trust to avoid interactive prompts when loading\n            // tracked configs (e.g., during `mise upgrade`). Only MiseToml files\n            // call trust_check during parsing, but we can't cheaply distinguish\n            // file types here, so we check trust for all files and fall through\n            // to parse for trusted files. Untrusted non-MiseToml files (like\n            // .tool-versions) don't need trust and will parse fine regardless.\n            let trust_root = config_file::config_trust_root(&path);\n            if !config_file::is_trusted(&trust_root) && !config_file::is_trusted(&path) {\n                debug!(\"skipping untrusted tracked config: {}\", display_path(&path));\n                continue;\n            }\n            match config_file::parse(&path).await {\n                Ok(cf) => {\n                    config_files.insert(path, cf);\n                }\n                Err(err) => {\n                    warn!(\n                        \"error loading tracked config file {}: {err:#}\",\n                        display_path(&path)\n                    );\n                }\n            }\n        }\n        Ok(config_files)\n    }\n\n    pub fn global_config(&self) -> Result<MiseToml> {\n        let settings_path = global_config_path();\n        match settings_path.exists() {\n            false => {\n                trace!(\"settings does not exist {:?}\", settings_path);\n                Ok(MiseToml::init(&settings_path))\n            }\n            true => MiseToml::from_file(&settings_path)\n                .wrap_err_with(|| eyre!(\"Error parsing {}\", display_path(&settings_path))),\n        }\n    }\n\n    fn validate(&self) -> eyre::Result<()> {\n        self.validate_versions()?;\n        Ok(())\n    }\n\n    fn validate_versions(&self) -> eyre::Result<()> {\n        for cf in self.config_files.values() {\n            if let Some(spec) = cf.min_version() {\n                Self::enforce_min_version_spec(spec)?;\n            }\n        }\n        Ok(())\n    }\n\n    pub fn enforce_min_version_spec(spec: &MinVersionSpec) -> eyre::Result<()> {\n        let cur = &*version::V;\n        if let Some(required) = spec.hard_violation(cur) {\n            let min = style::eyellow(required);\n            let cur = style::eyellow(cur);\n            let msg = format!(\"mise version {min} is required, but you are using {cur}\");\n            bail!(crate::cli::self_update::append_self_update_instructions(\n                msg\n            ));\n        } else if let Some(recommended) = spec.soft_violation(cur) {\n            let min = style::eyellow(recommended);\n            let cur = style::eyellow(cur);\n            let msg = format!(\"mise version {min} is recommended, but you are using {cur}\");\n            warn!(\n                \"{}\",\n                crate::cli::self_update::append_self_update_instructions(msg)\n            );\n        }\n        Ok(())\n    }\n\n    async fn load_env(self: &Arc<Self>) -> Result<EnvResults> {\n        if Settings::no_env() || Settings::get().no_env.unwrap_or(false) {\n            return Ok(EnvResults::default());\n        }\n        time!(\"load_env start\");\n        let cache_enabled = CachedNonToolEnv::is_enabled();\n        let cache_key = if cache_enabled {\n            let config_files: Vec<(PathBuf, u64)> = self\n                .config_files\n                .keys()\n                .map(|p| (p.clone(), get_file_mtime(p).unwrap_or(0)))\n                .collect();\n            let settings_hash = compute_settings_hash();\n            let base_path = join_paths(env::PATH.iter())\n                .map(|p| p.to_string_lossy().to_string())\n                .unwrap_or_default();\n            Some(CachedNonToolEnv::compute_cache_key(\n                &config_files,\n                &settings_hash,\n                &base_path,\n            ))\n        } else {\n            None\n        };\n        if let Some(cache_key) = cache_key.as_ref()\n            && let Some(cached) = CachedNonToolEnv::load(cache_key)?\n        {\n            let env_results = EnvResults {\n                env: cached.env.clone(),\n                vars: Default::default(),\n                env_remove: cached.env_remove.clone(),\n                env_files: cached.env_files.clone(),\n                env_paths: cached.env_paths.clone(),\n                env_scripts: cached.env_scripts.clone(),\n                redactions: cached.redactions.clone(),\n                tool_add_paths: Vec::new(),\n                watch_files: cached.watch_files.clone(),\n                has_uncacheable: false,\n            };\n            let redact_keys = self\n                .redaction_keys()\n                .into_iter()\n                .chain(env_results.redactions.clone())\n                .collect_vec();\n            self.add_redactions(\n                redact_keys,\n                &env_results\n                    .env\n                    .iter()\n                    .map(|(k, v)| (k.clone(), v.0.clone()))\n                    .collect(),\n            );\n            if log::log_enabled!(log::Level::Trace) {\n                trace!(\"{env_results:#?}\");\n            } else if !env_results.is_empty() {\n                debug!(\"{env_results:?}\");\n            }\n            trace!(\"env_cache: using cached non-tool env results\");\n            return Ok(env_results);\n        }\n        let entries = self\n            .config_files\n            .iter()\n            .rev()\n            .map(|(source, cf)| {\n                cf.env_entries()\n                    .map(|ee| ee.into_iter().map(|e| (e, source.clone())))\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .flatten()\n            .collect();\n        // trace!(\"load_env: entries: {:#?}\", entries);\n        let env_results = EnvResults::resolve(\n            self,\n            self.tera_ctx.clone(),\n            &env::PRISTINE_ENV,\n            entries,\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::NonToolsOnly,\n                warn_on_missing_required: *env::WARN_ON_MISSING_REQUIRED_ENV,\n            },\n        )\n        .await?;\n        let redact_keys = self\n            .redaction_keys()\n            .into_iter()\n            .chain(env_results.redactions.clone())\n            .collect_vec();\n        self.add_redactions(\n            redact_keys,\n            &env_results\n                .env\n                .iter()\n                .map(|(k, v)| (k.clone(), v.0.clone()))\n                .collect(),\n        );\n        if cache_enabled\n            && !env_results.has_uncacheable\n            && let Some(cache_key) = cache_key\n        {\n            let mut watch_files = env_results.watch_files.clone();\n            watch_files.extend(env_results.env_files.clone());\n            watch_files.extend(env_results.env_scripts.clone());\n            let watch_file_mtimes: Vec<u64> = watch_files\n                .iter()\n                .map(|p| get_file_mtime(p).unwrap_or(0))\n                .collect();\n            let now = SystemTime::now()\n                .duration_since(SystemTime::UNIX_EPOCH)\n                .unwrap_or_default()\n                .as_secs();\n            let cached = CachedNonToolEnv {\n                env: env_results.env.clone(),\n                env_remove: env_results.env_remove.clone(),\n                env_files: env_results.env_files.clone(),\n                env_paths: env_results.env_paths.clone(),\n                env_scripts: env_results.env_scripts.clone(),\n                redactions: env_results.redactions.clone(),\n                watch_files,\n                watch_file_mtimes,\n                created_at: now,\n                mise_version: env!(\"CARGO_PKG_VERSION\").to_string(),\n                cache_key_debug: cache_key.clone(),\n            };\n            if let Err(e) = cached.save(&cache_key) {\n                debug!(\"env_cache: failed to save non-tool env cache: {}\", e);\n            }\n        }\n        if log::log_enabled!(log::Level::Trace) {\n            trace!(\"{env_results:#?}\");\n        } else if !env_results.is_empty() {\n            debug!(\"{env_results:?}\");\n        }\n        Ok(env_results)\n    }\n\n    pub async fn hooks(&self) -> Result<&Vec<(PathBuf, Hook)>> {\n        self.hooks\n            .get_or_try_init(|| async {\n                self.config_files\n                    .values()\n                    .map(|cf| {\n                        let is_global = cf.project_root().is_none();\n                        let root = cf.project_root().unwrap_or_else(|| cf.config_root());\n                        let mut hooks = cf.hooks()?;\n                        if is_global {\n                            for h in &mut hooks {\n                                h.global = true;\n                            }\n                        }\n                        Ok((root, hooks))\n                    })\n                    .map_ok(|(root, hooks)| {\n                        hooks\n                            .into_iter()\n                            .map(|h| (root.clone(), h))\n                            .collect::<Vec<_>>()\n                    })\n                    .flatten_ok()\n                    .collect()\n            })\n            .await\n    }\n\n    pub fn watch_file_hooks(&self) -> Result<IndexSet<(PathBuf, WatchFile)>> {\n        Ok(self\n            .config_files\n            .values()\n            .map(|cf| Ok((cf.project_root(), cf.watch_files()?)))\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .filter_map(|(root, watch_files)| root.map(|r| (r.to_path_buf(), watch_files)))\n            .flat_map(|(root, watch_files)| {\n                watch_files\n                    .iter()\n                    .map(|wf| (root.clone(), wf.clone()))\n                    .collect::<Vec<_>>()\n            })\n            .collect())\n    }\n\n    pub async fn watch_files(self: &Arc<Self>) -> Result<BTreeSet<WatchFilePattern>> {\n        let env_results = self.env_results().await?;\n        Ok(self\n            .config_files\n            .iter()\n            .map(|(p, cf)| {\n                let mut watch_files: Vec<WatchFilePattern> = vec![p.as_path().into()];\n                if let Some(parent) = p.parent() {\n                    watch_files.push(parent.join(\"mise.lock\").into());\n                }\n                watch_files.extend(cf.watch_files()?.iter().map(|wf| WatchFilePattern {\n                    root: cf.project_root().map(|pr| pr.to_path_buf()),\n                    patterns: wf.patterns.clone(),\n                }));\n                Ok(watch_files)\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .flatten()\n            .chain(env_results.env_files.iter().map(|p| p.as_path().into()))\n            .chain(env_results.env_scripts.iter().map(|p| p.as_path().into()))\n            .chain(\n                Settings::get()\n                    .env_files()\n                    .iter()\n                    .map(|p| p.as_path().into()),\n            )\n            .chain(self.tera_files.iter().map(|p| p.as_path().into()))\n            .collect())\n    }\n\n    pub fn redaction_keys(&self) -> Vec<String> {\n        self.config_files\n            .values()\n            .flat_map(|cf| cf.redactions().0.iter())\n            .cloned()\n            .collect()\n    }\n    pub fn add_redactions(&self, redactions: impl IntoIterator<Item = String>, env: &EnvMap) {\n        let mut r = _REDACTOR.lock().unwrap();\n        let new_redactions = redactions.into_iter().flat_map(|pattern| {\n            let matcher = Wildcard::new(vec![pattern]);\n            env.iter()\n                .filter(|(k, _)| matcher.match_any(k))\n                .map(|(_, v)| v.clone())\n                .collect::<Vec<_>>()\n        });\n        *r = r.with_additional(new_redactions);\n    }\n\n    /// Get the current redaction patterns.\n    pub fn redactions(&self) -> Arc<IndexSet<String>> {\n        _REDACTOR.lock().unwrap().patterns_arc()\n    }\n\n    /// Redact sensitive values from a string using Aho-Corasick for efficiency.\n    pub fn redact(&self, input: &str) -> String {\n        _REDACTOR.lock().unwrap().redact(input)\n    }\n}\n\nfn configs_at_root<'a>(dir: &Path, config_files: &'a ConfigMap) -> Vec<&'a Arc<dyn ConfigFile>> {\n    let mut configs: Vec<&'a Arc<dyn ConfigFile>> = DEFAULT_CONFIG_FILENAMES\n        .iter()\n        .rev()\n        .flat_map(|f| {\n            if f.contains('*') {\n                // Handle glob patterns by matching against actual config file paths\n                glob(dir, f)\n                    .unwrap_or_default()\n                    .into_iter()\n                    .filter_map(|path| config_files.get(&path))\n                    .collect::<Vec<_>>()\n            } else {\n                // Handle regular filenames\n                config_files\n                    .get(&dir.join(f))\n                    .into_iter()\n                    .collect::<Vec<_>>()\n            }\n        })\n        .collect();\n    // Remove duplicates while preserving order\n    let mut seen = std::collections::HashSet::new();\n    configs.retain(|cf| seen.insert(cf.get_path().to_path_buf()));\n    configs\n}\n\nfn get_project_root(config_files: &ConfigMap) -> Option<PathBuf> {\n    let project_root = config_files\n        .values()\n        .find_map(|cf| cf.project_root())\n        .map(|pr| pr.to_path_buf());\n    trace!(\"project_root: {project_root:?}\");\n    project_root\n}\n\nfn find_monorepo_root(config_files: &ConfigMap) -> Option<PathBuf> {\n    find_monorepo_config(config_files).and_then(|cf| cf.project_root().map(|p| p.to_path_buf()))\n}\n\n/// Find the config file that has experimental_monorepo_root = true\nfn find_monorepo_config(config_files: &ConfigMap) -> Option<&Arc<dyn ConfigFile>> {\n    // This feature requires experimental mode\n    if !Settings::get().experimental {\n        return None;\n    }\n    config_files\n        .values()\n        .find(|cf| cf.experimental_monorepo_root() == Some(true))\n}\n\nasync fn load_idiomatic_filenames() -> BTreeMap<String, Vec<String>> {\n    let enable_tools = Settings::get().idiomatic_version_file_enable_tools.clone();\n    if enable_tools.is_empty() {\n        return BTreeMap::new();\n    }\n    if !Settings::get()\n        .idiomatic_version_file_disable_tools\n        .is_empty()\n    {\n        deprecated!(\n            \"idiomatic_version_file_disable_tools\",\n            \"is deprecated, use idiomatic_version_file_enable_tools instead\"\n        );\n    }\n    let mut jset = JoinSet::new();\n    for tool in backend::list() {\n        let enable_tools = enable_tools.clone();\n        jset.spawn(async move {\n            if !enable_tools.contains(tool.id()) {\n                return vec![];\n            }\n            match tool.idiomatic_filenames().await {\n                Ok(filenames) => filenames\n                    .iter()\n                    .map(|f| (f.to_string(), tool.id().to_string()))\n                    .collect::<Vec<_>>(),\n                Err(err) => {\n                    eprintln!(\"Error: {err}\");\n                    vec![]\n                }\n            }\n        });\n    }\n    let idiomatic = jset\n        .join_all()\n        .await\n        .into_iter()\n        .flatten()\n        .collect::<Vec<_>>();\n\n    let mut idiomatic_filenames = BTreeMap::new();\n    for (filename, plugin) in idiomatic {\n        idiomatic_filenames\n            .entry(filename)\n            .or_insert_with(Vec::new)\n            .push(plugin);\n    }\n    idiomatic_filenames\n}\n\nstatic LOCAL_CONFIG_FILENAMES: Lazy<IndexSet<&'static str>> = Lazy::new(|| {\n    let mut paths: IndexSet<&'static str> = IndexSet::new();\n    if let Some(o) = &*env::MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES {\n        paths.extend(o.iter().map(|s| s.as_str()));\n    } else {\n        paths.extend([\n            \".tool-versions\",\n            &*env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME, // .tool-versions\n        ]);\n    }\n    if !env::MISE_OVERRIDE_CONFIG_FILENAMES.is_empty() {\n        paths.extend(\n            env::MISE_OVERRIDE_CONFIG_FILENAMES\n                .iter()\n                .map(|s| s.as_str()),\n        )\n    } else {\n        paths.extend([\n            \".config/mise/conf.d/*.toml\",\n            \".config/mise/config.toml\",\n            \".config/mise/mise.toml\",\n            \".config/mise.toml\",\n            \".mise/config.toml\",\n            \"mise/config.toml\",\n            \".rtx.toml\",\n            \"mise.toml\",\n            &*env::MISE_DEFAULT_CONFIG_FILENAME, // mise.toml\n            \".mise.toml\",\n            \".config/mise/config.local.toml\",\n            \".config/mise/mise.local.toml\",\n            \".config/mise.local.toml\",\n            \".mise/config.local.toml\",\n            \"mise/config.local.toml\",\n            \".rtx.local.toml\",\n            \"mise.local.toml\",\n            \".mise.local.toml\",\n        ]);\n    }\n\n    paths\n});\npub static DEFAULT_CONFIG_FILENAMES: Lazy<Vec<String>> = Lazy::new(|| {\n    let mut filenames = LOCAL_CONFIG_FILENAMES\n        .iter()\n        .map(|f| f.to_string())\n        .collect_vec();\n    for env in &*env::MISE_ENV {\n        filenames.push(format!(\".config/mise/config.{env}.toml\"));\n        filenames.push(format!(\".config/mise.{env}.toml\"));\n        filenames.push(format!(\"mise/config.{env}.toml\"));\n        filenames.push(format!(\"mise.{env}.toml\"));\n        filenames.push(format!(\".mise/config.{env}.toml\"));\n        filenames.push(format!(\".mise.{env}.toml\"));\n        filenames.push(format!(\".config/mise/config.{env}.local.toml\"));\n        filenames.push(format!(\".config/mise.{env}.local.toml\"));\n        filenames.push(format!(\"mise/config.{env}.local.toml\"));\n        filenames.push(format!(\"mise.{env}.local.toml\"));\n        filenames.push(format!(\".mise/config.{env}.local.toml\"));\n        filenames.push(format!(\".mise.{env}.local.toml\"));\n    }\n    filenames\n});\nstatic TOML_CONFIG_FILENAMES: Lazy<Vec<String>> = Lazy::new(|| {\n    DEFAULT_CONFIG_FILENAMES\n        .iter()\n        .filter(|s| s.ends_with(\".toml\"))\n        .map(|s| s.to_string())\n        .collect()\n});\npub static ALL_CONFIG_FILES: Lazy<IndexSet<PathBuf>> = Lazy::new(|| {\n    load_config_paths(&DEFAULT_CONFIG_FILENAMES, false)\n        .into_iter()\n        .collect()\n});\npub static IGNORED_CONFIG_FILES: Lazy<IndexSet<PathBuf>> = Lazy::new(|| {\n    load_config_paths(&DEFAULT_CONFIG_FILENAMES, true)\n        .into_iter()\n        .filter(|p| config_file::is_ignored(&config_trust_root(p)) || config_file::is_ignored(p))\n        .collect()\n});\n// pub static LOCAL_CONFIG_FILES: Lazy<Vec<PathBuf>> = Lazy::new(|| {\n//     ALL_CONFIG_FILES\n//         .iter()\n//         .filter(|cf| !is_global_config(cf))\n//         .cloned()\n//         .collect()\n// });\n\ntype GlobResults = HashMap<(PathBuf, String), Vec<PathBuf>>;\nstatic GLOB_RESULTS: Lazy<Mutex<GlobResults>> = Lazy::new(Default::default);\n\npub fn glob(dir: &Path, pattern: &str) -> Result<Vec<PathBuf>> {\n    let mut results = GLOB_RESULTS.lock().unwrap();\n    let key = (dir.to_path_buf(), pattern.to_string());\n    if let Some(glob) = results.get(&key) {\n        return Ok(glob.clone());\n    }\n    let paths = glob::glob(dir.join(pattern).to_string_lossy().as_ref())?\n        .filter_map(|p| p.ok())\n        .collect_vec();\n    results.insert(key, paths.clone());\n    Ok(paths)\n}\n\npub fn config_files_in_dir(dir: &Path) -> IndexSet<PathBuf> {\n    DEFAULT_CONFIG_FILENAMES\n        .iter()\n        .flat_map(|f| glob(dir, f).unwrap_or_default())\n        .collect()\n}\n\nfn all_dirs() -> Result<Vec<PathBuf>> {\n    file::all_dirs(env::current_dir()?, &env::MISE_CEILING_PATHS)\n}\n\n/// Get all directories in the hierarchy from a starting directory up to ceiling paths\nfn all_dirs_from(start_dir: &Path) -> Result<Vec<PathBuf>> {\n    file::all_dirs(start_dir, &env::MISE_CEILING_PATHS)\n}\n\n/// Returns true if a path is a .tool-versions file (lower priority for writes)\nfn is_tool_versions_file(p: &Path) -> bool {\n    p.file_name()\n        .is_some_and(|f| f.to_string_lossy().ends_with(\".tool-versions\"))\n}\n\n/// Get the first (lowest precedence) config file, but skip .tool-versions unless\n/// it's the only option. This ensures commands like `mise use` write to mise.toml\n/// instead of mise.local.toml or .tool-versions when multiple configs exist.\n/// See: https://github.com/jdx/mise/discussions/6475\nfn first_config_file(files: &IndexSet<PathBuf>) -> Option<&PathBuf> {\n    files\n        .iter()\n        .find(|p| !is_tool_versions_file(p) && !is_conf_d_file(p))\n        .or_else(|| files.first())\n}\n\nfn is_conf_d_file(p: &Path) -> bool {\n    p.parent()\n        .is_some_and(|d| d.file_name().is_some_and(|n| n == \"conf.d\"))\n}\n\npub fn config_file_from_dir(p: &Path) -> PathBuf {\n    if !p.is_dir() {\n        return p.to_path_buf();\n    }\n    for dir in all_dirs().unwrap_or_default() {\n        let files = self::config_files_in_dir(&dir);\n        if let Some(cf) = first_config_file(&files)\n            && !is_global_config(cf)\n        {\n            return cf.clone();\n        }\n    }\n    match Settings::get().asdf_compat {\n        true => p.join(&*MISE_DEFAULT_TOOL_VERSIONS_FILENAME),\n        false => p.join(&*MISE_DEFAULT_CONFIG_FILENAME),\n    }\n}\n\npub fn load_config_paths(config_filenames: &[String], include_ignored: bool) -> Vec<PathBuf> {\n    if Settings::no_config() {\n        return vec![];\n    }\n    let dirs = all_dirs().unwrap_or_default();\n\n    let mut config_files = dirs\n        .iter()\n        .flat_map(|dir| {\n            if !include_ignored\n                && env::MISE_IGNORED_CONFIG_PATHS\n                    .iter()\n                    .any(|p| dir.starts_with(p))\n            {\n                vec![]\n            } else {\n                config_filenames\n                    .iter()\n                    .rev()\n                    .flat_map(|f| glob(dir, f).unwrap_or_default().into_iter().rev())\n                    .collect()\n            }\n        })\n        .collect::<Vec<_>>();\n\n    config_files.extend(global_config_files());\n    config_files.extend(system_config_files());\n\n    config_files\n        .into_iter()\n        .unique_by(|p| file::desymlink_path(p))\n        .filter(|p| {\n            if is_default_config_dir_override_filtered(p) {\n                return false;\n            }\n            include_ignored\n                || !(config_file::is_ignored(&config_trust_root(p)) || config_file::is_ignored(p))\n        })\n        .collect()\n}\n\n/// Load config hierarchy from a specific directory (for monorepo tasks)\n/// This loads all config files from start_dir up through parent directories,\n/// including MISE_ENV-specific configs\npub fn load_config_hierarchy_from_dir(start_dir: &Path) -> Result<Vec<PathBuf>> {\n    if Settings::no_config() {\n        return Ok(vec![]);\n    }\n\n    let config_filenames = DEFAULT_CONFIG_FILENAMES.iter().cloned().collect_vec();\n\n    // Get all directories from start_dir up to root/ceiling\n    let dirs = all_dirs_from(start_dir)?;\n\n    let mut config_files = dirs\n        .iter()\n        .flat_map(|dir| {\n            if env::MISE_IGNORED_CONFIG_PATHS\n                .iter()\n                .any(|p| dir.starts_with(p))\n            {\n                vec![]\n            } else {\n                config_filenames\n                    .iter()\n                    .rev()\n                    .flat_map(|f| glob(dir, f).unwrap_or_default().into_iter().rev())\n                    .collect()\n            }\n        })\n        .collect::<Vec<_>>();\n\n    // Add global and system configs\n    config_files.extend(global_config_files());\n    config_files.extend(system_config_files());\n\n    let paths = config_files\n        .into_iter()\n        .unique_by(|p| file::desymlink_path(p))\n        .filter(|p| {\n            if is_default_config_dir_override_filtered(p) {\n                return false;\n            }\n            !(config_file::is_ignored(&config_trust_root(p)) || config_file::is_ignored(p))\n        })\n        .collect();\n\n    Ok(paths)\n}\n\npub fn is_global_config(path: &Path) -> bool {\n    global_config_files().contains(path) || system_config_files().contains(path)\n}\n\n/// Returns true if the path should be filtered out due to MISE_CONFIG_DIR override.\n/// When MISE_CONFIG_DIR is set to a non-default location, this filters out configs\n/// found under the default location (~/.config/mise) during traversal.\n/// See: https://github.com/jdx/mise/discussions/7015\nfn is_default_config_dir_override_filtered(path: &Path) -> bool {\n    *env::MISE_CONFIG_DIR_OVERRIDDEN\n        && !global_config_files().contains(path)\n        && path.starts_with(&*env::MISE_DEFAULT_CONFIG_DIR)\n}\n\nstatic GLOBAL_CONFIG_FILES: Lazy<Mutex<Option<IndexSet<PathBuf>>>> = Lazy::new(Default::default);\nstatic SYSTEM_CONFIG_FILES: Lazy<Mutex<Option<IndexSet<PathBuf>>>> = Lazy::new(Default::default);\n\npub fn global_config_files() -> IndexSet<PathBuf> {\n    let mut g = GLOBAL_CONFIG_FILES.lock().unwrap();\n    if let Some(g) = &*g {\n        return g.clone();\n    }\n    if let Some(global_config_file) = &*env::MISE_GLOBAL_CONFIG_FILE {\n        return vec![global_config_file.clone()].into_iter().collect();\n    }\n    let mut config_files = IndexSet::new();\n    if !*env::MISE_USE_TOML {\n        // only add ~/.tool-versions if MISE_CONFIG_FILE is not set\n        // because that's how the user overrides the default\n        config_files.insert(dirs::HOME.join(env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME.as_str()));\n    };\n    config_files.extend(config_files_from_dir(&dirs::CONFIG));\n    *g = Some(config_files.clone());\n    config_files\n}\n\npub fn system_config_files() -> IndexSet<PathBuf> {\n    let mut s = SYSTEM_CONFIG_FILES.lock().unwrap();\n    if let Some(s) = &*s {\n        return s.clone();\n    }\n    if let Some(p) = &*env::MISE_SYSTEM_CONFIG_FILE {\n        return vec![p.clone()].into_iter().collect();\n    }\n    let config_files = config_files_from_dir(&dirs::SYSTEM_CONFIG);\n    *s = Some(config_files.clone());\n    config_files\n}\n\nstatic CONFIG_FILENAMES: Lazy<Vec<String>> = Lazy::new(|| {\n    let mut filenames = vec![\"config.toml\".to_string(), \"mise.toml\".to_string()];\n    for env in &*env::MISE_ENV {\n        filenames.push(format!(\"config.{env}.toml\"));\n        filenames.push(format!(\"mise.{env}.toml\"));\n    }\n    filenames.push(\"config.local.toml\".to_string());\n    filenames.push(\"mise.local.toml\".to_string());\n    for env in &*env::MISE_ENV {\n        filenames.push(format!(\"config.{env}.local.toml\"));\n        filenames.push(format!(\"mise.{env}.local.toml\"));\n    }\n    filenames\n});\n\nfn config_files_from_dir(dir: &Path) -> IndexSet<PathBuf> {\n    let mut files = IndexSet::new();\n    for p in file::ls(&dir.join(\"conf.d\")).unwrap_or_default() {\n        if let Some(file_name) = p.file_name().map(|f| f.to_string_lossy().to_string())\n            && !file_name.starts_with(\".\")\n            && file_name.ends_with(\".toml\")\n        {\n            files.insert(p);\n        }\n    }\n    files.extend(CONFIG_FILENAMES.iter().map(|f| dir.join(f)));\n    files.into_iter().filter(|p| p.is_file()).collect()\n}\n\n/// the preferred global config file to write to, or the path where it should be created.\n/// Uses first_config_file() to pick the lowest-precedence non-local TOML (i.e., config.toml\n/// rather than config.local.toml) so that `mise use -g` writes to config.toml.\n/// See: https://github.com/jdx/mise/discussions/8236\npub fn global_config_path() -> PathBuf {\n    let files = global_config_files();\n    first_config_file(&files)\n        .cloned()\n        .or_else(|| env::MISE_GLOBAL_CONFIG_FILE.clone())\n        .unwrap_or_else(|| dirs::CONFIG.join(\"config.toml\"))\n}\n\n/// the top-most mise.toml (local or global)\npub fn top_toml_config() -> Option<PathBuf> {\n    load_config_paths(&TOML_CONFIG_FILENAMES, false)\n        .iter()\n        .find(|p| p.to_string_lossy().ends_with(\".toml\"))\n        .map(|p| p.to_path_buf())\n}\n\npub static ALL_TOML_CONFIG_FILES: Lazy<IndexSet<PathBuf>> = Lazy::new(|| {\n    load_config_paths(&TOML_CONFIG_FILENAMES, false)\n        .into_iter()\n        .collect()\n});\n\n/// list of all non-global mise.tomls\npub fn local_toml_config_paths() -> Vec<&'static PathBuf> {\n    ALL_TOML_CONFIG_FILES\n        .iter()\n        .filter(|p| !is_global_config(p))\n        .collect()\n}\n\n/// The last (lowest precedence) local mise.toml or the path to where it should be written to.\n/// This ensures commands write to mise.toml instead of mise.local.toml when both exist.\n/// Note: local_toml_config_paths() returns files in highest-to-lowest precedence order,\n/// so we use .last() to get the lowest precedence file.\npub fn local_toml_config_path() -> PathBuf {\n    static CWD: Lazy<PathBuf> = Lazy::new(|| PathBuf::from(\".\"));\n    local_toml_config_paths()\n        .into_iter()\n        .last()\n        .cloned()\n        .unwrap_or_else(|| {\n            dirs::CWD\n                .as_ref()\n                .unwrap_or(&CWD)\n                .join(&*env::MISE_DEFAULT_CONFIG_FILENAME)\n        })\n}\n\n/// Options for resolving target config file path\n#[derive(Debug, Default)]\npub struct ConfigPathOptions {\n    pub global: bool,\n    pub path: Option<PathBuf>,\n    pub env: Option<String>,\n    pub cwd: Option<PathBuf>,\n    pub prefer_toml: bool,\n    pub prevent_home_local: bool,\n}\n\n/// Unified config file path resolution for both `mise use` and `mise set`\n///\n/// This function centralizes the logic for determining which config file to target\n/// based on various options, ensuring consistent behavior between commands.\npub fn resolve_target_config_path(opts: ConfigPathOptions) -> Result<PathBuf> {\n    let cwd = match opts.cwd {\n        Some(ref path) => path.clone(),\n        None => env::current_dir()?,\n    };\n\n    // If path is provided, handle it (file or directory) - explicit paths take precedence\n    if let Some(ref path) = opts.path {\n        if path.is_file() {\n            return Ok(path.clone());\n        } else if path.is_dir() {\n            let resolved = config_file_from_dir(path);\n            if opts.prefer_toml && !resolved.to_string_lossy().ends_with(\".toml\") {\n                // For TOML-only commands, ensure we get a TOML file in the specified directory\n                return Ok(path.join(&*env::MISE_DEFAULT_CONFIG_FILENAME));\n            }\n            return Ok(resolved);\n        } else {\n            // Path doesn't exist yet, return it as-is\n            return Ok(path.clone());\n        }\n    }\n\n    // If global flag is set and no explicit path provided, use global config\n    if opts.global {\n        return Ok(global_config_path());\n    }\n\n    // If env-specific config is requested\n    if let Some(ref env_name) = opts.env {\n        let dotfile_path = cwd.join(format!(\".mise.{}.toml\", env_name));\n        if dotfile_path.exists() {\n            return Ok(dotfile_path);\n        } else {\n            return Ok(cwd.join(format!(\"mise.{}.toml\", env_name)));\n        }\n    }\n\n    // If we're in HOME directory and prevent_home_local is true, use global config\n    if opts.prevent_home_local && env::in_home_dir() {\n        return Ok(global_config_path());\n    }\n\n    // Default: determine based on current directory\n    if opts.prefer_toml {\n        // For mise set, prefer TOML and use local_toml_config_path logic\n        Ok(local_toml_config_path())\n    } else {\n        // For mise use, use existing config_file_from_dir logic which respects ASDF compat\n        Ok(config_file_from_dir(&cwd))\n    }\n}\n\nasync fn load_all_config_files(\n    config_filenames: &[PathBuf],\n    idiomatic_filenames: &BTreeMap<String, Vec<String>>,\n) -> Result<ConfigMap> {\n    backend::load_tools().await?;\n    let mut config_map = ConfigMap::default();\n    for f in config_filenames.iter().unique() {\n        if f.is_dir() {\n            continue;\n        }\n        let cf = match parse_config_file(f, idiomatic_filenames).await {\n            Ok(cfg) => cfg,\n            Err(err) => {\n                return Err(err.wrap_err(format!(\n                    \"error parsing config file: {}\",\n                    style::ebold(display_path(f))\n                )));\n            }\n        };\n        if let Err(err) = Tracker::track(f) {\n            warn!(\"tracking config: {err:#}\");\n        }\n\n        // Mark monorepo roots so descendant configs are implicitly trusted\n        if cf.experimental_monorepo_root() == Some(true)\n            && let Err(err) = config_file::mark_as_monorepo_root(f)\n        {\n            warn!(\"failed to mark monorepo root: {err:#}\");\n        }\n\n        config_map.insert(f.clone(), cf);\n    }\n    Ok(config_map)\n}\n\n/// Load config files from a list of paths (for monorepo task config contexts)\npub async fn load_config_files_from_paths(config_paths: &[PathBuf]) -> Result<ConfigMap> {\n    backend::load_tools().await?;\n    let idiomatic_filenames = load_idiomatic_filenames().await;\n    let mut config_map = ConfigMap::default();\n\n    for f in config_paths.iter().unique() {\n        if f.is_dir() {\n            continue;\n        }\n        let cf = match parse_config_file(f, &idiomatic_filenames).await {\n            Ok(cfg) => cfg,\n            Err(err) => {\n                return Err(err.wrap_err(format!(\n                    \"error parsing config file: {}\",\n                    style::ebold(display_path(f))\n                )));\n            }\n        };\n\n        config_map.insert(f.clone(), cf);\n    }\n    Ok(config_map)\n}\n\nasync fn parse_config_file(\n    f: &PathBuf,\n    idiomatic_filenames: &BTreeMap<String, Vec<String>>,\n) -> Result<Arc<dyn ConfigFile>> {\n    match idiomatic_filenames.get(&f.file_name().unwrap().to_string_lossy().to_string()) {\n        Some(plugin) => {\n            trace!(\"idiomatic version file: {}\", display_path(f));\n            let tools = backend::list()\n                .into_iter()\n                .filter(|f| plugin.contains(&f.to_string()))\n                .collect::<Vec<_>>();\n            IdiomaticVersionFile::parse(f.into(), tools)\n                .await\n                .map(|f| Arc::new(f) as Arc<dyn ConfigFile>)\n        }\n        None => config_file::parse(f).await,\n    }\n}\n\nfn load_aliases(config_files: &ConfigMap) -> Result<AliasMap> {\n    let mut aliases: AliasMap = AliasMap::new();\n\n    for config_file in config_files.values() {\n        for (plugin, plugin_aliases) in config_file.aliases()? {\n            let alias = aliases.entry(plugin.clone()).or_default();\n            if let Some(full) = plugin_aliases.backend {\n                alias.backend = Some(full);\n            }\n            for (from, to) in plugin_aliases.versions {\n                alias.versions.insert(from, to);\n            }\n        }\n    }\n    trace!(\"load_aliases: {}\", aliases.len());\n\n    Ok(aliases)\n}\n\nfn load_shell_aliases(config_files: &ConfigMap) -> Result<EnvWithSources> {\n    let mut shell_aliases: EnvWithSources = EnvWithSources::new();\n\n    // Iterate in reverse order (global -> local) so child directories override parent configs\n    for config_file in config_files.values().rev() {\n        let path = config_file.get_path().to_path_buf();\n        for (name, cmd) in config_file.shell_aliases()? {\n            shell_aliases.insert(name, (cmd, path.clone()));\n        }\n    }\n    trace!(\"load_shell_aliases: {}\", shell_aliases.len());\n\n    Ok(shell_aliases)\n}\n\nfn load_plugins(config_files: &ConfigMap) -> Result<HashMap<String, String>> {\n    let mut plugins = HashMap::new();\n    for config_file in config_files.values() {\n        for (plugin, url) in config_file.plugins()? {\n            plugins.insert(plugin.clone(), url.clone());\n        }\n    }\n    trace!(\"load_plugins: {}\", plugins.len());\n    Ok(plugins)\n}\n\npub(crate) async fn resolve_vars_from_config_files(\n    config: &Arc<Config>,\n    config_files: &ConfigMap,\n) -> Result<EnvResults> {\n    let entries = config_files\n        .iter()\n        .rev()\n        .map(|(source, cf)| {\n            cf.vars_entries()\n                .map(|ee| ee.into_iter().map(|e| (e, source.clone())))\n        })\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .flatten()\n        .collect();\n\n    EnvResults::resolve(\n        config,\n        config.tera_ctx.clone(),\n        &env::PRISTINE_ENV,\n        entries,\n        EnvResolveOptions {\n            vars: true,\n            tools: ToolsFilter::NonToolsOnly,\n            warn_on_missing_required: false,\n        },\n    )\n    .await\n}\n\nasync fn load_vars(config: &Arc<Config>) -> Result<EnvResults> {\n    time!(\"load_vars start\");\n    let vars_results = resolve_vars_from_config_files(config, &config.config_files).await?;\n    time!(\"load_vars done\");\n    if log::log_enabled!(log::Level::Trace) {\n        trace!(\"{vars_results:#?}\");\n    } else if !vars_results.is_empty() {\n        debug!(\"{vars_results:?}\");\n    }\n    Ok(vars_results)\n}\n\nimpl Debug for Config {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let config_files = self\n            .config_files\n            .iter()\n            .map(|(p, _)| display_path(p))\n            .collect::<Vec<_>>();\n        let mut s = f.debug_struct(\"Config\");\n        s.field(\"Config Files\", &config_files);\n        // Note: tasks are now lazily loaded and cached, so we can't access them synchronously here\n        // Try to get the default (current hierarchy) cache entry\n        let default_ctx = crate::task::TaskLoadContext::default();\n        if let Some(tasks) = self.tasks_cache.get(&default_ctx) {\n            s.field(\n                \"Tasks\",\n                &tasks.values().map(|t| t.to_string()).collect_vec(),\n            );\n        }\n        if let Some(env) = self.env_maybe()\n            && !env.is_empty()\n        {\n            s.field(\"Env\", &env);\n            // s.field(\"Env Sources\", &self.env_sources);\n        }\n        if let Some(env_results) = self.env.get() {\n            if !env_results.env_files.is_empty() {\n                s.field(\"Path Dirs\", &env_results.env_paths);\n            }\n            if !env_results.env_scripts.is_empty() {\n                s.field(\"Scripts\", &env_results.env_scripts);\n            }\n            if !env_results.env_files.is_empty() {\n                s.field(\"Files\", &env_results.env_files);\n            }\n        }\n        if !self.aliases.is_empty() {\n            s.field(\"Aliases\", &self.aliases);\n        }\n        s.finish()\n    }\n}\n\n/// Collect all task templates from the config file hierarchy.\n/// Templates from child configs (closer to cwd) override templates from parent configs.\nfn collect_task_templates(config_files: &ConfigMap) -> IndexMap<String, TaskTemplate> {\n    let mut templates = IndexMap::new();\n\n    // Iterate in reverse order (global -> local) so child directories override parent configs\n    for cf in config_files.values().rev() {\n        for (name, template) in cf.task_templates() {\n            templates.insert(name, template);\n        }\n    }\n\n    templates\n}\n\n/// Resolve a task template and merge it into the task.\n/// Returns an error if the template is not found or if experimental mode is not enabled.\nfn resolve_task_template(\n    task: &mut Task,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<()> {\n    if let Some(template_name) = &task.extends {\n        if !Settings::get().experimental {\n            bail!(\n                \"Task '{}' uses 'extends = \\\"{}\\\"' which requires 'experimental = true' in settings\",\n                task.name,\n                template_name\n            );\n        }\n\n        let template = templates.get(template_name).ok_or_else(|| {\n            eyre!(\n                \"Task '{}' extends template '{}' which was not found. \\\n                 Available templates: {}\",\n                task.name,\n                template_name,\n                if templates.is_empty() {\n                    \"(none)\".to_string()\n                } else {\n                    templates.keys().join(\", \")\n                }\n            )\n        })?;\n\n        task.merge_template(template);\n    }\n    Ok(())\n}\n\nfn default_task_includes() -> Vec<String> {\n    vec![\n        \"mise-tasks\".to_string(),\n        \".mise-tasks\".to_string(),\n        \".mise/tasks\".to_string(),\n        \".config/mise/tasks\".to_string(),\n        \"mise/tasks\".to_string(),\n    ]\n}\n\nfn is_global_task_include_path(path: &Path) -> bool {\n    path.starts_with(dirs::CONFIG.join(\"tasks\"))\n        || path.starts_with(dirs::SYSTEM_CONFIG.join(\"tasks\"))\n}\n\n#[async_backtrace::framed]\npub async fn rebuild_shims_and_runtime_symlinks(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    new_versions: &[ToolVersion],\n) -> Result<()> {\n    measure!(\"rebuilding shims\", {\n        shims::reshim(config, ts, false)\n            .await\n            .wrap_err(\"failed to rebuild shims\")?;\n    });\n    measure!(\"rebuilding runtime symlinks\", {\n        runtime_symlinks::rebuild(config)\n            .await\n            .wrap_err(\"failed to rebuild runtime symlinks\")?;\n    });\n    measure!(\"updating lockfiles\", {\n        lockfile::update_lockfiles(config, ts, new_versions)\n            .wrap_err(\"failed to update lockfiles\")?;\n    });\n    if !new_versions.is_empty() {\n        measure!(\"auto-locking platforms\", {\n            if let Err(e) = lockfile::auto_lock_new_versions(config, new_versions).await {\n                warn!(\"failed to auto-lock platforms for new versions: {e}\");\n            }\n        });\n    }\n\n    Ok(())\n}\n\nfn prefix_monorepo_task_names(tasks: &mut [Task], dir: &Path, monorepo_root: &Path) {\n    const MONOREPO_PATH_PREFIX: &str = \"//\";\n    const MONOREPO_TASK_SEPARATOR: &str = \":\";\n\n    if let Ok(rel_path) = dir.strip_prefix(monorepo_root) {\n        let prefix = rel_path\n            .to_string_lossy()\n            .replace(std::path::MAIN_SEPARATOR, \"/\");\n        for task in tasks.iter_mut() {\n            task.name = format!(\n                \"{}{}{}{}\",\n                MONOREPO_PATH_PREFIX, prefix, MONOREPO_TASK_SEPARATOR, task.name\n            );\n        }\n    }\n}\n\nasync fn load_local_tasks_with_context(\n    config: &Arc<Config>,\n    ctx: Option<&crate::task::TaskLoadContext>,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<Vec<Task>> {\n    let mut tasks = vec![];\n    let monorepo_config = find_monorepo_config(&config.config_files);\n    let monorepo_root = monorepo_config.and_then(|cf| cf.project_root().map(|p| p.to_path_buf()));\n\n    // Load tasks from parent directories (current working directory up to root)\n\n    let local_config_files = config\n        .config_files\n        .iter()\n        .filter(|(_, cf)| !is_global_config(cf.get_path()))\n        .map(|(k, v)| (k.clone(), v.clone()))\n        .collect::<IndexMap<_, _>>();\n    for d in all_dirs()? {\n        if cfg!(test) && !d.starts_with(*dirs::HOME) {\n            continue;\n        }\n        let mut dir_tasks = load_tasks_in_dir(config, &d, &local_config_files, templates).await?;\n\n        if let Some(ref monorepo_root) = monorepo_root {\n            prefix_monorepo_task_names(&mut dir_tasks, &d, monorepo_root);\n        }\n\n        tasks.extend(dir_tasks);\n    }\n\n    // Determine if we should load monorepo tasks from subdirectories\n    // We should load subdirs if:\n    // 1. load_all is true (--all flag or wildcard patterns like //...:task)\n    // 2. OR we have specific path_hints (patterns like //foo/bar:task)\n    let should_load_subdirs = ctx.is_some_and(|c| c.load_all || !c.path_hints.is_empty());\n\n    // If in a monorepo, also discover and load tasks from subdirectories\n    if let Some(monorepo_root) = &monorepo_root {\n        // By default, only load tasks from current directory hierarchy (already loaded above)\n        // With --all flag or path hints, also load tasks from matching subdirectories\n        if !should_load_subdirs {\n            // Default: don't load any additional monorepo subdirs (they're not in our hierarchy)\n            return Ok(tasks);\n        }\n\n        // Get config_roots from [monorepo] section if defined\n        let config_roots = monorepo_config\n            .and_then(|cf| cf.monorepo())\n            .map(|m| &m.config_roots);\n        let subdirs = discover_monorepo_subdirs(monorepo_root, config_roots, ctx)?;\n\n        // Load tasks from subdirectories in parallel\n        let subdir_tasks_futures: Vec<_> = subdirs\n            .into_iter()\n            .filter(|subdir| !cfg!(test) || subdir.starts_with(*dirs::HOME))\n            .map(|subdir| {\n                let config = config.clone();\n                let monorepo_root = monorepo_root.clone();\n                let templates = templates.clone();\n                async move {\n                    // Use IndexMap to deduplicate tasks by name within this subdirectory\n                    // Later inserts win, so file tasks override config tasks with the same name\n                    let mut task_map: IndexMap<String, Task> = IndexMap::new();\n\n                    // Load config files from subdirectory\n                    // Use .rev() so later files (like mise.local.toml) have higher precedence\n                    // Use glob() with .rev() for conf.d patterns so later files (02-override.toml) override earlier ones\n                    let config_paths: Vec<PathBuf> = DEFAULT_CONFIG_FILENAMES\n                        .iter()\n                        .rev()\n                        .flat_map(|f| {\n                            if f.contains('*') {\n                                glob(&subdir, f).unwrap_or_default().into_iter().rev().collect()\n                            } else {\n                                let path = subdir.join(f);\n                                if path.exists() {\n                                    vec![path]\n                                } else {\n                                    vec![]\n                                }\n                            }\n                        })\n                        .collect();\n\n                    // Deduplicate config paths while preserving precedence order\n                    let mut seen = std::collections::HashSet::new();\n                    let config_paths: Vec<PathBuf> = config_paths\n                        .into_iter()\n                        .filter(|p| seen.insert(p.clone()))\n                        .collect();\n\n                    let found_config = !config_paths.is_empty();\n                    for config_path in config_paths {\n                        match config_file::parse(&config_path).await {\n                            Ok(cf) => {\n                                let mut subdir_tasks =\n                                    load_config_and_file_tasks(&config, cf.clone(), &templates).await?;\n\n                                prefix_monorepo_task_names(&mut subdir_tasks, &subdir, &monorepo_root);\n                                for task in subdir_tasks.iter_mut() {\n                                    // Store reference to config file for later use\n                                    task.cf = Some(cf.clone());\n                                }\n\n                                // Add tasks to map - later tasks override earlier ones with same name\n                                for task in subdir_tasks {\n                                    task_map.insert(task.name.clone(), task);\n                                }\n                            }\n                            Err(err) => {\n                                let rel_path = subdir\n                                    .strip_prefix(&monorepo_root)\n                                    .unwrap_or(&subdir);\n                                warn!(\n                                    \"Failed to parse config file {} in monorepo subdirectory {}: {}. Tasks from this directory will not be loaded.\",\n                                    config_path.display(),\n                                    rel_path.display(),\n                                    err\n                                );\n                            }\n                        }\n                    }\n\n                    // If no config file exists, still load default task include dirs\n                    if !found_config {\n                        let includes = task_includes_for_dir(&subdir, &config.config_files);\n                        for include in includes {\n                            let mut subdir_tasks =\n                                load_tasks_includes(&config, &include, &subdir).await?;\n                            if is_global_task_include_path(&include) {\n                                mark_tasks_as_global(&mut subdir_tasks);\n                            }\n                            prefix_monorepo_task_names(&mut subdir_tasks, &subdir, &monorepo_root);\n                            for task in subdir_tasks {\n                                task_map.insert(task.name.clone(), task);\n                            }\n                        }\n                    }\n\n                    Ok::<Vec<Task>, eyre::Report>(task_map.into_values().collect())\n                }\n            })\n            .collect();\n\n        // Wait for all subdirectory tasks to load\n        use tokio::task::JoinSet;\n        let mut join_set = JoinSet::new();\n        for future in subdir_tasks_futures {\n            join_set.spawn(future);\n        }\n\n        while let Some(result) = join_set.join_next().await {\n            tasks.extend(result??);\n        }\n    }\n\n    Ok(tasks)\n}\n\n/// Expand [monorepo].config_roots patterns to actual directories.\n/// Supports explicit paths and single-level globs (*).\n/// Recursive globs (**) are not supported.\nfn expand_config_roots(\n    root: &Path,\n    patterns: &[String],\n    ctx: Option<&crate::task::TaskLoadContext>,\n) -> Result<Vec<PathBuf>> {\n    let mut subdirs = Vec::new();\n\n    for pattern in patterns {\n        // Reject absolute paths and parent directory escapes\n        if pattern.starts_with('/') || pattern.starts_with(\"..\") || pattern.contains(\"/../\") {\n            warn!(\n                \"[monorepo] config_roots: '{}' must be a relative path within the monorepo\",\n                pattern\n            );\n            continue;\n        }\n\n        // Reject recursive glob patterns (**)\n        if pattern.contains(\"**\") {\n            warn!(\n                \"[monorepo] config_roots: recursive glob '**' not supported in '{}', use single-level '*' instead\",\n                pattern\n            );\n            continue;\n        }\n\n        if pattern.contains('*') {\n            // Single-level glob expansion\n            let full_pattern = root.join(pattern);\n            match glob::glob(&full_pattern.to_string_lossy()) {\n                Ok(entries) => {\n                    for entry in entries {\n                        match entry {\n                            Ok(path) => {\n                                // Verify path is within monorepo root\n                                if path.strip_prefix(root).is_err() {\n                                    warn!(\n                                        \"[monorepo] config_roots: glob matched path outside monorepo root: {}\",\n                                        path.display()\n                                    );\n                                    continue;\n                                }\n                                if path.is_dir() && has_mise_config(&path) {\n                                    subdirs.push(path);\n                                }\n                            }\n                            Err(e) => {\n                                warn!(\"[monorepo] config_roots glob error: {e}\");\n                            }\n                        }\n                    }\n                }\n                Err(e) => {\n                    warn!(\"[monorepo] config_roots invalid glob pattern '{pattern}': {e}\");\n                }\n            }\n        } else {\n            // Explicit path\n            let path = root.join(pattern);\n            // Verify path is within monorepo root after resolution\n            if let Ok(canonical) = path.canonicalize()\n                && let Ok(canonical_root) = root.canonicalize()\n                && !canonical.starts_with(&canonical_root)\n            {\n                warn!(\n                    \"[monorepo] config_roots: '{}' resolves outside monorepo root\",\n                    pattern\n                );\n                continue;\n            }\n            if path.is_dir() {\n                if has_mise_config(&path) {\n                    subdirs.push(path);\n                } else {\n                    warn!(\n                        \"[monorepo] config_roots: '{}' has no mise config file\",\n                        pattern\n                    );\n                }\n            } else {\n                warn!(\"[monorepo] config_roots: '{}' does not exist\", pattern);\n            }\n        }\n    }\n\n    // Apply TaskLoadContext filtering if provided\n    if let Some(ctx) = ctx {\n        subdirs.retain(|dir| {\n            let rel_path = dir\n                .strip_prefix(root)\n                .ok()\n                .and_then(|p| p.to_str())\n                .unwrap_or(\"\");\n            ctx.should_load_subdir(rel_path, root.to_str().unwrap_or(\"\"))\n        });\n    }\n\n    Ok(subdirs)\n}\n\n/// Check if a directory contains a mise config file or file tasks directory\nfn has_mise_config(dir: &Path) -> bool {\n    DEFAULT_CONFIG_FILENAMES\n        .iter()\n        .any(|f| dir.join(f).exists())\n        || dir.join(\".mise/tasks\").is_dir()\n        || dir.join(\"mise-tasks\").is_dir()\n}\n\nfn discover_monorepo_subdirs(\n    root: &Path,\n    config_roots: Option<&Vec<String>>,\n    ctx: Option<&crate::task::TaskLoadContext>,\n) -> Result<Vec<PathBuf>> {\n    // If [monorepo].config_roots is defined, use explicit paths instead of walking\n    if let Some(patterns) = config_roots\n        && !patterns.is_empty()\n    {\n        return expand_config_roots(root, patterns, ctx);\n    }\n\n    // Fall back to filesystem walking (deprecated)\n    deprecated!(\n        \"monorepo_auto_discovery\",\n        \"Automatic monorepo discovery is deprecated. \\\n         Please define [monorepo].config_roots in your root mise.toml. \\\n         See https://mise.jdx.dev/tasks/monorepo.html#explicit-config-roots\"\n    );\n    const DEFAULT_IGNORED_DIRS: &[&str] = &[\"node_modules\", \"target\", \"dist\", \"build\"];\n    let has_task_includes = |dir: &Path| {\n        default_task_includes()\n            .into_iter()\n            .any(|include| dir.join(include).exists())\n    };\n\n    let mut subdirs = Vec::new();\n    let settings = Settings::get();\n    let respect_gitignore = settings.task.monorepo_respect_gitignore;\n    let max_depth = settings.task.monorepo_depth as usize;\n\n    // Build the list of excluded directories\n    // If user defined custom exclude dirs, use only those, otherwise use defaults\n    let excluded_dirs: Vec<&str> = if settings.task.monorepo_exclude_dirs.is_empty() {\n        DEFAULT_IGNORED_DIRS.to_vec()\n    } else {\n        settings\n            .task\n            .monorepo_exclude_dirs\n            .iter()\n            .map(|s| s.as_str())\n            .collect()\n    };\n\n    if respect_gitignore {\n        // Use the `ignore` crate which respects .gitignore files\n        let walker = ignore::WalkBuilder::new(root)\n            .max_depth(Some(max_depth))\n            .hidden(true) // Skip hidden files/dirs\n            .git_ignore(true) // Respect .gitignore\n            .git_global(true) // Respect global .gitignore\n            .git_exclude(true) // Respect .git/info/exclude\n            .require_git(false) // Don't require a git repo\n            .build();\n\n        for entry in walker {\n            let entry = entry?;\n            if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {\n                let dir = entry.path();\n\n                // Skip if depth is 0 (root itself)\n                if dir == root {\n                    continue;\n                }\n\n                // Check against excluded directories\n                let name = dir.file_name().and_then(|n| n.to_str()).unwrap_or(\"\");\n                if excluded_dirs.contains(&name) {\n                    continue;\n                }\n\n                // Check if this directory has a mise config file\n                let has_config = DEFAULT_CONFIG_FILENAMES\n                    .iter()\n                    .any(|f| dir.join(f).exists());\n                let has_task_includes = has_task_includes(dir);\n                if has_config || has_task_includes {\n                    // Apply context filtering if provided\n                    if let Some(ctx) = ctx {\n                        let rel_path = dir\n                            .strip_prefix(root)\n                            .ok()\n                            .and_then(|p| p.to_str())\n                            .unwrap_or(\"\");\n                        if ctx.should_load_subdir(rel_path, root.to_str().unwrap_or(\"\")) {\n                            subdirs.push(dir.to_path_buf());\n                        }\n                    } else {\n                        subdirs.push(dir.to_path_buf());\n                    }\n                }\n            }\n        }\n    } else {\n        // Fall back to WalkDir for non-gitignore-aware walking\n        for entry in WalkDir::new(root)\n            .min_depth(1)\n            .max_depth(max_depth)\n            .into_iter()\n            .filter_entry(|e| {\n                // Skip hidden directories and excluded patterns\n                let name = e.file_name().to_string_lossy();\n                !name.starts_with('.') && !excluded_dirs.contains(&name.as_ref())\n            })\n        {\n            let entry = entry?;\n            if entry.file_type().is_dir() {\n                let dir = entry.path();\n                // Check if this directory has a mise config file\n                let has_config = DEFAULT_CONFIG_FILENAMES\n                    .iter()\n                    .any(|f| dir.join(f).exists());\n                let has_task_includes = has_task_includes(dir);\n                if has_config || has_task_includes {\n                    // Apply context filtering if provided\n                    if let Some(ctx) = ctx {\n                        let rel_path = dir\n                            .strip_prefix(root)\n                            .ok()\n                            .and_then(|p| p.to_str())\n                            .unwrap_or(\"\");\n                        if ctx.should_load_subdir(rel_path, root.to_str().unwrap_or(\"\")) {\n                            subdirs.push(dir.to_path_buf());\n                        }\n                    } else {\n                        subdirs.push(dir.to_path_buf());\n                    }\n                }\n            }\n        }\n    }\n\n    Ok(subdirs)\n}\n\nasync fn load_global_tasks(\n    config: &Arc<Config>,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<Vec<Task>> {\n    let config_files = config\n        .config_files\n        .values()\n        .filter(|cf| is_global_config(cf.get_path()))\n        .collect::<Vec<_>>();\n    let mut tasks = vec![];\n    for cf in config_files {\n        tasks.extend(load_config_and_file_tasks(config, cf.clone(), templates).await?);\n    }\n    Ok(tasks)\n}\n\nasync fn load_config_and_file_tasks(\n    config: &Arc<Config>,\n    cf: Arc<dyn ConfigFile>,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<Vec<Task>> {\n    let config_root = cf.config_root();\n    let tasks = load_config_tasks(config, cf.clone(), &config_root, templates).await?;\n    let file_tasks = load_file_tasks(config, cf.clone(), &config_root).await?;\n    Ok(tasks.into_iter().chain(file_tasks).collect())\n}\n\nasync fn load_config_tasks(\n    config: &Arc<Config>,\n    cf: Arc<dyn ConfigFile>,\n    config_root: &Path,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<Vec<Task>> {\n    let is_global = is_global_config(cf.get_path());\n    let config_root = Arc::new(config_root.to_path_buf());\n    let mut tasks = vec![];\n    for t in cf.tasks().into_iter() {\n        let config_root = config_root.clone();\n        let config = config.clone();\n        let mut t = t.clone();\n        if is_global {\n            t.global = true;\n        }\n        // Resolve template if the task extends one\n        resolve_task_template(&mut t, templates)?;\n        match t.render(&config, &config_root).await {\n            Ok(()) => {\n                tasks.push(t);\n            }\n            Err(e) => {\n                return Err(e);\n            }\n        }\n    }\n    Ok(tasks)\n}\n\nasync fn load_tasks_includes(\n    config: &Arc<Config>,\n    root: &Path,\n    config_root: &Path,\n) -> Result<Vec<Task>> {\n    if root.is_file() && root.extension().map(|e| e == \"toml\").unwrap_or(false) {\n        load_task_file(config, root, config_root).await\n    } else if root.is_dir() {\n        let files = WalkDir::new(root)\n            .follow_links(true)\n            .into_iter()\n            // skip hidden directories (if the root is hidden that's ok)\n            .filter_entry(|e| e.path() == root || !e.file_name().to_string_lossy().starts_with('.'))\n            .filter_ok(|e| e.file_type().is_file())\n            .map_ok(|e| e.path().to_path_buf())\n            .try_collect::<_, Vec<PathBuf>, _>()?\n            .into_iter()\n            .filter(|p| file::is_executable(p))\n            .filter(|p| {\n                !Settings::get()\n                    .task\n                    .disable_paths\n                    .iter()\n                    .any(|d| p.starts_with(d))\n            })\n            .collect::<Vec<_>>();\n        let mut tasks = vec![];\n        let root = Arc::new(root.to_path_buf());\n        let config_root = Arc::new(config_root.to_path_buf());\n        for path in files {\n            let root = root.clone();\n            let config_root = config_root.clone();\n            let config = config.clone();\n            tasks.push(Task::from_path(&config, &path, &root, &config_root).await?);\n        }\n        Ok(tasks)\n    } else {\n        Ok(vec![])\n    }\n}\n\nasync fn resolve_git_url_to_path(git_url: &str) -> Result<PathBuf> {\n    let no_cache = Settings::get().task.remote_no_cache.unwrap_or(false);\n    let task_file_providers = TaskFileProvidersBuilder::new()\n        .with_cache(!no_cache)\n        .build();\n\n    match task_file_providers.get_provider(git_url) {\n        Some(provider) => provider.get_local_path(git_url).await,\n        None => bail!(\"No provider found for git URL: {}\", git_url),\n    }\n}\n\n/// Check if a pattern contains glob metacharacters\nfn is_glob_pattern(pattern: &str) -> bool {\n    // Check for unescaped glob metacharacters: *, ?, [, ], {, }\n    // Note: This is a simple check that may have false positives with escaped chars,\n    // but glob() will handle those correctly\n    pattern.contains('*')\n        || pattern.contains('?')\n        || pattern.contains('[')\n        || pattern.contains(']')\n        || pattern.contains('{')\n        || pattern.contains('}')\n}\n\n/// Expand a task include pattern (which may be a glob) to a list of paths\nfn expand_task_include(dir: &Path, pattern: &str) -> Vec<PathBuf> {\n    if is_glob_pattern(pattern) {\n        match glob(dir, pattern) {\n            Ok(paths) => paths,\n            Err(err) => {\n                warn!(\n                    \"failed to expand glob pattern '{}' in '{}': {}\",\n                    pattern,\n                    display_path(dir),\n                    err\n                );\n                vec![]\n            }\n        }\n    } else {\n        // Literal path\n        let path = PathBuf::from(pattern);\n        let resolved = if path.is_absolute() {\n            path\n        } else {\n            dir.join(path)\n        };\n        if resolved.exists() {\n            vec![resolved]\n        } else {\n            vec![]\n        }\n    }\n}\n\nasync fn load_file_tasks(\n    config: &Arc<Config>,\n    cf: Arc<dyn ConfigFile>,\n    config_root: &Path,\n) -> Result<Vec<Task>> {\n    let includes = cf\n        .task_config()\n        .includes\n        .clone()\n        .unwrap_or_else(default_task_includes);\n\n    let mut tasks = vec![];\n    let config_root = Arc::new(config_root.to_path_buf());\n    let cf_root = cf.config_root();\n\n    for include in includes {\n        let paths = if include.starts_with(\"git::\") {\n            vec![resolve_git_url_to_path(&include).await?]\n        } else {\n            expand_task_include(&cf_root, &include)\n        };\n        for path in paths {\n            let mut loaded = load_tasks_includes(config, &path, &config_root).await?;\n            if is_global_task_include_path(&path) {\n                mark_tasks_as_global(&mut loaded);\n            }\n            tasks.extend(loaded);\n        }\n    }\n    Ok(tasks)\n}\n\npub fn task_includes_for_dir(dir: &Path, config_files: &ConfigMap) -> Vec<PathBuf> {\n    let configs = configs_at_root(dir, config_files);\n\n    // Find the first config that has explicit task_config.includes\n    // and resolve paths relative to that config file's directory\n    let (includes, resolve_dir) = configs\n        .iter()\n        .rev()\n        .find_map(|cf| {\n            cf.task_config().includes.clone().map(|includes| {\n                // Resolve relative paths from the config root, not the config file's directory\n                (includes, cf.config_root())\n            })\n        })\n        .unwrap_or_else(|| {\n            // Default includes should be resolved relative to the search directory\n            (default_task_includes(), dir.to_path_buf())\n        });\n\n    includes\n        .into_iter()\n        .flat_map(|p| {\n            // Git URLs are handled by load_file_tasks, not here\n            if p.starts_with(\"git::\") {\n                return vec![];\n            }\n            expand_task_include(&resolve_dir, &p)\n        })\n        .unique()\n        .collect::<Vec<_>>()\n}\n\npub async fn load_tasks_in_dir(\n    config: &Arc<Config>,\n    dir: &Path,\n    config_files: &ConfigMap,\n    templates: &IndexMap<String, TaskTemplate>,\n) -> Result<Vec<Task>> {\n    let configs = configs_at_root(dir, config_files);\n\n    let git_includes: Vec<String> = configs\n        .iter()\n        .rev()\n        .find_map(|cf| cf.task_config().includes.clone())\n        .unwrap_or_default()\n        .into_iter()\n        .filter(|p| p.starts_with(\"git::\"))\n        .collect();\n\n    let mut config_tasks = vec![];\n    for cf in &configs {\n        let dir = dir.to_path_buf();\n        config_tasks.extend(load_config_tasks(config, (*cf).clone(), &dir, templates).await?);\n    }\n\n    let mut file_tasks = vec![];\n    for p in task_includes_for_dir(dir, config_files) {\n        let mut loaded = load_tasks_includes(config, &p, dir).await?;\n        if is_global_task_include_path(&p) {\n            mark_tasks_as_global(&mut loaded);\n        }\n        file_tasks.extend(loaded);\n    }\n\n    for include in git_includes {\n        let resolved = resolve_git_url_to_path(&include).await?;\n        file_tasks.extend(load_tasks_includes(config, &resolved, dir).await?);\n    }\n\n    let mut tasks = file_tasks\n        .into_iter()\n        .chain(config_tasks)\n        .sorted_by_cached_key(|t| t.name.clone())\n        .collect::<Vec<_>>();\n    let all_tasks = tasks\n        .clone()\n        .into_iter()\n        .map(|t| (t.name.clone(), t))\n        .collect::<BTreeMap<_, _>>();\n    for task in tasks.iter_mut() {\n        task.display_name = task.display_name(&all_tasks);\n    }\n    Ok(tasks)\n}\n\nasync fn load_task_file(\n    config: &Arc<Config>,\n    path: &Path,\n    config_root: &Path,\n) -> Result<Vec<Task>> {\n    let raw = file::read_to_string_async(path).await?;\n    let mut tasks = toml::from_str::<Tasks>(&raw)\n        .wrap_err_with(|| format!(\"Error parsing task file: {}\", display_path(path)))?\n        .0;\n    for (name, task) in &mut tasks {\n        task.name = name.clone();\n        task.config_source = path.to_path_buf();\n        task.config_root = Some(config_root.to_path_buf());\n    }\n    let mut out = vec![];\n    for (_, mut task) in tasks {\n        let config_root = config_root.to_path_buf();\n        if let Err(err) = task.render(config, &config_root).await {\n            warn!(\"rendering task: {err:?}\");\n        }\n        out.push(task);\n    }\n    Ok(out)\n}\n\nfn mark_tasks_as_global(tasks: &mut [Task]) {\n    tasks.iter_mut().for_each(|task| task.global = true);\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use insta::assert_debug_snapshot;\n    use std::collections::BTreeMap;\n    use std::fs::{self, File};\n    use tempfile::TempDir;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_load() {\n        let config = Config::reset().await.unwrap();\n        assert_debug_snapshot!(config);\n    }\n\n    #[tokio::test]\n    async fn test_load_all_config_files_skips_directories() -> Result<()> {\n        let _config = Config::get().await?;\n        let temp_dir = TempDir::new()?;\n        let temp_path = temp_dir.path();\n\n        let sub_dir = temp_path.join(\"subdir\");\n        fs::create_dir(&sub_dir)?;\n\n        let file1_path = temp_path.join(\"config1.toml\");\n        let file2_path = temp_path.join(\"config2.toml\");\n        File::create(&file1_path)?;\n        File::create(&file2_path)?;\n\n        fs::write(&file1_path, \"key1 = 'value1'\")?;\n        fs::write(&file2_path, \"key2 = 'value2'\")?;\n\n        let config_filenames = vec![file1_path.clone(), file2_path.clone(), sub_dir.clone()];\n        let idiomatic_filenames = BTreeMap::new();\n\n        let result = load_all_config_files(&config_filenames, &idiomatic_filenames).await?;\n\n        // the result should have only two entries for the files, the directory should not be present\n        assert_eq!(result.len(), 2);\n\n        // Check that the directory is not in the result\n        assert!(result.contains_key(&file1_path));\n        assert!(result.contains_key(&file2_path));\n        assert!(!result.contains_key(&sub_dir));\n\n        Ok(())\n    }\n\n    #[tokio::test]\n    async fn test_load_task_file_supports_per_task_vars() -> Result<()> {\n        let config = Config::reset().await?;\n        let temp_dir = TempDir::new()?;\n        let tasks_toml = temp_dir.path().join(\"tasks.toml\");\n        fs::write(\n            &tasks_toml,\n            r#\"\n[build]\ndescription = \"{{vars.target}}\"\nrun = \"echo build\"\nvars = { target = \"linux\" }\n\"#,\n        )?;\n\n        let tasks = load_task_file(&config, &tasks_toml, temp_dir.path()).await?;\n        assert_eq!(tasks.len(), 1);\n        assert_eq!(tasks[0].name, \"build\");\n        assert_eq!(tasks[0].description, \"linux\");\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/config/settings.rs",
    "content": "use crate::cli::Cli;\nuse crate::config::ALL_TOML_CONFIG_FILES;\nuse crate::duration;\nuse crate::file::FindUp;\nuse crate::{dirs, env, file};\n#[allow(unused_imports)]\nuse confique::env::parse::{list_by_colon, list_by_comma};\nuse confique::{Config, Partial};\nuse eyre::{Result, bail};\nuse indexmap::{IndexMap, indexmap};\nuse itertools::Itertools;\nuse serde::ser::Error;\nuse serde::{Deserialize, Deserializer, Serializer};\nuse serde_derive::Serialize;\nuse std::env::consts::{ARCH, OS};\nuse std::fmt::{Debug, Display, Formatter};\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::sync::LazyLock as Lazy;\nuse std::sync::{Arc, Mutex, RwLock};\nuse std::time::Duration;\nuse std::{\n    collections::{BTreeSet, HashSet},\n    sync::atomic::Ordering,\n};\nuse url::Url;\n\n// settings are generated from settings.toml in the project root\n// make sure you run `mise run render` after updating settings.toml\ninclude!(concat!(env!(\"OUT_DIR\"), \"/settings.rs\"));\n\npub enum SettingsType {\n    Bool,\n    String,\n    Integer,\n    Duration,\n    Path,\n    Url,\n    ListString,\n    ListPath,\n    SetString,\n    IndexMap,\n    BoolOrString,\n}\n\npub struct SettingsMeta {\n    // pub key: String,\n    pub type_: SettingsType,\n    pub description: &'static str,\n    pub deprecated: Option<&'static str>,\n    pub deprecated_warn_at: Option<&'static str>,\n    pub deprecated_remove_at: Option<&'static str>,\n}\n\n#[derive(\n    Debug,\n    Clone,\n    Copy,\n    Serialize,\n    Deserialize,\n    Default,\n    strum::EnumString,\n    strum::Display,\n    PartialEq,\n    Eq,\n)]\n#[serde(rename_all = \"snake_case\")]\n#[strum(serialize_all = \"snake_case\")]\npub enum SettingsStatusMissingTools {\n    /// never show the warning\n    Never,\n    /// hide this warning if the user hasn't installed at least 1 version of the tool before\n    #[default]\n    IfOtherVersionsInstalled,\n    /// always show the warning if tools are missing\n    Always,\n}\n\n#[derive(\n    Debug,\n    Clone,\n    Copy,\n    Serialize,\n    Deserialize,\n    Default,\n    strum::EnumString,\n    strum::Display,\n    PartialEq,\n    Eq,\n)]\n#[serde(rename_all = \"snake_case\")]\n#[strum(serialize_all = \"snake_case\")]\npub enum NpmPackageManager {\n    #[default]\n    Npm,\n    Bun,\n    Pnpm,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum PythonUvVenvAuto {\n    #[default]\n    Off,\n    Source,\n    CreateSource,\n    LegacyTrue,\n}\n\nimpl PythonUvVenvAuto {\n    pub fn should_source(self) -> bool {\n        matches!(self, Self::Source | Self::CreateSource | Self::LegacyTrue)\n    }\n\n    pub fn should_create(self) -> bool {\n        matches!(self, Self::CreateSource | Self::LegacyTrue)\n    }\n\n    pub fn is_legacy_true(self) -> bool {\n        matches!(self, Self::LegacyTrue)\n    }\n}\n\nimpl<'de> Deserialize<'de> for PythonUvVenvAuto {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        use serde::de::{self, Visitor};\n        use std::fmt;\n\n        struct PythonUvVenvAutoVisitor;\n\n        impl<'de> Visitor<'de> for PythonUvVenvAutoVisitor {\n            type Value = PythonUvVenvAuto;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a boolean, \\\"source\\\", or \\\"create|source\\\"\")\n            }\n\n            fn visit_bool<E>(self, value: bool) -> Result<PythonUvVenvAuto, E>\n            where\n                E: de::Error,\n            {\n                if value {\n                    deprecated_at!(\n                        \"2026.7.0\",\n                        \"2027.7.0\",\n                        \"python.uv_venv_auto.true\",\n                        \"python.uv_venv_auto=true is deprecated. Use python.uv_venv_auto=\\\"create|source\\\" or \\\"source\\\" instead.\"\n                    );\n                }\n                Ok(if value {\n                    PythonUvVenvAuto::LegacyTrue\n                } else {\n                    PythonUvVenvAuto::Off\n                })\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<PythonUvVenvAuto, E>\n            where\n                E: de::Error,\n            {\n                let normalized = value.trim().to_ascii_lowercase();\n                match normalized.as_str() {\n                    \"source\" => Ok(PythonUvVenvAuto::Source),\n                    \"create|source\" => Ok(PythonUvVenvAuto::CreateSource),\n                    \"true\" | \"yes\" | \"1\" => self.visit_bool(true),\n                    \"false\" | \"no\" | \"0\" => self.visit_bool(false),\n                    _ => Err(E::invalid_value(de::Unexpected::Str(value), &self)),\n                }\n            }\n\n            fn visit_string<E>(self, value: String) -> Result<PythonUvVenvAuto, E>\n            where\n                E: de::Error,\n            {\n                self.visit_str(&value)\n            }\n        }\n\n        deserializer.deserialize_any(PythonUvVenvAutoVisitor)\n    }\n}\n\nimpl serde::Serialize for PythonUvVenvAuto {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match self {\n            PythonUvVenvAuto::Off => serializer.serialize_bool(false),\n            PythonUvVenvAuto::LegacyTrue => serializer.serialize_bool(true),\n            PythonUvVenvAuto::Source => serializer.serialize_str(\"source\"),\n            PythonUvVenvAuto::CreateSource => serializer.serialize_str(\"create|source\"),\n        }\n    }\n}\n\npub type SettingsPartial = <Settings as Config>::Partial;\n\nstatic BASE_SETTINGS: RwLock<Option<Arc<Settings>>> = RwLock::new(None);\nstatic CLI_SETTINGS: Mutex<Option<SettingsPartial>> = Mutex::new(None);\nstatic DEFAULT_SETTINGS: Lazy<SettingsPartial> = Lazy::new(|| {\n    let mut s = SettingsPartial::empty();\n    s.python.default_packages_file = Some(env::HOME.join(\".default-python-packages\"));\n    if let Some(\"alpine\" | \"nixos\") = env::LINUX_DISTRO.as_ref().map(|s| s.as_str())\n        && !cfg!(test)\n    {\n        s.all_compile = Some(true);\n    }\n    s\n});\n\npub fn is_loaded() -> bool {\n    BASE_SETTINGS.read().unwrap().is_some()\n}\n\n#[derive(Serialize, Deserialize)]\npub struct SettingsFile {\n    #[serde(default)]\n    pub settings: SettingsPartial,\n}\n\nfn warn_deprecated(key: &str) {\n    if let Some(meta) = SETTINGS_META.get(key)\n        && let (Some(msg), Some(warn_at), Some(remove_at)) = (\n            meta.deprecated,\n            meta.deprecated_warn_at,\n            meta.deprecated_remove_at,\n        )\n    {\n        use versions::Versioning;\n        let warn_version = Versioning::new(warn_at).unwrap();\n        let remove_version = Versioning::new(remove_at).unwrap();\n        debug_assert!(\n            *crate::cli::version::V < remove_version,\n            \"Deprecated setting [{key}] should have been removed in {remove_at}. Please remove this deprecated setting.\",\n        );\n        if *crate::cli::version::V >= warn_version {\n            let id = Box::leak(format!(\"setting.{key}\").into_boxed_str());\n            if crate::output::DEPRECATED.lock().unwrap().insert(id) {\n                warn!(\n                    \"deprecated [setting.{key}]: {msg} This will be removed in mise {remove_at}.\"\n                );\n            }\n        }\n    }\n}\n\nimpl Settings {\n    pub fn get() -> Arc<Self> {\n        Self::try_get().unwrap()\n    }\n    pub fn try_get() -> Result<Arc<Self>> {\n        if let Some(settings) = BASE_SETTINGS.read().unwrap().as_ref() {\n            return Ok(settings.clone());\n        }\n        time!(\"try_get\");\n\n        // Initial pass to obtain cd option\n        let mut sb = Self::builder()\n            .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default())\n            .env();\n\n        let mut settings = sb.load()?;\n        if let Some(mut cd) = settings.cd {\n            static ORIG_PATH: Lazy<std::io::Result<PathBuf>> = Lazy::new(env::current_dir);\n            if cd.is_relative() {\n                cd = ORIG_PATH.as_ref()?.join(cd);\n            }\n            env::set_current_dir(cd)?;\n        }\n\n        // Reload settings after current directory option processed\n        sb = Self::builder()\n            .preloaded(CLI_SETTINGS.lock().unwrap().clone().unwrap_or_default())\n            .env();\n        for file in Self::all_settings_files() {\n            sb = sb.preloaded(file);\n        }\n        sb = sb.preloaded(DEFAULT_SETTINGS.clone());\n\n        settings = sb.load()?;\n        if !settings.legacy_version_file {\n            settings.idiomatic_version_file = Some(false);\n        }\n        if settings.raw {\n            settings.jobs = 1;\n        }\n        // Handle NO_COLOR environment variable\n        if *env::NO_COLOR {\n            settings.color = false;\n        }\n        if settings.debug {\n            settings.log_level = \"debug\".to_string();\n        }\n        if settings.trace {\n            settings.log_level = \"trace\".to_string();\n        }\n        if settings.quiet {\n            settings.log_level = \"error\".to_string();\n        }\n        if settings.log_level == \"trace\" || settings.log_level == \"debug\" {\n            settings.verbose = true;\n            settings.debug = true;\n            if settings.log_level == \"trace\" {\n                settings.trace = true;\n            }\n        }\n        let args = env::args().collect_vec();\n        // handle the special case of `mise -v` which should show version, not set verbose\n        if settings.verbose && !(args.len() == 2 && args[1] == \"-v\") {\n            settings.quiet = false;\n            if settings.log_level != \"trace\" {\n                settings.log_level = \"debug\".to_string();\n            }\n        }\n        if !settings.color {\n            console::set_colors_enabled(false);\n            console::set_colors_enabled_stderr(false);\n        } else if *env::CLICOLOR_FORCE == Some(true) {\n            console::set_colors_enabled(true);\n            console::set_colors_enabled_stderr(true);\n        } else if *env::CLICOLOR == Some(false) {\n            console::set_colors_enabled(false);\n            console::set_colors_enabled_stderr(false);\n        } else if ci_info::is_ci() && !cfg!(test) {\n            console::set_colors_enabled_stderr(true);\n        }\n        if settings.ci {\n            settings.yes = true;\n        }\n        if settings.all_compile {\n            if settings.node.compile.is_none() {\n                settings.node.compile = Some(true);\n            }\n            if settings.python.compile.is_none() {\n                settings.python.compile = Some(true);\n            }\n            if settings.erlang.compile.is_none() {\n                settings.erlang.compile = Some(true);\n            }\n            if settings.ruby.compile.is_none() {\n                settings.ruby.compile = Some(true);\n            }\n        }\n        if settings.gpg_verify.is_some() {\n            settings.node.gpg_verify = settings.node.gpg_verify.or(settings.gpg_verify);\n            settings.swift.gpg_verify = settings.swift.gpg_verify.or(settings.gpg_verify);\n        }\n        settings.set_hidden_configs();\n        if cfg!(test) {\n            settings.experimental = true;\n        }\n        let settings = Arc::new(settings);\n        *BASE_SETTINGS.write().unwrap() = Some(settings.clone());\n        time!(\"try_get done\");\n        trace!(\"Settings: {:#?}\", settings);\n        Ok(settings)\n    }\n\n    /// Sets deprecated settings to new names\n    fn set_hidden_configs(&mut self) {\n        // Migrate task_* settings to task.* (must run before auto_install override below)\n        if let Some(v) = self.task_disable_paths.take()\n            && !v.is_empty()\n        {\n            warn_deprecated(\"task_disable_paths\");\n            self.task.disable_paths.extend(v);\n        }\n        if let Some(v) = self.task_output.take() {\n            warn_deprecated(\"task_output\");\n            self.task.output = Some(v);\n        }\n        if let Some(v) = self.task_remote_no_cache {\n            warn_deprecated(\"task_remote_no_cache\");\n            self.task.remote_no_cache = Some(v);\n        }\n        if let Some(v) = self.task_run_auto_install {\n            warn_deprecated(\"task_run_auto_install\");\n            self.task.run_auto_install = v;\n        }\n        if let Some(v) = self.task_show_full_cmd {\n            warn_deprecated(\"task_show_full_cmd\");\n            self.task.show_full_cmd = v;\n        }\n        if let Some(v) = self.task_skip.take()\n            && !v.is_empty()\n        {\n            warn_deprecated(\"task_skip\");\n            self.task.skip.extend(v);\n        }\n        if let Some(v) = self.task_skip_depends {\n            warn_deprecated(\"task_skip_depends\");\n            self.task.skip_depends = v;\n        }\n        if let Some(v) = self.task_timeout.take() {\n            warn_deprecated(\"task_timeout\");\n            self.task.timeout = Some(v);\n        }\n        if let Some(v) = self.task_timings {\n            warn_deprecated(\"task_timings\");\n            self.task.timings = Some(v);\n        }\n        if !self.auto_install {\n            self.exec_auto_install = false;\n            self.not_found_auto_install = false;\n            self.task.run_auto_install = false;\n        }\n        if let Some(false) = self.asdf {\n            self.disable_backends.push(\"asdf\".to_string());\n        }\n        if let Some(false) = self.vfox {\n            self.disable_backends.push(\"vfox\".to_string());\n        }\n        if let Some(disable_default_shorthands) = self.disable_default_shorthands {\n            self.disable_default_registry = disable_default_shorthands;\n        }\n        if let Some(cargo_binstall) = self.cargo_binstall {\n            self.cargo.binstall = cargo_binstall;\n        }\n        if let Some(pipx_uvx) = self.pipx_uvx {\n            self.pipx.uvx = Some(pipx_uvx);\n        }\n        if let Some(python_compile) = self.python_compile {\n            self.python.compile = Some(python_compile);\n        }\n        if let Some(python_default_packages_file) = &self.python_default_packages_file {\n            self.python.default_packages_file = Some(python_default_packages_file.clone());\n        }\n        if let Some(python_patch_url) = &self.python_patch_url {\n            self.python.patch_url = Some(python_patch_url.clone());\n        }\n        if let Some(python_patches_directory) = &self.python_patches_directory {\n            self.python.patches_directory = Some(python_patches_directory.clone());\n        }\n        if let Some(python_precompiled_arch) = &self.python_precompiled_arch {\n            self.python.precompiled_arch = Some(python_precompiled_arch.clone());\n        }\n        if let Some(python_precompiled_os) = &self.python_precompiled_os {\n            self.python.precompiled_os = Some(python_precompiled_os.clone());\n        }\n        if let Some(python_pyenv_repo) = &self.python_pyenv_repo {\n            self.python.pyenv_repo = python_pyenv_repo.clone();\n        }\n        if let Some(python_venv_stdlib) = self.python_venv_stdlib {\n            self.python.venv_stdlib = python_venv_stdlib;\n        }\n        if self.npm.bun {\n            self.npm.package_manager = NpmPackageManager::Bun;\n        }\n    }\n\n    pub fn add_cli_matches(cli: &Cli) {\n        let mut s = SettingsPartial::empty();\n\n        // Don't process mise-specific flags when running as a shim\n        if *crate::env::IS_RUNNING_AS_SHIM {\n            Self::reset(Some(s));\n            return;\n        }\n\n        if cli.raw {\n            s.raw = Some(true);\n        }\n        if cli.locked {\n            s.locked = Some(true);\n        }\n        if let Some(cd) = &cli.cd {\n            s.cd = Some(cd.clone());\n        }\n        if cli.profile.is_some() {\n            s.env = cli.profile.clone();\n        }\n        if cli.env.is_some() {\n            s.env = cli.env.clone();\n        }\n        if cli.yes {\n            s.yes = Some(true);\n        }\n        if cli.quiet {\n            s.quiet = Some(true);\n        }\n        if cli.trace {\n            s.log_level = Some(\"trace\".to_string());\n        }\n        if cli.debug {\n            s.log_level = Some(\"debug\".to_string());\n        }\n        if let Some(log_level) = &cli.log_level {\n            s.log_level = Some(log_level.to_string());\n        }\n        if cli.verbose > 0 {\n            s.verbose = Some(true);\n        }\n        if cli.verbose > 1 {\n            s.log_level = Some(\"trace\".to_string());\n        }\n        Self::reset(Some(s));\n    }\n\n    pub fn parse_settings_file(path: &Path) -> Result<SettingsPartial> {\n        let raw = file::read_to_string(path)?;\n        let settings_file: SettingsFile = toml::from_str(&raw)?;\n\n        Ok(settings_file.settings)\n    }\n\n    fn all_settings_files() -> Vec<SettingsPartial> {\n        ALL_TOML_CONFIG_FILES\n            .iter()\n            .map(|p| Self::parse_settings_file(p))\n            .filter_map(|cfg| match cfg {\n                Ok(cfg) => Some(cfg),\n                Err(e) => {\n                    eprintln!(\"Error loading settings file: {e}\");\n                    None\n                }\n            })\n            .collect()\n    }\n\n    pub fn hidden_configs() -> &'static HashSet<&'static str> {\n        static HIDDEN_CONFIGS: Lazy<HashSet<&'static str>> =\n            Lazy::new(|| [\"ci\", \"cd\", \"debug\", \"env_file\", \"trace\", \"log_level\"].into());\n        &HIDDEN_CONFIGS\n    }\n\n    pub fn reset(cli_settings: Option<SettingsPartial>) {\n        *CLI_SETTINGS.lock().unwrap() = cli_settings;\n        *BASE_SETTINGS.write().unwrap() = None;\n        // Clear caches that depend on settings and environment\n        crate::config::config_file::config_root::reset();\n    }\n\n    pub fn lockfile_enabled(&self) -> bool {\n        self.lockfile.unwrap_or(true)\n    }\n\n    pub fn ensure_experimental(&self, what: &str) -> Result<()> {\n        if !self.experimental {\n            bail!(\"{what} is experimental. Enable it with `mise settings experimental=true`\");\n        }\n        Ok(())\n    }\n\n    pub fn trusted_config_paths(&self) -> impl Iterator<Item = PathBuf> + '_ {\n        self.trusted_config_paths\n            .iter()\n            .filter(|p| !p.to_string_lossy().is_empty())\n            .map(file::replace_path)\n            .filter_map(|p| p.canonicalize().ok())\n    }\n\n    pub fn global_tools_file(&self) -> PathBuf {\n        env::var_path(\"MISE_GLOBAL_CONFIG_FILE\")\n            .or_else(|| env::var_path(\"MISE_CONFIG_FILE\"))\n            .unwrap_or_else(|| {\n                if self.asdf_compat {\n                    env::HOME.join(&*env::MISE_DEFAULT_TOOL_VERSIONS_FILENAME)\n                } else {\n                    dirs::CONFIG.join(\"config.toml\")\n                }\n            })\n    }\n\n    pub fn env_files(&self) -> Vec<PathBuf> {\n        let mut files = vec![];\n        if let Some(cwd) = &*dirs::CWD\n            && let Some(env_file) = &self.env_file\n        {\n            let env_file = env_file.to_string_lossy().to_string();\n            for p in FindUp::new(cwd, &[env_file]) {\n                files.push(p);\n            }\n        }\n        files.into_iter().rev().collect()\n    }\n\n    pub fn as_dict(&self) -> eyre::Result<toml::Table> {\n        let s = toml::to_string(self)?;\n        let table = toml::from_str(&s)?;\n        Ok(table)\n    }\n\n    pub fn cache_prune_age_duration(&self) -> Option<Duration> {\n        let age = duration::parse_duration(&self.cache_prune_age).unwrap();\n        if age.as_secs() == 0 { None } else { Some(age) }\n    }\n\n    pub fn fetch_remote_versions_timeout(&self) -> Duration {\n        duration::parse_duration(&self.fetch_remote_versions_timeout).unwrap()\n    }\n\n    /// duration that remote version cache is kept for\n    /// for \"fast\" commands (represented by PREFER_OFFLINE), these are always\n    /// cached. For \"slow\" commands like `mise ls-remote` or `mise install`:\n    /// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is set, use that\n    /// - if MISE_FETCH_REMOTE_VERSIONS_CACHE is not set, use HOURLY\n    pub fn fetch_remote_versions_cache(&self) -> Option<Duration> {\n        if self.prefer_offline() {\n            None\n        } else {\n            Some(duration::parse_duration(&self.fetch_remote_versions_cache).unwrap())\n        }\n    }\n\n    pub fn http_timeout(&self) -> Duration {\n        duration::parse_duration(&self.http_timeout).unwrap()\n    }\n\n    /// Returns true if offline mode is enabled via setting or CLI flag/env var.\n    pub fn offline(&self) -> bool {\n        self.offline || *env::OFFLINE\n    }\n\n    /// Returns true if prefer-offline mode is enabled via setting, env var, or\n    /// because the current command is a \"fast\" command (hook-env, activate, etc.).\n    /// Also returns true if offline mode is enabled (offline implies prefer-offline).\n    pub fn prefer_offline(&self) -> bool {\n        self.offline() || self.prefer_offline || env::PREFER_OFFLINE.load(Ordering::Relaxed)\n    }\n\n    pub fn env_cache_ttl(&self) -> Duration {\n        duration::parse_duration(&self.env_cache_ttl).unwrap()\n    }\n\n    pub fn task_timeout_duration(&self) -> Option<Duration> {\n        self.task\n            .timeout\n            .as_ref()\n            .and_then(|s| duration::parse_duration(s).ok())\n    }\n\n    pub fn log_level(&self) -> log::LevelFilter {\n        self.log_level.parse().unwrap_or(log::LevelFilter::Info)\n    }\n\n    pub fn disable_tools(&self) -> BTreeSet<String> {\n        self.disable_tools\n            .iter()\n            .map(|t| t.trim().to_string())\n            .collect()\n    }\n\n    pub fn enable_tools(&self) -> BTreeSet<String> {\n        self.enable_tools\n            .iter()\n            .map(|t| t.trim().to_string())\n            .collect()\n    }\n\n    pub fn partial_as_dict(partial: &SettingsPartial) -> eyre::Result<toml::Table> {\n        let s = toml::to_string(partial)?;\n        let table = toml::from_str(&s)?;\n        Ok(table)\n    }\n\n    pub fn default_inline_shell(&self) -> Result<Vec<String>> {\n        let sa = if cfg!(windows) {\n            &self.windows_default_inline_shell_args\n        } else {\n            &self.unix_default_inline_shell_args\n        };\n        Ok(shell_words::split(sa)?)\n    }\n\n    pub fn default_file_shell(&self) -> Result<Vec<String>> {\n        let sa = if cfg!(windows) {\n            &self.windows_default_file_shell_args\n        } else {\n            &self.unix_default_file_shell_args\n        };\n        Ok(shell_words::split(sa)?)\n    }\n\n    pub fn os(&self) -> &str {\n        match self.os.as_deref().unwrap_or(OS) {\n            \"darwin\" | \"macos\" => \"macos\",\n            \"linux\" => \"linux\",\n            \"windows\" => \"windows\",\n            other => other,\n        }\n    }\n\n    pub fn arch(&self) -> &str {\n        match self.arch.as_deref().unwrap_or(ARCH) {\n            \"x86_64\" | \"amd64\" => \"x64\",\n            \"aarch64\" | \"arm64\" => \"arm64\",\n            other => other,\n        }\n    }\n\n    pub fn no_config() -> bool {\n        *env::MISE_NO_CONFIG\n            || !*crate::env::IS_RUNNING_AS_SHIM\n                && env::ARGS\n                    .read()\n                    .unwrap()\n                    .iter()\n                    .take_while(|a| *a != \"--\")\n                    .any(|a| a == \"--no-config\")\n    }\n\n    pub fn no_env() -> bool {\n        *env::MISE_NO_ENV\n            || !*crate::env::IS_RUNNING_AS_SHIM\n                && env::ARGS\n                    .read()\n                    .unwrap()\n                    .iter()\n                    .take_while(|a| *a != \"--\")\n                    .any(|a| a == \"--no-env\")\n    }\n\n    pub fn no_hooks() -> bool {\n        *env::MISE_NO_HOOKS\n            || !*crate::env::IS_RUNNING_AS_SHIM\n                && env::ARGS\n                    .read()\n                    .unwrap()\n                    .iter()\n                    .take_while(|a| *a != \"--\")\n                    .any(|a| a == \"--no-hooks\")\n    }\n}\n\nimpl Display for Settings {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match toml::to_string_pretty(self) {\n            Ok(s) => write!(f, \"{s}\"),\n            Err(e) => Err(std::fmt::Error::custom(e)),\n        }\n    }\n}\n\npub const DEFAULT_NODE_MIRROR_URL: &str = \"https://nodejs.org/dist/\";\n\nimpl SettingsNode {\n    pub fn mirror_url(&self) -> Url {\n        let s = self\n            .mirror_url\n            .clone()\n            .or(env::var(\"NODE_BUILD_MIRROR_URL\").ok())\n            .unwrap_or_else(|| DEFAULT_NODE_MIRROR_URL.to_string());\n        Url::parse(&s).unwrap()\n    }\n\n    pub fn ninja(&self) -> bool {\n        self.ninja.unwrap_or_else(|| which::which(\"ninja\").is_ok())\n    }\n\n    pub fn concurrency(&self) -> Option<usize> {\n        self.concurrency\n            .map(|c| std::cmp::max(c, 1) as usize)\n            .or_else(|| {\n                if self.ninja() {\n                    None\n                } else {\n                    Some(num_cpus::get_physical())\n                }\n            })\n    }\n\n    pub fn default_packages_file(&self) -> PathBuf {\n        self.default_packages_file\n            .clone()\n            .or_else(|| {\n                env::var(\"NODE_DEFAULT_PACKAGES_FILE\")\n                    .ok()\n                    .map(PathBuf::from)\n            })\n            .unwrap_or_else(|| {\n                let p = env::HOME.join(\".default-nodejs-packages\");\n                if p.exists() {\n                    return p;\n                }\n                let p = env::HOME.join(\".default-node-packages\");\n                if p.exists() {\n                    return p;\n                }\n                env::HOME.join(\".default-npm-packages\")\n            })\n    }\n\n    pub fn cflags(&self) -> Option<String> {\n        self.cflags.clone().or_else(|| env::var(\"NODE_CFLAGS\").ok())\n    }\n\n    pub fn configure_cmd(&self, install_path: &Path) -> String {\n        let mut configure_cmd = format!(\"./configure --prefix={}\", install_path.display());\n        if self.ninja() {\n            configure_cmd.push_str(\" --ninja\");\n        }\n        if let Some(opts) = self\n            .configure_opts\n            .clone()\n            .or_else(|| env::var(\"NODE_CONFIGURE_OPTS\").ok())\n        {\n            configure_cmd.push_str(&format!(\" {opts}\"));\n        }\n        configure_cmd\n    }\n\n    pub fn make_cmd(&self) -> String {\n        let mut make_cmd = self.make.clone().unwrap_or_else(|| \"make\".into());\n        if let Some(concurrency) = self.concurrency() {\n            make_cmd.push_str(&format!(\" -j{concurrency}\"));\n        }\n        if let Some(opts) = self\n            .make_opts\n            .clone()\n            .or_else(|| env::var(\"NODE_MAKE_OPTS\").ok())\n        {\n            make_cmd.push_str(&format!(\" {opts}\"));\n        }\n        make_cmd\n    }\n\n    pub fn make_install_cmd(&self) -> String {\n        let make = self.make.clone().unwrap_or_else(|| \"make\".into());\n        let mut make_install_cmd = format!(\"{} install\", make);\n        if let Some(opts) = self\n            .make_install_opts\n            .clone()\n            .or_else(|| env::var(\"NODE_MAKE_INSTALL_OPTS\").ok())\n        {\n            make_install_cmd.push_str(&format!(\" {opts}\"));\n        }\n        make_install_cmd\n    }\n}\n\nimpl SettingsStatus {\n    pub fn missing_tools(&self) -> SettingsStatusMissingTools {\n        SettingsStatusMissingTools::from_str(&self.missing_tools).unwrap()\n    }\n}\n\n/// Deserialize a string to a boolean, accepting \"false\", \"no\", \"0\"\n/// and their case-insensitive variants as `false`. Any other value (incl. \"\") is considered `true`.\nfn bool_string<'de, D>(deserializer: D) -> Result<bool, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let s = String::deserialize(deserializer)?;\n    match s.to_lowercase().as_str() {\n        \"false\" | \"no\" | \"0\" => Ok(false),\n        _ => Ok(true),\n    }\n}\n\nfn set_by_comma<T, C>(input: &str) -> Result<C, <T as FromStr>::Err>\nwhere\n    T: FromStr + Eq + Ord,\n    C: FromIterator<T>,\n{\n    input\n        .split(',')\n        // Filter out empty strings\n        .filter_map(|s| {\n            let trimmed = s.trim();\n            if !trimmed.is_empty() {\n                Some(T::from_str(trimmed))\n            } else {\n                None\n            }\n        })\n        // collect into BTreeSet to remove duplicates\n        .collect::<Result<BTreeSet<_>, _>>()\n        .map(|set| set.into_iter().collect())\n}\n\n/// Parse URL replacements from JSON string format\n/// Expected format: {\"source_domain\": \"replacement_domain\", ...}\npub fn parse_url_replacements(input: &str) -> Result<IndexMap<String, String>, serde_json::Error> {\n    serde_json::from_str(input)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_set_by_comma_empty_string() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"\");\n        assert!(result.is_ok());\n        assert_eq!(result.unwrap(), BTreeSet::new());\n    }\n\n    #[test]\n    fn test_set_by_comma_whitespace_only() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"  \");\n        assert!(result.is_ok());\n        assert_eq!(result.unwrap(), BTreeSet::new());\n    }\n\n    #[test]\n    fn test_set_by_comma_single_value() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> = [\"foo\".to_string()].into_iter().collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_set_by_comma_multiple_values() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo,bar,baz\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> = [\"foo\".to_string(), \"bar\".to_string(), \"baz\".to_string()]\n            .into_iter()\n            .collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_set_by_comma_with_whitespace() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo, bar, baz\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> = [\"foo\".to_string(), \"bar\".to_string(), \"baz\".to_string()]\n            .into_iter()\n            .collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_set_by_comma_trailing_comma() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo,bar,\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> =\n            [\"foo\".to_string(), \"bar\".to_string()].into_iter().collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_set_by_comma_duplicate_values() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo,bar,foo\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> =\n            [\"foo\".to_string(), \"bar\".to_string()].into_iter().collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_set_by_comma_empty_elements() {\n        let result: Result<BTreeSet<String>, _> = set_by_comma(\"foo,,bar\");\n        assert!(result.is_ok());\n        let expected: BTreeSet<String> =\n            [\"foo\".to_string(), \"bar\".to_string()].into_iter().collect();\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[test]\n    fn test_offline_default_is_false() {\n        Settings::reset(None);\n        let settings = Settings::get();\n        // When neither setting nor env var is set, offline should be false\n        // (env::OFFLINE is process-global so we can't easily toggle it,\n        // but the setting field defaults to false)\n        assert!(!settings.offline);\n    }\n\n    #[test]\n    fn test_prefer_offline_default_is_false() {\n        Settings::reset(None);\n        let settings = Settings::get();\n        assert!(!settings.prefer_offline);\n    }\n\n    #[test]\n    fn test_offline_setting_enables_offline() {\n        let mut partial = SettingsPartial::empty();\n        partial.offline = Some(true);\n        Settings::reset(Some(partial));\n        let settings = Settings::get();\n        assert!(settings.offline());\n        Settings::reset(None);\n    }\n\n    #[test]\n    fn test_offline_implies_prefer_offline() {\n        let mut partial = SettingsPartial::empty();\n        partial.offline = Some(true);\n        Settings::reset(Some(partial));\n        let settings = Settings::get();\n        assert!(settings.prefer_offline());\n        Settings::reset(None);\n    }\n\n    #[test]\n    fn test_prefer_offline_setting() {\n        let mut partial = SettingsPartial::empty();\n        partial.prefer_offline = Some(true);\n        Settings::reset(Some(partial));\n        let settings = Settings::get();\n        assert!(settings.prefer_offline());\n        // prefer_offline does NOT imply offline\n        assert!(!settings.offline);\n        Settings::reset(None);\n    }\n\n    #[test]\n    fn test_settings_toml_is_sorted() {\n        let content =\n            std::fs::read_to_string(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/settings.toml\"))\n                .expect(\"failed to read settings.toml\");\n        let table: toml::Table = content.parse().expect(\"failed to parse settings.toml\");\n\n        fn collect_keys(table: &toml::Table, prefix: &str) -> Vec<String> {\n            let mut keys = Vec::new();\n            for (key, value) in table {\n                let full_key = if prefix.is_empty() {\n                    key.clone()\n                } else {\n                    format!(\"{prefix}.{key}\")\n                };\n                if let toml::Value::Table(sub) = value {\n                    // A nested table that has no \"type\" or \"description\" is a grouping table\n                    // (e.g., [aqua], [node]), not a setting itself.\n                    if !sub.contains_key(\"type\") && !sub.contains_key(\"description\") {\n                        keys.extend(collect_keys(sub, &full_key));\n                        continue;\n                    }\n                }\n                keys.push(full_key);\n            }\n            keys\n        }\n\n        let keys = collect_keys(&table, \"\");\n        let mut sorted = keys.clone();\n        sorted.sort();\n\n        for (i, (got, expected)) in keys.iter().zip(sorted.iter()).enumerate() {\n            assert_eq!(\n                got, expected,\n                \"settings.toml is not alphabetically sorted at index {i}: found \\\"{got}\\\", expected \\\"{expected}\\\". Run the sort script or reorder manually.\"\n            );\n        }\n    }\n\n    #[test]\n    fn test_settings_node_build_cmds() {\n        let node = SettingsNode::default();\n        let path = Path::new(\"/tmp/install\");\n\n        // Defaults\n        assert!(\n            node.configure_cmd(path)\n                .starts_with(\"./configure --prefix=/tmp/install\")\n        );\n        assert!(node.make_cmd().starts_with(\"make\"));\n        assert_eq!(node.make_install_cmd(), \"make install\");\n    }\n\n    #[test]\n    fn test_settings_node_build_cmds_with_opts() {\n        let node = SettingsNode {\n            configure_opts: Some(\"--verbose\".to_string()),\n            make_opts: Some(\"-s\".to_string()),\n            make_install_opts: Some(\"--no-strip\".to_string()),\n            make: Some(\"gmake\".to_string()),\n            concurrency: Some(4),\n            ..Default::default()\n        };\n\n        let path = Path::new(\"/tmp/install\");\n        assert!(node.configure_cmd(path).contains(\"--verbose\"));\n        assert!(node.make_cmd().starts_with(\"gmake -j4 -s\"));\n        assert_eq!(node.make_install_cmd(), \"gmake install --no-strip\");\n    }\n}\n"
  },
  {
    "path": "src/config/tracking.rs",
    "content": "use std::fs;\nuse std::fs::{read_dir, remove_file};\nuse std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::dirs::TRACKED_CONFIGS;\nuse crate::file::{create_dir_all, make_symlink_or_file};\nuse crate::hash::hash_to_str;\n\npub struct Tracker {}\n\nimpl Tracker {\n    pub fn track(path: &Path) -> Result<()> {\n        let tracking_path = TRACKED_CONFIGS.join(hash_to_str(&path));\n        if !tracking_path.exists() {\n            create_dir_all(&*TRACKED_CONFIGS)?;\n            make_symlink_or_file(path, &tracking_path)?;\n        }\n        Ok(())\n    }\n\n    pub fn list_all() -> Result<Vec<PathBuf>> {\n        let mut output = vec![];\n        if !TRACKED_CONFIGS.exists() {\n            return Ok(output);\n        }\n        for path in read_dir(&*TRACKED_CONFIGS)? {\n            let mut path = path?.path();\n            if path.is_symlink() {\n                path = fs::read_link(path)?;\n            } else if cfg!(target_os = \"windows\") {\n                path = PathBuf::from(fs::read_to_string(&path)?.trim());\n            } else {\n                continue;\n            }\n            if path.exists() {\n                output.push(path);\n            }\n        }\n        Ok(output)\n    }\n\n    pub fn clean() -> Result<()> {\n        if TRACKED_CONFIGS.is_dir() {\n            for path in read_dir(&*TRACKED_CONFIGS)? {\n                let path = path?.path();\n                if !path.exists() {\n                    remove_file(&path)?;\n                }\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/deps_graph.rs",
    "content": "use std::collections::{HashMap, HashSet};\nuse std::fmt;\nuse std::hash::Hash;\n\nuse eyre::{Result, bail};\nuse indexmap::IndexSet;\nuse petgraph::Direction;\nuse petgraph::algo::is_cyclic_directed;\nuse petgraph::stable_graph::{NodeIndex, StableGraph};\nuse tokio::sync::mpsc;\n\n/// Generic dependency graph scheduler using Kahn's algorithm.\n///\n/// Emits nodes that are ready to process (all dependencies satisfied)\n/// via an mpsc channel. Supports success/failure completion with\n/// transitive dependency blocking and cycle detection.\n///\n/// Type parameters:\n/// - `K`: Key type for identifying nodes\n/// - `N`: Node value type stored in the graph\n#[derive(Debug)]\npub struct DepsGraph<K, N>\nwhere\n    K: Hash + Eq + Clone + fmt::Display,\n    N: Clone + fmt::Debug,\n{\n    graph: StableGraph<N, ()>,\n    node_indices: HashMap<K, NodeIndex>,\n    sent: HashSet<K>,\n    blocked: HashSet<K>,\n    tx: mpsc::UnboundedSender<Option<N>>,\n    key_fn: fn(&N) -> K,\n}\n\nimpl<K, N> DepsGraph<K, N>\nwhere\n    K: Hash + Eq + Clone + fmt::Display,\n    N: Clone + fmt::Debug,\n{\n    /// Create a new DepsGraph.\n    ///\n    /// - `nodes`: Iterator of (key, node) pairs to add to the graph\n    /// - `edges`: Iterator of (from_key, to_key) pairs meaning \"from depends on to\"\n    /// - `key_fn`: Function to extract a key from a node value\n    pub fn new(\n        nodes: impl IntoIterator<Item = (K, N)>,\n        edges: impl IntoIterator<Item = (K, K)>,\n        key_fn: fn(&N) -> K,\n    ) -> Result<Self> {\n        let mut graph = StableGraph::new();\n        let mut node_indices = HashMap::new();\n\n        for (key, node) in nodes {\n            if node_indices.contains_key(&key) {\n                continue;\n            }\n            let idx = graph.add_node(node);\n            node_indices.insert(key, idx);\n        }\n\n        for (from_key, to_key) in edges {\n            let Some(&from_idx) = node_indices.get(&from_key) else {\n                continue;\n            };\n            let Some(&to_idx) = node_indices.get(&to_key) else {\n                bail!(\"'{}' depends on unknown '{}'\", from_key, to_key);\n            };\n            if from_key != to_key {\n                graph.update_edge(from_idx, to_idx, ());\n            }\n        }\n\n        let (tx, _) = mpsc::unbounded_channel();\n\n        let mut deps = Self {\n            graph,\n            node_indices,\n            sent: HashSet::new(),\n            blocked: HashSet::new(),\n            tx,\n            key_fn,\n        };\n\n        deps.detect_and_block_cycles();\n\n        Ok(deps)\n    }\n\n    /// Subscribe to receive nodes that are ready to process.\n    /// Returns a receiver that emits `Some(node)` for each ready node,\n    /// followed by `None` when all nodes have been processed.\n    pub fn subscribe(&mut self) -> mpsc::UnboundedReceiver<Option<N>> {\n        let (tx, rx) = mpsc::unbounded_channel();\n        self.tx = tx;\n        self.emit_leaves();\n        rx\n    }\n\n    /// Mark a node as successfully completed and emit any newly-ready nodes.\n    pub fn complete_success(&mut self, key: &K) {\n        self.remove_node(key);\n        self.emit_leaves();\n    }\n\n    /// Mark a node as failed and block all transitive dependents.\n    pub fn complete_failure(&mut self, key: &K) {\n        if let Some(&idx) = self.node_indices.get(key) {\n            let dependents = self.get_transitive_dependents(idx);\n            for dep_idx in dependents {\n                if let Some(dep_node) = self.graph.node_weight(dep_idx) {\n                    let dep_key = (self.key_fn)(dep_node);\n                    self.blocked.insert(dep_key);\n                }\n            }\n        }\n\n        self.remove_node(key);\n        self.emit_leaves();\n    }\n\n    /// Returns whether all nodes have been processed.\n    pub fn is_empty(&self) -> bool {\n        self.graph.node_count() == 0\n    }\n\n    /// Returns the keys of all blocked nodes (dependency failures or cycles).\n    pub fn blocked_keys(&self) -> Vec<K> {\n        self.graph\n            .node_indices()\n            .filter_map(|idx| {\n                let node = self.graph.node_weight(idx)?;\n                let key = (self.key_fn)(node);\n                if self.blocked.contains(&key) {\n                    Some(key)\n                } else {\n                    None\n                }\n            })\n            .collect()\n    }\n\n    /// Returns the node values that are blocked.\n    pub fn blocked_nodes(&self) -> Vec<N> {\n        self.graph\n            .node_indices()\n            .filter_map(|idx| {\n                let node = self.graph.node_weight(idx)?;\n                let key = (self.key_fn)(node);\n                if self.blocked.contains(&key) {\n                    Some(node.clone())\n                } else {\n                    None\n                }\n            })\n            .collect()\n    }\n\n    /// Detect cycles and mark all nodes in cycles as blocked.\n    fn detect_and_block_cycles(&mut self) {\n        if !is_cyclic_directed(&self.graph) {\n            return;\n        }\n\n        let mut can_reach_leaf: HashSet<NodeIndex> = HashSet::new();\n\n        // Start with all leaf nodes (no outgoing edges = no dependencies)\n        for idx in self.graph.node_indices() {\n            if self\n                .graph\n                .neighbors_directed(idx, Direction::Outgoing)\n                .next()\n                .is_none()\n            {\n                can_reach_leaf.insert(idx);\n            }\n        }\n\n        // Propagate backwards: if all dependencies of a node can reach a leaf,\n        // then it can also reach a leaf\n        let mut changed = true;\n        while changed {\n            changed = false;\n            for idx in self.graph.node_indices() {\n                if can_reach_leaf.contains(&idx) {\n                    continue;\n                }\n                let deps_can_reach = self\n                    .graph\n                    .neighbors_directed(idx, Direction::Outgoing)\n                    .all(|dep_idx| can_reach_leaf.contains(&dep_idx));\n                if deps_can_reach\n                    && self\n                        .graph\n                        .neighbors_directed(idx, Direction::Outgoing)\n                        .next()\n                        .is_some()\n                {\n                    can_reach_leaf.insert(idx);\n                    changed = true;\n                }\n            }\n        }\n\n        // Any node that cannot reach a leaf is in a cycle\n        for idx in self.graph.node_indices() {\n            if !can_reach_leaf.contains(&idx)\n                && let Some(node) = self.graph.node_weight(idx)\n            {\n                let key = (self.key_fn)(node);\n                self.blocked.insert(key);\n            }\n        }\n    }\n\n    /// Emit all nodes that have no remaining dependencies (leaf nodes).\n    fn emit_leaves(&mut self) {\n        let leaves = self.find_leaves();\n\n        for (key, node) in leaves {\n            if self.sent.contains(&key) || self.blocked.contains(&key) {\n                continue;\n            }\n\n            if self.sent.insert(key.clone()) {\n                trace!(\"Scheduling: {}\", key);\n                if let Err(e) = self.tx.send(Some(node)) {\n                    trace!(\"Error sending node: {e:?}\");\n                }\n            }\n        }\n\n        if self.is_all_done() {\n            trace!(\"All nodes finished\");\n            if let Err(e) = self.tx.send(None) {\n                trace!(\"Error closing stream: {e:?}\");\n            }\n        }\n    }\n\n    /// Find all leaf nodes (no unsatisfied dependencies).\n    fn find_leaves(&self) -> Vec<(K, N)> {\n        self.graph\n            .externals(Direction::Outgoing)\n            .filter_map(|idx| {\n                let node = self.graph.node_weight(idx)?;\n                Some(((self.key_fn)(node), node.clone()))\n            })\n            .collect()\n    }\n\n    /// Check if all nodes have been processed (sent, completed, or blocked).\n    fn is_all_done(&self) -> bool {\n        if self.is_empty() {\n            return true;\n        }\n\n        self.graph.node_indices().all(|idx| {\n            self.graph\n                .node_weight(idx)\n                .map(|node| self.blocked.contains(&(self.key_fn)(node)))\n                .unwrap_or(true)\n        })\n    }\n\n    /// Remove a node from the graph by its key.\n    fn remove_node(&mut self, key: &K) {\n        if let Some(&idx) = self.node_indices.get(key) {\n            self.graph.remove_node(idx);\n            self.node_indices.remove(key);\n        }\n    }\n\n    /// Get all transitive dependents of a node (nodes that depend on this one).\n    fn get_transitive_dependents(&self, start_idx: NodeIndex) -> IndexSet<NodeIndex> {\n        let mut dependents = IndexSet::new();\n        let mut stack = vec![start_idx];\n\n        while let Some(idx) = stack.pop() {\n            for neighbor in self.graph.neighbors_directed(idx, Direction::Incoming) {\n                if dependents.insert(neighbor) {\n                    stack.push(neighbor);\n                }\n            }\n        }\n\n        dependents\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[allow(clippy::ptr_arg)]\n    fn string_key(s: &String) -> String {\n        s.clone()\n    }\n\n    #[test]\n    fn test_empty_graph() {\n        let deps: DepsGraph<String, String> =\n            DepsGraph::new(vec![], Vec::<(String, String)>::new(), string_key).unwrap();\n        assert!(deps.is_empty());\n    }\n\n    #[test]\n    fn test_no_deps_all_ready() {\n        let nodes = vec![\n            (\"a\".into(), \"a\".into()),\n            (\"b\".into(), \"b\".into()),\n            (\"c\".into(), \"c\".into()),\n        ];\n        let mut deps: DepsGraph<String, String> =\n            DepsGraph::new(nodes, Vec::<(String, String)>::new(), string_key).unwrap();\n        let mut rx = deps.subscribe();\n\n        let mut emitted = vec![];\n        while let Ok(Some(id)) = rx.try_recv() {\n            emitted.push(id);\n        }\n        assert_eq!(emitted.len(), 3);\n    }\n\n    #[test]\n    fn test_linear_ordering() {\n        let nodes: Vec<(String, String)> = vec![\n            (\"a\".into(), \"a\".into()),\n            (\"b\".into(), \"b\".into()),\n            (\"c\".into(), \"c\".into()),\n        ];\n        let edges: Vec<(String, String)> = vec![(\"b\".into(), \"a\".into()), (\"c\".into(), \"b\".into())];\n        let mut deps = DepsGraph::new(nodes, edges, string_key).unwrap();\n        let mut rx = deps.subscribe();\n\n        let first = rx.try_recv().unwrap().unwrap();\n        assert_eq!(first, \"a\");\n        assert!(rx.try_recv().is_err());\n\n        deps.complete_success(&\"a\".into());\n        let second = rx.try_recv().unwrap().unwrap();\n        assert_eq!(second, \"b\");\n\n        deps.complete_success(&\"b\".into());\n        let third = rx.try_recv().unwrap().unwrap();\n        assert_eq!(third, \"c\");\n\n        deps.complete_success(&\"c\".into());\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_failure_blocks_dependents() {\n        let nodes: Vec<(String, String)> = vec![\n            (\"a\".into(), \"a\".into()),\n            (\"b\".into(), \"b\".into()),\n            (\"c\".into(), \"c\".into()),\n            (\"d\".into(), \"d\".into()),\n        ];\n        let edges: Vec<(String, String)> = vec![(\"b\".into(), \"a\".into()), (\"c\".into(), \"b\".into())];\n        let mut deps = DepsGraph::new(nodes, edges, string_key).unwrap();\n        let mut rx = deps.subscribe();\n\n        let mut initial = vec![];\n        while let Ok(Some(id)) = rx.try_recv() {\n            initial.push(id);\n        }\n        assert_eq!(initial.len(), 2);\n        assert!(initial.contains(&\"a\".to_string()));\n        assert!(initial.contains(&\"d\".to_string()));\n\n        deps.complete_failure(&\"a\".into());\n        let blocked = deps.blocked_keys();\n        assert!(blocked.contains(&\"b\".to_string()));\n        assert!(blocked.contains(&\"c\".to_string()));\n\n        deps.complete_success(&\"d\".into());\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_cycle_detection() {\n        let nodes: Vec<(String, String)> = vec![\n            (\"a\".into(), \"a\".into()),\n            (\"b\".into(), \"b\".into()),\n            (\"c\".into(), \"c\".into()),\n        ];\n        let edges: Vec<(String, String)> = vec![(\"a\".into(), \"b\".into()), (\"b\".into(), \"a\".into())];\n        let mut deps = DepsGraph::new(nodes, edges, string_key).unwrap();\n\n        let blocked = deps.blocked_keys();\n        assert!(blocked.contains(&\"a\".to_string()));\n        assert!(blocked.contains(&\"b\".to_string()));\n\n        let mut rx = deps.subscribe();\n        let first = rx.try_recv().unwrap().unwrap();\n        assert_eq!(first, \"c\");\n\n        deps.complete_success(&\"c\".into());\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_unknown_dep_error() {\n        let nodes: Vec<(String, String)> = vec![(\"a\".into(), \"a\".into())];\n        let edges: Vec<(String, String)> = vec![(\"a\".into(), \"nonexistent\".into())];\n        let result = DepsGraph::new(nodes, edges, string_key);\n        assert!(result.is_err());\n        assert!(result.unwrap_err().to_string().contains(\"unknown\"));\n    }\n}\n"
  },
  {
    "path": "src/direnv.rs",
    "content": "use std::collections::HashMap;\nuse std::env::{join_paths, split_paths};\nuse std::fmt::{Display, Formatter};\nuse std::io::Write;\nuse std::path::{Path, PathBuf};\n\nuse crate::env::PATH_KEY;\nuse base64::prelude::*;\nuse eyre::Result;\nuse flate2::Compression;\nuse flate2::write::{ZlibDecoder, ZlibEncoder};\nuse itertools::Itertools;\nuse serde_derive::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct DirenvDiff {\n    #[serde(default, rename = \"p\")]\n    pub old: HashMap<String, String>,\n    #[serde(default, rename = \"n\")]\n    pub new: HashMap<String, String>,\n}\n\nimpl DirenvDiff {\n    pub fn parse(input: &str) -> Result<DirenvDiff> {\n        // let bytes = BASE64_URL_SAFE.decode(input)?;\n        // let uncompressed = inflate_bytes_zlib(&bytes).unwrap();\n        // Ok(serde_json::from_slice(&uncompressed[..])?)\n        let mut writer = Vec::new();\n        let mut decoder = ZlibDecoder::new(writer);\n        let bytes = BASE64_URL_SAFE.decode(input)?;\n        decoder.write_all(&bytes[..])?;\n        writer = decoder.finish()?;\n        Ok(serde_json::from_slice(&writer[..])?)\n    }\n\n    pub fn new_path(&self) -> Vec<PathBuf> {\n        let path = self.new.get(&*PATH_KEY);\n        match path {\n            Some(path) => split_paths(path).collect(),\n            None => vec![],\n        }\n    }\n\n    pub fn old_path(&self) -> Vec<PathBuf> {\n        let path = self.old.get(&*PATH_KEY);\n        match path {\n            Some(path) => split_paths(path).collect(),\n            None => vec![],\n        }\n    }\n\n    /// this adds a directory to both the old and new path in DIRENV_DIFF\n    /// the purpose is to trick direnv into thinking that this path has always been there\n    /// that way it does not remove it when it modifies PATH\n    /// it returns the old and new paths as vectors\n    pub fn add_path_to_old_and_new(&mut self, path: &Path) -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {\n        let mut old = self.old_path();\n        let mut new = self.new_path();\n\n        old.insert(0, path.into());\n        new.insert(0, path.into());\n\n        self.old.insert(\n            PATH_KEY.to_string(),\n            join_paths(&old)?.into_string().unwrap(),\n        );\n        self.new.insert(\n            PATH_KEY.to_string(),\n            join_paths(&new)?.into_string().unwrap(),\n        );\n\n        Ok((old, new))\n    }\n\n    pub fn remove_path_from_old_and_new(\n        &mut self,\n        path: &Path,\n    ) -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {\n        let mut old = self.old_path();\n        let mut new = self.new_path();\n\n        // remove the path from both old and new but only once\n        old.iter().position(|p| p == path).map(|i| old.remove(i));\n        new.iter().position(|p| p == path).map(|i| new.remove(i));\n\n        self.old.insert(\n            PATH_KEY.to_string(),\n            join_paths(&old)?.into_string().unwrap(),\n        );\n        self.new.insert(\n            PATH_KEY.to_string(),\n            join_paths(&new)?.into_string().unwrap(),\n        );\n\n        Ok((old, new))\n    }\n\n    pub fn dump(&self) -> Result<String> {\n        let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast());\n        gz.write_all(&serde_json::to_vec(self)?)?;\n        Ok(BASE64_URL_SAFE.encode(gz.finish()?))\n    }\n}\n\nimpl Display for DirenvDiff {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let print_sorted = |hashmap: &HashMap<String, String>| {\n            hashmap\n                .iter()\n                .map(|(k, v)| format!(\"{k}={v}\"))\n                .sorted()\n                .collect::<Vec<_>>()\n        };\n        f.debug_struct(\"DirenvDiff\")\n            .field(\"old\", &print_sorted(&self.old))\n            .field(\"new\", &print_sorted(&self.new))\n            .finish()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n    use insta::assert_snapshot;\n\n    #[tokio::test]\n    async fn test_parse() {\n        let _config = Config::get().await.unwrap();\n        let input = r#\"eJys0c1yojAAwPF3ybmWaLB-zPSAGCqIQCGgeGGIELDlM2BEOr77zs7szr7AXv-H3-X_Axqw_gGabYM1qPk1A88XUP1OW93FVhBtdReswURq-FXEfSqJmEusLpKUdxLspALRJY1Yt2Bifk8aLhf5iiZIhhDCjEtE6svmteGuSJVHAV7-qppuYrAG_0WVXtNK8Ms__KgQdYc9sAapMXRj1-9XW8VX7A16UA4NPIs9xCK5WO51XnvfwWBT1R9N7zIcHvvJbZF5g8pk0V2c5CboIw8_NjOUWDK5qcxIcaFrp3anhwdr5FeKJmfd9stgqvuVZqcXsXHYJ-kSGWpoxyZLzf0a0LUcMgv17exenXXunfOTZZfybiVmb9OAhjDtHEcOk0lrRWG84OrRobW6IgGGZqwelglTq8UmJrbP9p0x9pTW5t3L21P1mZfL7_pMtIW599v-Cx_dmzEdCcZ1TAzkz7dvfO4QAefO6Y4VxYmijzgP_Oz9Hbz8uU5jDp7PXwEAAP__wB6qKg==\"#;\n        let diff = DirenvDiff::parse(input).unwrap();\n        assert_snapshot!(diff);\n    }\n\n    #[tokio::test]\n    async fn test_dump() {\n        let _config = Config::get().await.unwrap();\n        let diff = DirenvDiff {\n            old: HashMap::from([(\"a\".to_string(), \"b\".to_string())]),\n            new: HashMap::from([(\"c\".to_string(), \"d\".to_string())]),\n        };\n        let output = diff.dump().unwrap();\n        assert_snapshot!(&output);\n        let diff = DirenvDiff::parse(&output).unwrap();\n        assert_snapshot!(diff);\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_add_path_to_old_and_new() {\n        let _config = Config::get().await.unwrap();\n        let mut diff = DirenvDiff {\n            old: HashMap::from([(\"PATH\".to_string(), \"/foo:/tmp:/bar:/old\".to_string())]),\n            new: HashMap::from([(\"PATH\".to_string(), \"/foo:/bar:/new\".to_string())]),\n        };\n        let path = PathBuf::from(\"/tmp\");\n        diff.add_path_to_old_and_new(&path).unwrap();\n        assert_snapshot!(diff.old.get(\"PATH\").unwrap());\n        assert_snapshot!(diff.new.get(\"PATH\").unwrap());\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_null_path() {\n        let _config = Config::get().await.unwrap();\n        let mut diff = DirenvDiff {\n            old: HashMap::from([]),\n            new: HashMap::from([]),\n        };\n        let path = PathBuf::from(\"/tmp\");\n        diff.add_path_to_old_and_new(&path).unwrap();\n        assert_snapshot!(diff.old.get(\"PATH\").unwrap());\n        assert_snapshot!(diff.new.get(\"PATH\").unwrap());\n    }\n}\n"
  },
  {
    "path": "src/dirs.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse std::sync::LazyLock as Lazy;\n\nuse crate::env;\n\npub static HOME: Lazy<&Path> = Lazy::new(|| &env::HOME);\npub static CWD: Lazy<Option<PathBuf>> = Lazy::new(|| env::current_dir().ok());\npub static DATA: Lazy<&Path> = Lazy::new(|| &env::MISE_DATA_DIR);\npub static CACHE: Lazy<&Path> = Lazy::new(|| &env::MISE_CACHE_DIR);\npub static CONFIG: Lazy<&Path> = Lazy::new(|| &env::MISE_CONFIG_DIR);\npub static STATE: Lazy<&Path> = Lazy::new(|| &env::MISE_STATE_DIR);\npub static SYSTEM_CONFIG: Lazy<&Path> = Lazy::new(|| &env::MISE_SYSTEM_CONFIG_DIR);\n\npub static PLUGINS: Lazy<&Path> = Lazy::new(|| &env::MISE_PLUGINS_DIR);\npub static DOWNLOADS: Lazy<&Path> = Lazy::new(|| &env::MISE_DOWNLOADS_DIR);\npub static INSTALLS: Lazy<&Path> = Lazy::new(|| &env::MISE_INSTALLS_DIR);\npub static SHIMS: Lazy<&Path> = Lazy::new(|| &env::MISE_SHIMS_DIR);\n\npub static TRACKED_CONFIGS: Lazy<PathBuf> = Lazy::new(|| STATE.join(\"tracked-configs\"));\npub static TRUSTED_CONFIGS: Lazy<PathBuf> = Lazy::new(|| STATE.join(\"trusted-configs\"));\npub static IGNORED_CONFIGS: Lazy<PathBuf> = Lazy::new(|| STATE.join(\"ignored-configs\"));\n"
  },
  {
    "path": "src/duration.rs",
    "content": "pub use std::time::Duration;\n\nuse eyre::{Result, bail};\nuse jiff::{Span, Timestamp, Zoned, civil::date};\n\npub const HOURLY: Duration = Duration::from_secs(60 * 60);\npub const DAILY: Duration = Duration::from_secs(60 * 60 * 24);\npub const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7);\n\npub fn parse_duration(s: &str) -> Result<Duration> {\n    match s.parse::<Span>() {\n        Ok(span) => {\n            // we must provide a relative date to determine the duration with months and years\n            let duration = span.to_duration(date(2025, 1, 1))?;\n            if duration.is_negative() {\n                bail!(\"duration must not be negative: {}\", s);\n            }\n            Ok(duration.unsigned_abs())\n        }\n        Err(_) => Ok(Duration::from_secs(s.parse()?)),\n    }\n}\n\n/// Parse a date/duration string into a Timestamp.\n/// Supports:\n/// - RFC3339 timestamps: \"2024-06-01T12:00:00Z\"\n/// - ISO dates: \"2024-06-01\" (treated as end of day in UTC)\n/// - Relative durations: \"90d\", \"1y\", \"6m\" (subtracted from now)\npub fn parse_into_timestamp(s: &str) -> Result<Timestamp> {\n    // Try RFC3339 timestamp first\n    if let Ok(ts) = s.parse::<Timestamp>() {\n        return Ok(ts);\n    }\n\n    // Try parsing as a Zoned datetime (handles various formats)\n    if let Ok(zoned) = s.parse::<Zoned>() {\n        return Ok(zoned.timestamp());\n    }\n\n    // Try parsing as date only (YYYY-MM-DD) - use end of day UTC\n    if let Ok(civil_date) = s.parse::<jiff::civil::Date>() {\n        let datetime = civil_date.at(23, 59, 59, 0);\n        let ts = datetime.to_zoned(jiff::tz::TimeZone::UTC)?.timestamp();\n        return Ok(ts);\n    }\n\n    // Try parsing as duration and subtract from now\n    if let Ok(span) = s.parse::<Span>() {\n        // Validate that duration is positive (negative would result in future date)\n        let duration = span.to_duration(date(2025, 1, 1))?;\n        if duration.is_negative() {\n            bail!(\"duration must not be negative: {}\", s);\n        }\n        let now = Timestamp::now();\n        // Convert to Zoned to support calendar units (days, months, years)\n        let now_zoned = now.to_zoned(jiff::tz::TimeZone::UTC);\n        let past = now_zoned.checked_sub(span)?;\n        return Ok(past.timestamp());\n    }\n\n    bail!(\n        \"Invalid date or duration: {s}. Expected formats: '2024-06-01', '2024-06-01T12:00:00Z', '90d', '1y'\"\n    )\n}\n"
  },
  {
    "path": "src/env.rs",
    "content": "use crate::Result;\nuse crate::config::miserc;\nuse crate::env_diff::{EnvDiff, EnvDiffOperation, EnvDiffPatches, EnvMap};\nuse crate::file::replace_path;\nuse crate::shell::ShellType;\nuse crate::{cli::args::ToolArg, file::display_path};\nuse eyre::Context;\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse log::LevelFilter;\npub use std::env::*;\nuse std::sync::LazyLock as Lazy;\nuse std::sync::RwLock;\nuse std::{\n    collections::{HashMap, HashSet},\n    ffi::OsStr,\n    sync::Mutex,\n};\nuse std::{path, process};\nuse std::{path::Path, string::ToString};\nuse std::{path::PathBuf, sync::atomic::AtomicBool};\n\npub static ARGS: RwLock<Vec<String>> = RwLock::new(vec![]);\npub static TOOL_ARGS: RwLock<Vec<ToolArg>> = RwLock::new(vec![]);\n#[cfg(unix)]\npub static SHELL: Lazy<String> = Lazy::new(|| var(\"SHELL\").unwrap_or_else(|_| \"sh\".into()));\n#[cfg(windows)]\npub static SHELL: Lazy<String> = Lazy::new(|| var(\"COMSPEC\").unwrap_or_else(|_| \"cmd.exe\".into()));\npub static MISE_SHELL: Lazy<Option<ShellType>> = Lazy::new(|| {\n    var(\"MISE_SHELL\")\n        .unwrap_or_else(|_| SHELL.clone())\n        .parse()\n        .ok()\n});\n#[cfg(unix)]\npub static SHELL_COMMAND_FLAG: &str = \"-c\";\n#[cfg(windows)]\npub static SHELL_COMMAND_FLAG: &str = \"/c\";\n\n// paths and directories\n#[cfg(test)]\npub static HOME: Lazy<PathBuf> =\n    Lazy::new(|| PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"test\"));\n#[cfg(not(test))]\npub static HOME: Lazy<PathBuf> = Lazy::new(|| {\n    homedir::my_home()\n        .ok()\n        .flatten()\n        .unwrap_or_else(|| PathBuf::from(\"/\"))\n});\n\npub static EDITOR: Lazy<String> =\n    Lazy::new(|| var(\"VISUAL\").unwrap_or_else(|_| var(\"EDITOR\").unwrap_or_else(|_| \"nano\".into())));\n\n#[cfg(macos)]\npub static XDG_CACHE_HOME: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"XDG_CACHE_HOME\").unwrap_or_else(|| HOME.join(\"Library/Caches\")));\n#[cfg(windows)]\npub static XDG_CACHE_HOME: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"XDG_CACHE_HOME\")\n        .or_else(|| var_path(\"TEMP\"))\n        .unwrap_or_else(temp_dir)\n});\n#[cfg(all(not(windows), not(macos)))]\npub static XDG_CACHE_HOME: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"XDG_CACHE_HOME\").unwrap_or_else(|| HOME.join(\".cache\")));\npub static XDG_CONFIG_HOME: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"XDG_CONFIG_HOME\").unwrap_or_else(|| HOME.join(\".config\")));\n#[cfg(unix)]\npub static XDG_DATA_HOME: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"XDG_DATA_HOME\").unwrap_or_else(|| HOME.join(\".local\").join(\"share\")));\n#[cfg(windows)]\npub static XDG_DATA_HOME: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"XDG_DATA_HOME\")\n        .or(var_path(\"LOCALAPPDATA\"))\n        .unwrap_or_else(|| HOME.join(\"AppData/Local\"))\n});\npub static XDG_STATE_HOME: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"XDG_STATE_HOME\").unwrap_or_else(|| HOME.join(\".local\").join(\"state\")));\n\n/// control display of \"friendly\" errors - defaults to release mode behavior unless overridden\npub static MISE_FRIENDLY_ERROR: Lazy<bool> = Lazy::new(|| {\n    if var_is_true(\"MISE_FRIENDLY_ERROR\") {\n        true\n    } else if var_is_false(\"MISE_FRIENDLY_ERROR\") {\n        false\n    } else {\n        // default behavior: friendly in release mode unless debug logging\n        !cfg!(debug_assertions) && log::max_level() < log::LevelFilter::Debug\n    }\n});\npub static MISE_TOOL_STUB: Lazy<bool> =\n    Lazy::new(|| ARGS.read().unwrap().get(1).map(|s| s.as_str()) == Some(\"tool-stub\"));\npub static MISE_NO_CONFIG: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_NO_CONFIG\"));\npub static MISE_NO_ENV: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_NO_ENV\"));\npub static MISE_NO_HOOKS: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_NO_HOOKS\"));\npub static MISE_PROGRESS_TRACE: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_PROGRESS_TRACE\"));\npub static MISE_CACHE_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_CACHE_DIR\").unwrap_or_else(|| XDG_CACHE_HOME.join(\"mise\")));\npub static MISE_CONFIG_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_CONFIG_DIR\").unwrap_or_else(|| XDG_CONFIG_HOME.join(\"mise\")));\n/// The default config directory location (XDG_CONFIG_HOME/mise), used to filter out\n/// configs from this location when MISE_CONFIG_DIR is set to a different path\npub static MISE_DEFAULT_CONFIG_DIR: Lazy<PathBuf> = Lazy::new(|| XDG_CONFIG_HOME.join(\"mise\"));\n/// True if MISE_CONFIG_DIR was explicitly set to a non-default location\npub static MISE_CONFIG_DIR_OVERRIDDEN: Lazy<bool> = Lazy::new(|| {\n    var_path(\"MISE_CONFIG_DIR\").is_some() && *MISE_CONFIG_DIR != *MISE_DEFAULT_CONFIG_DIR\n});\npub static MISE_DATA_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_DATA_DIR\").unwrap_or_else(|| XDG_DATA_HOME.join(\"mise\")));\npub static MISE_STATE_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_STATE_DIR\").unwrap_or_else(|| XDG_STATE_HOME.join(\"mise\")));\npub static MISE_TMP_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_TMP_DIR\").unwrap_or_else(|| temp_dir().join(\"mise\")));\npub static MISE_SYSTEM_CONFIG_DIR: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"MISE_SYSTEM_CONFIG_DIR\")\n        .or_else(|| var_path(\"MISE_SYSTEM_DIR\"))\n        .unwrap_or_else(|| PathBuf::from(\"/etc/mise\"))\n});\n\n// data subdirs\npub static MISE_INSTALLS_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_INSTALLS_DIR\").unwrap_or_else(|| MISE_DATA_DIR.join(\"installs\")));\npub static MISE_DOWNLOADS_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_DOWNLOADS_DIR\").unwrap_or_else(|| MISE_DATA_DIR.join(\"downloads\")));\npub static MISE_PLUGINS_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_PLUGINS_DIR\").unwrap_or_else(|| MISE_DATA_DIR.join(\"plugins\")));\npub static MISE_SHIMS_DIR: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_SHIMS_DIR\").unwrap_or_else(|| MISE_DATA_DIR.join(\"shims\")));\n/// System-level data directory (like MISE_DATA_DIR but for system-wide tools).\npub static MISE_SYSTEM_DATA_DIR: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"MISE_SYSTEM_DATA_DIR\").unwrap_or_else(|| PathBuf::from(\"/usr/local/share/mise\"))\n});\n/// System-level installs directory, derived from MISE_SYSTEM_DATA_DIR.\npub static MISE_SYSTEM_INSTALLS_DIR: Lazy<PathBuf> =\n    Lazy::new(|| MISE_SYSTEM_DATA_DIR.join(\"installs\"));\n\n/// Extra shared install directories parsed from the environment variable.\n/// This is the early/fallback source; prefer `shared_install_dirs()` which also\n/// reads from Settings (config files) when available.\nstatic MISE_SHARED_INSTALL_DIRS_ENV: Lazy<Vec<PathBuf>> = Lazy::new(|| {\n    var_os(\"MISE_SHARED_INSTALL_DIRS\")\n        .map(|v| {\n            std::env::split_paths(&v)\n                .filter(|p| !p.as_os_str().is_empty())\n                .map(replace_path)\n                .collect()\n        })\n        .unwrap_or_default()\n});\n\n/// Returns the list of shared install directories to search.\n/// Includes the system installs dir (`MISE_SYSTEM_DATA_DIR/installs`) plus any\n/// user-configured dirs from Settings (config files) or the environment variable.\n/// The user's primary install dir is NOT included here — it is checked separately.\npub fn shared_install_dirs() -> Vec<PathBuf> {\n    use crate::config::Settings;\n    let user_dirs = if let std::result::Result::Ok(settings) = Settings::try_get()\n        && let Some(ref dirs) = settings.shared_install_dirs\n        && !dirs.is_empty()\n    {\n        dirs.clone()\n    } else {\n        MISE_SHARED_INSTALL_DIRS_ENV.clone()\n    };\n    let system = &*MISE_SYSTEM_INSTALLS_DIR;\n    // System dir first (if it exists and isn't the user's own install dir),\n    // then user-configured dirs.\n    let mut result = Vec::new();\n    if system.is_dir() && *system != *MISE_INSTALLS_DIR {\n        result.push(system.clone());\n    }\n    result.extend(user_dirs);\n    result\n}\n\n/// Early-boot variant used by install_state::init_tools() before Settings is loaded.\npub fn shared_install_dirs_early() -> Vec<PathBuf> {\n    let system = &*MISE_SYSTEM_INSTALLS_DIR;\n    let mut result = Vec::new();\n    if system.is_dir() && *system != *MISE_INSTALLS_DIR {\n        result.push(system.clone());\n    }\n    result.extend(MISE_SHARED_INSTALL_DIRS_ENV.iter().cloned());\n    result\n}\n\n/// Categorize an install path as system, shared, or local.\npub fn install_path_category(path: &Path) -> InstallPathCategory {\n    if path.starts_with(&*MISE_SYSTEM_INSTALLS_DIR) {\n        InstallPathCategory::System\n    } else if shared_install_dirs().iter().any(|d| path.starts_with(d)) {\n        InstallPathCategory::Shared\n    } else {\n        InstallPathCategory::Local\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub enum InstallPathCategory {\n    /// Primary user install dir\n    Local,\n    /// System-level (/usr/local/share/mise/installs)\n    System,\n    /// User-configured shared dir\n    Shared,\n}\n\n/// Look up a tool version in shared install directories.\n/// `tool_dir_name` should be the kebab-cased directory name (e.g. from `ba.installs_path`).\n/// Returns the first shared path where `<shared_dir>/<tool_dir_name>/<pathname>` exists,\n/// or `primary_path` if not found in any shared directory.\npub fn find_in_shared_installs(\n    primary_path: PathBuf,\n    tool_dir_name: &str,\n    pathname: &str,\n) -> PathBuf {\n    if !primary_path.exists() {\n        for shared_dir in shared_install_dirs() {\n            let shared_path = shared_dir.join(tool_dir_name).join(pathname);\n            if shared_path.exists() {\n                return shared_path;\n            }\n        }\n    }\n    primary_path\n}\n\npub static MISE_DEFAULT_TOOL_VERSIONS_FILENAME: Lazy<String> = Lazy::new(|| {\n    var(\"MISE_DEFAULT_TOOL_VERSIONS_FILENAME\")\n        .ok()\n        .or(MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES\n            .as_ref()\n            .and_then(|v| v.first().cloned()))\n        .or(var(\"MISE_DEFAULT_TOOL_VERSIONS_FILENAME\").ok())\n        .unwrap_or_else(|| \".tool-versions\".into())\n});\npub static MISE_DEFAULT_CONFIG_FILENAME: Lazy<String> = Lazy::new(|| {\n    var(\"MISE_DEFAULT_CONFIG_FILENAME\")\n        .ok()\n        .or(MISE_OVERRIDE_CONFIG_FILENAMES.first().cloned())\n        .unwrap_or_else(|| \"mise.toml\".into())\n});\npub static MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES: Lazy<Option<IndexSet<String>>> =\n    Lazy::new(|| match var(\"MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES\") {\n        Ok(v) if v == \"none\" => Some([].into()),\n        Ok(v) => Some(v.split(':').map(|s| s.to_string()).collect()),\n        Err(_) => {\n            miserc::get_override_tool_versions_filenames().map(|v| v.iter().cloned().collect())\n        }\n    });\npub static MISE_OVERRIDE_CONFIG_FILENAMES: Lazy<IndexSet<String>> =\n    Lazy::new(|| match var(\"MISE_OVERRIDE_CONFIG_FILENAMES\") {\n        Ok(v) => v.split(':').map(|s| s.to_string()).collect(),\n        Err(_) => miserc::get_override_config_filenames()\n            .map(|v| v.iter().cloned().collect())\n            .unwrap_or_default(),\n    });\npub static MISE_ENV: Lazy<Vec<String>> = Lazy::new(|| environment(&ARGS.read().unwrap()));\npub static MISE_GLOBAL_CONFIG_FILE: Lazy<Option<PathBuf>> =\n    Lazy::new(|| var_path(\"MISE_GLOBAL_CONFIG_FILE\").or_else(|| var_path(\"MISE_CONFIG_FILE\")));\npub static MISE_GLOBAL_CONFIG_ROOT: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"MISE_GLOBAL_CONFIG_ROOT\").unwrap_or_else(|| HOME.to_path_buf()));\npub static MISE_SYSTEM_CONFIG_FILE: Lazy<Option<PathBuf>> =\n    Lazy::new(|| var_path(\"MISE_SYSTEM_CONFIG_FILE\"));\npub static MISE_IGNORED_CONFIG_PATHS: Lazy<Vec<PathBuf>> = Lazy::new(|| {\n    var(\"MISE_IGNORED_CONFIG_PATHS\")\n        .ok()\n        .map(|v| {\n            v.split(':')\n                .filter(|p| !p.is_empty())\n                .map(PathBuf::from)\n                .map(replace_path)\n                .collect()\n        })\n        .or_else(|| {\n            miserc::get_ignored_config_paths()\n                .map(|paths| paths.iter().cloned().map(replace_path).collect())\n        })\n        .unwrap_or_default()\n});\npub static MISE_CEILING_PATHS: Lazy<HashSet<PathBuf>> = Lazy::new(|| {\n    var(\"MISE_CEILING_PATHS\")\n        .ok()\n        .map(|v| {\n            split_paths(&v)\n                .filter(|p| !p.as_os_str().is_empty())\n                .map(replace_path)\n                .collect()\n        })\n        .or_else(|| {\n            miserc::get_ceiling_paths()\n                .map(|paths| paths.iter().cloned().map(replace_path).collect())\n        })\n        .unwrap_or_default()\n});\npub static MISE_USE_TOML: Lazy<bool> = Lazy::new(|| !var_is_false(\"MISE_USE_TOML\"));\npub static MISE_LIST_ALL_VERSIONS: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_LIST_ALL_VERSIONS\"));\npub static ARGV0: Lazy<String> = Lazy::new(|| ARGS.read().unwrap()[0].to_string());\npub static MISE_BIN_NAME: Lazy<&str> = Lazy::new(|| filename(&ARGV0));\npub static MISE_LOG_FILE: Lazy<Option<PathBuf>> = Lazy::new(|| var_path(\"MISE_LOG_FILE\"));\npub static MISE_LOG_FILE_LEVEL: Lazy<Option<LevelFilter>> = Lazy::new(log_file_level);\nfn find_in_tree(base: &Path, rels: &[&[&str]]) -> Option<PathBuf> {\n    for rel in rels {\n        let mut p = base.to_path_buf();\n        for part in *rel {\n            p = p.join(part);\n        }\n        if p.exists() {\n            return Some(p);\n        }\n    }\n    None\n}\n\nfn mise_install_base() -> Option<PathBuf> {\n    std::fs::canonicalize(&*MISE_BIN)\n        .ok()\n        .and_then(|p| p.parent().map(|p| p.to_path_buf()))\n        .and_then(|p| p.parent().map(|p| p.to_path_buf()))\n}\n\npub static MISE_SELF_UPDATE_INSTRUCTIONS: Lazy<Option<PathBuf>> = Lazy::new(|| {\n    if let Some(p) = var_path(\"MISE_SELF_UPDATE_INSTRUCTIONS\") {\n        return Some(p);\n    }\n    let base = mise_install_base()?;\n    // search lib/, lib/mise/, lib64/mise/\n    find_in_tree(\n        &base,\n        &[\n            &[\"lib\", \"mise-self-update-instructions.toml\"],\n            &[\"lib\", \"mise\", \"mise-self-update-instructions.toml\"],\n            &[\"lib64\", \"mise\", \"mise-self-update-instructions.toml\"],\n        ],\n    )\n});\n#[cfg(feature = \"self_update\")]\npub static MISE_SELF_UPDATE_AVAILABLE: Lazy<Option<bool>> = Lazy::new(|| {\n    if var_is_true(\"MISE_SELF_UPDATE_AVAILABLE\") {\n        Some(true)\n    } else if var_is_false(\"MISE_SELF_UPDATE_AVAILABLE\") {\n        Some(false)\n    } else {\n        None\n    }\n});\n#[cfg(feature = \"self_update\")]\npub static MISE_SELF_UPDATE_DISABLED_PATH: Lazy<Option<PathBuf>> = Lazy::new(|| {\n    let base = mise_install_base()?;\n    find_in_tree(\n        &base,\n        &[\n            &[\"lib\", \".disable-self-update\"],\n            &[\"lib\", \"mise\", \".disable-self-update\"],\n            &[\"lib64\", \"mise\", \".disable-self-update\"],\n        ],\n    )\n});\npub static MISE_LOG_HTTP: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_LOG_HTTP\"));\n\npub static __USAGE: Lazy<Option<String>> = Lazy::new(|| var(\"__USAGE\").ok());\n\n// true if running inside a shim\npub static __MISE_SHIM: Lazy<bool> = Lazy::new(|| var_is_true(\"__MISE_SHIM\"));\n\n// true if the current process is running as a shim (not direct mise invocation)\npub static IS_RUNNING_AS_SHIM: Lazy<bool> = Lazy::new(|| {\n    // When running tests, always treat as direct mise invocation\n    // to avoid interfering with test expectations\n    if cfg!(test) {\n        return false;\n    }\n\n    // Check if running as tool stub\n    if *MISE_TOOL_STUB {\n        return true;\n    }\n\n    let bin_name = *MISE_BIN_NAME;\n    !is_mise_binary(bin_name)\n});\n\n/// Returns true if the given binary name refers to mise itself (not a shim).\n/// Handles \"mise\", \"mise.exe\", \"mise.bat\", \"mise.cmd\", \"mise-doctor\", etc.\npub fn is_mise_binary(bin_name: &str) -> bool {\n    bin_name == \"mise\" || bin_name.starts_with(\"mise.\") || bin_name.starts_with(\"mise-\")\n}\n\n#[cfg(test)]\npub static TERM_WIDTH: Lazy<usize> = Lazy::new(|| 80);\n\n#[cfg(not(test))]\npub static TERM_WIDTH: Lazy<usize> = Lazy::new(|| {\n    terminal_size::terminal_size()\n        .map(|(w, _)| w.0 as usize)\n        .unwrap_or(80)\n        .max(80)\n});\n\n/// true if inside a script like bin/exec-env or bin/install\n/// used to prevent infinite loops\npub static MISE_BIN: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"__MISE_BIN\")\n        .or_else(|| current_exe().ok())\n        .unwrap_or_else(|| \"mise\".into())\n});\npub static MISE_TIMINGS: Lazy<u8> = Lazy::new(|| var_u8(\"MISE_TIMINGS\"));\npub static MISE_PID: Lazy<String> = Lazy::new(|| process::id().to_string());\npub static MISE_JOBS: Lazy<Option<usize>> =\n    Lazy::new(|| var(\"MISE_JOBS\").ok().and_then(|v| v.parse::<usize>().ok()));\npub static __MISE_SCRIPT: Lazy<bool> = Lazy::new(|| var_is_true(\"__MISE_SCRIPT\"));\npub static __MISE_DIFF: Lazy<EnvDiff> = Lazy::new(get_env_diff);\npub static __MISE_ORIG_PATH: Lazy<Option<String>> = Lazy::new(|| var(\"__MISE_ORIG_PATH\").ok());\npub static __MISE_ZSH_PRECMD_RUN: Lazy<bool> = Lazy::new(|| !var_is_false(\"__MISE_ZSH_PRECMD_RUN\"));\npub static LINUX_DISTRO: Lazy<Option<String>> = Lazy::new(linux_distro);\n/// Detected glibc version on Linux as (major, minor), e.g. (2, 17).\n/// Returns None on non-Linux or if detection fails.\npub static LINUX_GLIBC_VERSION: Lazy<Option<(u32, u32)>> = Lazy::new(linux_glibc_version);\npub static PREFER_OFFLINE: Lazy<AtomicBool> =\n    Lazy::new(|| prefer_offline(&ARGS.read().unwrap()).into());\npub static OFFLINE: Lazy<bool> = Lazy::new(|| offline(&ARGS.read().unwrap()));\npub static WARN_ON_MISSING_REQUIRED_ENV: Lazy<bool> =\n    Lazy::new(|| warn_on_missing_required_env(&ARGS.read().unwrap()));\n/// essentially, this is whether we show spinners or build output on runtime install\npub static PRISTINE_ENV: Lazy<EnvMap> =\n    Lazy::new(|| get_pristine_env(&__MISE_DIFF, vars_safe().collect()));\npub static PATH_KEY: Lazy<String> = Lazy::new(|| {\n    vars_safe()\n        .map(|(k, _)| k)\n        .find_or_first(|k| k.to_uppercase() == \"PATH\")\n        .map(|k| k.to_string())\n        .unwrap_or(\"PATH\".into())\n});\npub static PATH: Lazy<Vec<PathBuf>> = Lazy::new(|| match PRISTINE_ENV.get(&*PATH_KEY) {\n    Some(path) => split_paths(path).collect(),\n    None => vec![],\n});\npub static PATH_NON_PRISTINE: Lazy<Vec<PathBuf>> = Lazy::new(|| match var(&*PATH_KEY) {\n    Ok(ref path) => split_paths(path).collect(),\n    Err(_) => vec![],\n});\npub static DIRENV_DIFF: Lazy<Option<String>> = Lazy::new(|| var(\"DIRENV_DIFF\").ok());\n\npub static GITHUB_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_GITHUB_TOKEN\", \"GITHUB_API_TOKEN\", \"GITHUB_TOKEN\"]));\npub static MISE_GITHUB_ENTERPRISE_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_GITHUB_ENTERPRISE_TOKEN\"]));\npub static GITLAB_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_GITLAB_TOKEN\", \"GITLAB_TOKEN\"]));\npub static MISE_GITLAB_ENTERPRISE_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_GITLAB_ENTERPRISE_TOKEN\"]));\npub static FORGEJO_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_FORGEJO_TOKEN\", \"FORGEJO_TOKEN\"]));\npub static MISE_FORGEJO_ENTERPRISE_TOKEN: Lazy<Option<String>> =\n    Lazy::new(|| get_token(&[\"MISE_FORGEJO_ENTERPRISE_TOKEN\"]));\n\npub static TEST_TRANCHE: Lazy<usize> = Lazy::new(|| var_u8(\"TEST_TRANCHE\") as usize);\npub static TEST_TRANCHE_COUNT: Lazy<usize> = Lazy::new(|| var_u8(\"TEST_TRANCHE_COUNT\") as usize);\n\npub static CLICOLOR_FORCE: Lazy<Option<bool>> =\n    Lazy::new(|| var(\"CLICOLOR_FORCE\").ok().map(|v| v != \"0\"));\n\npub static CLICOLOR: Lazy<Option<bool>> = Lazy::new(|| {\n    if *CLICOLOR_FORCE == Some(true) {\n        Some(true)\n    } else if *NO_COLOR {\n        Some(false)\n    } else if let Ok(v) = var(\"CLICOLOR\") {\n        Some(v != \"0\")\n    } else {\n        None\n    }\n});\n\n/// Disable color output - https://no-color.org/\npub static NO_COLOR: Lazy<bool> = Lazy::new(|| var(\"NO_COLOR\").is_ok_and(|v| !v.is_empty()));\n\n/// Force progress bars even in non-TTY (for debugging)\npub static MISE_FORCE_PROGRESS: Lazy<bool> = Lazy::new(|| var_is_true(\"MISE_FORCE_PROGRESS\"));\n\n// python\npub static PYENV_ROOT: Lazy<PathBuf> =\n    Lazy::new(|| var_path(\"PYENV_ROOT\").unwrap_or_else(|| HOME.join(\".pyenv\")));\npub static UV_PYTHON_INSTALL_DIR: Lazy<PathBuf> = Lazy::new(|| {\n    var_path(\"UV_PYTHON_INSTALL_DIR\").unwrap_or_else(|| XDG_DATA_HOME.join(\"uv\").join(\"python\"))\n});\n\n#[cfg(unix)]\npub const PATH_ENV_SEP: char = ':';\n#[cfg(windows)]\npub const PATH_ENV_SEP: char = ';';\n\nfn get_env_diff() -> EnvDiff {\n    let env = vars_safe().collect::<HashMap<_, _>>();\n    match env.get(\"__MISE_DIFF\") {\n        Some(raw) => EnvDiff::deserialize(raw).unwrap_or_else(|err| {\n            warn!(\"Failed to deserialize __MISE_DIFF: {:#}\", err);\n            EnvDiff::default()\n        }),\n        None => EnvDiff::default(),\n    }\n}\n\nfn var_u8(key: &str) -> u8 {\n    var(key)\n        .ok()\n        .and_then(|v| v.parse::<u8>().ok())\n        .unwrap_or_default()\n}\n\nfn var_is_true(key: &str) -> bool {\n    match var(key) {\n        Ok(v) => {\n            let v = v.to_lowercase();\n            v == \"y\" || v == \"yes\" || v == \"true\" || v == \"1\" || v == \"on\"\n        }\n        Err(_) => false,\n    }\n}\n\nfn var_is_false(key: &str) -> bool {\n    match var(key) {\n        Ok(v) => {\n            let v = v.to_lowercase();\n            v == \"n\" || v == \"no\" || v == \"false\" || v == \"0\" || v == \"off\"\n        }\n        Err(_) => false,\n    }\n}\n\npub fn in_home_dir() -> bool {\n    current_dir().is_ok_and(|d| d == *HOME)\n}\n\npub fn var_path(key: &str) -> Option<PathBuf> {\n    var_os(key).map(PathBuf::from).map(replace_path)\n}\n\n/// this returns the environment as if __MISE_DIFF was reversed.\n/// putting the shell back into a state before hook-env was run\nfn get_pristine_env(mise_diff: &EnvDiff, orig_env: EnvMap) -> EnvMap {\n    let patches = mise_diff.reverse().to_patches();\n    let mut env = apply_patches(&orig_env, &patches);\n\n    // get the current path as a vector\n    let path = match env.get(&*PATH_KEY) {\n        Some(path) => split_paths(path).collect(),\n        None => vec![],\n    };\n    // get the paths that were removed by mise as a hashset\n    let mut to_remove = mise_diff.path.iter().collect::<HashSet<_>>();\n\n    // remove those paths that were added by mise, but only once (the first time)\n    let path = path\n        .into_iter()\n        .filter(|p| !to_remove.remove(p))\n        .collect_vec();\n\n    // put the pristine PATH back into the environment\n    env.insert(\n        PATH_KEY.to_string(),\n        join_paths(path).unwrap().to_string_lossy().to_string(),\n    );\n    env\n}\n\nfn apply_patches(env: &EnvMap, patches: &EnvDiffPatches) -> EnvMap {\n    let mut new_env = env.clone();\n    for patch in patches {\n        match patch {\n            EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => {\n                new_env.insert(k.into(), v.into());\n            }\n            EnvDiffOperation::Remove(k) => {\n                new_env.remove(k);\n            }\n        }\n    }\n\n    new_env\n}\n\nfn offline(args: &[String]) -> bool {\n    if var_is_true(\"MISE_OFFLINE\") {\n        return true;\n    }\n\n    args.iter()\n        .take_while(|a| *a != \"--\")\n        .any(|a| a == \"--offline\")\n}\n\n/// returns true if new runtime versions should not be fetched\nfn prefer_offline(args: &[String]) -> bool {\n    // First check if MISE_PREFER_OFFLINE is set\n    if var_is_true(\"MISE_PREFER_OFFLINE\") {\n        return true;\n    }\n\n    // Otherwise fall back to the original command-based logic\n    args.iter()\n        .take_while(|a| *a != \"--\")\n        .filter(|a| !a.starts_with('-') || *a == \"--prefer-offline\")\n        .nth(1)\n        .map(|a| {\n            [\n                \"--prefer-offline\",\n                \"activate\",\n                \"current\",\n                \"direnv\",\n                \"env\",\n                \"exec\",\n                \"hook-env\",\n                \"ls\",\n                \"where\",\n                \"x\",\n            ]\n            .contains(&a.as_str())\n        })\n        .unwrap_or_default()\n}\n\n/// returns true if missing required env vars should produce warnings instead of errors\nfn warn_on_missing_required_env(args: &[String]) -> bool {\n    // Check if we're running in a command that should warn instead of error\n    args.iter()\n        .take_while(|a| *a != \"--\")\n        .filter(|a| !a.starts_with('-'))\n        .nth(1)\n        .map(|a| {\n            [\n                \"hook-env\", // Shell activation should not break the shell\n            ]\n            .contains(&a.as_str())\n        })\n        .unwrap_or_default()\n}\n\nfn environment(args: &[String]) -> Vec<String> {\n    let arg_defs = HashSet::from([\"--profile\", \"-P\", \"--env\", \"-E\"]);\n\n    // Get environment value from args or env vars\n    // Precedence: CLI args > env vars > .miserc.toml\n    if *IS_RUNNING_AS_SHIM {\n        // When running as shim, ignore command line args and use env vars only\n        None\n    } else {\n        // Try to get from command line args first\n        args.windows(2)\n            .take_while(|window| !window.iter().any(|a| a == \"--\"))\n            .find_map(|window| {\n                if arg_defs.contains(&*window[0]) {\n                    Some(window[1].clone())\n                } else {\n                    None\n                }\n            })\n    }\n    .map(|s| {\n        s.split(',')\n            .filter(|s| !s.is_empty())\n            .map(String::from)\n            .collect()\n    })\n    .or_else(|| {\n        var(\"MISE_ENV\")\n            .ok()\n            .or_else(|| var(\"MISE_PROFILE\").ok())\n            .or_else(|| var(\"MISE_ENVIRONMENT\").ok())\n            .map(|s| {\n                s.split(',')\n                    .filter(|s| !s.is_empty())\n                    .map(String::from)\n                    .collect()\n            })\n    })\n    .or_else(|| miserc::get_env().cloned())\n    .unwrap_or_default()\n}\n\nfn log_file_level() -> Option<LevelFilter> {\n    let log_level = var(\"MISE_LOG_FILE_LEVEL\").unwrap_or_default();\n    log_level.parse::<LevelFilter>().ok()\n}\n\nfn linux_distro() -> Option<String> {\n    match sys_info::linux_os_release() {\n        Ok(release) => release.id,\n        _ => None,\n    }\n}\n\n#[cfg(target_os = \"linux\")]\nfn linux_glibc_version() -> Option<(u32, u32)> {\n    let output = std::process::Command::new(\"ldd\")\n        .arg(\"--version\")\n        .output()\n        .ok()?;\n    // ldd --version prints to stdout on glibc, stderr on some systems\n    let text = String::from_utf8_lossy(&output.stdout);\n    let text = if text.is_empty() {\n        String::from_utf8_lossy(&output.stderr)\n    } else {\n        text\n    };\n    let first_line = text.lines().next()?;\n    let version_str = first_line.rsplit(' ').next()?;\n    let mut parts = version_str.split('.');\n    let major = parts.next()?.parse().ok()?;\n    let minor = parts.next()?.parse().ok()?;\n    debug!(\"detected glibc version: {}.{}\", major, minor);\n    Some((major, minor))\n}\n\n#[cfg(not(target_os = \"linux\"))]\nfn linux_glibc_version() -> Option<(u32, u32)> {\n    None\n}\n\nfn filename(path: &str) -> &str {\n    path.rsplit_once(path::MAIN_SEPARATOR_STR)\n        .map(|(_, file)| file)\n        .unwrap_or(path)\n}\n\nfn get_token(keys: &[&str]) -> Option<String> {\n    keys.iter()\n        .find_map(|key| var(key).ok())\n        .and_then(|v| if v.trim().is_empty() { None } else { Some(v) })\n}\n\npub fn is_activated() -> bool {\n    var(\"__MISE_DIFF\").is_ok()\n}\n\npub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {\n    static MUTEX: Mutex<()> = Mutex::new(());\n    let _mutex = MUTEX.lock().unwrap();\n    unsafe {\n        std::env::set_var(key, value);\n    }\n}\n\npub fn remove_var<K: AsRef<OsStr>>(key: K) {\n    static MUTEX: Mutex<()> = Mutex::new(());\n    let _mutex = MUTEX.lock().unwrap();\n    unsafe {\n        std::env::remove_var(key);\n    }\n}\n\n/// Remove the env cache encryption key to force fresh env computation\npub fn reset_env_cache_key() {\n    remove_var(\"__MISE_ENV_CACHE_KEY\");\n}\n\n/// Safe wrapper around std::env::vars() that handles invalid UTF-8 gracefully.\n/// This function uses vars_os() and converts OsString to String, skipping any\n/// environment variables that contain invalid UTF-8 sequences.\npub fn vars_safe() -> impl Iterator<Item = (String, String)> {\n    vars_os().filter_map(|(k, v)| {\n        let k_str = k.to_str()?;\n        let v_str = v.to_str()?;\n        Some((k_str.to_string(), v_str.to_string()))\n    })\n}\n\npub fn set_current_dir<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"cd {}\", display_path(path));\n    unsafe {\n        std::env::set_current_dir(path).wrap_err_with(|| {\n            format!(\"failed to set current directory to {}\", display_path(path))\n        })?;\n        path_absolutize::update_cwd();\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_apply_patches() {\n        let _config = Config::get().await.unwrap();\n        let mut env = EnvMap::new();\n        env.insert(\"foo\".into(), \"bar\".into());\n        env.insert(\"baz\".into(), \"qux\".into());\n        let patches = vec![\n            EnvDiffOperation::Add(\"foo\".into(), \"bar\".into()),\n            EnvDiffOperation::Change(\"baz\".into(), \"qux\".into()),\n            EnvDiffOperation::Remove(\"quux\".into()),\n        ];\n        let new_env = apply_patches(&env, &patches);\n        assert_eq!(new_env.len(), 2);\n        assert_eq!(new_env.get(\"foo\").unwrap(), \"bar\");\n        assert_eq!(new_env.get(\"baz\").unwrap(), \"qux\");\n    }\n\n    #[tokio::test]\n    async fn test_var_path() {\n        let _config = Config::get().await.unwrap();\n        set_var(\"MISE_TEST_PATH\", \"/foo/bar\");\n        assert_eq!(\n            var_path(\"MISE_TEST_PATH\").unwrap(),\n            PathBuf::from(\"/foo/bar\")\n        );\n        remove_var(\"MISE_TEST_PATH\");\n    }\n\n    #[test]\n    fn test_token_overwrite() {\n        // Clean up any existing environment variables that might interfere\n        remove_var(\"MISE_GITHUB_TOKEN\");\n        remove_var(\"GITHUB_TOKEN\");\n        remove_var(\"GITHUB_API_TOKEN\");\n\n        set_var(\"MISE_GITHUB_TOKEN\", \"\");\n        set_var(\"GITHUB_TOKEN\", \"invalid_token\");\n        assert_eq!(\n            get_token(&[\"MISE_GITHUB_TOKEN\", \"GITHUB_TOKEN\"]),\n            None,\n            \"Empty token should overwrite other tokens\"\n        );\n        assert_eq!(\n            get_token(&[\"GITHUB_API_TOKEN\", \"GITHUB_TOKEN\"]),\n            Some(\"invalid_token\".into()),\n            \"Unset token should not overwrite other tokens\"\n        );\n        remove_var(\"MISE_GITHUB_TOKEN\");\n        remove_var(\"GITHUB_TOKEN\");\n        remove_var(\"GITHUB_API_TOKEN\");\n    }\n}\n"
  },
  {
    "path": "src/env_diff.rs",
    "content": "use std::collections::BTreeMap;\nuse std::ffi::OsString;\nuse std::fmt::Debug;\nuse std::io::prelude::*;\nuse std::iter::once;\nuse std::path::{Path, PathBuf};\n\nuse base64::prelude::*;\nuse eyre::Result;\nuse flate2::Compression;\nuse flate2::write::{ZlibDecoder, ZlibEncoder};\nuse indexmap::{IndexMap, IndexSet};\nuse itertools::Itertools;\nuse serde_derive::{Deserialize, Serialize};\nuse std::sync::LazyLock as Lazy;\n\nuse crate::env::PATH_KEY;\nuse crate::file;\n\n#[derive(Default, Serialize, Deserialize)]\npub struct EnvDiff {\n    #[serde(default)]\n    pub old: IndexMap<String, String>,\n    #[serde(default)]\n    pub new: IndexMap<String, String>,\n    #[serde(default)]\n    pub path: Vec<PathBuf>,\n}\n\n#[derive(Debug)]\npub enum EnvDiffOperation {\n    Add(String, String),\n    Change(String, String),\n    Remove(String),\n}\n\npub type EnvDiffPatches = Vec<EnvDiffOperation>;\npub type EnvMap = BTreeMap<String, String>;\n\nimpl EnvDiff {\n    pub fn new<T>(original: &EnvMap, additions: T) -> EnvDiff\n    where\n        T: IntoIterator<Item = (String, String)>,\n    {\n        let mut diff = EnvDiff::default();\n\n        for (key, new_val) in additions.into_iter() {\n            let key: String = key;\n            match original.get(&key) {\n                Some(original_val) => {\n                    if original_val != &new_val {\n                        diff.old.insert(key.clone(), original_val.into());\n                        diff.new.insert(key, new_val);\n                    }\n                }\n                None => {\n                    diff.new.insert(key, new_val);\n                }\n            }\n        }\n\n        diff\n    }\n\n    pub fn from_bash_script<T, U, V>(\n        script: &Path,\n        dir: &Path,\n        env: T,\n        opts: &EnvDiffOptions,\n    ) -> Result<Self>\n    where\n        T: IntoIterator<Item = (U, V)>,\n        U: Into<OsString>,\n        V: Into<OsString>,\n    {\n        let env: IndexMap<OsString, OsString> =\n            env.into_iter().map(|(k, v)| (k.into(), v.into())).collect();\n        let bash_path = file::which(if cfg!(windows) { \"bash.exe\" } else { \"bash\" })\n            .unwrap_or(\"/bin/bash\".into());\n        let out = cmd!(\n            bash_path,\n            \"--noprofile\",\n            \"-c\",\n            indoc::formatdoc! {\"\n                . \\\"{script}\\\"\n                export -p\n            \", script = script.display()}\n        )\n        .dir(dir)\n        .full_env(&env)\n        .read()?;\n        let env: EnvMap = env\n            .into_iter()\n            .map(|(k, v)| (k.into_string().unwrap(), v.into_string().unwrap()))\n            .collect();\n\n        let mut additions = EnvMap::new();\n        let mut cur_key = None;\n        for line in out.lines() {\n            match line.strip_prefix(\"declare -x \") {\n                Some(line) => {\n                    let (k, v) = line.split_once('=').unwrap_or_default();\n                    if invalid_key(k, opts) {\n                        continue;\n                    }\n                    cur_key = Some(k.to_string());\n                    additions.insert(k.to_string(), v.to_string());\n                }\n                None => {\n                    if let Some(k) = &cur_key {\n                        let v = format!(\"\\n{line}\");\n                        additions.get_mut(k).unwrap().push_str(&v);\n                    }\n                }\n            }\n        }\n        for (k, v) in additions.clone().iter() {\n            let v = normalize_escape_sequences(v);\n            if let Some(orig) = env.get(k)\n                && &v == orig\n            {\n                additions.remove(k);\n                continue;\n            }\n            additions.insert(k.into(), v);\n        }\n        Ok(Self::new(&env, additions))\n    }\n\n    pub fn deserialize(raw: &str) -> Result<EnvDiff> {\n        let mut writer = Vec::new();\n        let mut decoder = ZlibDecoder::new(writer);\n        let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?;\n        decoder.write_all(&bytes[..])?;\n        writer = decoder.finish()?;\n        Ok(rmp_serde::from_slice(&writer[..])?)\n    }\n\n    pub fn serialize(&self) -> Result<String> {\n        let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast());\n        gz.write_all(&rmp_serde::to_vec_named(self)?)?;\n        Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?))\n    }\n\n    pub fn to_patches(&self) -> EnvDiffPatches {\n        let mut patches = EnvDiffPatches::new();\n\n        for k in self.old.keys() {\n            match self.new.get(k) {\n                Some(v) => patches.push(EnvDiffOperation::Change(k.into(), v.into())),\n                None => patches.push(EnvDiffOperation::Remove(k.into())),\n            };\n        }\n        for (k, v) in self.new.iter() {\n            if !self.old.contains_key(k) {\n                patches.push(EnvDiffOperation::Add(k.into(), v.into()))\n            };\n        }\n\n        patches\n    }\n\n    pub fn reverse(&self) -> EnvDiff {\n        EnvDiff {\n            old: self.new.clone(),\n            new: self.old.clone(),\n            path: self.path.clone(),\n        }\n    }\n}\n\nfn invalid_key(k: &str, opts: &EnvDiffOptions) -> bool {\n    k.is_empty()\n        || opts.ignore_keys.contains(k)\n        // following two ignores are for exported bash functions and exported bash\n        // functions which are multiline, they appear in the environment as e.g.:\n        // BASH_FUNC_exported-bash-function%%=() { echo \"this is an\"\n        //  echo \"exported bash function\"\n        //  echo \"with multiple lines\"\n        // }\n        || k.starts_with(\"BASH_FUNC_\")\n        || k.starts_with(' ')\n}\n\nstatic DEFAULT_IGNORE_KEYS: Lazy<IndexSet<String>> = Lazy::new(|| {\n    [\n        \"_\",\n        \"SHLVL\",\n        \"PWD\",\n        \"OLDPWD\",\n        \"HOME\",\n        \"USER\",\n        \"SHELL\",\n        \"SHELLOPTS\",\n        \"COMP_WORDBREAKS\",\n        \"PS1\",\n        \"PROMPT_DIRTRIM\",\n    ]\n    .iter()\n    .map(|s| s.to_string())\n    .collect()\n});\n\nimpl Debug for EnvDiff {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let print_sorted = |hashmap: &IndexMap<String, String>| {\n            hashmap\n                .iter()\n                .map(|(k, v)| format!(\"{k}={v}\"))\n                .sorted()\n                .collect::<Vec<_>>()\n        };\n        f.debug_struct(\"EnvDiff\")\n            .field(\"old\", &print_sorted(&self.old))\n            .field(\"new\", &print_sorted(&self.new))\n            .finish()\n    }\n}\n\nfn normalize_escape_sequences(input: &str) -> String {\n    let input = if input.starts_with('\"') && input.ends_with('\"') {\n        input[1..input.len() - 1].to_string()\n    } else if input.starts_with(\"$'\") && input.ends_with('\\'') {\n        input[2..input.len() - 1].to_string()\n    } else {\n        input.to_string()\n    };\n\n    let mut result = String::with_capacity(input.len());\n    let mut chars = input.chars();\n\n    while let Some(c) = chars.next() {\n        if c == '\\\\' {\n            match chars.next() {\n                Some(val) => match val {\n                    'a' => result.push('\\u{07}'),\n                    'b' => result.push('\\u{08}'),\n                    'e' | 'E' => result.push('\\u{1b}'),\n                    'f' => result.push('\\u{0c}'),\n                    'n' => result.push('\\n'),\n                    'r' => result.push('\\r'),\n                    't' => result.push('\\t'),\n                    'v' => result.push('\\u{0b}'),\n                    '\\\\' => result.push('\\\\'),\n                    '\\'' => result.push('\\''),\n                    '\"' => result.push('\"'),\n                    '?' => result.push('?'),\n                    '`' => result.push('`'),\n                    '$' => result.push('$'),\n                    _ => {\n                        result.push('\\\\');\n                        result.push(val);\n                    }\n                },\n                None => {\n                    warn!(\"Invalid escape sequence: {}\", input);\n                }\n            }\n        } else {\n            result.push(c)\n        }\n    }\n\n    result\n}\n\npub struct EnvDiffOptions {\n    pub ignore_keys: IndexSet<String>,\n}\n\nimpl Default for EnvDiffOptions {\n    fn default() -> Self {\n        Self {\n            ignore_keys: DEFAULT_IGNORE_KEYS\n                .iter()\n                .cloned()\n                .chain(once(PATH_KEY.to_string()))\n                .collect(),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n\n    use insta::assert_debug_snapshot;\n    use pretty_assertions::assert_str_eq;\n\n    #[tokio::test]\n    async fn test_diff() {\n        let _config = Config::get().await.unwrap();\n        let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap());\n        assert_debug_snapshot!(diff.to_patches());\n    }\n\n    #[tokio::test]\n    async fn test_reverse() {\n        let _config = Config::get().await.unwrap();\n        let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap());\n        let patches = diff.reverse().to_patches();\n        let to_remove = patches\n            .iter()\n            .filter_map(|p| match p {\n                EnvDiffOperation::Remove(k) => Some(k),\n                _ => None,\n            })\n            .collect::<Vec<_>>();\n        assert_debug_snapshot!(to_remove, @r#\"\n        [\n            \"c\",\n        ]\n        \"#);\n        let to_add = patches\n            .iter()\n            .filter_map(|p| match p {\n                EnvDiffOperation::Add(k, v) => Some((k, v)),\n                _ => None,\n            })\n            .collect::<Vec<_>>();\n        assert_debug_snapshot!(to_add, @\"[]\");\n        let to_change = patches\n            .iter()\n            .filter_map(|p| match p {\n                EnvDiffOperation::Change(k, v) => Some((k, v)),\n                _ => None,\n            })\n            .collect::<Vec<_>>();\n        assert_debug_snapshot!(to_change, @r#\"\n        [\n            (\n                \"b\",\n                \"2\",\n            ),\n        ]\n        \"#);\n    }\n\n    fn new_from_hashmap() -> EnvMap {\n        [(\"a\", \"1\"), (\"b\", \"2\")]\n            .map(|(k, v)| (k.into(), v.into()))\n            .into()\n    }\n\n    fn new_to_hashmap() -> EnvMap {\n        [(\"a\", \"1\"), (\"b\", \"3\"), (\"c\", \"4\")]\n            .map(|(k, v)| (k.into(), v.into()))\n            .into()\n    }\n\n    #[tokio::test]\n    async fn test_serialize() {\n        let _config = Config::get().await.unwrap();\n        let diff = EnvDiff::new(&new_from_hashmap(), new_to_hashmap());\n        let serialized = diff.serialize().unwrap();\n        let deserialized = EnvDiff::deserialize(&serialized).unwrap();\n        assert_debug_snapshot!(deserialized.to_patches());\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_from_bash_script() {\n        let _config = Config::get().await.unwrap();\n        use crate::{config::Config, dirs};\n        use indexmap::indexmap;\n        let path = dirs::HOME.join(\"fixtures/exec-env\");\n        let orig = indexmap! {\n            \"UNMODIFIED_VAR\" => \"unmodified\",\n            \"UNMODIFIED_NEWLINE_VAR\" => \"hello\\\\nworld\",\n            \"UNMODIFIED_SQUOTE_VAR\" => \"hello\\\\'world\",\n            \"UNMODIFIED_ESCAPE_VAR\" => \"hello\\\\world\",\n            \"MODIFIED_VAR\" => \"original\",\n            \"ESCAPES\" => \"\\\\n\\\\t\\\\r\\\\v\\\\f\\\\a\\\\b\\\\e\\\\0\\\\x1b\\\\u1234\\\\U00012345\\\\a\\\\b\\\\e\\\\E\\\\f\\\\n\\\\r\\\\t\\\\v\\\"?`$\\\\g'\\\\0\",\n            \"BACKSPACE\" => \"\\u{08}\",\n            \"BACKTICK\" => \"`\",\n            \"BELL\" => \"\\u{07}\",\n            \"CARRIAGE_RETURN\" => \"\\r\",\n            \"DOLLAR\" => \"$\",\n            \"DOUBLE_QUOTE\" => \"\\\"\",\n            \"ESCAPE\" => \"\\u{1b}\",\n            \"ESCAPE2\" => \"\\u{1b}\",\n            \"FORM_FEED\" => \"\\u{0c}\",\n            \"G\" => \"g\",\n            \"NEWLINE\" => \"\\n\",\n            \"QUESTION_MARK\" => \"?\",\n            \"SINGLE_QUOTE\" => \"'\",\n            \"TAB\" => \"\\t\",\n            \"VERTICAL_TAB\" => \"\\u{0b}\",\n        }\n            .into_iter()\n            .map(|(k, v)| (k.into(), v.into()))\n            .collect::<Vec<(String, String)>>();\n        let cwd = dirs::CWD.clone().unwrap();\n        let ed =\n            EnvDiff::from_bash_script(path.as_path(), &cwd, orig, &Default::default()).unwrap();\n        assert_debug_snapshot!(ed);\n    }\n\n    #[tokio::test]\n    async fn test_invalid_escape_sequence() {\n        let _config = Config::get().await.unwrap();\n        let input = r#\"\"\\g\\\"\"#;\n        let output = normalize_escape_sequences(input);\n        // just warns\n        assert_str_eq!(output, r\"\\g\");\n    }\n}\n"
  },
  {
    "path": "src/errors.rs",
    "content": "use std::path::PathBuf;\nuse std::process::ExitStatus;\n\nuse crate::cli::args::BackendArg;\nuse crate::file::display_path;\nuse crate::toolset::{ToolRequest, ToolSource, ToolVersion};\nuse eyre::Report;\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum Error {\n    #[error(\"[{ts}] {tr}: {source:#}\")]\n    FailedToResolveVersion {\n        tr: Box<ToolRequest>,\n        ts: ToolSource,\n        source: Report,\n    },\n    #[error(\"[{0}] plugin not installed\")]\n    PluginNotInstalled(String),\n    #[error(\"{0}@{1} not installed\")]\n    VersionNotInstalled(Box<BackendArg>, String),\n    #[error(\"{} exited with non-zero status: {}\", .0, render_exit_status(.1))]\n    ScriptFailed(String, Option<ExitStatus>),\n    #[error(\n        \"Config files in {} are not trusted.\\nTrust them with `mise trust`. See https://mise.jdx.dev/cli/trust.html for more information.\",\n        display_path(.0)\n    )]\n    UntrustedConfig(PathBuf),\n    #[error(\"{}\", format_install_failures(.failed_installations))]\n    InstallFailed {\n        successful_installations: Vec<ToolVersion>,\n        failed_installations: Vec<(ToolRequest, Report)>,\n    },\n}\n\nfn render_exit_status(exit_status: &Option<ExitStatus>) -> String {\n    match exit_status.and_then(|s| s.code()) {\n        Some(exit_status) => format!(\"exit code {exit_status}\"),\n        None => \"no exit status\".into(),\n    }\n}\n\nfn format_install_failures(failed_installations: &[(ToolRequest, Report)]) -> String {\n    if failed_installations.is_empty() {\n        return \"Installation failed\".to_string();\n    }\n\n    // For a single failure, show the underlying error directly to preserve\n    // the original error location for better debugging\n    if failed_installations.len() == 1 {\n        let (tr, error) = &failed_installations[0];\n        // Show the underlying error with the tool context\n        // Use {:#} to show full error chain (includes wrapped errors)\n        return format!(\n            \"Failed to install {}@{}: {:#}\",\n            tr.ba().full(),\n            tr.version(),\n            error\n        );\n    }\n\n    // For multiple failures, show a summary and then each error\n    // Sort by tool name for deterministic output (parallel installs complete in arbitrary order)\n    let mut sorted_failures: Vec<_> = failed_installations\n        .iter()\n        .map(|(tr, err)| (format!(\"{}@{}\", tr.ba().full(), tr.version()), err))\n        .collect();\n    sorted_failures.sort_by(|a, b| a.0.cmp(&b.0));\n\n    let mut output = vec![];\n    let failed_tools: Vec<&str> = sorted_failures\n        .iter()\n        .map(|(name, _)| name.as_str())\n        .collect();\n\n    output.push(format!(\n        \"Failed to install tools: {}\",\n        failed_tools.join(\", \")\n    ));\n\n    // Show detailed errors for each failure (in sorted order)\n    // Use {:#} to show full error chain (includes wrapped errors)\n    for (name, error) in sorted_failures.iter() {\n        output.push(format!(\"\\n{}: {:#}\", name, error));\n    }\n\n    output.join(\"\\n\")\n}\n\nimpl Error {\n    pub fn get_exit_status(err: &Report) -> Option<i32> {\n        if let Some(Error::ScriptFailed(_, Some(status))) = err.downcast_ref::<Error>() {\n            status.code()\n        } else {\n            None\n        }\n    }\n\n    pub fn is_argument_err(err: &Report) -> bool {\n        err.downcast_ref::<Error>()\n            .map(|e| {\n                matches!(\n                    e,\n                    Error::FailedToResolveVersion {\n                        ts: ToolSource::Argument,\n                        ..\n                    }\n                )\n            })\n            .unwrap_or(false)\n    }\n}\n"
  },
  {
    "path": "src/exit.rs",
    "content": "use crate::cmd::CmdLineRunner;\n#[cfg(unix)]\nuse nix::sys::signal::SIGTERM;\n\npub fn exit(code: i32) -> ! {\n    #[cfg(unix)]\n    CmdLineRunner::kill_all(SIGTERM);\n\n    #[cfg(windows)]\n    CmdLineRunner::kill_all();\n\n    debug!(\"exiting with code: {code}\");\n    std::process::exit(code)\n}\n"
  },
  {
    "path": "src/fake_asdf.rs",
    "content": "use std::fs;\nuse std::os::unix::fs::PermissionsExt;\nuse std::path::PathBuf;\n\nuse color_eyre::eyre::ErrReport;\nuse indoc::formatdoc;\nuse once_cell::sync::OnceCell;\n\nuse crate::env::PATH_KEY;\nuse crate::path_env::PathEnv;\nuse crate::{env, file};\n\npub fn setup() -> color_eyre::Result<PathBuf> {\n    static SETUP: OnceCell<PathBuf> = OnceCell::new();\n    let path = SETUP.get_or_try_init(|| {\n        let path = env::MISE_DATA_DIR.join(\".fake-asdf\");\n        let asdf_bin = path.join(\"asdf\");\n        if !asdf_bin.exists() {\n            file::create_dir_all(&path)?;\n            file::write(\n                &asdf_bin,\n                formatdoc! {r#\"\n                #!/bin/sh\n                mise asdf \"$@\"\n            \"#},\n            )?;\n            let mut perms = asdf_bin.metadata()?.permissions();\n            perms.set_mode(0o755);\n            fs::set_permissions(&asdf_bin, perms)?;\n        }\n        Ok::<PathBuf, ErrReport>(path)\n    })?;\n\n    Ok(path.clone())\n}\n\npub fn get_path_with_fake_asdf() -> String {\n    let mut path_env = PathEnv::from_iter(env::split_paths(\n        &env::var_os(&*PATH_KEY).unwrap_or_default(),\n    ));\n    match setup() {\n        Ok(fake_asdf_path) => path_env.add(fake_asdf_path),\n        Err(e) => warn!(\"Failed to setup fake asdf: {:#}\", e),\n    };\n    path_env.to_string()\n}\n"
  },
  {
    "path": "src/fake_asdf_windows.rs",
    "content": "use std::env::{join_paths, split_paths};\nuse std::path::PathBuf;\n\nuse crate::env;\nuse crate::env::PATH_KEY;\n\n#[cfg(windows)]\npub fn setup() -> color_eyre::Result<PathBuf> {\n    let path = env::MISE_DATA_DIR.join(\".fake-asdf\");\n    Ok(path)\n}\n\npub fn get_path_with_fake_asdf() -> String {\n    let mut path = split_paths(&env::var_os(&*PATH_KEY).unwrap_or_default()).collect::<Vec<_>>();\n    match setup() {\n        Ok(fake_asdf_path) => {\n            path.insert(0, fake_asdf_path);\n        }\n        Err(e) => {\n            warn!(\"Failed to setup fake asdf: {:#}\", e);\n        }\n    };\n    join_paths(path).unwrap().to_string_lossy().to_string()\n}\n"
  },
  {
    "path": "src/file.rs",
    "content": "use crate::path::{Path, PathBuf, PathExt};\nuse std::collections::{BTreeSet, HashMap, HashSet};\nuse std::fmt::Display;\nuse std::fs;\nuse std::fs::File;\nuse std::io::Write;\n#[cfg(unix)]\nuse std::os::unix::fs::symlink;\n#[cfg(unix)]\nuse std::os::unix::prelude::*;\nuse std::sync::Mutex;\nuse std::time::Duration;\n\nuse bzip2::read::BzDecoder;\nuse color_eyre::eyre::{Context, Result};\nuse eyre::bail;\nuse filetime::{FileTime, set_file_times};\nuse flate2::read::GzDecoder;\nuse itertools::Itertools;\nuse std::sync::LazyLock as Lazy;\nuse tar::Archive;\nuse walkdir::WalkDir;\nuse zip::ZipArchive;\n\n#[cfg(windows)]\nuse crate::config::Settings;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{dirs, env};\n\npub fn open<P: AsRef<Path>>(path: P) -> Result<File> {\n    let path = path.as_ref();\n    trace!(\"open {}\", display_path(path));\n    File::open(path).wrap_err_with(|| format!(\"failed open: {}\", display_path(path)))\n}\n\npub fn read<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {\n    let path = path.as_ref();\n    trace!(\"cat {}\", display_path(path));\n    fs::read(path).wrap_err_with(|| format!(\"failed read: {}\", display_path(path)))\n}\n\npub fn size<P: AsRef<Path>>(path: P) -> Result<u64> {\n    let path = path.as_ref();\n    trace!(\"du -b {}\", display_path(path));\n    path.metadata()\n        .map(|m| m.len())\n        .wrap_err_with(|| format!(\"failed size: {}\", display_path(path)))\n}\n\npub fn append<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"append {}\", display_path(path));\n    fs::OpenOptions::new()\n        .append(true)\n        .create(true)\n        .open(path)\n        .and_then(|mut f| f.write_all(contents.as_ref()))\n        .wrap_err_with(|| format!(\"failed append: {}\", display_path(path)))\n}\n\npub fn remove_all<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    match path.metadata().map(|m| m.file_type()) {\n        Ok(x) if x.is_symlink() || x.is_file() => {\n            remove_file(path)?;\n        }\n        Ok(x) if x.is_dir() => {\n            trace!(\"rm -rf {}\", display_path(path));\n            fs::remove_dir_all(path)\n                .wrap_err_with(|| format!(\"failed rm -rf: {}\", display_path(path)))?;\n        }\n        _ => {}\n    };\n    Ok(())\n}\n\npub fn remove_file_or_dir<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    match path.metadata().map(|m| m.file_type()) {\n        Ok(x) if x.is_dir() => {\n            remove_dir(path)?;\n        }\n        _ => {\n            remove_file(path)?;\n        }\n    };\n    Ok(())\n}\n\npub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"rm {}\", display_path(path));\n    fs::remove_file(path).wrap_err_with(|| format!(\"failed rm: {}\", display_path(path)))\n}\n\npub async fn remove_file_async<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"rm {}\", display_path(path));\n    tokio::fs::remove_file(path)\n        .await\n        .wrap_err_with(|| format!(\"failed rm: {}\", display_path(path)))\n}\n\npub fn remove_dir<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    (|| -> Result<()> {\n        if path.exists() && is_empty_dir(path)? {\n            trace!(\"rmdir {}\", display_path(path));\n            fs::remove_dir(path)?;\n        }\n        Ok(())\n    })()\n    .wrap_err_with(|| format!(\"failed to remove_dir: {}\", display_path(path)))\n}\n\npub fn remove_dir_ignore<P: AsRef<Path>>(path: P, is_empty_ignore_files: Vec<&str>) -> Result<()> {\n    let path = path.as_ref();\n    (|| -> Result<()> {\n        if path.exists() && is_empty_dir_ignore(path, is_empty_ignore_files)? {\n            trace!(\"rm -rf {}\", display_path(path));\n            remove_all_with_warning(path)?;\n        }\n        Ok(())\n    })()\n    .wrap_err_with(|| format!(\"failed to remove_dir: {}\", display_path(path)))\n}\n\npub fn remove_all_with_warning<P: AsRef<Path>>(path: P) -> Result<()> {\n    remove_all(&path).map_err(|e| {\n        warn!(\"failed to remove {}: {}\", path.as_ref().display(), e);\n        e\n    })\n}\n\npub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {\n    let from = from.as_ref();\n    let to = to.as_ref();\n    trace!(\"mv {} {}\", from.display(), to.display());\n    fs::rename(from, to).wrap_err_with(|| {\n        format!(\n            \"failed rename: {} -> {}\",\n            display_path(from),\n            display_path(to)\n        )\n    })\n}\n\npub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {\n    let from = from.as_ref();\n    let to = to.as_ref();\n    trace!(\"cp {} {}\", from.display(), to.display());\n    fs::copy(from, to)\n        .wrap_err_with(|| {\n            format!(\n                \"failed copy: {} -> {}\",\n                display_path(from),\n                display_path(to)\n            )\n        })\n        .map(|_| ())\n}\n\npub fn copy_dir_all<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {\n    let from = from.as_ref();\n    let to = to.as_ref();\n    trace!(\"cp -r {} {}\", from.display(), to.display());\n    recursive_ls(from)?.into_iter().try_for_each(|path| {\n        let relative = path.strip_prefix(from)?;\n        let dest = to.join(relative);\n        create_dir_all(dest.parent().unwrap())?;\n        copy(&path, &dest)?;\n        Ok(())\n    })\n}\n\npub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"write {}\", display_path(path));\n    fs::write(path, contents).wrap_err_with(|| format!(\"failed write: {}\", display_path(path)))\n}\npub async fn write_async<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"write {}\", display_path(path));\n    tokio::fs::write(path, contents)\n        .await\n        .wrap_err_with(|| format!(\"failed write: {}\", display_path(path)))\n}\n\npub fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String> {\n    let path = path.as_ref();\n    trace!(\"cat {}\", path.display_user());\n    fs::read_to_string(path)\n        .wrap_err_with(|| format!(\"failed read_to_string: {}\", path.display_user()))\n}\n\npub async fn read_to_string_async<P: AsRef<Path>>(path: P) -> Result<String> {\n    let path = path.as_ref();\n    trace!(\"cat {}\", path.display_user());\n    tokio::fs::read_to_string(path)\n        .await\n        .wrap_err_with(|| format!(\"failed read_to_string: {}\", path.display_user()))\n}\n\npub fn create(path: &Path) -> Result<File> {\n    if let Some(parent) = path.parent() {\n        create_dir_all(parent)?;\n    }\n    trace!(\"touch {}\", display_path(path));\n    File::create(path).wrap_err_with(|| format!(\"failed create: {}\", display_path(path)))\n}\n\npub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {\n    static LOCK: Lazy<Mutex<u8>> = Lazy::new(Default::default);\n    let _lock = LOCK.lock().unwrap();\n\n    let path = path.as_ref();\n    if !path.exists() {\n        trace!(\"mkdir -p {}\", display_path(path));\n        if let Err(err) = fs::create_dir_all(path) {\n            // if not exists error\n            if err.kind() != std::io::ErrorKind::AlreadyExists {\n                return Err(err)\n                    .wrap_err_with(|| format!(\"failed create_dir_all: {}\", display_path(path)));\n            }\n        }\n    }\n    Ok(())\n}\n\n/// replaces $HOME with \"~\"\npub fn display_path<P: AsRef<Path>>(path: P) -> String {\n    path.as_ref().display_user()\n}\n\npub fn display_rel_path<P: AsRef<Path>>(path: P) -> String {\n    let path = path.as_ref();\n    match path.strip_prefix(dirs::CWD.as_ref().unwrap()) {\n        Ok(rel) => format!(\"./{}\", rel.display()),\n        Err(_) => display_path(path),\n    }\n}\n\n/// replaces $HOME in a string with \"~\" and $PATH with \"$PATH\", generally used to clean up output\n/// after it is rendered\npub fn replace_paths_in_string<S: Display>(input: S) -> String {\n    let home = env::HOME.to_string_lossy().to_string();\n    input.to_string().replace(&home, \"~\")\n}\n\n/// replaces \"~\" with $HOME\npub fn replace_path<P: AsRef<Path>>(path: P) -> PathBuf {\n    let path = path.as_ref();\n    match path.starts_with(\"~/\") {\n        true => dirs::HOME.join(path.strip_prefix(\"~/\").unwrap()),\n        false => path.to_path_buf(),\n    }\n}\n\npub fn touch_file(file: &Path) -> Result<()> {\n    if !file.exists() {\n        create(file)?;\n        return Ok(());\n    }\n    trace!(\"touch_file {}\", file.display());\n    let now = FileTime::now();\n    set_file_times(file, now, now)\n        .wrap_err_with(|| format!(\"failed to touch file: {}\", display_path(file)))\n}\n\npub fn touch_dir(dir: &Path) -> Result<()> {\n    trace!(\"touch {}\", dir.display());\n    let now = FileTime::now();\n    set_file_times(dir, now, now)\n        .wrap_err_with(|| format!(\"failed to touch dir: {}\", display_path(dir)))\n}\n\n/// Synchronizes a directory to disk, ensuring that filesystem metadata changes\n/// (such as file creations or deletions) are persisted.\n///\n/// This is important after operations like removing files to ensure the changes\n/// are immediately visible to other processes, e.g. to avoid race conditions.\n///\n/// # Platform-specific behavior\n///\n/// - **Unix/Linux**: Performs an fsync on the directory file descriptor, which\n///   ensures directory metadata (like file listings) is written to disk.\n/// - **Windows**: Not implemented (no-op).\n///\n/// # Errors\n///\n/// On Unix systems, returns an error if the directory cannot be opened or synced.\n/// On Windows, always succeeds.\n#[cfg(unix)]\npub fn sync_dir<P: AsRef<Path>>(path: P) -> Result<()> {\n    let path = path.as_ref();\n    trace!(\"sync {}\", display_path(path));\n    let dir = File::open(path)\n        .wrap_err_with(|| format!(\"failed to open dir for sync: {}\", display_path(path)))?;\n    dir.sync_all()\n        .wrap_err_with(|| format!(\"failed to sync dir: {}\", display_path(path)))\n}\n\n#[cfg(windows)]\npub fn sync_dir<P: AsRef<Path>>(_path: P) -> Result<()> {\n    // Not implemented on Windows\n    Ok(())\n}\n\npub fn modified_duration(path: &Path) -> Result<Duration> {\n    let metadata = path.metadata()?;\n    let modified = metadata.modified()?;\n    let duration = modified.elapsed().unwrap_or_default();\n    Ok(duration)\n}\n\npub fn find_up<FN: AsRef<str>>(from: &Path, filenames: &[FN]) -> Option<PathBuf> {\n    let mut current = from.to_path_buf();\n    loop {\n        for filename in filenames {\n            let path = current.join(filename.as_ref());\n            if path.exists() {\n                return Some(path);\n            }\n        }\n        if !current.pop() {\n            return None;\n        }\n    }\n}\n\npub fn dir_subdirs(dir: &Path) -> Result<BTreeSet<String>> {\n    let mut output = Default::default();\n\n    if !dir.exists() {\n        return Ok(output);\n    }\n\n    for entry in dir.read_dir()? {\n        let entry = entry?;\n        let ft = entry.file_type()?;\n        if ft.is_dir() || (ft.is_symlink() && entry.path().is_dir()) {\n            output.insert(entry.file_name().into_string().unwrap());\n        }\n    }\n\n    Ok(output)\n}\n\npub fn ls(dir: &Path) -> Result<BTreeSet<PathBuf>> {\n    let mut output = Default::default();\n\n    if !dir.is_dir() {\n        return Ok(output);\n    }\n\n    for entry in dir.read_dir()? {\n        let entry = entry?;\n        output.insert(entry.path());\n    }\n\n    Ok(output)\n}\n\npub fn recursive_ls(dir: &Path) -> Result<BTreeSet<PathBuf>> {\n    if !dir.is_dir() {\n        return Ok(Default::default());\n    }\n\n    Ok(WalkDir::new(dir)\n        .follow_links(true)\n        .into_iter()\n        .filter_ok(|e| e.file_type().is_file())\n        .map_ok(|e| e.path().to_path_buf())\n        .try_collect()?)\n}\n\n#[cfg(unix)]\npub fn make_symlink(target: &Path, link: &Path) -> Result<(PathBuf, PathBuf)> {\n    trace!(\"ln -sf {} {}\", target.display(), link.display());\n    if link.is_file() || link.is_symlink() {\n        fs::remove_file(link)?;\n    }\n    symlink(target, link)\n        .wrap_err_with(|| format!(\"failed to ln -sf {} {}\", target.display(), link.display()))?;\n    Ok((target.to_path_buf(), link.to_path_buf()))\n}\n\n#[cfg(unix)]\npub fn make_symlink_or_copy(target: &Path, link: &Path) -> Result<()> {\n    make_symlink(target, link)?;\n    Ok(())\n}\n\n#[cfg(windows)]\npub fn make_symlink_or_copy(target: &Path, link: &Path) -> Result<()> {\n    copy(target, link)?;\n    Ok(())\n}\n\n#[cfg(windows)]\npub fn make_symlink(target: &Path, link: &Path) -> Result<(PathBuf, PathBuf)> {\n    if let Err(err) = junction::create(target, link) {\n        if err.kind() == std::io::ErrorKind::AlreadyExists {\n            let _ = fs::remove_file(link);\n            junction::create(target, link)\n        } else {\n            Err(err)\n        }\n    } else {\n        Ok(())\n    }\n    .wrap_err_with(|| format!(\"failed to ln -sf {} {}\", target.display(), link.display()))?;\n    Ok((target.to_path_buf(), link.to_path_buf()))\n}\n\n#[cfg(windows)]\npub fn make_symlink_or_file(target: &Path, link: &Path) -> Result<()> {\n    trace!(\"ln -sf {} {}\", target.display(), link.display());\n    if link.is_file() || link.is_symlink() {\n        // remove existing file if exists\n        fs::remove_file(link)?;\n    }\n    xx::file::write(link, target.to_string_lossy().to_string())?;\n    Ok(())\n}\n\npub fn resolve_symlink(link: &Path) -> Result<Option<PathBuf>> {\n    // Windows symlink are write in file currently\n    // may be changed to symlink in the future\n    if link.is_symlink() {\n        Ok(Some(fs::read_link(link)?))\n    } else if link.is_file() {\n        Ok(Some(fs::read_to_string(link)?.into()))\n    } else {\n        Ok(None)\n    }\n}\n\n#[cfg(unix)]\npub fn make_symlink_or_file(target: &Path, link: &Path) -> Result<()> {\n    make_symlink(target, link)?;\n    Ok(())\n}\n\npub fn remove_symlinks_with_target_prefix(\n    symlink_dir: &Path,\n    target_prefix: &Path,\n) -> Result<Vec<PathBuf>> {\n    if !symlink_dir.exists() {\n        return Ok(vec![]);\n    }\n    let mut removed = vec![];\n    for entry in symlink_dir.read_dir()? {\n        let entry = entry?;\n        let path = entry.path();\n        if path.is_symlink() {\n            let target = path.read_link()?;\n            if target.starts_with(target_prefix) {\n                fs::remove_file(&path)?;\n                removed.push(path);\n            }\n        }\n    }\n    Ok(removed)\n}\n\n#[cfg(unix)]\npub fn is_executable(path: &Path) -> bool {\n    if let Ok(metadata) = path.metadata() {\n        return metadata.permissions().mode() & 0o111 != 0;\n    }\n    false\n}\n\n#[cfg(windows)]\npub fn is_executable(path: &Path) -> bool {\n    if has_known_executable_extension(path) {\n        return true;\n    }\n    has_shebang(path)\n}\n\n#[cfg(windows)]\npub fn has_known_executable_extension(path: &Path) -> bool {\n    path.extension().map_or(\n        Settings::get()\n            .windows_executable_extensions\n            .contains(&String::new()),\n        |ext| {\n            if let Some(str_val) = ext.to_str() {\n                return Settings::get()\n                    .windows_executable_extensions\n                    .contains(&str_val.to_lowercase().to_string());\n            }\n            false\n        },\n    )\n}\n\n/// Check if a file starts with a shebang (#!).\n/// Only reads the first 2 bytes to minimize I/O during task discovery.\n#[cfg(windows)]\npub fn has_shebang(path: &Path) -> bool {\n    std::fs::File::open(path)\n        .and_then(|mut f| {\n            use std::io::Read;\n            let mut buf = [0u8; 2];\n            f.read_exact(&mut buf)?;\n            Ok(buf == *b\"#!\")\n        })\n        .unwrap_or(false)\n}\n\n#[cfg(unix)]\npub fn make_executable<P: AsRef<Path>>(path: P) -> Result<()> {\n    trace!(\"chmod +x {}\", display_path(&path));\n    let path = path.as_ref();\n    let mut perms = path.metadata()?.permissions();\n    perms.set_mode(perms.mode() | 0o111);\n    fs::set_permissions(path, perms)\n        .wrap_err_with(|| format!(\"failed to chmod +x: {}\", display_path(path)))?;\n    Ok(())\n}\n\n#[cfg(windows)]\npub fn make_executable<P: AsRef<Path>>(_path: P) -> Result<()> {\n    Ok(())\n}\n\n#[cfg(unix)]\npub async fn make_executable_async<P: AsRef<Path>>(path: P) -> Result<()> {\n    trace!(\"chmod +x {}\", display_path(&path));\n    let path = path.as_ref();\n    let mut perms = path.metadata()?.permissions();\n    perms.set_mode(perms.mode() | 0o111);\n    tokio::fs::set_permissions(path, perms)\n        .await\n        .wrap_err_with(|| format!(\"failed to chmod +x: {}\", display_path(path)))\n}\n\n#[cfg(windows)]\npub async fn make_executable_async<P: AsRef<Path>>(_path: P) -> Result<()> {\n    Ok(())\n}\n\npub fn all_dirs<P: AsRef<Path>>(\n    start_dir: P,\n    ceiling_dirs: &HashSet<PathBuf>,\n) -> Result<Vec<PathBuf>> {\n    trace!(\n        \"file::all_dirs Collecting all ancestors of {} until ceiling {:?}\",\n        display_path(&start_dir),\n        ceiling_dirs\n    );\n    Ok(start_dir\n        .as_ref()\n        .ancestors()\n        .map_while(|p| {\n            if ceiling_dirs.contains(p) {\n                debug!(\n                    \"file::all_dirs Reached ceiling directory: {}\",\n                    display_path(p)\n                );\n                None\n            } else {\n                trace!(\n                    \"file::all_dirs Adding ancestor directory: {}\",\n                    display_path(p)\n                );\n                Some(p.to_path_buf())\n            }\n        })\n        .collect())\n}\n\nfn is_empty_dir(path: &Path) -> Result<bool> {\n    path.read_dir()\n        .map(|mut i| i.next().is_none())\n        .wrap_err_with(|| format!(\"failed to read_dir: {}\", display_path(path)))\n}\n\nfn is_empty_dir_ignore(path: &Path, ignore_files: Vec<&str>) -> Result<bool> {\n    path.read_dir()\n        .map(|mut i| {\n            i.all(|entry| match entry {\n                Ok(entry) => ignore_files.iter().any(|ignore_file| {\n                    entry\n                        .file_name()\n                        .to_string_lossy()\n                        .eq_ignore_ascii_case(ignore_file)\n                }),\n                Err(_) => false,\n            })\n        })\n        .wrap_err_with(|| format!(\"failed to read_dir: {}\", display_path(path)))\n}\n\npub struct FindUp {\n    current_dir: PathBuf,\n    current_dir_filenames: Vec<String>,\n    filenames: Vec<String>,\n}\n\nimpl FindUp {\n    pub fn new(from: &Path, filenames: &[String]) -> Self {\n        let filenames: Vec<String> = filenames.iter().map(|s| s.to_string()).collect();\n        Self {\n            current_dir: from.to_path_buf(),\n            filenames: filenames.clone(),\n            current_dir_filenames: filenames,\n        }\n    }\n}\n\nimpl Iterator for FindUp {\n    type Item = PathBuf;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        while let Some(filename) = self.current_dir_filenames.pop() {\n            let path = self.current_dir.join(filename);\n            if path.is_file() {\n                return Some(path);\n            }\n        }\n        self.current_dir_filenames.clone_from(&self.filenames);\n        if cfg!(test) && self.current_dir == *dirs::HOME {\n            return None; // in tests, do not recurse further than ./test\n        }\n        if !self.current_dir.pop() {\n            return None;\n        }\n        self.next()\n    }\n}\n\n/// returns the first executable in PATH\n/// will not include mise bin paths or other paths added by mise\npub fn which<P: AsRef<Path>>(name: P) -> Option<PathBuf> {\n    static CACHE: Lazy<Mutex<HashMap<PathBuf, Option<PathBuf>>>> = Lazy::new(Default::default);\n\n    let name = name.as_ref();\n    if let Some(path) = CACHE.lock().unwrap().get(name) {\n        return path.clone();\n    }\n    let path = _which(name, &env::PATH);\n    CACHE\n        .lock()\n        .unwrap()\n        .insert(name.to_path_buf(), path.clone());\n    path\n}\n\n/// returns the first executable in PATH\n/// will include mise bin paths or other paths added by mise\npub fn which_non_pristine<P: AsRef<Path>>(name: P) -> Option<PathBuf> {\n    _which(name, &env::PATH_NON_PRISTINE)\n}\n\n/// returns the first executable in PATH, excluding the mise shim directory\n/// use this for internal tool lookups to avoid recursive shim invocations\n/// (shims call `mise exec`, which would re-enter the same code path)\npub fn which_no_shims<P: AsRef<Path>>(name: P) -> Option<PathBuf> {\n    let shim_dir = &*dirs::SHIMS;\n    let paths: Vec<PathBuf> = env::PATH_NON_PRISTINE\n        .iter()\n        .filter(|p| p.as_path() != *shim_dir)\n        .cloned()\n        .collect();\n    _which(name, &paths)\n}\n\nfn _which<P: AsRef<Path>>(name: P, paths: &[PathBuf]) -> Option<PathBuf> {\n    let name = name.as_ref();\n    paths.iter().find_map(|path| {\n        let bin = path.join(name);\n        if is_executable(&bin) { Some(bin) } else { None }\n    })\n}\n\npub fn un_gz(input: &Path, dest: &Path) -> Result<()> {\n    debug!(\"gunzip {} > {}\", input.display(), dest.display());\n    let f = File::open(input)?;\n    let mut dec = GzDecoder::new(f);\n    let mut output = File::create(dest)?;\n    std::io::copy(&mut dec, &mut output)\n        .wrap_err_with(|| format!(\"failed to un-gzip: {}\", display_path(input)))?;\n    Ok(())\n}\n\npub fn un_xz(input: &Path, dest: &Path) -> Result<()> {\n    debug!(\"xz -d {} -c > {}\", input.display(), dest.display());\n    let f = File::open(input)?;\n    let mut dec = xz2::read::XzDecoder::new(f);\n    let mut output = File::create(dest)?;\n    std::io::copy(&mut dec, &mut output)\n        .wrap_err_with(|| format!(\"failed to un-xz: {}\", display_path(input)))?;\n    Ok(())\n}\n\npub fn un_zst(input: &Path, dest: &Path) -> Result<()> {\n    debug!(\"zstd -d {} -c > {}\", input.display(), dest.display());\n    let f = File::open(input)?;\n    let mut dec = zstd::Decoder::new(f)?;\n    let mut output = File::create(dest)?;\n    std::io::copy(&mut dec, &mut output)\n        .wrap_err_with(|| format!(\"failed to un-zst: {}\", display_path(input)))?;\n    Ok(())\n}\n\npub fn un_bz2(input: &Path, dest: &Path) -> Result<()> {\n    debug!(\"bzip2 -d {} -c > {}\", input.display(), dest.display());\n    let f = File::open(input)?;\n    let mut dec = BzDecoder::new(f);\n    let mut output = File::create(dest)?;\n    std::io::copy(&mut dec, &mut output)\n        .wrap_err_with(|| format!(\"failed to un-bz2: {}\", display_path(input)))?;\n    Ok(())\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, strum::EnumString, strum::Display)]\npub enum TarFormat {\n    #[strum(serialize = \"tar.gz\", serialize = \"tgz\")]\n    TarGz,\n    #[strum(serialize = \"gz\")]\n    Gz,\n    #[strum(serialize = \"tar.xz\", serialize = \"txz\")]\n    TarXz,\n    #[strum(serialize = \"xz\")]\n    Xz,\n    #[strum(serialize = \"tar.bz2\", serialize = \"tbz2\")]\n    TarBz2,\n    #[strum(serialize = \"bz2\")]\n    Bz2,\n    #[strum(serialize = \"tar.zst\", serialize = \"tzst\")]\n    TarZst,\n    #[strum(serialize = \"zst\")]\n    Zst,\n    #[strum(serialize = \"tar\")]\n    Tar,\n    #[strum(serialize = \"zip\", serialize = \"vsix\")]\n    Zip,\n    #[strum(serialize = \"7z\")]\n    SevenZip,\n    #[strum(serialize = \"raw\")]\n    Raw,\n}\n\nimpl TarFormat {\n    pub fn from_file_name(filename: &str) -> Self {\n        let filename = filename.to_lowercase();\n\n        if let Some(idx) = filename.rfind(\".tar.\") {\n            let ext = &filename[idx + 1..];\n            let fmt = Self::from_ext(ext);\n            if fmt != TarFormat::Raw {\n                return fmt;\n            }\n        }\n\n        if let Some(ext) = Path::new(&filename).extension().and_then(|s| s.to_str()) {\n            Self::from_ext(ext)\n        } else {\n            TarFormat::Raw\n        }\n    }\n\n    pub fn from_ext(ext: &str) -> Self {\n        ext.to_lowercase().parse().unwrap_or(TarFormat::Raw)\n    }\n\n    pub fn is_archive(&self) -> bool {\n        match self {\n            TarFormat::TarGz\n            | TarFormat::TarXz\n            | TarFormat::TarBz2\n            | TarFormat::TarZst\n            | TarFormat::Tar\n            | TarFormat::Zip\n            | TarFormat::SevenZip => true,\n            TarFormat::Gz | TarFormat::Xz | TarFormat::Bz2 | TarFormat::Zst | TarFormat::Raw => {\n                false\n            }\n        }\n    }\n\n    pub fn extension(&self) -> Option<&'static str> {\n        match self {\n            TarFormat::TarGz => Some(\"tar.gz\"),\n            TarFormat::Gz => Some(\"gz\"),\n            TarFormat::TarXz => Some(\"tar.xz\"),\n            TarFormat::Xz => Some(\"xz\"),\n            TarFormat::TarBz2 => Some(\"tar.bz2\"),\n            TarFormat::Bz2 => Some(\"bz2\"),\n            TarFormat::TarZst => Some(\"tar.zst\"),\n            TarFormat::Zst => Some(\"zst\"),\n            TarFormat::Tar => Some(\"tar\"),\n            TarFormat::Zip => Some(\"zip\"),\n            TarFormat::SevenZip => Some(\"7z\"),\n            TarFormat::Raw => None,\n        }\n    }\n}\n\npub struct TarOptions<'a> {\n    pub format: TarFormat,\n    pub strip_components: usize,\n    pub pr: Option<&'a dyn SingleReport>,\n    /// When false, files will be extracted with current timestamp instead of archive's mtime\n    pub preserve_mtime: bool,\n}\n\nimpl<'a> TarOptions<'a> {\n    pub fn new(format: TarFormat) -> Self {\n        Self {\n            format,\n            strip_components: 0,\n            pr: None,\n            preserve_mtime: true,\n        }\n    }\n}\n\npub fn untar(archive: &Path, dest: &Path, opts: &TarOptions) -> Result<()> {\n    if opts.format == TarFormat::Zip {\n        return unzip(\n            archive,\n            dest,\n            &ZipOptions {\n                strip_components: opts.strip_components,\n            },\n        );\n    } else if opts.format == TarFormat::SevenZip {\n        #[cfg(windows)]\n        return un7z(\n            archive,\n            dest,\n            &SevenZipOptions {\n                strip_components: opts.strip_components,\n            },\n        );\n    }\n\n    debug!(\"tar -xf {} -C {}\", archive.display(), dest.display());\n    if let Some(pr) = &opts.pr {\n        pr.set_message(format!(\n            \"extract {}\",\n            archive.file_name().unwrap().to_string_lossy()\n        ));\n    }\n\n    let err = || {\n        let archive = display_path(archive);\n        let dest = display_path(dest);\n        format!(\"failed to extract tar: {archive} to {dest}\")\n    };\n\n    let format = opts.format;\n    if !format.is_archive() && format != TarFormat::Raw {\n        let mut reader = open_tar(format, archive)?;\n        // If dest is a directory, join with the archive filename (minus extension)\n        // If dest is not a dir, assume it's the target file path\n        let out_path = if dest.is_dir() {\n            let name = archive\n                .file_stem()\n                .unwrap_or_else(|| archive.file_name().unwrap());\n            dest.join(name)\n        } else {\n            dest.to_path_buf()\n        };\n\n        if let Some(parent) = out_path.parent() {\n            create_dir_all(parent).wrap_err_with(err)?;\n        }\n        let mut out = File::create(&out_path).wrap_err_with(err)?;\n        std::io::copy(&mut reader, &mut out).wrap_err_with(err)?;\n        return Ok(());\n    }\n\n    let tar = open_tar(format, archive)?;\n    // TODO: put this back in when we can read+write in parallel\n    // let mut cur = Cursor::new(vec![]);\n    // let mut total = 0;\n    // loop {\n    //     let mut buf = Cursor::new(vec![0; 1024 * 1024]);\n    //     let n = tar.read(buf.get_mut()).wrap_err_with(err)?;\n    //     cur.get_mut().extend_from_slice(&buf.get_ref()[..n]);\n    //     if n == 0 {\n    //         break;\n    //     }\n    //     if let Some(pr) = &opts.pr {\n    //         total += n as u64;\n    //         pr.set_length(total);\n    //     }\n    // }\n    create_dir_all(dest).wrap_err_with(err)?;\n\n    // Try to extract using the tar crate, detecting sparse files during extraction\n    let mut needs_system_tar = false;\n    for entry in Archive::new(tar).entries().wrap_err_with(err)? {\n        let mut entry = entry.wrap_err_with(err)?;\n\n        // Check if this is a GNU sparse file\n        if entry.header().entry_type().is_gnu_sparse() {\n            debug!(\"Detected GNU sparse file, falling back to system tar\");\n            needs_system_tar = true;\n            // Clean up any partial extraction\n            remove_all(dest)?;\n            create_dir_all(dest)?;\n            break;\n        }\n\n        // Configure mtime preservation based on options\n        entry.set_preserve_mtime(opts.preserve_mtime);\n\n        trace!(\"extracting {}\", entry.path().wrap_err_with(err)?.display());\n        entry.unpack_in(dest).wrap_err_with(err)?;\n    }\n\n    // Check for the GNUSparseFile.0 directory which indicates the tar crate\n    // incorrectly handled a sparse file\n    if !needs_system_tar {\n        let sparse_dir = dest.join(\"GNUSparseFile.0\");\n        if sparse_dir.exists() && sparse_dir.is_dir() {\n            debug!(\"Found GNUSparseFile.0 directory, using system tar\");\n            needs_system_tar = true;\n            // Clean up the bad extraction\n            remove_all(dest)?;\n            create_dir_all(dest)?;\n        }\n    }\n\n    if needs_system_tar {\n        // Use system tar for archives with problematic sparse files\n        // The tar crate doesn't properly handle certain GNU sparse formats\n        debug!(\"Using system tar for: {}\", archive.display());\n\n        // When preserve_mtime is false, use -m flag to not restore modification times\n        // This causes extracted files to have current time, which is important for\n        // cache invalidation and autopruning. Works on both BSD and GNU tar.\n        if !opts.preserve_mtime {\n            cmd!(\"tar\", \"-mxf\", archive, \"-C\", dest)\n                .run()\n                .wrap_err_with(|| {\n                    format!(\"Failed to extract {} using system tar\", archive.display())\n                })?;\n        } else {\n            cmd!(\"tar\", \"-xf\", archive, \"-C\", dest)\n                .run()\n                .wrap_err_with(|| {\n                    format!(\"Failed to extract {} using system tar\", archive.display())\n                })?;\n        }\n    }\n\n    // Always use our manual strip to ensure consistent behavior across backends\n    strip_archive_path_components(dest, opts.strip_components).wrap_err_with(err)?;\n    Ok(())\n}\n\nfn open_tar(format: TarFormat, archive: &Path) -> Result<Box<dyn std::io::Read>> {\n    let f = File::open(archive)?;\n    Ok(match format {\n        // TODO: we probably shouldn't assume raw is tar.gz, but this was to retain existing behavior\n        TarFormat::TarGz | TarFormat::Gz | TarFormat::Raw => Box::new(GzDecoder::new(f)),\n        TarFormat::TarXz | TarFormat::Xz => Box::new(xz2::read::XzDecoder::new(f)),\n        TarFormat::TarBz2 | TarFormat::Bz2 => Box::new(BzDecoder::new(f)),\n        TarFormat::TarZst | TarFormat::Zst => Box::new(zstd::stream::read::Decoder::new(f)?),\n        TarFormat::Tar => Box::new(f),\n        TarFormat::Zip => bail!(\"zip format not supported\"),\n        TarFormat::SevenZip => bail!(\"7z format not supported\"),\n    })\n}\n\nfn strip_archive_path_components(dir: &Path, strip_depth: usize) -> Result<()> {\n    if strip_depth == 0 {\n        return Ok(());\n    }\n    if strip_depth > 1 {\n        bail!(\"strip-components > 1 is not supported\");\n    }\n\n    let top_level_paths = ls(dir)?;\n\n    for path in top_level_paths {\n        if !path.symlink_metadata()?.is_dir() {\n            continue;\n        }\n\n        // rename the directory to a temp name to avoid conflicts when moving files\n        let temp_path = path.with_file_name(format!(\n            \"{}_tmp_strip\",\n            path.file_name().unwrap().to_string_lossy()\n        ));\n        fs::rename(&path, &temp_path)?;\n\n        for entry in ls(&temp_path)? {\n            if let Some(file_name) = entry.file_name() {\n                let dest_path = dir.join(file_name);\n                fs::rename(entry, dest_path)?;\n            } else {\n                continue;\n            }\n        }\n\n        remove_dir(temp_path)?;\n    }\n    Ok(())\n}\n\n#[derive(Default)]\npub struct ZipOptions {\n    pub strip_components: usize,\n}\n\npub fn unzip(archive: &Path, dest: &Path, opts: &ZipOptions) -> Result<()> {\n    // TODO: show progress\n    debug!(\"unzip {} -d {}\", archive.display(), dest.display());\n    ZipArchive::new(File::open(archive)?)\n        .wrap_err_with(|| format!(\"failed to open zip archive: {}\", display_path(archive)))?\n        .extract(dest)\n        .wrap_err_with(|| format!(\"failed to extract zip archive: {}\", display_path(archive)))?;\n\n    strip_archive_path_components(dest, opts.strip_components).wrap_err_with(|| {\n        format!(\n            \"failed to strip path components from zip archive: {}\",\n            display_path(archive)\n        )\n    })\n}\n\npub fn un_dmg(archive: &Path, dest: &Path) -> Result<()> {\n    debug!(\n        \"hdiutil attach -quiet -nobrowse -mountpoint {} {}\",\n        dest.display(),\n        archive.display()\n    );\n    let tmp = tempfile::TempDir::new()?;\n    cmd!(\n        \"hdiutil\",\n        \"attach\",\n        \"-quiet\",\n        \"-nobrowse\",\n        \"-mountpoint\",\n        tmp.path(),\n        archive.to_path_buf()\n    )\n    .run()?;\n    copy_dir_all(tmp.path(), dest)?;\n    cmd!(\"hdiutil\", \"detach\", tmp.path()).run()?;\n    Ok(())\n}\n\npub fn un_pkg(archive: &Path, dest: &Path) -> Result<()> {\n    debug!(\n        \"pkgutil --expand-full {} {}\",\n        archive.display(),\n        dest.display()\n    );\n    cmd!(\"pkgutil\", \"--expand-full\", archive, dest).run()?;\n    Ok(())\n}\n\n#[cfg(windows)]\n#[derive(Default)]\npub struct SevenZipOptions {\n    pub strip_components: usize,\n}\n\n#[cfg(windows)]\npub fn un7z(archive: &Path, dest: &Path, opts: &SevenZipOptions) -> Result<()> {\n    sevenz_rust::decompress_file(archive, dest)\n        .wrap_err_with(|| format!(\"failed to extract 7z archive: {}\", display_path(archive)))?;\n\n    strip_archive_path_components(dest, opts.strip_components).wrap_err_with(|| {\n        format!(\n            \"failed to strip path components from 7z archive: {}\",\n            display_path(archive)\n        )\n    })\n}\n\npub fn split_file_name(path: &Path) -> (String, String) {\n    let file_name = path.file_name().unwrap().to_string_lossy();\n    let (file_name_base, ext) = file_name\n        .split_once('.')\n        .unwrap_or((file_name.as_ref(), \"\"));\n    (file_name_base.to_string(), ext.to_string())\n}\n\npub fn same_file(a: &Path, b: &Path) -> bool {\n    desymlink_path(a) == desymlink_path(b)\n}\n\npub fn desymlink_path(p: &Path) -> PathBuf {\n    if p.is_symlink()\n        && let Ok(target) = fs::read_link(p)\n    {\n        return target\n            .canonicalize()\n            .unwrap_or_else(|_| target.to_path_buf());\n    }\n    p.canonicalize().unwrap_or_else(|_| p.to_path_buf())\n}\n\npub fn clone_dir(from: &PathBuf, to: &PathBuf) -> Result<()> {\n    if cfg!(macos) {\n        cmd!(\"cp\", \"-cR\", from, to).run()?;\n    } else if cfg!(windows) {\n        cmd!(\"robocopy\", from, to, \"/MIR\").run()?;\n    } else {\n        cmd!(\"cp\", \"--reflink=auto\", \"-r\", from, to).run()?;\n    }\n    Ok(())\n}\n\n/// Inspects the top-level contents of a tar archive without extracting it\n/// Skips leading CurDir (\".\") components from a path's components iterator.\n/// Archives often have paths like \"./foo/bar\" where the leading \".\" should be ignored.\nfn skip_curdir_components(path: &Path) -> impl Iterator<Item = std::path::Component<'_>> {\n    path.components()\n        .skip_while(|c| matches!(c, std::path::Component::CurDir))\n}\n\npub fn inspect_tar_contents(archive: &Path, format: TarFormat) -> Result<Vec<(String, bool)>> {\n    let tar = open_tar(format, archive)?;\n    let mut archive = Archive::new(tar);\n    let mut top_level_components = std::collections::HashMap::new();\n\n    for entry in archive.entries()? {\n        let entry = entry?;\n        let path = entry.path()?;\n        let header = entry.header();\n\n        // Get the first non-CurDir component of the path (top-level directory/file)\n        let mut components = skip_curdir_components(&path);\n\n        if let Some(first_component) = components.next() {\n            let name = first_component.as_os_str().to_string_lossy().to_string();\n\n            // Check if this entry indicates the component is a directory\n            // It's a directory if the entry type is dir OR if there are more components after the first\n            let is_directory = header.entry_type().is_dir() || components.next().is_some();\n\n            // Update the component's directory status\n            // A component is a directory if ANY entry indicates it's a directory\n            let existing = top_level_components.entry(name.clone()).or_insert(false);\n            *existing = *existing || is_directory;\n        }\n    }\n\n    Ok(top_level_components.into_iter().collect())\n}\n\n/// Inspects the top-level contents of a zip archive without extracting it\npub fn inspect_zip_contents(archive: &Path) -> Result<Vec<(String, bool)>> {\n    let f = File::open(archive)?;\n    let mut archive = ZipArchive::new(f)\n        .wrap_err_with(|| format!(\"failed to open zip archive: {}\", display_path(archive)))?;\n    let mut top_level_components = std::collections::HashMap::new();\n\n    for i in 0..archive.len() {\n        let file = archive.by_index(i)?;\n        if let Some(path) = file.enclosed_name() {\n            // Get the first non-CurDir component of the path (top-level directory/file)\n            let mut components = skip_curdir_components(&path);\n\n            if let Some(first_component) = components.next() {\n                let name = first_component.as_os_str().to_string_lossy().to_string();\n\n                // Check if this entry indicates the component is a directory\n                // It's a directory if the entry type is dir OR if there are more components after the first\n                let is_directory = file.is_dir() || components.next().is_some();\n\n                let existing = top_level_components.entry(name.clone()).or_insert(false);\n                *existing = *existing || is_directory;\n            }\n        }\n    }\n\n    Ok(top_level_components.into_iter().collect())\n}\n\n/// Adapted from inspect_tar_contents for 7z archives\n#[cfg(windows)]\npub fn inspect_7z_contents(archive: &Path) -> Result<Vec<(String, bool)>> {\n    let sevenz = sevenz_rust::SevenZReader::open(archive, sevenz_rust::Password::empty())?;\n    let mut top_level_components = std::collections::HashMap::new();\n\n    for file in &sevenz.archive().files {\n        let path = PathBuf::from(file.name());\n\n        // Get the first non-CurDir component of the path (top-level directory/file)\n        let mut components = skip_curdir_components(&path);\n\n        if let Some(first_component) = components.next() {\n            let name = first_component.as_os_str().to_string_lossy().to_string();\n            // It's a directory if the entry type is dir OR if there are more components after the first\n            let is_directory = file.is_directory() || components.next().is_some();\n\n            let existing = top_level_components.entry(name.clone()).or_insert(false);\n            *existing = *existing || is_directory;\n        }\n    }\n\n    Ok(top_level_components.into_iter().collect())\n}\n\n#[cfg(not(windows))]\npub fn inspect_7z_contents(_archive: &Path) -> Result<Vec<(String, bool)>> {\n    unimplemented!(\"7z format not supported on this platform\")\n}\n\n/// Determines if strip_components=1 should be applied based on archive structure\npub fn should_strip_components(archive: &Path, format: TarFormat) -> Result<bool> {\n    let top_level_entries = match format {\n        TarFormat::Zip => inspect_zip_contents(archive)?,\n        TarFormat::SevenZip => inspect_7z_contents(archive)?,\n        _ => inspect_tar_contents(archive, format)?,\n    };\n\n    // If there's exactly one top-level entry and it's a directory, we should strip it\n    if top_level_entries.len() == 1 {\n        let (_, is_directory) = &top_level_entries[0];\n        Ok(*is_directory)\n    } else {\n        Ok(false)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_find_up() {\n        let _config = Config::get().await.unwrap();\n        let path = &env::current_dir().unwrap();\n        let filenames = vec![\".miserc\", \".mise.toml\", \".test-tool-versions\"]\n            .into_iter()\n            .map(|s| s.to_string())\n            .collect_vec();\n        #[allow(clippy::needless_collect)]\n        let find_up = FindUp::new(path, &filenames).collect::<Vec<_>>();\n        let mut find_up = find_up.into_iter();\n        assert_eq!(\n            find_up.next(),\n            Some(dirs::HOME.join(\"cwd/.test-tool-versions\"))\n        );\n        assert_eq!(find_up.next(), Some(dirs::HOME.join(\".test-tool-versions\")));\n    }\n\n    #[tokio::test]\n    async fn test_find_up_2() {\n        let _config = Config::get().await.unwrap();\n        let path = &dirs::HOME.join(\"fixtures\");\n        let filenames = vec![\".test-tool-versions\"];\n        let result = find_up(path, &filenames);\n        assert_eq!(result, Some(dirs::HOME.join(\".test-tool-versions\")));\n    }\n\n    #[tokio::test]\n    async fn test_dir_subdirs() {\n        let _config = Config::get().await.unwrap();\n        let subdirs = dir_subdirs(&dirs::HOME).unwrap();\n        assert!(subdirs.contains(\"cwd\"));\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_display_path() {\n        let _config = Config::get().await.unwrap();\n        use std::ops::Deref;\n        let path = dirs::HOME.join(\"cwd\");\n        assert_eq!(display_path(path), \"~/cwd\");\n\n        let path = Path::new(\"/tmp\")\n            .join(dirs::HOME.deref().strip_prefix(\"/\").unwrap())\n            .join(\"cwd\");\n        assert_eq!(display_path(&path), path.display().to_string());\n    }\n\n    #[tokio::test]\n    async fn test_replace_path() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(replace_path(Path::new(\"~/cwd\")), dirs::HOME.join(\"cwd\"));\n        assert_eq!(replace_path(Path::new(\"/cwd\")), Path::new(\"/cwd\"));\n    }\n\n    #[test]\n    fn test_should_strip_components() {\n        // Test that the function correctly identifies when to strip components\n        // This is a basic test to ensure the logic works correctly\n\n        // For now, we'll test with a non-existent file to ensure the function\n        // returns false when it can't read the archive\n        let non_existent_path = Path::new(\"/non/existent/archive.tar.gz\");\n        let result = should_strip_components(non_existent_path, TarFormat::TarGz);\n        assert!(result.is_err()); // Should fail to open non-existent file\n\n        // Note: To properly test this function, we would need actual tar archives\n        // with different structures (single file, single directory, multiple entries)\n        // This would require creating test fixtures, which is beyond the scope\n        // of this fix. The important thing is that the logic now correctly\n        // checks if the single entry is a directory before deciding to strip.\n    }\n\n    #[test]\n    fn test_inspect_tar_contents_logic() {\n        // Test the logic of inspect_tar_contents with simulated data\n        // This tests the core logic without requiring actual tar files\n\n        // Simulate a HashMap that would be returned by inspect_tar_contents\n        // for an archive with a single directory containing files\n        let mut components = std::collections::HashMap::new();\n        components.insert(\"mydir\".to_string(), true); // Directory with nested files\n\n        let result: Vec<(String, bool)> = components.into_iter().collect();\n\n        // Should have exactly one entry that is a directory\n        assert_eq!(result.len(), 1);\n        let (name, is_directory) = &result[0];\n        assert_eq!(name, \"mydir\");\n        assert!(*is_directory);\n\n        // Test the should_strip_components logic with this result\n        // This simulates what would happen if inspect_tar_contents returned this\n        let should_strip = result.len() == 1 && result[0].1;\n        assert!(should_strip);\n    }\n\n    #[test]\n    fn test_inspect_tar_contents_curdir_prefix() {\n        // Test that archives with \"./\" prefixed paths are handled correctly\n        // This reproduces the bug from https://github.com/jdx/mise/discussions/7862\n        use flate2::Compression;\n        use flate2::write::GzEncoder;\n        use tar::Builder;\n        use tempfile::NamedTempFile;\n\n        // Create a temp tar.gz with \"./\" prefixed paths (like unison's archive)\n        let temp_file = NamedTempFile::new().unwrap();\n        let gz = GzEncoder::new(temp_file.as_file(), Compression::default());\n        let mut builder = Builder::new(gz);\n\n        // Add entries with \"./\" prefix - simulating archive structure like:\n        // ./dir1/file1\n        // ./dir2/file2\n        // ./standalone\n        let mut header = tar::Header::new_gnu();\n        header.set_size(0);\n        header.set_mode(0o755);\n        header.set_entry_type(tar::EntryType::Regular);\n        header.set_cksum();\n\n        // Add ./dir1/file1\n        builder\n            .append_data(&mut header.clone(), \"./dir1/file1\", std::io::empty())\n            .unwrap();\n\n        // Add ./dir2/file2\n        builder\n            .append_data(&mut header.clone(), \"./dir2/file2\", std::io::empty())\n            .unwrap();\n\n        // Add ./standalone (file at root with ./ prefix)\n        builder\n            .append_data(&mut header.clone(), \"./standalone\", std::io::empty())\n            .unwrap();\n\n        let gz = builder.into_inner().unwrap();\n        gz.finish().unwrap();\n\n        // Now test inspect_tar_contents\n        let result = inspect_tar_contents(temp_file.path(), TarFormat::TarGz).unwrap();\n\n        // Should have 3 top-level entries: dir1, dir2, standalone\n        // NOT a single \".\" entry\n        assert_eq!(\n            result.len(),\n            3,\n            \"Expected 3 top-level entries, got: {:?}\",\n            result\n        );\n\n        let names: std::collections::HashSet<_> = result.iter().map(|(n, _)| n.as_str()).collect();\n        assert!(names.contains(\"dir1\"), \"Should contain dir1\");\n        assert!(names.contains(\"dir2\"), \"Should contain dir2\");\n        assert!(names.contains(\"standalone\"), \"Should contain standalone\");\n        assert!(!names.contains(\".\"), \"Should NOT contain '.' (CurDir)\");\n\n        // dir1 and dir2 should be marked as directories (have nested content)\n        for (name, is_dir) in &result {\n            if name == \"dir1\" || name == \"dir2\" {\n                assert!(*is_dir, \"{} should be marked as directory\", name);\n            } else if name == \"standalone\" {\n                assert!(!*is_dir, \"standalone should NOT be marked as directory\");\n            }\n        }\n\n        // Verify should_strip_components returns false (multiple top-level entries)\n        let should_strip = should_strip_components(temp_file.path(), TarFormat::TarGz).unwrap();\n        assert!(\n            !should_strip,\n            \"Should NOT strip components for multi-entry archive\"\n        );\n    }\n\n    #[test]\n    fn test_all_dirs_no_ceiling() {\n        let start_dir = Path::new(\"/a/b/c\");\n        let ceiling_dirs = HashSet::new();\n\n        let result = all_dirs(start_dir, &ceiling_dirs).unwrap();\n\n        assert_eq!(result.len(), 4);\n        assert!(result.contains(&PathBuf::from(\"/a/b/c\")));\n        assert!(result.contains(&PathBuf::from(\"/a/b\")));\n        assert!(result.contains(&PathBuf::from(\"/a\")));\n        assert!(result.contains(&PathBuf::from(\"/\")));\n    }\n\n    #[test]\n    fn test_all_dirs_with_ceiling() {\n        let start_dir = Path::new(\"/a/b/c\");\n        let mut ceiling_dirs = HashSet::new();\n        ceiling_dirs.insert(PathBuf::from(\"/a\"));\n\n        let result = all_dirs(start_dir, &ceiling_dirs).unwrap();\n\n        assert_eq!(result.len(), 2);\n        assert!(result.contains(&PathBuf::from(\"/a/b/c\")));\n        assert!(result.contains(&PathBuf::from(\"/a/b\")));\n        assert!(!result.contains(&PathBuf::from(\"/a\")));\n        assert!(!result.contains(&PathBuf::from(\"/\")));\n    }\n\n    #[test]\n    fn test_all_dirs_with_ceiling_at_start() {\n        let start_dir = Path::new(\"/a/b/c\");\n        let mut ceiling_dirs = HashSet::new();\n        ceiling_dirs.insert(PathBuf::from(\"/a/b/c\"));\n\n        let result = all_dirs(start_dir, &ceiling_dirs).unwrap();\n\n        assert_eq!(result.len(), 0);\n    }\n\n    #[test]\n    fn test_all_dirs_with_multiple_ceilings() {\n        let start_dir = Path::new(\"/a/b/c/d/e\");\n        let mut ceiling_dirs = HashSet::new();\n        ceiling_dirs.insert(PathBuf::from(\"/a/b\"));\n        ceiling_dirs.insert(PathBuf::from(\"/a/b/c/d\"));\n\n        let result = all_dirs(start_dir, &ceiling_dirs).unwrap();\n\n        assert_eq!(result.len(), 1);\n        assert!(result.contains(&PathBuf::from(\"/a/b/c/d/e\")));\n    }\n\n    #[test]\n    fn test_all_dirs_with_relative_path() {\n        let start_dir = Path::new(\"a/b/c\");\n        let ceiling_dirs = HashSet::new();\n\n        let result = all_dirs(start_dir, &ceiling_dirs).unwrap();\n\n        assert!(result.contains(&PathBuf::from(\"a/b/c\")));\n        assert!(result.contains(&PathBuf::from(\"a/b\")));\n        assert!(result.contains(&PathBuf::from(\"a\")));\n    }\n\n    #[test]\n    fn test_tar_format_from_file_name() {\n        assert_eq!(TarFormat::from_file_name(\"foo.tar.gz\"), TarFormat::TarGz);\n        assert_eq!(TarFormat::from_file_name(\"foo.tgz\"), TarFormat::TarGz);\n        assert_eq!(TarFormat::from_file_name(\"foo.tar.xz\"), TarFormat::TarXz);\n        assert_eq!(TarFormat::from_file_name(\"foo.txz\"), TarFormat::TarXz);\n        assert_eq!(TarFormat::from_file_name(\"foo.tar.bz2\"), TarFormat::TarBz2);\n        assert_eq!(TarFormat::from_file_name(\"foo.tbz2\"), TarFormat::TarBz2);\n        assert_eq!(TarFormat::from_file_name(\"foo.tar.zst\"), TarFormat::TarZst);\n        assert_eq!(TarFormat::from_file_name(\"foo.tzst\"), TarFormat::TarZst);\n        assert_eq!(TarFormat::from_file_name(\"foo.tar\"), TarFormat::Tar);\n        assert_eq!(TarFormat::from_file_name(\"foo.zip\"), TarFormat::Zip);\n        assert_eq!(TarFormat::from_file_name(\"foo.vsix\"), TarFormat::Zip);\n        assert_eq!(TarFormat::from_file_name(\"foo.7z\"), TarFormat::SevenZip);\n        assert_eq!(TarFormat::from_file_name(\"foo.gz\"), TarFormat::Gz);\n        assert_eq!(TarFormat::from_file_name(\"foo.xz\"), TarFormat::Xz);\n        assert_eq!(TarFormat::from_file_name(\"foo.bz2\"), TarFormat::Bz2);\n        assert_eq!(TarFormat::from_file_name(\"foo.zst\"), TarFormat::Zst);\n        assert_eq!(TarFormat::from_file_name(\"foo\"), TarFormat::Raw);\n        assert_eq!(TarFormat::from_file_name(\"foo.txt\"), TarFormat::Raw);\n    }\n\n    #[test]\n    fn test_untar_single_file() {\n        use flate2::Compression;\n        use flate2::write::GzEncoder;\n        use std::io::Write;\n        use tempfile::tempdir;\n\n        let dir = tempdir().unwrap();\n        let src_path = dir.path().join(\"test.gz\");\n        let dest_path = dir.path().join(\"test-out\");\n\n        // Create a dummy gzip file\n        let file = File::create(&src_path).unwrap();\n        let mut encoder = GzEncoder::new(file, Compression::default());\n        encoder.write_all(b\"hello world\").unwrap();\n        encoder.finish().unwrap();\n\n        // untar (decompress) it\n        untar(\n            &src_path,\n            &dest_path,\n            &TarOptions {\n                pr: None,\n                ..TarOptions::new(TarFormat::Gz)\n            },\n        )\n        .unwrap();\n\n        // Verify output\n        assert!(dest_path.exists());\n        assert!(dest_path.is_file());\n        let content = std::fs::read_to_string(&dest_path).unwrap();\n        assert_eq!(content, \"hello world\");\n    }\n\n    #[test]\n    fn test_untar_single_file_to_dir() {\n        use flate2::Compression;\n        use flate2::write::GzEncoder;\n        use std::io::Write;\n        use tempfile::tempdir;\n\n        let dir = tempdir().unwrap();\n        let src_path = dir.path().join(\"test_file.gz\");\n        let dest_dir = dir.path().join(\"out_dir\");\n        std::fs::create_dir(&dest_dir).unwrap();\n\n        // Create a dummy gzip file\n        let file = File::create(&src_path).unwrap();\n        let mut encoder = GzEncoder::new(file, Compression::default());\n        encoder.write_all(b\"hello world\").unwrap();\n        encoder.finish().unwrap();\n\n        // untar (decompress) it\n        untar(\n            &src_path,\n            &dest_dir,\n            &TarOptions {\n                pr: None,\n                ..TarOptions::new(TarFormat::Gz)\n            },\n        )\n        .unwrap();\n\n        // Verify output - should be out_dir/test_file\n        let expected_path = dest_dir.join(\"test_file\");\n        assert!(expected_path.exists());\n        assert!(expected_path.is_file());\n        let content = std::fs::read_to_string(&expected_path).unwrap();\n        assert_eq!(content, \"hello world\");\n    }\n}\n"
  },
  {
    "path": "src/forgejo.rs",
    "content": "use crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::{dirs, duration, env};\nuse eyre::Result;\nuse heck::ToKebabCase;\nuse reqwest::IntoUrl;\nuse reqwest::header::{HeaderMap, HeaderValue};\nuse serde_derive::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::sync::LazyLock as Lazy;\nuse tokio::sync::RwLock;\nuse tokio::sync::RwLockReadGuard;\nuse xx::regex;\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ForgejoRelease {\n    pub id: u64,\n    pub tag_name: String,\n    pub draft: bool,\n    pub prerelease: bool,\n    pub created_at: String,\n    pub assets: Vec<ForgejoAsset>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ForgejoAsset {\n    pub id: u64,\n    pub name: String,\n    // pub size: u64,\n    pub uuid: String,\n    pub browser_download_url: String,\n}\n\ntype CacheGroup<T> = HashMap<String, CacheManager<T>>;\n\nstatic RELEASES_CACHE: Lazy<RwLock<CacheGroup<Vec<ForgejoRelease>>>> = Lazy::new(Default::default);\n\nstatic RELEASE_CACHE: Lazy<RwLock<CacheGroup<ForgejoRelease>>> = Lazy::new(Default::default);\n\nasync fn get_releases_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<Vec<ForgejoRelease>>> {\n    RELEASES_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}-releases.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASES_CACHE.read().await\n}\n\nasync fn get_release_cache<'a>(key: &str) -> RwLockReadGuard<'a, CacheGroup<ForgejoRelease>> {\n    RELEASE_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASE_CACHE.read().await\n}\n\npub async fn list_releases_from_url(api_url: &str, repo: &str) -> Result<Vec<ForgejoRelease>> {\n    let key = format!(\"{api_url}-{repo}\").to_kebab_case();\n    let cache = get_releases_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_releases_(api_url, repo).await)\n        .await?\n        .to_vec())\n}\n\nasync fn list_releases_(api_url: &str, repo: &str) -> Result<Vec<ForgejoRelease>> {\n    let url = format!(\"{api_url}/repos/{repo}/releases\");\n    let headers = get_headers(&url);\n    let (mut releases, mut headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<ForgejoRelease>, _>(url, &headers)\n        .await?;\n\n    if *env::MISE_LIST_ALL_VERSIONS {\n        while let Some(next) = next_page(&headers) {\n            headers = get_headers(&next);\n            let (more, h) = crate::http::HTTP_FETCH\n                .json_headers_with_headers::<Vec<ForgejoRelease>, _>(next, &headers)\n                .await?;\n            releases.extend(more);\n            headers = h;\n        }\n    }\n    releases.retain(|r| !r.draft && !r.prerelease);\n\n    Ok(releases)\n}\n\npub async fn get_release_for_url(api_url: &str, repo: &str, tag: &str) -> Result<ForgejoRelease> {\n    let key = format!(\"{api_url}-{repo}-{tag}\").to_kebab_case();\n    let cache = get_release_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || get_release_(api_url, repo, tag).await)\n        .await?\n        .clone())\n}\n\nasync fn get_release_(api_url: &str, repo: &str, tag: &str) -> Result<ForgejoRelease> {\n    let url = if tag == \"latest\" {\n        format!(\"{api_url}/repos/{repo}/releases/latest\")\n    } else {\n        format!(\"{api_url}/repos/{repo}/releases/tags/{tag}\")\n    };\n    let headers = get_headers(&url);\n    crate::http::HTTP_FETCH\n        .json_with_headers(url, &headers)\n        .await\n}\n\nfn next_page(headers: &HeaderMap) -> Option<String> {\n    let link = headers\n        .get(\"link\")\n        .map(|l| l.to_str().unwrap_or_default().to_string())\n        .unwrap_or_default();\n    regex!(r#\"<([^>]+)>; rel=\"next\"\"#)\n        .captures(&link)\n        .map(|c| c.get(1).unwrap().as_str().to_string())\n}\n\nfn cache_dir() -> PathBuf {\n    dirs::CACHE.join(\"forgejo\")\n}\n\npub fn get_headers<U: IntoUrl>(url: U) -> HeaderMap {\n    let mut headers = HeaderMap::new();\n    let url = url.into_url().unwrap();\n    let mut set_headers = |token: &str| {\n        headers.insert(\n            reqwest::header::AUTHORIZATION,\n            HeaderValue::from_str(format!(\"Bearer {token}\").as_str()).unwrap(),\n        );\n    };\n\n    if url.host_str() == Some(\"codeberg.org\") {\n        if let Some(token) = env::FORGEJO_TOKEN.as_ref() {\n            set_headers(token);\n        }\n    } else if let Some(token) = env::MISE_FORGEJO_ENTERPRISE_TOKEN.as_ref() {\n        set_headers(token);\n    }\n    headers\n}\n"
  },
  {
    "path": "src/git.rs",
    "content": "use std::fmt::Debug;\nuse std::path::{Path, PathBuf};\n\nuse duct::Expression;\nuse eyre::{Result, WrapErr, eyre};\nuse gix::{self};\nuse once_cell::sync::OnceCell;\nuse xx::file;\n\nuse crate::cmd::CmdLineRunner;\nuse crate::config::Settings;\nuse crate::file::touch_dir;\nuse crate::ui::progress_report::SingleReport;\n\npub struct Git {\n    pub dir: PathBuf,\n    pub repo: OnceCell<gix::Repository>,\n}\n\nmacro_rules! git_cmd {\n    ( $dir:expr $(, $arg:expr )* $(,)? ) => {\n        {\n            let safe = format!(\"safe.directory={}\", $dir.display());\n            cmd!(\"git\", \"-C\", $dir, \"-c\", safe, \"-c\", \"core.autocrlf=false\" $(, $arg)*)\n        }\n    }\n}\n\nmacro_rules! git_cmd_read {\n    ( $dir:expr $(, $arg:expr )* $(,)? ) => {\n        {\n            git_cmd!($dir $(, $arg)*).read().wrap_err_with(|| {\n                let args = [$($arg,)*].join(\" \");\n                format!(\"git {args} failed\")\n            })\n        }\n    }\n}\n\nimpl Git {\n    pub fn new<P: AsRef<Path>>(dir: P) -> Self {\n        Self {\n            dir: dir.as_ref().to_path_buf(),\n            repo: OnceCell::new(),\n        }\n    }\n\n    pub fn repo(&self) -> Result<&gix::Repository> {\n        self.repo.get_or_try_init(|| {\n            trace!(\"opening git repository via gix at {:?}\", self.dir);\n            gix::open(&self.dir)\n                .wrap_err_with(|| format!(\"failed to open git repository at {:?}\", self.dir))\n                .inspect_err(|err| warn!(\"{err:#}\"))\n        })\n    }\n\n    pub fn is_repo(&self) -> bool {\n        self.dir.join(\".git\").is_dir()\n    }\n\n    pub fn update(&self, gitref: Option<String>) -> Result<(String, String)> {\n        let gitref = gitref.map_or_else(|| self.current_branch(), Ok)?;\n        self.update_ref(gitref, false)\n    }\n\n    pub fn update_tag(&self, gitref: String) -> Result<(String, String)> {\n        self.update_ref(gitref, true)\n    }\n\n    fn update_ref(&self, gitref: String, is_tag_ref: bool) -> Result<(String, String)> {\n        debug!(\"updating {} to {}\", self.dir.display(), gitref);\n        let exec = |cmd: Expression| match cmd.stderr_to_stdout().stdout_capture().unchecked().run()\n        {\n            Ok(res) => {\n                if res.status.success() {\n                    Ok(())\n                } else {\n                    Err(eyre!(\n                        \"git failed: {cmd:?} {}\",\n                        String::from_utf8(res.stdout).unwrap()\n                    ))\n                }\n            }\n            Err(err) => Err(eyre!(\"git failed: {cmd:?} {err:#}\")),\n        };\n        debug!(\"updating {} to {} with git\", self.dir.display(), gitref);\n\n        let refspec = if is_tag_ref {\n            format!(\"refs/tags/{gitref}:refs/tags/{gitref}\")\n        } else {\n            format!(\"{gitref}:{gitref}\")\n        };\n        exec(git_cmd!(\n            &self.dir,\n            \"fetch\",\n            \"--prune\",\n            \"--update-head-ok\",\n            \"origin\",\n            &refspec\n        ))?;\n        let prev_rev = self.current_sha()?;\n        exec(git_cmd!(\n            &self.dir,\n            \"-c\",\n            \"advice.detachedHead=false\",\n            \"-c\",\n            \"advice.objectNameWarning=false\",\n            \"checkout\",\n            \"--force\",\n            &gitref\n        ))?;\n        let post_rev = self.current_sha()?;\n        touch_dir(&self.dir)?;\n\n        Ok((prev_rev, post_rev))\n    }\n\n    pub fn clone(&self, url: &str, options: CloneOptions) -> Result<()> {\n        if let Some(parent) = self.dir.parent() {\n            file::mkdirp(parent)?;\n        }\n        if Settings::get().libgit2 || Settings::get().gix {\n            debug!(\"cloning {} to {} with gix\", url, self.dir.display());\n            let mut prepare_clone = gix::prepare_clone(url, &self.dir)?;\n\n            if let Some(branch) = &options.branch {\n                prepare_clone = prepare_clone.with_ref_name(Some(branch))?;\n            }\n\n            let (mut prepare_checkout, _) = prepare_clone\n                .fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;\n\n            prepare_checkout\n                .main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;\n\n            return Ok(());\n        }\n        debug!(\"cloning {} to {} with git\", url, self.dir.display());\n        match get_git_version() {\n            Ok(version) => trace!(\"git version: {}\", version),\n            Err(err) => warn!(\n                \"failed to get git version: {:#}\\n Git is required to use mise.\",\n                err\n            ),\n        }\n        if let Some(pr) = &options.pr {\n            // in order to prevent hiding potential password prompt, just disable the progress bar\n            pr.abandon();\n        }\n\n        let mut cmd = CmdLineRunner::new(\"git\")\n            .arg(\"clone\")\n            .arg(\"-q\")\n            .arg(\"-o\")\n            .arg(\"origin\")\n            .arg(\"-c\")\n            .arg(\"core.autocrlf=false\")\n            .arg(\"--depth\")\n            .arg(\"1\")\n            .arg(url)\n            .arg(&self.dir);\n\n        if let Some(branch) = &options.branch {\n            cmd = cmd.args([\n                \"-b\",\n                branch,\n                \"--single-branch\",\n                \"-c\",\n                \"advice.detachedHead=false\",\n            ]);\n        }\n\n        cmd.execute()?;\n        Ok(())\n    }\n\n    pub fn update_submodules(&self) -> Result<()> {\n        debug!(\"updating submodules in {}\", self.dir.display());\n\n        let exec = |cmd: Expression| match cmd.stderr_to_stdout().stdout_capture().unchecked().run()\n        {\n            Ok(res) => {\n                if res.status.success() {\n                    Ok(())\n                } else {\n                    Err(eyre!(\n                        \"git failed: {cmd:?} {}\",\n                        String::from_utf8(res.stdout).unwrap()\n                    ))\n                }\n            }\n            Err(err) => Err(eyre!(\"git failed: {cmd:?} {err:#}\")),\n        };\n\n        exec(\n            git_cmd!(&self.dir, \"submodule\", \"update\", \"--init\", \"--recursive\")\n                .env(\"GIT_TERMINAL_PROMPT\", \"0\"),\n        )?;\n\n        Ok(())\n    }\n\n    pub fn current_branch(&self) -> Result<String> {\n        let dir = &self.dir;\n        if let Ok(repo) = self.repo() {\n            let head = repo.head()?;\n            let branch = head\n                .referent_name()\n                .map(|name| name.shorten().to_string())\n                .unwrap_or_else(|| head.id().unwrap().to_string());\n            debug!(\"current branch for {dir:?}: {branch}\");\n            return Ok(branch);\n        }\n        let branch = git_cmd_read!(&self.dir, \"branch\", \"--show-current\")?;\n        debug!(\"current branch for {}: {}\", self.dir.display(), &branch);\n        Ok(branch)\n    }\n    pub fn current_sha(&self) -> Result<String> {\n        let dir = &self.dir;\n        if let Ok(repo) = self.repo() {\n            let head = repo.head()?;\n            let id = head.id();\n            let sha = id.unwrap().to_string();\n            debug!(\"current sha for {dir:?}: {sha}\");\n            return Ok(sha);\n        }\n        let sha = git_cmd_read!(&self.dir, \"rev-parse\", \"HEAD\")?;\n        debug!(\"current sha for {}: {}\", self.dir.display(), &sha);\n        Ok(sha)\n    }\n\n    pub fn current_sha_short(&self) -> Result<String> {\n        let dir = &self.dir;\n        if let Ok(repo) = self.repo() {\n            let head = repo.head()?;\n            let id = head.id();\n            let sha = id.unwrap().to_string()[..7].to_string();\n            debug!(\"current sha for {dir:?}: {sha}\");\n            return Ok(sha);\n        }\n        let sha = git_cmd_read!(&self.dir, \"rev-parse\", \"--short\", \"HEAD\")?;\n        debug!(\"current sha for {dir:?}: {sha}\");\n        Ok(sha)\n    }\n\n    pub fn current_abbrev_ref(&self) -> Result<String> {\n        let dir = &self.dir;\n        if let Ok(repo) = self.repo() {\n            let head = repo.head()?;\n            let head = head.name().shorten().to_string();\n            debug!(\"current abbrev ref for {dir:?}: {head}\");\n            return Ok(head);\n        }\n        let aref = git_cmd_read!(&self.dir, \"rev-parse\", \"--abbrev-ref\", \"HEAD\")?;\n        debug!(\"current abbrev ref for {}: {}\", self.dir.display(), &aref);\n        Ok(aref)\n    }\n\n    pub fn get_remote_url(&self) -> Option<String> {\n        let dir = &self.dir;\n        if !self.exists() {\n            return None;\n        }\n        if let Ok(repo) = self.repo()\n            && let Ok(remote) = repo.find_remote(\"origin\")\n            && let Some(url) = remote.url(gix::remote::Direction::Fetch)\n        {\n            trace!(\"remote url for {dir:?}: {url}\");\n            return Some(url.to_string());\n        }\n        let res = git_cmd_read!(&self.dir, \"config\", \"--get\", \"remote.origin.url\");\n        match res {\n            Ok(url) => {\n                debug!(\"remote url for {dir:?}: {url}\");\n                Some(url)\n            }\n            Err(err) => {\n                warn!(\"failed to get remote url for {dir:?}: {err:#}\");\n                None\n            }\n        }\n    }\n\n    pub fn split_url_and_ref(url: &str) -> (String, Option<String>) {\n        match url.split_once('#') {\n            Some((url, _ref)) => (url.to_string(), Some(_ref.to_string())),\n            None => (url.to_string(), None),\n        }\n    }\n\n    pub fn remote_sha(&self, branch: &str) -> Result<Option<String>> {\n        let output = git_cmd_read!(&self.dir, \"ls-remote\", \"origin\", branch)?;\n        Ok(output\n            .lines()\n            .next()\n            .and_then(|line| line.split_whitespace().next())\n            .map(|sha| sha.to_string()))\n    }\n\n    pub fn exists(&self) -> bool {\n        self.dir.join(\".git\").is_dir()\n    }\n\n    pub fn get_root() -> eyre::Result<PathBuf> {\n        Ok(cmd!(\"git\", \"rev-parse\", \"--show-toplevel\")\n            .read()?\n            .trim()\n            .into())\n    }\n}\n\nfn get_git_version() -> Result<String> {\n    let version = cmd!(\"git\", \"--version\").read()?;\n    Ok(version.trim().into())\n}\n\nimpl Debug for Git {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Git\").field(\"dir\", &self.dir).finish()\n    }\n}\n\n#[derive(Default)]\npub struct CloneOptions<'a> {\n    pr: Option<&'a dyn SingleReport>,\n    branch: Option<String>,\n}\n\nimpl<'a> CloneOptions<'a> {\n    pub fn pr(mut self, pr: &'a dyn SingleReport) -> Self {\n        self.pr = Some(pr);\n        self\n    }\n\n    pub fn branch(mut self, branch: &str) -> Self {\n        self.branch = Some(branch.to_string());\n        self\n    }\n}\n"
  },
  {
    "path": "src/github.rs",
    "content": "use crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::{dirs, duration, env};\nuse eyre::Result;\nuse heck::ToKebabCase;\nuse reqwest::IntoUrl;\nuse reqwest::header::{HeaderMap, HeaderValue};\nuse serde_derive::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::sync::LazyLock as Lazy;\nuse tokio::sync::RwLock;\nuse tokio::sync::RwLockReadGuard;\nuse xx::regex;\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubRelease {\n    pub tag_name: String,\n    // pub name: Option<String>,\n    // pub body: Option<String>,\n    pub draft: bool,\n    pub prerelease: bool,\n    pub created_at: String,\n    // pub published_at: Option<String>,\n    pub assets: Vec<GithubAsset>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubTag {\n    pub name: String,\n    pub commit: Option<GithubTagCommit>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubTagCommit {\n    pub sha: String,\n    pub url: String,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubCommit {\n    pub commit: GithubCommitInfo,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubCommitInfo {\n    pub committer: GithubCommitPerson,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubCommitPerson {\n    pub date: String,\n}\n\n/// Tag with date information\n#[derive(Debug, Clone)]\npub struct GithubTagWithDate {\n    pub name: String,\n    pub date: Option<String>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GithubAsset {\n    pub name: String,\n    // pub size: u64,\n    pub browser_download_url: String,\n    pub url: String,\n    /// SHA256 digest provided by GitHub API (format: \"sha256:hash\")\n    /// Will be null for releases created before this feature was added\n    #[serde(default)]\n    pub digest: Option<String>,\n}\n\ntype CacheGroup<T> = HashMap<String, CacheManager<T>>;\n\nstatic RELEASES_CACHE: Lazy<RwLock<CacheGroup<Vec<GithubRelease>>>> = Lazy::new(Default::default);\n\nstatic RELEASE_CACHE: Lazy<RwLock<CacheGroup<GithubRelease>>> = Lazy::new(Default::default);\n\nstatic TAGS_CACHE: Lazy<RwLock<CacheGroup<Vec<String>>>> = Lazy::new(Default::default);\n\npub static API_URL: &str = \"https://api.github.com\";\n\nasync fn get_tags_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<Vec<String>>> {\n    TAGS_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}-tags.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    TAGS_CACHE.read().await\n}\n\nasync fn get_releases_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<Vec<GithubRelease>>> {\n    RELEASES_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}-releases.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASES_CACHE.read().await\n}\n\nasync fn get_release_cache<'a>(key: &str) -> RwLockReadGuard<'a, CacheGroup<GithubRelease>> {\n    RELEASE_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASE_CACHE.read().await\n}\n\npub async fn list_releases(repo: &str) -> Result<Vec<GithubRelease>> {\n    let key = repo.to_kebab_case();\n    let cache = get_releases_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_releases_(API_URL, repo).await)\n        .await?\n        .to_vec())\n}\n\npub async fn list_releases_from_url(api_url: &str, repo: &str) -> Result<Vec<GithubRelease>> {\n    let key = format!(\"{api_url}-{repo}\").to_kebab_case();\n    let cache = get_releases_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_releases_(api_url, repo).await)\n        .await?\n        .to_vec())\n}\n\nasync fn list_releases_(api_url: &str, repo: &str) -> Result<Vec<GithubRelease>> {\n    let url = format!(\"{api_url}/repos/{repo}/releases\");\n    let headers = get_headers(&url);\n    let (mut releases, mut headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<GithubRelease>, _>(url, &headers)\n        .await?;\n\n    if *env::MISE_LIST_ALL_VERSIONS {\n        while let Some(next) = next_page(&headers) {\n            headers = get_headers(&next);\n            let (more, h) = crate::http::HTTP_FETCH\n                .json_headers_with_headers::<Vec<GithubRelease>, _>(next, &headers)\n                .await?;\n            releases.extend(more);\n            headers = h;\n        }\n    }\n    releases.retain(|r| !r.draft && !r.prerelease);\n\n    Ok(releases)\n}\n\npub async fn list_tags(repo: &str) -> Result<Vec<String>> {\n    let key = repo.to_kebab_case();\n    let cache = get_tags_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_tags_(API_URL, repo).await)\n        .await?\n        .to_vec())\n}\n\npub async fn list_tags_from_url(api_url: &str, repo: &str) -> Result<Vec<String>> {\n    let key = format!(\"{api_url}-{repo}\").to_kebab_case();\n    let cache = get_tags_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_tags_(api_url, repo).await)\n        .await?\n        .to_vec())\n}\n\nasync fn list_tags_(api_url: &str, repo: &str) -> Result<Vec<String>> {\n    let url = format!(\"{api_url}/repos/{repo}/tags\");\n    let headers = get_headers(&url);\n    let (mut tags, mut headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<GithubTag>, _>(url, &headers)\n        .await?;\n\n    if *env::MISE_LIST_ALL_VERSIONS {\n        while let Some(next) = next_page(&headers) {\n            headers = get_headers(&next);\n            let (more, h) = crate::http::HTTP_FETCH\n                .json_headers_with_headers::<Vec<GithubTag>, _>(next, &headers)\n                .await?;\n            tags.extend(more);\n            headers = h;\n        }\n    }\n\n    Ok(tags.into_iter().map(|t| t.name).collect())\n}\n\n/// List tags with their commit dates. This is slower than `list_tags` as it requires\n/// fetching commit info for each tag. Use only when MISE_LIST_ALL_VERSIONS is set.\npub async fn list_tags_with_dates(repo: &str) -> Result<Vec<GithubTagWithDate>> {\n    list_tags_with_dates_(API_URL, repo).await\n}\n\nasync fn list_tags_with_dates_(api_url: &str, repo: &str) -> Result<Vec<GithubTagWithDate>> {\n    let url = format!(\"{api_url}/repos/{repo}/tags\");\n    let headers = get_headers(&url);\n    let (mut tags, mut response_headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<GithubTag>, _>(url, &headers)\n        .await?;\n\n    // Fetch all pages when MISE_LIST_ALL_VERSIONS is set\n    while let Some(next) = next_page(&response_headers) {\n        response_headers = get_headers(&next);\n        let (more, h) = crate::http::HTTP_FETCH\n            .json_headers_with_headers::<Vec<GithubTag>, _>(next, &response_headers)\n            .await?;\n        tags.extend(more);\n        response_headers = h;\n    }\n\n    // Fetch commit dates in parallel using the parallel utility\n    let results = crate::parallel::parallel(tags, |tag| async move {\n        let date = if let Some(commit) = tag.commit {\n            let headers = get_headers(&commit.url);\n            match crate::http::HTTP_FETCH\n                .json_with_headers::<GithubCommit, _>(&commit.url, &headers)\n                .await\n            {\n                Ok(commit_info) => Some(commit_info.commit.committer.date),\n                Err(e) => {\n                    warn!(\"Failed to fetch commit date for tag {}: {}\", tag.name, e);\n                    None\n                }\n            }\n        } else {\n            None\n        };\n        Ok((tag.name, date))\n    })\n    .await?;\n\n    Ok(results\n        .into_iter()\n        .map(|(name, date)| GithubTagWithDate { name, date })\n        .collect())\n}\n\npub async fn get_release(repo: &str, tag: &str) -> Result<GithubRelease> {\n    let key = format!(\"{repo}-{tag}\").to_kebab_case();\n    let cache = get_release_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || get_release_(API_URL, repo, tag).await)\n        .await?\n        .clone())\n}\n\npub async fn get_release_for_url(api_url: &str, repo: &str, tag: &str) -> Result<GithubRelease> {\n    let key = format!(\"{api_url}-{repo}-{tag}\").to_kebab_case();\n    let cache = get_release_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || get_release_(api_url, repo, tag).await)\n        .await?\n        .clone())\n}\n\nasync fn get_release_(api_url: &str, repo: &str, tag: &str) -> Result<GithubRelease> {\n    let url = if tag == \"latest\" {\n        format!(\"{api_url}/repos/{repo}/releases/latest\")\n    } else {\n        format!(\"{api_url}/repos/{repo}/releases/tags/{tag}\")\n    };\n    let headers = get_headers(&url);\n    crate::http::HTTP_FETCH\n        .json_with_headers(url, &headers)\n        .await\n}\n\nfn next_page(headers: &HeaderMap) -> Option<String> {\n    let link = headers\n        .get(\"link\")\n        .map(|l| l.to_str().unwrap_or_default().to_string())\n        .unwrap_or_default();\n    regex!(r#\"<([^>]+)>; rel=\"next\"\"#)\n        .captures(&link)\n        .map(|c| c.get(1).unwrap().as_str().to_string())\n}\n\nfn cache_dir() -> PathBuf {\n    dirs::CACHE.join(\"github\")\n}\n\npub fn get_headers<U: IntoUrl>(url: U) -> HeaderMap {\n    let mut headers = HeaderMap::new();\n    let url = url.into_url().unwrap();\n    let mut set_headers = |token: &str| {\n        headers.insert(\n            reqwest::header::AUTHORIZATION,\n            HeaderValue::from_str(format!(\"Bearer {token}\").as_str()).unwrap(),\n        );\n        headers.insert(\n            \"x-github-api-version\",\n            HeaderValue::from_static(\"2022-11-28\"),\n        );\n    };\n\n    if url.host_str() == Some(\"api.github.com\") {\n        if let Some(token) = env::GITHUB_TOKEN.as_ref() {\n            set_headers(token);\n        }\n    } else if let Some(token) = env::MISE_GITHUB_ENTERPRISE_TOKEN\n        .as_ref()\n        .or(env::GITHUB_TOKEN.as_ref())\n    {\n        set_headers(token);\n    }\n\n    if url.path().contains(\"/releases/assets/\") {\n        headers.insert(\n            \"accept\",\n            HeaderValue::from_static(\"application/octet-stream\"),\n        );\n    }\n\n    headers\n}\n"
  },
  {
    "path": "src/gitlab.rs",
    "content": "use eyre::Result;\nuse heck::ToKebabCase;\nuse reqwest::IntoUrl;\nuse reqwest::header::{HeaderMap, HeaderValue};\nuse serde_derive::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse std::path::PathBuf;\nuse std::sync::LazyLock as Lazy;\nuse tokio::sync::{RwLock, RwLockReadGuard};\nuse xx::regex;\n\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::{dirs, duration, env};\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GitlabRelease {\n    pub tag_name: String,\n    pub description: Option<String>,\n    pub released_at: Option<String>,\n    pub assets: GitlabAssets,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GitlabTag {\n    pub name: String,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GitlabAssets {\n    // pub count: i64,\n    pub sources: Vec<GitlabAssetSource>,\n    pub links: Vec<GitlabAssetLink>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GitlabAssetSource {\n    pub format: String,\n    pub url: String,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct GitlabAssetLink {\n    pub id: i64,\n    pub name: String,\n    pub url: String,\n    pub direct_asset_url: String,\n    pub link_type: String,\n}\n\ntype CacheGroup<T> = HashMap<String, CacheManager<T>>;\n\nstatic RELEASES_CACHE: Lazy<RwLock<CacheGroup<Vec<GitlabRelease>>>> = Lazy::new(Default::default);\n\nstatic RELEASE_CACHE: Lazy<RwLock<CacheGroup<GitlabRelease>>> = Lazy::new(Default::default);\n\nstatic TAGS_CACHE: Lazy<RwLock<CacheGroup<Vec<String>>>> = Lazy::new(Default::default);\n\npub static API_URL: &str = \"https://gitlab.com/api/v4\";\n\nasync fn get_tags_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<Vec<String>>> {\n    TAGS_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}-tags.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    TAGS_CACHE.read().await\n}\n\nasync fn get_releases_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<Vec<GitlabRelease>>> {\n    RELEASES_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}-releases.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASES_CACHE.read().await\n}\n\nasync fn get_release_cache(key: &str) -> RwLockReadGuard<'_, CacheGroup<GitlabRelease>> {\n    RELEASE_CACHE\n        .write()\n        .await\n        .entry(key.to_string())\n        .or_insert_with(|| {\n            CacheManagerBuilder::new(cache_dir().join(format!(\"{key}.msgpack.z\")))\n                .with_fresh_duration(Some(duration::DAILY))\n                .build()\n        });\n    RELEASE_CACHE.read().await\n}\n\n#[allow(dead_code)]\npub async fn list_releases(repo: &str) -> Result<Vec<GitlabRelease>> {\n    let key = repo.to_kebab_case();\n    let cache = get_releases_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_releases_(API_URL, repo).await)\n        .await?\n        .to_vec())\n}\n\npub async fn list_releases_from_url(api_url: &str, repo: &str) -> Result<Vec<GitlabRelease>> {\n    let key = format!(\"{api_url}-{repo}\").to_kebab_case();\n    let cache = get_releases_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_releases_(api_url, repo).await)\n        .await?\n        .to_vec())\n}\n\nasync fn list_releases_(api_url: &str, repo: &str) -> Result<Vec<GitlabRelease>> {\n    let url = format!(\n        \"{}/projects/{}/releases\",\n        api_url,\n        urlencoding::encode(repo)\n    );\n\n    let headers = get_headers(&url);\n    let (mut releases, mut headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<GitlabRelease>, _>(url, &headers)\n        .await?;\n\n    if *env::MISE_LIST_ALL_VERSIONS {\n        while let Some(next) = next_page(&headers) {\n            let (more, h) = crate::http::HTTP_FETCH\n                .json_headers_with_headers::<Vec<GitlabRelease>, _>(next, &headers)\n                .await?;\n            releases.extend(more);\n            headers = h;\n        }\n    }\n\n    Ok(releases)\n}\n\n#[allow(dead_code)]\npub async fn list_tags(repo: &str) -> Result<Vec<String>> {\n    let key = repo.to_kebab_case();\n    let cache = get_tags_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_tags_(API_URL, repo).await)\n        .await?\n        .to_vec())\n}\n\npub async fn list_tags_from_url(api_url: &str, repo: &str) -> Result<Vec<String>> {\n    let key = format!(\"{api_url}-{repo}\").to_kebab_case();\n    let cache = get_tags_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || list_tags_(api_url, repo).await)\n        .await?\n        .to_vec())\n}\n\nasync fn list_tags_(api_url: &str, repo: &str) -> Result<Vec<String>> {\n    let url = format!(\n        \"{}/projects/{}/repository/tags\",\n        api_url,\n        urlencoding::encode(repo)\n    );\n    let headers = get_headers(&url);\n    let (mut tags, mut headers) = crate::http::HTTP_FETCH\n        .json_headers_with_headers::<Vec<GitlabTag>, _>(url, &headers)\n        .await?;\n\n    if *env::MISE_LIST_ALL_VERSIONS {\n        while let Some(next) = next_page(&headers) {\n            let (more, h) = crate::http::HTTP_FETCH\n                .json_headers_with_headers::<Vec<GitlabTag>, _>(next, &headers)\n                .await?;\n            tags.extend(more);\n            headers = h;\n        }\n    }\n\n    Ok(tags.into_iter().map(|t| t.name).collect())\n}\n\n#[allow(dead_code)]\npub async fn get_release(repo: &str, tag: &str) -> Result<GitlabRelease> {\n    let key = format!(\"{repo}-{tag}\").to_kebab_case();\n    let cache = get_release_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || get_release_(API_URL, repo, tag).await)\n        .await?\n        .clone())\n}\n\npub async fn get_release_for_url(api_url: &str, repo: &str, tag: &str) -> Result<GitlabRelease> {\n    let key = format!(\"{api_url}-{repo}-{tag}\").to_kebab_case();\n    let cache = get_release_cache(&key).await;\n    let cache = cache.get(&key).unwrap();\n    Ok(cache\n        .get_or_try_init_async(async || get_release_(api_url, repo, tag).await)\n        .await?\n        .clone())\n}\n\nasync fn get_release_(api_url: &str, repo: &str, tag: &str) -> Result<GitlabRelease> {\n    let url = format!(\n        \"{}/projects/{}/releases/{}\",\n        api_url,\n        urlencoding::encode(repo),\n        tag\n    );\n    let headers = get_headers(&url);\n    crate::http::HTTP_FETCH\n        .json_with_headers(url, &headers)\n        .await\n}\n\nfn next_page(headers: &HeaderMap) -> Option<String> {\n    let link = headers\n        .get(\"link\")\n        .map(|l| l.to_str().unwrap_or_default().to_string())\n        .unwrap_or_default();\n    regex!(r#\"<([^>]+)>; rel=\"next\"\"#)\n        .captures(&link)\n        .map(|c| c.get(1).unwrap().as_str().to_string())\n}\n\nfn cache_dir() -> PathBuf {\n    dirs::CACHE.join(\"gitlab\")\n}\n\npub fn get_headers<U: IntoUrl>(url: U) -> HeaderMap {\n    let mut headers = HeaderMap::new();\n    let url = url.into_url().unwrap();\n    let mut set_headers = |token: &str| {\n        headers.insert(\n            reqwest::header::AUTHORIZATION,\n            HeaderValue::from_str(format!(\"Bearer {token}\").as_str()).unwrap(),\n        );\n    };\n    if url.host_str() == Some(\"gitlab.com\") {\n        if let Some(token) = env::GITLAB_TOKEN.as_ref() {\n            set_headers(token);\n        }\n    } else if let Some(token) = env::MISE_GITLAB_ENTERPRISE_TOKEN.as_ref() {\n        set_headers(token);\n    }\n    headers\n}\n"
  },
  {
    "path": "src/gpg.rs",
    "content": "use crate::Result;\nuse crate::cmd::CmdLineRunner;\nuse crate::install_context::InstallContext;\n\npub fn add_keys_node(ctx: &InstallContext) -> Result<()> {\n    add_keys(ctx, include_str!(\"assets/gpg/node.asc\"))\n}\n\npub fn add_keys_swift(ctx: &InstallContext) -> Result<()> {\n    add_keys(ctx, include_str!(\"assets/gpg/swift.asc\"))\n}\n\nfn add_keys(ctx: &InstallContext, keys: &str) -> Result<()> {\n    CmdLineRunner::new(\"gpg\")\n        .arg(\"--quiet\")\n        .arg(\"--import\")\n        .stdin_string(keys)\n        .with_pr(ctx.pr.as_ref())\n        .execute()\n}\n"
  },
  {
    "path": "src/hash.rs",
    "content": "use std::collections::HashMap;\nuse std::hash::{Hash, Hasher};\nuse std::io::{Read, Write};\nuse std::path::Path;\n\nuse crate::file;\nuse crate::file::display_path;\nuse crate::ui::progress_report::SingleReport;\nuse blake3::Hasher as Blake3Hasher;\nuse digest::Digest;\nuse eyre::{Result, bail};\nuse md5::Md5;\nuse sha1::Sha1;\nuse sha2::{Sha256, Sha512};\nuse siphasher::sip::SipHasher;\n\npub fn hash_to_str<T: Hash>(t: &T) -> String {\n    let mut s = SipHasher::new();\n    t.hash(&mut s);\n    format!(\"{:x}\", s.finish())\n}\n\npub fn hash_sha256_to_str(s: &str) -> String {\n    let mut hasher = Sha256::new();\n    hasher.update(s);\n    format!(\"{:x}\", hasher.finalize())\n}\n\npub fn file_hash_sha256(path: &Path, pr: Option<&dyn SingleReport>) -> Result<String> {\n    let use_external_hasher = file::size(path).unwrap_or_default() > 50 * 1024 * 1024;\n    if use_external_hasher && file::which(\"sha256sum\").is_some() {\n        let out = cmd!(\"sha256sum\", path).read()?;\n        Ok(out.split_whitespace().next().unwrap().to_string())\n    } else {\n        file_hash_prog::<Sha256>(path, pr)\n    }\n}\n\nfn file_hash_prog<D>(path: &Path, pr: Option<&dyn SingleReport>) -> Result<String>\nwhere\n    D: Digest + Write,\n{\n    let mut file = file::open(path)?;\n    if let Some(pr) = pr {\n        pr.set_length(file.metadata()?.len());\n    }\n    let mut hasher = D::new();\n    let mut buf = [0; 32 * 1024];\n    loop {\n        let n = file.read(&mut buf)?;\n        if n == 0 {\n            break;\n        }\n        hasher.write_all(&buf[..n])?;\n        if let Some(pr) = pr {\n            pr.inc(n as u64);\n        }\n    }\n    std::io::copy(&mut file, &mut hasher)?;\n    let hash = hasher.finalize();\n    Ok(hash.iter().map(|b| format!(\"{b:02x}\")).collect())\n}\n\npub fn hash_blake3_to_str(s: &str) -> String {\n    let mut hasher = Blake3Hasher::new();\n    hasher.update(s.as_bytes());\n    hasher.finalize().to_hex().to_string()\n}\n\npub fn file_hash_blake3(path: &Path, pr: Option<&dyn SingleReport>) -> Result<String> {\n    let mut file = file::open(path)?;\n    if let Some(pr) = pr {\n        pr.set_length(file.metadata()?.len());\n    }\n    let mut hasher = Blake3Hasher::new();\n    let mut buf = [0; 32 * 1024];\n    loop {\n        let n = file.read(&mut buf)?;\n        if n == 0 {\n            break;\n        }\n        hasher.update(&buf[..n]);\n        if let Some(pr) = pr {\n            pr.inc(n as u64);\n        }\n    }\n    let hash = hasher.finalize();\n    Ok(format!(\"{}\", hash.to_hex()))\n}\n\npub fn ensure_checksum(\n    path: &Path,\n    checksum: &str,\n    pr: Option<&dyn SingleReport>,\n    algo: &str,\n) -> Result<()> {\n    let use_external_hasher = file::size(path).unwrap_or(u64::MAX) > 10 * 1024 * 1024;\n    let actual = match algo {\n        \"blake3\" => file_hash_blake3(path, pr)?,\n        \"sha512\" => {\n            if use_external_hasher && file::which(\"sha512sum\").is_some() {\n                let out = cmd!(\"sha512sum\", path).read()?;\n                out.split_whitespace().next().unwrap().to_string()\n            } else {\n                file_hash_prog::<Sha512>(path, pr)?\n            }\n        }\n        \"sha256\" => file_hash_prog::<Sha256>(path, pr)?,\n        \"sha1\" => {\n            if use_external_hasher && file::which(\"sha1sum\").is_some() {\n                let out = cmd!(\"sha1sum\", path).read()?;\n                out.split_whitespace().next().unwrap().to_string()\n            } else {\n                file_hash_prog::<Sha1>(path, pr)?\n            }\n        }\n        \"md5\" => {\n            if use_external_hasher && file::which(\"md5sum\").is_some() {\n                let out = cmd!(\"md5sum\", path).read()?;\n                out.split_whitespace().next().unwrap().to_string()\n            } else {\n                file_hash_prog::<Md5>(path, pr)?\n            }\n        }\n        _ => bail!(\"Unknown checksum algorithm: {}\", algo),\n    };\n    let checksum = checksum.to_lowercase();\n    if actual != checksum {\n        bail!(\n            \"Checksum mismatch for file {}:\\nExpected: {algo}:{checksum}\\nActual:   {algo}:{actual}\",\n            display_path(path)\n        );\n    }\n    Ok(())\n}\n\npub fn parse_shasums(text: &str) -> HashMap<String, String> {\n    text.lines()\n        .map(|l| {\n            let mut parts = l.split_whitespace();\n            let hash = parts.next().unwrap();\n            let name = parts.next().unwrap();\n            (name.into(), hash.into())\n        })\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_hash_to_str() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(hash_to_str(&\"foo\"), \"e1b19adfb2e348a2\");\n    }\n\n    #[tokio::test]\n    async fn test_hash_sha256() {\n        let _config = Config::get().await.unwrap();\n        let path = Path::new(\".test-tool-versions\");\n        let hash = file_hash_prog::<Sha256>(path, None).unwrap();\n        assert_snapshot!(hash);\n    }\n}\n"
  },
  {
    "path": "src/hint.rs",
    "content": "use crate::config::Settings;\nuse crate::dirs;\nuse std::collections::HashSet;\nuse std::path::PathBuf;\nuse std::sync::LazyLock as Lazy;\nuse std::sync::Mutex;\n\n#[macro_export]\nmacro_rules! hint {\n    ($id:expr, $message:expr, $example_cmd:expr) => {{\n        if $crate::hint::should_display_hint($id) {\n            let _ = $crate::file::touch_file(&$crate::hint::HINTS_DIR.join($id));\n            let prefix = console::style(\"hint\")\n                .dim()\n                .yellow()\n                .for_stderr()\n                .to_string();\n            let message = format!($message);\n            let cmd = console::style($example_cmd).bold().for_stderr();\n            info!(\"{prefix} {message} {cmd}\");\n        }\n    }};\n}\n\npub static HINTS_DIR: Lazy<PathBuf> = Lazy::new(|| dirs::STATE.join(\"hints\"));\n\npub static DISPLAYED_HINTS: Lazy<Mutex<HashSet<String>>> = Lazy::new(|| {\n    let mut hints = HashSet::new();\n\n    for file in xx::file::ls(&*HINTS_DIR).unwrap_or_default() {\n        if let Some(file_name) = file.file_name().map(|f| f.to_string_lossy()) {\n            if file_name.starts_with(\".\") {\n                continue;\n            }\n            hints.insert(file_name.to_string());\n        }\n    }\n\n    Mutex::new(hints)\n});\n\npub fn should_display_hint(id: &str) -> bool {\n    if cfg!(test) || !console::user_attended() || !console::user_attended_stderr() {\n        return false;\n    }\n    if Settings::get()\n        .disable_hints\n        .iter()\n        .any(|hint| hint == id || hint == \"*\")\n    {\n        return false;\n    }\n    let displayed_hints = &mut DISPLAYED_HINTS.lock().unwrap();\n    if displayed_hints.contains(id) {\n        return false;\n    }\n    displayed_hints.insert(id.to_string());\n    true\n}\n"
  },
  {
    "path": "src/hook_env.rs",
    "content": "use std::io::prelude::*;\nuse std::ops::Deref;\nuse std::path::{Path, PathBuf};\nuse std::time::{SystemTime, UNIX_EPOCH};\nuse std::{collections::BTreeSet, sync::Arc};\n\nuse base64::prelude::*;\nuse eyre::Result;\nuse flate2::Compression;\nuse flate2::write::{ZlibDecoder, ZlibEncoder};\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse serde_derive::{Deserialize, Serialize};\nuse std::sync::LazyLock as Lazy;\n\nuse crate::cli::HookReason;\nuse crate::config::{Config, DEFAULT_CONFIG_FILENAMES, Settings};\nuse crate::env::PATH_KEY;\nuse crate::env_diff::{EnvDiffOperation, EnvDiffPatches, EnvMap};\nuse crate::hash::hash_to_str;\nuse crate::shell::Shell;\nuse crate::{dirs, duration, env, file, hooks, watch_files};\n\n/// Directory to store per-directory last check timestamps.\n/// Timestamps are stored per-directory (using a hash of CWD) so that\n/// multiple shells in different directories don't interfere with each other.\nstatic LAST_CHECK_DIR: Lazy<PathBuf> = Lazy::new(|| dirs::STATE.join(\"hook-env-checks\"));\n\n/// Get the path to the last check file for a specific directory.\nfn last_check_file_for_dir(dir: &Path) -> PathBuf {\n    let hash = hash_to_str(&dir.to_string_lossy());\n    LAST_CHECK_DIR.join(hash)\n}\n\n/// Read the last full check timestamp from the state file for the current directory.\nfn read_last_full_check() -> u128 {\n    let Some(cwd) = &*dirs::CWD else {\n        return 0;\n    };\n    std::fs::read_to_string(last_check_file_for_dir(cwd))\n        .ok()\n        .and_then(|s| s.trim().parse().ok())\n        .unwrap_or(0)\n}\n\n/// Write the last full check timestamp to the state file for the current directory.\nfn write_last_full_check(timestamp: u128) {\n    let Some(cwd) = &*dirs::CWD else {\n        return;\n    };\n    if let Err(e) = file::create_dir_all(&*LAST_CHECK_DIR) {\n        trace!(\"failed to create last check dir: {e}\");\n        return;\n    }\n    if let Err(e) = std::fs::write(last_check_file_for_dir(cwd), timestamp.to_string()) {\n        trace!(\"failed to write last check file: {e}\");\n    }\n}\n\n/// Convert a SystemTime to milliseconds since Unix epoch\nfn mtime_to_millis(mtime: SystemTime) -> u128 {\n    mtime\n        .duration_since(UNIX_EPOCH)\n        .unwrap_or_default()\n        .as_millis()\n}\n\npub static PREV_SESSION: Lazy<HookEnvSession> = Lazy::new(|| {\n    env::var(\"__MISE_SESSION\")\n        .ok()\n        .and_then(|s| {\n            deserialize(s)\n                .map_err(|err| {\n                    warn!(\"error deserializing __MISE_SESSION: {err}\");\n                    err\n                })\n                .ok()\n        })\n        .unwrap_or_default()\n});\n\n#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]\npub struct WatchFilePattern {\n    pub root: Option<PathBuf>,\n    pub patterns: Vec<String>,\n}\n\nimpl From<&Path> for WatchFilePattern {\n    fn from(path: &Path) -> Self {\n        Self {\n            root: None,\n            patterns: vec![path.to_string_lossy().to_string()],\n        }\n    }\n}\n\nimpl From<PathBuf> for WatchFilePattern {\n    fn from(path: PathBuf) -> Self {\n        Self {\n            patterns: vec![path.to_string_lossy().to_string()],\n            root: Some(path),\n        }\n    }\n}\n\n/// Fast-path early exit check that can be called BEFORE loading config/tools.\n/// This checks basic conditions using only the previous session data.\n/// Returns true if we can definitely skip hook-env, false if we need to continue.\npub fn should_exit_early_fast() -> bool {\n    let args = env::ARGS.read().unwrap();\n    if args.len() < 2 || args[1] != \"hook-env\" {\n        return false;\n    }\n    // Can't exit early if no previous session\n    // Check for dir being set as a proxy for \"has valid session\"\n    // (loaded_configs can be empty if there are no config files)\n    if PREV_SESSION.dir.is_none() {\n        return false;\n    }\n    // Can't exit early if --force flag is present\n    if args.iter().any(|a| a == \"--force\" || a == \"-f\") {\n        return false;\n    }\n    // Check if running from precmd for the first time\n    // Handle both \"--reason=precmd\" and \"--reason precmd\" forms\n    let is_precmd = args.iter().any(|a| a == \"--reason=precmd\")\n        || args\n            .windows(2)\n            .any(|w| w[0] == \"--reason\" && w[1] == \"precmd\");\n    if is_precmd && !*env::__MISE_ZSH_PRECMD_RUN {\n        return false;\n    }\n\n    // Get settings for cache_ttl and chpwd_only\n    let settings = Settings::get();\n    let cache_ttl_ms = duration::parse_duration(&settings.hook_env.cache_ttl)\n        .map(|d| d.as_millis())\n        .inspect_err(|e| warn!(\"invalid hook_env.cache_ttl setting: {e}\"))\n        .unwrap_or(0);\n\n    // Compute TTL window check only if cache_ttl is enabled (avoid unnecessary file read)\n    let (now, within_ttl_window) = if cache_ttl_ms > 0 {\n        let now = SystemTime::now()\n            .duration_since(UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_millis();\n        let last_full_check = read_last_full_check();\n        (now, now.saturating_sub(last_full_check) < cache_ttl_ms)\n    } else {\n        (0, false)\n    };\n\n    // Can't exit early if directory changed\n    if dir_change().is_some() {\n        return false;\n    }\n    // Can't exit early if MISE_ env vars changed (cheap in-memory hash comparison)\n    if have_mise_env_vars_been_modified() {\n        return false;\n    }\n\n    // chpwd_only mode: skip on precmd if directory hasn't changed\n    // This significantly reduces stat operations on slow filesystems like NFS\n    // Note: We check this AFTER env var check since that's cheap (no I/O)\n    if settings.hook_env.chpwd_only && is_precmd {\n        trace!(\"chpwd_only enabled, skipping precmd hook-env\");\n        return true;\n    }\n\n    // Cache TTL check: if within the TTL window, skip all stat operations\n    // This is useful for slow filesystems like NFS where stat calls are expensive\n    if within_ttl_window {\n        trace!(\"within cache TTL, skipping filesystem checks\");\n        return true;\n    }\n\n    // Check if any loaded config files have been modified\n    for config_path in &PREV_SESSION.loaded_configs {\n        if let Ok(metadata) = config_path.metadata() {\n            if let Ok(modified) = metadata.modified()\n                && mtime_to_millis(modified) > PREV_SESSION.latest_update\n            {\n                return false;\n            }\n        } else if !config_path.exists() {\n            return false;\n        }\n    }\n    // Check if any files accessed by tera template functions have been modified\n    for path in &PREV_SESSION.tera_files {\n        if let Ok(metadata) = path.metadata() {\n            if let Ok(modified) = metadata.modified()\n                && mtime_to_millis(modified) > PREV_SESSION.latest_update\n            {\n                return false;\n            }\n        } else if !path.exists() {\n            return false;\n        }\n    }\n    // Check if any files from [[watch_files]] patterns have been modified\n    for path in &PREV_SESSION.watch_files {\n        if let Ok(metadata) = path.metadata() {\n            if let Ok(modified) = metadata.modified()\n                && mtime_to_millis(modified) > PREV_SESSION.latest_update\n            {\n                return false;\n            }\n        } else if !path.exists() {\n            return false;\n        }\n    }\n    // Check if data dir has been modified (new tools installed, etc.)\n    // Also check if it's been deleted - this requires a full update\n    if !dirs::DATA.exists() {\n        return false;\n    }\n    if let Ok(metadata) = dirs::DATA.metadata()\n        && let Ok(modified) = metadata.modified()\n        && mtime_to_millis(modified) > PREV_SESSION.latest_update\n    {\n        return false;\n    }\n    // Check if any directory in the config search path has been modified\n    // This catches new config files created anywhere in the hierarchy\n    if let Some(cwd) = &*dirs::CWD\n        && let Ok(ancestor_dirs) = file::all_dirs(cwd, &env::MISE_CEILING_PATHS)\n    {\n        // Config subdirectories that might contain config files\n        let config_subdirs = DEFAULT_CONFIG_FILENAMES\n            .iter()\n            .map(|f| Path::new(f).parent().and_then(|p| p.to_str()).unwrap_or(\"\"))\n            .unique()\n            .collect::<Vec<_>>();\n        for dir in ancestor_dirs {\n            for subdir in &config_subdirs {\n                let check_dir = if subdir.is_empty() {\n                    dir.clone()\n                } else {\n                    dir.join(subdir)\n                };\n                if let Ok(metadata) = check_dir.metadata()\n                    && let Ok(modified) = metadata.modified()\n                    && mtime_to_millis(modified) > PREV_SESSION.latest_update\n                {\n                    return false;\n                }\n            }\n        }\n    }\n    // Filesystem checks passed - update the last check timestamp so subsequent\n    // prompts can benefit from the TTL cache without repeating these checks\n    if cache_ttl_ms > 0 {\n        write_last_full_check(now);\n    }\n    true\n}\n\n/// Check if hook-env can exit early after config is loaded.\n/// This is called after the fast-path check and handles cases that need\n/// the full config (watch_files, hook scheduling).\npub fn should_exit_early(\n    watch_files: impl IntoIterator<Item = WatchFilePattern>,\n    reason: Option<HookReason>,\n) -> bool {\n    // Force hook-env to run at least once from precmd after activation\n    // This catches PATH modifications from shell initialization (e.g., path_helper in zsh)\n    if reason == Some(HookReason::Precmd) && !*env::__MISE_ZSH_PRECMD_RUN {\n        trace!(\"__MISE_ZSH_PRECMD_RUN=0 and reason=precmd, forcing hook-env to run\");\n        return false;\n    }\n    // Schedule hooks on directory change (can't do this in fast-path)\n    if dir_change().is_some() {\n        hooks::schedule_hook(hooks::Hooks::Leave);\n        hooks::schedule_hook(hooks::Hooks::Cd);\n        hooks::schedule_hook(hooks::Hooks::Enter);\n        return false;\n    }\n    // Check full watch_files list from config (may include more than config files)\n    let watch_files = match get_watch_files(watch_files) {\n        Ok(w) => w,\n        Err(e) => {\n            warn!(\"error getting watch files: {e}\");\n            return false;\n        }\n    };\n    if have_files_been_modified(watch_files) {\n        return false;\n    }\n    if have_mise_env_vars_been_modified() {\n        return false;\n    }\n    trace!(\"early-exit\");\n    true\n}\n\npub fn dir_change() -> Option<(Option<PathBuf>, PathBuf)> {\n    match (&PREV_SESSION.dir, &*dirs::CWD) {\n        (Some(old), Some(new)) if old != new => {\n            trace!(\"dir change: {:?} -> {:?}\", old, new);\n            Some((Some(old.clone()), new.clone()))\n        }\n        (None, Some(new)) => {\n            trace!(\"dir change: None -> {:?}\", new);\n            Some((None, new.clone()))\n        }\n        _ => None,\n    }\n}\n\nfn have_files_been_modified(watch_files: BTreeSet<PathBuf>) -> bool {\n    if let Some(p) = PREV_SESSION.loaded_configs.iter().find(|p| !p.exists()) {\n        trace!(\"config deleted: {}\", p.display());\n        return true;\n    }\n    // check the files to see if they've been altered\n    let mut modified = false;\n    for fp in &watch_files {\n        if let Ok(mtime) = fp.metadata().and_then(|m| m.modified()) {\n            if mtime_to_millis(mtime) > PREV_SESSION.latest_update {\n                trace!(\"file modified: {:?}\", fp);\n                modified = true;\n                watch_files::add_modified_file(fp.clone());\n            }\n        } else if !fp.exists() {\n            trace!(\"file deleted: {:?}\", fp);\n            modified = true;\n            watch_files::add_modified_file(fp.clone());\n        }\n    }\n    if !modified {\n        trace!(\"watch files unmodified\");\n    }\n    modified\n}\n\nfn have_mise_env_vars_been_modified() -> bool {\n    get_mise_env_vars_hashed() != PREV_SESSION.env_var_hash\n}\n\n#[derive(Debug, Default, Serialize, Deserialize)]\npub struct HookEnvSession {\n    pub loaded_tools: IndexSet<String>,\n    pub loaded_configs: IndexSet<PathBuf>,\n    pub config_paths: IndexSet<PathBuf>,\n    pub env: EnvMap,\n    #[serde(default)]\n    pub aliases: indexmap::IndexMap<String, String>,\n    /// Files accessed by tera template functions (read_file, hash_file, etc.)\n    /// that should be watched for changes.\n    #[serde(default)]\n    pub tera_files: Vec<PathBuf>,\n    /// Resolved file paths from [[watch_files]] config patterns.\n    /// Stored so the fast-path can detect changes without loading config.\n    #[serde(default)]\n    watch_files: Vec<PathBuf>,\n    dir: Option<PathBuf>,\n    env_var_hash: String,\n    latest_update: u128,\n}\n\npub fn serialize<T: serde::Serialize>(obj: &T) -> Result<String> {\n    let mut gz = ZlibEncoder::new(Vec::new(), Compression::fast());\n    gz.write_all(&rmp_serde::to_vec_named(obj)?)?;\n    Ok(BASE64_STANDARD_NO_PAD.encode(gz.finish()?))\n}\n\npub fn deserialize<T: serde::de::DeserializeOwned>(raw: String) -> Result<T> {\n    let mut writer = Vec::new();\n    let mut decoder = ZlibDecoder::new(writer);\n    let bytes = BASE64_STANDARD_NO_PAD.decode(raw)?;\n    decoder.write_all(&bytes[..])?;\n    writer = decoder.finish()?;\n    Ok(rmp_serde::from_slice(&writer[..])?)\n}\n\npub async fn build_session(\n    config: &Arc<Config>,\n    env: EnvMap,\n    aliases: indexmap::IndexMap<String, String>,\n    loaded_tools: IndexSet<String>,\n    watch_files: BTreeSet<WatchFilePattern>,\n    config_paths: IndexSet<PathBuf>,\n) -> Result<HookEnvSession> {\n    let mut max_modtime = UNIX_EPOCH;\n    let resolved_watch_files = get_watch_files(watch_files)?;\n    for cf in &resolved_watch_files {\n        if let Ok(Ok(modified)) = cf.metadata().map(|m| m.modified()) {\n            max_modtime = std::cmp::max(modified, max_modtime);\n        }\n    }\n    // Include tera template files in max_modtime so latest_update reflects\n    // their mtimes even when watch_files comes from env_cache\n    for tf in &config.tera_files {\n        if let Ok(Ok(modified)) = tf.metadata().map(|m| m.modified()) {\n            max_modtime = std::cmp::max(modified, max_modtime);\n        }\n    }\n\n    let loaded_configs: IndexSet<PathBuf> = config.config_files.keys().cloned().collect();\n\n    // Update the last full check timestamp (only if cache_ttl feature is enabled)\n    let settings = Settings::get();\n    if duration::parse_duration(&settings.hook_env.cache_ttl)\n        .map(|d| d.as_millis() > 0)\n        .unwrap_or(false)\n    {\n        let now = SystemTime::now()\n            .duration_since(UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_millis();\n        write_last_full_check(now);\n    }\n\n    Ok(HookEnvSession {\n        dir: dirs::CWD.clone(),\n        env_var_hash: get_mise_env_vars_hashed(),\n        env,\n        aliases,\n        tera_files: config.tera_files.clone(),\n        watch_files: resolved_watch_files.into_iter().collect(),\n        loaded_configs,\n        loaded_tools,\n        config_paths,\n        latest_update: mtime_to_millis(max_modtime),\n    })\n}\n\npub fn get_watch_files(\n    watch_files: impl IntoIterator<Item = WatchFilePattern>,\n) -> Result<BTreeSet<PathBuf>> {\n    let mut watches = BTreeSet::new();\n    if dirs::DATA.exists() {\n        watches.insert(dirs::DATA.to_path_buf());\n    }\n    if dirs::TRUSTED_CONFIGS.exists() {\n        watches.insert(dirs::TRUSTED_CONFIGS.to_path_buf());\n    }\n    if dirs::IGNORED_CONFIGS.exists() {\n        watches.insert(dirs::IGNORED_CONFIGS.to_path_buf());\n    }\n    for (root, patterns) in &watch_files.into_iter().chunk_by(|wfp| wfp.root.clone()) {\n        if let Some(root) = root {\n            let patterns = patterns.flat_map(|wfp| wfp.patterns).collect::<Vec<_>>();\n            watches.extend(watch_files::glob(&root, &patterns)?);\n        } else {\n            watches.extend(patterns.flat_map(|wfp| wfp.patterns).map(PathBuf::from));\n        }\n    }\n\n    Ok(watches)\n}\n\n/// gets a hash of all MISE_ environment variables\nfn get_mise_env_vars_hashed() -> String {\n    let env_vars: Vec<(&String, &String)> = env::PRISTINE_ENV\n        .deref()\n        .iter()\n        .filter(|(k, _)| k.starts_with(\"MISE_\"))\n        .sorted()\n        .collect();\n    hash_to_str(&env_vars)\n}\n\npub fn clear_old_env(shell: &dyn Shell) -> String {\n    let mut patches = env::__MISE_DIFF.reverse().to_patches();\n\n    // For fish shell, filter out PATH operations from the reversed diff because\n    // fish has its own PATH management that conflicts with ours.\n    if shell.to_string() == \"fish\" {\n        patches.retain(|p| match p {\n            EnvDiffOperation::Add(k, _)\n            | EnvDiffOperation::Change(k, _)\n            | EnvDiffOperation::Remove(k) => k != &*PATH_KEY,\n        });\n        // Fish also needs PATH restored during deactivation\n        let new_path = compute_deactivated_path();\n        patches.push(EnvDiffOperation::Change(PATH_KEY.to_string(), new_path));\n    } else {\n        // For non-fish shells, we need to preserve user-added paths while removing mise paths\n        let new_path = compute_deactivated_path();\n        patches.push(EnvDiffOperation::Change(PATH_KEY.to_string(), new_path));\n    }\n    build_env_commands(shell, &patches)\n}\n\n/// Clear all aliases from the previous session. Called only during deactivation.\npub fn clear_aliases(shell: &dyn Shell) -> String {\n    let mut output = String::new();\n    for name in PREV_SESSION.aliases.keys() {\n        output.push_str(&shell.unset_alias(name));\n    }\n    output\n}\n\n/// Compute PATH after deactivation, preserving user additions\nfn compute_deactivated_path() -> String {\n    // Get current PATH (may include user additions since last hook-env)\n    let current_path = env::var(\"PATH\").unwrap_or_default();\n\n    // Get the PATH that mise set during the last hook-env\n    let mise_paths = &env::__MISE_DIFF.path;\n\n    // Get pristine PATH (from before mise activation)\n    let pristine_path = env::PRISTINE_ENV\n        .deref()\n        .get(&*PATH_KEY)\n        .map(|s| s.to_string())\n        .unwrap_or_default();\n\n    if current_path.is_empty() || mise_paths.is_empty() {\n        // If no current PATH or no mise PATH, just return pristine\n        return pristine_path;\n    }\n\n    // Parse paths\n    let current_paths: Vec<PathBuf> = env::split_paths(&current_path).collect();\n    let mise_paths_vec = mise_paths.clone();\n\n    // Count occurrences of each path in current_path, mise_paths, and pristine_path\n    let pristine_paths: Vec<PathBuf> = env::split_paths(&pristine_path).collect();\n\n    let mut current_counts: std::collections::HashMap<PathBuf, usize> =\n        std::collections::HashMap::new();\n    for path in &current_paths {\n        *current_counts.entry(path.clone()).or_insert(0) += 1;\n    }\n\n    let mut mise_counts: std::collections::HashMap<PathBuf, usize> =\n        std::collections::HashMap::new();\n    for path in &mise_paths_vec {\n        *mise_counts.entry(path.clone()).or_insert(0) += 1;\n    }\n\n    let mut pristine_counts: std::collections::HashMap<PathBuf, usize> =\n        std::collections::HashMap::new();\n    for path in &pristine_paths {\n        *pristine_counts.entry(path.clone()).or_insert(0) += 1;\n    }\n\n    // Determine how many copies of each path we should keep: user additions plus pristine entries\n    use std::collections::HashMap;\n\n    let mut target_counts: HashMap<PathBuf, usize> = HashMap::new();\n    for (path, current_count) in current_counts.iter() {\n        let removal_count = *mise_counts.get(path).unwrap_or(&0);\n        let pristine_count = *pristine_counts.get(path).unwrap_or(&0);\n        let user_and_pristine = current_count\n            .saturating_sub(removal_count)\n            .max(pristine_count);\n        target_counts.insert(path.clone(), user_and_pristine);\n    }\n\n    for (path, pristine_count) in pristine_counts.iter() {\n        target_counts\n            .entry(path.clone())\n            .and_modify(|count| *count = (*count).max(*pristine_count))\n            .or_insert(*pristine_count);\n    }\n\n    let mut kept_counts: HashMap<PathBuf, usize> = HashMap::new();\n    let mut final_paths: Vec<PathBuf> = Vec::new();\n\n    for path in &current_paths {\n        if let Some(target) = target_counts.get(path) {\n            let kept = kept_counts.entry(path.clone()).or_insert(0);\n            if *kept < *target {\n                final_paths.push(path.clone());\n                *kept += 1;\n            }\n        }\n    }\n\n    for path in pristine_paths {\n        let target = target_counts.get(&path).copied().unwrap_or(0);\n        let kept = kept_counts.entry(path.clone()).or_insert(0);\n        while *kept < target {\n            final_paths.push(path.clone());\n            *kept += 1;\n        }\n    }\n\n    env::join_paths(final_paths.iter())\n        .map(|p| p.to_string_lossy().to_string())\n        .unwrap_or(pristine_path)\n}\n\npub fn build_env_commands(shell: &dyn Shell, patches: &EnvDiffPatches) -> String {\n    let mut output = String::new();\n\n    for patch in patches.iter() {\n        match patch {\n            EnvDiffOperation::Add(k, v) | EnvDiffOperation::Change(k, v) => {\n                output.push_str(&shell.set_env(k, v));\n            }\n            EnvDiffOperation::Remove(k) => {\n                output.push_str(&shell.unset_env(k));\n            }\n        }\n    }\n\n    output\n}\n\n/// Build shell alias commands based on the difference between old and new aliases\npub fn build_alias_commands(\n    shell: &dyn Shell,\n    old_aliases: &indexmap::IndexMap<String, String>,\n    new_aliases: &indexmap::IndexMap<String, String>,\n) -> String {\n    let mut output = String::new();\n\n    // Remove aliases that no longer exist or have changed\n    for (name, old_cmd) in old_aliases {\n        match new_aliases.get(name) {\n            Some(new_cmd) if new_cmd != old_cmd => {\n                // Alias changed, unset then set new\n                output.push_str(&shell.unset_alias(name));\n                output.push_str(&shell.set_alias(name, new_cmd));\n            }\n            None => {\n                // Alias removed\n                output.push_str(&shell.unset_alias(name));\n            }\n            _ => {\n                // Alias unchanged, do nothing\n            }\n        }\n    }\n\n    // Add new aliases\n    for (name, cmd) in new_aliases {\n        if !old_aliases.contains_key(name) {\n            output.push_str(&shell.set_alias(name, cmd));\n        }\n    }\n\n    output\n}\n"
  },
  {
    "path": "src/hooks.rs",
    "content": "use crate::cmd::cmd;\nuse crate::config::{Config, Settings, config_file};\nuse crate::shell::Shell;\nuse crate::tera::get_tera;\nuse crate::toolset::{ToolVersion, Toolset};\nuse crate::{dirs, hook_env};\nuse eyre::Result;\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::sync::Mutex;\nuse std::{iter::once, sync::Arc};\nuse tokio::sync::OnceCell;\n\n/// Represents installed tool info for hooks\n#[derive(Debug, Clone, serde::Serialize)]\npub struct InstalledToolInfo {\n    pub name: String,\n    pub version: String,\n}\n\nimpl From<&ToolVersion> for InstalledToolInfo {\n    fn from(tv: &ToolVersion) -> Self {\n        Self {\n            name: tv.ba().short.clone(),\n            version: tv.version.clone(),\n        }\n    }\n}\n\n#[derive(\n    Debug,\n    Clone,\n    Copy,\n    serde::Serialize,\n    serde::Deserialize,\n    strum::Display,\n    Ord,\n    PartialOrd,\n    Eq,\n    PartialEq,\n    Hash,\n)]\n#[serde(rename_all = \"lowercase\")]\npub enum Hooks {\n    Enter,\n    Leave,\n    Cd,\n    Preinstall,\n    Postinstall,\n}\n\n/// Represents a hook definition in TOML config.\n/// Supports string, table, task reference, or array formats via serde untagged deserialization.\n#[derive(Debug, Clone, serde::Deserialize)]\n#[serde(untagged)]\npub enum HookDef {\n    /// Simple script string: `enter = \"echo hello\"`\n    Script(String),\n    /// Table with script and optional shell: `enter = { script = \"echo hello\", shell = \"bash\" }`\n    Table {\n        script: String,\n        shell: Option<String>,\n    },\n    /// Task reference: `enter = { task = \"setup\" }`\n    TaskRef { task: String },\n    /// Array of hook definitions: `enter = [\"echo hello\", { task = \"setup\" }]`\n    Array(Vec<HookDef>),\n}\n\nimpl HookDef {\n    /// Convert to a list of Hook structs with the given hook type\n    pub fn into_hooks(self, hook_type: Hooks) -> Vec<Hook> {\n        match self {\n            HookDef::Script(script) => vec![Hook {\n                hook: hook_type,\n                script,\n                shell: None,\n                task_name: None,\n                global: false,\n            }],\n            HookDef::Table { script, shell } => vec![Hook {\n                hook: hook_type,\n                script,\n                shell,\n                task_name: None,\n                global: false,\n            }],\n            HookDef::TaskRef { task } => vec![Hook {\n                hook: hook_type,\n                script: String::new(),\n                shell: None,\n                task_name: Some(task),\n                global: false,\n            }],\n            HookDef::Array(arr) => arr\n                .into_iter()\n                .flat_map(|d| d.into_hooks(hook_type))\n                .collect(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Hash)]\npub struct Hook {\n    pub hook: Hooks,\n    pub script: String,\n    pub shell: Option<String>,\n    /// Task name to run instead of a script\n    pub task_name: Option<String>,\n    /// Whether this hook comes from a global config (skip directory matching)\n    pub global: bool,\n}\n\npub static SCHEDULED_HOOKS: Lazy<Mutex<IndexSet<Hooks>>> = Lazy::new(Default::default);\n\npub fn schedule_hook(hook: Hooks) {\n    let mut mu = SCHEDULED_HOOKS.lock().unwrap();\n    mu.insert(hook);\n}\n\npub async fn run_all_hooks(config: &Arc<Config>, ts: &Toolset, shell: &dyn Shell) {\n    if Settings::no_hooks() || Settings::get().no_hooks.unwrap_or(false) {\n        return;\n    }\n    let hooks = {\n        let mut mu = SCHEDULED_HOOKS.lock().unwrap();\n        mu.drain(..).collect::<Vec<_>>()\n    };\n    for hook in hooks {\n        run_one_hook(config, ts, hook, Some(shell)).await;\n    }\n}\n\nasync fn all_hooks(config: &Arc<Config>) -> &'static Vec<(PathBuf, Hook)> {\n    static ALL_HOOKS: OnceCell<Vec<(PathBuf, Hook)>> = OnceCell::const_new();\n    ALL_HOOKS\n        .get_or_init(async || {\n            let mut hooks = config.hooks().await.cloned().unwrap_or_default();\n            let cur_configs = config.config_files.keys().cloned().collect::<IndexSet<_>>();\n            let prev_configs = &hook_env::PREV_SESSION.loaded_configs;\n            let old_configs = prev_configs.difference(&cur_configs);\n            for p in old_configs {\n                if let Ok(cf) = config_file::parse(p).await\n                    && let Ok(mut h) = cf.hooks()\n                {\n                    let is_global = cf.project_root().is_none();\n                    if is_global {\n                        for hook in &mut h {\n                            hook.global = true;\n                        }\n                    }\n                    let root = cf.project_root().unwrap_or_else(|| cf.config_root());\n                    hooks.extend(h.into_iter().map(|h| (root.clone(), h)));\n                }\n            }\n            hooks\n        })\n        .await\n}\n\n#[async_backtrace::framed]\npub async fn run_one_hook(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    hook: Hooks,\n    shell: Option<&dyn Shell>,\n) {\n    run_one_hook_with_context(config, ts, hook, shell, None).await\n}\n\n/// Run a hook with optional installed tools context (for postinstall hooks)\n#[async_backtrace::framed]\npub async fn run_one_hook_with_context(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    hook: Hooks,\n    shell: Option<&dyn Shell>,\n    installed_tools: Option<&[InstalledToolInfo]>,\n) {\n    if Settings::no_hooks() || Settings::get().no_hooks.unwrap_or(false) {\n        return;\n    }\n    for (root, h) in all_hooks(config).await {\n        if hook != h.hook || (h.shell.is_some() && h.shell != shell.map(|s| s.to_string())) {\n            continue;\n        }\n        trace!(\"running hook {hook} in {root:?}\");\n        // Global hooks skip directory matching — they fire for all projects\n        if !h.global {\n            match (hook, hook_env::dir_change()) {\n                (Hooks::Enter, Some((old, new))) => {\n                    if !new.starts_with(root) {\n                        continue;\n                    }\n                    if old.as_ref().is_some_and(|old| old.starts_with(root)) {\n                        continue;\n                    }\n                }\n                (Hooks::Leave, Some((old, new))) => {\n                    if new.starts_with(root) {\n                        continue;\n                    }\n                    if old.as_ref().is_some_and(|old| !old.starts_with(root)) {\n                        continue;\n                    }\n                }\n                (Hooks::Cd, Some((_old, new))) => {\n                    if !new.starts_with(root) {\n                        continue;\n                    }\n                }\n                // Pre/postinstall hooks only run if CWD is under the config root\n                (Hooks::Preinstall | Hooks::Postinstall, _) => {\n                    if let Some(cwd) = dirs::CWD.as_ref()\n                        && !cwd.starts_with(root)\n                    {\n                        continue;\n                    }\n                }\n                _ => {}\n            }\n        }\n        if h.task_name.is_some() {\n            if let Err(e) = execute_task(config, ts, root, h, installed_tools).await {\n                warn!(\"{hook} hook in {} failed: {e}\", root.display());\n            }\n        } else if h.shell.is_some() {\n            if let Some(shell) = shell {\n                // Set hook environment variables so shell hooks can access them\n                println!(\n                    \"{}\",\n                    shell.set_env(\"MISE_PROJECT_ROOT\", &root.to_string_lossy())\n                );\n                println!(\n                    \"{}\",\n                    shell.set_env(\"MISE_CONFIG_ROOT\", &root.to_string_lossy())\n                );\n                if let Some(cwd) = dirs::CWD.as_ref() {\n                    println!(\n                        \"{}\",\n                        shell.set_env(\"MISE_ORIGINAL_CWD\", &cwd.to_string_lossy())\n                    );\n                }\n                if let Some((Some(old), _new)) = hook_env::dir_change() {\n                    println!(\n                        \"{}\",\n                        shell.set_env(\"MISE_PREVIOUS_DIR\", &old.to_string_lossy())\n                    );\n                }\n                if let Some(tools) = installed_tools\n                    && let Ok(json) = serde_json::to_string(tools)\n                {\n                    println!(\"{}\", shell.set_env(\"MISE_INSTALLED_TOOLS\", &json));\n                }\n            }\n            println!(\"{}\", h.script);\n        } else if let Err(e) = execute(config, ts, root, h, installed_tools).await {\n            // Warn but continue running remaining hooks of this type\n            warn!(\"{hook} hook in {} failed: {e}\", root.display());\n        }\n    }\n}\n\nasync fn execute(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    root: &Path,\n    hook: &Hook,\n    installed_tools: Option<&[InstalledToolInfo]>,\n) -> Result<()> {\n    Settings::get().ensure_experimental(\"hooks\")?;\n    let shell = Settings::get().default_inline_shell()?;\n\n    // Preinstall hooks skip `tools=true` env directives since the tools\n    // providing those env vars aren't installed yet (fixes #6162)\n    let (tera_ctx, mut env) = if hook.hook == Hooks::Preinstall {\n        let env = ts.full_env_without_tools(config).await?;\n        let mut ctx = config.tera_ctx.clone();\n        ctx.insert(\"env\", &env);\n        (ctx, env)\n    } else {\n        let ctx = ts.tera_ctx(config).await?.clone();\n        let env = ts.full_env(config).await?;\n        (ctx, env)\n    };\n    let mut tera = get_tera(Some(root));\n    let rendered_script = tera.render_str(&hook.script, &tera_ctx)?;\n\n    let args = shell\n        .iter()\n        .skip(1)\n        .map(|s| s.as_str())\n        .chain(once(rendered_script.as_str()))\n        .collect_vec();\n    if let Some(cwd) = dirs::CWD.as_ref() {\n        env.insert(\n            \"MISE_ORIGINAL_CWD\".to_string(),\n            cwd.to_string_lossy().to_string(),\n        );\n    }\n    env.insert(\n        \"MISE_PROJECT_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    if let Some((Some(old), _new)) = hook_env::dir_change() {\n        env.insert(\n            \"MISE_PREVIOUS_DIR\".to_string(),\n            old.to_string_lossy().to_string(),\n        );\n    }\n    // Add installed tools info for postinstall hooks\n    if let Some(tools) = installed_tools\n        && let Ok(json) = serde_json::to_string(tools)\n    {\n        env.insert(\"MISE_INSTALLED_TOOLS\".to_string(), json);\n    }\n    env.insert(\n        \"MISE_CONFIG_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    // Prevent recursive hook execution (e.g. hook runs `mise run` which spawns\n    // a shell that activates mise and re-triggers hooks)\n    env.insert(\"MISE_NO_HOOKS\".to_string(), \"1\".to_string());\n    cmd(&shell[0], args)\n        .stdout_to_stderr()\n        // .dir(root)\n        .full_env(env)\n        .run()?;\n    Ok(())\n}\n\nasync fn execute_task(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    root: &Path,\n    hook: &Hook,\n    installed_tools: Option<&[InstalledToolInfo]>,\n) -> Result<()> {\n    Settings::get().ensure_experimental(\"hooks\")?;\n    let task_name = hook\n        .task_name\n        .as_ref()\n        .ok_or_else(|| eyre::eyre!(\"hook has no task name\"))?;\n\n    let mise_bin = std::env::current_exe().unwrap_or_else(|_| PathBuf::from(\"mise\"));\n\n    let mut env = if hook.hook == Hooks::Preinstall {\n        ts.full_env_without_tools(config).await?\n    } else {\n        ts.full_env(config).await?\n    };\n    if let Some(cwd) = dirs::CWD.as_ref() {\n        env.insert(\n            \"MISE_ORIGINAL_CWD\".to_string(),\n            cwd.to_string_lossy().to_string(),\n        );\n    }\n    env.insert(\n        \"MISE_PROJECT_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    env.insert(\n        \"MISE_CONFIG_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    if let Some((Some(old), _new)) = hook_env::dir_change() {\n        env.insert(\n            \"MISE_PREVIOUS_DIR\".to_string(),\n            old.to_string_lossy().to_string(),\n        );\n    }\n    if let Some(tools) = installed_tools\n        && let Ok(json) = serde_json::to_string(tools)\n    {\n        env.insert(\"MISE_INSTALLED_TOOLS\".to_string(), json);\n    }\n    env.insert(\"MISE_NO_HOOKS\".to_string(), \"1\".to_string());\n\n    cmd(\n        mise_bin,\n        [\"--cd\", &root.to_string_lossy(), \"run\", task_name.as_str()],\n    )\n    .stdout_to_stderr()\n    .full_env(env)\n    .run()?;\n    Ok(())\n}\n"
  },
  {
    "path": "src/http.rs",
    "content": "use std::collections::HashMap;\nuse std::io::Write;\nuse std::path::Path;\nuse std::sync::{Arc, Mutex};\nuse std::time::Duration;\n\nuse base64::Engine;\nuse base64::prelude::BASE64_STANDARD;\nuse eyre::{Report, Result, bail, ensure};\nuse regex::Regex;\nuse reqwest::header::{HeaderMap, HeaderValue};\nuse reqwest::{ClientBuilder, IntoUrl, Method, Response};\nuse std::sync::LazyLock as Lazy;\nuse tokio::sync::OnceCell;\nuse tokio_retry::Retry;\nuse tokio_retry::strategy::{ExponentialBackoff, jitter};\nuse url::Url;\n\nuse crate::cli::version;\nuse crate::config::Settings;\nuse crate::file::display_path;\nuse crate::netrc;\nuse crate::ui::progress_report::SingleReport;\nuse crate::ui::time::format_duration;\nuse crate::{env, file};\n\n#[cfg(not(test))]\npub static HTTP_VERSION_CHECK: Lazy<Client> =\n    Lazy::new(|| Client::new(Duration::from_secs(3), ClientKind::VersionCheck).unwrap());\n\npub static HTTP: Lazy<Client> =\n    Lazy::new(|| Client::new(Settings::get().http_timeout(), ClientKind::Http).unwrap());\n\npub static HTTP_FETCH: Lazy<Client> = Lazy::new(|| {\n    Client::new(\n        Settings::get().fetch_remote_versions_timeout(),\n        ClientKind::Fetch,\n    )\n    .unwrap()\n});\n\n/// In-memory cache for HTTP text responses, useful for requests that are repeated\n/// during a single operation (e.g., fetching SHASUMS256.txt for multiple platforms).\n/// Each URL gets its own OnceCell to ensure concurrent requests for the same URL\n/// wait for the first fetch to complete rather than all fetching simultaneously.\ntype CachedResult = Arc<OnceCell<Result<String, String>>>;\nstatic HTTP_CACHE: Lazy<Mutex<HashMap<String, CachedResult>>> =\n    Lazy::new(|| Mutex::new(HashMap::new()));\n\n#[derive(Debug)]\npub struct Client {\n    reqwest: reqwest::Client,\n    timeout: Duration,\n    kind: ClientKind,\n}\n\n#[derive(Debug, Clone, Copy)]\nenum ClientKind {\n    Http,\n    Fetch,\n    #[allow(dead_code)]\n    VersionCheck,\n}\n\nimpl Client {\n    fn new(timeout: Duration, kind: ClientKind) -> Result<Self> {\n        Ok(Self {\n            reqwest: Self::_new()\n                .read_timeout(timeout)\n                .connect_timeout(timeout)\n                .build()?,\n            timeout,\n            kind,\n        })\n    }\n\n    fn _new() -> ClientBuilder {\n        let v = &*version::VERSION;\n        let shell = env::MISE_SHELL.map(|s| s.to_string()).unwrap_or_default();\n        ClientBuilder::new()\n            .user_agent(format!(\"mise/{v} {shell}\").trim())\n            .gzip(true)\n            .zstd(true)\n    }\n\n    pub async fn get_bytes<U: IntoUrl>(&self, url: U) -> Result<impl AsRef<[u8]>> {\n        let url = url.into_url().unwrap();\n        let resp = self.get_async(url.clone()).await?;\n        Ok(resp.bytes().await?)\n    }\n\n    pub async fn get_async<U: IntoUrl>(&self, url: U) -> Result<Response> {\n        let url = url.into_url().unwrap();\n        let headers = github_headers(&url);\n        self.get_async_with_headers(url, &headers).await\n    }\n\n    async fn get_async_with_headers<U: IntoUrl>(\n        &self,\n        url: U,\n        headers: &HeaderMap,\n    ) -> Result<Response> {\n        ensure!(!Settings::get().offline(), \"offline mode is enabled\");\n        let url = url.into_url().unwrap();\n        let resp = self\n            .send_with_https_fallback(Method::GET, url, headers, \"GET\")\n            .await?;\n        resp.error_for_status_ref()?;\n        Ok(resp)\n    }\n\n    pub async fn head<U: IntoUrl>(&self, url: U) -> Result<Response> {\n        let url = url.into_url().unwrap();\n        let headers = github_headers(&url);\n        self.head_async_with_headers(url, &headers).await\n    }\n\n    pub async fn head_async_with_headers<U: IntoUrl>(\n        &self,\n        url: U,\n        headers: &HeaderMap,\n    ) -> Result<Response> {\n        ensure!(!Settings::get().offline(), \"offline mode is enabled\");\n        let url = url.into_url().unwrap();\n        let resp = self\n            .send_with_https_fallback(Method::HEAD, url, headers, \"HEAD\")\n            .await?;\n        resp.error_for_status_ref()?;\n        Ok(resp)\n    }\n\n    pub async fn get_text<U: IntoUrl>(&self, url: U) -> Result<String> {\n        self.get_text_with_headers(url, &HeaderMap::new()).await\n    }\n\n    pub async fn get_text_with_headers<U: IntoUrl>(\n        &self,\n        url: U,\n        extra_headers: &HeaderMap,\n    ) -> Result<String> {\n        let mut url = url.into_url().unwrap();\n        // Merge GitHub headers with any extra headers provided\n        let mut headers = github_headers(&url);\n        headers.extend(extra_headers.clone());\n        let resp = self.get_async_with_headers(url.clone(), &headers).await?;\n        let text = resp.text().await?;\n        if text.starts_with(\"<!DOCTYPE html>\") {\n            if url.scheme() == \"http\" {\n                // try with https since http may be blocked\n                url.set_scheme(\"https\").unwrap();\n                return Box::pin(self.get_text_with_headers(url, extra_headers)).await;\n            }\n            bail!(\"Got HTML instead of text from {}\", url);\n        }\n        Ok(text)\n    }\n\n    /// Like get_text but caches results in memory for the duration of the process.\n    /// Useful when the same URL will be requested multiple times (e.g., SHASUMS256.txt\n    /// when locking multiple platforms). Concurrent requests for the same URL will\n    /// wait for the first fetch to complete.\n    pub async fn get_text_cached<U: IntoUrl>(&self, url: U) -> Result<String> {\n        let url = url.into_url().unwrap();\n        let key = url.to_string();\n\n        // Get or create the OnceCell for this URL\n        let cell = {\n            let mut cache = HTTP_CACHE.lock().unwrap();\n            cache.entry(key).or_default().clone()\n        };\n\n        // Initialize the cell if needed - concurrent callers will wait\n        let result = cell\n            .get_or_init(|| {\n                let url = url.clone();\n                async move {\n                    match self.get_text(url).await {\n                        Ok(text) => Ok(text),\n                        Err(err) => Err(err.to_string()),\n                    }\n                }\n            })\n            .await;\n\n        match result {\n            Ok(text) => Ok(text.clone()),\n            Err(err) => bail!(\"{}\", err),\n        }\n    }\n\n    pub async fn get_html<U: IntoUrl>(&self, url: U) -> Result<String> {\n        let url = url.into_url().unwrap();\n        let resp = self.get_async(url.clone()).await?;\n        let html = resp.text().await?;\n        if !html.starts_with(\"<!DOCTYPE html>\") {\n            bail!(\"Got non-HTML text from {}\", url);\n        }\n        Ok(html)\n    }\n\n    pub async fn json_headers<T, U: IntoUrl>(&self, url: U) -> Result<(T, HeaderMap)>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        let url = url.into_url().unwrap();\n        let resp = self.get_async(url).await?;\n        let headers = resp.headers().clone();\n        let json = resp.json().await?;\n        Ok((json, headers))\n    }\n\n    pub async fn json_headers_with_headers<T, U: IntoUrl>(\n        &self,\n        url: U,\n        headers: &HeaderMap,\n    ) -> Result<(T, HeaderMap)>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        let url = url.into_url().unwrap();\n        let resp = self.get_async_with_headers(url, headers).await?;\n        let headers = resp.headers().clone();\n        let json = resp.json().await?;\n        Ok((json, headers))\n    }\n\n    pub async fn json<T, U: IntoUrl>(&self, url: U) -> Result<T>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        self.json_headers(url).await.map(|(json, _)| json)\n    }\n\n    /// Like json but caches raw JSON text in memory for the duration of the process.\n    /// Useful when the same URL will be requested multiple times (e.g., zig index.json\n    /// when locking multiple platforms). Concurrent requests for the same URL will\n    /// wait for the first fetch to complete.\n    pub async fn json_cached<T, U: IntoUrl>(&self, url: U) -> Result<T>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        let text = self.get_text_cached(url).await?;\n        Ok(serde_json::from_str(&text)?)\n    }\n\n    pub async fn json_with_headers<T, U: IntoUrl>(&self, url: U, headers: &HeaderMap) -> Result<T>\n    where\n        T: serde::de::DeserializeOwned,\n    {\n        self.json_headers_with_headers(url, headers)\n            .await\n            .map(|(json, _)| json)\n    }\n\n    /// POST JSON data to a URL. Returns Ok(true) on success, Ok(false) on non-success status.\n    /// Errors only on network/connection failures.\n    #[allow(dead_code)]\n    pub async fn post_json<U: IntoUrl, T: serde::Serialize>(\n        &self,\n        url: U,\n        body: &T,\n    ) -> Result<bool> {\n        self.post_json_with_headers(url, body, &HeaderMap::new())\n            .await\n    }\n\n    /// POST JSON data to a URL with custom headers.\n    pub async fn post_json_with_headers<U: IntoUrl, T: serde::Serialize>(\n        &self,\n        url: U,\n        body: &T,\n        headers: &HeaderMap,\n    ) -> Result<bool> {\n        ensure!(!Settings::get().offline(), \"offline mode is enabled\");\n        let url = url.into_url()?;\n        debug!(\"POST {}\", &url);\n        let resp = self\n            .reqwest\n            .post(url)\n            .header(\"Content-Type\", \"application/json\")\n            .headers(headers.clone())\n            .json(body)\n            .send()\n            .await?;\n        Ok(resp.status().is_success())\n    }\n\n    pub async fn download_file<U: IntoUrl>(\n        &self,\n        url: U,\n        path: &Path,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<()> {\n        let url = url.into_url()?;\n        let headers = github_headers(&url);\n        self.download_file_with_headers(url, path, &headers, pr)\n            .await\n    }\n\n    pub async fn download_file_with_headers<U: IntoUrl>(\n        &self,\n        url: U,\n        path: &Path,\n        headers: &HeaderMap,\n        pr: Option<&dyn SingleReport>,\n    ) -> Result<()> {\n        let url = url.into_url()?;\n        debug!(\"GET Downloading {} to {}\", &url, display_path(path));\n        let mut resp = self.get_async_with_headers(url.clone(), headers).await?;\n        if let Some(length) = resp.content_length()\n            && let Some(pr) = pr\n        {\n            // Reset progress on each attempt\n            pr.set_length(length);\n            pr.set_position(0);\n        }\n\n        let parent = path.parent().unwrap();\n        file::create_dir_all(parent)?;\n        let mut file = tempfile::NamedTempFile::with_prefix_in(path, parent)?;\n        while let Some(chunk) = resp.chunk().await? {\n            if crate::ui::ctrlc::is_cancelled() {\n                bail!(\"download cancelled by user\");\n            }\n            file.write_all(&chunk)?;\n            if let Some(pr) = pr {\n                pr.inc(chunk.len() as u64);\n            }\n        }\n        file.persist(path)?;\n        Ok(())\n    }\n\n    async fn send_with_https_fallback(\n        &self,\n        method: Method,\n        url: Url,\n        headers: &HeaderMap,\n        verb_label: &str,\n    ) -> Result<Response> {\n        Retry::spawn(\n            default_backoff_strategy(Settings::get().http_retries),\n            || {\n                let method = method.clone();\n                let url = url.clone();\n                let headers = headers.clone();\n                async move {\n                    match self\n                        .send_once(method.clone(), url.clone(), &headers, verb_label)\n                        .await\n                    {\n                        Ok(resp) => Ok(resp),\n                        Err(_err) if url.scheme() == \"http\" => {\n                            let mut url = url;\n                            url.set_scheme(\"https\").unwrap();\n                            self.send_once(method, url, &headers, verb_label).await\n                        }\n                        Err(err) => Err(err),\n                    }\n                }\n            },\n        )\n        .await\n    }\n\n    async fn send_once(\n        &self,\n        method: Method,\n        mut url: Url,\n        headers: &HeaderMap,\n        verb_label: &str,\n    ) -> Result<Response> {\n        apply_url_replacements(&mut url);\n        debug!(\"{} {}\", verb_label, &url);\n\n        // Apply netrc credentials after URL replacement\n        let mut final_headers = headers.clone();\n        final_headers.extend(netrc_headers(&url));\n\n        let mut req = self.reqwest.request(method, url.clone());\n        req = req.headers(final_headers);\n        let resp = match req.send().await {\n            Ok(resp) => resp,\n            Err(err) => {\n                if err.is_timeout() {\n                    let (setting, env_var) = match self.kind {\n                        ClientKind::Http => (\"http_timeout\", \"MISE_HTTP_TIMEOUT\"),\n                        ClientKind::Fetch => (\n                            \"fetch_remote_versions_timeout\",\n                            \"MISE_FETCH_REMOTE_VERSIONS_TIMEOUT\",\n                        ),\n                        ClientKind::VersionCheck => (\"version_check_timeout\", \"\"),\n                    };\n                    let hint = if env_var.is_empty() {\n                        format!(\n                            \"HTTP timed out after {} for {}.\",\n                            format_duration(self.timeout),\n                            url\n                        )\n                    } else {\n                        format!(\n                            \"HTTP timed out after {} for {} (change with `{}` or env `{}`).\",\n                            format_duration(self.timeout),\n                            url,\n                            setting,\n                            env_var\n                        )\n                    };\n                    bail!(hint);\n                }\n                return Err(err.into());\n            }\n        };\n        if *env::MISE_LOG_HTTP {\n            eprintln!(\"{} {url} {}\", verb_label, resp.status());\n        }\n        debug!(\"{} {url} {}\", verb_label, resp.status());\n        display_github_rate_limit(&resp);\n        resp.error_for_status_ref()?;\n        Ok(resp)\n    }\n}\n\npub fn error_code(e: &Report) -> Option<u16> {\n    if e.to_string().contains(\"404\") {\n        // TODO: not this when I can figure out how to use eyre properly\n        return Some(404);\n    }\n    if let Some(err) = e.downcast_ref::<reqwest::Error>() {\n        err.status().map(|s| s.as_u16())\n    } else {\n        None\n    }\n}\n\nfn github_headers(url: &Url) -> HeaderMap {\n    let mut headers = HeaderMap::new();\n    if url.host_str() == Some(\"api.github.com\")\n        && let Some(token) = &*env::GITHUB_TOKEN\n    {\n        headers.insert(\n            reqwest::header::AUTHORIZATION,\n            HeaderValue::from_str(format!(\"Bearer {token}\").as_str()).unwrap(),\n        );\n        headers.insert(\n            \"x-github-api-version\",\n            HeaderValue::from_static(\"2022-11-28\"),\n        );\n    }\n    headers\n}\n\n/// Get HTTP Basic authentication headers from netrc file for the given URL\nfn netrc_headers(url: &Url) -> HeaderMap {\n    let mut headers = HeaderMap::new();\n    if let Some(host) = url.host_str()\n        && let Some((login, password)) = netrc::get_credentials(host)\n    {\n        let credentials = BASE64_STANDARD.encode(format!(\"{login}:{password}\"));\n        if let Ok(value) = HeaderValue::from_str(&format!(\"Basic {credentials}\")) {\n            headers.insert(reqwest::header::AUTHORIZATION, value);\n        }\n    }\n    headers\n}\n\n/// Apply URL replacements based on settings configuration\n/// Supports both simple string replacement and regex patterns (prefixed with \"regex:\")\npub fn apply_url_replacements(url: &mut Url) {\n    let settings = Settings::get();\n    if let Some(replacements) = &settings.url_replacements {\n        let url_string = url.to_string();\n\n        for (pattern, replacement) in replacements {\n            if let Some(pattern_without_prefix) = pattern.strip_prefix(\"regex:\") {\n                // Regex replacement\n                if let Ok(regex) = Regex::new(pattern_without_prefix) {\n                    let new_url_string = regex.replace(&url_string, replacement.as_str());\n                    // Only proceed if the URL actually changed\n                    if new_url_string != url_string\n                        && let Ok(new_url) = new_url_string.parse()\n                    {\n                        *url = new_url;\n                        trace!(\n                            \"Replaced URL using regex '{}': {} -> {}\",\n                            pattern_without_prefix,\n                            url_string,\n                            url.as_str()\n                        );\n                        return; // Apply only the first matching replacement\n                    }\n                } else {\n                    warn!(\n                        \"Invalid regex pattern in URL replacement: {}\",\n                        pattern_without_prefix\n                    );\n                }\n            } else {\n                // Simple string replacement\n                if url_string.contains(pattern) {\n                    let new_url_string = url_string.replace(pattern, replacement);\n                    // Only proceed if the URL actually changed\n                    if new_url_string != url_string\n                        && let Ok(new_url) = new_url_string.parse()\n                    {\n                        *url = new_url;\n                        trace!(\n                            \"Replaced URL using string replacement '{}': {} -> {}\",\n                            pattern,\n                            url_string,\n                            url.as_str()\n                        );\n                        return; // Apply only the first matching replacement\n                    }\n                }\n            }\n        }\n    }\n}\n\nfn display_github_rate_limit(resp: &Response) {\n    let status = resp.status().as_u16();\n    if status == 403 || status == 429 {\n        let remaining = resp\n            .headers()\n            .get(\"x-ratelimit-remaining\")\n            .and_then(|r| r.to_str().ok());\n        if remaining.is_some_and(|r| r == \"0\") {\n            if let Some(reset_time) = resp\n                .headers()\n                .get(\"x-ratelimit-reset\")\n                .and_then(|h| h.to_str().ok())\n                .and_then(|s| s.parse::<i64>().ok())\n                .and_then(|ts| chrono::DateTime::from_timestamp(ts, 0))\n            {\n                warn!(\n                    \"GitHub rate limit exceeded. Resets at {}\",\n                    reset_time.with_timezone(&chrono::Local)\n                );\n            }\n            return;\n        }\n        // retry-after header is processed only if x-ratelimit-remaining is not 0 or is missing\n        if let Some(retry_after) = resp\n            .headers()\n            .get(\"retry-after\")\n            .and_then(|h| h.to_str().ok())\n            .and_then(|s| s.parse::<u64>().ok())\n        {\n            warn!(\n                \"GitHub rate limit exceeded. Retry after {} seconds\",\n                retry_after\n            );\n        }\n    }\n}\n\nfn default_backoff_strategy(retries: i64) -> impl Iterator<Item = std::time::Duration> {\n    ExponentialBackoff::from_millis(10)\n        .map(jitter)\n        .take(retries.max(0) as usize)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use confique::Partial;\n    use indexmap::IndexMap;\n    use url::Url;\n\n    // Mutex to ensure tests don't interfere with each other when modifying global settings\n    static TEST_SETTINGS_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());\n\n    // Helper to create test settings with specific URL replacements\n    fn with_test_settings<F, R>(replacements: IndexMap<String, String>, test_fn: F) -> R\n    where\n        F: FnOnce() -> R,\n    {\n        // Lock to prevent parallel tests from interfering with global settings\n        let _guard = TEST_SETTINGS_LOCK.lock().unwrap();\n\n        // Create settings with custom URL replacements\n        let mut settings = crate::config::settings::SettingsPartial::empty();\n        settings.url_replacements = Some(replacements);\n\n        // Set settings for this test\n        crate::config::Settings::reset(Some(settings));\n\n        // Run test\n        let result = test_fn();\n\n        // Clean up after test\n        crate::config::Settings::reset(None);\n\n        result\n    }\n\n    #[test]\n    fn test_simple_string_replacement() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\"github.com\".to_string(), \"my-proxy.com\".to_string());\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(url.as_str(), \"https://my-proxy.com/owner/repo\");\n        });\n    }\n\n    #[test]\n    fn test_full_url_string_replacement() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            \"https://github.com\".to_string(),\n            \"https://my-proxy.com/artifactory/github-remote\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(\n                url.as_str(),\n                \"https://my-proxy.com/artifactory/github-remote/owner/repo\"\n            );\n        });\n    }\n\n    #[test]\n    fn test_protocol_specific_replacement() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            \"https://github.com\".to_string(),\n            \"https://secure-proxy.com\".to_string(),\n        );\n\n        with_test_settings(replacements.clone(), || {\n            // HTTPS gets replaced\n            let mut url1 = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url1);\n            assert_eq!(url1.as_str(), \"https://secure-proxy.com/owner/repo\");\n        });\n\n        with_test_settings(replacements, || {\n            // HTTP does not get replaced (no match)\n            let mut url2 = Url::parse(\"http://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url2);\n            assert_eq!(url2.as_str(), \"http://github.com/owner/repo\");\n        });\n    }\n\n    #[test]\n    fn test_regex_replacement() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            r\"regex:https://github\\.com\".to_string(),\n            \"https://my-proxy.com\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(url.as_str(), \"https://my-proxy.com/owner/repo\");\n        });\n    }\n\n    #[test]\n    fn test_regex_with_capture_groups() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            r\"regex:https://github\\.com/([^/]+)/([^/]+)\".to_string(),\n            \"https://my-proxy.com/mirror/$1/$2\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo/releases\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(\n                url.as_str(),\n                \"https://my-proxy.com/mirror/owner/repo/releases\"\n            );\n        });\n    }\n\n    #[test]\n    fn test_regex_invalid_replacement_url() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            r\"regex:https://github\\.com/([^/]+)\".to_string(),\n            \"not-a-valid-url\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            // Invalid result URL should be ignored, original URL unchanged\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            let original = url.clone();\n            apply_url_replacements(&mut url);\n            assert_eq!(url.as_str(), original.as_str());\n        });\n    }\n\n    #[test]\n    fn test_multiple_replacements_first_match_wins() {\n        let mut replacements = IndexMap::new();\n        replacements.insert(\"github.com\".to_string(), \"first-proxy.com\".to_string());\n        replacements.insert(\"github\".to_string(), \"second-proxy.com\".to_string());\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            // First replacement should win\n            assert_eq!(url.as_str(), \"https://first-proxy.com/owner/repo\");\n        });\n    }\n\n    #[test]\n    fn test_no_replacements_configured() {\n        let replacements = IndexMap::new(); // Empty\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            let original = url.clone();\n            apply_url_replacements(&mut url);\n            assert_eq!(url.as_str(), original.as_str());\n        });\n    }\n\n    #[test]\n    fn test_regex_complex_patterns() {\n        let mut replacements = IndexMap::new();\n        // Convert GitHub releases to JFrog Artifactory\n        replacements.insert(\n            r\"regex:https://github\\.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(.+)\".to_string(),\n            \"https://artifactory.company.com/artifactory/github-releases/$1/$2/$3/$4\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            let mut url =\n                Url::parse(\"https://github.com/owner/repo/releases/download/v1.0.0/file.tar.gz\")\n                    .unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(\n                url.as_str(),\n                \"https://artifactory.company.com/artifactory/github-releases/owner/repo/v1.0.0/file.tar.gz\"\n            );\n        });\n    }\n\n    #[test]\n    fn test_no_settings_configured() {\n        // Test the real apply_url_replacements function with no settings override\n        let _guard = TEST_SETTINGS_LOCK.lock().unwrap();\n        crate::config::Settings::reset(None);\n\n        let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n        let original = url.clone();\n\n        // This should not crash and should leave URL unchanged\n        apply_url_replacements(&mut url);\n        assert_eq!(url.as_str(), original.as_str());\n    }\n\n    #[test]\n    fn test_replacement_affects_full_url_not_just_hostname() {\n        // Test that replacement works on the full URL string, not just hostname\n        let mut replacements = IndexMap::new();\n        replacements.insert(\n            \"github.com/owner\".to_string(),\n            \"proxy.com/mirror\".to_string(),\n        );\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/owner/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            // This demonstrates that replacement happens on full URL, not just hostname\n            assert_eq!(url.as_str(), \"https://proxy.com/mirror/repo\");\n        });\n    }\n\n    #[test]\n    fn test_path_replacement_example() {\n        // Test replacing part of the path, proving it's not hostname-only\n        let mut replacements = IndexMap::new();\n        replacements.insert(\"/releases/download/\".to_string(), \"/artifacts/\".to_string());\n\n        with_test_settings(replacements, || {\n            let mut url =\n                Url::parse(\"https://github.com/owner/repo/releases/download/v1.0.0/file.tar.gz\")\n                    .unwrap();\n            apply_url_replacements(&mut url);\n            // Path component was replaced, proving it's full URL replacement\n            assert_eq!(\n                url.as_str(),\n                \"https://github.com/owner/repo/artifacts/v1.0.0/file.tar.gz\"\n            );\n        });\n    }\n\n    #[test]\n    fn test_documentation_examples() {\n        // Test the examples from the documentation to ensure they work correctly\n\n        // Example 1: Simple hostname replacement\n        let mut replacements = IndexMap::new();\n        replacements.insert(\"github.com\".to_string(), \"myregistry.net\".to_string());\n\n        with_test_settings(replacements, || {\n            let mut url = Url::parse(\"https://github.com/user/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(url.as_str(), \"https://myregistry.net/user/repo\");\n        });\n\n        // Example 2: Protocol + hostname replacement\n        let mut replacements2 = IndexMap::new();\n        replacements2.insert(\n            \"https://github.com\".to_string(),\n            \"https://proxy.corp.com/github-mirror\".to_string(),\n        );\n\n        with_test_settings(replacements2, || {\n            let mut url = Url::parse(\"https://github.com/user/repo\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(\n                url.as_str(),\n                \"https://proxy.corp.com/github-mirror/user/repo\"\n            );\n        });\n\n        // Example 3: Domain + path replacement\n        let mut replacements3 = IndexMap::new();\n        replacements3.insert(\n            \"github.com/releases/download/\".to_string(),\n            \"cdn.example.com/artifacts/\".to_string(),\n        );\n\n        with_test_settings(replacements3, || {\n            let mut url =\n                Url::parse(\"https://github.com/releases/download/v1.0.0/file.tar.gz\").unwrap();\n            apply_url_replacements(&mut url);\n            assert_eq!(\n                url.as_str(),\n                \"https://cdn.example.com/artifacts/v1.0.0/file.tar.gz\"\n            );\n        });\n    }\n}\n"
  },
  {
    "path": "src/install_context.rs",
    "content": "use std::sync::Arc;\n\nuse crate::ui::progress_report::SingleReport;\nuse crate::{config::Config, toolset::Toolset};\n\npub struct InstallContext {\n    pub config: Arc<Config>,\n    pub ts: Arc<Toolset>,\n    pub pr: Box<dyn SingleReport>,\n    pub force: bool,\n    pub dry_run: bool,\n    /// require lockfile URLs to be present; fail if not\n    pub locked: bool,\n}\n"
  },
  {
    "path": "src/lock_file.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::dirs;\nuse crate::file::{create_dir_all, display_path};\nuse crate::hash::hash_to_str;\n\npub type OnLockedFn = Box<dyn Fn(&Path)>;\n\npub struct LockFile {\n    path: PathBuf,\n    on_locked: Option<OnLockedFn>,\n}\n\nimpl LockFile {\n    pub fn new(path: &Path) -> Self {\n        let path = dirs::CACHE.join(\"lockfiles\").join(hash_to_str(&path));\n        Self {\n            path,\n            on_locked: None,\n        }\n    }\n\n    pub fn with_callback<F>(mut self, cb: F) -> Self\n    where\n        F: Fn(&Path) + 'static,\n    {\n        self.on_locked = Some(Box::new(cb));\n        self\n    }\n\n    pub fn lock(self) -> Result<fslock::LockFile> {\n        if let Some(parent) = self.path.parent() {\n            create_dir_all(parent)?;\n        }\n        let mut lock = fslock::LockFile::open(&self.path)?;\n        if !lock.try_lock()? {\n            if let Some(f) = self.on_locked {\n                f(&self.path)\n            }\n            lock.lock()?;\n        }\n        Ok(lock)\n    }\n}\n\npub(crate) fn get(path: &Path, force: bool) -> eyre::Result<Option<fslock::LockFile>> {\n    let lock = if force {\n        None\n    } else {\n        let lock = LockFile::new(path)\n            .with_callback(|l| {\n                debug!(\"waiting for lock on {}\", display_path(l));\n            })\n            .lock()?;\n        Some(lock)\n    };\n    Ok(lock)\n}\n"
  },
  {
    "path": "src/lockfile.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::backend::conda::CondaBackend;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::file;\nuse crate::file::display_path;\nuse crate::path::PathExt;\nuse crate::platform::Platform;\nuse crate::toolset::{ToolSource, ToolVersion, ToolVersionList, Toolset};\nuse eyre::{Report, Result, bail, eyre};\nuse itertools::Itertools;\nuse serde_derive::{Deserialize, Serialize};\nuse std::fs;\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::sync::Mutex;\nuse std::{\n    collections::{BTreeMap, BTreeSet, HashMap, HashSet},\n    sync::Arc,\n};\nuse tokio::sync::Semaphore;\nuse tokio::task::JoinSet;\nuse toml_edit::DocumentMut;\nuse xx::regex;\n\n/// Global caches for lockfile data - declared here so invalidation can access them\nstatic ALL_LOCKFILES_CACHE: Lazy<Mutex<HashMap<Vec<PathBuf>, Arc<Lockfile>>>> =\n    Lazy::new(Default::default);\nstatic SINGLE_LOCKFILE_CACHE: Lazy<Mutex<HashMap<PathBuf, Arc<Lockfile>>>> =\n    Lazy::new(Default::default);\n\n/// Invalidate all lockfile caches. Call this after modifying a lockfile.\npub fn invalidate_caches() {\n    if let Ok(mut cache) = ALL_LOCKFILES_CACHE.lock() {\n        cache.clear();\n    }\n    if let Ok(mut cache) = SINGLE_LOCKFILE_CACHE.lock() {\n        cache.clear();\n    }\n}\n\n#[derive(Debug, Clone, Default, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct Lockfile {\n    #[serde(skip)]\n    tools: BTreeMap<String, Vec<LockfileTool>>,\n    /// Shared conda packages: platform -> basename -> CondaPackageInfo\n    /// Basename includes version+build (e.g., \"ncurses-6.4-h7ea286d_0\")\n    #[serde(skip)]\n    conda_packages: BTreeMap<String, BTreeMap<String, CondaPackageInfo>>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]\npub struct LockfileTool {\n    pub version: String,\n    pub backend: Option<String>,\n    #[serde(skip_serializing_if = \"BTreeMap::is_empty\", default)]\n    pub options: BTreeMap<String, String>,\n    #[serde(skip_serializing_if = \"BTreeMap::is_empty\", default)]\n    pub platforms: BTreeMap<String, PlatformInfo>,\n}\n\n/// Type of provenance verification, ordered by priority (lowest to highest).\n/// The ordering is significant: during verification, higher-priority mechanisms\n/// are tried first, and the lockfile records whichever succeeds.\n/// SLSA carries an optional URL for the provenance file (.intoto.jsonl).\n///\n/// If adding or reordering variants, also update `VerifiedAttestation` in\n/// `crates/vfox/src/hooks/pre_install.rs`.\n#[derive(Debug, Clone, strum::Display, strum::EnumIs)]\n#[strum(serialize_all = \"kebab-case\")]\npub enum ProvenanceType {\n    Minisign,\n    Cosign,\n    #[strum(serialize = \"slsa\")]\n    Slsa {\n        url: Option<String>,\n    },\n    GithubAttestations,\n}\n\nimpl std::str::FromStr for ProvenanceType {\n    type Err = String;\n    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {\n        match s {\n            \"minisign\" => Ok(Self::Minisign),\n            \"cosign\" => Ok(Self::Cosign),\n            \"slsa\" => Ok(Self::Slsa { url: None }),\n            \"github-attestations\" => Ok(Self::GithubAttestations),\n            other => Err(format!(\"unknown provenance type: {other}\")),\n        }\n    }\n}\n\n/// PartialEq, Eq, Hash, and Ord all compare by ordinal (variant priority) only.\n/// `Slsa { url: None } == Slsa { url: Some(\"x\") }` — this is intentional so that\n/// variant priority determines equality and ordering, not inner data.\n/// Do NOT use `ProvenanceType` as a `BTreeMap`/`HashSet` key for this reason.\n/// Use `merge()` instead of `max()` when both values may carry data to preserve.\nimpl PartialEq for ProvenanceType {\n    fn eq(&self, other: &Self) -> bool {\n        self.ordinal() == other.ordinal()\n    }\n}\n\nimpl Eq for ProvenanceType {}\n\nimpl std::hash::Hash for ProvenanceType {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.ordinal().hash(state);\n    }\n}\n\nimpl ProvenanceType {\n    /// Discriminant for ordering (lowest = lowest priority)\n    fn ordinal(&self) -> u8 {\n        match self {\n            Self::Minisign => 0,\n            Self::Cosign => 1,\n            Self::Slsa { .. } => 2,\n            Self::GithubAttestations => 3,\n        }\n    }\n\n    /// Merge two provenance values, keeping the higher-priority variant.\n    /// When both are `Slsa`, preserves the URL from whichever has one.\n    fn merge(self, other: Self) -> Self {\n        match (&self, &other) {\n            (Self::Slsa { url: a }, Self::Slsa { url: b }) => Self::Slsa {\n                url: a.clone().or_else(|| b.clone()),\n            },\n            _ => std::cmp::max(self, other),\n        }\n    }\n}\n\nimpl PartialOrd for ProvenanceType {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for ProvenanceType {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.ordinal().cmp(&other.ordinal())\n    }\n}\n\nimpl serde::Serialize for ProvenanceType {\n    fn serialize<S: serde::Serializer>(\n        &self,\n        serializer: S,\n    ) -> std::result::Result<S::Ok, S::Error> {\n        match self {\n            Self::Slsa { url: Some(u) } => {\n                // Serialize as { slsa = { url = \"...\" } } only when URL is present\n                use serde::ser::SerializeMap;\n                let mut slsa_map = std::collections::BTreeMap::new();\n                slsa_map.insert(\"url\", u.as_str());\n                let mut outer = serializer.serialize_map(Some(1))?;\n                outer.serialize_entry(\"slsa\", &slsa_map)?;\n                outer.end()\n            }\n            // Slsa without URL serializes as plain string, like other variants\n            _ => serializer.serialize_str(&self.to_string()),\n        }\n    }\n}\n\nimpl<'de> serde::Deserialize<'de> for ProvenanceType {\n    fn deserialize<D: serde::Deserializer<'de>>(\n        deserializer: D,\n    ) -> std::result::Result<Self, D::Error> {\n        use serde::de;\n\n        struct ProvenanceVisitor;\n        impl<'de> de::Visitor<'de> for ProvenanceVisitor {\n            type Value = ProvenanceType;\n            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n                write!(f, \"a provenance string or table\")\n            }\n            fn visit_str<E: de::Error>(self, s: &str) -> std::result::Result<Self::Value, E> {\n                s.parse().map_err(de::Error::custom)\n            }\n            fn visit_map<A: de::MapAccess<'de>>(\n                self,\n                mut map: A,\n            ) -> std::result::Result<Self::Value, A::Error> {\n                let key: String = map\n                    .next_key()?\n                    .ok_or_else(|| de::Error::custom(\"empty provenance table\"))?;\n                let result = match key.as_str() {\n                    \"slsa\" => {\n                        #[derive(serde_derive::Deserialize)]\n                        struct SlsaInner {\n                            url: Option<String>,\n                        }\n                        let inner: SlsaInner = map.next_value()?;\n                        Ok(ProvenanceType::Slsa { url: inner.url })\n                    }\n                    other => Err(de::Error::custom(format!(\n                        \"unknown provenance table key: {other}\"\n                    ))),\n                }?;\n                // Drain any remaining entries to satisfy strict deserializers\n                while map.next_entry::<String, de::IgnoredAny>()?.is_some() {}\n                Ok(result)\n            }\n        }\n        deserializer.deserialize_any(ProvenanceVisitor)\n    }\n}\n\n#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]\npub struct PlatformInfo {\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub checksum: Option<String>,\n    /// Size in bytes (read-only field, preserved from existing lockfiles but not written)\n    #[serde(skip_serializing, default)]\n    pub size: Option<u64>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub url: Option<String>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub url_api: Option<String>,\n    /// References to conda packages in the shared conda-packages section (by basename)\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub conda_deps: Option<Vec<String>>,\n    /// Type of provenance verification that succeeded (SLSA carries its URL)\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub provenance: Option<ProvenanceType>,\n}\n\n// Re-export CondaPackageInfo from conda backend for lockfile serialization\npub use crate::backend::conda::CondaPackageInfo;\n\nimpl PlatformInfo {\n    /// Returns true if this PlatformInfo has no meaningful data (for serde skip)\n    pub fn is_empty(&self) -> bool {\n        self.checksum.is_none()\n            && self.url.is_none()\n            && self.url_api.is_none()\n            && self.conda_deps.is_none()\n            && self.provenance.is_none()\n    }\n\n    /// Merge this PlatformInfo with another, preserving important data.\n    /// - Prefers sha256 checksums over blake3 (more portable/verifiable)\n    /// - Preserves URL if missing in self\n    /// - Preserves url_api if missing in self\n    pub fn merge_with(&self, other: &PlatformInfo) -> PlatformInfo {\n        // For checksums, prefer sha256 over blake3 since sha256 comes from\n        // official releases and is more portable/verifiable\n        let checksum = match (&self.checksum, &other.checksum) {\n            (Some(self_cs), Some(other_cs)) => {\n                let self_is_sha256 = self_cs.starts_with(\"sha256:\");\n                let other_is_sha256 = other_cs.starts_with(\"sha256:\");\n                match (self_is_sha256, other_is_sha256) {\n                    (true, _) => Some(self_cs.clone()),\n                    (false, true) => Some(other_cs.clone()),\n                    (false, false) => Some(self_cs.clone()), // both blake3, use self\n                }\n            }\n            (Some(cs), None) | (None, Some(cs)) => Some(cs.clone()),\n            (None, None) => None,\n        };\n\n        PlatformInfo {\n            checksum,\n            size: self.size.or(other.size),\n            url: self.url.clone().or_else(|| other.url.clone()),\n            url_api: self.url_api.clone().or_else(|| other.url_api.clone()),\n            conda_deps: self.conda_deps.clone().or_else(|| other.conda_deps.clone()),\n            provenance: match (self.provenance.clone(), other.provenance.clone()) {\n                (Some(a), Some(b)) => Some(a.merge(b)),\n                (a, b) => a.or(b),\n            },\n        }\n    }\n}\n\nimpl TryFrom<toml::Value> for PlatformInfo {\n    type Error = Report;\n    fn try_from(value: toml::Value) -> Result<Self> {\n        match value {\n            toml::Value::String(checksum) => Ok(PlatformInfo {\n                checksum: Some(checksum),\n                ..Default::default()\n            }),\n            toml::Value::Table(mut t) => {\n                let checksum = match t.remove(\"checksum\") {\n                    Some(toml::Value::String(s)) => Some(s),\n                    _ => None,\n                };\n                let size = t\n                    .remove(\"size\")\n                    .and_then(|v| v.as_integer())\n                    .map(|i| i.try_into())\n                    .transpose()?;\n                let url = match t.remove(\"url\") {\n                    Some(toml::Value::String(s)) => Some(s),\n                    _ => None,\n                };\n                let url_api = match t.remove(\"url_api\") {\n                    Some(toml::Value::String(s)) => Some(s),\n                    _ => None,\n                };\n                let conda_deps = match t.remove(\"conda_deps\") {\n                    Some(toml::Value::Array(arr)) => Some(\n                        arr.into_iter()\n                            .filter_map(|v| v.as_str().map(String::from))\n                            .collect(),\n                    ),\n                    _ => None,\n                };\n                // Legacy: read provenance_url for backwards compat with old lockfiles\n                let legacy_provenance_url = match t.remove(\"provenance_url\") {\n                    Some(toml::Value::String(s)) => Some(s),\n                    _ => None,\n                };\n                let provenance = match t.remove(\"provenance\") {\n                    Some(toml::Value::String(s)) => {\n                        let mut prov: ProvenanceType = s\n                            .parse()\n                            .map_err(|_| eyre!(\"unrecognized provenance type {s:?} in lockfile\"))?;\n                        // Attach legacy provenance_url to SLSA if present\n                        if let ProvenanceType::Slsa { ref mut url } = prov {\n                            *url = legacy_provenance_url;\n                        }\n                        Some(prov)\n                    }\n                    Some(toml::Value::Table(mut prov_table)) => {\n                        if let Some(slsa_val) = prov_table.remove(\"slsa\") {\n                            let slsa_url = match slsa_val {\n                                toml::Value::Table(mut st) => match st.remove(\"url\") {\n                                    Some(toml::Value::String(u)) => Some(u),\n                                    _ => None,\n                                },\n                                _ => None,\n                            };\n                            Some(ProvenanceType::Slsa { url: slsa_url })\n                        } else {\n                            // Unknown table variant\n                            let keys: Vec<_> = prov_table.keys().cloned().collect();\n                            bail!(\n                                \"unrecognized provenance table format in lockfile: {:?}\",\n                                keys\n                            );\n                        }\n                    }\n                    _ => None,\n                };\n                Ok(PlatformInfo {\n                    checksum,\n                    size,\n                    url,\n                    url_api,\n                    conda_deps,\n                    provenance,\n                })\n            }\n            _ => bail!(\"unsupported asset info format\"),\n        }\n    }\n}\n\nimpl From<PlatformInfo> for toml::Value {\n    fn from(platform_info: PlatformInfo) -> Self {\n        let mut table = toml::Table::new();\n        if let Some(checksum) = platform_info.checksum {\n            table.insert(\"checksum\".to_string(), checksum.into());\n        }\n        if let Some(url) = platform_info.url {\n            table.insert(\"url\".to_string(), url.into());\n        }\n        if let Some(url_api) = platform_info.url_api {\n            table.insert(\"url_api\".to_string(), url_api.into());\n        }\n        if let Some(conda_deps) = platform_info.conda_deps {\n            let deps: toml::Value = conda_deps\n                .into_iter()\n                .map(toml::Value::String)\n                .collect::<Vec<_>>()\n                .into();\n            table.insert(\"conda_deps\".to_string(), deps);\n        }\n        if let Some(ref provenance) = platform_info.provenance {\n            match provenance {\n                ProvenanceType::Slsa { url: Some(url) } => {\n                    let mut slsa_table = toml::Table::new();\n                    slsa_table.insert(\"url\".to_string(), url.clone().into());\n                    let mut prov_table = toml::Table::new();\n                    prov_table.insert(\"slsa\".to_string(), toml::Value::Table(slsa_table));\n                    table.insert(\"provenance\".to_string(), toml::Value::Table(prov_table));\n                }\n                // Slsa without URL and all other variants serialize as plain string\n                _ => {\n                    table.insert(\"provenance\".to_string(), provenance.to_string().into());\n                }\n            }\n        }\n        toml::Value::Table(table)\n    }\n}\n\nimpl TryFrom<toml::Value> for CondaPackageInfo {\n    type Error = Report;\n    fn try_from(value: toml::Value) -> Result<Self> {\n        match value {\n            toml::Value::Table(mut t) => {\n                let url = t\n                    .remove(\"url\")\n                    .and_then(|v| match v {\n                        toml::Value::String(s) => Some(s),\n                        _ => None,\n                    })\n                    .ok_or_else(|| eyre::eyre!(\"missing url in conda package info\"))?;\n                let checksum = match t.remove(\"checksum\") {\n                    Some(toml::Value::String(s)) => Some(s),\n                    _ => None,\n                };\n                Ok(CondaPackageInfo { url, checksum })\n            }\n            _ => bail!(\"unsupported conda package info format\"),\n        }\n    }\n}\n\nimpl Lockfile {\n    pub fn read<P: AsRef<Path>>(path: P) -> Result<Self> {\n        let path = path.as_ref();\n        if !path.exists() {\n            return Ok(Lockfile::default());\n        }\n        trace!(\"reading lockfile {}\", path.display_user());\n        let content = file::read_to_string(path)?;\n        let mut table: toml::Table = toml::from_str(&content)?;\n\n        let tools: toml::Table = table\n            .remove(\"tools\")\n            .unwrap_or(toml::Table::new().into())\n            .try_into()?;\n\n        let mut lockfile = Lockfile::default();\n\n        for (short, value) in tools {\n            let versions = match value {\n                toml::Value::Array(arr) => arr\n                    .into_iter()\n                    .map(LockfileTool::try_from)\n                    .collect::<Result<Vec<_>>>()?,\n                _ => bail!(\n                    \"invalid lockfile format for tool {short}: expected array ([[tools.{short}]])\"\n                ),\n            };\n            lockfile.tools.insert(short, versions);\n        }\n\n        // Parse conda-packages section: platform -> basename -> CondaPackageInfo\n        if let Some(conda_packages) = table.remove(\"conda-packages\") {\n            let platforms: toml::Table = conda_packages.try_into()?;\n            for (platform, packages) in platforms {\n                let packages_table: toml::Table = packages.try_into()?;\n                for (basename, info) in packages_table {\n                    let info: CondaPackageInfo = info.try_into()?;\n                    lockfile\n                        .conda_packages\n                        .entry(platform.clone())\n                        .or_default()\n                        .insert(basename, info);\n                }\n            }\n        }\n\n        Ok(lockfile)\n    }\n\n    fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {\n        let mut lockfile = toml::Table::new();\n\n        // Write conda-packages section first (before tools for nicer ordering)\n        if !self.conda_packages.is_empty() {\n            let mut conda_packages = toml::Table::new();\n            for (platform, packages) in &self.conda_packages {\n                let mut platform_table = toml::Table::new();\n                for (basename, info) in packages {\n                    let mut pkg_table = toml::Table::new();\n                    pkg_table.insert(\"url\".to_string(), info.url.clone().into());\n                    if let Some(checksum) = &info.checksum {\n                        pkg_table.insert(\"checksum\".to_string(), checksum.clone().into());\n                    }\n                    platform_table.insert(basename.clone(), pkg_table.into());\n                }\n                conda_packages.insert(platform.clone(), platform_table.into());\n            }\n            lockfile.insert(\"conda-packages\".to_string(), conda_packages.into());\n        }\n\n        // Write tools section\n        let mut tools = toml::Table::new();\n        for (short, versions) in &self.tools {\n            // Always write Multi-Version format (array format) for consistency\n            let value: toml::Value = versions\n                .iter()\n                .cloned()\n                .map(|version| version.into_toml_value())\n                .collect::<Vec<toml::Value>>()\n                .into();\n            tools.insert(short.clone(), value);\n        }\n        lockfile.insert(\"tools\".to_string(), tools.into());\n\n        let content = toml::to_string_pretty(&toml::Value::Table(lockfile))?;\n        let content = format(content.parse()?);\n        let content = format!(\n            \"# @generated - this file is auto-generated by `mise lock` https://mise.jdx.dev/dev-tools/mise-lock.html\\n\\\n                 \\n\\\n                 {content}\"\n        );\n\n        let path = path.as_ref();\n        // Resolve the symlink target first, before writing the temp file\n        let target = if path.is_symlink() {\n            // If the existing lockfile is a symlink, resolve it and update the target instead\n            // of replacing the symlink\n            trace!(\n                \"lockfile {} is a symlink, updating target instead of replacing\",\n                display_path(path)\n            );\n\n            match fs::canonicalize(path) {\n                Ok(link_target) => {\n                    trace!(\n                        \"resolved lockfile symlink {} to {}\",\n                        display_path(path),\n                        display_path(&link_target)\n                    );\n                    link_target\n                }\n                Err(e) => {\n                    // Dangling symlink – fall back to overwriting the symlink itself\n                    // TODO: Maybe instead of overwriting, we should create the new lockfile at\n                    // the symlink's target path?\n                    warn!(\n                        \"lockfile {} is a dangling symlink ({}), overwriting the symlink itself\",\n                        display_path(path),\n                        e\n                    );\n                    path.to_path_buf()\n                }\n            }\n        } else {\n            path.to_path_buf()\n        };\n        // Use atomic write: write to temp file, then rename\n        // This prevents partial writes from corrupting the lockfile\n        // Write temp file alongside the real target (guarantees same-filesystem rename)\n        let temp_path = target.with_extension(\"lock.tmp\");\n        file::write(&temp_path, &content)?;\n        fs::rename(&temp_path, target)?;\n\n        invalidate_caches();\n        Ok(())\n    }\n\n    /// Add or update a conda package in the shared section\n    /// `basename` is without extension, e.g., \"ncurses-6.4-h7ea286d_0\"\n    pub fn set_conda_package(&mut self, platform: &str, basename: &str, info: CondaPackageInfo) {\n        self.conda_packages\n            .entry(platform.to_string())\n            .or_default()\n            .insert(basename.to_string(), info);\n    }\n\n    /// Get a conda package from the shared section by basename\n    pub fn get_conda_package(&self, platform: &str, basename: &str) -> Option<&CondaPackageInfo> {\n        self.conda_packages.get(platform)?.get(basename)\n    }\n\n    /// Remove unreferenced conda packages from the shared section.\n    /// A package is unreferenced if no tool's conda_deps references it.\n    fn cleanup_unreferenced_conda_packages(&mut self) {\n        // Collect all referenced conda packages (platform -> set of basenames)\n        let mut referenced: HashMap<String, HashSet<String>> = HashMap::new();\n        for tools in self.tools.values() {\n            for tool in tools {\n                for (platform, info) in &tool.platforms {\n                    if let Some(deps) = &info.conda_deps {\n                        for dep in deps {\n                            referenced\n                                .entry(platform.clone())\n                                .or_default()\n                                .insert(dep.clone());\n                        }\n                    }\n                }\n            }\n        }\n\n        // Remove unreferenced packages\n        for (platform, packages) in &mut self.conda_packages {\n            let referenced_for_platform = referenced.get(platform);\n            packages.retain(|basename, _| {\n                referenced_for_platform\n                    .map(|refs| refs.contains(basename))\n                    .unwrap_or(false)\n            });\n        }\n\n        // Remove empty platform entries\n        self.conda_packages\n            .retain(|_, packages| !packages.is_empty());\n    }\n\n    /// Get all platform keys present in the lockfile\n    pub fn all_platform_keys(&self) -> BTreeSet<String> {\n        let mut platforms = BTreeSet::new();\n        for tools in self.tools.values() {\n            for tool in tools {\n                for platform_key in tool.platforms.keys() {\n                    platforms.insert(platform_key.clone());\n                }\n            }\n        }\n        platforms\n    }\n\n    /// Keep only tools matching configured short names or backend identifiers.\n    /// Also removes conda packages that become unreferenced.\n    pub fn retain_tools_by_short_or_backend(\n        &mut self,\n        keep_shorts: &BTreeSet<String>,\n        keep_backends: &BTreeSet<String>,\n    ) {\n        self.tools.retain(|short, versions| {\n            Self::should_keep_tool(short, versions, keep_shorts, keep_backends)\n        });\n        self.cleanup_unreferenced_conda_packages();\n    }\n\n    /// Return tool keys that would be removed by `retain_tools_by_short_or_backend`.\n    pub fn stale_tool_shorts(\n        &self,\n        keep_shorts: &BTreeSet<String>,\n        keep_backends: &BTreeSet<String>,\n    ) -> BTreeSet<String> {\n        self.tools\n            .iter()\n            .filter_map(|(short, versions)| {\n                (!Self::should_keep_tool(short, versions, keep_shorts, keep_backends))\n                    .then_some(short.clone())\n            })\n            .collect()\n    }\n\n    fn should_keep_tool(\n        short: &str,\n        versions: &[LockfileTool],\n        keep_shorts: &BTreeSet<String>,\n        keep_backends: &BTreeSet<String>,\n    ) -> bool {\n        keep_shorts.contains(short)\n            || versions\n                .iter()\n                .filter_map(|v| v.backend.as_ref())\n                .any(|backend| keep_backends.contains(backend))\n    }\n\n    /// Update or add platform info for a tool version\n    /// Merges with existing info, preserving fields we don't have new values for\n    pub fn set_platform_info(\n        &mut self,\n        short: &str,\n        version: &str,\n        backend: Option<&str>,\n        options: &BTreeMap<String, String>,\n        platform_key: &str,\n        platform_info: PlatformInfo,\n    ) {\n        let tools = self.tools.entry(short.to_string()).or_default();\n        // Find existing tool version with matching options or create new one\n        if let Some(tool) = tools\n            .iter_mut()\n            .find(|t| t.version == version && &t.options == options)\n        {\n            // Merge with existing platform info, preferring new values when present\n            let merged = if let Some(existing) = tool.platforms.get(platform_key) {\n                PlatformInfo {\n                    checksum: platform_info.checksum.or_else(|| existing.checksum.clone()),\n                    size: platform_info.size.or(existing.size),\n                    url: platform_info.url.or_else(|| existing.url.clone()),\n                    url_api: platform_info.url_api.or_else(|| existing.url_api.clone()),\n                    // For conda_deps, always use the new value - None means \"no dependencies\"\n                    // rather than \"not computed\", so we shouldn't preserve stale deps\n                    conda_deps: platform_info.conda_deps,\n                    provenance: match (platform_info.provenance, existing.provenance.clone()) {\n                        (Some(a), Some(b)) => Some(a.merge(b)),\n                        (a, b) => a.or(b),\n                    },\n                }\n            } else {\n                platform_info\n            };\n            // Only insert non-empty platform info to avoid `\"platforms.linux-x64\" = {}`\n            if !merged.is_empty() {\n                tool.platforms.insert(platform_key.to_string(), merged);\n            }\n        } else {\n            let mut platforms = BTreeMap::new();\n            // Only insert non-empty platform info\n            if !platform_info.is_empty() {\n                platforms.insert(platform_key.to_string(), platform_info);\n            }\n            tools.push(LockfileTool {\n                version: version.to_string(),\n                backend: backend.map(|s| s.to_string()),\n                options: options.clone(),\n                platforms,\n            });\n        }\n    }\n\n    /// Save the lockfile to disk (public for mise lock command)\n    pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<()> {\n        self.save(path)\n    }\n}\n\n/// Determines the lockfile path for a given config file path\n/// Returns (lockfile_path, is_local)\n///\n/// Lockfiles are placed alongside their config files:\n/// - `mise.toml` -> `mise.lock`\n/// - `.config/mise.toml` -> `.config/mise.lock`\n/// - `.mise/config.toml` -> `.mise/mise.lock`\n/// - `.mise/conf.d/foo.toml` -> `.mise/mise.lock` (conf.d files share parent's lockfile)\npub fn lockfile_path_for_config(config_path: &Path) -> (PathBuf, bool) {\n    let is_local = is_local_config(config_path);\n    let env = extract_env_from_config_path(config_path);\n    let lockfile_name = match (&env, is_local) {\n        (Some(e), true) => format!(\"mise.{e}.local.lock\"),\n        (Some(e), false) => format!(\"mise.{e}.lock\"),\n        (None, true) => \"mise.local.lock\".to_string(),\n        (None, false) => \"mise.lock\".to_string(),\n    };\n\n    let parent = config_path.parent().unwrap_or(Path::new(\".\"));\n    let parent_name = parent\n        .file_name()\n        .and_then(|n| n.to_str())\n        .unwrap_or_default();\n\n    // For conf.d files, place lockfile at parent of conf.d so all conf.d files share one lockfile\n    let lockfile_dir = if parent_name == \"conf.d\" {\n        parent.parent().unwrap_or(parent)\n    } else {\n        parent\n    };\n\n    (lockfile_dir.join(lockfile_name), is_local)\n}\n\n/// Checks if a config path is a \"local\" config (should go to mise.local.lock)\nfn is_local_config(path: &Path) -> bool {\n    let filename = path\n        .file_name()\n        .and_then(|n| n.to_str())\n        .unwrap_or_default();\n    filename.contains(\".local.\")\n}\n\n/// Extracts environment name from config filename\n/// e.g., \"mise.test.toml\" -> Some(\"test\"), \"mise.test.local.toml\" -> Some(\"test\"), \"mise.toml\" -> None\npub fn extract_env_from_config_path(path: &Path) -> Option<String> {\n    let filename = path\n        .file_name()\n        .and_then(|n| n.to_str())\n        .unwrap_or_default();\n\n    // Pattern matches:\n    // - mise.{env}.toml -> captures env\n    // - mise.{env}.local.toml -> captures env (env-specific local config)\n    // - .mise.{env}.toml -> captures env\n    // - config.{env}.toml -> captures env\n    // Does NOT match (returns None):\n    // - mise.toml, .mise.toml, config.toml (base configs)\n    // - mise.local.toml (local without env - filtered by \"local\" check)\n    let re = regex!(r\"^(?:\\.?mise|config)\\.([^.]+)(?:\\.local)?\\.toml$\");\n    re.captures(filename)\n        .and_then(|caps| caps.get(1))\n        .map(|m| m.as_str().to_string())\n        .filter(|s| s != \"local\")\n}\n\npub fn update_lockfiles(config: &Config, ts: &Toolset, new_versions: &[ToolVersion]) -> Result<()> {\n    if !Settings::get().lockfile_enabled() || Settings::get().locked {\n        return Ok(());\n    }\n\n    // Collect tools by source (config file)\n    let mut tools_by_source: HashMap<ToolSource, HashMap<String, ToolVersionList>> = HashMap::new();\n    for (source, group) in &ts.versions.iter().chunk_by(|(_, tvl)| &tvl.source) {\n        for (ba, tvl) in group {\n            tools_by_source\n                .entry(source.clone())\n                .or_default()\n                .insert(ba.short.to_string(), tvl.clone());\n        }\n    }\n\n    // Add versions added within this session (from `mise use` or `mise up`)\n    for (backend, group) in &new_versions.iter().chunk_by(|tv| tv.ba()) {\n        let tvs = group.cloned().collect_vec();\n        let source = tvs[0].request.source().clone();\n        let source_tools = tools_by_source.entry(source.clone()).or_default();\n\n        if let Some(existing_tvl) = source_tools.get_mut(&backend.short) {\n            for new_tv in tvs {\n                existing_tvl\n                    .versions\n                    .retain(|tv| tv.request.version() != new_tv.request.version());\n                existing_tvl.versions.push(new_tv);\n            }\n        } else {\n            let mut tvl = ToolVersionList::new(Arc::new(backend.clone()), source.clone());\n            tvl.versions.extend(tvs);\n            source_tools.insert(backend.short.to_string(), tvl);\n        }\n    }\n\n    // Group config files by target lockfile path\n    let mut lockfile_configs: HashMap<PathBuf, Vec<PathBuf>> = HashMap::new();\n    for (config_path, cf) in config.config_files.iter().rev() {\n        if !cf.source().is_mise_toml() {\n            continue;\n        }\n        let (lockfile_path, _is_local) = lockfile_path_for_config(config_path);\n        lockfile_configs\n            .entry(lockfile_path)\n            .or_default()\n            .push(config_path.clone());\n    }\n\n    debug!(\"updating {} lockfiles\", lockfile_configs.len());\n\n    // Process each lockfile\n    for (lockfile_path, configs) in lockfile_configs {\n        // Only update existing lockfiles - creation is done elsewhere (e.g., by `mise lock`)\n        if !lockfile_path.exists() {\n            continue;\n        }\n\n        trace!(\n            \"updating lockfile {} from {} config files\",\n            display_path(&lockfile_path),\n            configs.len()\n        );\n\n        let mut existing_lockfile = Lockfile::read(&lockfile_path)\n            .unwrap_or_else(|err| handle_lockfile_read_error(err, &lockfile_path));\n\n        // Collect all tools from all contributing configs\n        let mut tools_by_short: HashMap<String, Vec<LockfileTool>> = HashMap::new();\n\n        for config_path in &configs {\n            let tool_source = ToolSource::MiseToml(config_path.clone());\n            if let Some(tools) = tools_by_source.get(&tool_source) {\n                for (short, tvl) in tools {\n                    let lockfile_tools: Vec<LockfileTool> = tvl.clone().into();\n                    for tool in lockfile_tools {\n                        tools_by_short.entry(short.clone()).or_default().push(tool);\n                    }\n                }\n            }\n        }\n\n        // Process each tool with deduplication\n        for (short, entries) in tools_by_short {\n            let merged_tools = merge_tool_entries(entries, existing_lockfile.tools.get(&short));\n            existing_lockfile.tools.insert(short, merged_tools);\n        }\n\n        // Merge conda packages from new_versions into the lockfile\n        for tv in new_versions {\n            for ((platform, basename), pkg_info) in &tv.conda_packages {\n                existing_lockfile.set_conda_package(platform, basename, pkg_info.clone());\n            }\n        }\n\n        // Clean up any conda packages that are no longer referenced by any tool\n        existing_lockfile.cleanup_unreferenced_conda_packages();\n\n        existing_lockfile.save(&lockfile_path)?;\n    }\n\n    Ok(())\n}\n\n/// Determine target platforms for lockfile operations.\n/// Returns the 5 common platforms + current platform + any existing platforms in the lockfile.\npub fn determine_target_platforms(lockfile_path: &Path) -> Vec<Platform> {\n    let lockfile = Lockfile::read(lockfile_path).ok();\n    determine_target_platforms_from_lockfile(lockfile.as_ref())\n}\n\n/// Determine target platforms using an already-loaded lockfile.\nfn determine_target_platforms_from_lockfile(lockfile: Option<&Lockfile>) -> Vec<Platform> {\n    let mut platforms: BTreeSet<Platform> = Platform::common_platforms().into_iter().collect();\n    platforms.insert(Platform::current());\n    if let Some(lockfile) = lockfile {\n        for platform_key in lockfile.all_platform_keys() {\n            if let Ok(p) = Platform::parse(&platform_key)\n                && p.validate().is_ok()\n            {\n                platforms.insert(p);\n            }\n        }\n    }\n    platforms.into_iter().collect()\n}\n\n/// After installing new tool versions, resolve checksums/URLs for all common platforms\n/// so the lockfile is complete and doesn't change when other developers on different\n/// platforms run `mise install`.\npub async fn auto_lock_new_versions(_config: &Config, new_versions: &[ToolVersion]) -> Result<()> {\n    if !Settings::get().lockfile_enabled() || Settings::get().locked || new_versions.is_empty() {\n        return Ok(());\n    }\n\n    // Group new_versions by lockfile path (only mise.toml sources, matching update_lockfiles)\n    let mut versions_by_lockfile: HashMap<PathBuf, Vec<&ToolVersion>> = HashMap::new();\n    for tv in new_versions {\n        if !tv.request.source().is_mise_toml() {\n            continue;\n        }\n        if let Some(source_path) = tv.request.source().path() {\n            let (lockfile_path, _) = lockfile_path_for_config(source_path);\n            versions_by_lockfile\n                .entry(lockfile_path)\n                .or_default()\n                .push(tv);\n        }\n    }\n\n    let settings = Settings::get();\n    let jobs = settings.jobs;\n\n    for (lockfile_path, versions) in versions_by_lockfile {\n        // Only update existing lockfiles (consistent with update_lockfiles)\n        if !lockfile_path.exists() {\n            continue;\n        }\n\n        let mut lockfile = Lockfile::read(&lockfile_path)\n            .unwrap_or_else(|err| handle_lockfile_read_error(err, &lockfile_path));\n\n        let target_platforms = determine_target_platforms_from_lockfile(Some(&lockfile));\n\n        let semaphore = Arc::new(Semaphore::new(jobs));\n        let mut jset: JoinSet<LockResolutionResult> = JoinSet::new();\n\n        for tv in &versions {\n            let ba = tv.ba().clone();\n            let backend = crate::backend::get(&ba);\n\n            for platform in &target_platforms {\n                // Expand platform variants from the backend\n                let variants = if let Some(ref backend) = backend {\n                    backend.platform_variants(platform)\n                } else {\n                    vec![platform.clone()]\n                };\n\n                for variant in variants {\n                    let platform_key = variant.to_key();\n\n                    // Skip if this tool/version/platform already has both checksum and URL\n                    if let Some(tools) = lockfile.tools.get(&ba.short)\n                        && let Some(tool) = tools.iter().find(|t| t.version == tv.version)\n                        && let Some(info) = tool.platforms.get(&platform_key)\n                        && info.checksum.is_some()\n                        && info.url.is_some()\n                    {\n                        continue;\n                    }\n\n                    let semaphore = semaphore.clone();\n                    let ba = ba.clone();\n                    let tv = (*tv).clone();\n                    let backend = backend.clone();\n\n                    jset.spawn(async move {\n                        let _permit = semaphore.acquire().await;\n                        resolve_tool_lock_info(ba, tv, variant, backend).await\n                    });\n                }\n            }\n        }\n\n        // Collect results and update lockfile\n        while let Some(result) = jset.join_next().await {\n            match result {\n                Ok(resolution) => {\n                    if let Err(msg) = &resolution.4 {\n                        debug!(\"auto-lock: {msg}\");\n                    }\n                    apply_lock_result(&mut lockfile, resolution);\n                }\n                Err(e) => {\n                    debug!(\"auto-lock task failed: {}\", e);\n                }\n            }\n        }\n\n        lockfile.save(&lockfile_path)?;\n    }\n\n    Ok(())\n}\n\n/// Result type for lock resolution tasks (shared by `mise lock` and auto-lock).\n///\n/// Fields: (short_name, version, backend_full, platform, info_or_error, options, conda_packages).\n/// The `info_or_error` field is `Ok(info)` on success or `Err(message)` on failure,\n/// allowing callers to log at the appropriate level.\npub type LockResolutionResult = (\n    String,\n    String,\n    String,\n    Platform,\n    Result<PlatformInfo, String>,\n    BTreeMap<String, String>,\n    BTreeMap<String, CondaPackageInfo>,\n);\n\n/// Resolve lock info for a single tool/platform combination.\n///\n/// Returns a tuple of (short_name, version, backend_full, platform, info_or_error, options, conda_packages).\n/// Does not log errors — callers decide the appropriate log level.\npub async fn resolve_tool_lock_info(\n    ba: crate::cli::args::BackendArg,\n    tv: ToolVersion,\n    platform: Platform,\n    backend: Option<crate::backend::ABackend>,\n) -> LockResolutionResult {\n    let target = PlatformTarget::new(platform.clone());\n\n    let (info, options, conda_packages) = if let Some(backend) = backend {\n        let options = backend.resolve_lockfile_options(&tv.request, &target);\n        match backend.resolve_lock_info(&tv, &target).await {\n            Ok(info) => {\n                let conda_packages = if backend.get_type() == BackendType::Conda {\n                    let conda_backend = CondaBackend::from_arg(ba.clone());\n                    match conda_backend.resolve_conda_packages(&tv, &target).await {\n                        Ok(packages) => packages,\n                        Err(e) => {\n                            debug!(\n                                \"failed to resolve conda packages for {} on {}: {}\",\n                                ba.short,\n                                platform.to_key(),\n                                e\n                            );\n                            BTreeMap::new()\n                        }\n                    }\n                } else {\n                    BTreeMap::new()\n                };\n                (Ok(info), options, conda_packages)\n            }\n            Err(e) => (\n                Err(format!(\n                    \"failed to resolve {} for {}: {}\",\n                    ba.short,\n                    platform.to_key(),\n                    e\n                )),\n                options,\n                BTreeMap::new(),\n            ),\n        }\n    } else {\n        (\n            Err(format!(\"backend not found for {}\", ba.short)),\n            BTreeMap::new(),\n            BTreeMap::new(),\n        )\n    };\n\n    (\n        ba.short.clone(),\n        tv.version.clone(),\n        ba.full(),\n        platform,\n        info,\n        options,\n        conda_packages,\n    )\n}\n\n/// Apply a lock resolution result to a lockfile, updating platform info and conda packages.\n/// Only applies data when the resolution succeeded (info is `Ok`).\npub fn apply_lock_result(lockfile: &mut Lockfile, result: LockResolutionResult) {\n    let (short, version, backend, platform, info, options, conda_packages) = result;\n    let platform_key = platform.to_key();\n    if let Ok(info) = info {\n        lockfile.set_platform_info(\n            &short,\n            &version,\n            Some(&backend),\n            &options,\n            &platform_key,\n            info,\n        );\n    }\n    for (basename, pkg_info) in conda_packages {\n        lockfile.set_conda_package(&platform_key, &basename, pkg_info);\n    }\n}\n\n/// Merge tool entries with deduplication by (version, options).\n/// Merges platform info for entries with the same key.\n/// Preserves existing platform info for matching entries.\nfn merge_tool_entries(\n    entries: Vec<LockfileTool>,\n    existing_tools: Option<&Vec<LockfileTool>>,\n) -> Vec<LockfileTool> {\n    // Group by (version, options) - the key for deduplication\n    let mut by_key: HashMap<(String, BTreeMap<String, String>), LockfileTool> = HashMap::new();\n\n    for tool in entries {\n        let key = (tool.version.clone(), tool.options.clone());\n        let entry = by_key.entry(key).or_insert_with(|| tool.clone());\n\n        // Merge platforms - properly combine platform info to preserve URLs and prefer sha256\n        for (platform, info) in tool.platforms {\n            entry\n                .platforms\n                .entry(platform)\n                .and_modify(|existing| *existing = info.merge_with(existing))\n                .or_insert(info);\n        }\n    }\n\n    // Merge with existing tools to preserve platform info\n    if let Some(existing) = existing_tools {\n        for existing_tool in existing {\n            let key = (existing_tool.version.clone(), existing_tool.options.clone());\n            if let Some(entry) = by_key.get_mut(&key) {\n                // Merge platform info from existing - preserve URLs and prefer sha256\n                for (platform, info) in &existing_tool.platforms {\n                    entry\n                        .platforms\n                        .entry(platform.clone())\n                        .and_modify(|existing| *existing = existing.merge_with(info))\n                        .or_insert(info.clone());\n                }\n            }\n        }\n    }\n\n    // Convert to final list\n    by_key\n        .into_values()\n        .sorted_by(|a, b| a.version.cmp(&b.version))\n        .collect()\n}\n\nfn read_all_lockfiles(config: &Config) -> Arc<Lockfile> {\n    // Create a cache key from the config file paths\n    let cache_key: Vec<PathBuf> = config.config_files.keys().cloned().collect();\n\n    // Use unwrap_or_else to recover from poisoned mutex (thread panicked while holding lock)\n    let mut cache = ALL_LOCKFILES_CACHE\n        .lock()\n        .unwrap_or_else(|e| e.into_inner());\n    if let Some(cached) = cache.get(&cache_key) {\n        return Arc::clone(cached);\n    }\n\n    let mut seen_roots: HashSet<PathBuf> = HashSet::new();\n    let mut all: Vec<Lockfile> = Vec::new();\n\n    for (path, cf) in config.config_files.iter().rev() {\n        if !cf.source().is_mise_toml() {\n            continue;\n        }\n\n        let (lockfile_path, _) = lockfile_path_for_config(path);\n        let root = lockfile_path.parent().unwrap_or(path).to_path_buf();\n        if seen_roots.contains(&root) {\n            continue;\n        }\n        seen_roots.insert(root.clone());\n\n        // Read lockfiles in priority order (highest first):\n        // 1. mise.<env>.local.lock (if MISE_ENV is set)\n        // 2. mise.local.lock\n        // 3. mise.<env>.lock (if MISE_ENV is set)\n        // 4. mise.lock\n        for env_name in env::MISE_ENV.iter() {\n            let p = root.join(format!(\"mise.{env_name}.local.lock\"));\n            if let Ok(l) = Lockfile::read(&p) {\n                all.push(l);\n            }\n        }\n        let local_path = root.join(\"mise.local.lock\");\n        if let Ok(local) = Lockfile::read(&local_path) {\n            all.push(local);\n        }\n        for env_name in env::MISE_ENV.iter() {\n            let p = root.join(format!(\"mise.{env_name}.lock\"));\n            if let Ok(l) = Lockfile::read(&p) {\n                all.push(l);\n            }\n        }\n        let main_path = root.join(\"mise.lock\");\n        if let Ok(main) = Lockfile::read(&main_path) {\n            all.push(main);\n        }\n    }\n\n    let result = all.into_iter().fold(Lockfile::default(), |mut acc, l| {\n        for (short, tools) in l.tools {\n            let existing = acc.tools.entry(short).or_default();\n            for tool in tools {\n                // Avoid duplicates (same version+options)\n                if !existing\n                    .iter()\n                    .any(|t| t.version == tool.version && t.options == tool.options)\n                {\n                    existing.push(tool);\n                }\n            }\n        }\n        acc\n    });\n\n    let result = Arc::new(result);\n    cache.insert(cache_key, Arc::clone(&result));\n    result\n}\n\nfn read_lockfile_for(path: &Path) -> Arc<Lockfile> {\n    // Use unwrap_or_else to recover from poisoned mutex (thread panicked while holding lock)\n    let mut cache = SINGLE_LOCKFILE_CACHE\n        .lock()\n        .unwrap_or_else(|e| e.into_inner());\n    if let Some(cached) = cache.get(path) {\n        return Arc::clone(cached);\n    }\n\n    // Only compute lockfile path when not cached\n    let (lockfile_path, _is_local) = lockfile_path_for_config(path);\n    let lockfile = Lockfile::read(&lockfile_path)\n        .unwrap_or_else(|err| handle_lockfile_read_error(err, &lockfile_path));\n\n    let lockfile = Arc::new(lockfile);\n    cache.insert(path.to_path_buf(), Arc::clone(&lockfile));\n    lockfile\n}\n\npub fn get_locked_version(\n    config: &Config,\n    path: Option<&Path>,\n    short: &str,\n    prefix: &str,\n    request_options: &BTreeMap<String, String>,\n) -> Result<Option<LockfileTool>> {\n    let settings = Settings::get();\n    if !settings.lockfile_enabled() {\n        return Ok(None);\n    }\n\n    let lockfile = match path {\n        Some(path) => {\n            trace!(\n                \"[{short}@{prefix}] reading lockfile for {}\",\n                display_path(path)\n            );\n            read_lockfile_for(path)\n        }\n        None => {\n            trace!(\"[{short}@{prefix}] reading all lockfiles\");\n            read_all_lockfiles(config)\n        }\n    };\n\n    if let Some(tools) = lockfile.tools.get(short) {\n        // Filter by version prefix and options\n        let mut matching: Vec<_> = tools\n            .iter()\n            .filter(|v| {\n                let norm_prefix = prefix\n                    .strip_prefix('v')\n                    .or(prefix.strip_prefix('V'))\n                    .unwrap_or(prefix);\n                let norm_version = v\n                    .version\n                    .strip_prefix('v')\n                    .or(v.version.strip_prefix('V'))\n                    .unwrap_or(&v.version);\n                let version_matches = prefix == \"latest\" || norm_version.starts_with(norm_prefix);\n                let options_match = &v.options == request_options;\n                version_matches && options_match\n            })\n            .collect();\n\n        // Only sort when prefix is \"latest\" and we have multiple matches\n        // This is expensive, so avoid it for specific version prefixes\n        if prefix == \"latest\" && matching.len() > 1 {\n            matching.sort_by(|a, b| {\n                versions::Versioning::new(&b.version).cmp(&versions::Versioning::new(&a.version))\n            });\n        }\n\n        if let Some(found) = matching.first() {\n            trace!(\"[{short}@{prefix}] found {} in lockfile\", found.version);\n            return Ok(Some((*found).clone()));\n        }\n    }\n\n    Ok(None)\n}\n\n/// Get the backend for a tool from the lockfile, ignoring options.\n/// This is used for backend discovery where we just need any entry's backend.\npub fn get_locked_backend(config: &Config, short: &str) -> Option<String> {\n    let settings = Settings::get();\n    if !settings.lockfile_enabled() {\n        return None;\n    }\n\n    let lockfile = read_all_lockfiles(config);\n\n    lockfile\n        .tools\n        .get(short)\n        .and_then(|tools| tools.first())\n        .and_then(|tool| tool.backend.clone())\n}\n\nfn handle_lockfile_read_error(err: Report, lockfile_path: &Path) -> Lockfile {\n    // Differentiate between \"file not found\" (fine) and \"parse error\" (problem)\n    // File not found is expected when lockfile doesn't exist yet\n    if let Some(io_err) = err.downcast_ref::<std::io::Error>()\n        && io_err.kind() == std::io::ErrorKind::NotFound\n    {\n        trace!(\n            \"lockfile {} not found, using empty lockfile\",\n            display_path(lockfile_path)\n        );\n        return Lockfile::default();\n    }\n    // For other errors (parse errors, permission issues), warn the user\n    // as this could indicate data loss or corruption\n    warn!(\n        \"failed to read lockfile {} (possible corruption): {err:?}\",\n        display_path(lockfile_path)\n    );\n    Lockfile::default()\n}\n\nimpl TryFrom<toml::Value> for LockfileTool {\n    type Error = Report;\n    fn try_from(value: toml::Value) -> Result<Self> {\n        let tool = match value {\n            toml::Value::String(v) => LockfileTool {\n                version: v,\n                backend: Default::default(),\n                options: Default::default(),\n                platforms: Default::default(),\n            },\n            toml::Value::Table(mut t) => {\n                let mut platforms = BTreeMap::new();\n                // Handle nested platforms table format: [tools.X.platforms.linux-x64]\n                if let Some(platforms_table) = t.remove(\"platforms\") {\n                    let platforms_table: toml::Table = platforms_table.try_into()?;\n                    for (platform, platform_info) in platforms_table {\n                        platforms.insert(platform, platform_info.try_into()?);\n                    }\n                }\n                // Handle inline table format: \"platforms.linux-x64\" = { ... }\n                let platform_keys: Vec<_> = t\n                    .keys()\n                    .filter(|k| k.starts_with(\"platforms.\"))\n                    .cloned()\n                    .collect();\n                for key in platform_keys {\n                    if let Some(platform_info) = t.remove(&key) {\n                        let platform_name = key.strip_prefix(\"platforms.\").unwrap().to_string();\n                        platforms.insert(platform_name, platform_info.try_into()?);\n                    }\n                }\n                let mut options = BTreeMap::new();\n                if let Some(opts) = t.remove(\"options\") {\n                    let opts_table: toml::Table = opts.try_into()?;\n                    for (key, value) in opts_table {\n                        if let toml::Value::String(s) = value {\n                            options.insert(key, s);\n                        }\n                    }\n                }\n                // Silently discard env field from old lockfiles for backwards compat\n                t.remove(\"env\");\n                LockfileTool {\n                    version: t\n                        .remove(\"version\")\n                        .map(|v| v.try_into())\n                        .transpose()?\n                        .unwrap_or_default(),\n                    backend: t\n                        .remove(\"backend\")\n                        .map(|v| v.try_into())\n                        .transpose()?\n                        .unwrap_or_default(),\n                    options,\n                    platforms,\n                }\n            }\n            _ => bail!(\"unsupported lockfile format {}\", value),\n        };\n        Ok(tool)\n    }\n}\n\nimpl LockfileTool {\n    fn into_toml_value(self) -> toml::Value {\n        let mut table = toml::Table::new();\n        table.insert(\"version\".to_string(), self.version.into());\n        if let Some(backend) = self.backend {\n            table.insert(\"backend\".to_string(), backend.into());\n        }\n        if !self.options.is_empty() {\n            let opts_table: toml::Table = self\n                .options\n                .into_iter()\n                .map(|(k, v)| (k, toml::Value::String(v)))\n                .collect();\n            table.insert(\"options\".to_string(), toml::Value::Table(opts_table));\n        }\n        if !self.platforms.is_empty() {\n            table.insert(\"platforms\".to_string(), self.platforms.clone().into());\n        }\n        table.into()\n    }\n}\n\nimpl From<ToolVersionList> for Vec<LockfileTool> {\n    fn from(tvl: ToolVersionList) -> Self {\n        use crate::backend::platform_target::PlatformTarget;\n\n        tvl.versions\n            .iter()\n            .map(|tv| {\n                let mut platforms = BTreeMap::new();\n\n                // Convert tool version lock_platforms to lockfile platforms\n                for (platform, platform_info) in &tv.lock_platforms {\n                    platforms.insert(platform.clone(), platform_info.clone());\n                }\n\n                // Resolve lockfile options from the backend\n                let options = if let Ok(backend) = tv.request.backend() {\n                    let target = PlatformTarget::from_current();\n                    backend.resolve_lockfile_options(&tv.request, &target)\n                } else {\n                    BTreeMap::new()\n                };\n\n                LockfileTool {\n                    version: tv.version.clone(),\n                    backend: Some(tv.ba().stored_full()),\n                    options,\n                    platforms,\n                }\n            })\n            .collect()\n    }\n}\n\nfn format(mut doc: DocumentMut) -> String {\n    if let Some(tools) = doc.get_mut(\"tools\") {\n        for (_k, v) in tools.as_table_mut().unwrap().iter_mut() {\n            if let toml_edit::Item::ArrayOfTables(art) = v {\n                for t in art.iter_mut() {\n                    t.sort_values_by(|a, _, b, _| {\n                        if a == \"version\" {\n                            return std::cmp::Ordering::Less;\n                        }\n                        if b == \"version\" {\n                            return std::cmp::Ordering::Greater;\n                        }\n                        a.to_string().cmp(&b.to_string())\n                    });\n                    // TODO: use TOML 1.1 multiline inline tables once toml_edit supports\n                    // InlineTable::set_multiline(). See https://github.com/toml-rs/toml/issues/1027\n                    // Convert platforms to dotted-key subtables (multi-line)\n                    if let Some(toml_edit::Item::Table(platforms_table)) = t.remove(\"platforms\") {\n                        for (platform_key, platform_value) in platforms_table.iter() {\n                            if let toml_edit::Item::Table(platform_info) = platform_value {\n                                let dotted_key = format!(\"platforms.{}\", platform_key);\n                                let mut subtable = toml_edit::Table::new();\n                                let mut keys: Vec<_> =\n                                    platform_info.iter().map(|(k, _)| k.to_string()).collect();\n                                keys.sort_by_key(|k| match k.as_str() {\n                                    \"checksum\" => 0,\n                                    \"size\" => 1,\n                                    \"url\" => 2,\n                                    \"url_api\" => 3,\n                                    \"provenance\" => 4,\n                                    _ => 5,\n                                });\n                                for k in &keys {\n                                    if let Some(item) = platform_info.get(k) {\n                                        subtable.insert(k, item.clone());\n                                    }\n                                }\n                                subtable.set_implicit(true);\n                                t.insert(&dotted_key, toml_edit::Item::Table(subtable));\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    doc.to_string()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::collections::{BTreeMap, BTreeSet};\n\n    fn basic_tool(version: &str, backend: &str) -> LockfileTool {\n        LockfileTool {\n            version: version.to_string(),\n            backend: Some(backend.to_string()),\n            options: BTreeMap::new(),\n            platforms: BTreeMap::new(),\n        }\n    }\n\n    fn tool_with_conda_dep(\n        version: &str,\n        backend: &str,\n        platform: &str,\n        dep: &str,\n    ) -> LockfileTool {\n        let mut platforms = BTreeMap::new();\n        platforms.insert(\n            platform.to_string(),\n            PlatformInfo {\n                checksum: None,\n                size: None,\n                url: None,\n                url_api: None,\n                conda_deps: Some(vec![dep.to_string()]),\n                ..Default::default()\n            },\n        );\n        LockfileTool {\n            version: version.to_string(),\n            backend: Some(backend.to_string()),\n            options: BTreeMap::new(),\n            platforms,\n        }\n    }\n\n    fn add_test_conda_package(lockfile: &mut Lockfile, platform: &str, basename: &str) {\n        lockfile.set_conda_package(\n            platform,\n            basename,\n            CondaPackageInfo {\n                url: format!(\"https://example.com/{basename}.conda\"),\n                checksum: Some(format!(\"sha256:{basename}\")),\n            },\n        );\n    }\n\n    #[test]\n    fn test_array_format_required() {\n        // Test that multi-version (array) format is read correctly\n        let multi_version_toml = r#\"\n[[tools.node]]\nversion = \"20.10.0\"\nbackend = \"core:node\"\n\n[[tools.python]]\nversion = \"3.11.0\"\nbackend = \"core:python\"\n\"#;\n\n        let table: toml::Table = toml::from_str(multi_version_toml).unwrap();\n        let tools: toml::Table = table.get(\"tools\").unwrap().clone().try_into().unwrap();\n\n        let mut lockfile = Lockfile::default();\n        for (short, value) in tools {\n            let versions = match value {\n                toml::Value::Array(arr) => arr\n                    .into_iter()\n                    .map(LockfileTool::try_from)\n                    .collect::<Result<Vec<_>>>()\n                    .unwrap(),\n                _ => panic!(\"expected array format\"),\n            };\n            lockfile.tools.insert(short, versions);\n        }\n\n        // Verify that we have the expected tools\n        assert_eq!(lockfile.tools.len(), 2);\n        assert!(lockfile.tools.contains_key(\"node\"));\n        assert!(lockfile.tools.contains_key(\"python\"));\n\n        // Verify node\n        let node_versions = &lockfile.tools[\"node\"];\n        assert_eq!(node_versions.len(), 1);\n        assert_eq!(node_versions[0].version, \"20.10.0\");\n        assert_eq!(node_versions[0].backend, Some(\"core:node\".to_string()));\n\n        // Verify python\n        let python_versions = &lockfile.tools[\"python\"];\n        assert_eq!(python_versions.len(), 1);\n        assert_eq!(python_versions[0].version, \"3.11.0\");\n    }\n\n    #[test]\n    fn test_save_uses_array_format() {\n        let mut lockfile = Lockfile::default();\n        let mut platforms = BTreeMap::new();\n        platforms.insert(\n            \"macos-arm64\".to_string(),\n            PlatformInfo {\n                checksum: Some(\"sha256:abc123\".to_string()),\n                size: Some(12345678),\n                url: Some(\"https://example.com/node.tar.gz\".to_string()),\n                url_api: Some(\"https://api.github.com.com/repos/test/1234\".to_string()),\n                conda_deps: None,\n                ..Default::default()\n            },\n        );\n\n        let tool = LockfileTool {\n            version: \"20.10.0\".to_string(),\n            backend: Some(\"core:node\".to_string()),\n            options: BTreeMap::new(),\n            platforms,\n        };\n\n        lockfile.tools.insert(\"node\".to_string(), vec![tool]);\n\n        // Create a temporary file to test saving\n        let temp_dir = std::env::temp_dir();\n        let test_lockfile = temp_dir.join(\"test_lockfile.lock\");\n\n        // Save and verify it uses multi-version format\n        lockfile.save(&test_lockfile).unwrap();\n\n        let content = std::fs::read_to_string(&test_lockfile).unwrap();\n\n        // Should use [[tools.node]] array syntax, not [tools.node] single version\n        assert!(content.contains(\"[[tools.node]]\"));\n        // Verify it doesn't use single-version format (but allow platforms sections)\n        assert!(!content.lines().any(|line| line.trim() == \"[tools.node]\"));\n\n        // Clean up\n        let _ = std::fs::remove_file(&test_lockfile);\n    }\n\n    #[test]\n    fn test_options_field_parsing_and_serialization() {\n        // Test parsing lockfile with options\n        let toml_with_options = r#\"\n[[tools.ripgrep]]\nversion = \"14.0.0\"\nbackend = \"ubi:BurntSushi/ripgrep\"\noptions = { exe = \"rg\", matching = \"musl\" }\n\n[tools.ripgrep.platforms.linux-x64]\nchecksum = \"blake3:abc123\"\n\"#;\n\n        let table: toml::Table = toml::from_str(toml_with_options).unwrap();\n        let tools: toml::Table = table.get(\"tools\").unwrap().clone().try_into().unwrap();\n\n        let mut lockfile = Lockfile::default();\n        for (short, value) in tools {\n            let versions = match value {\n                toml::Value::Array(arr) => arr\n                    .into_iter()\n                    .map(LockfileTool::try_from)\n                    .collect::<Result<Vec<_>>>()\n                    .unwrap(),\n                _ => vec![LockfileTool::try_from(value).unwrap()],\n            };\n            lockfile.tools.insert(short, versions);\n        }\n\n        // Verify options were parsed correctly\n        let ripgrep = &lockfile.tools[\"ripgrep\"][0];\n        assert_eq!(ripgrep.options.get(\"exe\"), Some(&\"rg\".to_string()));\n        assert_eq!(ripgrep.options.get(\"matching\"), Some(&\"musl\".to_string()));\n    }\n\n    #[test]\n    fn test_options_field_not_serialized_when_empty() {\n        let mut lockfile = Lockfile::default();\n        let tool = LockfileTool {\n            version: \"14.0.0\".to_string(),\n            backend: Some(\"ubi:BurntSushi/ripgrep\".to_string()),\n            options: BTreeMap::new(), // Empty options\n            platforms: BTreeMap::new(),\n        };\n        lockfile.tools.insert(\"ripgrep\".to_string(), vec![tool]);\n\n        let temp_dir = std::env::temp_dir();\n        let test_lockfile = temp_dir.join(\"test_lockfile_no_options.lock\");\n\n        lockfile.save(&test_lockfile).unwrap();\n        let content = std::fs::read_to_string(&test_lockfile).unwrap();\n\n        // Should NOT contain \"options\" when it's empty\n        assert!(!content.contains(\"options\"));\n\n        let _ = std::fs::remove_file(&test_lockfile);\n    }\n\n    #[test]\n    fn test_options_field_serialized_when_present() {\n        let mut lockfile = Lockfile::default();\n        let mut options = BTreeMap::new();\n        options.insert(\"exe\".to_string(), \"rg\".to_string());\n        options.insert(\"matching\".to_string(), \"musl\".to_string());\n\n        let tool = LockfileTool {\n            version: \"14.0.0\".to_string(),\n            backend: Some(\"ubi:BurntSushi/ripgrep\".to_string()),\n            options,\n            platforms: BTreeMap::new(),\n        };\n        lockfile.tools.insert(\"ripgrep\".to_string(), vec![tool]);\n\n        let temp_dir = std::env::temp_dir();\n        let test_lockfile = temp_dir.join(\"test_lockfile_with_options.lock\");\n\n        lockfile.save(&test_lockfile).unwrap();\n        let content = std::fs::read_to_string(&test_lockfile).unwrap();\n\n        // Should contain options\n        assert!(content.contains(\"options\"));\n        assert!(content.contains(\"exe\"));\n        assert!(content.contains(\"rg\"));\n\n        let _ = std::fs::remove_file(&test_lockfile);\n    }\n\n    #[test]\n    fn test_options_matching_in_get_locked_version() {\n        // This tests that get_locked_version requires exact options match\n        let toml_with_options = r#\"\n[[tools.ripgrep]]\nversion = \"14.0.0\"\nbackend = \"ubi:BurntSushi/ripgrep\"\noptions = { exe = \"rg\", matching = \"musl\" }\n\n[[tools.ripgrep]]\nversion = \"14.0.0\"\nbackend = \"ubi:BurntSushi/ripgrep\"\noptions = { exe = \"rg\" }\n\"#;\n\n        let table: toml::Table = toml::from_str(toml_with_options).unwrap();\n        let tools: toml::Table = table.get(\"tools\").unwrap().clone().try_into().unwrap();\n\n        let mut lockfile = Lockfile::default();\n        for (short, value) in tools {\n            let versions = match value {\n                toml::Value::Array(arr) => arr\n                    .into_iter()\n                    .map(LockfileTool::try_from)\n                    .collect::<Result<Vec<_>>>()\n                    .unwrap(),\n                _ => vec![LockfileTool::try_from(value).unwrap()],\n            };\n            lockfile.tools.insert(short, versions);\n        }\n\n        // Verify we have 2 entries for ripgrep with different options\n        assert_eq!(lockfile.tools[\"ripgrep\"].len(), 2);\n        assert_eq!(lockfile.tools[\"ripgrep\"][0].options.len(), 2);\n        assert_eq!(lockfile.tools[\"ripgrep\"][1].options.len(), 1);\n    }\n\n    #[test]\n    fn test_lockfile_path_for_config() {\n        // Simple case: mise.toml in project root\n        let (path, is_local) = lockfile_path_for_config(Path::new(\"/foo/bar/mise.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/mise.lock\"));\n        assert!(!is_local);\n\n        // Local config\n        let (path, is_local) = lockfile_path_for_config(Path::new(\"/foo/bar/mise.local.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/mise.local.lock\"));\n        assert!(is_local);\n\n        // Config in .config directory\n        let (path, is_local) = lockfile_path_for_config(Path::new(\"/foo/bar/.config/mise.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/.config/mise.lock\"));\n        assert!(!is_local);\n\n        // Config in .mise directory\n        let (path, is_local) = lockfile_path_for_config(Path::new(\"/foo/bar/.mise/config.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/.mise/mise.lock\"));\n        assert!(!is_local);\n\n        // Config in conf.d directory - should go to parent of conf.d\n        let (path, is_local) =\n            lockfile_path_for_config(Path::new(\"/foo/bar/.mise/conf.d/foo.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/.mise/mise.lock\"));\n        assert!(!is_local);\n\n        // Config in .config/mise/conf.d directory\n        let (path, is_local) =\n            lockfile_path_for_config(Path::new(\"/foo/bar/.config/mise/conf.d/foo.toml\"));\n        assert_eq!(path, PathBuf::from(\"/foo/bar/.config/mise/mise.lock\"));\n        assert!(!is_local);\n    }\n\n    #[test]\n    fn test_conda_packages_parsing() {\n        let toml_with_conda = r#\"\n[conda-packages.\"macos-arm64\"]\n\"ncurses-6.4-h7ea286d_0\" = { url = \"https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4-h7ea286d_0.conda\", checksum = \"sha256:abc123\" }\n\"readline-8.2-h92ec313_1\" = { url = \"https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda\" }\n\n[[tools.jq]]\nversion = \"1.7.1\"\nbackend = \"conda:jq\"\n\"platforms.macos-arm64\" = { url = \"https://example.com/jq.conda\", checksum = \"sha256:def456\", conda_deps = [\"ncurses-6.4-h7ea286d_0\", \"readline-8.2-h92ec313_1\"] }\n\"#;\n\n        let temp_dir = std::env::temp_dir();\n        let test_lockfile = temp_dir.join(\"test_conda_parse.lock\");\n        std::fs::write(&test_lockfile, toml_with_conda).unwrap();\n\n        let lockfile = Lockfile::read(&test_lockfile).unwrap();\n\n        // Verify conda packages were parsed\n        let macos_packages = lockfile.conda_packages.get(\"macos-arm64\").unwrap();\n        assert_eq!(macos_packages.len(), 2);\n\n        let ncurses = macos_packages.get(\"ncurses-6.4-h7ea286d_0\").unwrap();\n        assert_eq!(\n            ncurses.url,\n            \"https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4-h7ea286d_0.conda\"\n        );\n        assert_eq!(ncurses.checksum, Some(\"sha256:abc123\".to_string()));\n\n        let readline = macos_packages.get(\"readline-8.2-h92ec313_1\").unwrap();\n        assert!(readline.checksum.is_none());\n\n        // Verify tool with conda_deps was parsed\n        let jq = &lockfile.tools[\"jq\"][0];\n        let platform_info = jq.platforms.get(\"macos-arm64\").unwrap();\n        assert_eq!(\n            platform_info.conda_deps,\n            Some(vec![\n                \"ncurses-6.4-h7ea286d_0\".to_string(),\n                \"readline-8.2-h92ec313_1\".to_string()\n            ])\n        );\n\n        let _ = std::fs::remove_file(&test_lockfile);\n    }\n\n    #[test]\n    fn test_conda_packages_serialization() {\n        let mut lockfile = Lockfile::default();\n\n        // Add conda packages\n        lockfile.set_conda_package(\n            \"macos-arm64\",\n            \"ncurses-6.4-h7ea286d_0\",\n            CondaPackageInfo {\n                url: \"https://example.com/ncurses.conda\".to_string(),\n                checksum: Some(\"sha256:abc123\".to_string()),\n            },\n        );\n\n        // Add a tool with conda_deps\n        let mut platforms = BTreeMap::new();\n        platforms.insert(\n            \"macos-arm64\".to_string(),\n            PlatformInfo {\n                url: Some(\"https://example.com/jq.conda\".to_string()),\n                checksum: Some(\"sha256:def456\".to_string()),\n                size: None,\n                url_api: None,\n                conda_deps: Some(vec![\"ncurses-6.4-h7ea286d_0\".to_string()]),\n                ..Default::default()\n            },\n        );\n        lockfile.tools.insert(\n            \"jq\".to_string(),\n            vec![LockfileTool {\n                version: \"1.7.1\".to_string(),\n                backend: Some(\"conda:jq\".to_string()),\n                options: BTreeMap::new(),\n                platforms,\n            }],\n        );\n\n        let temp_dir = std::env::temp_dir();\n        let test_lockfile = temp_dir.join(\"test_conda_serialize.lock\");\n\n        lockfile.save(&test_lockfile).unwrap();\n        let content = std::fs::read_to_string(&test_lockfile).unwrap();\n\n        // Verify content contains conda-packages section (TOML formats it as nested tables)\n        assert!(\n            content.contains(\"conda-packages\"),\n            \"content should contain conda-packages section: {content}\"\n        );\n        assert!(\n            content.contains(\"ncurses-6.4-h7ea286d_0\"),\n            \"content should contain package name: {content}\"\n        );\n        assert!(\n            content.contains(\"https://example.com/ncurses.conda\"),\n            \"content should contain URL: {content}\"\n        );\n\n        // Verify tool section contains conda_deps\n        assert!(\n            content.contains(\"conda_deps\"),\n            \"content should contain conda_deps: {content}\"\n        );\n\n        // Round-trip test: read it back\n        let reloaded = Lockfile::read(&test_lockfile).unwrap();\n        let packages = reloaded.conda_packages.get(\"macos-arm64\").unwrap();\n        assert!(packages.contains_key(\"ncurses-6.4-h7ea286d_0\"));\n\n        let _ = std::fs::remove_file(&test_lockfile);\n    }\n\n    #[test]\n    fn test_cleanup_unreferenced_conda_packages() {\n        let mut lockfile = Lockfile::default();\n\n        // Add some conda packages\n        lockfile.set_conda_package(\n            \"macos-arm64\",\n            \"referenced-pkg\",\n            CondaPackageInfo {\n                url: \"https://example.com/referenced.conda\".to_string(),\n                checksum: Some(\"sha256:abc123\".to_string()),\n            },\n        );\n        lockfile.set_conda_package(\n            \"macos-arm64\",\n            \"unreferenced-pkg\",\n            CondaPackageInfo {\n                url: \"https://example.com/unreferenced.conda\".to_string(),\n                checksum: Some(\"sha256:def456\".to_string()),\n            },\n        );\n        lockfile.set_conda_package(\n            \"linux-x64\",\n            \"orphan-platform-pkg\",\n            CondaPackageInfo {\n                url: \"https://example.com/orphan.conda\".to_string(),\n                checksum: None,\n            },\n        );\n\n        // Add a tool that only references one package\n        let mut platforms = BTreeMap::new();\n        platforms.insert(\n            \"macos-arm64\".to_string(),\n            PlatformInfo {\n                url: Some(\"https://example.com/tool.conda\".to_string()),\n                checksum: None,\n                size: None,\n                url_api: None,\n                conda_deps: Some(vec![\"referenced-pkg\".to_string()]),\n                ..Default::default()\n            },\n        );\n        lockfile.tools.insert(\n            \"mytool\".to_string(),\n            vec![LockfileTool {\n                version: \"1.0.0\".to_string(),\n                backend: Some(\"conda:mytool\".to_string()),\n                options: BTreeMap::new(),\n                platforms,\n            }],\n        );\n\n        // Verify we have all packages before cleanup\n        assert_eq!(lockfile.conda_packages.len(), 2);\n        assert_eq!(lockfile.conda_packages[\"macos-arm64\"].len(), 2);\n        assert_eq!(lockfile.conda_packages[\"linux-x64\"].len(), 1);\n\n        // Run cleanup\n        lockfile.cleanup_unreferenced_conda_packages();\n\n        // Verify only referenced package remains\n        assert_eq!(lockfile.conda_packages.len(), 1);\n        assert!(lockfile.conda_packages.contains_key(\"macos-arm64\"));\n        assert!(!lockfile.conda_packages.contains_key(\"linux-x64\"));\n        assert_eq!(lockfile.conda_packages[\"macos-arm64\"].len(), 1);\n        assert!(lockfile.conda_packages[\"macos-arm64\"].contains_key(\"referenced-pkg\"));\n        assert!(!lockfile.conda_packages[\"macos-arm64\"].contains_key(\"unreferenced-pkg\"));\n    }\n\n    #[test]\n    fn test_retain_tools_by_short_prunes_removed_tools() {\n        let mut lockfile = Lockfile::default();\n        lockfile\n            .tools\n            .insert(\"dummy\".to_string(), vec![basic_tool(\"1.0.0\", \"asdf:dummy\")]);\n        lockfile\n            .tools\n            .insert(\"tiny\".to_string(), vec![basic_tool(\"2.1.0\", \"asdf:tiny\")]);\n\n        let keep_shorts = BTreeSet::from([\"tiny\".to_string()]);\n        lockfile.retain_tools_by_short_or_backend(&keep_shorts, &BTreeSet::new());\n\n        assert!(!lockfile.tools.contains_key(\"dummy\"));\n        assert!(lockfile.tools.contains_key(\"tiny\"));\n    }\n\n    #[test]\n    fn test_stale_tool_shorts_identifies_removed_tools() {\n        let mut lockfile = Lockfile::default();\n        lockfile\n            .tools\n            .insert(\"dummy\".to_string(), vec![basic_tool(\"1.0.0\", \"asdf:dummy\")]);\n        lockfile\n            .tools\n            .insert(\"tiny\".to_string(), vec![basic_tool(\"2.1.0\", \"asdf:tiny\")]);\n\n        let keep_shorts = BTreeSet::from([\"tiny\".to_string()]);\n        let stale = lockfile.stale_tool_shorts(&keep_shorts, &BTreeSet::new());\n        assert_eq!(stale, BTreeSet::from([\"dummy\".to_string()]));\n    }\n\n    #[test]\n    fn test_stale_tool_shorts_respects_backend_identifiers() {\n        let mut lockfile = Lockfile::default();\n        lockfile.tools.insert(\n            \"jq\".to_string(),\n            vec![basic_tool(\"1.7.1\", \"aqua:jqlang/jq\")],\n        );\n\n        let keep_backends = BTreeSet::from([\"aqua:jqlang/jq\".to_string()]);\n        let stale = lockfile.stale_tool_shorts(&BTreeSet::new(), &keep_backends);\n        assert!(stale.is_empty());\n    }\n\n    #[test]\n    fn test_retain_tools_by_short_cleans_unreferenced_conda_packages() {\n        let mut lockfile = Lockfile::default();\n\n        add_test_conda_package(&mut lockfile, \"linux-x64\", \"keep-pkg\");\n        add_test_conda_package(&mut lockfile, \"linux-x64\", \"drop-pkg\");\n\n        lockfile.tools.insert(\n            \"tiny\".to_string(),\n            vec![tool_with_conda_dep(\n                \"2.1.0\",\n                \"conda:tiny\",\n                \"linux-x64\",\n                \"keep-pkg\",\n            )],\n        );\n        lockfile.tools.insert(\n            \"dummy\".to_string(),\n            vec![tool_with_conda_dep(\n                \"1.0.0\",\n                \"conda:dummy\",\n                \"linux-x64\",\n                \"drop-pkg\",\n            )],\n        );\n\n        let keep_shorts = BTreeSet::from([\"tiny\".to_string()]);\n        lockfile.retain_tools_by_short_or_backend(&keep_shorts, &BTreeSet::new());\n\n        assert!(lockfile.tools.contains_key(\"tiny\"));\n        assert!(!lockfile.tools.contains_key(\"dummy\"));\n\n        let linux_packages = lockfile.conda_packages.get(\"linux-x64\").unwrap();\n        assert!(linux_packages.contains_key(\"keep-pkg\"));\n        assert!(!linux_packages.contains_key(\"drop-pkg\"));\n    }\n\n    #[test]\n    fn test_retain_tools_by_short_or_backend_preserves_legacy_keyed_entries() {\n        let mut lockfile = Lockfile::default();\n        lockfile.tools.insert(\n            \"jq\".to_string(),\n            vec![LockfileTool {\n                version: \"1.7.1\".to_string(),\n                backend: Some(\"aqua:jqlang/jq\".to_string()),\n                options: BTreeMap::new(),\n\n                platforms: BTreeMap::new(),\n            }],\n        );\n\n        let keep_shorts = BTreeSet::from([\"aqua:jqlang/jq\".to_string()]);\n        let keep_backends = BTreeSet::from([\"aqua:jqlang/jq\".to_string()]);\n        lockfile.retain_tools_by_short_or_backend(&keep_shorts, &keep_backends);\n\n        assert!(lockfile.tools.contains_key(\"jq\"));\n    }\n\n    #[test]\n    fn test_platform_info_merge_prefers_sha256() {\n        // Test that merge_with prefers sha256 over blake3\n        let sha256_info = PlatformInfo {\n            checksum: Some(\"sha256:abc123\".to_string()),\n            url: Some(\"https://example.com/a\".to_string()),\n            ..Default::default()\n        };\n        let blake3_info = PlatformInfo {\n            checksum: Some(\"blake3:def456\".to_string()),\n            url: Some(\"https://example.com/b\".to_string()),\n            ..Default::default()\n        };\n\n        // sha256 + blake3 -> sha256\n        let merged = sha256_info.merge_with(&blake3_info);\n        assert_eq!(merged.checksum, Some(\"sha256:abc123\".to_string()));\n\n        // blake3 + sha256 -> sha256\n        let merged = blake3_info.merge_with(&sha256_info);\n        assert_eq!(merged.checksum, Some(\"sha256:abc123\".to_string()));\n\n        // blake3 + blake3 -> self (first)\n        let another_blake3 = PlatformInfo {\n            checksum: Some(\"blake3:ghi789\".to_string()),\n            ..Default::default()\n        };\n        let merged = blake3_info.merge_with(&another_blake3);\n        assert_eq!(merged.checksum, Some(\"blake3:def456\".to_string()));\n\n        // Preserves URL from other if self is missing\n        let no_url = PlatformInfo {\n            checksum: Some(\"sha256:abc123\".to_string()),\n            url: None,\n            ..Default::default()\n        };\n        let merged = no_url.merge_with(&blake3_info);\n        assert_eq!(merged.url, Some(\"https://example.com/b\".to_string()));\n    }\n\n    #[test]\n    fn test_provenance_fields_roundtrip() {\n        let info = PlatformInfo {\n            checksum: Some(\"sha256:abc123\".to_string()),\n            url: Some(\"https://example.com/tool.tar.gz\".to_string()),\n            provenance: Some(ProvenanceType::Slsa {\n                url: Some(\"https://example.com/tool.intoto.jsonl\".to_string()),\n            }),\n            ..Default::default()\n        };\n\n        // Test toml roundtrip — SLSA serializes as a table with url inside\n        let toml_val: toml::Value = info.clone().into();\n        let table = toml_val.as_table().unwrap();\n        let prov_table = table.get(\"provenance\").unwrap().as_table().unwrap();\n        let slsa_table = prov_table.get(\"slsa\").unwrap().as_table().unwrap();\n        assert_eq!(\n            slsa_table.get(\"url\").unwrap().as_str().unwrap(),\n            \"https://example.com/tool.intoto.jsonl\"\n        );\n        let parsed: PlatformInfo = toml_val.try_into().unwrap();\n        assert!(parsed.provenance.as_ref().unwrap().is_slsa());\n        match &parsed.provenance {\n            Some(ProvenanceType::Slsa { url }) => {\n                assert_eq!(\n                    url.as_deref(),\n                    Some(\"https://example.com/tool.intoto.jsonl\")\n                );\n            }\n            _ => panic!(\"expected Slsa provenance\"),\n        }\n    }\n\n    #[test]\n    fn test_provenance_legacy_provenance_url_compat() {\n        // Old lockfile format: provenance = \"slsa\" + provenance_url = \"...\"\n        // Must go through TryFrom<toml::Value> which handles the legacy field\n        let mut table = toml::Table::new();\n        table.insert(\"provenance\".to_string(), \"slsa\".into());\n        table.insert(\n            \"provenance_url\".to_string(),\n            \"https://example.com/tool.intoto.jsonl\".into(),\n        );\n        let parsed = PlatformInfo::try_from(toml::Value::Table(table)).unwrap();\n        assert!(parsed.provenance.as_ref().unwrap().is_slsa());\n        match &parsed.provenance {\n            Some(ProvenanceType::Slsa { url }) => {\n                assert_eq!(\n                    url.as_deref(),\n                    Some(\"https://example.com/tool.intoto.jsonl\")\n                );\n            }\n            _ => panic!(\"expected Slsa provenance\"),\n        }\n    }\n\n    #[test]\n    fn test_provenance_merge_preserves_existing() {\n        let with_provenance = PlatformInfo {\n            provenance: Some(ProvenanceType::GithubAttestations),\n            ..Default::default()\n        };\n        let without = PlatformInfo::default();\n\n        // Merging with empty preserves provenance\n        let merged = with_provenance.merge_with(&without);\n        assert_eq!(merged.provenance, Some(ProvenanceType::GithubAttestations));\n\n        // Merging empty (new) with provenance (old) preserves existing provenance\n        let merged = without.merge_with(&with_provenance);\n        assert_eq!(merged.provenance, Some(ProvenanceType::GithubAttestations));\n\n        // Merging Slsa { url: None } with Slsa { url: Some(...) } preserves URL\n        let with_url = PlatformInfo {\n            provenance: Some(ProvenanceType::Slsa {\n                url: Some(\"https://example.com/provenance.intoto.jsonl\".to_string()),\n            }),\n            ..Default::default()\n        };\n        let without_url = PlatformInfo {\n            provenance: Some(ProvenanceType::Slsa { url: None }),\n            ..Default::default()\n        };\n        let merged = without_url.merge_with(&with_url);\n        assert!(merged.provenance.as_ref().unwrap().is_slsa());\n        match &merged.provenance {\n            Some(ProvenanceType::Slsa { url }) => {\n                assert_eq!(\n                    url.as_deref(),\n                    Some(\"https://example.com/provenance.intoto.jsonl\")\n                );\n            }\n            _ => panic!(\"expected Slsa provenance\"),\n        }\n        // Also in reverse order\n        let merged = with_url.merge_with(&without_url);\n        match &merged.provenance {\n            Some(ProvenanceType::Slsa { url }) => {\n                assert_eq!(\n                    url.as_deref(),\n                    Some(\"https://example.com/provenance.intoto.jsonl\")\n                );\n            }\n            _ => panic!(\"expected Slsa provenance\"),\n        }\n    }\n\n    #[test]\n    fn test_provenance_not_empty() {\n        let info = PlatformInfo {\n            provenance: Some(ProvenanceType::Slsa { url: None }),\n            ..Default::default()\n        };\n        assert!(!info.is_empty());\n    }\n}\n"
  },
  {
    "path": "src/logger.rs",
    "content": "use crate::config::{Config, Settings};\nuse clx::progress;\nuse eyre::Result;\nuse std::fs::{File, OpenOptions, create_dir_all};\nuse std::path::Path;\nuse std::sync::Mutex;\nuse std::thread;\nuse std::{io::Write, sync::OnceLock};\n\nuse crate::{config, env, ui};\nuse log::{Level, LevelFilter, Metadata, Record};\n\n#[derive(Debug)]\nstruct Logger {\n    level: Mutex<LevelFilter>,\n    term_level: Mutex<LevelFilter>,\n    file_level: LevelFilter,\n    log_file: Option<Mutex<File>>,\n}\n\nimpl log::Log for Logger {\n    fn enabled(&self, metadata: &Metadata) -> bool {\n        metadata.level() <= *self.level.lock().unwrap()\n    }\n\n    fn log(&self, record: &Record) {\n        let term_level = *self.term_level.lock().unwrap();\n        let will_log_file = record.level() <= self.file_level && self.log_file.is_some();\n        let will_log_term = record.level() <= term_level;\n\n        if !will_log_file && !will_log_term {\n            return;\n        }\n\n        // Redact once for all outputs (Aho-Corasick makes this efficient)\n        let args = record.args().to_string();\n        let args = if config::is_loaded() {\n            Config::get_().redact(&args)\n        } else {\n            args\n        };\n\n        if will_log_file && let Some(log_file) = &self.log_file {\n            let mut log_file = log_file.lock().unwrap();\n            let out = self.render(record, self.file_level, &args);\n            if !out.is_empty() {\n                let _ = writeln!(log_file, \"{}\", console::strip_ansi_codes(&out));\n            }\n        }\n        if will_log_term {\n            let out = self.render(record, term_level, &args);\n            if !out.is_empty() {\n                // Use clx pause/resume for clean logging during progress display\n                progress::pause();\n                eprintln!(\"{out}\");\n                progress::resume();\n            }\n        }\n    }\n\n    fn flush(&self) {}\n}\n\nimpl Logger {\n    fn init(term_level: LevelFilter, file_level: LevelFilter) -> Self {\n        let mut logger = Logger {\n            level: Mutex::new(std::cmp::max(term_level, file_level)),\n            file_level,\n            term_level: Mutex::new(term_level),\n            log_file: None,\n        };\n\n        if let Some(log_file) = &*env::MISE_LOG_FILE {\n            if let Ok(log_file) = init_log_file(log_file) {\n                logger.log_file = Some(Mutex::new(log_file));\n            } else {\n                eprintln!(\"mise: could not open log file: {log_file:?}\");\n            }\n        }\n\n        logger\n    }\n\n    fn render(&self, record: &Record, level: LevelFilter, args: &str) -> String {\n        match level {\n            LevelFilter::Off => \"\".to_string(),\n            LevelFilter::Trace => {\n                let level = record.level();\n                let file = record.file().unwrap_or(\"<unknown>\");\n                if level == LevelFilter::Trace && file.contains(\"/expr-lang\") {\n                    return \"\".to_string();\n                };\n                let meta = ui::style::edim(format!(\n                    \"{thread_id:>2} [{file}:{line}]\",\n                    thread_id = thread_id(),\n                    line = record.line().unwrap_or(0),\n                ));\n                format!(\"{level} {meta} {args}\", level = self.styled_level(level),)\n            }\n            LevelFilter::Debug => {\n                format!(\"{level} {args}\", level = self.styled_level(record.level()),)\n            }\n            _ => {\n                let mise = match record.level() {\n                    Level::Error => ui::style::ered(\"mise\"),\n                    Level::Warn => ui::style::eyellow(\"mise\"),\n                    _ => ui::style::edim(\"mise\"),\n                };\n                match record.level() {\n                    Level::Info => format!(\"{mise} {args}\"),\n                    _ => format!(\n                        \"{mise} {level} {args}\",\n                        level = self.styled_level(record.level()),\n                    ),\n                }\n            }\n        }\n    }\n\n    fn styled_level(&self, level: Level) -> String {\n        let level = match level {\n            Level::Error => ui::style::ered(\"ERROR\").to_string(),\n            Level::Warn => ui::style::eyellow(\"WARN\").to_string(),\n            Level::Info => ui::style::ecyan(\"INFO\").to_string(),\n            Level::Debug => ui::style::emagenta(\"DEBUG\").to_string(),\n            Level::Trace => ui::style::edim(\"TRACE\").to_string(),\n        };\n        console::pad_str(&level, 5, console::Alignment::Left, None).to_string()\n    }\n}\n\npub fn thread_id() -> String {\n    let id = format!(\"{:?}\", thread::current().id());\n    let id = id.replace(\"ThreadId(\", \"\");\n    id.replace(\")\", \"\")\n}\n\npub fn init() {\n    static LOGGER: OnceLock<Logger> = OnceLock::new();\n    let settings = Settings::try_get().unwrap_or_else(|_| Default::default());\n    let term_level = settings.log_level();\n    if let Some(logger) = LOGGER.get() {\n        *logger.term_level.lock().unwrap() = term_level;\n        *logger.level.lock().unwrap() = std::cmp::max(term_level, logger.file_level);\n    } else {\n        let file_level = env::MISE_LOG_FILE_LEVEL.unwrap_or(settings.log_level());\n        let logger = LOGGER.get_or_init(|| Logger::init(term_level, file_level));\n        if let Err(err) = log::set_logger(logger) {\n            eprintln!(\"mise: could not initialize logger: {err}\");\n        }\n    }\n    log::set_max_level(term_level);\n}\n\nfn init_log_file(log_file: &Path) -> Result<File> {\n    if let Some(log_dir) = log_file.parent() {\n        create_dir_all(log_dir)?;\n    }\n    Ok(OpenOptions::new()\n        .create(true)\n        .append(true)\n        .open(log_file)?)\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_init() {\n        let _config = Config::get().await.unwrap();\n        init();\n    }\n}\n"
  },
  {
    "path": "src/main.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\n\nuse std::{\n    panic,\n    sync::atomic::{AtomicBool, Ordering},\n};\n\nuse crate::cli::Cli;\nuse crate::cli::version::VERSION;\nuse color_eyre::{Section, SectionExt};\nuse eyre::Report;\nuse indoc::indoc;\nuse itertools::Itertools;\n\n#[cfg(test)]\n#[macro_use]\nmod test;\n\n#[macro_use]\nmod output;\n\n#[macro_use]\nmod hint;\n\n#[macro_use]\nmod timings;\n\n#[macro_use]\nmod cmd;\n\nmod agecrypt;\nmod aqua;\nmod backend;\npub(crate) mod build_time;\nmod cache;\nmod cli;\nmod config;\npub(crate) mod deps_graph;\nmod direnv;\nmod dirs;\npub(crate) mod duration;\nmod env;\nmod env_diff;\nmod errors;\nmod exit;\n#[cfg_attr(windows, path = \"fake_asdf_windows.rs\")]\nmod fake_asdf;\nmod file;\npub(crate) mod forgejo;\nmod git;\npub(crate) mod github;\npub(crate) mod gitlab;\nmod gpg;\nmod hash;\nmod hook_env;\nmod hooks;\nmod http;\nmod install_context;\nmod lock_file;\nmod lockfile;\npub(crate) mod logger;\npub(crate) mod maplit;\nmod migrate;\nmod minisign;\nmod netrc;\npub(crate) mod parallel;\nmod path;\nmod path_env;\nmod platform;\nmod plugins;\nmod prepare;\nmod rand;\nmod redactions;\nmod registry;\npub(crate) mod result;\nmod runtime_symlinks;\nmod semver;\nmod shell;\nmod shims;\nmod shorthands;\nmod sops;\nmod sysconfig;\npub(crate) mod task;\npub(crate) mod tera;\npub(crate) mod timeout;\nmod toml;\nmod toolset;\nmod ui;\nmod uv;\nmod versions_host;\nmod watch_files;\nmod wildcard;\n\npub(crate) use crate::exit::exit;\npub(crate) use crate::result::Result;\nuse crate::ui::multi_progress_report::MultiProgressReport;\n\nfn main() -> eyre::Result<()> {\n    let nprocs = std::thread::available_parallelism()\n        .map(|n| n.get())\n        .unwrap_or_default();\n    let threads = crate::env::MISE_JOBS.unwrap_or(nprocs).max(8);\n    tokio::runtime::Builder::new_multi_thread()\n        .enable_all()\n        .worker_threads(threads)\n        .build()?\n        .block_on(main_())\n}\n\nasync fn main_() -> eyre::Result<()> {\n    // Configure color-eyre based on color preferences\n    if *env::CLICOLOR == Some(false) {\n        // Use blank theme (no colors) when colors are disabled\n        color_eyre::config::HookBuilder::new()\n            .theme(color_eyre::config::Theme::new())\n            .install()?;\n    } else {\n        // Use default installation with colors\n        color_eyre::install()?;\n    }\n    install_panic_hook();\n    if std::env::current_dir().is_ok() {\n        unsafe {\n            path_absolutize::update_cwd();\n        }\n    }\n    measure!(\"main\", {\n        let args = env::args().collect_vec();\n        match Cli::run(&args)\n            .await\n            .with_section(|| VERSION.to_string().header(\"Version:\"))\n        {\n            Ok(()) => Ok(()),\n            Err(err) => handle_err(err),\n        }?;\n    });\n    if let Some(mpr) = MultiProgressReport::try_get() {\n        mpr.stop()?;\n    }\n    Ok(())\n}\n\nfn handle_err(err: Report) -> eyre::Result<()> {\n    if let Some(err) = err.downcast_ref::<std::io::Error>()\n        && err.kind() == std::io::ErrorKind::BrokenPipe\n    {\n        return Ok(());\n    }\n\n    // Check for miette diagnostic errors and render them specially\n    if let Some(diagnostic) = err.downcast_ref::<config::config_file::diagnostic::MiseDiagnostic>()\n    {\n        eprintln!(\"{}\", diagnostic.render());\n        exit(1);\n    }\n\n    show_github_rate_limit_err(&err);\n    if *env::MISE_FRIENDLY_ERROR {\n        display_friendly_err(&err);\n        exit(1);\n    }\n    let async_backtrace = async_backtrace::taskdump_tree(true);\n    Err(err.section(async_backtrace.header(\"Async Tasks\")))\n}\n\nfn show_github_rate_limit_err(err: &Report) {\n    let msg = format!(\"{err:?}\");\n    if msg.contains(\"HTTP status client error (403 Forbidden) for url (https://api.github.com\") {\n        warn!(\n            \"GitHub API returned a 403 Forbidden error. This likely means you have exceeded the rate limit.\"\n        );\n        if env::GITHUB_TOKEN.is_none() {\n            warn!(indoc!(\n                r#\"GITHUB_TOKEN is not set. This means mise is making unauthenticated requests to GitHub which have a lower rate limit.\n                   To increase the rate limit, set the GITHUB_TOKEN environment variable to a GitHub personal access token.\n                   Create a token at https://github.com/settings/tokens and set it as GITHUB_TOKEN in your environment.\n                   You do not need to give this token any scopes.\"#\n            ));\n        }\n    }\n}\n\nfn display_friendly_err(err: &Report) {\n    for err in err.chain() {\n        error!(\"{err}\");\n    }\n    let msg = ui::style::edim(\"Run with --verbose or MISE_VERBOSE=1 for more information\");\n    error!(\"{msg}\");\n}\n\nstatic ASYNC_PANIC_OCCURRED: AtomicBool = AtomicBool::new(false);\n\npub fn install_panic_hook() {\n    let default_hook = panic::take_hook();\n    panic::set_hook(Box::new(move |panic_info| {\n        if tokio::runtime::Handle::try_current().is_ok()\n            && !ASYNC_PANIC_OCCURRED.swap(true, Ordering::SeqCst)\n        {\n            let bt = async_backtrace::backtrace();\n            let mut bt_buffer = String::new();\n            if let Some(bt) = bt {\n                let locations = &*bt;\n                for (index, loc) in locations.iter().enumerate() {\n                    bt_buffer.push_str(&format!(\"{index:3}: {loc:?}\\n\"));\n                }\n            } else {\n                bt_buffer.push_str(\"[no accessible async backtrace]\");\n            }\n            let all = async_backtrace::taskdump_tree(true);\n            eprintln!(\n                \"=== Async Backtrace (panic occurred in tokio runtime) ===\\n\\\n                {bt_buffer}\\n\\\n                ------- TASK DUMP TREE -------\\n\\\n                {all}\\n\\\n                === End Async Backtrace ===\\n\"\n            );\n        }\n\n        default_hook(panic_info);\n    }));\n}\n"
  },
  {
    "path": "src/maplit.rs",
    "content": "#[macro_export]\nmacro_rules! hashmap {\n    (@single $($x:tt)*) => (());\n    (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));\n\n    ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };\n    ($($key:expr => $value:expr),*) => {\n        {\n            let _cap = hashmap!(@count $($key),*);\n            let mut _map = ::std::collections::HashMap::with_capacity(_cap);\n            $(\n                let _ = _map.insert($key, $value);\n            )*\n            _map\n        }\n    };\n}\n"
  },
  {
    "path": "src/migrate.rs",
    "content": "use std::fs;\nuse std::path::Path;\n\nuse crate::dirs::*;\nuse crate::file;\nuse eyre::Result;\n\npub async fn run() {\n    tokio::join!(\n        task(migrate_trusted_configs),\n        task(migrate_tracked_configs),\n        task(|| remove_deprecated_plugin(\"node\", \"rtx-nodejs\")),\n        task(|| remove_deprecated_plugin(\"go\", \"rtx-golang\")),\n        task(|| remove_deprecated_plugin(\"java\", \"rtx-java\")),\n        task(|| remove_deprecated_plugin(\"python\", \"rtx-python\")),\n        task(|| remove_deprecated_plugin(\"ruby\", \"rtx-ruby\")),\n    );\n}\n\nasync fn task(job: impl FnOnce() -> Result<()> + Send + 'static) {\n    if let Err(err) = job() {\n        eprintln!(\"[WARN] migrate: {err}\");\n    }\n}\n\nfn migrate_tracked_configs() -> Result<()> {\n    move_dirs(&DATA.join(\"tracked_config_files\"), &TRACKED_CONFIGS)?;\n    move_dirs(&DATA.join(\"tracked-config-files\"), &TRACKED_CONFIGS)?;\n    Ok(())\n}\n\nfn migrate_trusted_configs() -> Result<()> {\n    move_dirs(&CACHE.join(\"trusted-configs\"), &TRUSTED_CONFIGS)?;\n    move_dirs(&CONFIG.join(\"trusted-configs\"), &TRUSTED_CONFIGS)?;\n    move_dirs(&DATA.join(\"trusted-configs\"), &TRUSTED_CONFIGS)?;\n    Ok(())\n}\n\nfn move_dirs(from: &Path, to: &Path) -> Result<bool> {\n    if from.exists() && !to.exists() {\n        eprintln!(\"migrating {} to {}\", from.display(), to.display());\n        file::create_dir_all(to.parent().unwrap())?;\n        file::rename(from, to)?;\n        Ok(true)\n    } else {\n        Ok(false)\n    }\n}\n\nfn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> {\n    let plugin_root = PLUGINS.join(name);\n    let gitconfig = plugin_root.join(\".git\").join(\"config\");\n    let gitconfig_body = fs::read_to_string(gitconfig).unwrap_or_default();\n    if !gitconfig_body.contains(&format!(\"github.com/mise-plugins/{plugin_name}\")) {\n        return Ok(());\n    }\n    eprintln!(\"removing deprecated plugin {plugin_name}, will use core {name} plugin from now on\");\n    file::remove_all(plugin_root)?;\n    Ok(())\n}\n"
  },
  {
    "path": "src/minisign.rs",
    "content": "use crate::*;\nuse minisign_verify::*;\nuse std::iter::Iterator;\nuse std::sync::LazyLock;\n\npub static MISE_PUB_KEY: LazyLock<String> = LazyLock::new(|| {\n    include_str!(\"../minisign.pub\")\n        .to_string()\n        .lines()\n        .last()\n        .unwrap()\n        .to_string()\n});\n\npub fn verify(pub_key: &str, data: &[u8], sig: &str) -> Result<()> {\n    let public_key = PublicKey::from_base64(pub_key)?;\n    let signature = Signature::decode(sig)?;\n    public_key.verify(data, &signature, false)?;\n    Ok(())\n}\n"
  },
  {
    "path": "src/netrc.rs",
    "content": "use std::path::PathBuf;\nuse std::sync::LazyLock;\n\nuse netrc_rs::Netrc;\n\nuse crate::config::Settings;\nuse crate::dirs;\n\n/// Cached parsed netrc file\nstatic NETRC: LazyLock<Option<Netrc>> = LazyLock::new(|| {\n    let settings = Settings::get();\n    if !settings.netrc {\n        return None;\n    }\n\n    let path = netrc_path();\n    if !path.exists() {\n        return None;\n    }\n\n    // Check file permissions on Unix systems\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::PermissionsExt;\n        if let Ok(metadata) = std::fs::metadata(&path) {\n            let mode = metadata.permissions().mode();\n            if mode & 0o077 != 0 {\n                warn!(\n                    \"netrc file {} has insecure permissions (mode: {:o}). Should be 0600 or 0400\",\n                    path.display(),\n                    mode & 0o777\n                );\n            }\n        }\n    }\n\n    match std::fs::read_to_string(&path) {\n        Ok(content) => match Netrc::parse(content, false) {\n            Ok(netrc) => {\n                debug!(\"Loaded netrc from {}\", path.display());\n                Some(netrc)\n            }\n            Err(e) => {\n                warn!(\"Failed to parse netrc file {}: {}\", path.display(), e);\n                None\n            }\n        },\n        Err(e) => {\n            warn!(\"Failed to read netrc file {}: {}\", path.display(), e);\n            None\n        }\n    }\n});\n\n/// Get the path to the netrc file\n///\n/// Checks in order:\n/// 1. Custom path from settings (netrc_file)\n/// 2. %USERPROFILE%\\_netrc on Windows (Windows convention)\n/// 3. ~/.netrc (Unix default, also Windows fallback)\nfn netrc_path() -> PathBuf {\n    let settings = Settings::get();\n    if let Some(path) = &settings.netrc_file {\n        return path.clone();\n    }\n\n    #[cfg(windows)]\n    {\n        // On Windows, try _netrc first (Windows convention)\n        let windows_netrc = dirs::HOME.join(\"_netrc\");\n        if windows_netrc.exists() {\n            return windows_netrc;\n        }\n    }\n\n    dirs::HOME.join(\".netrc\")\n}\n\n/// Look up credentials for a given host from the netrc file\n///\n/// Returns `Some((login, password))` if credentials are found, `None` otherwise\npub fn get_credentials(host: &str) -> Option<(String, String)> {\n    let netrc = NETRC.as_ref()?;\n\n    // First try exact host match\n    if let Some(machine) = netrc.machines.iter().find(|m| {\n        m.name\n            .as_ref()\n            .is_some_and(|name| name.eq_ignore_ascii_case(host))\n    }) && let (Some(login), Some(password)) = (&machine.login, &machine.password)\n    {\n        trace!(\"Found netrc credentials for host: {}\", host);\n        return Some((login.clone(), password.clone()));\n    }\n\n    // Fall back to default machine if no exact match\n    if let Some(machine) = netrc.machines.iter().find(|m| m.name.is_none())\n        && let (Some(login), Some(password)) = (&machine.login, &machine.password)\n    {\n        trace!(\"Using default netrc credentials for host: {}\", host);\n        return Some((login.clone(), password.clone()));\n    }\n\n    None\n}\n"
  },
  {
    "path": "src/output.rs",
    "content": "use std::collections::HashSet;\nuse std::sync::LazyLock;\nuse std::sync::Mutex;\n\n#[macro_export]\nmacro_rules! prefix_println {\n    ($prefix:expr, $($arg:tt)*) => {{\n        let msg = format!($($arg)*);\n        let _ = calm_io::stdoutln!(\"{} {}\", $prefix, msg);\n    }};\n}\n#[macro_export]\nmacro_rules! prefix_eprintln {\n    ($prefix:expr, $($arg:tt)*) => {{\n        let msg = format!($($arg)*);\n        let _ = calm_io::stderrln!(\"{} {}\", $prefix, msg);\n    }};\n}\n\n#[cfg(test)]\n#[macro_export]\nmacro_rules! miseprintln {\n    () => {\n        miseprint!(\"\\n\")?;\n    };\n    ($($arg:tt)*) => {{\n        let mut stdout = $crate::output::tests::STDOUT.lock().unwrap();\n        stdout.push(format!($($arg)*));\n    }}\n}\n\n#[cfg(not(test))]\n#[macro_export]\nmacro_rules! miseprintln {\n    () => {\n        calm_io::stdoutln!()?;\n    };\n    ($($arg:tt)*) => {{\n        calm_io::stdoutln!($($arg)*)?;\n    }}\n}\n\n#[cfg(test)]\n#[macro_export]\nmacro_rules! miseprint {\n    ($($arg:tt)*) => {{\n        let mut stdout = $crate::output::tests::STDOUT.lock().unwrap();\n        let cur = stdout.pop().unwrap_or_default();\n        stdout.push(cur + &format!($($arg)*));\n        std::io::Result::Ok(())\n    }}\n}\n\n#[cfg(not(test))]\n#[macro_export]\nmacro_rules! miseprint {\n    ($($arg:tt)*) => {{\n        calm_io::stdout!($($arg)*)\n    }}\n}\n\n#[cfg(test)]\n#[macro_export]\nmacro_rules! info {\n        ($($arg:tt)*) => {{\n            let mut stderr = $crate::output::tests::STDERR.lock().unwrap();\n            let mise = console::style(\"mise\").dim().for_stderr();\n            stderr.push(format!(\"{} {}\", mise, format!($($arg)*)));\n        }};\n    }\n\n#[cfg(test)]\n#[macro_export]\nmacro_rules! warn {\n        ($($arg:tt)*) => {{\n            let mut stderr = $crate::output::tests::STDERR.lock().unwrap();\n            let mise = console::style(\"mise\").yellow().for_stderr();\n            stderr.push(format!(\"{} {}\", mise, format!($($arg)*)));\n        }}\n    }\n\n#[cfg(test)]\n#[macro_export]\nmacro_rules! error {\n        ($($arg:tt)*) => {\n            let mut stderr = $crate::output::tests::STDERR.lock().unwrap();\n            let mise = console::style(\"mise\").red().for_stderr();\n            stderr.push(format!(\"{} {}\", mise, format!($($arg)*)));\n        }\n    }\n\n#[macro_export]\nmacro_rules! trace {\n    ($($arg:tt)*) => {{\n        log::trace!($($arg)*);\n    }};\n}\n\n#[macro_export]\nmacro_rules! debug {\n    ($($arg:tt)*) => {{\n        log::debug!($($arg)*);\n    }};\n}\n\n#[cfg(not(test))]\n#[macro_export]\nmacro_rules! info {\n    ($($arg:tt)*) => {{\n       log::info!($($arg)*);\n    }};\n}\n\n#[macro_export]\nmacro_rules! info_trunc {\n    ($($arg:tt)*) => {{\n        let msg = format!($($arg)*);\n        let msg = msg.lines().next().unwrap_or_default();\n        let msg = console::truncate_str(&msg, *$crate::env::TERM_WIDTH, \"…\");\n        info!(\"{msg}\");\n    }};\n}\n\n#[cfg(not(test))]\n#[macro_export]\nmacro_rules! warn {\n    ($($arg:tt)*) => {{\n       log::warn!($($arg)*);\n    }};\n}\n\npub static WARNED_ONCE: LazyLock<Mutex<HashSet<String>>> = LazyLock::new(Default::default);\nmacro_rules! warn_once {\n    ($($arg:tt)*) => {{\n        let msg = format!($($arg)*);\n        if $crate::output::WARNED_ONCE.lock().unwrap().insert(msg.clone()) {\n            warn!(\"{}\", msg);\n        }\n    }};\n}\n\n#[cfg(not(test))]\n#[macro_export]\nmacro_rules! error {\n    ($($arg:tt)*) => {{\n       log::error!($($arg)*);\n    }};\n}\n\npub static DEPRECATED: LazyLock<Mutex<HashSet<&'static str>>> = LazyLock::new(Default::default);\n\n#[macro_export]\nmacro_rules! deprecated {\n    ($id:tt, $($arg:tt)*) => {{\n        if $crate::output::DEPRECATED.lock().unwrap().insert($id) {\n            warn!(\"deprecated [{}]: {}\", $id, format!($($arg)*));\n        }\n    }};\n}\n\n/// Emits a deprecation warning when mise version >= warn_at, and fires a debug_assert\n/// when version >= remove_at to remind developers to remove the deprecated code.\n/// The removal version is automatically appended to the warning message.\n///\n/// # Example\n/// ```ignore\n/// deprecated_at!(\"2026.3.0\", \"2027.3.0\", \"legacy-syntax\", \"Use {{version}} instead of {version}\");\n/// ```\n#[macro_export]\nmacro_rules! deprecated_at {\n    ($warn_at:tt, $remove_at:tt, $id:tt, $($arg:tt)*) => {{\n        use versions::Versioning;\n        let warn_version = Versioning::new($warn_at).expect(\"invalid warn_at version in deprecated_at!\");\n        let remove_version = Versioning::new($remove_at).expect(\"invalid remove_at version in deprecated_at!\");\n        debug_assert!(\n            *$crate::cli::version::V < remove_version,\n            \"Deprecated code [{}] should have been removed in version {}. Please remove this deprecated functionality.\",\n            $id, $remove_at\n        );\n        if *$crate::cli::version::V >= warn_version {\n            if $crate::output::DEPRECATED.lock().unwrap().insert($id) {\n                warn!(\"deprecated [{}]: {} This will be removed in mise {}.\", $id, format!($($arg)*), $remove_at);\n            }\n        }\n    }};\n}\n\n#[cfg(test)]\npub mod tests {\n    use std::sync::Mutex;\n\n    pub static STDOUT: Mutex<Vec<String>> = Mutex::new(Vec::new());\n    pub static STDERR: Mutex<Vec<String>> = Mutex::new(Vec::new());\n}\n"
  },
  {
    "path": "src/parallel.rs",
    "content": "use crate::Result;\nuse crate::config::Settings;\nuse std::sync::Arc;\nuse tokio::sync::Semaphore;\nuse tokio::task::JoinSet;\n\npub async fn parallel<T, F, Fut, U>(input: Vec<T>, f: F) -> Result<Vec<U>>\nwhere\n    T: Send + 'static,\n    U: Send + 'static,\n    F: Fn(T) -> Fut + Send + Copy + 'static,\n    Fut: Future<Output = Result<U>> + Send + 'static,\n{\n    let semaphore = Arc::new(Semaphore::new(Settings::get().jobs));\n    let mut jset = JoinSet::new();\n    let mut results = input.iter().map(|_| None).collect::<Vec<_>>();\n    for item in input.into_iter().enumerate() {\n        let semaphore = semaphore.clone();\n        let permit = semaphore.acquire_owned().await?;\n        jset.spawn(async move {\n            let _permit = permit;\n            let res = f(item.1).await?;\n            Ok((item.0, res))\n        });\n    }\n    while let Some(result) = jset.join_next().await {\n        let err: eyre::Report = match result {\n            Ok(Ok((i, result))) => {\n                results[i] = Some(result);\n                continue;\n            }\n            Ok(Err(e)) => e,\n            Err(e) => e.into(),\n        };\n        jset.abort_all();\n        // Drain remaining tasks - don't use join_all() as it panics on cancelled tasks\n        while jset.join_next().await.is_some() {}\n        return Err(err);\n    }\n    Ok(results.into_iter().flatten().collect())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use tokio::test;\n\n    #[test]\n    async fn test_parallel() {\n        let input = vec![1, 2, 3, 4, 5];\n        let results = parallel(input, |x| async move { Ok(x * 2) }).await.unwrap();\n        assert_eq!(results, vec![2, 4, 6, 8, 10]);\n    }\n}\n"
  },
  {
    "path": "src/path.rs",
    "content": "pub use std::path::*;\n\nuse crate::dirs;\n\npub trait PathExt {\n    /// replaces $HOME with \"~\"\n    fn display_user(&self) -> String;\n    fn mount(&self, on: &Path) -> PathBuf;\n    fn is_empty(&self) -> bool;\n}\n\nimpl PathExt for Path {\n    fn display_user(&self) -> String {\n        let home = dirs::HOME.to_string_lossy();\n        let home_str: &str = home.as_ref();\n        match cfg!(unix) && self.starts_with(home_str) && home != \"/\" {\n            true => self.to_string_lossy().replacen(home_str, \"~\", 1),\n            false => self.to_string_lossy().to_string(),\n        }\n    }\n\n    fn mount(&self, on: &Path) -> PathBuf {\n        if PathExt::is_empty(self) {\n            on.to_path_buf()\n        } else {\n            on.join(self)\n        }\n    }\n\n    fn is_empty(&self) -> bool {\n        self.as_os_str().is_empty()\n    }\n}\n"
  },
  {
    "path": "src/path_env.rs",
    "content": "use crate::config::Settings;\nuse crate::dirs;\nuse std::env::{join_paths, split_paths};\nuse std::ffi::OsString;\nuse std::fmt;\nuse std::fmt::{Display, Formatter};\nuse std::path::PathBuf;\nuse std::str::FromStr;\n\npub struct PathEnv {\n    pre: Vec<PathBuf>,\n    mise: Vec<PathBuf>,\n    post: Vec<PathBuf>,\n    seen_shims: bool,\n}\n\nimpl PathEnv {\n    pub fn new() -> Self {\n        Self {\n            pre: Vec::new(),\n            mise: Vec::new(),\n            post: Vec::new(),\n            seen_shims: false,\n        }\n    }\n\n    pub fn add(&mut self, path: PathBuf) {\n        for part in split_paths(&path) {\n            self.mise.push(part);\n        }\n    }\n\n    pub fn to_vec(&self) -> Vec<PathBuf> {\n        self.pre\n            .iter()\n            .chain(self.mise.iter())\n            .chain(self.post.iter())\n            .map(|p| p.to_path_buf())\n            .collect()\n    }\n\n    pub fn join(&self) -> OsString {\n        join_paths(self.to_vec()).unwrap()\n    }\n}\n\nimpl Display for PathEnv {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.join().to_string_lossy())\n    }\n}\n\nimpl FromIterator<PathBuf> for PathEnv {\n    fn from_iter<T: IntoIterator<Item = PathBuf>>(paths: T) -> Self {\n        let settings = Settings::get();\n\n        // When not_found_auto_install is enabled, preserve shims in PATH so they can\n        // trigger auto-install for tools that aren't installed yet\n        let preserve_shims = settings.not_found_auto_install;\n\n        let mut path_env = Self::new();\n\n        for path in paths {\n            if path_env.seen_shims {\n                path_env.post.push(path);\n            } else if path == *dirs::SHIMS && !settings.activate_aggressive {\n                path_env.seen_shims = true;\n                if preserve_shims {\n                    path_env.post.push(path);\n                }\n            } else {\n                path_env.pre.push(path);\n            }\n        }\n        if !path_env.seen_shims {\n            path_env.post = path_env.pre;\n            path_env.pre = Vec::new();\n        }\n\n        path_env\n    }\n}\n\nimpl PathEnv {\n    pub fn from_path_str(path: &str) -> Self {\n        Self::from_iter(split_paths(path))\n    }\n}\n\nimpl FromStr for PathEnv {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self::from_path_str(s))\n    }\n}\n\n#[cfg(unix)]\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_path_env() {\n        let _config = Config::get().await.unwrap();\n        let shims = dirs::SHIMS.to_str().unwrap();\n        let mut path_env = PathEnv::from_iter(\n            [\n                \"/before-1\",\n                \"/before-2\",\n                \"/before-3\",\n                shims,\n                \"/after-1\",\n                \"/after-2\",\n                \"/after-3\",\n            ]\n            .map(PathBuf::from),\n        );\n        path_env.add(\"/1\".into());\n        path_env.add(\"/2\".into());\n        path_env.add(\"/3\".into());\n        assert_eq!(\n            path_env.to_string(),\n            format!(\"/before-1:/before-2:/before-3:/1:/2:/3:{shims}:/after-1:/after-2:/after-3\")\n        );\n    }\n\n    #[tokio::test]\n    async fn test_path_env_no_mise() {\n        let _config = Config::get().await.unwrap();\n        let mut path_env = PathEnv::from_iter(\n            [\n                \"/before-1\",\n                \"/before-2\",\n                \"/before-3\",\n                \"/after-1\",\n                \"/after-2\",\n                \"/after-3\",\n            ]\n            .map(PathBuf::from),\n        );\n        path_env.add(\"/1\".into());\n        path_env.add(\"/2\".into());\n        path_env.add(\"/3\".into());\n        assert_eq!(\n            path_env.to_string(),\n            format!(\"/1:/2:/3:/before-1:/before-2:/before-3:/after-1:/after-2:/after-3\")\n        );\n    }\n    #[tokio::test]\n    async fn test_path_env_with_colon() {\n        let _config = Config::get().await.unwrap();\n        let mut path_env = PathEnv::from_iter([\"/item1\", \"/item2\"].map(PathBuf::from));\n        path_env.add(\"/1:/2\".into());\n        assert_eq!(path_env.to_string(), format!(\"/1:/2:/item1:/item2\"));\n    }\n}\n"
  },
  {
    "path": "src/platform.rs",
    "content": "use crate::config::Settings;\nuse eyre::{Result, bail};\nuse std::fmt;\n\n/// Represents a target platform for lockfile operations\n#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]\npub struct Platform {\n    pub os: String,\n    pub arch: String,\n    pub qualifier: Option<String>,\n}\n\nimpl Platform {\n    /// Parse a platform string in the format \"os-arch\" or \"os-arch-qualifier\"\n    /// Qualifier may contain hyphens (e.g., \"musl-baseline\")\n    pub fn parse(platform_str: &str) -> Result<Self> {\n        let parts: Vec<&str> = platform_str.split('-').collect();\n\n        match parts.len() {\n            0 | 1 => bail!(\n                \"Invalid platform format '{}'. Expected 'os-arch' or 'os-arch-qualifier'\",\n                platform_str\n            ),\n            2 => Ok(Platform {\n                os: parts[0].to_string(),\n                arch: parts[1].to_string(),\n                qualifier: None,\n            }),\n            _ => {\n                // Join remaining parts as qualifier (handles compound qualifiers like \"musl-baseline\")\n                let qualifier = parts[2..].join(\"-\");\n                Ok(Platform {\n                    os: parts[0].to_string(),\n                    arch: parts[1].to_string(),\n                    qualifier: Some(qualifier),\n                })\n            }\n        }\n    }\n\n    /// Get the current platform from system information.\n    /// On Linux, detects musl vs glibc at runtime and sets the qualifier accordingly.\n    pub fn current() -> Self {\n        let settings = Settings::get();\n        let os = settings.os().to_string();\n        let qualifier = if os == \"linux\" && is_musl_system() {\n            Some(\"musl\".to_string())\n        } else {\n            None\n        };\n        Platform {\n            os,\n            arch: settings.arch().to_string(),\n            qualifier,\n        }\n    }\n\n    /// Validate that this platform is supported\n    pub fn validate(&self) -> Result<()> {\n        // Validate OS\n        match self.os.as_str() {\n            \"linux\" | \"macos\" | \"windows\" => {}\n            _ => bail!(\n                \"Unsupported OS '{}'. Supported: linux, macos, windows\",\n                self.os\n            ),\n        }\n\n        // Validate architecture\n        match self.arch.as_str() {\n            \"x64\" | \"arm64\" | \"x86\" => {}\n            _ => bail!(\n                \"Unsupported architecture '{}'. Supported: x64, arm64, x86\",\n                self.arch\n            ),\n        }\n\n        // Validate qualifier if present\n        if let Some(qualifier) = &self.qualifier {\n            match qualifier.as_str() {\n                \"gnu\" | \"musl\" | \"msvc\" | \"baseline\" | \"musl-baseline\" => {}\n                _ => bail!(\n                    \"Unsupported qualifier '{}'. Supported: gnu, musl, msvc, baseline, musl-baseline\",\n                    qualifier\n                ),\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Check if this platform is compatible with the current system\n    pub fn is_compatible_with_current(&self) -> bool {\n        let current = Self::current();\n        self.os == current.os && self.arch == current.arch\n    }\n\n    /// Convert to platform key format used in lockfiles\n    pub fn to_key(&self) -> String {\n        match &self.qualifier {\n            Some(qualifier) => format!(\"{}-{}-{}\", self.os, self.arch, qualifier),\n            None => format!(\"{}-{}\", self.os, self.arch),\n        }\n    }\n\n    /// Parse multiple platform strings, validating each one\n    pub fn parse_multiple(platform_strings: &[String]) -> Result<Vec<Self>> {\n        let mut platforms = Vec::new();\n\n        for platform_str in platform_strings {\n            let platform = Self::parse(platform_str)?;\n            platform.validate()?;\n            platforms.push(platform);\n        }\n\n        // Remove duplicates and sort\n        platforms.sort();\n        platforms.dedup();\n\n        Ok(platforms)\n    }\n\n    /// Get a list of commonly supported platforms\n    pub fn common_platforms() -> Vec<Self> {\n        vec![\n            Platform::parse(\"linux-x64\").unwrap(),\n            Platform::parse(\"linux-x64-musl\").unwrap(),\n            Platform::parse(\"linux-arm64\").unwrap(),\n            Platform::parse(\"linux-arm64-musl\").unwrap(),\n            Platform::parse(\"macos-x64\").unwrap(),\n            Platform::parse(\"macos-arm64\").unwrap(),\n            Platform::parse(\"windows-x64\").unwrap(),\n        ]\n    }\n\n    /// Check if this is a Windows platform\n    pub fn is_windows(&self) -> bool {\n        self.os == \"windows\"\n    }\n\n    /// Check if this is a macOS platform\n    pub fn is_macos(&self) -> bool {\n        self.os == \"macos\"\n    }\n\n    /// Check if this is a Linux platform\n    pub fn is_linux(&self) -> bool {\n        self.os == \"linux\"\n    }\n\n    /// Check if this uses ARM64 architecture\n    pub fn is_arm64(&self) -> bool {\n        self.arch == \"arm64\"\n    }\n\n    /// Check if this uses x64 architecture\n    pub fn is_x64(&self) -> bool {\n        self.arch == \"x64\"\n    }\n}\n\nimpl fmt::Display for Platform {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.to_key())\n    }\n}\n\nimpl From<String> for Platform {\n    fn from(s: String) -> Self {\n        Self::parse(&s).unwrap_or_else(|_| {\n            // Fallback to current platform if parsing fails\n            Self::current()\n        })\n    }\n}\n\nimpl From<&str> for Platform {\n    fn from(s: &str) -> Self {\n        Self::parse(s).unwrap_or_else(|_| {\n            // Fallback to current platform if parsing fails\n            Self::current()\n        })\n    }\n}\n\n/// Detect whether the system uses musl libc at runtime.\n/// Checks for the absence of glibc's dynamic linker (`ld-linux-*`) in /lib and /lib64.\n/// On glibc systems, `ld-linux-*` is always present (even if musl-tools is installed\n/// for cross-compilation, which also places `ld-musl-*` in /lib). On musl-only systems\n/// (Alpine, Void musl, etc.), only `ld-musl-*` exists without `ld-linux-*`.\n// NOTE: This logic is mirrored in crates/vfox/src/config.rs env_type(). Keep in sync.\n#[cfg(target_os = \"linux\")]\nfn is_musl_system() -> bool {\n    use std::sync::LazyLock;\n    static IS_MUSL: LazyLock<bool> = LazyLock::new(|| {\n        // If glibc's dynamic linker exists, this is a glibc system\n        for dir in [\"/lib\", \"/lib64\"] {\n            if has_file_prefix(dir, \"ld-linux-\") {\n                return false;\n            }\n        }\n        // No glibc linker found — check for musl's\n        has_file_prefix(\"/lib\", \"ld-musl-\")\n    });\n    *IS_MUSL\n}\n\n#[cfg(target_os = \"linux\")]\nfn has_file_prefix(dir: &str, prefix: &str) -> bool {\n    std::fs::read_dir(dir)\n        .map(|entries| {\n            entries\n                .flatten()\n                .any(|e| e.file_name().to_string_lossy().starts_with(prefix))\n        })\n        .unwrap_or(false)\n}\n\n#[cfg(not(target_os = \"linux\"))]\nfn is_musl_system() -> bool {\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_platform_parse_basic() {\n        let platform = Platform::parse(\"linux-x64\").unwrap();\n        assert_eq!(platform.os, \"linux\");\n        assert_eq!(platform.arch, \"x64\");\n        assert_eq!(platform.qualifier, None);\n    }\n\n    #[test]\n    fn test_platform_parse_with_qualifier() {\n        let platform = Platform::parse(\"linux-x64-gnu\").unwrap();\n        assert_eq!(platform.os, \"linux\");\n        assert_eq!(platform.arch, \"x64\");\n        assert_eq!(platform.qualifier, Some(\"gnu\".to_string()));\n    }\n\n    #[test]\n    fn test_platform_parse_with_compound_qualifier() {\n        // Compound qualifiers like \"musl-baseline\" should parse correctly\n        let platform = Platform::parse(\"linux-x64-musl-baseline\").unwrap();\n        assert_eq!(platform.os, \"linux\");\n        assert_eq!(platform.arch, \"x64\");\n        assert_eq!(platform.qualifier, Some(\"musl-baseline\".to_string()));\n\n        // Verify round-trip: parse -> to_key -> parse\n        assert_eq!(platform.to_key(), \"linux-x64-musl-baseline\");\n        let reparsed = Platform::parse(&platform.to_key()).unwrap();\n        assert_eq!(reparsed.qualifier, Some(\"musl-baseline\".to_string()));\n    }\n\n    #[test]\n    fn test_platform_parse_invalid() {\n        assert!(Platform::parse(\"linux\").is_err());\n        assert!(Platform::parse(\"\").is_err());\n    }\n\n    #[test]\n    fn test_platform_validation() {\n        // Valid platforms\n        assert!(Platform::parse(\"linux-x64\").unwrap().validate().is_ok());\n        assert!(Platform::parse(\"macos-arm64\").unwrap().validate().is_ok());\n        assert!(Platform::parse(\"windows-x64\").unwrap().validate().is_ok());\n        assert!(Platform::parse(\"linux-x64-gnu\").unwrap().validate().is_ok());\n\n        // Invalid OS\n        assert!(Platform::parse(\"invalid-x64\").unwrap().validate().is_err());\n\n        // Invalid arch\n        assert!(\n            Platform::parse(\"linux-invalid\")\n                .unwrap()\n                .validate()\n                .is_err()\n        );\n\n        // Invalid qualifier\n        assert!(\n            Platform::parse(\"linux-x64-invalid\")\n                .unwrap()\n                .validate()\n                .is_err()\n        );\n    }\n\n    #[test]\n    fn test_platform_to_key() {\n        let platform1 = Platform::parse(\"linux-x64\").unwrap();\n        assert_eq!(platform1.to_key(), \"linux-x64\");\n\n        let platform2 = Platform::parse(\"linux-x64-gnu\").unwrap();\n        assert_eq!(platform2.to_key(), \"linux-x64-gnu\");\n    }\n\n    #[test]\n    fn test_platform_multiple_parsing() {\n        let platform_strings = vec![\n            \"linux-x64\".to_string(),\n            \"macos-arm64\".to_string(),\n            \"linux-x64\".to_string(), // duplicate should be removed\n        ];\n\n        let platforms = Platform::parse_multiple(&platform_strings).unwrap();\n        assert_eq!(platforms.len(), 2);\n        assert_eq!(platforms[0].to_key(), \"linux-x64\");\n        assert_eq!(platforms[1].to_key(), \"macos-arm64\");\n    }\n\n    #[test]\n    fn test_platform_helpers() {\n        let linux_platform = Platform::parse(\"linux-arm64\").unwrap();\n        assert!(linux_platform.is_linux());\n        assert!(linux_platform.is_arm64());\n        assert!(!linux_platform.is_windows());\n        assert!(!linux_platform.is_x64());\n\n        let windows_platform = Platform::parse(\"windows-x64\").unwrap();\n        assert!(windows_platform.is_windows());\n        assert!(windows_platform.is_x64());\n        assert!(!windows_platform.is_linux());\n        assert!(!windows_platform.is_arm64());\n    }\n\n    #[test]\n    fn test_common_platforms() {\n        let platforms = Platform::common_platforms();\n        assert_eq!(platforms.len(), 7);\n\n        let keys: Vec<String> = platforms.iter().map(|p| p.to_key()).collect();\n        assert!(keys.contains(&\"linux-x64\".to_string()));\n        assert!(keys.contains(&\"linux-x64-musl\".to_string()));\n        assert!(keys.contains(&\"linux-arm64\".to_string()));\n        assert!(keys.contains(&\"linux-arm64-musl\".to_string()));\n        assert!(keys.contains(&\"macos-x64\".to_string()));\n        assert!(keys.contains(&\"macos-arm64\".to_string()));\n        assert!(keys.contains(&\"windows-x64\".to_string()));\n    }\n}\n"
  },
  {
    "path": "src/plugins/asdf_plugin.rs",
    "content": "use crate::config::{Config, Settings};\nuse crate::errors::Error::PluginNotInstalled;\nuse crate::file::{display_path, remove_all};\nuse crate::git::{CloneOptions, Git};\nuse crate::http::HTTP;\nuse crate::plugins::{Plugin, PluginSource, Script, ScriptManager};\nuse crate::result::Result;\nuse crate::timeout::run_with_timeout;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse crate::ui::prompt;\nuse crate::{dirs, env, exit, file, lock_file, registry};\nuse async_trait::async_trait;\nuse clap::Command;\nuse console::style;\nuse contracts::requires;\nuse eyre::{Context, bail, eyre};\nuse itertools::Itertools;\nuse std::ffi::OsString;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Mutex, MutexGuard};\nuse std::{collections::HashMap, sync::Arc};\nuse xx::regex;\n\n#[derive(Debug)]\npub struct AsdfPlugin {\n    pub name: String,\n    pub plugin_path: PathBuf,\n    pub repo: Mutex<Git>,\n    pub script_man: ScriptManager,\n    repo_url: Mutex<Option<String>>,\n}\n\nimpl AsdfPlugin {\n    #[requires(!name.is_empty())]\n    pub fn new(name: String, plugin_path: PathBuf) -> Self {\n        let repo = Git::new(&plugin_path);\n        Self {\n            script_man: build_script_man(&name, &plugin_path),\n            name,\n            repo_url: Mutex::new(None),\n            repo: Mutex::new(repo),\n            plugin_path,\n        }\n    }\n\n    fn repo(&self) -> MutexGuard<'_, Git> {\n        self.repo.lock().unwrap()\n    }\n\n    fn get_repo_url(&self, config: &Config) -> eyre::Result<String> {\n        self.repo_url\n            .lock()\n            .unwrap()\n            .clone()\n            .or_else(|| self.repo().get_remote_url())\n            .or_else(|| config.get_repo_url(&self.name))\n            .ok_or_else(|| eyre!(\"No repository found for plugin {}\", self.name))\n    }\n\n    fn exec_hook_post_plugin_update(\n        &self,\n        pr: &dyn SingleReport,\n        pre: String,\n        post: String,\n    ) -> eyre::Result<()> {\n        if pre != post {\n            let env = [\n                (\"ASDF_PLUGIN_PREV_REF\", pre.clone()),\n                (\"ASDF_PLUGIN_POST_REF\", post.clone()),\n                (\"MISE_PLUGIN_PREV_REF\", pre),\n                (\"MISE_PLUGIN_POST_REF\", post),\n            ]\n            .into_iter()\n            .map(|(k, v)| (k.into(), v.into()))\n            .collect();\n            self.exec_hook_env(pr, \"post-plugin-update\", env)?;\n        }\n        Ok(())\n    }\n\n    fn exec_hook(&self, pr: &dyn SingleReport, hook: &str) -> eyre::Result<()> {\n        self.exec_hook_env(pr, hook, Default::default())\n    }\n    fn exec_hook_env(\n        &self,\n        pr: &dyn SingleReport,\n        hook: &str,\n        env: HashMap<OsString, OsString>,\n    ) -> eyre::Result<()> {\n        let script = Script::Hook(hook.to_string());\n        let mut sm = self.script_man.clone();\n        sm.env.extend(env);\n        if sm.script_exists(&script) {\n            pr.set_message(format!(\"bin/{hook}\"));\n            sm.run_by_line(&script, pr)?;\n        }\n        Ok(())\n    }\n    pub fn fetch_remote_versions(&self) -> eyre::Result<Vec<String>> {\n        let cmd = self.script_man.cmd(&Script::ListAll);\n        let result = run_with_timeout(\n            move || {\n                let result = cmd.stdout_capture().stderr_capture().unchecked().run()?;\n                Ok(result)\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .wrap_err_with(|| {\n            let script = self.script_man.get_script_path(&Script::ListAll);\n            eyre!(\"Failed to run {}\", display_path(script))\n        })?;\n        let stdout = String::from_utf8(result.stdout).unwrap();\n        let stderr = String::from_utf8(result.stderr).unwrap().trim().to_string();\n\n        let display_stderr = || {\n            if !stderr.is_empty() {\n                eprintln!(\"{stderr}\");\n            }\n        };\n        if !result.status.success() {\n            let s = Script::ListAll;\n            match result.status.code() {\n                Some(code) => bail!(\"error running {}: exited with code {}\\n{}\", s, code, stderr),\n                None => bail!(\"error running {}: terminated by signal\\n{}\", s, stderr),\n            };\n        } else if Settings::get().verbose {\n            display_stderr();\n        }\n\n        Ok(stdout\n            .split_whitespace()\n            .map(|v| regex!(r\"^v(\\d+)\").replace(v, \"$1\").to_string())\n            .collect())\n    }\n    pub fn fetch_latest_stable(&self) -> eyre::Result<Option<String>> {\n        let latest_stable = self\n            .script_man\n            .read(&Script::LatestStable)?\n            .trim()\n            .to_string();\n        Ok(if latest_stable.is_empty() {\n            None\n        } else {\n            Some(latest_stable)\n        })\n    }\n\n    pub fn fetch_idiomatic_filenames(&self) -> eyre::Result<Vec<String>> {\n        let stdout = self.script_man.read(&Script::ListIdiomaticFilenames)?;\n        Ok(self.parse_idiomatic_filenames(&stdout))\n    }\n    pub fn parse_idiomatic_filenames(&self, data: &str) -> Vec<String> {\n        data.split_whitespace().map(|v| v.into()).collect()\n    }\n    pub fn has_list_alias_script(&self) -> bool {\n        self.script_man.script_exists(&Script::ListAliases)\n    }\n    pub fn has_list_idiomatic_filenames_script(&self) -> bool {\n        self.script_man\n            .script_exists(&Script::ListIdiomaticFilenames)\n    }\n    pub fn has_latest_stable_script(&self) -> bool {\n        self.script_man.script_exists(&Script::LatestStable)\n    }\n    pub fn fetch_aliases(&self) -> eyre::Result<Vec<(String, String)>> {\n        let stdout = self.script_man.read(&Script::ListAliases)?;\n        Ok(self.parse_aliases(&stdout))\n    }\n    pub(crate) fn parse_aliases(&self, data: &str) -> Vec<(String, String)> {\n        data.lines()\n            .filter_map(|line| {\n                let mut parts = line.split_whitespace().collect_vec();\n                if parts.len() != 2 {\n                    if !parts.is_empty() {\n                        trace!(\"invalid alias line: {}\", line);\n                    }\n                    return None;\n                }\n                Some((parts.remove(0).into(), parts.remove(0).into()))\n            })\n            .collect()\n    }\n    async fn install_from_zip(&self, url: &str, pr: &dyn SingleReport) -> eyre::Result<()> {\n        let temp_dir = tempfile::tempdir()?;\n        let temp_archive = temp_dir.path().join(\"archive.zip\");\n        HTTP.download_file(url, &temp_archive, Some(pr)).await?;\n\n        pr.set_message(\"extracting zip file\".to_string());\n\n        let strip_components = file::should_strip_components(&temp_archive, file::TarFormat::Zip)?;\n\n        file::unzip(\n            &temp_archive,\n            &self.plugin_path,\n            &file::ZipOptions {\n                strip_components: if strip_components { 1 } else { 0 },\n            },\n        )?;\n\n        Ok(())\n    }\n}\n\n#[async_trait]\nimpl Plugin for AsdfPlugin {\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn path(&self) -> PathBuf {\n        self.plugin_path.clone()\n    }\n\n    fn get_remote_url(&self) -> eyre::Result<Option<String>> {\n        let url = self.repo().get_remote_url();\n        Ok(url.or(self.repo_url.lock().unwrap().clone()))\n    }\n\n    fn set_remote_url(&self, url: String) {\n        *self.repo_url.lock().unwrap() = Some(url);\n    }\n\n    fn current_abbrev_ref(&self) -> eyre::Result<Option<String>> {\n        if !self.is_installed() {\n            return Ok(None);\n        }\n        self.repo().current_abbrev_ref().map(Some)\n    }\n\n    fn current_sha_short(&self) -> eyre::Result<Option<String>> {\n        if !self.is_installed() {\n            return Ok(None);\n        }\n        self.repo().current_sha_short().map(Some)\n    }\n\n    fn remote_sha(&self) -> eyre::Result<Option<String>> {\n        if !self.is_installed() {\n            return Ok(None);\n        }\n        let branch = self.repo().current_branch()?;\n        self.repo().remote_sha(&branch)\n    }\n\n    fn is_installed(&self) -> bool {\n        self.plugin_path.exists()\n    }\n\n    fn is_installed_err(&self) -> eyre::Result<()> {\n        if self.is_installed() {\n            return Ok(());\n        }\n        Err(eyre!(\"asdf plugin {} is not installed\", self.name())\n            .wrap_err(\"run with --yes to install plugin automatically\"))\n    }\n\n    async fn ensure_installed(\n        &self,\n        config: &Arc<Config>,\n        mpr: &MultiProgressReport,\n        force: bool,\n        dry_run: bool,\n    ) -> Result<()> {\n        let settings = Settings::try_get()?;\n        if !force {\n            if self.is_installed() {\n                return Ok(());\n            }\n            if !settings.yes && self.repo_url.lock().unwrap().is_none() {\n                let url = self.get_repo_url(config).unwrap_or_default();\n                if !registry::is_trusted_plugin(self.name(), &url) {\n                    warn!(\n                        \"⚠️ {} is a community-developed plugin – {}\",\n                        style(&self.name).blue(),\n                        style(url.trim_end_matches(\".git\")).yellow()\n                    );\n                    if settings.paranoid {\n                        bail!(\n                            \"Paranoid mode is enabled, refusing to install community-developed plugin\"\n                        );\n                    }\n                    if !prompt::confirm_with_all(format!(\n                        \"Would you like to install {}?\",\n                        self.name\n                    ))? {\n                        Err(PluginNotInstalled(self.name.clone()))?\n                    }\n                }\n            }\n        }\n        let prefix = format!(\"plugin:{}\", style(&self.name).blue().for_stderr());\n        let pr = mpr.add_with_options(&prefix, dry_run);\n        if !dry_run {\n            let _lock = lock_file::get(&self.plugin_path, force)?;\n            self.install(config, pr.as_ref()).await\n        } else {\n            Ok(())\n        }\n    }\n\n    async fn update(&self, pr: &dyn SingleReport, gitref: Option<String>) -> Result<()> {\n        let plugin_path = self.plugin_path.to_path_buf();\n        if plugin_path.is_symlink() {\n            warn!(\n                \"plugin:{} is a symlink, not updating\",\n                style(&self.name).blue().for_stderr()\n            );\n            return Ok(());\n        }\n        let git = Git::new(plugin_path);\n        if !git.is_repo() {\n            warn!(\n                \"plugin:{} is not a git repository, not updating\",\n                style(&self.name).blue().for_stderr()\n            );\n            return Ok(());\n        }\n        pr.set_message(\"update git repo\".into());\n        let (pre, post) = git.update(gitref)?;\n        let sha = git.current_sha_short()?;\n        let repo_url = self.get_remote_url()?.unwrap_or_default();\n        self.exec_hook_post_plugin_update(pr, pre, post)?;\n        pr.finish_with_message(format!(\n            \"{repo_url}#{}\",\n            style(&sha).bright().yellow().for_stderr(),\n        ));\n        Ok(())\n    }\n\n    async fn uninstall(&self, pr: &dyn SingleReport) -> Result<()> {\n        if !self.is_installed() {\n            return Ok(());\n        }\n        self.exec_hook(pr, \"pre-plugin-remove\")?;\n        pr.set_message(\"uninstall\".into());\n\n        let rmdir = |dir: &Path| {\n            if !dir.exists() {\n                return Ok(());\n            }\n            pr.set_message(format!(\"remove {}\", display_path(dir)));\n            remove_all(dir).wrap_err_with(|| {\n                format!(\n                    \"Failed to remove directory {}\",\n                    style(display_path(dir)).cyan().for_stderr()\n                )\n            })\n        };\n\n        rmdir(&self.plugin_path)?;\n\n        Ok(())\n    }\n\n    async fn install(&self, config: &Arc<Config>, pr: &dyn SingleReport) -> eyre::Result<()> {\n        let repository = self.get_repo_url(config)?;\n        let source = PluginSource::parse(&repository);\n        debug!(\"asdf_plugin[{}]:install {:?}\", self.name, repository);\n\n        if self.is_installed() {\n            self.uninstall(pr).await?;\n        }\n\n        match source {\n            PluginSource::Zip { url } => {\n                self.install_from_zip(&url, pr).await?;\n                self.exec_hook(pr, \"post-plugin-add\")?;\n                pr.finish_with_message(url.to_string());\n                Ok(())\n            }\n            PluginSource::Git {\n                url: repo_url,\n                git_ref,\n            } => {\n                if regex!(r\"^[/~]\").is_match(&repo_url) {\n                    Err(eyre!(\n                        r#\"Invalid repository URL: {repo_url}\nIf you are trying to link to a local directory, use `mise plugins link` instead.\nPlugins could support local directories in the future but for now a symlink is required which `mise plugins link` will create for you.\"#\n                    ))?;\n                }\n                let git = Git::new(&self.plugin_path);\n                pr.set_message(format!(\"clone {repo_url}\"));\n                git.clone(&repo_url, CloneOptions::default().pr(pr))?;\n                if let Some(ref_) = &git_ref {\n                    pr.set_message(format!(\"check out {ref_}\"));\n                    git.update(Some(ref_.to_string()))?;\n                }\n                self.exec_hook(pr, \"post-plugin-add\")?;\n\n                let sha = git.current_sha_short()?;\n                pr.finish_with_message(format!(\n                    \"{repo_url}#{}\",\n                    style(&sha).bright().yellow().for_stderr(),\n                ));\n                Ok(())\n            }\n        }\n    }\n\n    fn external_commands(&self) -> eyre::Result<Vec<Command>> {\n        let command_path = self.plugin_path.join(\"lib/commands\");\n        if !self.is_installed() || !command_path.exists() || self.name == \"direnv\" {\n            // asdf-direnv is disabled since it conflicts with mise's built-in direnv functionality\n            return Ok(vec![]);\n        }\n        let mut commands = vec![];\n        for p in crate::file::ls(&command_path)? {\n            let command = p.file_name().unwrap().to_string_lossy().to_string();\n            if !command.starts_with(\"command-\") || !command.ends_with(\".bash\") {\n                continue;\n            }\n            let command = command\n                .strip_prefix(\"command-\")\n                .unwrap()\n                .strip_suffix(\".bash\")\n                .unwrap()\n                .split('-')\n                .map(|s| s.to_string())\n                .collect::<Vec<String>>();\n            commands.push(command);\n        }\n        if commands.is_empty() {\n            return Ok(vec![]);\n        }\n\n        let topic = Command::new(self.name.clone())\n            .about(format!(\"Commands provided by {} plugin\", &self.name))\n            .subcommands(commands.into_iter().map(|cmd| {\n                Command::new(cmd.join(\"-\"))\n                    .about(format!(\"{} command\", cmd.join(\"-\")))\n                    .arg(\n                        clap::Arg::new(\"args\")\n                            .num_args(1..)\n                            .allow_hyphen_values(true)\n                            .trailing_var_arg(true),\n                    )\n            }));\n        Ok(vec![topic])\n    }\n\n    fn execute_external_command(&self, command: &str, args: Vec<String>) -> eyre::Result<()> {\n        if !self.is_installed() {\n            return Err(PluginNotInstalled(self.name.clone()).into());\n        }\n        let script = Script::RunExternalCommand(\n            self.plugin_path\n                .join(\"lib/commands\")\n                .join(format!(\"command-{command}.bash\")),\n            args,\n        );\n        let result = self.script_man.cmd(&script).unchecked().run()?;\n        exit(result.status.code().unwrap_or(-1));\n    }\n}\n\nfn build_script_man(name: &str, plugin_path: &Path) -> ScriptManager {\n    let plugin_path_s = plugin_path.to_string_lossy().to_string();\n    let token = env::GITHUB_TOKEN.as_deref().unwrap_or(\"\");\n    ScriptManager::new(plugin_path.to_path_buf())\n        .with_env(\"ASDF_PLUGIN_PATH\", plugin_path_s.clone())\n        .with_env(\"RTX_PLUGIN_PATH\", plugin_path_s.clone())\n        .with_env(\"RTX_PLUGIN_NAME\", name.to_string())\n        .with_env(\"RTX_SHIMS_DIR\", *dirs::SHIMS)\n        .with_env(\"MISE_PLUGIN_NAME\", name.to_string())\n        .with_env(\"MISE_PLUGIN_PATH\", plugin_path)\n        .with_env(\"MISE_SHIMS_DIR\", *dirs::SHIMS)\n        .with_env(\"GITHUB_TOKEN\", token)\n        // asdf plugins often use GITHUB_API_TOKEN as the env var for GitHub API token\n        .with_env(\"GITHUB_API_TOKEN\", token)\n}\n"
  },
  {
    "path": "src/plugins/core/assets/node_npm_shim",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\n# This script wraps npm so to run `mise reshim` after global installs and uninstalls\n# Any other cases are passed-through to npm\n\nthis_dir=$(dirname \"${BASH_SOURCE[0]}\")\nplugin_name=$(basename \"$(dirname \"$this_dir\")\")\n\nthis_dir=$(cd \"$this_dir\" && pwd -P) # Normalizes the directory\n\nplugin_dir=\"${this_dir}/..\"\n\nshould_reshim() {\n  if [ \"${MISE_SKIP_RESHIM:-}\" ]; then\n    return 1\n  fi\n\n  local is_global='' cmd='' cmd_needs_reshim=''\n  local additional_bare_cmds=()\n\n  for arg; do\n    case \"$arg\" in\n    -g | --global)\n      is_global=true\n      ;;\n\n    -*) ;; # Skip other options\n\n    *)\n      if ! [ \"$cmd\" ]; then\n        cmd=\"$arg\"\n      else\n        additional_bare_cmds+=(\"$arg\")\n      fi\n      ;;\n    esac\n  done\n\n  case \"$cmd\" in\n  # npm install aliases\n  install | i | in | ins | inst | insta | instal | isnt | isnta | isntal | add)\n    cmd_needs_reshim=true\n    ;;\n\n  # npm uninstall aliases\n  uninstall | un | unlink | remove | rm | r)\n    cmd_needs_reshim=true\n    ;;\n\n  link | ln)\n    # Bare link installs a global package\n    if ! [ \"${additional_bare_cmds[0]-}\" ]; then\n      is_global=1\n      cmd_needs_reshim=true\n    fi\n\n    # Links to directories also install a global package\n    if [[ \"${additional_bare_cmds[0]-}\" =~ [./].* && -d \"${additional_bare_cmds[0]-}\" ]]; then\n      is_global=1\n      cmd_needs_reshim=true\n    fi\n    ;;\n  esac\n\n  # Implicit return\n  [ \"$is_global\" ] && [ \"$cmd_needs_reshim\" ]\n}\n\nwrap_npm_if_reshim_is_needed() {\n  local npm_cli=\"$plugin_dir/lib/node_modules/npm/bin/npm-cli.js\"\n  if should_reshim \"$@\"; then\n    node \"$npm_cli\" \"$@\"\n    printf \"Reshimming mise %s...\\n\" \"$plugin_name\" >&2\n    mise reshim\n  else\n    exec node \"$npm_cli\" \"$@\"\n  fi\n}\n\nwrap_npm_if_reshim_is_needed \"$@\"\n"
  },
  {
    "path": "src/plugins/core/assets/rubygems_plugin.rb",
    "content": "# frozen_string_literal: true\n\n# Set PKG_CONFIG_PATH to include Ruby's bundled pkg-config files\n# This allows native gem extensions (openssl, psych, etc.) to find\n# headers and libraries from precompiled Ruby binaries\n# See: https://github.com/jdx/mise/discussions/7268\nif defined?(RbConfig::CONFIG)\n  ruby_pkgconfig = File.join(RbConfig::CONFIG[\"prefix\"], \"lib\", \"pkgconfig\")\n  if File.directory?(ruby_pkgconfig)\n    current = ENV[\"PKG_CONFIG_PATH\"]\n    ENV[\"PKG_CONFIG_PATH\"] = current ? \"#{ruby_pkgconfig}#{File::PATH_SEPARATOR}#{current}\" : ruby_pkgconfig\n  end\nend\n\nmodule ReshimInstaller\n  class << self\n    def debug?\n      ENV[\"MISE_DEBUG\"] == \"true\"\n    end\n\n    def log_debug(msg)\n      warn \"[DEBUG] mise #{msg}\" if debug?\n    end\n\n    def reshim\n      if defined?(RbConfig::CONFIG)\n        log_debug \"reshim\"\n        `mise reshim`\n      else\n        log_debug \"reshim skipped: ruby not found\"\n      end\n    end\n  end\n\n  def install(options)\n    super\n    # We don't know which gems were installed, so always reshim.\n    ReshimInstaller.reshim\n  end\nend unless defined?(ReshimInstaller)\n\nif defined?(Bundler::Installer)\n  Bundler::Installer.prepend ReshimInstaller\nelse\n  Gem.post_install do |installer|\n    # Reshim any (potentially) new executables.\n    ReshimInstaller.reshim if installer.spec.executables.any?\n  end\n  Gem.post_uninstall do |installer|\n    # Unfortunately, reshimming just the removed executables or\n    # ruby version doesn't work as of 2020/04/23.\n    ReshimInstaller.reshim if installer.spec.executables.any?\n  end\nend\n"
  },
  {
    "path": "src/plugins/core/bun.rs",
    "content": "use std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse async_trait::async_trait;\nuse eyre::Result;\nuse itertools::Itertools;\nuse versions::Versioning;\n\nuse crate::backend::static_helpers::fetch_checksum_from_shasums;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::ToolVersion;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{\n    backend::{\n        Backend, GitHubReleaseInfo, ReleaseType, VersionInfo, platform_target::PlatformTarget,\n    },\n    config::{Config, Settings},\n    platform::Platform,\n};\nuse crate::{file, github, plugins};\n\n#[derive(Debug)]\npub struct BunPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl BunPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"bun\")),\n        }\n    }\n\n    fn bun_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(bun_bin_name())\n    }\n\n    fn test_bun(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(\"bun -v\".into());\n        CmdLineRunner::new(self.bun_bin(tv))\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"-v\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let url = format!(\n            \"https://github.com/oven-sh/bun/releases/download/bun-v{}/bun-{}-{}.zip\",\n            tv.version,\n            os(),\n            arch()\n        );\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n\n        Ok(tarball_path)\n    }\n\n    fn install(&self, ctx: &InstallContext, tv: &ToolVersion, tarball_path: &Path) -> Result<()> {\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        file::remove_all(tv.install_path())?;\n        file::create_dir_all(tv.install_path().join(\"bin\"))?;\n        file::unzip(tarball_path, &tv.download_path(), &Default::default())?;\n        file::rename(\n            tv.download_path()\n                .join(format!(\"bun-{}-{}\", os(), arch()))\n                .join(bun_bin_name()),\n            self.bun_bin(tv),\n        )?;\n        if cfg!(unix) {\n            file::make_executable(self.bun_bin(tv))?;\n            file::make_symlink(Path::new(\"./bun\"), &tv.install_path().join(\"bin/bunx\"))?;\n        }\n        Ok(())\n    }\n\n    fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        self.test_bun(ctx, tv)\n    }\n}\n\n#[async_trait]\nimpl Backend for BunPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }]\n    }\n\n    /// Override get_platform_key to include bun's compile-time variant (baseline, musl, etc.)\n    /// This ensures lockfile lookups use the correct platform key that matches the variant\n    fn get_platform_key(&self) -> String {\n        let settings = Settings::get();\n        let os = settings.os();\n        let arch = settings.arch();\n\n        // Get the variant suffix based on compile-time features\n        let variant = Self::get_platform_variant();\n\n        if let Some(v) = variant {\n            format!(\"{os}-{arch}-{v}\")\n        } else {\n            format!(\"{os}-{arch}\")\n        }\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = github::list_releases(\"oven-sh/bun\")\n            .await?\n            .into_iter()\n            .filter_map(|r| {\n                r.tag_name\n                    .strip_prefix(\"bun-v\")\n                    .map(|v| (v.to_string(), r.created_at))\n            })\n            .unique_by(|(v, _)| v.clone())\n            .sorted_by_cached_key(|(s, _)| (Versioning::new(s), s.to_string()))\n            .map(|(version, created_at)| VersionInfo {\n                version,\n                created_at: Some(created_at),\n                ..Default::default()\n            })\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".bun-version\".into(), \"package.json\".into()])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let tarball_path = self.download(&tv, ctx.pr.as_ref()).await?;\n        ctx.pr.next_operation();\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.next_operation();\n        self.install(ctx, &tv, &tarball_path)?;\n        self.verify(ctx, &tv)?;\n\n        Ok(tv)\n    }\n\n    // ========== Lockfile Metadata Fetching Implementation ==========\n\n    async fn get_github_release_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<Option<GitHubReleaseInfo>> {\n        let version = &tv.version;\n\n        // Build the asset pattern for Bun's GitHub releases\n        // Pattern: bun-{os}-{arch}.zip (where arch may include variants like -musl, -baseline)\n        let os_name = Self::map_os_to_bun(target.os_name());\n        let arch_name = Self::get_bun_arch_for_target(target);\n        let asset_pattern = format!(\"bun-{os_name}-{arch_name}.zip\");\n\n        Ok(Some(GitHubReleaseInfo {\n            repo: \"oven-sh/bun\".to_string(),\n            asset_pattern: Some(asset_pattern),\n            api_url: Some(format!(\n                \"https://github.com/oven-sh/bun/releases/download/bun-v{version}\"\n            )),\n            release_type: ReleaseType::GitHub,\n        }))\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let version = &tv.version;\n\n        // Build platform-specific filename\n        let os_name = Self::map_os_to_bun(target.os_name());\n        let arch_name = Self::get_bun_arch_for_target(target);\n        let filename = format!(\"bun-{os_name}-{arch_name}.zip\");\n\n        // Build download URL\n        let url =\n            format!(\"https://github.com/oven-sh/bun/releases/download/bun-v{version}/{filename}\");\n\n        // Fetch SHASUMS256.txt to get checksum without downloading the zip\n        let shasums_url = format!(\n            \"https://github.com/oven-sh/bun/releases/download/bun-v{version}/SHASUMS256.txt\"\n        );\n        let checksum = fetch_checksum_from_shasums(&shasums_url, &filename).await;\n\n        Ok(PlatformInfo {\n            url: Some(url),\n            checksum,\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n\n    fn platform_variants(&self, platform: &Platform) -> Vec<Platform> {\n        // Bun has compile-time variants that affect the download URL and checksum:\n        // - baseline: for CPUs without AVX2 support\n        // - musl: for musl libc (Alpine Linux, etc.)\n        // - musl-baseline: musl + no AVX2\n        //\n        // Available variants by platform:\n        // - linux-x64: x64, x64-baseline, x64-musl, x64-musl-baseline\n        // - linux-arm64: aarch64, aarch64-musl\n        // - macos-x64: x64, x64-baseline\n        // - macos-arm64: aarch64\n        // - windows-x64: x64, x64-baseline\n\n        // If the platform already has a qualifier, it's already a specific variant\n        // Don't expand it to avoid duplicates\n        if platform.qualifier.is_some() {\n            return vec![platform.clone()];\n        }\n\n        let mut variants = vec![platform.clone()];\n\n        match (platform.os.as_str(), platform.arch.as_str()) {\n            (\"linux\", \"x64\") => {\n                // Linux x64 has all variants\n                variants.push(Platform {\n                    os: platform.os.clone(),\n                    arch: platform.arch.clone(),\n                    qualifier: Some(\"baseline\".to_string()),\n                });\n                variants.push(Platform {\n                    os: platform.os.clone(),\n                    arch: platform.arch.clone(),\n                    qualifier: Some(\"musl\".to_string()),\n                });\n                variants.push(Platform {\n                    os: platform.os.clone(),\n                    arch: platform.arch.clone(),\n                    qualifier: Some(\"musl-baseline\".to_string()),\n                });\n            }\n            (\"linux\", \"arm64\") => {\n                // Linux arm64 has musl variant\n                variants.push(Platform {\n                    os: platform.os.clone(),\n                    arch: platform.arch.clone(),\n                    qualifier: Some(\"musl\".to_string()),\n                });\n            }\n            (\"macos\", \"x64\") | (\"windows\", \"x64\") => {\n                // macOS x64 and Windows x64 have baseline variant\n                variants.push(Platform {\n                    os: platform.os.clone(),\n                    arch: platform.arch.clone(),\n                    qualifier: Some(\"baseline\".to_string()),\n                });\n            }\n            // macos-arm64 has no variants (just aarch64)\n            _ => {}\n        }\n\n        variants\n    }\n}\n\nimpl BunPlugin {\n    /// Map our platform OS names to Bun's naming convention\n    fn map_os_to_bun(os: &str) -> &str {\n        match os {\n            \"macos\" => \"darwin\",\n            \"linux\" => \"linux\",\n            \"windows\" => \"windows\",\n            other => other,\n        }\n    }\n\n    /// Map our platform arch names to Bun's naming convention\n    /// Note: This handles simple cases. Complex musl/baseline variants are handled in arch()\n    fn map_arch_to_bun(arch: &str) -> &str {\n        match arch {\n            \"x64\" => \"x64\",\n            \"arm64\" | \"aarch64\" => \"aarch64\",\n            other => other,\n        }\n    }\n\n    /// Get the full Bun arch string for a target platform\n    /// This handles musl, baseline, and other variants based on platform qualifiers\n    fn get_bun_arch_for_target(target: &PlatformTarget) -> String {\n        let base_arch = Self::map_arch_to_bun(target.arch_name());\n\n        // Handle qualifiers like musl, baseline, etc.\n        if let Some(qualifier) = target.qualifier() {\n            match qualifier {\n                \"musl\" => format!(\"{}-musl\", base_arch),\n                \"musl-baseline\" => format!(\"{}-musl-baseline\", base_arch),\n                \"baseline\" => format!(\"{}-baseline\", base_arch),\n                other => format!(\"{}-{}\", base_arch, other),\n            }\n        } else {\n            base_arch.to_string()\n        }\n    }\n\n    /// Check if the current system has AVX2 support (runtime detection)\n    #[cfg(target_arch = \"x86_64\")]\n    fn has_avx2() -> bool {\n        std::arch::is_x86_feature_detected!(\"avx2\")\n    }\n\n    #[cfg(not(target_arch = \"x86_64\"))]\n    fn has_avx2() -> bool {\n        false\n    }\n\n    /// Check if we're running on a musl-based system\n    /// This is determined by the binary's compile-time target, since mixing\n    /// glibc and musl binaries on the same system doesn't work anyway\n    fn is_musl() -> bool {\n        cfg!(target_env = \"musl\")\n    }\n\n    /// Get the platform variant suffix for the current system\n    /// Returns Some(\"baseline\"), Some(\"musl\"), Some(\"musl-baseline\"), or None\n    /// Uses runtime detection for AVX2 capability and Settings::get().arch() for MISE_ARCH support\n    fn get_platform_variant() -> Option<&'static str> {\n        let settings = Settings::get();\n        match settings.arch() {\n            \"x64\" => {\n                if Self::is_musl() {\n                    if Self::has_avx2() {\n                        Some(\"musl\")\n                    } else {\n                        Some(\"musl-baseline\")\n                    }\n                } else if Self::has_avx2() {\n                    None // Standard x64 with AVX2, no variant suffix\n                } else {\n                    Some(\"baseline\")\n                }\n            }\n            \"arm64\" => {\n                if Self::is_musl() {\n                    Some(\"musl\")\n                } else {\n                    None // Standard aarch64, no variant suffix\n                }\n            }\n            _ => None,\n        }\n    }\n\n    /// Get the full Bun arch string with variants (musl, baseline, etc.)\n    /// Uses Settings::get().arch() to respect MISE_ARCH overrides and runtime AVX2 detection\n    fn get_bun_arch_with_variants() -> String {\n        let settings = Settings::get();\n        let arch = settings.arch();\n        let os = settings.os();\n        match arch {\n            \"x64\" => {\n                if Self::is_musl() {\n                    if Self::has_avx2() {\n                        \"x64-musl\".to_string()\n                    } else {\n                        \"x64-musl-baseline\".to_string()\n                    }\n                } else if Self::has_avx2() {\n                    \"x64\".to_string()\n                } else {\n                    \"x64-baseline\".to_string()\n                }\n            }\n            \"arm64\" => {\n                if Self::is_musl() {\n                    \"aarch64-musl\".to_string()\n                } else if os == \"windows\" {\n                    // Bun has no native windows-arm64 build; fall back to x64 under emulation\n                    \"x64-baseline\".to_string()\n                } else {\n                    \"aarch64\".to_string()\n                }\n            }\n            other => other.to_string(),\n        }\n    }\n}\n\nfn os() -> String {\n    let settings = Settings::get();\n    BunPlugin::map_os_to_bun(settings.os()).to_string()\n}\n\nfn arch() -> String {\n    BunPlugin::get_bun_arch_with_variants()\n}\n\nfn bun_bin_name() -> &'static str {\n    if cfg!(windows) { \"bun.exe\" } else { \"bun\" }\n}\n"
  },
  {
    "path": "src/plugins/core/deno.rs",
    "content": "use std::collections::BTreeMap;\nuse std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse async_trait::async_trait;\nuse eyre::Result;\nuse itertools::Itertools;\nuse serde::Deserialize;\nuse versions::Versioning;\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::fetch_checksum_from_file;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::Config;\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::{ToolRequest, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{file, plugins};\n\n#[derive(Debug)]\npub struct DenoPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl DenoPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"deno\")),\n        }\n    }\n\n    fn deno_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(if cfg!(target_os = \"windows\") {\n            \"bin/deno.exe\"\n        } else {\n            \"bin/deno\"\n        })\n    }\n\n    fn test_deno(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> {\n        pr.set_message(\"deno -V\".into());\n        CmdLineRunner::new(self.deno_bin(tv))\n            .with_pr(pr)\n            .arg(\"-V\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let url = self\n            .get_tarball_url(tv, &PlatformTarget::from_current())\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"Failed to get deno tarball URL\"))?;\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n\n        Ok(tarball_path)\n    }\n\n    fn install(&self, tv: &ToolVersion, pr: &dyn SingleReport, tarball_path: &Path) -> Result<()> {\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        pr.set_message(format!(\"extract {filename}\"));\n        file::remove_all(tv.install_path())?;\n        file::create_dir_all(tv.install_path().join(\"bin\"))?;\n        file::unzip(tarball_path, &tv.download_path(), &Default::default())?;\n        file::rename(\n            tv.download_path().join(if cfg!(target_os = \"windows\") {\n                \"deno.exe\"\n            } else {\n                \"deno\"\n            }),\n            self.deno_bin(tv),\n        )?;\n        file::make_executable(self.deno_bin(tv))?;\n        Ok(())\n    }\n\n    fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> {\n        self.test_deno(tv, pr)\n    }\n}\n\n#[async_trait]\nimpl Backend for DenoPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }]\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions: DenoVersions = HTTP_FETCH.json(\"https://deno.com/versions.json\").await?;\n        let versions = versions\n            .cli\n            .into_iter()\n            .filter(|v| v.starts_with('v'))\n            .map(|v| VersionInfo {\n                version: v.trim_start_matches('v').to_string(),\n                ..Default::default()\n            })\n            .unique_by(|v| v.version.clone())\n            .sorted_by_cached_key(|v| (Versioning::new(&v.version), v.version.clone()))\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".deno-version\".into(), \"package.json\".into()])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let tarball_path = self.download(&tv, ctx.pr.as_ref()).await?;\n        ctx.pr.next_operation();\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.next_operation();\n        self.install(&tv, ctx.pr.as_ref(), &tarball_path)?;\n        self.verify(&tv, ctx.pr.as_ref())?;\n\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        if let ToolRequest::System { .. } = tv.request {\n            return Ok(vec![]);\n        }\n        let bin_paths = vec![\n            tv.install_path().join(\"bin\"),\n            tv.install_path().join(\".deno/bin\"),\n        ];\n        Ok(bin_paths)\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let map = BTreeMap::from([(\n            \"DENO_INSTALL_ROOT\".into(),\n            tv.install_path().join(\".deno\").to_string_lossy().into(),\n        )]);\n        Ok(map)\n    }\n\n    async fn get_tarball_url(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<Option<String>> {\n        let arch = match target.arch_name() {\n            \"x64\" => \"x86_64\",\n            \"arm64\" => \"aarch64\",\n            other => other,\n        };\n        let os = match target.os_name() {\n            \"macos\" => \"apple-darwin\",\n            \"linux\" => \"unknown-linux-gnu\",\n            \"windows\" => \"pc-windows-msvc\",\n            _ => \"unknown-linux-gnu\",\n        };\n        Ok(Some(format!(\n            \"https://dl.deno.land/release/v{}/deno-{}-{}.zip\",\n            tv.version, arch, os\n        )))\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let url = self\n            .get_tarball_url(tv, target)\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"Failed to get deno tarball URL\"))?;\n\n        // Deno provides .sha256sum files alongside each zip\n        let checksum_url = format!(\"{}.sha256sum\", &url);\n        let checksum = fetch_checksum_from_file(&checksum_url, \"sha256\").await;\n\n        Ok(PlatformInfo {\n            url: Some(url),\n            checksum,\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n}\n\n#[derive(Debug, Deserialize)]\nstruct DenoVersions {\n    cli: Vec<String>,\n}\n"
  },
  {
    "path": "src/plugins/core/dotnet.rs",
    "content": "use std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse async_trait::async_trait;\nuse eyre::Result;\nuse serde_derive::Deserialize;\nuse versions::Versioning;\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::parallel;\nuse crate::toolset::{ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{dirs, env, file, plugins};\n\n#[derive(Debug)]\npub struct DotnetPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl DotnetPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: plugins::core::new_backend_arg(\"dotnet\").into(),\n        }\n    }\n\n    fn is_isolated() -> bool {\n        Settings::get().dotnet.isolated\n    }\n\n    async fn test_dotnet(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(\"dotnet --version\".into());\n        CmdLineRunner::new(DOTNET_BIN)\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"--version\")\n            .envs(self.exec_env(&ctx.config, &ctx.ts, tv).await?)\n            .prepend_path(self.list_bin_paths(&ctx.config, tv).await?)?\n            .execute()\n    }\n}\n\n#[async_trait]\nimpl Backend for DotnetPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let index: ReleasesIndex = HTTP_FETCH\n            .json(\"https://builds.dotnet.microsoft.com/dotnet/release-metadata/releases-index.json\")\n            .await?;\n\n        // Fetch all channel release data in parallel\n        let urls: Vec<String> = index\n            .releases_index\n            .iter()\n            .filter_map(|ch| ch.releases_json.as_ref())\n            .filter(|url| !url.is_empty())\n            .cloned()\n            .collect();\n\n        let channels: Vec<ChannelReleases> =\n            parallel::parallel(urls, |url| async move { HTTP_FETCH.json(&url).await }).await?;\n\n        let mut versions = std::collections::BTreeSet::new();\n        for channel_data in &channels {\n            for release in &channel_data.releases {\n                let sdk_iter = release.sdk.iter();\n                let sdks_iter = release.sdks.iter().flatten();\n                for sdk in sdk_iter.chain(sdks_iter) {\n                    if let Some(ref version) = sdk.version {\n                        versions.insert(SortedVersion(version.clone()));\n                    }\n                }\n            }\n        }\n\n        Ok(versions\n            .into_iter()\n            .map(|v| VersionInfo {\n                version: v.0,\n                ..Default::default()\n            })\n            .collect())\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\"global.json\".into()])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let content = file::read_to_string(path)?;\n        let global_json: GlobalJson = serde_json::from_str(&content)?;\n        let sdk = global_json\n            .sdk\n            .ok_or_else(|| eyre::eyre!(\"no sdk.version found in {}\", path.display()))?;\n        if sdk.version.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(vec![sdk.version])\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        let isolated = Self::is_isolated();\n        let install_dir = if isolated {\n            tv.install_path()\n        } else {\n            dotnet_root()\n        };\n        file::create_dir_all(&install_dir)?;\n\n        // Download install script (always refresh to pick up upstream fixes)\n        let script_path = install_script_path();\n        file::create_dir_all(script_path.parent().unwrap())?;\n        ctx.pr\n            .set_message(\"Downloading dotnet-install script\".into());\n        HTTP.download_file(install_script_url(), &script_path, Some(ctx.pr.as_ref()))\n            .await?;\n        #[cfg(unix)]\n        file::make_executable(&script_path)?;\n\n        // Run install script\n        ctx.pr\n            .set_message(format!(\"Installing .NET SDK {}\", tv.version));\n        install_cmd(&script_path, &install_dir, &tv.version)\n            .with_pr(ctx.pr.as_ref())\n            .envs(self.exec_env(&ctx.config, &ctx.ts, &tv).await?)\n            .execute()?;\n\n        if !isolated {\n            // Symlink install_path -> DOTNET_ROOT so mise can track the installation\n            file::remove_all(tv.install_path())?;\n            file::make_symlink(&install_dir, &tv.install_path())?;\n        }\n\n        self.test_dotnet(ctx, &tv).await?;\n\n        Ok(tv)\n    }\n\n    async fn uninstall_version_impl(\n        &self,\n        _config: &Arc<Config>,\n        _pr: &dyn SingleReport,\n        tv: &ToolVersion,\n    ) -> Result<()> {\n        if Self::is_isolated() {\n            // Isolated: mise handles removal of install_path by default\n        } else {\n            // Shared: only remove this SDK version from the shared root\n            let sdk_dir = dotnet_root().join(\"sdk\").join(&tv.version);\n            if sdk_dir.exists() {\n                file::remove_all(&sdk_dir)?;\n            }\n        }\n        Ok(())\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        if Self::is_isolated() {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(vec![dotnet_root()])\n        }\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> Result<BTreeMap<String, String>> {\n        let root = if Self::is_isolated() {\n            tv.install_path()\n        } else {\n            dotnet_root()\n        };\n        let mut env = BTreeMap::from([\n            (\n                \"DOTNET_ROOT\".to_string(),\n                root.to_string_lossy().to_string(),\n            ),\n            (\"DOTNET_MULTILEVEL_LOOKUP\".to_string(), \"0\".to_string()),\n        ]);\n        if let Some(optout) = Settings::get().dotnet.cli_telemetry_optout {\n            env.insert(\n                \"DOTNET_CLI_TELEMETRY_OPTOUT\".to_string(),\n                if optout { \"1\" } else { \"0\" }.to_string(),\n            );\n        }\n        Ok(env)\n    }\n}\n\nfn dotnet_root() -> PathBuf {\n    Settings::get()\n        .dotnet\n        .dotnet_root\n        .clone()\n        .or(env::var_path(\"DOTNET_ROOT\"))\n        .unwrap_or(dirs::DATA.join(\"dotnet-root\"))\n}\n\nfn install_script_path() -> PathBuf {\n    dirs::CACHE.join(\"dotnet\").join(INSTALL_SCRIPT_NAME)\n}\n\n#[cfg(unix)]\nconst DOTNET_BIN: &str = \"dotnet\";\n\n#[cfg(windows)]\nconst DOTNET_BIN: &str = \"dotnet.exe\";\n\n#[cfg(unix)]\nconst INSTALL_SCRIPT_NAME: &str = \"dotnet-install.sh\";\n\n#[cfg(windows)]\nconst INSTALL_SCRIPT_NAME: &str = \"dotnet-install.ps1\";\n\n#[cfg(unix)]\nfn install_script_url() -> &'static str {\n    \"https://dot.net/v1/dotnet-install.sh\"\n}\n\n#[cfg(windows)]\nfn install_script_url() -> &'static str {\n    \"https://dot.net/v1/dotnet-install.ps1\"\n}\n\n#[cfg(unix)]\nfn install_cmd<'a>(script_path: &Path, install_dir: &Path, version: &str) -> CmdLineRunner<'a> {\n    CmdLineRunner::new(script_path)\n        .arg(\"--install-dir\")\n        .arg(install_dir)\n        .arg(\"--version\")\n        .arg(version)\n        .arg(\"--no-path\")\n}\n\n#[cfg(windows)]\nfn install_cmd<'a>(script_path: &Path, install_dir: &Path, version: &str) -> CmdLineRunner<'a> {\n    CmdLineRunner::new(\"powershell\")\n        .arg(\"-ExecutionPolicy\")\n        .arg(\"Bypass\")\n        .arg(\"-File\")\n        .arg(script_path)\n        .arg(\"-InstallDir\")\n        .arg(install_dir)\n        .arg(\"-Version\")\n        .arg(version)\n        .arg(\"-NoPath\")\n}\n\n// --- Microsoft releases API types ---\n\n#[derive(Deserialize)]\nstruct ReleasesIndex {\n    #[serde(rename = \"releases-index\")]\n    releases_index: Vec<ChannelEntry>,\n}\n\n#[derive(Deserialize)]\nstruct ChannelEntry {\n    #[serde(rename = \"releases.json\")]\n    releases_json: Option<String>,\n}\n\n#[derive(Deserialize)]\nstruct ChannelReleases {\n    releases: Vec<Release>,\n}\n\n#[derive(Deserialize)]\nstruct Release {\n    sdk: Option<Sdk>,\n    sdks: Option<Vec<Sdk>>,\n}\n\n#[derive(Deserialize)]\nstruct Sdk {\n    version: Option<String>,\n}\n\n// --- global.json ---\n\n#[derive(Deserialize)]\nstruct GlobalJson {\n    sdk: Option<GlobalJsonSdk>,\n}\n\n#[derive(Deserialize)]\nstruct GlobalJsonSdk {\n    version: String,\n}\n\n// --- semver-sorted wrapper for BTreeSet dedup + ordering ---\n\n#[derive(Eq, PartialEq)]\nstruct SortedVersion(String);\n\nimpl Ord for SortedVersion {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        let a = Versioning::new(&self.0);\n        let b = Versioning::new(&other.0);\n        a.cmp(&b).then_with(|| self.0.cmp(&other.0))\n    }\n}\n\nimpl PartialOrd for SortedVersion {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/elixir.rs",
    "content": "use std::{\n    collections::BTreeMap,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::plugins::VERSION_REGEX;\nuse crate::toolset::{ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{backend::Backend, backend::VersionInfo, config::Config};\nuse crate::{env, file, plugins};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse itertools::Itertools;\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct ElixirPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl ElixirPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"elixir\")),\n        }\n    }\n\n    fn elixir_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(elixir_bin_name())\n    }\n\n    async fn test_elixir(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(\"elixir --version\".into());\n        CmdLineRunner::new(self.elixir_bin(tv))\n            .with_pr(ctx.pr.as_ref())\n            .envs(self.dependency_env(&ctx.config).await?)\n            .arg(\"--version\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let version = &tv.version;\n        let version = if regex!(r\"^[0-9]\").is_match(version) {\n            &format!(\"v{version}\")\n        } else {\n            version\n        };\n        let url = format!(\"https://builds.hex.pm/builds/elixir/{version}.zip\");\n\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        pr.set_message(format!(\"download {filename}\"));\n        if !tarball_path.exists() {\n            HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n        }\n\n        Ok(tarball_path)\n    }\n\n    async fn install(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        tarball_path: &Path,\n    ) -> Result<()> {\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        file::remove_all(tv.install_path())?;\n        file::unzip(tarball_path, &tv.install_path(), &Default::default())?;\n\n        Ok(())\n    }\n\n    async fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        self.test_elixir(ctx, tv).await\n    }\n}\n\n#[async_trait]\nimpl Backend for ElixirPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        // Format: \"version hash timestamp checksum\"\n        // Example: \"v1.17.3 abc123 2024-12-01T00:00:00Z def456\"\n        let versions: Vec<VersionInfo> = HTTP_FETCH\n            .get_text(\"https://builds.hex.pm/builds/elixir/builds.txt\")\n            .await?\n            .lines()\n            .unique()\n            .filter_map(|s| {\n                let parts: Vec<&str> = s.split_whitespace().collect();\n                if parts.len() >= 3 {\n                    let version = parts[0].trim_start_matches('v');\n                    let timestamp = parts[2]; // Third field is the timestamp\n                    Some((version.to_string(), timestamp.to_string()))\n                } else {\n                    None\n                }\n            })\n            .filter(|(v, _)| regex!(r\"^[0-9]+\\.[0-9]+\\.[0-9]\").is_match(v))\n            .sorted_by_cached_key(|(s, _)| {\n                (\n                    Versioning::new(s.split_once('-').map(|(v, _)| v).unwrap_or(s)),\n                    !VERSION_REGEX.is_match(s),\n                    s.contains(\"-otp-\"),\n                    Versioning::new(s),\n                    s.to_string(),\n                )\n            })\n            .map(|(version, created_at)| VersionInfo {\n                version,\n                created_at: Some(created_at),\n                ..Default::default()\n            })\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> eyre::Result<Vec<String>> {\n        Ok(vec![\".exenv-version\".into()])\n    }\n\n    fn get_dependencies(&self) -> Result<Vec<&str>> {\n        Ok(vec![\"erlang\"])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let tarball_path = self.download(&tv, ctx.pr.as_ref()).await?;\n        ctx.pr.next_operation();\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.next_operation();\n        self.install(ctx, &tv, &tarball_path).await?;\n        self.verify(ctx, &tv).await?;\n        Ok(tv)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        Ok([\"bin\", \".mix/escripts\"]\n            .iter()\n            .map(|p| tv.install_path().join(p))\n            .collect())\n    }\n\n    async fn exec_env(\n        &self,\n        config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let mut map = BTreeMap::new();\n        let mut set = |k: &str, v: PathBuf| {\n            map.insert(k.to_string(), v.to_string_lossy().to_string());\n        };\n        let config_env = config.env().await?;\n        if !env::PRISTINE_ENV.contains_key(\"MIX_HOME\") && !config_env.contains_key(\"MIX_HOME\") {\n            set(\"MIX_HOME\", tv.install_path().join(\".mix\"));\n        }\n        if !env::PRISTINE_ENV.contains_key(\"MIX_ARCHIVES\")\n            && !config_env.contains_key(\"MIX_ARCHIVES\")\n        {\n            set(\n                \"MIX_ARCHIVES\",\n                tv.install_path().join(\".mix\").join(\"archives\"),\n            );\n        }\n        Ok(map)\n    }\n}\n\nfn elixir_bin_name() -> &'static str {\n    if cfg!(windows) {\n        \"elixir.bat\"\n    } else {\n        \"elixir\"\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/erlang.rs",
    "content": "use std::collections::BTreeMap;\nuse std::{path::PathBuf, sync::Arc};\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\n#[cfg(unix)]\nuse crate::file::TarOptions;\nuse crate::file::display_path;\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lock_file::LockFile;\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse crate::{file, github, plugins};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse xx::regex;\n\n#[cfg(linux)]\nuse crate::cmd::CmdLineRunner;\n#[cfg(linux)]\nuse std::fs;\n\n#[derive(Debug)]\npub struct ErlangPlugin {\n    ba: Arc<BackendArg>,\n}\n\nconst KERL_VERSION: &str = \"4.4.0\";\n\nimpl ErlangPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"erlang\")),\n        }\n    }\n\n    fn kerl_path(&self) -> PathBuf {\n        self.ba.cache_path.join(format!(\"kerl-{KERL_VERSION}\"))\n    }\n\n    fn kerl_base_dir(&self) -> PathBuf {\n        self.ba.cache_path.join(\"kerl\")\n    }\n\n    fn lock_build_tool(&self) -> Result<fslock::LockFile> {\n        LockFile::new(&self.kerl_path())\n            .with_callback(|l| {\n                trace!(\"install_or_update_kerl {}\", l.display());\n            })\n            .lock()\n    }\n\n    async fn update_kerl(&self) -> Result<()> {\n        let _lock = self.lock_build_tool();\n        if self.kerl_path().exists() {\n            // TODO: find a way to not have to do this #1209\n            file::remove_all(self.kerl_base_dir())?;\n            return Ok(());\n        }\n        self.install_kerl().await?;\n        let output = cmd!(self.kerl_path(), \"update\", \"releases\")\n            .env(\"KERL_BASE_DIR\", self.kerl_base_dir())\n            .stdout_capture()\n            .stderr_capture()\n            .run()?;\n        trace!(\"kerl stdout: {}\", String::from_utf8_lossy(&output.stdout));\n        trace!(\"kerl stderr: {}\", String::from_utf8_lossy(&output.stderr));\n        Ok(())\n    }\n\n    async fn install_kerl(&self) -> Result<()> {\n        debug!(\"Installing kerl to {}\", display_path(self.kerl_path()));\n        HTTP_FETCH\n            .download_file(\n                format!(\"https://raw.githubusercontent.com/kerl/kerl/{KERL_VERSION}/kerl\"),\n                &self.kerl_path(),\n                None,\n            )\n            .await?;\n        file::make_executable(self.kerl_path())?;\n        Ok(())\n    }\n\n    #[cfg(linux)]\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> Result<Option<ToolVersion>> {\n        if Settings::get().erlang.compile == Some(true) {\n            return Ok(None);\n        }\n        let release_tag = format!(\"OTP-{}\", tv.version);\n\n        let settings = Settings::get();\n        let arch: String = match settings.arch() {\n            \"x64\" => \"amd64\".to_string(),\n            \"arm64\" => \"arm64\".to_string(),\n            other => {\n                debug!(\"Unsupported architecture: {}\", other);\n                return Ok(None);\n            }\n        };\n\n        let os_ver: String;\n        if let Ok(os) = std::env::var(\"ImageOS\") {\n            os_ver = match os.as_str() {\n                \"ubuntu24\" => \"ubuntu-24.04\".to_string(),\n                \"ubuntu22\" => \"ubuntu-22.04\".to_string(),\n                \"ubuntu20\" => \"ubuntu-20.04\".to_string(),\n                _ => os,\n            };\n        } else if let Ok(os_release) = &*os_release::OS_RELEASE {\n            os_ver = format!(\"{}-{}\", os_release.id, os_release.version_id);\n        } else {\n            return Ok(None);\n        };\n\n        // Currently, Bob only builds for Ubuntu, so we have to check that we're on ubuntu, and on a supported version\n        if ![\"ubuntu-20.04\", \"ubuntu-22.04\", \"ubuntu-24.04\"].contains(&os_ver.as_str()) {\n            debug!(\"Unsupported OS version: {}\", os_ver);\n            return Ok(None);\n        }\n\n        let url: String =\n            format!(\"https://builds.hex.pm/builds/otp/{arch}/{os_ver}/{release_tag}.tar.gz\");\n\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        ctx.pr.set_message(format!(\"Downloading {filename}\"));\n        if !tarball_path.exists() {\n            HTTP.download_file(&url, &tarball_path, Some(ctx.pr.as_ref()))\n                .await?;\n        }\n        ctx.pr.set_message(format!(\"Extracting {filename}\"));\n        file::untar(\n            &tarball_path,\n            &tv.download_path(),\n            &TarOptions {\n                pr: Some(ctx.pr.as_ref()),\n                ..TarOptions::new(file::TarFormat::TarGz)\n            },\n        )?;\n\n        self.move_to_install_path(&tv)?;\n\n        CmdLineRunner::new(tv.install_path().join(\"Install\"))\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"-minimal\")\n            .arg(tv.install_path())\n            .execute()?;\n\n        Ok(Some(tv))\n    }\n\n    #[cfg(linux)]\n    fn move_to_install_path(&self, tv: &ToolVersion) -> Result<()> {\n        let base_dir = tv\n            .download_path()\n            .read_dir()?\n            .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir())\n            .unwrap()?\n            .path();\n        file::remove_all(tv.install_path())?;\n        file::create_dir_all(tv.install_path())?;\n        for entry in fs::read_dir(base_dir)? {\n            let entry = entry?;\n            let dest = tv.install_path().join(entry.file_name());\n            trace!(\"moving {:?} to {:?}\", entry.path(), &dest);\n            file::rename(entry.path(), dest)?;\n        }\n\n        Ok(())\n    }\n\n    #[cfg(macos)]\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<Option<ToolVersion>> {\n        if Settings::get().erlang.compile == Some(true) {\n            return Ok(None);\n        }\n        let release_tag = format!(\"OTP-{}\", tv.version);\n        let gh_release = match github::get_release(\"erlef/otp_builds\", &release_tag).await {\n            Ok(release) => release,\n            Err(e) => {\n                debug!(\"Failed to get release: {}\", e);\n                return Ok(None);\n            }\n        };\n        let settings = Settings::get();\n        let arch = match settings.arch() {\n            \"x64\" => \"x86_64\",\n            \"arm64\" => \"aarch64\",\n            other => other,\n        };\n        let os = match settings.os() {\n            \"macos\" => \"apple-darwin\",\n            other => other,\n        };\n        let tarball_name = format!(\"otp-{arch}-{os}.tar.gz\");\n        let asset = match gh_release.assets.iter().find(|a| a.name == tarball_name) {\n            Some(asset) => asset,\n            None => {\n                debug!(\"No asset found for {}\", release_tag);\n                return Ok(None);\n            }\n        };\n        ctx.pr.set_message(format!(\"Downloading {tarball_name}\"));\n        let tarball_path = tv.download_path().join(&tarball_name);\n        HTTP.download_file(\n            &asset.browser_download_url,\n            &tarball_path,\n            Some(ctx.pr.as_ref()),\n        )\n        .await?;\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.set_message(format!(\"Extracting {tarball_name}\"));\n        file::untar(\n            &tarball_path,\n            &tv.install_path(),\n            &TarOptions {\n                pr: Some(ctx.pr.as_ref()),\n                ..TarOptions::new(file::TarFormat::TarGz)\n            },\n        )?;\n        Ok(Some(tv))\n    }\n\n    #[cfg(windows)]\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<Option<ToolVersion>> {\n        if Settings::get().erlang.compile == Some(true) {\n            return Ok(None);\n        }\n        let release_tag = format!(\"OTP-{}\", tv.version);\n        let gh_release = match github::get_release(\"erlang/otp\", &release_tag).await {\n            Ok(release) => release,\n            Err(e) => {\n                debug!(\"Failed to get release: {}\", e);\n                return Ok(None);\n            }\n        };\n        let settings = Settings::get();\n        let os = match settings.os() {\n            \"windows\" => \"win64\",\n            other => other,\n        };\n        let zip_name = format!(\"otp_{os}_{version}.zip\", version = tv.version);\n        let asset = match gh_release.assets.iter().find(|a| a.name == zip_name) {\n            Some(asset) => asset,\n            None => {\n                debug!(\"No asset found for {}\", release_tag);\n                return Ok(None);\n            }\n        };\n        ctx.pr.set_message(format!(\"Downloading {}\", zip_name));\n        let zip_path = tv.download_path().join(&zip_name);\n        HTTP.download_file(\n            &asset.browser_download_url,\n            &zip_path,\n            Some(ctx.pr.as_ref()),\n        )\n        .await?;\n        self.verify_checksum(ctx, &mut tv, &zip_path)?;\n        ctx.pr.set_message(format!(\"Extracting {}\", zip_name));\n        file::unzip(&zip_path, &tv.install_path(), &Default::default())?;\n        Ok(Some(tv))\n    }\n\n    #[cfg(not(any(linux, macos, windows)))]\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> Result<Option<ToolVersion>> {\n        Ok(None)\n    }\n\n    async fn install_via_kerl(\n        &self,\n        _ctx: &InstallContext,\n        tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        self.update_kerl().await?;\n\n        file::remove_all(tv.install_path())?;\n        match &tv.request {\n            ToolRequest::Ref { .. } => {\n                unimplemented!(\"erlang does not yet support refs\");\n            }\n            _ => {\n                cmd!(\n                    self.kerl_path(),\n                    \"build-install\",\n                    &tv.version,\n                    &tv.version,\n                    tv.install_path()\n                )\n                .env(\"KERL_BASE_DIR\", self.ba.cache_path.join(\"kerl\"))\n                .env(\"MAKEFLAGS\", format!(\"-j{}\", num_cpus::get()))\n                .run()?;\n            }\n        }\n\n        Ok(tv)\n    }\n}\n\n#[async_trait]\nimpl Backend for ErlangPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = if Settings::get().erlang.compile == Some(false) {\n            github::list_releases(\"erlef/otp_builds\")\n                .await?\n                .into_iter()\n                .filter_map(|r| {\n                    r.tag_name\n                        .strip_prefix(\"OTP-\")\n                        .map(|s| (s.to_string(), Some(r.created_at)))\n                })\n                .map(|(version, created_at)| VersionInfo {\n                    version,\n                    created_at,\n                    ..Default::default()\n                })\n                .collect()\n        } else {\n            self.update_kerl().await?;\n            let kerl_path = self.kerl_path().to_string_lossy().to_string();\n            let kerl_base_dir = self.ba.cache_path.join(\"kerl\");\n            plugins::core::run_fetch_task_with_timeout_async(async move || {\n                let output = crate::cmd::cmd_read_async_inherited_env(\n                    &kerl_path,\n                    &[\"list\", \"releases\", \"all\"],\n                    [(\"KERL_BASE_DIR\", kerl_base_dir.as_os_str())],\n                )\n                .await?;\n                let versions = output\n                    .split('\\n')\n                    .filter(|s| regex!(r\"^[0-9].+$\").is_match(s))\n                    .map(|s| VersionInfo {\n                        version: s.to_string(),\n                        ..Default::default()\n                    })\n                    .collect();\n                Ok(versions)\n            })\n            .await?\n        };\n        Ok(versions)\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        if let Some(tv) = self.install_precompiled(ctx, tv.clone()).await? {\n            return Ok(tv);\n        }\n        self.install_via_kerl(ctx, tv).await\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        _request: &ToolRequest,\n        target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let mut opts = BTreeMap::new();\n        let settings = Settings::get();\n        let is_current_platform = target.is_current();\n\n        // Only include compile option if true (non-default)\n        let compile = if is_current_platform {\n            settings.erlang.compile.unwrap_or(false)\n        } else {\n            false\n        };\n        if compile {\n            opts.insert(\"compile\".to_string(), \"true\".to_string());\n        }\n\n        opts\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/go.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::Result;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::fetch_checksum_from_file;\nuse crate::backend::{Backend, VersionInfo};\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::file::{TarFormat, TarOptions};\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::{ToolRequest, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{env, file, github, plugins};\nuse async_trait::async_trait;\nuse itertools::Itertools;\nuse tempfile::tempdir_in;\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct GoPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl GoPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"go\")),\n        }\n    }\n\n    /// Check if a Go version string is valid (not \"1\" and not beta/rc)\n    /// - \"1\" corresponds to the `go1` tag which has no installable download\n    /// - beta/rc versions are pre-release and should be excluded by default\n    fn is_valid_version(v: &str) -> bool {\n        v != \"1\" && !regex!(r\"(beta|rc)[0-9]*$\").is_match(v)\n    }\n\n    // Represents go binary path\n    fn go_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(\"go\")\n    }\n\n    // Represents GOPATH environment variable\n    fn gopath(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"packages\")\n    }\n\n    // Represents GOROOT environment variable\n    fn goroot(&self, tv: &ToolVersion) -> PathBuf {\n        let old_path = tv.install_path().join(\"go\");\n        if old_path.exists() {\n            return old_path;\n        }\n        tv.install_path()\n    }\n\n    // Represents GOBIN environment variable\n    fn gobin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\")\n    }\n\n    fn install_default_packages(\n        &self,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> eyre::Result<()> {\n        let settings = Settings::get();\n        let default_packages_file = file::replace_path(&settings.go_default_packages_file);\n        let body = file::read_to_string(default_packages_file).unwrap_or_default();\n        for package in body.lines() {\n            let package = package.split('#').next().unwrap_or_default().trim();\n            if package.is_empty() {\n                continue;\n            }\n            pr.set_message(format!(\"install default package: {package}\"));\n            let package = if package.contains('@') {\n                package.to_string()\n            } else {\n                format!(\"{package}@latest\")\n            };\n            CmdLineRunner::new(self.go_bin(tv))\n                .with_pr(pr)\n                .arg(\"install\")\n                .arg(package)\n                .envs(self._exec_env(tv)?)\n                .execute()?;\n        }\n        Ok(())\n    }\n\n    fn test_go(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> eyre::Result<()> {\n        pr.set_message(\"go version\".into());\n        CmdLineRunner::new(self.go_bin(tv))\n            // run the command in the install path to prevent issues with go.mod version mismatch\n            .current_dir(tv.install_path())\n            .with_pr(pr)\n            .arg(\"version\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &mut ToolVersion, pr: &dyn SingleReport) -> eyre::Result<PathBuf> {\n        let settings = Settings::get();\n        let tarball_url = Arc::new(\n            self.get_tarball_url(tv, &PlatformTarget::from_current())\n                .await?\n                .ok_or_else(|| eyre::eyre!(\"Failed to get go tarball URL\"))?,\n        );\n        let filename = tarball_url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        let tarball_url_ = tarball_url.clone();\n        let checksum_handle = tokio::spawn(async move {\n            let checksum_url = format!(\"{}.sha256\", &tarball_url_);\n            HTTP.get_text(checksum_url).await\n        });\n        pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&*tarball_url, &tarball_path, Some(pr))\n            .await?;\n\n        if !settings.go_skip_checksum {\n            let platform_key = self.get_platform_key();\n            let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n            platform_info.url = Some(tarball_url.to_string());\n            if platform_info.checksum.is_none() {\n                let checksum = checksum_handle.await.unwrap()?;\n                platform_info.checksum = Some(format!(\"sha256:{checksum}\"));\n            }\n        }\n        Ok(tarball_path)\n    }\n\n    fn install(\n        &self,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n        tarball_path: &Path,\n    ) -> eyre::Result<()> {\n        let tarball = tarball_path\n            .file_name()\n            .unwrap_or_default()\n            .to_string_lossy();\n        pr.set_message(format!(\"extract {tarball}\"));\n        let tmp_extract_path = tempdir_in(tv.install_path().parent().unwrap())?;\n        if cfg!(windows) {\n            file::unzip(tarball_path, tmp_extract_path.path(), &Default::default())?;\n        } else {\n            file::untar(\n                tarball_path,\n                tmp_extract_path.path(),\n                &TarOptions {\n                    pr: Some(pr),\n                    ..TarOptions::new(TarFormat::TarGz)\n                },\n            )?;\n        }\n        file::remove_all(tv.install_path())?;\n        file::rename(tmp_extract_path.path().join(\"go\"), tv.install_path())?;\n        Ok(())\n    }\n\n    fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> eyre::Result<()> {\n        self.test_go(tv, pr)?;\n        if let Err(err) = self.install_default_packages(tv, pr) {\n            warn!(\"failed to install default go packages: {err:#}\");\n        }\n        let settings = Settings::get();\n        if settings.go_set_gopath {\n            warn!(\"setting go_set_gopath is deprecated\");\n        }\n        Ok(())\n    }\n\n    fn _exec_env(&self, tv: &ToolVersion) -> eyre::Result<BTreeMap<String, String>> {\n        let mut map = BTreeMap::new();\n        let mut set = |k: &str, v: PathBuf| {\n            map.insert(k.to_string(), v.to_string_lossy().to_string());\n        };\n        let settings = Settings::get();\n        let gobin = settings.go_set_gobin;\n        let gobin_env_is_set = env::PRISTINE_ENV.contains_key(\"GOBIN\");\n        if gobin == Some(true) || (gobin.is_none() && !gobin_env_is_set) {\n            set(\"GOBIN\", self.gobin(tv));\n        }\n        if settings.go_set_goroot {\n            set(\"GOROOT\", self.goroot(tv));\n        }\n        if settings.go_set_gopath {\n            set(\"GOPATH\", self.gopath(tv));\n        }\n        Ok(map)\n    }\n}\n\n#[async_trait]\nimpl Backend for GoPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }]\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        // Extract repo name (e.g., \"golang/go\") from the configured URL\n        // The go_repo setting is like \"https://github.com/golang/go\"\n        let settings = Settings::get();\n        let repo = settings\n            .go_repo\n            .trim_start_matches(\"https://\")\n            .trim_start_matches(\"http://\")\n            .trim_start_matches(\"github.com/\")\n            .trim_end_matches(\".git\")\n            .trim_end_matches('/');\n\n        // Go uses tags, not releases. When MISE_LIST_ALL_VERSIONS is set,\n        // we fetch tags with dates (slower). Otherwise, use fast method without dates.\n        let versions: Vec<VersionInfo> = if *env::MISE_LIST_ALL_VERSIONS {\n            // Slow path: fetch tags with commit dates for versions host\n            github::list_tags_with_dates(repo)\n                .await?\n                .into_iter()\n                .filter_map(|t| t.name.strip_prefix(\"go\").map(|v| (v.to_string(), t.date)))\n                .filter(|(v, _)| Self::is_valid_version(v))\n                .unique_by(|(v, _)| v.clone())\n                .sorted_by_cached_key(|(v, _)| (Versioning::new(v), v.to_string()))\n                .map(|(version, created_at)| VersionInfo {\n                    version,\n                    created_at,\n                    ..Default::default()\n                })\n                .collect()\n        } else {\n            // Fast path: use git ls-remote to get all go tags efficiently\n            // We can't use github::list_tags here because golang/go has 500+ tags\n            // and the \"go1.x\" version tags aren't on the first page of API results\n            let go_repo = Settings::get().go_repo.clone();\n            plugins::core::run_fetch_task_with_timeout_async(async move || {\n                let output = crate::cmd::cmd_read_async_inherited_env(\n                    \"git\",\n                    &[\"ls-remote\", \"--tags\", \"--refs\", &go_repo, \"go*\"],\n                    std::iter::empty::<(&str, &std::ffi::OsStr)>(),\n                )\n                .await?;\n                let versions: Vec<VersionInfo> = output\n                    .lines()\n                    .filter_map(|line| line.split(\"/go\").last())\n                    .filter(|s| !s.is_empty())\n                    .filter(|s| Self::is_valid_version(s))\n                    .map(|s| s.to_string())\n                    .unique()\n                    .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string()))\n                    .map(|version| VersionInfo {\n                        version,\n                        ..Default::default()\n                    })\n                    .collect();\n                Ok(versions)\n            })\n            .await?\n        };\n        Ok(versions)\n    }\n    async fn _idiomatic_filenames(&self) -> eyre::Result<Vec<String>> {\n        Ok(vec![\".go-version\".into()])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let tarball_path = self.download(&mut tv, ctx.pr.as_ref()).await?;\n        ctx.pr.next_operation();\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.next_operation();\n        self.install(&tv, ctx.pr.as_ref(), &tarball_path)?;\n        self.verify(&tv, ctx.pr.as_ref())?;\n\n        Ok(tv)\n    }\n\n    async fn uninstall_version_impl(\n        &self,\n        _config: &Arc<Config>,\n        _pr: &dyn SingleReport,\n        tv: &ToolVersion,\n    ) -> eyre::Result<()> {\n        let gopath = self.gopath(tv);\n        if gopath.exists() {\n            cmd!(\"chmod\", \"-R\", \"u+wx\", gopath).run()?;\n        }\n        Ok(())\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Vec<PathBuf>> {\n        if let ToolRequest::System { .. } = tv.request {\n            return Ok(vec![]);\n        }\n        // goroot/bin must always be included, irrespective of MISE_GO_SET_GOROOT\n        Ok(vec![self.gobin(tv)])\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        self._exec_env(tv)\n    }\n\n    async fn get_tarball_url(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<Option<String>> {\n        let settings = Settings::get();\n        let platform = match target.os_name() {\n            \"macos\" => \"darwin\",\n            \"linux\" => \"linux\",\n            \"windows\" => \"windows\",\n            _ => \"linux\",\n        };\n        let arch = match target.arch_name() {\n            \"x64\" => \"amd64\",\n            \"arm64\" => \"arm64\",\n            \"arm\" => \"armv6l\",\n            \"riscv64\" => \"riscv64\",\n            other => other,\n        };\n        let ext = if target.os_name() == \"windows\" {\n            \"zip\"\n        } else {\n            \"tar.gz\"\n        };\n        Ok(Some(format!(\n            \"{}/go{}.{}-{}.{}\",\n            &settings.go_download_mirror, tv.version, platform, arch, ext\n        )))\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let settings = Settings::get();\n\n        // Build tarball URL\n        let url = self\n            .get_tarball_url(tv, target)\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"Failed to get go tarball URL\"))?;\n\n        // Go provides .sha256 files alongside each tarball\n        let checksum = if !settings.go_skip_checksum {\n            let checksum_url = format!(\"{}.sha256\", &url);\n            fetch_checksum_from_file(&checksum_url, \"sha256\").await\n        } else {\n            None\n        };\n\n        Ok(PlatformInfo {\n            url: Some(url),\n            checksum,\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/java.rs",
    "content": "use std::collections::{BTreeMap, HashMap, HashSet};\nuse std::fmt::Display;\nuse std::fs::{self};\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse crate::backend::{Backend, VersionInfo, normalize_idiomatic_contents};\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::cli::version::OS;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::file::{TarFormat, TarOptions};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::toolset::{ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{file, plugins};\nuse async_trait::async_trait;\nuse color_eyre::eyre::{Result, eyre};\nuse indoc::formatdoc;\nuse itertools::Itertools;\nuse regex::Regex;\nuse serde_derive::{Deserialize, Serialize};\nuse std::str::FromStr;\nuse std::sync::LazyLock as Lazy;\nuse versions::Versioning;\nuse xx::regex;\n\nstatic VERSION_REGEX: Lazy<regex::Regex> = Lazy::new(|| {\n    Regex::new(\n        r\"(?i)(^Available versions:|-src|-dev|-latest|-stm|[-\\\\.]rc|-milestone|-alpha|-beta|[-\\\\.]pre|-next|-test|snapshot|SNAPSHOT|master)\"\n    )\n        .unwrap()\n});\n\n#[derive(Debug)]\npub struct JavaPlugin {\n    ba: Arc<BackendArg>,\n    java_metadata_ea_cache: CacheManager<HashMap<String, JavaMetadata>>,\n    java_metadata_ga_cache: CacheManager<HashMap<String, JavaMetadata>>,\n}\n\nimpl JavaPlugin {\n    pub fn new() -> Self {\n        let settings = Settings::get();\n        let ba = Arc::new(plugins::core::new_backend_arg(\"java\"));\n        Self {\n            java_metadata_ea_cache: CacheManagerBuilder::new(\n                ba.cache_path.join(\"java_metadata_ea.msgpack.z\"),\n            )\n            .with_fresh_duration(settings.fetch_remote_versions_cache())\n            .build(),\n            java_metadata_ga_cache: CacheManagerBuilder::new(\n                ba.cache_path.join(\"java_metadata_ga.msgpack.z\"),\n            )\n            .with_fresh_duration(settings.fetch_remote_versions_cache())\n            .build(),\n            ba,\n        }\n    }\n\n    async fn fetch_java_metadata(\n        &self,\n        release_type: &str,\n    ) -> Result<&HashMap<String, JavaMetadata>> {\n        let cache = if release_type == \"ea\" {\n            &self.java_metadata_ea_cache\n        } else {\n            &self.java_metadata_ga_cache\n        };\n        let release_type = release_type.to_string();\n        cache\n            .get_or_try_init_async(async || {\n                let mut metadata = HashMap::new();\n\n                for m in self.download_java_metadata(&release_type).await? {\n                    // add openjdk short versions like \"java@17.0.0\" which default to openjdk\n                    if m.vendor == Settings::get().java.shorthand_vendor {\n                        metadata.insert(m.version.to_string(), m.clone());\n                    }\n                    metadata.insert(m.to_string(), m);\n                }\n\n                Ok(metadata)\n            })\n            .await\n    }\n\n    fn java_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin/java\")\n    }\n\n    fn test_java(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> {\n        CmdLineRunner::new(self.java_bin(tv))\n            .with_pr(pr)\n            .env(\"JAVA_HOME\", tv.install_path())\n            .arg(\"-version\")\n            .execute()\n    }\n\n    async fn download(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pr: &dyn SingleReport,\n        m: &JavaMetadata,\n    ) -> Result<PathBuf> {\n        let filename = m.url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&m.url, &tarball_path, Some(pr)).await?;\n\n        let platform_key = self.get_platform_key();\n        if !tv.lock_platforms.contains_key(&platform_key) {\n            let platform_info = tv.lock_platforms.entry(platform_key).or_default();\n            platform_info.url = Some(m.url.clone());\n            if m.checksum.is_some() {\n                platform_info.checksum = m.checksum.clone();\n            }\n        }\n        self.verify_checksum(ctx, tv, &tarball_path)?;\n\n        Ok(tarball_path)\n    }\n\n    fn install(\n        &self,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n        tarball_path: &Path,\n        m: &JavaMetadata,\n    ) -> Result<()> {\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        pr.set_message(format!(\"extract {filename}\"));\n        match m.file_type.as_deref() {\n            Some(\"zip\") => file::unzip(tarball_path, &tv.download_path(), &Default::default())?,\n            _ => file::untar(\n                tarball_path,\n                &tv.download_path(),\n                &TarOptions {\n                    pr: Some(pr),\n                    ..TarOptions::new(TarFormat::from_file_name(\n                        &tarball_path.file_name().unwrap().to_string_lossy(),\n                    ))\n                },\n            )?,\n        }\n        self.move_to_install_path(tv, m)\n    }\n\n    fn move_to_install_path(&self, tv: &ToolVersion, m: &JavaMetadata) -> Result<()> {\n        let basedir = tv\n            .download_path()\n            .read_dir()?\n            .find(|e| e.as_ref().unwrap().file_type().unwrap().is_dir())\n            .unwrap()?\n            .path();\n        let contents_dir = basedir.join(\"Contents\");\n        let source_dir = match m.vendor.as_str() {\n            \"zulu\" | \"liberica\" => basedir,\n            _ if os() == \"macosx\" => basedir.join(\"Contents\").join(\"Home\"),\n            _ => basedir,\n        };\n        file::remove_all(tv.install_path())?;\n        file::create_dir_all(tv.install_path())?;\n        for entry in fs::read_dir(source_dir)? {\n            let entry = entry?;\n            let dest = tv.install_path().join(entry.file_name());\n            trace!(\"moving {:?} to {:?}\", entry.path(), &dest);\n            file::rename(entry.path(), dest)?;\n        }\n\n        if cfg!(target_os = \"macos\") {\n            self.handle_macos_integration(&contents_dir, tv, m)?;\n        }\n\n        Ok(())\n    }\n\n    fn handle_macos_integration(\n        &self,\n        contents_dir: &Path,\n        tv: &ToolVersion,\n        m: &JavaMetadata,\n    ) -> Result<()> {\n        // move Contents dir to install path for macOS, if it exists\n        if contents_dir.exists() {\n            file::create_dir_all(tv.install_path().join(\"Contents\"))?;\n            for entry in fs::read_dir(contents_dir)? {\n                let entry = entry?;\n                // skip Home dir, so we can symlink it later\n                if entry.file_name() == \"Home\" {\n                    continue;\n                }\n                let dest = tv.install_path().join(\"Contents\").join(entry.file_name());\n                trace!(\"moving {:?} to {:?}\", entry.path(), &dest);\n                file::rename(entry.path(), dest)?;\n            }\n            file::make_symlink(\n                tv.install_path().as_path(),\n                &tv.install_path().join(\"Contents\").join(\"Home\"),\n            )?;\n        }\n\n        // if vendor is Zulu, symlink zulu-{major_version}.jdk/Contents to install path for macOS\n        if m.vendor.as_str() == \"zulu\" {\n            let (major_version, _) = m\n                .version\n                .split_once('.')\n                .unwrap_or_else(|| (&m.version, \"\"));\n            file::make_symlink(\n                tv.install_path()\n                    .join(format!(\"zulu-{major_version}.jdk\"))\n                    .join(\"Contents\")\n                    .as_path(),\n                &tv.install_path().join(\"Contents\"),\n            )?;\n        }\n\n        if tv.install_path().join(\"Contents\").exists() {\n            info!(\n                \"{}\",\n                formatdoc! {r#\"\n                To enable macOS integration, run the following commands:\n                sudo mkdir /Library/Java/JavaVirtualMachines/{version}.jdk\n                sudo ln -s {path}/Contents /Library/Java/JavaVirtualMachines/{version}.jdk/Contents\n                \"#,\n                    version = tv.version,\n                    path = tv.install_path().display(),\n                }\n            );\n        }\n        Ok(())\n    }\n\n    fn verify(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> {\n        pr.set_message(\"java -version\".into());\n        self.test_java(tv, pr)\n    }\n\n    fn tv_release_type(&self, tv: &ToolVersion) -> String {\n        tv.request\n            .options()\n            .get(\"release_type\")\n            .map(|s| s.to_string())\n            .unwrap_or(String::from(\"ga\"))\n    }\n\n    fn tv_to_java_version(&self, tv: &ToolVersion) -> String {\n        if regex!(r\"^\\d\").is_match(&tv.version) {\n            // undo openjdk shorthand\n            format!(\"{}-{}\", Settings::get().java.shorthand_vendor, tv.version)\n        } else {\n            tv.version.clone()\n        }\n    }\n\n    async fn tv_to_metadata(&self, tv: &ToolVersion) -> Result<&JavaMetadata> {\n        let v: String = self.tv_to_java_version(tv);\n        let release_type = self.tv_release_type(tv);\n        let m = self\n            .fetch_java_metadata(&release_type)\n            .await?\n            .get(&v)\n            .ok_or_else(|| eyre!(\"no metadata found for version {}\", tv.version))?;\n        Ok(m)\n    }\n\n    async fn download_java_metadata(&self, release_type: &str) -> Result<Vec<JavaMetadata>> {\n        let settings = Settings::get();\n        let url = format!(\n            \"https://mise-java.jdx.dev/jvm/{}/{}/{}.json\",\n            release_type,\n            os(),\n            arch(&settings)\n        );\n\n        let metadata = HTTP_FETCH\n            .json::<Vec<JavaMetadata>, _>(url)\n            .await?\n            .into_iter()\n            .filter(|m| {\n                m.file_type\n                    .as_ref()\n                    .is_some_and(|file_type| JAVA_FILE_TYPES.contains(file_type))\n            })\n            .collect();\n        Ok(metadata)\n    }\n}\n\n#[async_trait]\nimpl Backend for JavaPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let release_type = config\n            .get_tool_request_set()\n            .await?\n            .list_tools()\n            .iter()\n            .find(|ba| ba.short == \"java\")\n            .and_then(|ba| ba.opts().get(\"release_type\").map(|s| s.to_string()))\n            .unwrap_or_else(|| \"ga\".to_string());\n\n        let versions = self\n            .fetch_java_metadata(&release_type)\n            .await?\n            .iter()\n            .sorted_by_cached_key(|(v, m)| {\n                let is_shorthand = regex!(r\"^\\d\").is_match(v);\n                let vendor = &m.vendor;\n                let is_jdk = match is_shorthand {\n                    true => true,\n                    false => m\n                        .image_type\n                        .as_ref()\n                        .is_some_and(|image_type| image_type == \"jdk\"),\n                };\n                let features = 10 - m.features.as_ref().map_or(0, |f| f.len());\n                let version = Versioning::new(v);\n                // Extract build suffix after a '+', '.' if present. If not present, treat as 0.\n                let build_num = v\n                    .rsplit_once('+')\n                    .or_else(|| v.rsplit_once('.'))\n                    .and_then(|(_, tail)| {\n                        // take leading digits of tail\n                        let digits: String =\n                            tail.chars().take_while(|c| c.is_ascii_digit()).collect();\n                        if digits.is_empty() {\n                            None\n                        } else {\n                            u64::from_str(&digits).ok()\n                        }\n                    })\n                    .unwrap_or(0u64);\n                (\n                    is_shorthand,\n                    vendor,\n                    is_jdk,\n                    features,\n                    version,\n                    build_num,\n                    v.to_string(),\n                )\n            })\n            .map(|(v, m)| VersionInfo {\n                version: v.clone(),\n                created_at: m.created_at.clone(),\n                ..Default::default()\n            })\n            .unique_by(|v| v.version.clone())\n            .collect();\n\n        Ok(versions)\n    }\n\n    /// Override to bypass the shared remote_versions cache since Java has separate\n    /// caches for GA and EA release types in fetch_java_metadata.\n    async fn list_remote_versions_with_info(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<VersionInfo>> {\n        self._list_remote_versions(config).await\n    }\n\n    fn list_installed_versions_matching(&self, query: &str) -> Vec<String> {\n        let versions = self.list_installed_versions();\n        self.fuzzy_match_filter(versions, query)\n    }\n\n    async fn list_versions_matching(\n        &self,\n        config: &Arc<Config>,\n        query: &str,\n    ) -> eyre::Result<Vec<String>> {\n        let versions = self.list_remote_versions(config).await?;\n        Ok(self.fuzzy_match_filter(versions, query))\n    }\n\n    fn get_aliases(&self) -> Result<BTreeMap<String, String>> {\n        let aliases = BTreeMap::from([(\"lts\".into(), \"25\".into())]);\n        Ok(aliases)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".java-version\".into(), \".sdkmanrc\".into()])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let contents = file::read_to_string(path)?;\n        if path.file_name() == Some(\".sdkmanrc\".as_ref()) {\n            let version = contents\n                .lines()\n                .find(|l| l.starts_with(\"java\"))\n                .unwrap_or(\"java=\")\n                .split_once('=')\n                .unwrap_or_default()\n                .1;\n            if !version.contains('-') {\n                return Ok(vec![version.to_string()]);\n            }\n            let (version, vendor) = version.rsplit_once('-').unwrap_or_default();\n            let vendor = match vendor {\n                \"amzn\" => \"corretto\",\n                \"albba\" => \"dragonwell\",\n                \"graalce\" => \"graalvm-community\",\n                \"librca\" => \"liberica\",\n                \"open\" => \"openjdk\",\n                \"ms\" => \"microsoft\",\n                \"sapmchn\" => \"sapmachine\",\n                \"sem\" => \"semeru-openj9\",\n                \"tem\" => \"temurin\",\n                _ => vendor, // either same vendor name or unsupported\n            };\n            let mut version = version.split(['+', '-'].as_ref()).collect::<Vec<&str>>()[0];\n            // if vendor is zulu, we can only match the major version\n            if vendor == \"zulu\" {\n                version = version.split_once('.').unwrap_or_default().0;\n            }\n            Ok(vec![format!(\"{vendor}-{version}\")])\n        } else {\n            Ok(normalize_idiomatic_contents(&contents)\n                .lines()\n                .map(|s| s.to_string())\n                .collect())\n        }\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        // Check if URL already exists in lockfile platforms first\n        let platform_key = self.get_platform_key();\n        let (metadata, tarball_path) =\n            if let Some(platform_info) = tv.lock_platforms.get(&platform_key) {\n                if let Some(ref url) = platform_info.url {\n                    // Use the filename from the URL, not the platform key\n                    let filename = url.split('/').next_back().unwrap();\n                    debug!(\"Using existing URL from lockfile for {}: {}\", filename, url);\n                    let tarball_path = tv.download_path().join(filename);\n\n                    // If the file does not exist, download using the lockfile URL\n                    if !tarball_path.exists() {\n                        debug!(\"File not found, downloading from cached URL: {}\", url);\n                        // Download using the lockfile URL, not JavaMetadata\n                        HTTP.download_file(url, &tarball_path, Some(ctx.pr.as_ref()))\n                            .await?;\n                        // Optionally verify checksum if present\n                        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n                    }\n\n                    // Fetch metadata for installation (for install/move logic)\n                    let metadata = self.tv_to_metadata(&tv).await?;\n                    (metadata, tarball_path)\n                } else {\n                    // No URL in lockfile, fallback to metadata\n                    let metadata = self.tv_to_metadata(&tv).await?;\n                    let tarball_path = self\n                        .download(ctx, &mut tv, ctx.pr.as_ref(), metadata)\n                        .await?;\n                    (metadata, tarball_path)\n                }\n            } else {\n                let metadata = self.tv_to_metadata(&tv).await?;\n                let tarball_path = self\n                    .download(ctx, &mut tv, ctx.pr.as_ref(), metadata)\n                    .await?;\n                (metadata, tarball_path)\n            };\n\n        ctx.pr.next_operation();\n        self.install(&tv, ctx.pr.as_ref(), &tarball_path, metadata)?;\n        ctx.pr.next_operation();\n        self.verify(&tv, ctx.pr.as_ref())?;\n\n        Ok(tv)\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let map = BTreeMap::from([(\n            \"JAVA_HOME\".into(),\n            tv.install_path().to_string_lossy().into(),\n        )]);\n        Ok(map)\n    }\n\n    fn fuzzy_match_filter(&self, versions: Vec<String>, query: &str) -> Vec<String> {\n        let is_vendor_prefix = query != \"latest\" && query.ends_with('-');\n        let query_escaped = regex::escape(query);\n        let query = match query {\n            \"latest\" => \"[0-9].*\",\n            // else; use escaped query\n            _ => &query_escaped,\n        };\n        // Same semantics as Backend::fuzzy_match_filter:\n        // - \"1.2\" should match \"1.2.3\" but not \"1.20\"\n        // - vendor prefixes like \"temurin-\" should match \"temurin-25...\"\n        let query_regex = if is_vendor_prefix {\n            Regex::new(&format!(\"^{query}.*$\")).unwrap()\n        } else {\n            Regex::new(&format!(\"^{query}([+\\\\-.].+)?$\")).unwrap()\n        };\n\n        versions\n            .into_iter()\n            .filter(|v| {\n                if query == v {\n                    return true;\n                }\n                if VERSION_REGEX.is_match(v) {\n                    return false;\n                }\n                query_regex.is_match(v)\n            })\n            .collect()\n    }\n}\n\nfn os() -> &'static str {\n    if cfg!(target_os = \"macos\") {\n        \"macosx\"\n    } else if OS.as_str() == \"freebsd\" {\n        \"linux\"\n    } else {\n        &OS\n    }\n}\n\nfn arch(settings: &Settings) -> &str {\n    match settings.arch() {\n        \"x64\" => \"x86_64\",\n        \"arm64\" => \"aarch64\",\n        \"arm\" => \"arm32-vfp-hflt\",\n        other => other,\n    }\n}\n\n#[derive(Debug, Serialize, Deserialize, Clone, Default)]\n#[serde(default)]\nstruct JavaMetadata {\n    // architecture: String,\n    checksum: Option<String>,\n    // checksum_url: Option<String>,\n    created_at: Option<String>,\n    features: Option<Vec<String>>,\n    file_type: Option<String>,\n    // filename: String,\n    image_type: Option<String>,\n    java_version: String,\n    jvm_impl: String,\n    // os: String,\n    // release_type: String,\n    // size: Option<i32>,\n    url: String,\n    vendor: String,\n    version: String,\n}\n\nimpl Display for JavaMetadata {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let mut v = vec![self.vendor.clone()];\n        if self\n            .image_type\n            .as_ref()\n            .is_some_and(|image_type| image_type == \"jre\")\n        {\n            v.push(self.image_type.clone().unwrap());\n        } else if self.image_type.is_none() {\n            v.push(\"unknown\".to_string());\n        }\n        if let Some(features) = &self.features {\n            for f in features {\n                if JAVA_FEATURES.contains(f) {\n                    v.push(f.clone());\n                }\n            }\n        }\n        if self.jvm_impl == \"openj9\" {\n            v.push(self.jvm_impl.clone());\n        }\n        if self.vendor == \"liberica-nik\" {\n            let major = self\n                .java_version\n                .split('.')\n                .next()\n                .unwrap_or(&self.java_version);\n            v.push(format!(\"openjdk{}\", major));\n        }\n        v.push(self.version.clone());\n        write!(f, \"{}\", v.join(\"-\"))\n    }\n}\n\n// only care about these features\nstatic JAVA_FEATURES: Lazy<HashSet<String>> = Lazy::new(|| {\n    HashSet::from([\"crac\", \"javafx\", \"jcef\", \"leyden\", \"lite\", \"musl\"].map(|s| s.to_string()))\n});\n#[cfg(unix)]\nstatic JAVA_FILE_TYPES: Lazy<HashSet<String>> =\n    Lazy::new(|| HashSet::from([\"tar.gz\", \"tar.xz\"].map(|s| s.to_string())));\n#[cfg(windows)]\nstatic JAVA_FILE_TYPES: Lazy<HashSet<String>> =\n    Lazy::new(|| HashSet::from([\"zip\"].map(|s| s.to_string())));\n"
  },
  {
    "path": "src/plugins/core/mod.rs",
    "content": "use color_eyre::eyre::Context;\nuse eyre::Result;\nuse std::ffi::OsString;\nuse std::future::Future;\nuse std::sync::Arc;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::backend::{Backend, BackendMap};\nuse crate::cli::args::{BackendArg, BackendResolution};\nuse crate::config::Settings;\nuse crate::env;\nuse crate::path_env::PathEnv;\nuse crate::timeout::{TimeoutError, run_with_timeout, run_with_timeout_async};\nuse crate::toolset::ToolVersion;\n\nmod bun;\nmod deno;\nmod dotnet;\nmod elixir;\nmod erlang;\nmod go;\nmod java;\nmod node;\npub(crate) mod python;\n#[cfg_attr(windows, path = \"ruby_windows.rs\")]\nmod ruby;\nmod ruby_common;\nmod rust;\nmod swift;\nmod zig;\n\npub static CORE_PLUGINS: Lazy<BackendMap> = Lazy::new(|| {\n    let plugins: Vec<Arc<dyn Backend>> = vec![\n        Arc::new(bun::BunPlugin::new()),\n        Arc::new(deno::DenoPlugin::new()),\n        Arc::new(dotnet::DotnetPlugin::new()),\n        Arc::new(elixir::ElixirPlugin::new()),\n        Arc::new(erlang::ErlangPlugin::new()),\n        Arc::new(go::GoPlugin::new()),\n        Arc::new(java::JavaPlugin::new()),\n        Arc::new(node::NodePlugin::new()),\n        Arc::new(python::PythonPlugin::new()),\n        Arc::new(ruby::RubyPlugin::new()),\n        Arc::new(rust::RustPlugin::new()),\n        Arc::new(swift::SwiftPlugin::new()),\n        Arc::new(zig::ZigPlugin::new()),\n    ];\n    plugins\n        .into_iter()\n        .map(|p| (p.id().to_string(), p))\n        .collect()\n});\n\npub fn path_env_with_tv_path(tv: &ToolVersion) -> Result<OsString> {\n    let mut path_env = PathEnv::from_iter(env::PATH.clone());\n    path_env.add(tv.install_path().join(\"bin\"));\n    Ok(path_env.join())\n}\n\npub fn run_fetch_task_with_timeout<F, T>(f: F) -> Result<T>\nwhere\n    F: FnOnce() -> Result<T> + Send,\n    T: Send,\n{\n    let timeout = Settings::get().fetch_remote_versions_timeout();\n    match run_with_timeout(f, timeout) {\n        Ok(v) => Ok(v),\n        Err(err) => {\n            // Only add a hint when the error was actually caused by a timeout\n            if err.downcast_ref::<TimeoutError>().is_some() {\n                Err(err).context(\n                    \"change with `fetch_remote_versions_timeout` or env `MISE_FETCH_REMOTE_VERSIONS_TIMEOUT`\",\n                )\n            } else {\n                Err(err)\n            }\n        }\n    }\n}\n\npub async fn run_fetch_task_with_timeout_async<F, Fut, T>(f: F) -> Result<T>\nwhere\n    Fut: Future<Output = Result<T>> + Send,\n    T: Send,\n    F: FnOnce() -> Fut,\n{\n    let timeout = Settings::get().fetch_remote_versions_timeout();\n    match run_with_timeout_async(f, timeout).await {\n        Ok(v) => Ok(v),\n        Err(err) => {\n            if err.downcast_ref::<TimeoutError>().is_some() {\n                Err(err).context(\n                    \"change with `fetch_remote_versions_timeout` or env `MISE_FETCH_REMOTE_VERSIONS_TIMEOUT`\",\n                )\n            } else {\n                Err(err)\n            }\n        }\n    }\n}\n\npub fn new_backend_arg(tool_name: &str) -> BackendArg {\n    BackendArg::new_raw(\n        tool_name.to_string(),\n        Some(format!(\"core:{tool_name}\")),\n        tool_name.to_string(),\n        None,\n        BackendResolution::new(true),\n    )\n}\n"
  },
  {
    "path": "src/plugins/core/node.rs",
    "content": "use crate::backend::VersionInfo;\nuse crate::backend::static_helpers::fetch_checksum_from_shasums;\nuse crate::backend::{\n    Backend, VersionCacheManager, normalize_idiomatic_contents, platform_target::PlatformTarget,\n};\nuse crate::build_time::built_info;\nuse crate::cache::CacheManagerBuilder;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::settings::DEFAULT_NODE_MIRROR_URL;\nuse crate::config::{Config, Settings};\nuse crate::file::{TarFormat, TarOptions};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::{ToolRequest, ToolVersion};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{env, file, gpg, hash, http, plugins};\nuse async_trait::async_trait;\nuse eyre::{Result, bail, ensure};\nuse serde_derive::Deserialize;\nuse std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::sync::OnceLock;\nuse tempfile::tempdir_in;\nuse tokio::sync::Mutex;\nuse url::Url;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct NodePlugin {\n    ba: Arc<BackendArg>,\n}\n\nenum FetchOutcome {\n    Downloaded,\n    NotFound,\n}\n\nimpl NodePlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: plugins::core::new_backend_arg(\"node\").into(),\n        }\n    }\n\n    async fn fetch_binary(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        opts: &BuildOpts,\n        extract: impl FnOnce() -> Result<()>,\n    ) -> Result<FetchOutcome> {\n        debug!(\"{:?}: we will fetch a precompiled version\", self);\n\n        match self\n            .fetch_tarball(\n                ctx,\n                tv,\n                ctx.pr.as_ref(),\n                &opts.binary_tarball_url,\n                &opts.binary_tarball_path,\n                &opts.version,\n            )\n            .await\n        {\n            Ok(()) => {\n                debug!(\"{:?}: successfully downloaded node archive\", self);\n            }\n            Err(e) if matches!(http::error_code(&e), Some(404)) => {\n                debug!(\"{:?}: precompiled node archive not found {e}\", self);\n                return Ok(FetchOutcome::NotFound);\n            }\n            Err(e) => return Err(e),\n        };\n\n        ctx.pr.next_operation();\n        let tarball_name = &opts.binary_tarball_name;\n        ctx.pr.set_message(format!(\"extract {tarball_name}\"));\n        debug!(\"{:?}: extracting precompiled node\", self);\n\n        if let Err(e) = extract() {\n            debug!(\"{:?}: extraction failed: {e}\", self);\n            return Err(e);\n        }\n\n        debug!(\"{:?}: precompiled node extraction was successful\", self);\n        Ok(FetchOutcome::Downloaded)\n    }\n\n    fn extract_zip(&self, opts: &BuildOpts, _ctx: &InstallContext) -> Result<()> {\n        let tmp_extract_path = tempdir_in(opts.install_path.parent().unwrap())?;\n        file::unzip(\n            &opts.binary_tarball_path,\n            tmp_extract_path.path(),\n            &Default::default(),\n        )?;\n        file::remove_all(&opts.install_path)?;\n        file::rename(\n            tmp_extract_path.path().join(slug(&opts.version)),\n            &opts.install_path,\n        )?;\n        Ok(())\n    }\n\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        opts: &BuildOpts,\n    ) -> Result<()> {\n        match self\n            .fetch_binary(ctx, tv, opts, || {\n                file::untar(\n                    &opts.binary_tarball_path,\n                    &opts.install_path,\n                    &TarOptions {\n                        strip_components: 1,\n                        pr: Some(ctx.pr.as_ref()),\n                        ..TarOptions::new(TarFormat::TarGz)\n                    },\n                )?;\n                Ok(())\n            })\n            .await?\n        {\n            FetchOutcome::Downloaded => Ok(()),\n            FetchOutcome::NotFound => {\n                if Settings::get().node.compile != Some(false) {\n                    self.install_compiling(ctx, tv, opts).await\n                } else {\n                    bail!(\"precompiled node archive not found and compilation is disabled\")\n                }\n            }\n        }\n    }\n\n    async fn install_windows(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        opts: &BuildOpts,\n    ) -> Result<()> {\n        match self\n            .fetch_binary(ctx, tv, opts, || self.extract_zip(opts, ctx))\n            .await?\n        {\n            FetchOutcome::Downloaded => Ok(()),\n            FetchOutcome::NotFound => bail!(\"precompiled node archive not found (404)\"),\n        }\n    }\n\n    async fn install_compiling(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        opts: &BuildOpts,\n    ) -> Result<()> {\n        debug!(\"{:?}: we will fetch the source and compile\", self);\n        let tarball_name = &opts.source_tarball_name;\n        if let Err(err) = self\n            .fetch_tarball(\n                ctx,\n                tv,\n                ctx.pr.as_ref(),\n                &opts.source_tarball_url,\n                &opts.source_tarball_path,\n                &opts.version,\n            )\n            .await\n        {\n            if let Some(reqwest_err) = err.root_cause().downcast_ref::<reqwest::Error>()\n                && reqwest_err.status() == Some(reqwest::StatusCode::NOT_FOUND)\n                && let Ok(Some(msg)) = self\n                    .suggest_available_flavors(&opts.version, &Settings::get())\n                    .await\n            {\n                return Err(eyre::eyre!(\"{err}\\n{msg}\"));\n            }\n            return Err(err);\n        }\n        ctx.pr.next_operation();\n        ctx.pr.set_message(format!(\"extract {tarball_name}\"));\n        file::remove_all(&opts.build_dir)?;\n        file::untar(\n            &opts.source_tarball_path,\n            opts.build_dir.parent().unwrap(),\n            &TarOptions {\n                pr: Some(ctx.pr.as_ref()),\n                ..TarOptions::new(TarFormat::TarGz)\n            },\n        )?;\n        self.exec_configure(ctx, opts)?;\n        self.exec_make(ctx, opts)?;\n        self.exec_make_install(ctx, opts)?;\n        Ok(())\n    }\n\n    async fn fetch_tarball(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n        pr: &dyn SingleReport,\n        url: &Url,\n        local: &Path,\n        version: &str,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let tarball_name = local.file_name().unwrap().to_string_lossy().to_string();\n        if local.exists() {\n            pr.set_message(format!(\"using previously downloaded {tarball_name}\"));\n        } else {\n            pr.set_message(format!(\"download {tarball_name}\"));\n            HTTP.download_file(url.clone(), local, Some(pr)).await?;\n        }\n        ctx.pr.next_operation();\n        let platform_info = tv\n            .lock_platforms\n            .entry(self.get_platform_key())\n            .or_default();\n        platform_info.url = Some(url.to_string());\n        if settings.node.verify && platform_info.checksum.is_none() {\n            platform_info.checksum = Some(self.get_checksum(ctx, local, version).await?);\n        }\n        self.verify_checksum(ctx, tv, local)?;\n        Ok(())\n    }\n\n    fn sh<'a>(&self, ctx: &'a InstallContext, opts: &BuildOpts) -> eyre::Result<CmdLineRunner<'a>> {\n        let settings = Settings::get();\n        let mut cmd = CmdLineRunner::new(\"sh\")\n            .prepend_path(opts.path.clone())?\n            .with_pr(ctx.pr.as_ref())\n            .current_dir(&opts.build_dir)\n            .arg(\"-c\");\n        if let Some(cflags) = settings.node.cflags() {\n            cmd = cmd.env(\"CFLAGS\", cflags);\n        }\n        Ok(cmd)\n    }\n\n    fn exec_configure(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> {\n        self.sh(ctx, opts)?.arg(&opts.configure_cmd).execute()\n    }\n    fn exec_make(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> {\n        self.sh(ctx, opts)?.arg(&opts.make_cmd).execute()\n    }\n    fn exec_make_install(&self, ctx: &InstallContext, opts: &BuildOpts) -> Result<()> {\n        self.sh(ctx, opts)?.arg(&opts.make_install_cmd).execute()\n    }\n\n    async fn get_checksum(\n        &self,\n        ctx: &InstallContext,\n        tarball: &Path,\n        version: &str,\n    ) -> Result<String> {\n        let tarball_name = tarball.file_name().unwrap().to_string_lossy().to_string();\n        let shasums_file = tarball.parent().unwrap().join(\"SHASUMS256.txt\");\n        HTTP.download_file(\n            self.shasums_url(version)?,\n            &shasums_file,\n            Some(ctx.pr.as_ref()),\n        )\n        .await?;\n        if Settings::get().node.gpg_verify != Some(false) && version.starts_with(\"2\") {\n            self.verify_with_gpg(ctx, &shasums_file, version).await?;\n        }\n        let shasums = file::read_to_string(&shasums_file)?;\n        let shasums = hash::parse_shasums(&shasums);\n        let shasum = shasums.get(&tarball_name).unwrap();\n        Ok(format!(\"sha256:{shasum}\"))\n    }\n\n    async fn verify_with_gpg(\n        &self,\n        ctx: &InstallContext,\n        shasums_file: &Path,\n        v: &str,\n    ) -> Result<()> {\n        if file::which_non_pristine(\"gpg\").is_none() && Settings::get().node.gpg_verify.is_none() {\n            warn!(\"gpg not found, skipping verification\");\n            return Ok(());\n        }\n        let sig_file = shasums_file.with_extension(\"asc\");\n        let sig_url = format!(\"{}.sig\", self.shasums_url(v)?);\n        if let Err(e) = HTTP\n            .download_file(sig_url, &sig_file, Some(ctx.pr.as_ref()))\n            .await\n        {\n            if matches!(http::error_code(&e), Some(404)) {\n                warn!(\"gpg signature not found, skipping verification\");\n                return Ok(());\n            }\n            return Err(e);\n        }\n        gpg::add_keys_node(ctx)?;\n        CmdLineRunner::new(\"gpg\")\n            .arg(\"--quiet\")\n            .arg(\"--trust-model\")\n            .arg(\"always\")\n            .arg(\"--verify\")\n            .arg(sig_file)\n            .arg(shasums_file)\n            .with_pr(ctx.pr.as_ref())\n            .execute()?;\n        Ok(())\n    }\n\n    fn node_path(&self, tv: &ToolVersion) -> PathBuf {\n        if cfg!(windows) {\n            tv.install_path().join(\"node.exe\")\n        } else {\n            tv.install_path().join(\"bin\").join(\"node\")\n        }\n    }\n\n    fn npm_path(&self, tv: &ToolVersion) -> PathBuf {\n        if cfg!(windows) {\n            tv.install_path().join(\"npm.cmd\")\n        } else {\n            tv.install_path().join(\"bin\").join(\"npm\")\n        }\n    }\n\n    fn corepack_path(&self, tv: &ToolVersion) -> PathBuf {\n        if cfg!(windows) {\n            tv.install_path().join(\"corepack.cmd\")\n        } else {\n            tv.install_path().join(\"bin\").join(\"corepack\")\n        }\n    }\n\n    async fn install_default_packages(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let default_packages_file = settings.node.default_packages_file();\n        let body = file::read_to_string(&default_packages_file).unwrap_or_default();\n        for package in body.lines() {\n            let package = package.split('#').next().unwrap_or_default().trim();\n            if package.is_empty() {\n                continue;\n            }\n            pr.set_message(format!(\"install default package: {package}\"));\n            let npm = self.npm_path(tv);\n            CmdLineRunner::new(npm)\n                .with_pr(pr)\n                .arg(\"install\")\n                .arg(\"--global\")\n                .arg(package)\n                .envs(config.env().await?)\n                .env(&*env::PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n                .execute()?;\n        }\n        Ok(())\n    }\n\n    fn install_npm_shim(&self, tv: &ToolVersion) -> Result<()> {\n        file::remove_file(self.npm_path(tv)).ok();\n        file::write(self.npm_path(tv), include_str!(\"assets/node_npm_shim\"))?;\n        file::make_executable(self.npm_path(tv))?;\n        Ok(())\n    }\n\n    fn enable_default_corepack_shims(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<()> {\n        pr.set_message(\"enable corepack shims\".into());\n        let corepack = self.corepack_path(tv);\n        CmdLineRunner::new(corepack)\n            .with_pr(pr)\n            .arg(\"enable\")\n            .env(&*env::PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n            .execute()?;\n        Ok(())\n    }\n\n    async fn test_node(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        pr.set_message(\"node -v\".into());\n        CmdLineRunner::new(self.node_path(tv))\n            .with_pr(pr)\n            .arg(\"-v\")\n            .envs(config.env().await?)\n            .execute()\n    }\n\n    async fn test_npm(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        pr.set_message(\"npm -v\".into());\n        CmdLineRunner::new(self.npm_path(tv))\n            .with_pr(pr)\n            .arg(\"-v\")\n            .envs(config.env().await?)\n            .env(&*env::PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n            .execute()\n    }\n\n    fn shasums_url(&self, v: &str) -> Result<Url> {\n        // let url = MISE_NODE_MIRROR_URL.join(&format!(\"v{v}/SHASUMS256.txt.asc\"))?;\n        let settings = Settings::get();\n        let url = settings\n            .node\n            .mirror_url()\n            .join(&format!(\"v{v}/SHASUMS256.txt\"))?;\n        Ok(url)\n    }\n\n    async fn suggest_available_flavors(\n        &self,\n        v: &str,\n        settings: &Settings,\n    ) -> Result<Option<String>> {\n        let base = settings.node.mirror_url();\n        // If using default mirror, we don't need to suggest anything as it's likely a real 404\n        if base.to_string() == DEFAULT_NODE_MIRROR_URL {\n            return Ok(None);\n        }\n\n        let versions: Vec<NodeVersion> = HTTP_FETCH\n            .json(base.join(\"index.json\")?)\n            .await\n            .unwrap_or_default();\n\n        if let Some(version) = versions.iter().find(|nv| {\n            nv.version == format!(\"v{v}\") || nv.version == v || nv.version == format!(\"v{v}.\")\n        }) {\n            let os = os();\n            let arch = arch(settings);\n            let candidates: Vec<&String> = version\n                .files\n                .iter()\n                .filter(|f| f.starts_with(&format!(\"{os}-{arch}-\")))\n                .collect();\n\n            if !candidates.is_empty() {\n                let mut msg = format!(\"Could not find node@{v} with the current settings.\\n\");\n                msg.push_str(&format!(\n                    \"However, the following flavors are available on the mirror for {os}-{arch}:\\n\"\n                ));\n                for candidate in candidates {\n                    // Extract flavor from \"linux-x64-musl\" -> \"musl\"\n                    // format is {os}-{arch}-{flavor}\n                    let prefix = format!(\"{os}-{arch}-\");\n                    if let Some(flavor) = candidate.strip_prefix(&prefix) {\n                        msg.push_str(&format!(\"  - {flavor}\\n\"));\n                    } else {\n                        msg.push_str(&format!(\"  - {candidate} (unknown format)\\n\"));\n                    }\n                }\n                msg.push_str(\"\\nYou can try setting the flavor using:\\n\");\n                msg.push_str(\"  mise settings set node.flavor <flavor>\\n\");\n                return Ok(Some(msg));\n            } else {\n                // Fallback: list all files for that version if no arch match\n                let mut msg = format!(\"Could not find node@{v} for {os}-{arch}.\\n\");\n                msg.push_str(\"Available files for this version on the mirror:\\n\");\n                for file in &version.files {\n                    msg.push_str(&format!(\"  - {file}\\n\"));\n                }\n                return Ok(Some(msg));\n            }\n        }\n        Ok(None)\n    }\n}\n\n#[async_trait]\nimpl Backend for NodePlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        let mut features = vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }];\n\n        // GPG verification is available for Node.js v20+ when gpg is installed\n        if Settings::get().node.gpg_verify != Some(false) {\n            features.push(SecurityFeature::Gpg);\n        }\n\n        features\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let settings = Settings::get();\n        let base = settings.node.mirror_url();\n        let versions = HTTP_FETCH\n            .json::<Vec<NodeVersion>, _>(base.join(\"index.json\")?)\n            .await?\n            .into_iter()\n            .filter(|v| {\n                if let Some(flavor) = &settings.node.flavor {\n                    v.files\n                        .iter()\n                        .any(|f| f == &format!(\"{}-{}-{}\", os(), arch(&settings), flavor))\n                } else {\n                    true\n                }\n            })\n            .map(|v| {\n                let version = if regex!(r\"^v\\d+\\.\").is_match(&v.version) {\n                    v.version.strip_prefix('v').unwrap().to_string()\n                } else {\n                    v.version\n                };\n                VersionInfo {\n                    version,\n                    created_at: v.date,\n                    ..Default::default()\n                }\n            })\n            .rev()\n            .collect();\n        Ok(versions)\n    }\n\n    fn get_aliases(&self) -> Result<BTreeMap<String, String>> {\n        let aliases = [\n            (\"lts/argon\", \"4\"),\n            (\"lts/boron\", \"6\"),\n            (\"lts/carbon\", \"8\"),\n            (\"lts/dubnium\", \"10\"),\n            (\"lts/erbium\", \"12\"),\n            (\"lts/fermium\", \"14\"),\n            (\"lts/gallium\", \"16\"),\n            (\"lts/hydrogen\", \"18\"),\n            (\"lts/iron\", \"20\"),\n            (\"lts/jod\", \"22\"),\n            (\"lts/krypton\", \"24\"),\n            (\"lts-argon\", \"4\"),\n            (\"lts-boron\", \"6\"),\n            (\"lts-carbon\", \"8\"),\n            (\"lts-dubnium\", \"10\"),\n            (\"lts-erbium\", \"12\"),\n            (\"lts-fermium\", \"14\"),\n            (\"lts-gallium\", \"16\"),\n            (\"lts-hydrogen\", \"18\"),\n            (\"lts-iron\", \"20\"),\n            (\"lts-jod\", \"22\"),\n            (\"lts-krypton\", \"24\"),\n            (\"lts\", \"24\"),\n        ]\n        .into_iter()\n        .map(|(k, v)| (k.to_string(), v.to_string()))\n        .collect();\n        Ok(aliases)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\n            \".node-version\".into(),\n            \".nvmrc\".into(),\n            \"package.json\".into(),\n        ])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let contents = file::read_to_string(path)?;\n        let body = normalize_idiomatic_contents(&contents);\n\n        let versions = body\n            .lines()\n            .map(|line| {\n                let mut version = line.trim().strip_prefix('v').unwrap_or(line).to_string();\n                version = version.replace(\"lts/*\", \"lts\");\n                version\n            })\n            .collect();\n        Ok(versions)\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        ensure!(\n            tv.version != \"latest\",\n            \"version should not be 'latest' for node, something is wrong\"\n        );\n        let settings = Settings::get();\n        let opts = BuildOpts::new(ctx, &tv).await?;\n        trace!(\"node build opts: {:#?}\", opts);\n\n        if cfg!(windows) {\n            self.install_windows(ctx, &mut tv, &opts).await?;\n        } else if settings.node.compile == Some(true) {\n            self.install_compiling(ctx, &mut tv, &opts).await?;\n        } else {\n            self.install_precompiled(ctx, &mut tv, &opts).await?;\n        }\n        debug!(\"{:?}: checking installation is working as expected\", self);\n        self.test_node(&ctx.config, &tv, ctx.pr.as_ref()).await?;\n        if !cfg!(windows) {\n            self.install_npm_shim(&tv)?;\n        }\n        self.test_npm(&ctx.config, &tv, ctx.pr.as_ref()).await?;\n        if let Err(err) = self\n            .install_default_packages(&ctx.config, &tv, ctx.pr.as_ref())\n            .await\n        {\n            warn!(\"failed to install default npm packages: {err:#}\");\n        }\n        if settings.node.corepack && self.corepack_path(&tv).exists() {\n            self.enable_default_corepack_shims(&tv, ctx.pr.as_ref())?;\n        }\n\n        Ok(tv)\n    }\n\n    #[cfg(windows)]\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Vec<PathBuf>> {\n        Ok(vec![tv.install_path()])\n    }\n\n    fn get_remote_version_cache(&self) -> Arc<Mutex<VersionCacheManager>> {\n        static CACHE: OnceLock<Arc<Mutex<VersionCacheManager>>> = OnceLock::new();\n        CACHE\n            .get_or_init(|| {\n                let settings = Settings::get();\n                Mutex::new(\n                    CacheManagerBuilder::new(\n                        self.ba().cache_path.join(\"remote_versions.msgpack.z\"),\n                    )\n                    .with_fresh_duration(settings.fetch_remote_versions_cache())\n                    .with_cache_key(settings.node.mirror_url.clone().unwrap_or_default())\n                    .with_cache_key(settings.node.flavor.clone().unwrap_or_default())\n                    .build(),\n                )\n                .into()\n            })\n            .clone()\n    }\n\n    // ========== Lockfile Metadata Fetching Implementation ==========\n\n    async fn get_tarball_url(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<Option<String>> {\n        let version = &tv.version;\n        let settings = Settings::get();\n\n        // Build platform-specific filename like Node.js does\n        let slug = self.build_platform_slug(version, target);\n        let filename = if target.os_name() == \"windows\" {\n            format!(\"{slug}.zip\")\n        } else {\n            format!(\"{slug}.tar.gz\")\n        };\n\n        // Use Node.js mirror URL to construct download URL\n        let url = settings\n            .node\n            .mirror_url()\n            .join(&format!(\"v{version}/{filename}\"))\n            .map_err(|e| eyre::eyre!(\"Failed to construct Node.js download URL: {e}\"))?;\n\n        Ok(Some(url.to_string()))\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        _request: &ToolRequest,\n        target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let mut opts = BTreeMap::new();\n        let settings = Settings::get();\n        let is_current_platform = target.is_current();\n\n        // Only include compile option if true (non-default)\n        let compile = if is_current_platform {\n            settings.node.compile.unwrap_or(false)\n        } else {\n            false\n        };\n        if compile {\n            opts.insert(\"compile\".to_string(), \"true\".to_string());\n        }\n\n        // Flavor affects which binary variant is downloaded\n        // Apply to all platforms to avoid splitting lockfile entries (#8390)\n        if let Some(flavor) = settings.node.flavor.clone() {\n            opts.insert(\"flavor\".to_string(), flavor);\n        }\n\n        opts\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let version = &tv.version;\n        let settings = Settings::get();\n\n        // Build platform-specific filename\n        let slug = self.build_platform_slug(version, target);\n        let filename = if target.os_name() == \"windows\" {\n            format!(\"{slug}.zip\")\n        } else {\n            format!(\"{slug}.tar.gz\")\n        };\n\n        // Build download URL\n        let url = settings\n            .node\n            .mirror_url()\n            .join(&format!(\"v{version}/{filename}\"))\n            .map_err(|e| eyre::eyre!(\"Failed to construct Node.js download URL: {e}\"))?;\n\n        // Fetch SHASUMS256.txt to get checksum without downloading the tarball\n        let shasums_url = settings\n            .node\n            .mirror_url()\n            .join(&format!(\"v{version}/SHASUMS256.txt\"))?;\n        let checksum = fetch_checksum_from_shasums(shasums_url.as_str(), &filename).await;\n\n        Ok(PlatformInfo {\n            url: Some(url.to_string()),\n            checksum,\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n}\n\nimpl NodePlugin {\n    /// Map OS name from Platform to Node.js convention\n    fn map_os(os_name: &str) -> &str {\n        match os_name {\n            \"macos\" => \"darwin\",\n            \"linux\" => \"linux\",\n            \"windows\" => \"win\",\n            other => other,\n        }\n    }\n\n    /// Map arch name from Platform to Node.js convention\n    fn map_arch(arch_name: &str) -> &str {\n        match arch_name {\n            \"x86\" => \"x86\",\n            \"x64\" => \"x64\",\n            \"arm\" => \"armv7l\",\n            \"arm64\" => \"arm64\",\n            \"aarch64\" => \"arm64\",\n            \"loongarch64\" => \"loong64\",\n            \"riscv64\" => \"riscv64\",\n            other => other,\n        }\n    }\n\n    /// Build platform-specific slug for Node.js downloads\n    /// This mirrors the logic from BuildOpts::new() and slug() function\n    fn build_platform_slug(&self, version: &str, target: &PlatformTarget) -> String {\n        let settings = Settings::get();\n\n        let os = Self::map_os(target.os_name());\n        let arch = Self::map_arch(target.arch_name());\n\n        // Flavor (like \"glibc\") only applies to the current Linux platform\n        // Don't apply it to non-current platforms during cross-platform locking\n        if target.is_current()\n            && target.os_name() == \"linux\"\n            && let Some(flavor) = &settings.node.flavor\n        {\n            return format!(\"node-v{version}-{os}-{arch}-{flavor}\");\n        }\n        format!(\"node-v{version}-{os}-{arch}\")\n    }\n}\n\n#[derive(Debug)]\nstruct BuildOpts {\n    version: String,\n    path: Vec<PathBuf>,\n    install_path: PathBuf,\n    build_dir: PathBuf,\n    configure_cmd: String,\n    make_cmd: String,\n    make_install_cmd: String,\n    source_tarball_name: String,\n    source_tarball_path: PathBuf,\n    source_tarball_url: Url,\n    binary_tarball_name: String,\n    binary_tarball_path: PathBuf,\n    binary_tarball_url: Url,\n}\n\nimpl BuildOpts {\n    async fn new(ctx: &InstallContext, tv: &ToolVersion) -> Result<Self> {\n        let v = &tv.version;\n        let install_path = tv.install_path();\n        let source_tarball_name = format!(\"node-v{v}.tar.gz\");\n\n        let slug = slug(v);\n        #[cfg(windows)]\n        let binary_tarball_name = format!(\"{slug}.zip\");\n        #[cfg(not(windows))]\n        let binary_tarball_name = format!(\"{slug}.tar.gz\");\n\n        let settings = Settings::get();\n        Ok(Self {\n            version: v.clone(),\n            path: ctx.ts.list_paths(&ctx.config).await,\n            build_dir: env::MISE_TMP_DIR.join(format!(\"node-v{v}\")),\n            configure_cmd: settings.node.configure_cmd(&install_path),\n            make_cmd: settings.node.make_cmd(),\n            make_install_cmd: settings.node.make_install_cmd(),\n            source_tarball_path: tv.download_path().join(&source_tarball_name),\n            source_tarball_url: settings\n                .node\n                .mirror_url()\n                .join(&format!(\"v{v}/{source_tarball_name}\"))?,\n            source_tarball_name,\n            binary_tarball_path: tv.download_path().join(&binary_tarball_name),\n            binary_tarball_url: settings\n                .node\n                .mirror_url()\n                .join(&format!(\"v{v}/{binary_tarball_name}\"))?,\n            binary_tarball_name,\n            install_path,\n        })\n    }\n}\n\nfn os() -> &'static str {\n    NodePlugin::map_os(built_info::CFG_OS)\n}\n\nfn arch(settings: &Settings) -> &str {\n    let arch = settings.arch();\n    // Special handling for ARM with target features\n    if arch == \"arm\" && cfg!(target_feature = \"v6\") {\n        return \"armv6l\";\n    }\n    NodePlugin::map_arch(arch)\n}\n\nfn slug(v: &str) -> String {\n    let settings = Settings::get();\n    if let Some(flavor) = &settings.node.flavor {\n        format!(\"node-v{v}-{}-{}-{flavor}\", os(), arch(&settings))\n    } else {\n        format!(\"node-v{v}-{}-{}\", os(), arch(&settings))\n    }\n}\n\n#[derive(Debug, Deserialize)]\nstruct NodeVersion {\n    version: String,\n    date: Option<String>,\n    files: Vec<String>,\n}\n"
  },
  {
    "path": "src/plugins/core/python.rs",
    "content": "use crate::backend::platform_target::PlatformTarget;\nuse crate::backend::static_helpers::fetch_checksum_from_shasums;\nuse crate::backend::{Backend, VersionCacheManager, VersionInfo};\nuse crate::build_time::built_info;\nuse crate::cache::{CacheManager, CacheManagerBuilder};\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::file::{TarFormat, TarOptions, display_path};\nuse crate::git::{CloneOptions, Git};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lockfile::PlatformInfo;\nuse crate::toolset::{ToolRequest, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{Result, lock_file::LockFile};\nuse crate::{dirs, file, plugins, sysconfig};\nuse async_trait::async_trait;\nuse eyre::{bail, eyre};\nuse flate2::read::GzDecoder;\nuse itertools::Itertools;\nuse std::collections::BTreeMap;\nuse std::io::Read;\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::sync::{Arc, OnceLock};\nuse tokio::sync::Mutex;\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct PythonPlugin {\n    ba: Arc<BackendArg>,\n}\n\npub fn python_path(tv: &ToolVersion) -> PathBuf {\n    if cfg!(windows) {\n        tv.install_path().join(\"python.exe\")\n    } else {\n        tv.install_path().join(\"bin/python\")\n    }\n}\n\n/// Sort key for Python versions that handles miniconda's two versioning schemes correctly.\n///\n/// Miniconda has two formats:\n/// - Old format: `miniconda3-{conda_version}` (e.g., `miniconda3-3.16.0`, `miniconda3-4.7.12`)\n/// - New format: `miniconda3-{python_version}-{conda_version}` (e.g., `miniconda3-3.7-4.8.2`)\n///\n/// Returns a tuple for sorting: (distro_priority, prefix_order, is_not_latest, conda_version, python_version)\n/// distro_priority: 0 = other distros, 1 = miniconda, 2 = CPython (bare version numbers)\nfn python_version_sort_key(\n    version: &str,\n) -> (u8, u8, bool, Option<Versioning>, Option<Versioning>) {\n    // Check if this is a miniconda version and get prefix order\n    let (prefix_order, version_part) = if let Some(v) = version.strip_prefix(\"miniconda3-\") {\n        (2u8, v)\n    } else if let Some(v) = version.strip_prefix(\"miniconda2-\") {\n        (1u8, v)\n    } else if let Some(v) = version.strip_prefix(\"miniconda-\") {\n        (0u8, v)\n    } else {\n        // Not miniconda - put other distros first (0), CPython (digit-starting) last (2)\n        let starts_with_digit = regex!(r\"^\\d\").is_match(version);\n        return (if starts_with_digit { 2 } else { 0 }, 0, false, None, None);\n    };\n\n    // Handle \"latest\" specially - put first in each miniconda group\n    if version_part == \"latest\" {\n        return (1, prefix_order, false, None, None);\n    }\n\n    // Parse miniconda version: old format vs new format\n    // Old format has no dash in version part: \"3.16.0\"\n    // New format has dash separating python and conda: \"3.7-4.8.2\"\n    let (conda_version, python_version) = if let Some(dash_pos) = version_part.find('-') {\n        // New format: \"3.7-4.8.2\" -> python=3.7, conda=4.8.2\n        let python = &version_part[..dash_pos];\n        let conda = &version_part[dash_pos + 1..];\n        (Versioning::new(conda), Versioning::new(python))\n    } else {\n        // Old format: \"3.16.0\" -> conda=3.16.0, no python version\n        (Versioning::new(version_part), None)\n    };\n\n    (1, prefix_order, true, conda_version, python_version)\n}\n\nimpl PythonPlugin {\n    pub fn new() -> Self {\n        let ba = Arc::new(plugins::core::new_backend_arg(\"python\"));\n        Self { ba }\n    }\n\n    fn python_build_path(&self) -> PathBuf {\n        self.ba.cache_path.join(\"pyenv\")\n    }\n    fn python_build_bin(&self) -> PathBuf {\n        self.python_build_path()\n            .join(\"plugins/python-build/bin/python-build\")\n    }\n    fn lock_pyenv(&self) -> Result<fslock::LockFile> {\n        LockFile::new(&self.python_build_path())\n            .with_callback(|l| {\n                trace!(\"install_or_update_pyenv {}\", l.display());\n            })\n            .lock()\n    }\n    fn install_or_update_python_build(&self, ctx: Option<&InstallContext>) -> eyre::Result<()> {\n        ensure_not_windows()?;\n        let _lock = self.lock_pyenv();\n        if self.python_build_bin().exists() {\n            self.update_python_build()\n        } else {\n            self.install_python_build(ctx)\n        }\n    }\n    fn install_python_build(&self, ctx: Option<&InstallContext>) -> eyre::Result<()> {\n        if self.python_build_bin().exists() {\n            return Ok(());\n        }\n        let python_build_path = self.python_build_path();\n        debug!(\"Installing python-build to {}\", python_build_path.display());\n        file::remove_all(&python_build_path)?;\n        file::create_dir_all(self.python_build_path().parent().unwrap())?;\n        let git = Git::new(self.python_build_path());\n        let pr = ctx.map(|ctx| ctx.pr.as_ref());\n        let mut clone_options = CloneOptions::default();\n        if let Some(pr) = pr {\n            clone_options = clone_options.pr(pr);\n        }\n        git.clone(&Settings::get().python.pyenv_repo, clone_options)?;\n        Ok(())\n    }\n    fn update_python_build(&self) -> eyre::Result<()> {\n        // TODO: do not update if recently updated\n        debug!(\n            \"Updating python-build in {}\",\n            self.python_build_path().display()\n        );\n        let pyenv_path = self.python_build_path();\n        let git = Git::new(pyenv_path.clone());\n        match plugins::core::run_fetch_task_with_timeout(move || git.update(None)) {\n            Ok(_) => Ok(()),\n            Err(err) => {\n                warn!(\n                    \"failed to update python-build repo ({}), attempting self-repair by recloning\",\n                    err\n                );\n                // The cached pyenv repo can get corrupted (e.g. unable to read sha1 file).\n                // Repair by removing the cache and performing a fresh clone.\n                file::remove_all(&pyenv_path)?;\n                // Safe to reinstall without a context; progress reporting is optional here.\n                self.install_python_build(None)\n            }\n        }\n    }\n\n    async fn fetch_precompiled_remote_versions(\n        &self,\n    ) -> eyre::Result<&Vec<(String, String, String)>> {\n        static PRECOMPILED_CACHE: Lazy<CacheManager<Vec<(String, String, String)>>> =\n            Lazy::new(|| {\n                CacheManagerBuilder::new(dirs::CACHE.join(\"python\").join(\"precompiled.msgpack.z\"))\n                    .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n                    .with_cache_key(python_precompiled_platform())\n                    .build()\n            });\n        PRECOMPILED_CACHE\n            .get_or_try_init_async(async || {\n                let settings = Settings::get();\n                let url_path = python_precompiled_url_path(&settings);\n                let rsp = HTTP_FETCH\n                    .get_bytes(format!(\"https://mise-versions.jdx.dev/tools/{url_path}\"))\n                    .await?;\n                let mut decoder = GzDecoder::new(rsp.as_ref());\n                let mut raw = String::new();\n                decoder.read_to_string(&mut raw)?;\n                let platform = python_precompiled_platform();\n                let flavor = settings.python.precompiled_flavor.clone();\n                // order by version, whether it is a release candidate, date, and in the preferred order of install types\n                let rank = |v: &str, date: &str, name: &str| {\n                    let rc = if regex!(r\"rc\\d+$\").is_match(v) { 0 } else { 1 };\n                    let v = Versioning::new(v);\n                    let date = date.parse::<i64>().unwrap_or_default();\n                    let install_type = if let Some(ref flavor) = flavor {\n                        // When flavor is set, prefer exact match\n                        let name_without_ext = name.trim_end_matches(\".tar.gz\");\n                        if name_without_ext.ends_with(flavor.as_str()) {\n                            0\n                        } else {\n                            1\n                        }\n                    } else if name.contains(\"install_only_stripped\") {\n                        0\n                    } else if name.contains(\"install_only\") {\n                        1\n                    } else {\n                        2\n                    };\n                    (v, rc, -date, install_type)\n                };\n                let versions = raw\n                    .lines()\n                    .filter(|v| v.contains(&platform))\n                    .flat_map(|v| {\n                        // cpython-3.9.5+20210525 or cpython-3.9.5rc3+20210525\n                        regex!(r\"^cpython-(\\d+\\.\\d+\\.[\\da-z]+)\\+(\\d+).*\")\n                            .captures(v)\n                            .map(|caps| {\n                                (\n                                    caps[1].to_string(),\n                                    caps[2].to_string(),\n                                    caps[0].to_string(),\n                                )\n                            })\n                    })\n                    // multiple dates can have the same version, so sort by date and remove duplicates by unique\n                    .sorted_by_cached_key(|(v, date, name)| rank(v, date, name))\n                    .unique_by(|(v, _, _)| v.to_string())\n                    .collect_vec();\n                Ok(versions)\n            })\n            .await\n    }\n\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n    ) -> eyre::Result<()> {\n        let precompiled_versions = self.fetch_precompiled_remote_versions().await?;\n        let precompile_info = precompiled_versions\n            .iter()\n            .rev()\n            .find(|(v, _, _)| &tv.version == v);\n        let (tag, filename) = match precompile_info {\n            Some((_, tag, filename)) => (tag, filename),\n            None => {\n                if cfg!(windows) || Settings::get().python.compile == Some(false) {\n                    if !cfg!(windows) {\n                        hint!(\n                            \"python_compile\",\n                            \"To compile python from source, run\",\n                            \"mise settings python.compile=1\"\n                        );\n                    }\n                    let platform = python_precompiled_platform();\n                    bail!(\"no precompiled python found for {tv} on {platform}\");\n                }\n                let available = precompiled_versions.iter().map(|(v, _, _)| v).collect_vec();\n                if available.is_empty() {\n                    debug!(\"no precompiled python found for {}\", tv.version);\n                } else {\n                    warn!(\n                        \"no precompiled python found for {}, force mise to use a precompiled version with `mise settings set python.compile false`\",\n                        tv.version\n                    );\n                }\n                trace!(\n                    \"available precompiled versions: {}\",\n                    available.into_iter().join(\", \")\n                );\n                return self.install_compiled(ctx, tv).await;\n            }\n        };\n\n        if cfg!(unix) {\n            hint!(\n                \"python_precompiled\",\n                \"installing precompiled python from astral-sh/python-build-standalone\\n\\\n                if you experience issues with this python (e.g.: running poetry), switch to python-build by running\",\n                \"mise settings python.compile=1\"\n            );\n        }\n\n        let url = format!(\n            \"https://github.com/astral-sh/python-build-standalone/releases/download/{tag}/{filename}\"\n        );\n        let filename = url.split('/').next_back().unwrap();\n        let install = tv.install_path();\n        let download = tv.download_path();\n        let tarball_path = download.join(filename);\n\n        ctx.pr.set_message(format!(\"download {filename}\"));\n        HTTP.download_file(&url, &tarball_path, Some(ctx.pr.as_ref()))\n            .await?;\n\n        {\n            let platform_key = self.get_platform_key();\n            let pi = tv.lock_platforms.entry(platform_key).or_default();\n            pi.url = Some(url.clone());\n        }\n        self.verify_checksum(ctx, tv, &tarball_path)?;\n\n        file::remove_all(&install)?;\n        file::untar(\n            &tarball_path,\n            &install,\n            &TarOptions {\n                strip_components: 1,\n                pr: Some(ctx.pr.as_ref()),\n                ..TarOptions::new(TarFormat::from_file_name(filename))\n            },\n        )?;\n        if !install.join(\"bin\").exists() {\n            // debug builds of indygreg binaries have a different structure\n            for entry in file::ls(&install.join(\"install\"))? {\n                let filename = entry.file_name().unwrap();\n                file::remove_all(install.join(filename))?;\n                file::rename(&entry, install.join(filename))?;\n            }\n        }\n\n        let re_digits = regex!(r\"\\d+\");\n        let version_parts = tv.version.split('.').collect_vec();\n        let major = re_digits\n            .find(version_parts[0])\n            .and_then(|m| m.as_str().parse().ok());\n        let minor = re_digits\n            .find(version_parts[1])\n            .and_then(|m| m.as_str().parse().ok());\n        let suffix = version_parts\n            .get(2)\n            .map(|s| re_digits.replace(s, \"\").to_string());\n        if cfg!(unix) {\n            if let (Some(major), Some(minor), Some(suffix)) = (major, minor, suffix) {\n                if tv.request.options().get(\"patch_sysconfig\") != Some(\"false\") {\n                    sysconfig::update_sysconfig(&install, major, minor, &suffix)?;\n                }\n            } else {\n                debug!(\"failed to update sysconfig with version {}\", tv.version);\n            }\n        }\n\n        if !install.join(\"bin\").join(\"python\").exists() {\n            #[cfg(unix)]\n            file::make_symlink(&install.join(\"bin/python3\"), &install.join(\"bin/python\"))?;\n        }\n\n        Ok(())\n    }\n\n    async fn install_compiled(&self, ctx: &InstallContext, tv: &ToolVersion) -> eyre::Result<()> {\n        self.install_or_update_python_build(Some(ctx))?;\n        if matches!(&tv.request, ToolRequest::Ref { .. }) {\n            return Err(eyre!(\"Ref versions not supported for python\"));\n        }\n        ctx.pr.set_message(\"python-build\".into());\n        let mut cmd = CmdLineRunner::new(self.python_build_bin())\n            .with_pr(ctx.pr.as_ref())\n            .arg(tv.version.as_str())\n            .arg(tv.install_path())\n            .env(\"PIP_REQUIRE_VIRTUALENV\", \"false\")\n            .envs(ctx.config.env().await?);\n        if Settings::get().verbose {\n            cmd = cmd.arg(\"--verbose\");\n        }\n        if let Some(patch_url) = &Settings::get().python.patch_url {\n            ctx.pr\n                .set_message(format!(\"with patch file from: {patch_url}\"));\n            let patch = HTTP.get_text(patch_url).await?;\n            cmd = cmd.arg(\"--patch\").stdin_string(patch)\n        }\n        if let Some(patches_dir) = &Settings::get().python.patches_directory {\n            let patch_file = patches_dir.join(format!(\"{}.patch\", &tv.version));\n            if patch_file.exists() {\n                ctx.pr\n                    .set_message(format!(\"with patch file: {}\", patch_file.display()));\n                let contents = file::read_to_string(&patch_file)?;\n                cmd = cmd.arg(\"--patch\").stdin_string(contents);\n            } else {\n                warn!(\"patch file not found: {}\", patch_file.display());\n            }\n        }\n        cmd.execute()?;\n        Ok(())\n    }\n\n    async fn install_default_packages(\n        &self,\n        config: &Arc<Config>,\n        packages_file: &Path,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> eyre::Result<()> {\n        if !packages_file.exists() {\n            return Ok(());\n        }\n        pr.set_message(\"install default packages\".into());\n        CmdLineRunner::new(tv.install_path().join(\"bin/python\"))\n            .with_pr(pr)\n            .arg(\"-m\")\n            .arg(\"pip\")\n            .arg(\"install\")\n            .arg(\"--upgrade\")\n            .arg(\"-r\")\n            .arg(packages_file)\n            .env(\"PIP_REQUIRE_VIRTUALENV\", \"false\")\n            .envs(config.env().await?)\n            .execute()\n    }\n\n    async fn get_virtualenv(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Option<PathBuf>> {\n        if let Some(virtualenv) = tv.request.options().get(\"virtualenv\") {\n            if !Settings::get().experimental {\n                warn!(\n                    \"please enable experimental mode with `mise settings experimental=true` \\\n                    to use python virtualenv activation\"\n                );\n            }\n            let mut virtualenv: PathBuf = file::replace_path(Path::new(virtualenv));\n            if !virtualenv.is_absolute() {\n                // TODO: use the path of the config file that specified python, not the top one like this\n                if let Some(project_root) = &config.project_root {\n                    virtualenv = project_root.join(virtualenv);\n                }\n            }\n            if !virtualenv.exists() {\n                warn!(\n                    \"no venv found at: {p}\\n\\n\\\n                    To create a virtualenv manually, run:\\n\\\n                    python -m venv {p}\",\n                    p = display_path(&virtualenv)\n                );\n                return Ok(None);\n            }\n            // TODO: enable when it is more reliable\n            // self.check_venv_python(&virtualenv, tv)?;\n            Ok(Some(virtualenv))\n        } else {\n            Ok(None)\n        }\n    }\n\n    // fn check_venv_python(&self, virtualenv: &Path, tv: &ToolVersion) -> eyre::Result<()> {\n    //     let symlink = virtualenv.join(\"bin/python\");\n    //     let target = python_path(tv);\n    //     let symlink_target = symlink.read_link().unwrap_or_default();\n    //     ensure!(\n    //         symlink_target == target,\n    //         \"expected venv {} to point to {}.\\nTry deleting the venv at {}.\",\n    //         display_path(&symlink),\n    //         display_path(&target),\n    //         display_path(virtualenv)\n    //     );\n    //     Ok(())\n    // }\n\n    async fn test_python(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> eyre::Result<()> {\n        pr.set_message(\"python --version\".into());\n        CmdLineRunner::new(python_path(tv))\n            .with_pr(pr)\n            .arg(\"--version\")\n            .envs(config.env().await?)\n            .execute()\n    }\n\n    /// Fetch the best precompiled release for a specific version and platform target.\n    /// Unlike `fetch_precompiled_remote_versions` which uses compile-time cfg!() macros,\n    /// this takes a PlatformTarget to support cross-platform lockfile generation.\n    /// Respects precompiled_arch, precompiled_os, and precompiled_flavor settings\n    /// when the target matches the current platform.\n    async fn fetch_precompiled_for_target(\n        &self,\n        version: &str,\n        target: &PlatformTarget,\n    ) -> eyre::Result<Option<(String, String)>> {\n        let settings = Settings::get();\n\n        // Use settings-aware arch/os for the current platform,\n        // target-based defaults for other platforms\n        let (arch, os) = if target.is_current() {\n            (python_arch(&settings).to_string(), python_os(&settings))\n        } else {\n            (\n                python_arch_for_target(target).to_string(),\n                python_os_for_target(target).to_string(),\n            )\n        };\n\n        let platform = format!(\"{arch}-{os}\");\n        let url_path = format!(\"python-precompiled-{arch}-{os}.gz\");\n        let rsp = HTTP_FETCH\n            .get_bytes(format!(\"https://mise-versions.jdx.dev/tools/{url_path}\"))\n            .await?;\n        let mut decoder = GzDecoder::new(rsp.as_ref());\n        let mut raw = String::new();\n        decoder.read_to_string(&mut raw)?;\n\n        let flavor = settings.python.precompiled_flavor.clone();\n\n        // Find all entries matching this version, then pick the best one\n        let result = raw\n            .lines()\n            .filter(|v| v.contains(&platform))\n            .flat_map(|v| {\n                regex!(r\"^cpython-(\\d+\\.\\d+\\.[\\da-z]+)\\+(\\d+).*\")\n                    .captures(v)\n                    .map(|caps| {\n                        (\n                            caps[1].to_string(),\n                            caps[2].to_string(),\n                            caps[0].to_string(),\n                        )\n                    })\n            })\n            .filter(|(v, _, _)| v == version)\n            .min_by_key(|(_, date, name)| {\n                let install_type = if let Some(ref flavor) = flavor {\n                    // When flavor is set, prefer exact match\n                    let name_without_ext = name.trim_end_matches(\".tar.gz\");\n                    if name_without_ext.ends_with(flavor.as_str()) {\n                        0\n                    } else {\n                        1\n                    }\n                } else {\n                    // Default: prefer install_only_stripped > install_only > other\n                    if name.contains(\"install_only_stripped\") {\n                        0\n                    } else if name.contains(\"install_only\") {\n                        1\n                    } else {\n                        2\n                    }\n                };\n                let date = date.parse::<i64>().unwrap_or_default();\n                (install_type, -date)\n            })\n            .map(|(_, tag, filename)| (tag, filename));\n        Ok(result)\n    }\n}\n\n#[async_trait]\nimpl Backend for PythonPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> eyre::Result<Vec<VersionInfo>> {\n        if cfg!(windows) || Settings::get().python.compile == Some(false) {\n            Ok(self\n                .fetch_precompiled_remote_versions()\n                .await?\n                .iter()\n                .map(|(v, _, _)| VersionInfo {\n                    version: v.clone(),\n                    ..Default::default()\n                })\n                .collect())\n        } else {\n            self.install_or_update_python_build(None)?;\n            let python_build_bin = self.python_build_bin();\n            let python_build_str = python_build_bin.to_string_lossy().to_string();\n            plugins::core::run_fetch_task_with_timeout_async(async move || {\n                let output = crate::cmd::cmd_read_async_inherited_env(\n                    &python_build_str,\n                    &[\"--definitions\"],\n                    std::iter::empty::<(&str, &std::ffi::OsStr)>(),\n                )\n                .await?;\n                let versions = output\n                    .split('\\n')\n                    // remove free-threaded pythons like 3.13t and 3.14t-dev\n                    .filter(|s| !regex!(r\"\\dt(-dev)?$\").is_match(s))\n                    .map(|s| VersionInfo {\n                        version: s.to_string(),\n                        ..Default::default()\n                    })\n                    .sorted_by_cached_key(|v| python_version_sort_key(&v.version))\n                    .collect();\n                Ok(versions)\n            })\n            .await\n        }\n    }\n\n    async fn _idiomatic_filenames(&self) -> eyre::Result<Vec<String>> {\n        Ok(vec![\n            \".python-version\".to_string(),\n            \".python-versions\".to_string(),\n        ])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        if cfg!(windows) || Settings::get().python.compile != Some(true) {\n            self.install_precompiled(ctx, &mut tv).await?;\n        } else {\n            self.install_compiled(ctx, &tv).await?;\n        }\n        self.test_python(&ctx.config, &tv, ctx.pr.as_ref()).await?;\n        if let Err(e) = self.get_virtualenv(&ctx.config, &tv).await {\n            warn!(\"failed to get virtualenv: {e:#}\");\n        }\n        if let Some(default_file) = &Settings::get().python.default_packages_file {\n            let default_file = file::replace_path(default_file);\n            if let Err(err) = self\n                .install_default_packages(&ctx.config, &default_file, &tv, ctx.pr.as_ref())\n                .await\n            {\n                warn!(\"failed to install default python packages: {err:#}\");\n            }\n        }\n        Ok(tv)\n    }\n\n    #[cfg(windows)]\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> eyre::Result<Vec<PathBuf>> {\n        Ok(vec![tv.install_path()])\n    }\n\n    async fn exec_env(\n        &self,\n        config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let mut hm = BTreeMap::new();\n        match self.get_virtualenv(config, tv).await {\n            Err(e) => warn!(\"failed to get virtualenv: {e}\"),\n            Ok(Some(virtualenv)) => {\n                let bin = virtualenv.join(\"bin\");\n                hm.insert(\"VIRTUAL_ENV\".into(), virtualenv.to_string_lossy().into());\n                hm.insert(\"MISE_ADD_PATH\".into(), bin.to_string_lossy().into());\n            }\n            Ok(None) => {}\n        };\n        Ok(hm)\n    }\n\n    fn get_remote_version_cache(&self) -> Arc<Mutex<VersionCacheManager>> {\n        static CACHE: OnceLock<Arc<Mutex<VersionCacheManager>>> = OnceLock::new();\n        CACHE\n            .get_or_init(|| {\n                Arc::new(Mutex::new(\n                    CacheManagerBuilder::new(\n                        self.ba().cache_path.join(\"remote_versions.msgpack.z\"),\n                    )\n                    .with_fresh_duration(Settings::get().fetch_remote_versions_cache())\n                    .with_cache_key((Settings::get().python.compile == Some(false)).to_string())\n                    .build(),\n                ))\n            })\n            .clone()\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        _request: &ToolRequest,\n        target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let mut opts = BTreeMap::new();\n        let settings = Settings::get();\n        let is_current_platform = target.is_current();\n\n        // Only include compile option if true (non-default)\n        let compile = if is_current_platform {\n            settings.python.compile.unwrap_or(false)\n        } else {\n            false\n        };\n        if compile {\n            opts.insert(\"compile\".to_string(), \"true\".to_string());\n        }\n\n        // Include precompiled options for all platforms to avoid splitting\n        // lockfile entries between host and non-host platforms (#8390)\n        if !compile {\n            if let Some(arch) = settings.python.precompiled_arch.clone() {\n                opts.insert(\"precompiled_arch\".to_string(), arch);\n            }\n            if let Some(os) = settings.python.precompiled_os.clone() {\n                opts.insert(\"precompiled_os\".to_string(), os);\n            }\n            if let Some(flavor) = settings.python.precompiled_flavor.clone() {\n                opts.insert(\"precompiled_flavor\".to_string(), flavor);\n            }\n        }\n\n        opts\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let version = &tv.version;\n\n        // Look up the precompiled release for this version and target platform\n        let Some((tag, filename)) = self.fetch_precompiled_for_target(version, target).await?\n        else {\n            return Ok(PlatformInfo::default());\n        };\n\n        let url = format!(\n            \"https://github.com/astral-sh/python-build-standalone/releases/download/{tag}/{filename}\"\n        );\n\n        // Fetch SHA256SUMS from the release to get the checksum\n        let shasums_url = format!(\n            \"https://github.com/astral-sh/python-build-standalone/releases/download/{tag}/SHA256SUMS\"\n        );\n        let checksum = fetch_checksum_from_shasums(&shasums_url, &filename).await;\n\n        Ok(PlatformInfo {\n            url: Some(url),\n            checksum,\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        })\n    }\n}\n\nfn python_precompiled_url_path(settings: &Settings) -> String {\n    if cfg!(windows) || cfg!(linux) || cfg!(macos) {\n        format!(\n            \"python-precompiled-{}-{}.gz\",\n            python_arch(settings),\n            python_os(settings)\n        )\n    } else {\n        \"python-precompiled.gz\".into()\n    }\n}\n\nfn python_os(settings: &Settings) -> String {\n    if let Some(os) = &settings.python.precompiled_os {\n        return os.clone();\n    }\n    if cfg!(windows) {\n        \"pc-windows-msvc\".into()\n    } else if cfg!(target_os = \"macos\") {\n        \"apple-darwin\".into()\n    } else {\n        [\"unknown\", built_info::CFG_OS, built_info::CFG_ENV]\n            .iter()\n            .filter(|s| !s.is_empty())\n            .join(\"-\")\n    }\n}\n\nfn python_arch(settings: &Settings) -> &str {\n    if let Some(arch) = &settings.python.precompiled_arch {\n        return arch.as_str();\n    }\n    let arch = match settings.arch() {\n        \"x64\" => \"x86_64\",\n        \"arm64\" => \"aarch64\",\n        other => other,\n    };\n    if cfg!(windows) {\n        \"x86_64\"\n    } else if cfg!(linux) && arch == \"x86_64\" {\n        if cfg!(target_feature = \"avx512f\") {\n            \"x86_64_v4\"\n        } else if cfg!(target_feature = \"avx2\") {\n            \"x86_64_v3\"\n        } else if cfg!(target_feature = \"sse4.1\") {\n            \"x86_64_v2\"\n        } else {\n            \"x86_64\"\n        }\n    } else {\n        arch\n    }\n}\n\nfn python_precompiled_platform() -> String {\n    let settings = Settings::get();\n    let os = python_os(&settings);\n    let arch = python_arch(&settings);\n    if let Some(flavor) = &settings.python.precompiled_flavor {\n        format!(\"{arch}-{os}-{flavor}\")\n    } else {\n        format!(\"{arch}-{os}\")\n    }\n}\n\n/// Map a PlatformTarget OS to the python-build-standalone OS string.\nfn python_os_for_target(target: &PlatformTarget) -> &'static str {\n    match target.os_name() {\n        \"macos\" => \"apple-darwin\",\n        \"windows\" => \"pc-windows-msvc\",\n        _ => \"unknown-linux-gnu\",\n    }\n}\n\n/// Map a PlatformTarget arch to the python-build-standalone arch string.\nfn python_arch_for_target(target: &PlatformTarget) -> &'static str {\n    match target.arch_name() {\n        \"arm64\" => \"aarch64\",\n        _ => \"x86_64\",\n    }\n}\n\nfn ensure_not_windows() -> eyre::Result<()> {\n    if cfg!(windows) {\n        bail!(\n            \"python can not currently be compiled on windows with core:python, use vfox:python instead\"\n        );\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "src/plugins/core/ruby.rs",
    "content": "use std::collections::{BTreeMap, HashMap};\nuse std::env::temp_dir;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse async_trait::async_trait;\nuse eyre::{Result, WrapErr, eyre};\nuse itertools::Itertools;\nuse xx::regex;\n\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::backend::{Backend, VersionInfo, normalize_idiomatic_contents};\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::duration::DAILY;\nuse crate::env::{self, PATH_KEY};\nuse crate::git::{CloneOptions, Git};\nuse crate::github::{self, GithubRelease};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lock_file::LockFile;\nuse crate::lockfile::{PlatformInfo, ProvenanceType};\nuse crate::plugins::PluginSource;\nuse crate::toolset::{ToolRequest, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{file, hash, plugins, timeout};\n\nconst RUBY_INDEX_URL: &str = \"https://cache.ruby-lang.org/pub/ruby/index.txt\";\nconst ATTESTATION_HELP: &str = \"To disable attestation verification, set MISE_RUBY_GITHUB_ATTESTATIONS=false\\n\\\n    or add `ruby.github_attestations = false` to your mise config\";\n\n#[derive(Debug)]\npub struct RubyPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl RubyPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"ruby\")),\n        }\n    }\n\n    fn ruby_build_path(&self) -> PathBuf {\n        self.ba.cache_path.join(\"ruby-build\")\n    }\n    fn ruby_install_path(&self) -> PathBuf {\n        self.ba.cache_path.join(\"ruby-install\")\n    }\n\n    fn ruby_build_bin(&self) -> PathBuf {\n        self.ruby_build_path().join(\"bin/ruby-build\")\n    }\n\n    fn ruby_install_bin(&self) -> PathBuf {\n        self.ruby_install_path().join(\"bin/ruby-install\")\n    }\n\n    fn lock_build_tool(&self) -> Result<fslock::LockFile> {\n        let settings = Settings::get();\n        let build_tool_path = if settings.ruby.ruby_install {\n            self.ruby_install_bin()\n        } else {\n            self.ruby_build_bin()\n        };\n        LockFile::new(&build_tool_path)\n            .with_callback(|l| {\n                trace!(\"install_or_update_ruby_build_tool {}\", l.display());\n            })\n            .lock()\n    }\n\n    async fn update_build_tool(&self, ctx: Option<&InstallContext>) -> Result<()> {\n        let pr = ctx.map(|ctx| ctx.pr.as_ref());\n        if Settings::get().ruby.ruby_install {\n            self.update_ruby_install(pr)\n                .await\n                .wrap_err(\"failed to update ruby-install\")\n        } else {\n            self.update_ruby_build(pr)\n                .await\n                .wrap_err(\"failed to update ruby-build\")\n        }\n    }\n\n    async fn install_ruby_build(&self, pr: Option<&dyn SingleReport>) -> Result<()> {\n        debug!(\n            \"Installing ruby-build to {}\",\n            self.ruby_build_path().display()\n        );\n        let settings = Settings::get();\n        let tmp = self\n            .prepare_source_in_tmp(&settings.ruby.ruby_build_repo, pr, \"mise-ruby-build\")\n            .await?;\n\n        cmd!(\"sh\", \"install.sh\")\n            .env(\"PREFIX\", self.ruby_build_path())\n            .dir(&tmp)\n            .run()?;\n        file::remove_all(&tmp)?;\n        Ok(())\n    }\n    async fn update_ruby_build(&self, pr: Option<&dyn SingleReport>) -> Result<()> {\n        let _lock = self.lock_build_tool();\n        if self.ruby_build_bin().exists() {\n            let cur = self.ruby_build_version()?;\n            let latest = self.latest_ruby_build_version().await;\n            match (cur, latest) {\n                // ruby-build is up-to-date\n                (cur, Ok(latest)) if cur == latest => return Ok(()),\n                // ruby-build is not up-to-date\n                (_cur, Ok(_latest)) => {}\n                // error getting latest ruby-build version (usually github rate limit)\n                (_cur, Err(err)) => warn!(\"failed to get latest ruby-build version: {}\", err),\n            }\n        }\n        debug!(\n            \"Updating ruby-build in {}\",\n            self.ruby_build_path().display()\n        );\n        file::remove_all(self.ruby_build_path())?;\n        self.install_ruby_build(pr).await?;\n        Ok(())\n    }\n\n    async fn install_ruby_install(&self, pr: Option<&dyn SingleReport>) -> Result<()> {\n        debug!(\n            \"Installing ruby-install to {}\",\n            self.ruby_install_path().display()\n        );\n        let settings = Settings::get();\n        let tmp = self\n            .prepare_source_in_tmp(&settings.ruby.ruby_install_repo, pr, \"mise-ruby-install\")\n            .await?;\n        cmd!(\"make\", \"install\")\n            .env(\"PREFIX\", self.ruby_install_path())\n            .dir(&tmp)\n            .stdout_to_stderr()\n            .run()?;\n        file::remove_all(&tmp)?;\n        Ok(())\n    }\n    async fn update_ruby_install(&self, pr: Option<&dyn SingleReport>) -> Result<()> {\n        let _lock = self.lock_build_tool();\n        let ruby_install_path = self.ruby_install_path();\n        if !ruby_install_path.exists() {\n            self.install_ruby_install(pr).await?;\n        }\n        if self.ruby_install_recently_updated()? {\n            return Ok(());\n        }\n        debug!(\"Updating ruby-install in {}\", ruby_install_path.display());\n\n        plugins::core::run_fetch_task_with_timeout(move || {\n            cmd!(self.ruby_install_bin(), \"--update\")\n                .stdout_to_stderr()\n                .run()?;\n            file::touch_dir(&ruby_install_path)?;\n            Ok(())\n        })\n    }\n\n    fn ruby_install_recently_updated(&self) -> Result<bool> {\n        let updated_at = file::modified_duration(&self.ruby_install_path())?;\n        Ok(updated_at < DAILY)\n    }\n\n    async fn prepare_source_in_tmp(\n        &self,\n        repo: &str,\n        pr: Option<&dyn SingleReport>,\n        tmp_dir_name: &str,\n    ) -> Result<PathBuf> {\n        let tmp = temp_dir().join(tmp_dir_name);\n        file::remove_all(&tmp)?;\n        file::create_dir_all(tmp.parent().unwrap())?;\n        let source = PluginSource::parse(repo);\n        match source {\n            PluginSource::Zip { url } => {\n                let temp_archive = tmp.join(\"ruby.zip\");\n                HTTP.download_file(url, &temp_archive, pr).await?;\n\n                if let Some(pr) = pr {\n                    pr.set_message(\"extracting zip file\".to_string());\n                }\n\n                let strip_components =\n                    file::should_strip_components(&temp_archive, file::TarFormat::Zip)?;\n\n                file::unzip(\n                    &temp_archive,\n                    &tmp,\n                    &file::ZipOptions {\n                        strip_components: if strip_components { 1 } else { 0 },\n                    },\n                )?;\n            }\n            PluginSource::Git {\n                url: repo_url,\n                git_ref: _,\n            } => {\n                let git = Git::new(tmp.clone());\n                let mut clone_options = CloneOptions::default();\n                if let Some(pr) = pr {\n                    clone_options = clone_options.pr(pr);\n                }\n                git.clone(&repo_url, clone_options)?;\n            }\n        }\n        Ok(tmp)\n    }\n\n    fn gem_path(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin/gem\")\n    }\n\n    async fn install_default_gems(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let default_gems_file = file::replace_path(&settings.ruby.default_packages_file);\n        let body = file::read_to_string(&default_gems_file).unwrap_or_default();\n        for package in body.lines() {\n            let package = package.split('#').next().unwrap_or_default().trim();\n            if package.is_empty() {\n                continue;\n            }\n            pr.set_message(format!(\"install default gem: {package}\"));\n            let gem = self.gem_path(tv);\n            let mut cmd = CmdLineRunner::new(gem)\n                .with_pr(pr)\n                .arg(\"install\")\n                .envs(config.env().await?);\n            match package.split_once(' ') {\n                Some((name, \"--pre\")) => cmd = cmd.arg(name).arg(\"--pre\"),\n                Some((name, version)) => cmd = cmd.arg(name).arg(\"--version\").arg(version),\n                None => cmd = cmd.arg(package),\n            };\n            cmd.env(&*PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n                .execute()?;\n        }\n        Ok(())\n    }\n\n    fn ruby_build_version(&self) -> Result<String> {\n        let output = cmd!(self.ruby_build_bin(), \"--version\").read()?;\n        let re = regex!(r\"^ruby-build ([0-9.]+)\");\n        let caps = re.captures(&output).expect(\"ruby-build version regex\");\n        Ok(caps.get(1).unwrap().as_str().to_string())\n    }\n\n    async fn latest_ruby_build_version(&self) -> Result<String> {\n        let release: GithubRelease = HTTP_FETCH\n            .json(\"https://api.github.com/repos/rbenv/ruby-build/releases/latest\")\n            .await?;\n        Ok(release.tag_name.trim_start_matches('v').to_string())\n    }\n\n    fn install_rubygems_hook(&self, tv: &ToolVersion) -> Result<()> {\n        let site_ruby_path = tv.install_path().join(\"lib/ruby/site_ruby\");\n        let f = site_ruby_path.join(\"rubygems_plugin.rb\");\n        file::create_dir_all(site_ruby_path)?;\n        file::write(f, include_str!(\"assets/rubygems_plugin.rb\"))?;\n        Ok(())\n    }\n\n    async fn install_cmd<'a>(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &'a dyn SingleReport,\n    ) -> Result<CmdLineRunner<'a>> {\n        let settings = Settings::get();\n        let cmd = if settings.ruby.ruby_install {\n            CmdLineRunner::new(self.ruby_install_bin()).args(self.install_args_ruby_install(tv)?)\n        } else {\n            CmdLineRunner::new(self.ruby_build_bin())\n                .args(self.install_args_ruby_build(tv)?)\n                .stdin_string(self.fetch_patches().await?)\n        };\n        Ok(cmd.with_pr(pr).envs(config.env().await?))\n    }\n    fn install_args_ruby_build(&self, tv: &ToolVersion) -> Result<Vec<String>> {\n        let settings = Settings::get();\n        let mut args = vec![];\n        if self.verbose_install() {\n            args.push(\"--verbose\".into());\n        }\n        if settings.ruby.apply_patches.is_some() {\n            args.push(\"--patch\".into());\n        }\n        args.push(tv.version.clone());\n        args.push(tv.install_path().to_string_lossy().to_string());\n        if let Some(opts) = &settings.ruby.ruby_build_opts {\n            args.push(\"--\".into());\n            args.extend(shell_words::split(opts)?);\n        }\n        Ok(args)\n    }\n    fn install_args_ruby_install(&self, tv: &ToolVersion) -> Result<Vec<String>> {\n        let settings = Settings::get();\n        let mut args = vec![];\n        for patch in self.fetch_patch_sources() {\n            args.push(\"--patch\".into());\n            args.push(patch);\n        }\n        let (engine, version) = match tv.version.split_once('-') {\n            Some((engine, version)) => (engine, version),\n            None => (\"ruby\", tv.version.as_str()),\n        };\n        args.push(engine.into());\n        args.push(version.into());\n        args.push(\"--install-dir\".into());\n        args.push(tv.install_path().to_string_lossy().to_string());\n        if let Some(opts) = &settings.ruby.ruby_install_opts {\n            args.push(\"--\".into());\n            args.extend(shell_words::split(opts)?);\n        }\n        Ok(args)\n    }\n\n    fn verbose_install(&self) -> bool {\n        let settings = Settings::get();\n        let verbose_env = settings.ruby.verbose_install;\n        verbose_env == Some(true) || (settings.verbose && verbose_env != Some(false))\n    }\n\n    fn fetch_patch_sources(&self) -> Vec<String> {\n        let settings = Settings::get();\n        let patch_sources = settings.ruby.apply_patches.clone().unwrap_or_default();\n        patch_sources\n            .split('\\n')\n            .map(|s| s.to_string())\n            .filter(|s| !s.is_empty())\n            .collect()\n    }\n\n    async fn fetch_patches(&self) -> Result<String> {\n        let mut patches = vec![];\n        let re = regex!(r#\"^[Hh][Tt][Tt][Pp][Ss]?://\"#);\n        for f in &self.fetch_patch_sources() {\n            if re.is_match(f) {\n                patches.push(HTTP.get_text(f).await?);\n            } else {\n                patches.push(file::read_to_string(f)?);\n            }\n        }\n        Ok(patches.join(\"\\n\"))\n    }\n\n    /// Fetch Ruby source tarball info from cache.ruby-lang.org index\n    /// Returns (url, sha256) for the given version\n    async fn get_ruby_download_info(&self, version: &str) -> Result<Option<(String, String)>> {\n        // Only standard MRI Ruby versions are in the index (e.g., \"3.3.0\", not \"jruby-9.4.0\")\n        if !version.chars().next().is_some_and(|c| c.is_ascii_digit()) {\n            return Ok(None);\n        }\n\n        let index_text: String = HTTP_FETCH.get_text(RUBY_INDEX_URL).await?;\n\n        // Format: name\\turl\\tsha1\\tsha256\\tsha512\n        // Example: ruby-3.3.0\\thttps://cache.ruby-lang.org/pub/ruby/3.3/ruby-3.3.0.tar.gz\\t...\\t<sha256>\\t...\n        let target_name = format!(\"ruby-{version}\");\n        for line in index_text.lines().skip(1) {\n            // skip header\n            let parts: Vec<&str> = line.split('\\t').collect();\n            if parts.len() >= 4 {\n                let name = parts[0];\n                // Match exact version with .tar.gz (prefer over .tar.xz for compatibility)\n                if name == target_name {\n                    let url = parts[1];\n                    let sha256 = parts[3];\n                    if url.ends_with(\".tar.gz\") && !sha256.is_empty() {\n                        return Ok(Some((url.to_string(), format!(\"sha256:{sha256}\"))));\n                    }\n                }\n            }\n        }\n\n        Ok(None)\n    }\n\n    // ===== Precompiled Ruby support =====\n\n    /// Detect provenance type for precompiled Ruby binaries.\n    /// Records GithubAttestations based on settings and URL format without an API probe.\n    /// This assumes all releases from the configured precompiled source have attestations;\n    /// if a release lacks them, install will fail at verification time.\n    fn detect_precompiled_provenance(&self) -> Option<ProvenanceType> {\n        let settings = Settings::get();\n        let enabled = settings\n            .ruby\n            .github_attestations\n            .unwrap_or(settings.github_attestations);\n        if !enabled {\n            return None;\n        }\n        let source = &settings.ruby.precompiled_url;\n        // Custom URL templates aren't verified via GitHub attestation API\n        if source.contains(\"://\") {\n            return None;\n        }\n        // Must be a valid owner/repo format for GitHub attestation verification\n        if !source.contains('/') {\n            return None;\n        }\n        Some(ProvenanceType::GithubAttestations)\n    }\n\n    /// Check if precompiled binaries should be tried\n    /// Precompiled if: explicit opt-in (compile=false), or experimental + not opted out\n    /// TODO(2026.8.0): make precompiled the default when compile is unset, remove this debug_assert\n    fn should_try_precompiled(&self) -> bool {\n        debug_assert!(\n            *crate::cli::version::V < versions::Versioning::new(\"2026.8.0\").unwrap(),\n            \"precompiled ruby should be the default now, update should_try_precompiled()\"\n        );\n        let settings = Settings::get();\n        settings.ruby.compile == Some(false)\n            || (settings.experimental && settings.ruby.compile.is_none())\n    }\n\n    /// Get platform identifier for precompiled binaries\n    /// Returns platform in jdx/ruby format: \"macos\", \"arm64_linux\", or \"x86_64_linux\"\n    fn precompiled_platform(&self) -> Option<String> {\n        let settings = Settings::get();\n\n        // Check for user overrides first\n        if let (Some(arch), Some(os)) = (\n            settings.ruby.precompiled_arch.as_deref(),\n            settings.ruby.precompiled_os.as_deref(),\n        ) {\n            return Some(format!(\"{}_{}\", arch, os));\n        }\n\n        // Auto-detect platform\n        if cfg!(target_os = \"macos\") {\n            // macOS only supports arm64 and uses \"macos\" without arch prefix\n            match settings.arch() {\n                \"arm64\" | \"aarch64\" => Some(\"macos\".to_string()),\n                _ => None,\n            }\n        } else if cfg!(target_os = \"linux\") {\n            // Linux uses arch_linux format\n            let arch = match settings.arch() {\n                \"arm64\" | \"aarch64\" => \"arm64\",\n                \"x64\" | \"x86_64\" => \"x86_64\",\n                _ => return None,\n            };\n            Some(format!(\"{}_linux\", arch))\n        } else {\n            None\n        }\n    }\n\n    /// Get platform identifier for a specific target (used for lockfiles)\n    /// Returns platform in jdx/ruby format: \"macos\", \"arm64_linux\", or \"x86_64_linux\"\n    fn precompiled_platform_for_target(&self, target: &PlatformTarget) -> Option<String> {\n        match target.os_name() {\n            \"macos\" => {\n                // macOS only supports arm64 and uses \"macos\" without arch prefix\n                match target.arch_name() {\n                    \"arm64\" | \"aarch64\" => Some(\"macos\".to_string()),\n                    _ => None,\n                }\n            }\n            \"linux\" => {\n                // Linux uses arch_linux format\n                let arch = match target.arch_name() {\n                    \"arm64\" | \"aarch64\" => \"arm64\",\n                    \"x64\" | \"x86_64\" => \"x86_64\",\n                    _ => return None,\n                };\n                Some(format!(\"{}_linux\", arch))\n            }\n            _ => None,\n        }\n    }\n\n    /// Render URL template with version and platform variables\n    fn render_precompiled_url(&self, template: &str, version: &str, platform: &str) -> String {\n        let (arch, os) = platform.split_once('_').unwrap_or((platform, \"\"));\n        template\n            .replace(\"{version}\", version)\n            .replace(\"{platform}\", platform)\n            .replace(\"{os}\", os)\n            .replace(\"{arch}\", arch)\n    }\n\n    /// Check if the system needs the no-YJIT variant (glibc < 2.35 on Linux).\n    /// YJIT builds from jdx/ruby require glibc 2.35+.\n    fn needs_no_yjit() -> bool {\n        match *crate::env::LINUX_GLIBC_VERSION {\n            Some((major, minor)) => major < 2 || (major == 2 && minor < 35),\n            None => false, // non-Linux or can't detect, assume modern system\n        }\n    }\n\n    /// Find precompiled asset from a GitHub repo's releases.\n    /// On Linux with glibc < 2.35, prefers the no-YJIT variant (.no_yjit.) which\n    /// targets glibc 2.17. Falls back to the standard build if no variant is found.\n    async fn find_precompiled_asset_in_repo(\n        &self,\n        repo: &str,\n        version: &str,\n        platform: &str,\n        prefer_no_yjit: bool,\n    ) -> Result<Option<(String, Option<String>)>> {\n        let release = match github::get_release(repo, version).await {\n            Ok(r) => r,\n            Err(err) => {\n                debug!(\"no precompiled ruby found for {version}: {err}\");\n                return Ok(None);\n            }\n        };\n        let standard_name = format!(\"ruby-{}.{}.tar.gz\", version, platform);\n        let no_yjit_name = format!(\"ruby-{}.{}.no_yjit.tar.gz\", version, platform);\n\n        if prefer_no_yjit {\n            debug!(\"glibc < 2.35 detected, preferring no-YJIT Ruby variant\");\n        }\n\n        let mut standard_asset = None;\n        let mut no_yjit_asset = None;\n\n        for asset in &release.assets {\n            if no_yjit_asset.is_none() && asset.name == no_yjit_name {\n                no_yjit_asset = Some((asset.browser_download_url.clone(), asset.digest.clone()));\n            } else if standard_asset.is_none() && asset.name == standard_name {\n                standard_asset = Some((asset.browser_download_url.clone(), asset.digest.clone()));\n            }\n        }\n\n        if prefer_no_yjit {\n            if no_yjit_asset.is_some() {\n                return Ok(no_yjit_asset);\n            }\n            debug!(\"no-YJIT variant not found, falling back to standard build\");\n        }\n        Ok(standard_asset)\n    }\n\n    /// Resolve precompiled binary URL and checksum for a given version and platform\n    async fn resolve_precompiled_url(\n        &self,\n        version: &str,\n        platform: &str,\n        prefer_no_yjit: bool,\n    ) -> Result<Option<(String, Option<String>)>> {\n        let settings = Settings::get();\n        let source = &settings.ruby.precompiled_url;\n\n        if source.contains(\"://\") {\n            // Full URL template - no checksum available\n            Ok(Some((\n                self.render_precompiled_url(source, version, platform),\n                None,\n            )))\n        } else {\n            // GitHub repo shorthand (default: \"jdx/ruby\")\n            self.find_precompiled_asset_in_repo(source, version, platform, prefer_no_yjit)\n                .await\n        }\n    }\n\n    /// Convert a Ruby GitHub tag name to a version string.\n    /// Ruby uses tags like \"v3_3_0\" for version \"3.3.0\"\n    fn tag_to_version(tag: &str) -> Option<String> {\n        // Ruby tags are in format v3_3_0, v3_3_0_preview1, etc.\n        let tag = tag.strip_prefix('v')?;\n        // Replace underscores with dots, but be careful with preview/rc suffixes\n        let re = regex!(r\"^(\\d+)_(\\d+)_(\\d+)(.*)$\");\n        if let Some(caps) = re.captures(tag) {\n            let major = &caps[1];\n            let minor = &caps[2];\n            let patch = &caps[3];\n            let suffix = &caps[4];\n            // Convert suffix like \"_preview1\" to \"-preview1\"\n            let suffix = suffix.replace('_', \"-\");\n            Some(format!(\"{major}.{minor}.{patch}{suffix}\"))\n        } else {\n            None\n        }\n    }\n\n    /// Fetch created_at timestamps for Ruby versions from GitHub releases\n    async fn fetch_ruby_release_dates(&self) -> HashMap<String, String> {\n        let mut dates = HashMap::new();\n        match github::list_releases(\"ruby/ruby\").await {\n            Ok(releases) => {\n                for release in releases {\n                    if let Some(version) = Self::tag_to_version(&release.tag_name) {\n                        dates.insert(version, release.created_at);\n                    }\n                }\n            }\n            Err(err) => {\n                debug!(\"Failed to fetch Ruby release dates: {err}\");\n            }\n        }\n        dates\n    }\n\n    /// Try to install from precompiled binary\n    /// Returns Ok(None) if no precompiled version is available for this version/platform\n    async fn install_precompiled(\n        &self,\n        ctx: &InstallContext,\n        tv: &mut ToolVersion,\n    ) -> Result<Option<ToolVersion>> {\n        let Some(platform) = self.precompiled_platform() else {\n            return Ok(None);\n        };\n\n        let Some((url, checksum)) = self\n            .resolve_precompiled_url(&tv.version, &platform, Self::needs_no_yjit())\n            .await?\n        else {\n            return Ok(None);\n        };\n\n        let filename = match url.rsplit('/').next() {\n            Some(name) if !name.is_empty() => name.to_string(),\n            _ => format!(\"ruby-{}.{}.tar.gz\", tv.version, platform),\n        };\n        let tarball_path = tv.download_path().join(&filename);\n\n        ctx.pr.set_message(format!(\"download {}\", filename));\n        HTTP.download_file(&url, &tarball_path, Some(ctx.pr.as_ref()))\n            .await?;\n\n        if let Some(hash_str) = checksum.as_ref().and_then(|c| c.strip_prefix(\"sha256:\")) {\n            ctx.pr.set_message(format!(\"checksum {}\", filename));\n            hash::ensure_checksum(&tarball_path, hash_str, Some(ctx.pr.as_ref()), \"sha256\")?;\n        }\n\n        // Check lockfile provenance expectation before verification\n        let platform_key = PlatformTarget::from_current().to_key();\n        let locked_provenance = tv\n            .lock_platforms\n            .get_mut(&platform_key)\n            .and_then(|pi| pi.provenance.take());\n\n        // Verify GitHub artifact attestations for precompiled binaries\n        // Returns Ok(true) if verified, Ok(false) if skipped, Err if failed\n        let verified = self\n            .verify_github_artifact_attestations(ctx, &tarball_path, &tv.version)\n            .await?;\n\n        // Record provenance only if verification actually succeeded (not skipped)\n        if verified {\n            let pi = tv.lock_platforms.entry(platform_key.clone()).or_default();\n            pi.provenance = Some(ProvenanceType::GithubAttestations);\n        }\n\n        // Enforce lockfile provenance\n        if let Some(ref expected) = locked_provenance {\n            let got = tv\n                .lock_platforms\n                .get(&platform_key)\n                .and_then(|pi| pi.provenance.as_ref());\n            if !got.is_some_and(|g| std::mem::discriminant(g) == std::mem::discriminant(expected)) {\n                let got_str = got\n                    .map(|g| g.to_string())\n                    .unwrap_or_else(|| \"no verification\".to_string());\n                return Err(eyre!(\n                    \"Lockfile requires {expected} provenance for {tv} but {got_str} was used. \\\n                     This may indicate a downgrade attack. Enable the corresponding verification setting \\\n                     or update the lockfile.\"\n                ));\n            }\n        }\n\n        ctx.pr.set_message(format!(\"extract {}\", filename));\n        let install_path = tv.install_path();\n        file::create_dir_all(&install_path)?;\n        file::untar(\n            &tarball_path,\n            &install_path,\n            &file::TarOptions {\n                strip_components: 1,\n                pr: Some(ctx.pr.as_ref()),\n                ..file::TarOptions::new(file::TarFormat::TarGz)\n            },\n        )?;\n\n        Ok(Some(tv.clone()))\n    }\n\n    /// Verify GitHub artifact attestations for precompiled Ruby binary\n    /// Returns Ok(true) if verification succeeds\n    /// Returns Ok(false) if verification was skipped (disabled or not applicable)\n    /// Returns Err if verification is enabled and fails\n    async fn verify_github_artifact_attestations(\n        &self,\n        ctx: &InstallContext,\n        tarball_path: &std::path::Path,\n        version: &str,\n    ) -> Result<bool> {\n        let settings = Settings::get();\n\n        // Check Ruby-specific setting, fall back to global\n        let enabled = settings\n            .ruby\n            .github_attestations\n            .unwrap_or(settings.github_attestations);\n        if !enabled {\n            debug!(\"GitHub artifact attestations verification disabled for Ruby\");\n            return Ok(false);\n        }\n\n        let source = &settings.ruby.precompiled_url;\n\n        // Skip for custom URL templates (not GitHub repos)\n        if source.contains(\"://\") {\n            debug!(\"Skipping GitHub artifact attestation verification for custom URL template\");\n            return Ok(false);\n        }\n\n        let (owner, repo) = match source.split_once('/') {\n            Some((o, r)) => (o, r),\n            None => {\n                warn!(\"Invalid precompiled_url format: {}\", source);\n                return Ok(false);\n            }\n        };\n\n        ctx.pr\n            .set_message(\"verify GitHub artifact attestations\".to_string());\n\n        match sigstore_verification::verify_github_attestation(\n            tarball_path,\n            owner,\n            repo,\n            env::GITHUB_TOKEN.as_deref(),\n            None, // Accept any workflow from repo\n        )\n        .await\n        {\n            Ok(true) => {\n                ctx.pr\n                    .set_message(\"✓ GitHub artifact attestations verified\".to_string());\n                debug!(\n                    \"GitHub artifact attestations verified successfully for ruby@{}\",\n                    version\n                );\n                Ok(true)\n            }\n            Ok(false) => Err(eyre!(\n                \"GitHub artifact attestations verification failed for ruby@{version}\\n{ATTESTATION_HELP}\"\n            )),\n            Err(sigstore_verification::AttestationError::NoAttestations) => Err(eyre!(\n                \"No GitHub artifact attestations found for ruby@{version}\\n{ATTESTATION_HELP}\"\n            )),\n            Err(e) => Err(eyre!(\n                \"GitHub artifact attestations verification failed for ruby@{version}: {e}\\n{ATTESTATION_HELP}\"\n            )),\n        }\n    }\n}\n\n#[async_trait]\nimpl Backend for RubyPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n        let settings = Settings::get();\n\n        let mut features = vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }];\n\n        // Report GitHub artifact attestations if enabled for precompiled binaries\n        let github_attestations_enabled = settings\n            .ruby\n            .github_attestations\n            .unwrap_or(settings.github_attestations);\n        if self.should_try_precompiled() && github_attestations_enabled {\n            features.push(SecurityFeature::GithubAttestations {\n                signer_workflow: None,\n            });\n        }\n\n        features\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        timeout::run_with_timeout_async(\n            async || {\n                if let Err(err) = self.update_build_tool(None).await {\n                    warn!(\"{err}\");\n                }\n\n                // Fetch Ruby release dates from GitHub in parallel with version list\n                let release_dates = self.fetch_ruby_release_dates().await;\n\n                let ruby_build_bin = self.ruby_build_bin();\n                let ruby_build_str = ruby_build_bin.to_string_lossy().to_string();\n                let output = crate::cmd::cmd_read_async_inherited_env(\n                    &ruby_build_str,\n                    &[\"--definitions\"],\n                    std::iter::empty::<(&str, &std::ffi::OsStr)>(),\n                )\n                .await?;\n                let versions: Vec<String> = output\n                    .split('\\n')\n                    .sorted_by_cached_key(|s| regex!(r#\"^\\d\"#).is_match(s)) // show matz ruby first\n                    .map(|s| s.to_string())\n                    .collect();\n\n                // Map versions to VersionInfo with created_at timestamps\n                let version_infos = versions\n                    .into_iter()\n                    .map(|version| {\n                        let created_at = release_dates.get(&version).cloned();\n                        VersionInfo {\n                            version,\n                            created_at,\n                            ..Default::default()\n                        }\n                    })\n                    .collect();\n\n                Ok(version_infos)\n            },\n            Settings::get().fetch_remote_versions_timeout(),\n        )\n        .await\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".ruby-version\".into(), \"Gemfile\".into()])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let v = match path.file_name() {\n            Some(name) if name == \"Gemfile\" => parse_gemfile(&file::read_to_string(path)?),\n            _ => {\n                // .ruby-version\n                let body = normalize_idiomatic_contents(&file::read_to_string(path)?);\n                body.trim()\n                    .trim_start_matches(\"ruby-\")\n                    .trim_start_matches('v')\n                    .to_string()\n            }\n        };\n        if v.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(vec![v])\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        let mut tv = tv;\n        let settings = Settings::get();\n        if settings.ruby.compile.is_none() && !settings.experimental {\n            warn_once!(\n                \"precompiled ruby will be the default in 2026.8.0.\\n\\\n                 To use precompiled binaries now: mise settings ruby.compile=false\\n\\\n                 To keep compiling from source: mise settings ruby.compile=true\"\n            );\n        }\n\n        // Try precompiled if compile=false or experimental + not opted out\n        if self.should_try_precompiled()\n            && let Some(installed_tv) = self.install_precompiled(ctx, &mut tv).await?\n        {\n            hint!(\n                \"ruby_precompiled\",\n                \"installing precompiled ruby from jdx/ruby\\n\\\n                    if you experience issues, switch to ruby-build by running\",\n                \"mise settings ruby.compile=1\"\n            );\n            self.install_rubygems_hook(&installed_tv)?;\n            if let Err(err) = self\n                .install_default_gems(&ctx.config, &installed_tv, ctx.pr.as_ref())\n                .await\n            {\n                warn!(\"failed to install default ruby gems {err:#}\");\n            }\n            return Ok(installed_tv);\n        }\n        // No precompiled available, fall through to compile from source\n\n        // Compile from source\n        if let Err(err) = self.update_build_tool(Some(ctx)).await {\n            warn!(\"ruby build tool update error: {err:#}\");\n        }\n        ctx.pr.set_message(\"ruby-build\".into());\n        self.install_cmd(&ctx.config, &tv, ctx.pr.as_ref())\n            .await?\n            .execute()?;\n\n        self.install_rubygems_hook(&tv)?;\n        if let Err(err) = self\n            .install_default_gems(&ctx.config, &tv, ctx.pr.as_ref())\n            .await\n        {\n            warn!(\"failed to install default ruby gems {err:#}\");\n        }\n        Ok(tv)\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        _tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let map = BTreeMap::new();\n        // No modification to RUBYLIB\n        Ok(map)\n    }\n\n    fn resolve_lockfile_options(\n        &self,\n        _request: &ToolRequest,\n        target: &PlatformTarget,\n    ) -> BTreeMap<String, String> {\n        let mut opts = BTreeMap::new();\n        let settings = Settings::get();\n        let is_current_platform = target.is_current();\n\n        // Ruby uses ruby-install vs ruby-build (ruby compiles from source either way)\n        // Only include if using non-default ruby-install tool\n        let ruby_install = if is_current_platform {\n            settings.ruby.ruby_install\n        } else {\n            false\n        };\n        if ruby_install {\n            opts.insert(\"ruby_install\".to_string(), \"true\".to_string());\n        }\n\n        opts\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        // Windows uses RubyInstaller2 binaries, not source tarballs\n        if target.os_name() == \"windows\" {\n            return super::ruby_common::resolve_rubyinstaller_lock_info(&tv.version).await;\n        }\n\n        // Precompiled binary info if enabled\n        if self.should_try_precompiled()\n            && let Some(platform) = self.precompiled_platform_for_target(target)\n            && let Some((url, checksum)) = self\n                .resolve_precompiled_url(&tv.version, &platform, false)\n                .await?\n        {\n            // Detect provenance for precompiled binaries\n            let provenance = self.detect_precompiled_provenance();\n            return Ok(PlatformInfo {\n                url: Some(url),\n                checksum,\n                provenance,\n                ..Default::default()\n            });\n        }\n\n        // Default: source tarball\n        match self.get_ruby_download_info(&tv.version).await? {\n            Some((url, checksum)) => Ok(PlatformInfo {\n                url: Some(url),\n                checksum: Some(checksum),\n                size: None,\n                url_api: None,\n                conda_deps: None,\n                ..Default::default()\n            }),\n            None => Ok(PlatformInfo::default()),\n        }\n    }\n}\n\nfn parse_gemfile(body: &str) -> String {\n    let v = body\n        .lines()\n        .find(|line| line.trim().starts_with(\"ruby \"))\n        .unwrap_or_default()\n        .trim()\n        .split('#')\n        .next()\n        .unwrap_or_default()\n        .replace(\"engine:\", \":engine =>\")\n        .replace(\"engine_version:\", \":engine_version =>\");\n    let v = regex!(r#\".*:engine *=> *['\"](?<engine>[^'\"]*).*:engine_version *=> *['\"](?<engine_version>[^'\"]*).*\"#).replace_all(&v, \"${engine_version}__ENGINE__${engine}\").to_string();\n    let v = regex!(r#\".*:engine_version *=> *['\"](?<engine_version>[^'\"]*).*:engine *=> *['\"](?<engine>[^'\"]*).*\"#).replace_all(&v, \"${engine_version}__ENGINE__${engine}\").to_string();\n    let v = regex!(r#\" *ruby *['\"]([^'\"]*).*\"#)\n        .replace_all(&v, \"$1\")\n        .to_string();\n    let v = regex!(r#\"^[^0-9]\"#).replace_all(&v, \"\").to_string();\n    let v = regex!(r#\"(.*)__ENGINE__(.*)\"#)\n        .replace_all(&v, \"$2-$1\")\n        .to_string();\n    // make sure it's like \"ruby-3.0.0\" or \"3.0.0\"\n    if !regex!(r\"^(\\w+-)?([0-9])(\\.[0-9])*$\").is_match(&v) {\n        return \"\".to_string();\n    }\n    v\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use indoc::indoc;\n    use pretty_assertions::assert_eq;\n\n    #[test]\n    fn test_tag_to_version() {\n        // Standard versions\n        assert_eq!(\n            RubyPlugin::tag_to_version(\"v3_3_0\"),\n            Some(\"3.3.0\".to_string())\n        );\n        assert_eq!(\n            RubyPlugin::tag_to_version(\"v3_2_2\"),\n            Some(\"3.2.2\".to_string())\n        );\n        assert_eq!(\n            RubyPlugin::tag_to_version(\"v2_7_8\"),\n            Some(\"2.7.8\".to_string())\n        );\n\n        // Preview and RC versions\n        assert_eq!(\n            RubyPlugin::tag_to_version(\"v3_3_0_preview1\"),\n            Some(\"3.3.0-preview1\".to_string())\n        );\n        assert_eq!(\n            RubyPlugin::tag_to_version(\"v3_3_0_rc1\"),\n            Some(\"3.3.0-rc1\".to_string())\n        );\n\n        // Invalid tags\n        assert_eq!(RubyPlugin::tag_to_version(\"3_3_0\"), None); // Missing 'v' prefix\n        assert_eq!(RubyPlugin::tag_to_version(\"v3_3\"), None); // Missing patch version\n        assert_eq!(RubyPlugin::tag_to_version(\"jruby-9.4.0\"), None); // Different format\n    }\n\n    #[test]\n    fn test_parse_gemfile() {\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '2.7.2'\n        \"#}),\n            \"2.7.2\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', engine: 'jruby', engine_version: \"1.6.7\"\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', :engine => 'jruby', :engine_version => '1.6.7'\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', :engine_version => '1.6.7', :engine => 'jruby'\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            source \"https://rubygems.org\"\n            ruby File.read(File.expand_path(\".ruby-version\", __dir__)).strip\n        \"#}),\n            \"\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/ruby_common.rs",
    "content": "use crate::github;\nuse crate::lockfile::PlatformInfo;\nuse eyre::Result;\n\nconst RUBYINSTALLER_REPO: &str = \"oneclick/rubyinstaller2\";\n\n/// Check if a Ruby version string is a standard MRI version (starts with a digit).\n/// Non-MRI engines like jruby, truffleruby, etc. have prefixed version strings.\npub fn is_mri_version(version: &str) -> bool {\n    version.chars().next().is_some_and(|c| c.is_ascii_digit())\n}\n\n/// Build the RubyInstaller2 release tag for a given MRI version.\npub fn rubyinstaller_tag(version: &str) -> String {\n    format!(\"RubyInstaller-{version}-1\")\n}\n\n/// Build the RubyInstaller2 asset filename for a given MRI version.\npub fn rubyinstaller_asset_name(version: &str) -> String {\n    // RubyInstaller2 only provides x64 builds\n    format!(\"rubyinstaller-{version}-1-x64.7z\")\n}\n\n/// Build the RubyInstaller2 download URL for a given MRI version.\npub fn rubyinstaller_url(version: &str) -> String {\n    let tag = rubyinstaller_tag(version);\n    let asset = rubyinstaller_asset_name(version);\n    format!(\"https://github.com/{RUBYINSTALLER_REPO}/releases/download/{tag}/{asset}\")\n}\n\n/// Resolve RubyInstaller2 binary URL and checksum from GitHub releases.\n/// Returns `Ok(PlatformInfo::default())` for non-MRI versions since\n/// RubyInstaller2 only distributes standard MRI Ruby.\npub async fn resolve_rubyinstaller_lock_info(version: &str) -> Result<PlatformInfo> {\n    if !is_mri_version(version) {\n        return Ok(PlatformInfo::default());\n    }\n\n    let tag = rubyinstaller_tag(version);\n    let asset_name = rubyinstaller_asset_name(version);\n\n    if let Ok(release) = github::get_release(RUBYINSTALLER_REPO, &tag).await\n        && let Some(asset) = release.assets.iter().find(|a| a.name == asset_name)\n    {\n        return Ok(PlatformInfo {\n            url: Some(asset.browser_download_url.clone()),\n            checksum: asset.digest.clone(),\n            size: None,\n            url_api: None,\n            conda_deps: None,\n            ..Default::default()\n        });\n    }\n\n    // Fallback: construct URL without checksum\n    Ok(PlatformInfo {\n        url: Some(rubyinstaller_url(version)),\n        checksum: None,\n        size: None,\n        url_api: None,\n        conda_deps: None,\n        ..Default::default()\n    })\n}\n"
  },
  {
    "path": "src/plugins/core/ruby_windows.rs",
    "content": "use std::{\n    collections::BTreeMap,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::normalize_idiomatic_contents;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::env::PATH_KEY;\nuse crate::github::GithubRelease;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::toolset::{ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{file, github, plugins};\nuse async_trait::async_trait;\nuse eyre::{Result, bail};\nuse itertools::Itertools;\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct RubyPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl RubyPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: plugins::core::new_backend_arg(\"ruby\").into(),\n        }\n    }\n\n    fn ruby_path(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(\"ruby.exe\")\n    }\n\n    fn gem_path(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(\"gem.cmd\")\n    }\n\n    async fn install_default_gems(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        let settings = Settings::get();\n        let default_gems_file = file::replace_path(&settings.ruby.default_packages_file);\n        let body = file::read_to_string(&default_gems_file).unwrap_or_default();\n        for package in body.lines() {\n            let package = package.split('#').next().unwrap_or_default().trim();\n            if package.is_empty() {\n                continue;\n            }\n            pr.set_message(format!(\"install default gem: {}\", package));\n            let gem = self.gem_path(tv);\n            let mut cmd = CmdLineRunner::new(gem)\n                .with_pr(pr)\n                .arg(\"install\")\n                .envs(config.env().await?);\n            match package.split_once(' ') {\n                Some((name, \"--pre\")) => cmd = cmd.arg(name).arg(\"--pre\"),\n                Some((name, version)) => cmd = cmd.arg(name).arg(\"--version\").arg(version),\n                None => cmd = cmd.arg(package),\n            };\n            cmd.env(&*PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n                .execute()?;\n        }\n        Ok(())\n    }\n\n    async fn test_ruby(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        pr.set_message(\"ruby -v\".into());\n        CmdLineRunner::new(self.ruby_path(tv))\n            .with_pr(pr)\n            .arg(\"-v\")\n            .envs(config.env().await?)\n            .execute()\n    }\n\n    async fn test_gem(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        pr: &dyn SingleReport,\n    ) -> Result<()> {\n        pr.set_message(\"gem -v\".into());\n        CmdLineRunner::new(self.gem_path(tv))\n            .with_pr(pr)\n            .arg(\"-v\")\n            .envs(config.env().await?)\n            .env(&*PATH_KEY, plugins::core::path_env_with_tv_path(tv)?)\n            .execute()\n    }\n\n    fn install_rubygems_hook(&self, tv: &ToolVersion) -> Result<()> {\n        let site_ruby_path = tv.install_path().join(\"lib/ruby/site_ruby\");\n        let f = site_ruby_path.join(\"rubygems_plugin.rb\");\n        file::create_dir_all(site_ruby_path)?;\n        file::write(f, include_str!(\"assets/rubygems_plugin.rb\"))?;\n        Ok(())\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let url = super::ruby_common::rubyinstaller_url(&tv.version);\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        pr.set_message(format!(\"downloading {filename}\"));\n        HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n\n        Ok(tarball_path)\n    }\n\n    async fn install(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        tarball_path: &Path,\n    ) -> Result<()> {\n        let arch = arch();\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        file::remove_all(tv.install_path())?;\n        file::un7z(tarball_path, &tv.download_path(), &Default::default())?;\n        file::rename(\n            tv.download_path()\n                .join(format!(\"rubyinstaller-{}-1-{arch}\", tv.version)),\n            tv.install_path(),\n        )?;\n        Ok(())\n    }\n\n    async fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        self.test_ruby(&ctx.config, tv, ctx.pr.as_ref()).await\n    }\n}\n\n#[async_trait]\nimpl Backend for RubyPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        // TODO: use windows set of versions\n        //  match self.core.fetch_remote_versions_from_mise() {\n        //      Ok(Some(versions)) => return Ok(versions),\n        //      Ok(None) => {}\n        //      Err(e) => warn!(\"failed to fetch remote versions: {}\", e),\n        //  }\n        let releases: Vec<GithubRelease> = github::list_releases(\"oneclick/rubyinstaller2\").await?;\n        let versions = releases\n            .into_iter()\n            .filter_map(|r| {\n                regex!(r\"RubyInstaller-([0-9.]+)-.*\")\n                    .replace(&r.tag_name, \"$1\")\n                    .parse::<String>()\n                    .ok()\n                    .map(|version| VersionInfo {\n                        version,\n                        created_at: Some(r.created_at),\n                        ..Default::default()\n                    })\n            })\n            .unique_by(|v| v.version.clone())\n            .sorted_by_cached_key(|v| (Versioning::new(&v.version), v.version.clone()))\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".ruby-version\".into(), \"Gemfile\".into()])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let v = match path.file_name() {\n            Some(name) if name == \"Gemfile\" => parse_gemfile(&file::read_to_string(path)?),\n            _ => {\n                // .ruby-version\n                let body = normalize_idiomatic_contents(&file::read_to_string(path)?);\n                body.trim()\n                    .trim_start_matches(\"ruby-\")\n                    .trim_start_matches('v')\n                    .to_string()\n            }\n        };\n        if v.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(vec![v])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> eyre::Result<ToolVersion> {\n        if !super::ruby_common::is_mri_version(&tv.version) {\n            bail!(\n                \"Ruby engine '{}' is not supported on Windows.\\n\\\n                 Only standard MRI Ruby versions can be installed via RubyInstaller2.\",\n                tv.version\n            );\n        }\n        let tarball = self.download(&tv, ctx.pr.as_ref()).await?;\n        self.verify_checksum(ctx, &mut tv, &tarball)?;\n        self.install(ctx, &tv, &tarball).await?;\n        self.verify(ctx, &tv).await?;\n        self.install_rubygems_hook(&tv)?;\n        self.test_gem(&ctx.config, &tv, ctx.pr.as_ref()).await?;\n        if let Err(err) = self\n            .install_default_gems(&ctx.config, &tv, ctx.pr.as_ref())\n            .await\n        {\n            warn!(\"failed to install default ruby gems {err:#}\");\n        }\n        Ok(tv)\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        _tv: &ToolVersion,\n    ) -> eyre::Result<BTreeMap<String, String>> {\n        let map = BTreeMap::new();\n        // No modification to RUBYLIB\n        Ok(map)\n    }\n}\n\nfn parse_gemfile(body: &str) -> String {\n    let v = body\n        .lines()\n        .find(|line| line.trim().starts_with(\"ruby \"))\n        .unwrap_or_default()\n        .trim()\n        .split('#')\n        .next()\n        .unwrap_or_default()\n        .replace(\"engine:\", \":engine =>\")\n        .replace(\"engine_version:\", \":engine_version =>\");\n    let v = regex!(r#\".*:engine *=> *['\"](?<engine>[^'\"]*).*:engine_version *=> *['\"](?<engine_version>[^'\"]*).*\"#).replace_all(&v, \"${engine_version}__ENGINE__${engine}\").to_string();\n    let v = regex!(r#\".*:engine_version *=> *['\"](?<engine_version>[^'\"]*).*:engine *=> *['\"](?<engine>[^'\"]*).*\"#).replace_all(&v, \"${engine_version}__ENGINE__${engine}\").to_string();\n    let v = regex!(r#\" *ruby *['\"]([^'\"]*).*\"#)\n        .replace_all(&v, \"$1\")\n        .to_string();\n    let v = regex!(r#\"^[^0-9]\"#).replace_all(&v, \"\").to_string();\n    let v = regex!(r#\"(.*)__ENGINE__(.*)\"#)\n        .replace_all(&v, \"$2-$1\")\n        .to_string();\n    // make sure it's like \"ruby-3.0.0\" or \"3.0.0\"\n    if !regex!(r\"^(\\w+-)?([0-9])(\\.[0-9])*$\").is_match(&v) {\n        return \"\".to_string();\n    }\n    v\n}\n\n#[allow(clippy::if_same_then_else)]\nfn arch() -> &'static str {\n    if cfg!(target_arch = \"aarch64\") {\n        \"x64\"\n    } else {\n        \"x64\"\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n    use indoc::indoc;\n    use pretty_assertions::assert_eq;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_list_versions_matching() {\n        let config = Config::get().await.unwrap();\n        let plugin = RubyPlugin::new();\n        assert!(\n            !plugin\n                .list_versions_matching(&config, \"3\")\n                .await\n                .unwrap()\n                .is_empty(),\n            \"versions for 3 should not be empty\"\n        );\n        assert!(\n            !plugin\n                .list_versions_matching(&config, \"truffleruby-24\")\n                .await\n                .unwrap()\n                .is_empty(),\n            \"versions for truffleruby-24 should not be empty\"\n        );\n        assert!(\n            !plugin\n                .list_versions_matching(&config, \"truffleruby+graalvm-24\")\n                .await\n                .unwrap()\n                .is_empty(),\n            \"versions for truffleruby+graalvm-24 should not be empty\"\n        );\n    }\n\n    #[test]\n    fn test_parse_gemfile() {\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '2.7.2'\n        \"#}),\n            \"2.7.2\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', engine: 'jruby', engine_version: \"1.6.7\"\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', :engine => 'jruby', :engine_version => '1.6.7'\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            ruby '1.9.3', :engine_version => '1.6.7', :engine => 'jruby'\n        \"#}),\n            \"jruby-1.6.7\"\n        );\n        assert_eq!(\n            parse_gemfile(indoc! {r#\"\n            source \"https://rubygems.org\"\n            ruby File.read(File.expand_path(\".ruby-version\", __dir__)).strip\n        \"#}),\n            \"\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/plugins/core/rust.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::build_time::TARGET;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolSource::IdiomaticVersionFile;\nuse crate::toolset::outdated_info::OutdatedInfo;\nuse crate::toolset::{ResolveOptions, ToolVersion, Toolset};\nuse crate::ui::progress_report::SingleReport;\nuse crate::{dirs, env, file, github, plugins};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct RustPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl RustPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: plugins::core::new_backend_arg(\"rust\").into(),\n        }\n    }\n\n    async fn setup_rustup(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        let settings = Settings::get();\n        if rustup_home().join(\"settings.toml\").exists() && cargo_bin().exists() {\n            return Ok(());\n        }\n        ctx.pr.set_message(\"Downloading rustup-init\".into());\n        HTTP.download_file(rustup_url(&settings), &rustup_path(), Some(ctx.pr.as_ref()))\n            .await?;\n        file::make_executable(rustup_path())?;\n        file::create_dir_all(rustup_home())?;\n        let ts = ctx.config.get_toolset().await?;\n        let mut cmd = CmdLineRunner::new(rustup_path())\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"--no-modify-path\")\n            .arg(\"--default-toolchain\")\n            .arg(\"none\")\n            .arg(\"-y\")\n            .envs(self.exec_env(&ctx.config, ts, tv).await?);\n        if let Some(host) = settings.rust.default_host.as_ref() {\n            cmd = cmd.arg(\"--default-host\").arg(host);\n        }\n        cmd.execute()?;\n        Ok(())\n    }\n\n    async fn test_rust(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(format!(\"{RUSTC_BIN} -V\"));\n        let ts = ctx.config.get_toolset().await?;\n        CmdLineRunner::new(RUSTC_BIN)\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"-V\")\n            .envs(self.exec_env(&ctx.config, ts, tv).await?)\n            .prepend_path(self.list_bin_paths(&ctx.config, tv).await?)?\n            .execute()\n    }\n\n    fn target_triple(&self, tv: &ToolVersion) -> String {\n        format!(\"{}-{}\", tv.version, TARGET)\n    }\n}\n\n#[async_trait]\nimpl Backend for RustPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    /// Rust uses rustup for installation, which handles its own downloads.\n    /// Lockfile URLs are not applicable since we don't download artifacts directly.\n    fn supports_lockfile_url(&self) -> bool {\n        false\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions: Vec<VersionInfo> = github::list_releases(\"rust-lang/rust\")\n            .await?\n            .into_iter()\n            .map(|r| VersionInfo {\n                release_url: Some(format!(\"https://releases.rs/docs/{}/\", r.tag_name)),\n                version: r.tag_name,\n                created_at: Some(r.created_at),\n                ..Default::default()\n            })\n            .rev()\n            .chain(vec![\n                // Special channels - these are rolling releases that should always be updated\n                VersionInfo {\n                    version: \"nightly\".into(),\n                    rolling: true,\n                    ..Default::default()\n                },\n                VersionInfo {\n                    version: \"beta\".into(),\n                    rolling: true,\n                    ..Default::default()\n                },\n                VersionInfo {\n                    version: \"stable\".into(),\n                    rolling: true,\n                    ..Default::default()\n                },\n            ])\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\"rust-toolchain.toml\".into()])\n    }\n\n    async fn _parse_idiomatic_file(&self, path: &Path) -> Result<Vec<String>> {\n        let rt = parse_idiomatic_file(path)?;\n        if rt.channel.is_empty() {\n            return Ok(vec![]);\n        }\n        Ok(vec![rt.channel])\n    }\n\n    async fn install_version_(&self, ctx: &InstallContext, tv: ToolVersion) -> Result<ToolVersion> {\n        self.setup_rustup(ctx, &tv).await?;\n        let ts = ctx.config.get_toolset().await?;\n\n        let (profile, components, targets) = get_args(&tv);\n\n        let mut cmd = CmdLineRunner::new(RUSTUP_BIN)\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"toolchain\")\n            .arg(\"install\")\n            .arg(&tv.version)\n            .opt_args(\"--component\", components)\n            .opt_args(\"--target\", targets)\n            .prepend_path(self.list_bin_paths(&ctx.config, &tv).await?)?\n            .envs(self.exec_env(&ctx.config, ts, &tv).await?);\n        if let Some(profile) = profile.as_ref() {\n            cmd = cmd.arg(\"--profile\").arg(profile);\n        }\n        cmd.execute()?;\n\n        file::remove_all(tv.install_path())?;\n        file::make_symlink(&cargo_home().join(\"bin\"), &tv.install_path())?;\n\n        self.test_rust(ctx, &tv).await?;\n\n        Ok(tv)\n    }\n\n    async fn uninstall_version_impl(\n        &self,\n        config: &Arc<Config>,\n        pr: &dyn SingleReport,\n        tv: &ToolVersion,\n    ) -> Result<()> {\n        let ts = config.get_toolset().await?;\n        let mut env = self.exec_env(config, ts, tv).await?;\n        env.remove(\"RUSTUP_TOOLCHAIN\");\n        CmdLineRunner::new(RUSTUP_BIN)\n            .with_pr(pr)\n            .arg(\"toolchain\")\n            .arg(\"uninstall\")\n            .arg(&tv.version)\n            .prepend_path(self.list_bin_paths(config, tv).await?)?\n            .envs(env)\n            .execute()\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        _tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        Ok(vec![cargo_bindir()])\n    }\n\n    async fn exec_env(\n        &self,\n        _config: &Arc<Config>,\n        _ts: &Toolset,\n        tv: &ToolVersion,\n    ) -> Result<BTreeMap<String, String>> {\n        let toolchain = tv.version.to_string();\n        Ok([\n            (\n                \"CARGO_HOME\".to_string(),\n                cargo_home().to_string_lossy().to_string(),\n            ),\n            (\n                \"RUSTUP_HOME\".to_string(),\n                rustup_home().to_string_lossy().to_string(),\n            ),\n            (\"RUSTUP_TOOLCHAIN\".to_string(), toolchain),\n        ]\n        .into())\n    }\n\n    async fn outdated_info(\n        &self,\n        config: &Arc<Config>,\n        tv: &ToolVersion,\n        bump: bool,\n        opts: &ResolveOptions,\n    ) -> Result<Option<OutdatedInfo>> {\n        let v_re = regex!(r#\"Update available : (.*) -> (.*)\"#);\n        if regex!(r\"(\\d+)\\.(\\d+)\\.(\\d+)\").is_match(&tv.version) {\n            let oi = OutdatedInfo::resolve(config, tv.clone(), bump, opts).await?;\n            Ok(oi)\n        } else {\n            let ts = config.get_toolset().await?;\n            let mut cmd =\n                cmd!(RUSTUP_BIN, \"check\").env(\"PATH\", self.path_env_for_cmd(config, tv).await?);\n            for (k, v) in self.exec_env(config, ts, tv).await? {\n                cmd = cmd.env(k, v);\n            }\n            let out = cmd.read()?;\n            for line in out.lines() {\n                if line.starts_with(&self.target_triple(tv))\n                    && let Some(_cap) = v_re.captures(line)\n                {\n                    // let requested = cap.get(1).unwrap().as_str().to_string();\n                    // let latest = cap.get(2).unwrap().as_str().to_string();\n                    let oi = OutdatedInfo::new(config, tv.clone(), tv.version.clone())?;\n                    return Ok(Some(oi));\n                }\n            }\n            Ok(None)\n        }\n    }\n}\n\n#[derive(Debug, Default)]\nstruct RustToolchain {\n    channel: String,\n    profile: Option<String>,\n    components: Option<Vec<String>>,\n    targets: Option<Vec<String>>,\n}\n\nfn get_args(tv: &ToolVersion) -> (Option<String>, Option<Vec<String>>, Option<Vec<String>>) {\n    let rt = if tv.request.source().is_idiomatic_version_file() {\n        match tv.request.source() {\n            IdiomaticVersionFile(path) => parse_idiomatic_file(path).ok(),\n            _ => None,\n        }\n    } else {\n        None\n    };\n\n    let get_tooloption = |name: &str| {\n        tv.request\n            .options()\n            .get(name)\n            .map(|c| c.split(',').map(|s| s.to_string()).collect())\n    };\n    let profile = rt\n        .as_ref()\n        .and_then(|rt| rt.profile.clone())\n        .or_else(|| tv.request.options().get(\"profile\").map(|s| s.to_string()));\n    let components = rt\n        .as_ref()\n        .and_then(|rt| rt.components.clone())\n        .or_else(|| get_tooloption(\"components\"));\n    let targets = rt\n        .as_ref()\n        .and_then(|rt| rt.targets.clone())\n        .or_else(|| get_tooloption(\"targets\"));\n\n    (profile, components, targets)\n}\n\nfn parse_idiomatic_file(path: &Path) -> Result<RustToolchain> {\n    let content = file::read_to_string(path)?;\n    let toml: toml::Value = toml::de::from_str(&content)?;\n    let mut rt = RustToolchain::default();\n    if let Some(toolchain) = toml.get(\"toolchain\") {\n        if let Some(channel) = toolchain.get(\"channel\") {\n            rt.channel = channel.as_str().unwrap().to_string();\n        }\n        if let Some(profile) = toolchain.get(\"profile\") {\n            rt.profile = Some(profile.as_str().unwrap().to_string());\n        }\n        if let Some(components) = toolchain.get(\"components\") {\n            let components = components\n                .as_array()\n                .unwrap()\n                .iter()\n                .map(|c| c.as_str().unwrap().to_string())\n                .collect::<Vec<_>>();\n            if !components.is_empty() {\n                rt.components = Some(components);\n            }\n        }\n        if let Some(targets) = toolchain.get(\"targets\") {\n            let targets = targets\n                .as_array()\n                .unwrap()\n                .iter()\n                .map(|c| c.as_str().unwrap().to_string())\n                .collect::<Vec<_>>();\n            if !targets.is_empty() {\n                rt.targets = Some(targets);\n            }\n        }\n    }\n    Ok(rt)\n}\n\n#[cfg(unix)]\nconst RUSTC_BIN: &str = \"rustc\";\n\n#[cfg(windows)]\nconst RUSTC_BIN: &str = \"rustc.exe\";\n\n#[cfg(unix)]\nconst RUSTUP_INIT_BIN: &str = \"rustup-init\";\n\n#[cfg(windows)]\nconst RUSTUP_INIT_BIN: &str = \"rustup-init.exe\";\n\n#[cfg(unix)]\nconst RUSTUP_BIN: &str = \"rustup\";\n\n#[cfg(windows)]\nconst RUSTUP_BIN: &str = \"rustup.exe\";\n\n#[cfg(unix)]\nconst CARGO_BIN: &str = \"cargo\";\n\n#[cfg(windows)]\nconst CARGO_BIN: &str = \"cargo.exe\";\n\n#[cfg(unix)]\nfn rustup_url(_settings: &Settings) -> String {\n    \"https://sh.rustup.rs\".to_string()\n}\n\n#[cfg(windows)]\nfn rustup_url(settings: &Settings) -> String {\n    let arch = match settings.arch() {\n        \"x64\" => \"x86_64\",\n        \"arm64\" => \"aarch64\",\n        other => other,\n    };\n    format!(\"https://win.rustup.rs/{arch}\")\n}\n\nfn rustup_path() -> PathBuf {\n    dirs::CACHE.join(\"rust\").join(RUSTUP_INIT_BIN)\n}\n\nfn rustup_home() -> PathBuf {\n    let path = Settings::get()\n        .rust\n        .rustup_home\n        .clone()\n        .or(env::var_path(\"RUSTUP_HOME\"))\n        .unwrap_or(dirs::HOME.join(\".rustup\"));\n    if path.is_relative() {\n        std::env::current_dir()\n            .map(|cwd| cwd.join(&path))\n            .unwrap_or(path)\n    } else {\n        path\n    }\n}\n\nfn cargo_home() -> PathBuf {\n    let path = Settings::get()\n        .rust\n        .cargo_home\n        .clone()\n        .or(env::var_path(\"CARGO_HOME\"))\n        .unwrap_or(dirs::HOME.join(\".cargo\"));\n    if path.is_relative() {\n        std::env::current_dir()\n            .map(|cwd| cwd.join(&path))\n            .unwrap_or(path)\n    } else {\n        path\n    }\n}\n\nfn cargo_bin() -> PathBuf {\n    cargo_bindir().join(CARGO_BIN)\n}\nfn cargo_bindir() -> PathBuf {\n    cargo_home().join(\"bin\")\n}\n"
  },
  {
    "path": "src/plugins/core/swift.rs",
    "content": "use crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::Settings;\nuse crate::http::HTTP;\nuse crate::install_context::InstallContext;\nuse crate::toolset::ToolVersion;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{backend::Backend, backend::VersionInfo, config::Config};\nuse crate::{file, github, gpg, plugins};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse std::{\n    path::{Path, PathBuf},\n    sync::Arc,\n};\nuse tempfile::tempdir_in;\n\n#[derive(Debug)]\npub struct SwiftPlugin {\n    ba: Arc<BackendArg>,\n}\n\nimpl SwiftPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"swift\")),\n        }\n    }\n\n    fn swift_bin(&self, tv: &ToolVersion) -> PathBuf {\n        tv.install_path().join(\"bin\").join(swift_bin_name())\n    }\n\n    fn test_swift(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(\"swift --version\".into());\n        CmdLineRunner::new(self.swift_bin(tv))\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"--version\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let settings = Settings::get();\n        let url = format!(\n            \"https://download.swift.org/swift-{version}-release/{platform_directory}/swift-{version}-RELEASE/swift-{version}-RELEASE-{platform}{architecture}.{extension}\",\n            version = tv.version,\n            platform = platform(),\n            platform_directory = platform_directory(),\n            extension = extension(),\n            architecture = match architecture(&settings) {\n                Some(arch) => format!(\"-{arch}\"),\n                None => \"\".into(),\n            }\n        );\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n        if !tarball_path.exists() {\n            pr.set_message(format!(\"download {filename}\"));\n            HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n        }\n\n        Ok(tarball_path)\n    }\n\n    fn install(&self, ctx: &InstallContext, tv: &ToolVersion, tarball_path: &Path) -> Result<()> {\n        Settings::get().ensure_experimental(\"swift\")?;\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        let version = &tv.version;\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        if cfg!(macos) {\n            let tmp = {\n                tempdir_in(tv.install_path().parent().unwrap())?\n                    .path()\n                    .to_path_buf()\n            };\n            CmdLineRunner::new(pkgutil_path())\n                .arg(\"--expand-full\")\n                .arg(tarball_path)\n                .arg(&tmp)\n                .with_pr(ctx.pr.as_ref())\n                .execute()?;\n            file::remove_all(tv.install_path())?;\n            file::rename(\n                tmp.join(format!(\"swift-{version}-RELEASE-osx-package.pkg\"))\n                    .join(\"Payload\"),\n                tv.install_path(),\n            )?;\n        } else if cfg!(windows) {\n            todo!(\"install from exe\");\n        } else {\n            file::untar(\n                tarball_path,\n                &tv.install_path(),\n                &file::TarOptions {\n                    strip_components: 1,\n                    pr: Some(ctx.pr.as_ref()),\n                    ..file::TarOptions::new(file::TarFormat::TarGz)\n                },\n            )?;\n        }\n        Ok(())\n    }\n\n    fn symlink_bins(&self, tv: &ToolVersion) -> Result<()> {\n        let usr_bin = tv.install_path().join(\"usr\").join(\"bin\");\n        let bin_dir = tv.install_path().join(\"bin\");\n        file::create_dir_all(&bin_dir)?;\n        for bin in file::ls(&usr_bin)? {\n            if !file::is_executable(&bin) {\n                continue;\n            }\n            let file_name = bin.file_name().unwrap().to_string_lossy().to_string();\n            if file_name.contains(\"swift\") || file_name.contains(\"sourcekit\") {\n                file::make_symlink_or_copy(&bin, &bin_dir.join(file_name))?;\n            }\n        }\n        Ok(())\n    }\n\n    async fn verify_gpg(\n        &self,\n        ctx: &InstallContext,\n        tv: &ToolVersion,\n        tarball_path: &Path,\n    ) -> Result<()> {\n        if file::which_non_pristine(\"gpg\").is_none() && Settings::get().swift.gpg_verify.is_none() {\n            ctx.pr\n                .println(\"gpg not found, skipping verification\".to_string());\n            return Ok(());\n        }\n        gpg::add_keys_swift(ctx)?;\n        let sig_path = PathBuf::from(format!(\"{}.sig\", tarball_path.to_string_lossy()));\n        HTTP.download_file(format!(\"{}.sig\", url(tv)), &sig_path, Some(ctx.pr.as_ref()))\n            .await?;\n        self.gpg(ctx)\n            .arg(\"--quiet\")\n            .arg(\"--trust-model\")\n            .arg(\"always\")\n            .arg(\"--verify\")\n            .arg(&sig_path)\n            .arg(tarball_path)\n            .execute()?;\n        Ok(())\n    }\n\n    fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        self.test_swift(ctx, tv)\n    }\n\n    fn gpg<'a>(&self, ctx: &'a InstallContext) -> CmdLineRunner<'a> {\n        CmdLineRunner::new(\"gpg\").with_pr(ctx.pr.as_ref())\n    }\n}\n\n#[cfg(macos)]\nfn pkgutil_path() -> PathBuf {\n    resolve_pkgutil_path(file::which(\"pkgutil\"))\n}\n\n#[cfg(not(macos))]\nfn pkgutil_path() -> PathBuf {\n    PathBuf::from(\"pkgutil\")\n}\n\n#[cfg(macos)]\nfn resolve_pkgutil_path(which_result: Option<PathBuf>) -> PathBuf {\n    if let Some(path) = which_result {\n        return path;\n    }\n    let fallback = PathBuf::from(\"/usr/sbin/pkgutil\");\n    if file::is_executable(&fallback) {\n        fallback\n    } else {\n        PathBuf::from(\"pkgutil\")\n    }\n}\n\n#[cfg(all(test, macos))]\nmod tests {\n    use super::resolve_pkgutil_path;\n    use crate::file;\n    use std::path::PathBuf;\n\n    #[test]\n    fn resolve_pkgutil_path_prefers_discovered_path() {\n        let discovered = PathBuf::from(\"/tmp/custom/pkgutil\");\n        assert_eq!(resolve_pkgutil_path(Some(discovered.clone())), discovered);\n    }\n\n    #[test]\n    fn resolve_pkgutil_path_falls_back_to_system_location() {\n        let resolved = resolve_pkgutil_path(None);\n        let fallback = PathBuf::from(\"/usr/sbin/pkgutil\");\n        if file::is_executable(&fallback) {\n            assert_eq!(resolved, fallback);\n        } else {\n            assert_eq!(resolved, PathBuf::from(\"pkgutil\"));\n        }\n    }\n}\n\n#[async_trait]\nimpl Backend for SwiftPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        let mut features = vec![SecurityFeature::Checksum {\n            algorithm: Some(\"sha256\".to_string()),\n        }];\n\n        // GPG verification is available on Linux when gpg is installed\n        if cfg!(target_os = \"linux\") && Settings::get().swift.gpg_verify != Some(false) {\n            features.push(SecurityFeature::Gpg);\n        }\n\n        features\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let versions = github::list_releases(\"swiftlang/swift\")\n            .await?\n            .into_iter()\n            .filter_map(|r| {\n                r.tag_name\n                    .strip_prefix(\"swift-\")\n                    .and_then(|v| v.strip_suffix(\"-RELEASE\"))\n                    .map(|v| (v.to_string(), r.created_at))\n            })\n            .rev()\n            .map(|(version, created_at)| VersionInfo {\n                version,\n                created_at: Some(created_at),\n                ..Default::default()\n            })\n            .collect();\n        Ok(versions)\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        if Settings::get().experimental {\n            Ok(vec![\".swift-version\".into()])\n        } else {\n            Ok(vec![])\n        }\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        let tarball_path = self.download(&tv, ctx.pr.as_ref()).await?;\n        if cfg!(target_os = \"linux\") && Settings::get().swift.gpg_verify != Some(false) {\n            self.verify_gpg(ctx, &tv, &tarball_path).await?;\n        }\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        self.install(ctx, &tv, &tarball_path)?;\n        self.symlink_bins(&tv)?;\n        self.verify(ctx, &tv)?;\n\n        Ok(tv)\n    }\n}\n\nfn swift_bin_name() -> &'static str {\n    if cfg!(windows) { \"swift.exe\" } else { \"swift\" }\n}\n\nfn platform_directory() -> String {\n    if cfg!(macos) {\n        \"xcode\".into()\n    } else if cfg!(windows) {\n        \"windows10\".into()\n    } else if let Ok(os_release) = &*os_release::OS_RELEASE {\n        let settings = Settings::get();\n        let arch = settings.arch();\n        if os_release.id == \"ubuntu\" && arch == \"arm64\" {\n            let retval = format!(\"{}{}-aarch64\", os_release.id, os_release.version_id);\n            retval.replace(\".\", \"\")\n        } else {\n            platform().replace(\".\", \"\")\n        }\n    } else {\n        platform().replace(\".\", \"\")\n    }\n}\n\nfn platform() -> String {\n    if let Some(platform) = &Settings::get().swift.platform {\n        return platform.clone();\n    }\n    if cfg!(macos) {\n        \"osx\".to_string()\n    } else if cfg!(windows) {\n        \"windows10\".to_string()\n    } else if let Ok(os_release) = &*os_release::OS_RELEASE {\n        if os_release.id == \"amzn\" {\n            format!(\"amazonlinux{}\", os_release.version_id)\n        } else if os_release.id == \"ubi\" {\n            \"ubi9\".to_string() // only 9 is available\n        } else if os_release.id == \"fedora\" {\n            \"fedora39\".to_string() // only 39 is available\n        } else {\n            format!(\"{}{}\", os_release.id, os_release.version_id)\n        }\n    } else {\n        \"ubi9\".to_string()\n    }\n}\n\nfn extension() -> &'static str {\n    if cfg!(macos) {\n        \"pkg\"\n    } else if cfg!(windows) {\n        \"exe\"\n    } else {\n        \"tar.gz\"\n    }\n}\n\nfn architecture(settings: &Settings) -> Option<&str> {\n    let arch = settings.arch();\n    if cfg!(target_os = \"linux\") {\n        return match arch {\n            \"x64\" => None,\n            \"arm64\" => Some(\"aarch64\"),\n            _ => Some(arch),\n        };\n    } else if cfg!(windows) && arch == \"arm64\" {\n        return Some(\"arm64\");\n    }\n    None\n}\n\nfn url(tv: &ToolVersion) -> String {\n    let settings = Settings::get();\n    format!(\n        \"https://download.swift.org/swift-{version}-release/{platform_directory}/swift-{version}-RELEASE/swift-{version}-RELEASE-{platform}{architecture}.{extension}\",\n        version = tv.version,\n        platform = platform(),\n        platform_directory = platform_directory(),\n        extension = extension(),\n        architecture = match architecture(&settings) {\n            Some(arch) => format!(\"-{arch}\"),\n            None => \"\".into(),\n        }\n    )\n}\n"
  },
  {
    "path": "src/plugins/core/zig.rs",
    "content": "use std::{\n    collections::HashMap,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nuse crate::backend::Backend;\nuse crate::backend::VersionInfo;\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cli::args::BackendArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings};\nuse crate::duration::DAILY;\nuse crate::file::{TarFormat, TarOptions};\nuse crate::http::{HTTP, HTTP_FETCH};\nuse crate::install_context::InstallContext;\nuse crate::lockfile::{PlatformInfo, ProvenanceType};\nuse crate::toolset::ToolVersion;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{file, minisign, plugins};\nuse async_trait::async_trait;\nuse eyre::Result;\nuse itertools::Itertools;\nuse rand::seq::SliceRandom;\nuse versions::Versioning;\nuse xx::regex;\n\n#[derive(Debug)]\npub struct ZigPlugin {\n    ba: Arc<BackendArg>,\n}\n\nconst ZIG_MINISIGN_KEY: &str = \"RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U\";\nconst REQUEST_SUFFIX: &str = \"?source=mise-en-place\";\nconst MIRRORS_FILENAME: &str = \"community-mirrors.txt\";\n\nimpl ZigPlugin {\n    pub fn new() -> Self {\n        Self {\n            ba: Arc::new(plugins::core::new_backend_arg(\"zig\")),\n        }\n    }\n\n    fn zig_bin(&self, tv: &ToolVersion) -> PathBuf {\n        if cfg!(windows) {\n            tv.install_path().join(\"zig.exe\")\n        } else {\n            tv.install_path().join(\"bin\").join(\"zig\")\n        }\n    }\n\n    fn test_zig(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        ctx.pr.set_message(\"zig version\".into());\n        CmdLineRunner::new(self.zig_bin(tv))\n            .with_pr(ctx.pr.as_ref())\n            .arg(\"version\")\n            .execute()\n    }\n\n    async fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result<PathBuf> {\n        let settings = Settings::get();\n        let url = self\n            .get_tarball_url(tv, &PlatformTarget::from_current())\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"Failed to resolve zig tarball URL for {}\", tv.version))?;\n\n        let filename = url.split('/').next_back().unwrap();\n        let tarball_path = tv.download_path().join(filename);\n\n        let mut downloaded = false;\n        let mut used_url = url.clone();\n        // The ziglang.org website kindly asks for trying mirrors for automated downloads,\n        // read more on https://ziglang.org/download/community-mirrors/\n        let community_mirrors = if url.starts_with(\"https://ziglang.org\") {\n            self.get_community_mirrors().await\n        } else {\n            None\n        };\n\n        if settings.zig.use_community_mirrors\n            && let Some(mirrors) = community_mirrors\n        {\n            for i in 0..mirrors.len() {\n                let disp_i = i + 1;\n                let disp_len = mirrors.len();\n                pr.set_message(format!(\"mirror {disp_i}/{disp_len} {filename}\"));\n\n                let mirror_url = &mirrors[i];\n                used_url = format!(\"{mirror_url}/{filename}\");\n\n                if HTTP\n                    .download_file(\n                        format!(\"{used_url}{REQUEST_SUFFIX}\"),\n                        &tarball_path,\n                        Some(pr),\n                    )\n                    .await\n                    .is_ok()\n                {\n                    downloaded = true;\n                    break;\n                }\n            }\n        }\n\n        if !downloaded {\n            // Try the usual ziglang.org or machengine.org download\n            pr.set_message(format!(\"download {filename}\"));\n            used_url = url.clone();\n            HTTP.download_file(&url, &tarball_path, Some(pr)).await?;\n            // If this was ziglang.org and error is not 404 and community_mirrors is None,\n            // the user might want to place the mirror list in cache dir by hand\n        }\n\n        pr.set_message(format!(\"minisign {filename}\"));\n        let tarball_data = file::read(&tarball_path)?;\n        let sig = HTTP\n            .get_text(format!(\"{used_url}.minisig{REQUEST_SUFFIX}\"))\n            .await?;\n        minisign::verify(ZIG_MINISIGN_KEY, &tarball_data, &sig)?;\n        // Since this passed the verify step, the format is guaranteed to be correct\n        let trusted_comment = sig.split('\\n').nth(2).unwrap().to_string();\n        // Verify that this is the desired version using trusted comment to prevent downgrade attacks\n        if !trusted_comment.contains(&format!(\"file:{filename}\")) {\n            return Err(eyre::eyre!(\n                \"Expected {}, but signature {}.minisig had:\\n{}\",\n                filename,\n                used_url,\n                trusted_comment\n            ));\n        }\n\n        Ok(tarball_path)\n    }\n\n    fn install(&self, ctx: &InstallContext, tv: &ToolVersion, tarball_path: &Path) -> Result<()> {\n        let filename = tarball_path.file_name().unwrap().to_string_lossy();\n        ctx.pr.set_message(format!(\"extract {filename}\"));\n        file::remove_all(tv.install_path())?;\n        file::untar(\n            tarball_path,\n            &tv.install_path(),\n            &TarOptions {\n                strip_components: 1,\n                pr: Some(ctx.pr.as_ref()),\n                ..TarOptions::new(TarFormat::from_file_name(&filename))\n            },\n        )?;\n\n        if cfg!(unix) {\n            file::create_dir_all(tv.install_path().join(\"bin\"))?;\n            file::make_symlink(Path::new(\"../zig\"), &tv.install_path().join(\"bin/zig\"))?;\n        }\n\n        Ok(())\n    }\n\n    fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> {\n        self.test_zig(ctx, tv)\n    }\n\n    async fn get_tarball_url_from_json(\n        &self,\n        json_url: &str,\n        version: &str,\n        arch: &str,\n        os: &str,\n    ) -> Result<String> {\n        let version_json: serde_json::Value = HTTP_FETCH.json(json_url).await?;\n        let zig_tarball_url = version_json\n            .pointer(&format!(\"/{version}/{arch}-{os}/tarball\"))\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| eyre::eyre!(\"Failed to get zig tarball url from {:?}\", json_url))?;\n        Ok(zig_tarball_url.to_string())\n    }\n\n    /// Get full download info (tarball URL, shasum, size) from JSON index\n    /// Uses cached request since same index is fetched for all platforms\n    async fn get_download_info_from_json(\n        &self,\n        json_url: &str,\n        version: &str,\n        arch: &str,\n        os: &str,\n    ) -> Result<(String, Option<String>, Option<u64>)> {\n        let version_json: serde_json::Value = HTTP_FETCH.json_cached(json_url).await?;\n        let platform_info = version_json\n            .pointer(&format!(\"/{version}/{arch}-{os}\"))\n            .ok_or_else(|| eyre::eyre!(\"Failed to get zig platform info from {:?}\", json_url))?;\n\n        let tarball_url = platform_info\n            .get(\"tarball\")\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| eyre::eyre!(\"Failed to get zig tarball url from {:?}\", json_url))?\n            .to_string();\n\n        let shasum = platform_info\n            .get(\"shasum\")\n            .and_then(|v| v.as_str())\n            .map(|s| format!(\"sha256:{s}\"));\n\n        let size = platform_info\n            .get(\"size\")\n            .and_then(|v| v.as_str())\n            .and_then(|s| s.parse::<u64>().ok());\n\n        Ok((tarball_url, shasum, size))\n    }\n\n    async fn get_community_mirrors(&self) -> Option<Vec<String>> {\n        let cache_path = self.ba.cache_path.join(MIRRORS_FILENAME);\n        let recent_cache =\n            file::modified_duration(&cache_path).is_ok_and(|updated_at| updated_at < DAILY);\n        if !recent_cache {\n            HTTP.download_file(\n                &format!(\"https://ziglang.org/download/{MIRRORS_FILENAME}\"),\n                &cache_path,\n                None,\n            )\n            .await\n            .unwrap_or_else(|_| {\n                // We can still use an older mirror list\n                warn!(\"{}: Could not download {}\", self.ba, MIRRORS_FILENAME);\n            });\n        }\n\n        let mirror_list = String::from_utf8(file::read(cache_path).ok()?).ok()?;\n        let mut mirrors: Vec<String> = mirror_list\n            .split('\\n')\n            .filter(|s| !s.is_empty())\n            .map(str::to_string)\n            .collect();\n        let mut rng = rand::rng();\n        mirrors.shuffle(&mut rng);\n        Some(mirrors)\n    }\n}\n\n#[async_trait]\nimpl Backend for ZigPlugin {\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    async fn security_info(&self) -> Vec<crate::backend::SecurityFeature> {\n        use crate::backend::SecurityFeature;\n\n        vec![\n            SecurityFeature::Checksum {\n                algorithm: Some(\"sha256\".to_string()),\n            },\n            SecurityFeature::Minisign {\n                public_key: Some(ZIG_MINISIGN_KEY.to_string()),\n            },\n        ]\n    }\n\n    async fn _list_remote_versions(&self, _config: &Arc<Config>) -> Result<Vec<VersionInfo>> {\n        let indexes = [\n            \"https://ziglang.org/download/index.json\",\n            // \"https://machengine.org/zig/index.json\", // need to handle mach's CalVer\n        ];\n        let mut versions: Vec<(String, Option<String>)> = Vec::new();\n\n        for index in indexes {\n            let index_json: serde_json::Value = HTTP_FETCH.json(index).await?;\n            let index_obj = index_json\n                .as_object()\n                .ok_or_else(|| eyre::eyre!(\"Failed to get zig version from {:?}\", index))?;\n\n            for (version, data) in index_obj {\n                let date = data.get(\"date\").and_then(|d| d.as_str()).map(String::from);\n                versions.push((version.clone(), date));\n            }\n        }\n\n        let versions = versions\n            .into_iter()\n            .unique_by(|(v, _)| v.clone())\n            .sorted_by_cached_key(|(s, _)| (Versioning::new(s), s.to_string()))\n            .map(|(version, date)| VersionInfo {\n                version,\n                created_at: date,\n                ..Default::default()\n            })\n            .collect();\n\n        Ok(versions)\n    }\n\n    async fn list_bin_paths(\n        &self,\n        _config: &Arc<Config>,\n        tv: &ToolVersion,\n    ) -> Result<Vec<PathBuf>> {\n        if cfg!(windows) {\n            Ok(vec![tv.install_path()])\n        } else {\n            Ok(vec![tv.install_path().join(\"bin\")])\n        }\n    }\n\n    async fn _idiomatic_filenames(&self) -> Result<Vec<String>> {\n        Ok(vec![\".zig-version\".into()])\n    }\n\n    async fn install_version_(\n        &self,\n        ctx: &InstallContext,\n        mut tv: ToolVersion,\n    ) -> Result<ToolVersion> {\n        // download() unconditionally verifies minisign (not behind a settings check).\n        // If minisign verification fails, download() returns Err and we never reach\n        // the provenance recording below. This is safe to record unconditionally.\n        let tarball_path = self.download(&tv, ctx.pr.as_ref()).await?;\n\n        // Enforce lockfile provenance expectation\n        let platform_key = PlatformTarget::from_current().to_key();\n        let locked_provenance = tv\n            .lock_platforms\n            .get_mut(&platform_key)\n            .and_then(|pi| pi.provenance.take());\n\n        if let Some(ref expected) = locked_provenance\n            && !expected.is_minisign()\n        {\n            return Err(eyre::eyre!(\n                \"Lockfile requires {expected} provenance for {tv} but minisign was used. \\\n                     This may indicate a downgrade attack.\"\n            ));\n        }\n\n        // Record minisign provenance — only reached if download() (and its\n        // minisign::verify call) succeeded\n        let pi = tv.lock_platforms.entry(platform_key.clone()).or_default();\n        pi.provenance = Some(ProvenanceType::Minisign);\n\n        ctx.pr.next_operation();\n        self.verify_checksum(ctx, &mut tv, &tarball_path)?;\n        ctx.pr.next_operation();\n        self.install(ctx, &tv, &tarball_path)?;\n        self.verify(ctx, &tv)?;\n        Ok(tv)\n    }\n\n    async fn get_tarball_url(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<Option<String>> {\n        let indexes = HashMap::from([\n            (\"zig\", \"https://ziglang.org/download/index.json\"),\n            (\"mach\", \"https://machengine.org/zig/index.json\"),\n        ]);\n\n        let arch = match target.arch_name() {\n            \"x64\" => \"x86_64\",\n            \"arm64\" => \"aarch64\",\n            \"arm\" => \"armv7a\",\n            \"riscv64\" => \"riscv64\",\n            other => other,\n        };\n        let os = match target.os_name() {\n            \"macos\" => \"macos\",\n            \"linux\" => \"linux\",\n            \"freebsd\" => \"freebsd\",\n            \"windows\" => \"windows\",\n            _ => \"linux\",\n        };\n\n        let (json_url, version) = if regex!(r\"^mach-|-mach$\").is_match(&tv.version) {\n            (indexes[\"mach\"], tv.version.as_str())\n        } else {\n            (indexes[\"zig\"], tv.version.as_str())\n        };\n\n        match self\n            .get_tarball_url_from_json(json_url, version, arch, os)\n            .await\n        {\n            Ok(url) => Ok(Some(url)),\n            Err(_) if regex!(r\"^\\d+\\.\\d+\\.\\d+$\").is_match(&tv.version) => {\n                // Fallback: construct URL directly for numbered versions\n                Ok(Some(format!(\n                    \"https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz\",\n                    tv.version, os, arch, tv.version\n                )))\n            }\n            Err(_) => Ok(None),\n        }\n    }\n\n    async fn resolve_lock_info(\n        &self,\n        tv: &ToolVersion,\n        target: &PlatformTarget,\n    ) -> Result<PlatformInfo> {\n        let indexes = HashMap::from([\n            (\"zig\", \"https://ziglang.org/download/index.json\"),\n            (\"mach\", \"https://machengine.org/zig/index.json\"),\n        ]);\n\n        let arch = match target.arch_name() {\n            \"x64\" => \"x86_64\",\n            \"arm64\" => \"aarch64\",\n            \"arm\" => \"armv7a\",\n            \"riscv64\" => \"riscv64\",\n            other => other,\n        };\n        let os = match target.os_name() {\n            \"macos\" => \"macos\",\n            \"linux\" => \"linux\",\n            \"freebsd\" => \"freebsd\",\n            \"windows\" => \"windows\",\n            _ => \"linux\",\n        };\n\n        let (json_url, version) = if regex!(r\"^mach-|-mach$\").is_match(&tv.version) {\n            (indexes[\"mach\"], tv.version.as_str())\n        } else {\n            (indexes[\"zig\"], tv.version.as_str())\n        };\n\n        // Try to get full info from JSON (includes checksum and size)\n        // Don't pre-set provenance at lock time — minisign verification hasn't run yet.\n        // Provenance is recorded in install_version_ after download() confirms minisign\n        // verification succeeded.\n        match self\n            .get_download_info_from_json(json_url, version, arch, os)\n            .await\n        {\n            Ok((url, checksum, size)) => Ok(PlatformInfo {\n                url: Some(url),\n                checksum,\n                size,\n                ..Default::default()\n            }),\n            Err(_) if regex!(r\"^\\d+\\.\\d+\\.\\d+$\").is_match(&tv.version) => {\n                // Fallback: construct URL directly for numbered versions (no checksum available)\n                // Don't pre-set provenance here — record it only after download() confirms\n                // minisign verification succeeded during install\n                Ok(PlatformInfo {\n                    url: Some(format!(\n                        \"https://ziglang.org/download/{}/zig-{}-{}-{}.tar.xz\",\n                        tv.version, os, arch, tv.version\n                    )),\n                    ..Default::default()\n                })\n            }\n            Err(_) => Ok(PlatformInfo::default()),\n        }\n    }\n}\n"
  },
  {
    "path": "src/plugins/mise_plugin_toml.rs",
    "content": "use std::path::Path;\n\nuse color_eyre::Result;\nuse color_eyre::eyre::eyre;\nuse eyre::WrapErr;\nuse toml_edit::{DocumentMut, Item, Value};\n\nuse crate::{file, parse_error};\n\n#[derive(Debug, Default, Clone)]\npub struct MisePluginTomlScriptConfig {\n    pub cache_key: Option<Vec<String>>,\n    pub data: Option<String>,\n}\n\n#[derive(Debug, Default, Clone)]\npub struct MisePluginToml {\n    pub exec_env: MisePluginTomlScriptConfig,\n    pub list_aliases: MisePluginTomlScriptConfig,\n    pub list_bin_paths: MisePluginTomlScriptConfig,\n    pub list_idiomatic_filenames: MisePluginTomlScriptConfig,\n}\n\nimpl MisePluginToml {\n    pub fn from_file(path: &Path) -> Result<Self> {\n        if !path.exists() {\n            return Ok(Default::default());\n        }\n        trace!(\"parsing: {}\", path.display());\n        let mut rf = Self::init();\n        let body = file::read_to_string(path).wrap_err(\"ensure file exists and can be read\")?;\n        rf.parse(&body)?;\n        Ok(rf)\n    }\n\n    fn init() -> Self {\n        Self {\n            ..Default::default()\n        }\n    }\n\n    fn parse(&mut self, s: &str) -> Result<()> {\n        let doc: DocumentMut = s.parse().wrap_err(\"ensure file is valid TOML\")?;\n        for (k, v) in doc.iter() {\n            match k {\n                \"exec-env\" => self.exec_env = self.parse_script_config(k, v)?,\n                \"list-aliases\" => self.list_aliases = self.parse_script_config(k, v)?,\n                \"list-bin-paths\" => self.list_bin_paths = self.parse_script_config(k, v)?,\n                \"list-idiomatic-filenames\" | \"list-legacy-filenames\" => {\n                    self.list_idiomatic_filenames = self.parse_script_config(k, v)?\n                }\n                // this is an old key used in rtx-python\n                // this file is invalid, so just stop parsing entirely if we see it\n                \"idiomatic-filenames\" | \"legacy-filenames\" => return Ok(()),\n                _ => Err(eyre!(\"unknown key: {}\", k))?,\n            }\n        }\n        Ok(())\n    }\n\n    fn parse_script_config(&mut self, key: &str, v: &Item) -> Result<MisePluginTomlScriptConfig> {\n        match v.as_table_like() {\n            Some(table) => {\n                let mut config = MisePluginTomlScriptConfig::default();\n                for (k, v) in table.iter() {\n                    let key = format!(\"{key}.{k}\");\n                    match k {\n                        \"cache-key\" => config.cache_key = Some(self.parse_string_array(k, v)?),\n                        \"data\" => match v.as_value() {\n                            Some(v) => config.data = Some(self.parse_string(k, v)?),\n                            _ => parse_error!(key, v, \"string\"),\n                        },\n                        _ => parse_error!(key, v, \"one of: cache-key\"),\n                    }\n                }\n                Ok(config)\n            }\n            _ => parse_error!(key, v, \"table\"),\n        }\n    }\n\n    fn parse_string_array(&mut self, k: &str, v: &Item) -> Result<Vec<String>> {\n        match v.as_array() {\n            Some(arr) => {\n                let mut out = vec![];\n                for v in arr {\n                    out.push(self.parse_string(k, v)?);\n                }\n                Ok(out)\n            }\n            _ => parse_error!(k, v, \"array\"),\n        }\n    }\n\n    fn parse_string(&mut self, k: &str, v: &Value) -> Result<String> {\n        match v.as_str() {\n            Some(v) => Ok(v.to_string()),\n            _ => parse_error!(k, v, \"string\"),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use indoc::formatdoc;\n    use insta::assert_debug_snapshot;\n\n    use crate::dirs;\n\n    use super::*;\n\n    #[test]\n    fn test_fixture() {\n        let cf = MisePluginToml::from_file(&dirs::HOME.join(\"fixtures/mise.plugin.toml\")).unwrap();\n\n        assert_debug_snapshot!(cf.exec_env);\n    }\n\n    #[test]\n    fn test_exec_env() {\n        let cf = parse(&formatdoc! {r#\"\n        [list-aliases]\n        data = \"test-aliases\"\n        [list-idiomatic-filenames]\n        data = \"test-idiomatic-filenames\"\n        [exec-env]\n        cache-key = [\"foo\", \"bar\"]\n        [list-bin-paths]\n        cache-key = [\"foo\"]\n        \"#});\n\n        assert_debug_snapshot!(cf.exec_env, @r#\"\n        MisePluginTomlScriptConfig {\n            cache_key: Some(\n                [\n                    \"foo\",\n                    \"bar\",\n                ],\n            ),\n            data: None,\n        }\n        \"#);\n    }\n\n    fn parse(s: &str) -> MisePluginToml {\n        let mut cf = MisePluginToml::init();\n        cf.parse(s).unwrap();\n        cf\n    }\n}\n"
  },
  {
    "path": "src/plugins/mod.rs",
    "content": "use crate::errors::Error::PluginNotInstalled;\nuse crate::git::Git;\nuse crate::plugins::asdf_plugin::AsdfPlugin;\nuse crate::plugins::vfox_plugin::VfoxPlugin;\nuse crate::registry::REGISTRY;\nuse crate::toolset::install_state;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{config::Config, dirs};\nuse async_trait::async_trait;\nuse clap::Command;\nuse eyre::{Result, eyre};\nuse heck::ToKebabCase;\nuse regex::Regex;\npub use script_manager::{Script, ScriptManager};\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::vec;\nuse std::{\n    fmt::{Debug, Display},\n    sync::Arc,\n};\n\npub mod asdf_plugin;\npub mod core;\npub mod mise_plugin_toml;\npub mod script_manager;\npub mod vfox_plugin;\n\n#[derive(Debug, Clone, Copy, PartialEq, strum::EnumString, strum::Display)]\npub enum PluginType {\n    Asdf,\n    Vfox,\n    VfoxBackend,\n}\n\n#[derive(Debug)]\npub enum PluginEnum {\n    Asdf(Arc<AsdfPlugin>),\n    Vfox(Arc<VfoxPlugin>),\n    VfoxBackend(Arc<VfoxPlugin>),\n}\n\nimpl PluginEnum {\n    pub fn name(&self) -> &str {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.name(),\n            PluginEnum::Vfox(plugin) => plugin.name(),\n            PluginEnum::VfoxBackend(plugin) => plugin.name(),\n        }\n    }\n\n    pub fn path(&self) -> PathBuf {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.path(),\n            PluginEnum::Vfox(plugin) => plugin.path(),\n            PluginEnum::VfoxBackend(plugin) => plugin.path(),\n        }\n    }\n\n    pub fn get_plugin_type(&self) -> PluginType {\n        match self {\n            PluginEnum::Asdf(_) => PluginType::Asdf,\n            PluginEnum::Vfox(_) => PluginType::Vfox,\n            PluginEnum::VfoxBackend(_) => PluginType::VfoxBackend,\n        }\n    }\n\n    pub fn get_remote_url(&self) -> eyre::Result<Option<String>> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.get_remote_url(),\n            PluginEnum::Vfox(plugin) => plugin.get_remote_url(),\n            PluginEnum::VfoxBackend(plugin) => plugin.get_remote_url(),\n        }\n    }\n\n    pub fn set_remote_url(&self, url: String) {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.set_remote_url(url),\n            PluginEnum::Vfox(plugin) => plugin.set_remote_url(url),\n            PluginEnum::VfoxBackend(plugin) => plugin.set_remote_url(url),\n        }\n    }\n\n    pub fn current_abbrev_ref(&self) -> eyre::Result<Option<String>> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.current_abbrev_ref(),\n            PluginEnum::Vfox(plugin) => plugin.current_abbrev_ref(),\n            PluginEnum::VfoxBackend(plugin) => plugin.current_abbrev_ref(),\n        }\n    }\n\n    pub fn current_sha_short(&self) -> eyre::Result<Option<String>> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.current_sha_short(),\n            PluginEnum::Vfox(plugin) => plugin.current_sha_short(),\n            PluginEnum::VfoxBackend(plugin) => plugin.current_sha_short(),\n        }\n    }\n\n    pub fn remote_sha(&self) -> eyre::Result<Option<String>> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.remote_sha(),\n            PluginEnum::Vfox(plugin) => plugin.remote_sha(),\n            PluginEnum::VfoxBackend(plugin) => plugin.remote_sha(),\n        }\n    }\n\n    pub fn external_commands(&self) -> eyre::Result<Vec<Command>> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.external_commands(),\n            PluginEnum::Vfox(plugin) => plugin.external_commands(),\n            PluginEnum::VfoxBackend(plugin) => plugin.external_commands(),\n        }\n    }\n\n    pub fn execute_external_command(&self, command: &str, args: Vec<String>) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.execute_external_command(command, args),\n            PluginEnum::Vfox(plugin) => plugin.execute_external_command(command, args),\n            PluginEnum::VfoxBackend(plugin) => plugin.execute_external_command(command, args),\n        }\n    }\n\n    pub async fn update(&self, pr: &dyn SingleReport, gitref: Option<String>) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.update(pr, gitref).await,\n            PluginEnum::Vfox(plugin) => plugin.update(pr, gitref).await,\n            PluginEnum::VfoxBackend(plugin) => plugin.update(pr, gitref).await,\n        }\n    }\n\n    pub async fn uninstall(&self, pr: &dyn SingleReport) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.uninstall(pr).await,\n            PluginEnum::Vfox(plugin) => plugin.uninstall(pr).await,\n            PluginEnum::VfoxBackend(plugin) => plugin.uninstall(pr).await,\n        }\n    }\n\n    pub async fn install(&self, config: &Arc<Config>, pr: &dyn SingleReport) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.install(config, pr).await,\n            PluginEnum::Vfox(plugin) => plugin.install(config, pr).await,\n            PluginEnum::VfoxBackend(plugin) => plugin.install(config, pr).await,\n        }\n    }\n\n    pub fn is_installed(&self) -> bool {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.is_installed(),\n            PluginEnum::Vfox(plugin) => plugin.is_installed(),\n            PluginEnum::VfoxBackend(plugin) => plugin.is_installed(),\n        }\n    }\n\n    pub fn is_installed_err(&self) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.is_installed_err(),\n            PluginEnum::Vfox(plugin) => plugin.is_installed_err(),\n            PluginEnum::VfoxBackend(plugin) => plugin.is_installed_err(),\n        }\n    }\n\n    pub async fn ensure_installed(\n        &self,\n        config: &Arc<Config>,\n        mpr: &MultiProgressReport,\n        force: bool,\n        dry_run: bool,\n    ) -> eyre::Result<()> {\n        match self {\n            PluginEnum::Asdf(plugin) => plugin.ensure_installed(config, mpr, force, dry_run).await,\n            PluginEnum::Vfox(plugin) => plugin.ensure_installed(config, mpr, force, dry_run).await,\n            PluginEnum::VfoxBackend(plugin) => {\n                plugin.ensure_installed(config, mpr, force, dry_run).await\n            }\n        }\n    }\n}\n\nimpl PluginType {\n    pub fn from_full(full: &str) -> eyre::Result<Self> {\n        match full.split(':').next() {\n            Some(\"asdf\") => Ok(Self::Asdf),\n            Some(\"vfox\") => Ok(Self::Vfox),\n            Some(\"vfox-backend\") => Ok(Self::VfoxBackend),\n            _ => Err(eyre!(\"unknown plugin type: {full}\")),\n        }\n    }\n\n    pub fn plugin(&self, short: String) -> PluginEnum {\n        let path = dirs::PLUGINS.join(short.to_kebab_case());\n        match self {\n            PluginType::Asdf => PluginEnum::Asdf(Arc::new(AsdfPlugin::new(short, path))),\n            PluginType::Vfox => PluginEnum::Vfox(Arc::new(VfoxPlugin::new(short, path))),\n            PluginType::VfoxBackend => {\n                PluginEnum::VfoxBackend(Arc::new(VfoxPlugin::new(short, path)))\n            }\n        }\n    }\n}\n\n/// Warn if a plugin is an env-only vfox plugin that shadows a registry entry.\n/// Env-only plugins have `hooks/mise_env.lua` but not `hooks/available.lua`.\npub fn warn_if_env_plugin_shadows_registry(name: &str, plugin_path: &Path) {\n    let hooks = plugin_path.join(\"hooks\");\n    let is_env_only = hooks.join(\"mise_env.lua\").exists() && !hooks.join(\"available.lua\").exists();\n    if is_env_only && REGISTRY.contains_key(name) {\n        warn!(\n            \"plugin '{name}' is an env plugin and is shadowing the '{name}' registry tool - \\\n            consider renaming the plugin or removing it with: mise plugins rm {name}\"\n        );\n    }\n}\n\npub static VERSION_REGEX: Lazy<regex::Regex> = Lazy::new(|| {\n    Regex::new(\n        r\"(?i)(^Available versions:|-src|-dev|-latest|-stm|[-\\\\.]rc|-milestone|-alpha|-beta|[-\\\\.]pre|-next|-test|([abc])[0-9]+|snapshot|SNAPSHOT|master)\"\n    )\n        .unwrap()\n});\n\npub fn get(short: &str) -> Result<PluginEnum> {\n    let (name, full) = short.split_once(':').unwrap_or((short, short));\n\n    // For plugin:tool format, look up the plugin by just the plugin name\n    let plugin_lookup_key = if short.contains(':') {\n        // Check if the part before the colon is a plugin name\n        if let Some(_plugin_type) = install_state::list_plugins().get(name) {\n            name\n        } else {\n            short\n        }\n    } else {\n        short\n    };\n\n    let plugin_type =\n        if let Some(plugin_type) = install_state::list_plugins().get(plugin_lookup_key) {\n            *plugin_type\n        } else {\n            PluginType::from_full(full)?\n        };\n    Ok(plugin_type.plugin(name.to_string()))\n}\n\n#[allow(unused_variables)]\n#[async_trait]\npub trait Plugin: Debug + Send {\n    fn name(&self) -> &str;\n    fn path(&self) -> PathBuf;\n    fn get_remote_url(&self) -> eyre::Result<Option<String>>;\n    fn set_remote_url(&self, url: String) {}\n    fn current_abbrev_ref(&self) -> eyre::Result<Option<String>>;\n    fn current_sha_short(&self) -> eyre::Result<Option<String>>;\n    fn remote_sha(&self) -> eyre::Result<Option<String>> {\n        Ok(None)\n    }\n    fn is_installed(&self) -> bool {\n        true\n    }\n    fn is_installed_err(&self) -> eyre::Result<()> {\n        if !self.is_installed() {\n            return Err(PluginNotInstalled(self.name().to_string()).into());\n        }\n        Ok(())\n    }\n\n    async fn ensure_installed(\n        &self,\n        _config: &Arc<Config>,\n        _mpr: &MultiProgressReport,\n        _force: bool,\n        _dry_run: bool,\n    ) -> eyre::Result<()> {\n        Ok(())\n    }\n    async fn update(&self, _pr: &dyn SingleReport, _gitref: Option<String>) -> eyre::Result<()> {\n        Ok(())\n    }\n    async fn uninstall(&self, _pr: &dyn SingleReport) -> eyre::Result<()> {\n        Ok(())\n    }\n    async fn install(&self, _config: &Arc<Config>, _pr: &dyn SingleReport) -> eyre::Result<()> {\n        Ok(())\n    }\n    fn external_commands(&self) -> eyre::Result<Vec<Command>> {\n        Ok(vec![])\n    }\n    #[cfg_attr(coverage_nightly, coverage(off))]\n    fn execute_external_command(&self, _command: &str, _args: Vec<String>) -> eyre::Result<()> {\n        unimplemented!(\n            \"execute_external_command not implemented for {}\",\n            self.name()\n        )\n    }\n}\n\nimpl Ord for PluginEnum {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.name().cmp(other.name())\n    }\n}\n\nimpl PartialOrd for PluginEnum {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl PartialEq for PluginEnum {\n    fn eq(&self, other: &Self) -> bool {\n        self.name() == other.name()\n    }\n}\n\nimpl Eq for PluginEnum {}\n\nimpl Display for PluginEnum {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.name())\n    }\n}\n\n#[derive(Debug, Clone)]\npub enum PluginSource {\n    /// Git repository with URL and optional ref\n    Git {\n        url: String,\n        git_ref: Option<String>,\n    },\n    /// Zip file accessible via HTTPS\n    Zip { url: String },\n}\n\nimpl PluginSource {\n    pub fn parse(repository: &str) -> Self {\n        // Split Parameters\n        let url_path = repository\n            .split('?')\n            .next()\n            .unwrap_or(repository)\n            .split('#')\n            .next()\n            .unwrap_or(repository);\n        // Check if it's a zip file (ends with -zip)\n        if url_path.to_lowercase().ends_with(\".zip\") {\n            return PluginSource::Zip {\n                url: repository.to_string(),\n            };\n        }\n        // Otherwise treat as git repository\n        let (url, git_ref) = Git::split_url_and_ref(repository);\n        PluginSource::Git {\n            url: url.to_string(),\n            git_ref: git_ref.map(|s| s.to_string()),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_plugin_source_parse_git() {\n        // Test parsing Git URL\n        let source = PluginSource::parse(\"https://github.com/user/plugin.git\");\n        match source {\n            PluginSource::Git { url, git_ref } => {\n                assert_eq!(url, \"https://github.com/user/plugin.git\");\n                assert_eq!(git_ref, None);\n            }\n            _ => panic!(\"Expected a git plugin\"),\n        }\n    }\n\n    #[test]\n    fn test_plugin_source_parse_git_with_ref() {\n        // Test parsing Git URL with refs\n        let source = PluginSource::parse(\"https://github.com/user/plugin.git#v1.0.0\");\n        match source {\n            PluginSource::Git { url, git_ref } => {\n                assert_eq!(url, \"https://github.com/user/plugin.git\");\n                assert_eq!(git_ref, Some(\"v1.0.0\".to_string()));\n            }\n            _ => panic!(\"Expected a git plugin\"),\n        }\n    }\n\n    #[test]\n    fn test_plugin_source_parse_zip() {\n        // Test parsing zip URL\n        let source = PluginSource::parse(\"https://example.com/plugins/my-plugin.zip\");\n        match source {\n            PluginSource::Zip { url } => {\n                assert_eq!(url, \"https://example.com/plugins/my-plugin.zip\");\n            }\n            _ => panic!(\"Expected a Zip source\"),\n        }\n    }\n\n    #[test]\n    fn test_plugin_source_parse_uppercase_zip_with_query() {\n        // Test parsing zip URL with query\n        let source =\n            PluginSource::parse(\"https://example.com/plugins/my-plugin.ZIP?version=v1.0.0\");\n        match source {\n            PluginSource::Zip { url } => {\n                assert_eq!(\n                    url,\n                    \"https://example.com/plugins/my-plugin.ZIP?version=v1.0.0\"\n                );\n            }\n            _ => panic!(\"Expected a Zip source\"),\n        }\n    }\n\n    #[test]\n    fn test_plugin_source_parse_edge_cases() {\n        // Test parsing git url which contains `.zip`\n        let source = PluginSource::parse(\"https://example.com/.zip/plugin\");\n        match source {\n            PluginSource::Git { .. } => {}\n            _ => panic!(\"Expected a git plugin\"),\n        }\n    }\n}\n"
  },
  {
    "path": "src/plugins/script_manager.rs",
    "content": "use std::collections::HashMap;\nuse std::ffi::OsString;\nuse std::fmt;\nuse std::fmt::{Display, Formatter};\nuse std::path::PathBuf;\n\nuse color_eyre::eyre::{Context, Result};\nuse duct::Expression;\nuse indexmap::indexmap;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::cmd::{CmdLineRunner, cmd};\nuse crate::config::Settings;\nuse crate::env::PATH_KEY;\nuse crate::errors::Error;\nuse crate::errors::Error::ScriptFailed;\nuse crate::fake_asdf::get_path_with_fake_asdf;\nuse crate::file::display_path;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{dirs, env};\n\n#[derive(Debug, Clone)]\npub struct ScriptManager {\n    pub plugin_path: PathBuf,\n    pub env: HashMap<OsString, OsString>,\n}\n\n#[derive(Debug, Clone)]\npub enum Script {\n    Hook(String),\n\n    // Plugin\n    LatestStable,\n    ListAliases,\n    ListAll,\n    ListIdiomaticFilenames,\n    ParseIdiomaticFile(String),\n\n    // RuntimeVersion\n    Download,\n    ExecEnv,\n    Install,\n    ListBinPaths,\n    RunExternalCommand(PathBuf, Vec<String>),\n    Uninstall,\n}\n\nimpl Display for Script {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        match self {\n            // Plugin\n            Script::LatestStable => write!(f, \"latest-stable\"),\n            Script::ListAll => write!(f, \"list-all\"),\n            Script::ListIdiomaticFilenames => write!(f, \"list-legacy-filenames\"),\n            Script::ListAliases => write!(f, \"list-aliases\"),\n            Script::ParseIdiomaticFile(_) => write!(f, \"parse-legacy-file\"),\n            Script::Hook(script) => write!(f, \"{script}\"),\n\n            // RuntimeVersion\n            Script::Install => write!(f, \"install\"),\n            Script::Uninstall => write!(f, \"uninstall\"),\n            Script::ListBinPaths => write!(f, \"list-bin-paths\"),\n            Script::RunExternalCommand(_, _) => write!(f, \"run-external-command\"),\n            Script::ExecEnv => write!(f, \"exec-env\"),\n            Script::Download => write!(f, \"download\"),\n        }\n    }\n}\n\nstatic INITIAL_ENV: Lazy<HashMap<OsString, OsString>> = Lazy::new(|| {\n    let settings = Settings::get();\n    let mut env: HashMap<OsString, OsString> = env::PRISTINE_ENV\n        .iter()\n        .map(|(k, v)| (k.into(), v.into()))\n        .collect();\n    if settings.trace {\n        env.insert(\"MISE_TRACE\".into(), \"1\".into());\n    }\n    if settings.debug {\n        env.insert(\"MISE_DEBUG\".into(), \"1\".into());\n        env.insert(\"MISE_VERBOSE\".into(), \"1\".into());\n    }\n    env.extend(\n        (indexmap! {\n            \"ASDF_CONCURRENCY\" => num_cpus::get().to_string(),\n            &*PATH_KEY => get_path_with_fake_asdf(),\n            \"MISE_CACHE_DIR\" => env::MISE_CACHE_DIR.to_string_lossy().to_string(),\n            \"MISE_CONCURRENCY\" => num_cpus::get().to_string(),\n            \"MISE_DATA_DIR\" => dirs::DATA.to_string_lossy().to_string(),\n            \"MISE_LOG_LEVEL\" => settings.log_level.to_string(),\n            \"__MISE_BIN\" => env::MISE_BIN.to_string_lossy().to_string(),\n            \"__MISE_SCRIPT\" => \"1\".to_string(),\n        })\n        .into_iter()\n        .map(|(k, v)| (k.into(), v.into())),\n    );\n    env\n});\n\nimpl ScriptManager {\n    pub fn new(plugin_path: PathBuf) -> Self {\n        let mut env = INITIAL_ENV.clone();\n        if let Some(failure) = env::var_os(\"MISE_FAILURE\") {\n            // used for testing failure cases\n            env.insert(\"MISE_FAILURE\".into(), failure);\n        }\n        Self { env, plugin_path }\n    }\n\n    pub fn with_env<K, V>(mut self, k: K, v: V) -> Self\n    where\n        K: Into<OsString>,\n        V: Into<OsString>,\n    {\n        self.env.insert(k.into(), v.into());\n        self\n    }\n\n    pub fn prepend_path(&mut self, path: PathBuf) {\n        let k: OsString = PATH_KEY.to_string().into();\n        let mut paths = env::split_paths(&self.env[&k]).collect::<Vec<_>>();\n        paths.insert(0, path);\n        self.env\n            .insert(PATH_KEY.to_string().into(), env::join_paths(paths).unwrap());\n    }\n\n    pub fn get_script_path(&self, script: &Script) -> PathBuf {\n        match script {\n            Script::RunExternalCommand(path, _) => path.clone(),\n            _ => self.plugin_path.join(\"bin\").join(script.to_string()),\n        }\n    }\n\n    pub fn script_exists(&self, script: &Script) -> bool {\n        self.get_script_path(script).is_file()\n    }\n\n    pub fn cmd(&self, script: &Script) -> Expression {\n        let args = match script {\n            Script::ParseIdiomaticFile(filename) => vec![filename.clone()],\n            Script::RunExternalCommand(_, args) => args.clone(),\n            _ => vec![],\n        };\n        let script_path = self.get_script_path(script);\n        // if !script_path.exists() {\n        //     return Err(PluginNotInstalled(self.plugin_name.clone()).into());\n        // }\n        let mut cmd = cmd(script_path, args).full_env(&self.env);\n        let settings = &Settings::get();\n        if !settings.raw {\n            // ignore stdin, otherwise a prompt may show up where the user won't see it\n            cmd = cmd.stdin_null();\n        }\n        cmd\n    }\n\n    pub fn read(&self, script: &Script) -> Result<String> {\n        let mut cmd = self.cmd(script);\n        let settings = &Settings::try_get()?;\n        if !settings.verbose {\n            cmd = cmd.stderr_null();\n        }\n        cmd.read()\n            .wrap_err_with(|| ScriptFailed(display_path(self.get_script_path(script)), None))\n    }\n\n    pub fn run_by_line(&self, script: &Script, pr: &dyn SingleReport) -> Result<()> {\n        let path = self.get_script_path(script);\n        pr.set_message(display_path(&path));\n        let mut cmd = CmdLineRunner::new(path.clone());\n        if let Some(arch) = &Settings::get().arch\n            && arch == \"x86_64\"\n            && cfg!(macos)\n        {\n            cmd = CmdLineRunner::new(\"/usr/bin/arch\")\n                .arg(\"-x86_64\")\n                .arg(path.clone());\n        }\n        let cmd = cmd.with_pr(pr).env_clear().envs(&self.env);\n        if let Err(e) = cmd.execute() {\n            let status = match e.downcast_ref::<Error>() {\n                Some(ScriptFailed(_, status)) => *status,\n                _ => None,\n            };\n            return Err(ScriptFailed(display_path(&path), status).into());\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n    use test_log::test;\n\n    use super::*;\n\n    #[test]\n    fn test_script_manager() {\n        let plugin_path = PathBuf::from(\"/tmp/asdf\");\n        let script_manager = ScriptManager::new(plugin_path.clone());\n        assert_eq!(script_manager.plugin_path, plugin_path);\n    }\n\n    #[test]\n    fn test_get_script_path() {\n        let plugin_path = PathBuf::from(\"/tmp/asdf\");\n        let script_manager = ScriptManager::new(plugin_path.clone());\n\n        let test = |script, expected| {\n            assert_eq!(script_manager.get_script_path(script), expected);\n        };\n\n        test(\n            &Script::LatestStable,\n            plugin_path.join(\"bin\").join(\"latest-stable\"),\n        );\n\n        let script = Script::RunExternalCommand(PathBuf::from(\"/bin/ls\"), vec![\"-l\".to_string()]);\n        test(&script, PathBuf::from(\"/bin/ls\"));\n    }\n}\n"
  },
  {
    "path": "src/plugins/vfox_plugin.rs",
    "content": "use crate::file::{display_path, remove_all};\nuse crate::git::{CloneOptions, Git};\nuse crate::http::HTTP;\nuse crate::plugins::warn_if_env_plugin_shadows_registry;\nuse crate::plugins::{Plugin, PluginSource};\nuse crate::result::Result;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse crate::{config::Config, dirs, file, registry};\nuse async_trait::async_trait;\nuse console::style;\nuse contracts::requires;\nuse eyre::{Context, eyre};\nuse indexmap::{IndexMap, indexmap};\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, Mutex, MutexGuard, mpsc};\nuse url::Url;\nuse vfox::Vfox;\nuse vfox::embedded_plugins;\n\n/// Result from a mise_env call with cache metadata\n#[derive(Debug, Default)]\npub struct MiseEnvResponse {\n    /// Environment variables to set\n    pub env: IndexMap<String, String>,\n    /// Whether this module's output can be cached\n    pub cacheable: bool,\n    /// Files to watch for cache invalidation\n    pub watch_files: Vec<PathBuf>,\n    /// Whether the plugin wants its env vars to be redacted\n    pub redact: bool,\n}\nuse xx::regex;\n\n#[derive(Debug)]\npub struct VfoxPlugin {\n    pub name: String,\n    pub full: Option<String>,\n    pub plugin_path: PathBuf,\n    pub repo: Mutex<Git>,\n    repo_url: Mutex<Option<String>>,\n}\n\nimpl VfoxPlugin {\n    #[requires(!name.is_empty())]\n    pub fn new(name: String, plugin_path: PathBuf) -> Self {\n        let repo = Git::new(&plugin_path);\n        Self {\n            name,\n            full: None,\n            repo_url: Mutex::new(None),\n            repo: Mutex::new(repo),\n            plugin_path,\n        }\n    }\n\n    fn repo(&self) -> MutexGuard<'_, Git> {\n        self.repo.lock().unwrap()\n    }\n\n    fn get_repo_url(&self, config: &Config) -> eyre::Result<Url> {\n        if let Some(url) = self.repo().get_remote_url() {\n            return Ok(Url::parse(&url)?);\n        }\n        if let Some(url) = config.get_repo_url(&self.name) {\n            return Ok(Url::parse(&url)?);\n        }\n        let url = self\n            .full\n            .as_ref()\n            .unwrap_or(&self.name)\n            .split_once(':')\n            .map(|f| f.1)\n            .unwrap_or(&self.name);\n        vfox_to_url(url)\n    }\n\n    pub async fn mise_env(\n        &self,\n        opts: &toml::Value,\n        env: &IndexMap<String, String>,\n    ) -> Result<Option<MiseEnvResponse>> {\n        let (vfox, _) = self.vfox();\n        let result = vfox.mise_env(&self.name, opts, env).await?;\n        let mut result_env = indexmap!();\n        for ek in result.env {\n            result_env.insert(ek.key, ek.value);\n        }\n        Ok(Some(MiseEnvResponse {\n            env: result_env,\n            cacheable: result.cacheable,\n            watch_files: result.watch_files,\n            redact: result.redact,\n        }))\n    }\n\n    pub async fn mise_path(\n        &self,\n        opts: &toml::Value,\n        env: &IndexMap<String, String>,\n    ) -> Result<Option<Vec<String>>> {\n        let (vfox, _) = self.vfox();\n        let mut out = vec![];\n        let results = vfox.mise_path(&self.name, opts, env).await?;\n        for entry in results {\n            out.push(entry);\n        }\n        Ok(Some(out))\n    }\n\n    pub fn vfox(&self) -> (Vfox, mpsc::Receiver<String>) {\n        let mut vfox = Vfox::new();\n        vfox.plugin_dir = dirs::PLUGINS.to_path_buf();\n        vfox.cache_dir = dirs::CACHE.to_path_buf();\n        vfox.download_dir = dirs::DOWNLOADS.to_path_buf();\n        vfox.install_dir = dirs::INSTALLS.to_path_buf();\n        let rx = vfox.log_subscribe();\n        (vfox, rx)\n    }\n\n    async fn install_from_zip(&self, url: &str, pr: &dyn SingleReport) -> eyre::Result<()> {\n        let temp_dir = tempfile::tempdir()?;\n        let temp_archive = temp_dir.path().join(\"archive.zip\");\n        HTTP.download_file(url, &temp_archive, Some(pr)).await?;\n\n        pr.set_message(\"extracting zip file\".to_string());\n\n        let strip_components = file::should_strip_components(&temp_archive, file::TarFormat::Zip)?;\n\n        file::unzip(\n            &temp_archive,\n            &self.plugin_path,\n            &file::ZipOptions {\n                strip_components: if strip_components { 1 } else { 0 },\n            },\n        )?;\n        Ok(())\n    }\n\n    pub fn is_embedded(&self) -> bool {\n        embedded_plugins::get_embedded_plugin(&self.name).is_some()\n    }\n}\n\n#[async_trait]\nimpl Plugin for VfoxPlugin {\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn path(&self) -> PathBuf {\n        self.plugin_path.clone()\n    }\n\n    fn get_remote_url(&self) -> eyre::Result<Option<String>> {\n        let url = self.repo().get_remote_url();\n        Ok(url.or(self.repo_url.lock().unwrap().clone()))\n    }\n\n    fn set_remote_url(&self, url: String) {\n        *self.repo_url.lock().unwrap() = Some(url);\n    }\n\n    fn current_abbrev_ref(&self) -> eyre::Result<Option<String>> {\n        // No git ref for embedded plugins or if plugin_path doesn't exist\n        if !self.plugin_path.exists() {\n            return Ok(None);\n        }\n        self.repo().current_abbrev_ref().map(Some)\n    }\n\n    fn current_sha_short(&self) -> eyre::Result<Option<String>> {\n        // No git sha for embedded plugins or if plugin_path doesn't exist\n        if !self.plugin_path.exists() {\n            return Ok(None);\n        }\n        self.repo().current_sha_short().map(Some)\n    }\n\n    fn remote_sha(&self) -> eyre::Result<Option<String>> {\n        if !self.plugin_path.exists() {\n            return Ok(None);\n        }\n        let branch = self.repo().current_branch()?;\n        self.repo().remote_sha(&branch)\n    }\n\n    fn is_installed(&self) -> bool {\n        // Embedded plugins are always \"installed\"\n        self.is_embedded() || self.plugin_path.exists()\n    }\n\n    fn is_installed_err(&self) -> eyre::Result<()> {\n        if self.is_installed() {\n            return Ok(());\n        }\n        Err(eyre!(\"asdf plugin {} is not installed\", self.name())\n            .wrap_err(\"run with --yes to install plugin automatically\"))\n    }\n\n    async fn ensure_installed(\n        &self,\n        config: &Arc<Config>,\n        mpr: &MultiProgressReport,\n        _force: bool,\n        dry_run: bool,\n    ) -> Result<()> {\n        // Skip installation for embedded plugins\n        if self.is_embedded() {\n            return Ok(());\n        }\n\n        if !self.plugin_path.exists() {\n            let url = self.get_repo_url(config)?;\n            trace!(\"Cloning vfox plugin: {url}\");\n            let pr = mpr.add_with_options(&format!(\"clone vfox plugin {url}\"), dry_run);\n            if !dry_run {\n                self.repo()\n                    .clone(url.as_str(), CloneOptions::default().pr(pr.as_ref()))?;\n                warn_if_env_plugin_shadows_registry(&self.name, &self.plugin_path);\n            }\n        }\n        Ok(())\n    }\n\n    async fn update(&self, pr: &dyn SingleReport, gitref: Option<String>) -> Result<()> {\n        // If only embedded (no filesystem plugin), warn that it can't be updated\n        if self.is_embedded() && !self.plugin_path.exists() {\n            warn!(\n                \"plugin:{} is embedded in mise, not updating\",\n                style(&self.name).blue().for_stderr()\n            );\n            pr.finish_with_message(\"embedded plugin\".into());\n            return Ok(());\n        }\n\n        let plugin_path = self.plugin_path.to_path_buf();\n        if plugin_path.is_symlink() {\n            warn!(\n                \"plugin:{} is a symlink, not updating\",\n                style(&self.name).blue().for_stderr()\n            );\n            return Ok(());\n        }\n        let git = Git::new(plugin_path);\n        if !git.is_repo() {\n            warn!(\n                \"plugin:{} is not a git repository, not updating\",\n                style(&self.name).blue().for_stderr()\n            );\n            return Ok(());\n        }\n        pr.set_message(\"update git repo\".into());\n        git.update(gitref)?;\n        let sha = git.current_sha_short()?;\n        let repo_url = self.get_remote_url()?.unwrap_or_default();\n        pr.finish_with_message(format!(\n            \"{repo_url}#{}\",\n            style(&sha).bright().yellow().for_stderr(),\n        ));\n        Ok(())\n    }\n\n    async fn uninstall(&self, pr: &dyn SingleReport) -> Result<()> {\n        if !self.is_installed() {\n            return Ok(());\n        }\n        // If only embedded (no filesystem plugin), warn that it can't be uninstalled\n        if self.is_embedded() && !self.plugin_path.exists() {\n            warn!(\n                \"plugin:{} is embedded in mise, cannot uninstall\",\n                style(&self.name).blue().for_stderr()\n            );\n            pr.finish_with_message(\"embedded plugin\".into());\n            return Ok(());\n        }\n        pr.set_message(\"uninstall\".into());\n\n        let rmdir = |dir: &Path| {\n            if !dir.exists() {\n                return Ok(());\n            }\n            pr.set_message(format!(\"remove {}\", display_path(dir)));\n            remove_all(dir).wrap_err_with(|| {\n                format!(\n                    \"Failed to remove directory {}\",\n                    style(display_path(dir)).cyan().for_stderr()\n                )\n            })\n        };\n\n        rmdir(&self.plugin_path)?;\n\n        Ok(())\n    }\n\n    async fn install(&self, config: &Arc<Config>, pr: &dyn SingleReport) -> eyre::Result<()> {\n        let repository = self.get_repo_url(config)?;\n        let source = PluginSource::parse(repository.as_str());\n        debug!(\"vfox_plugin[{}]:install {:?}\", self.name, repository);\n\n        if self.is_installed() {\n            self.uninstall(pr).await?;\n        }\n\n        match source {\n            PluginSource::Zip { url } => {\n                self.install_from_zip(&url, pr).await?;\n                pr.finish_with_message(url.to_string());\n                Ok(())\n            }\n            PluginSource::Git {\n                url: repo_url,\n                git_ref,\n            } => {\n                if regex!(r\"^[/~]\").is_match(&repo_url) {\n                    Err(eyre!(\n                        r#\"Invalid repository URL: {repo_url}\nIf you are trying to link to a local directory, use `mise plugins link` instead.\nPlugins could support local directories in the future but for now a symlink is required which `mise plugins link` will create for you.\"#\n                    ))?;\n                }\n                let git = Git::new(&self.plugin_path);\n                pr.set_message(format!(\"clone {repo_url}\"));\n                git.clone(&repo_url, CloneOptions::default().pr(pr))?;\n                if let Some(ref_) = &git_ref {\n                    pr.set_message(format!(\"git update {ref_}\"));\n                    git.update(Some(ref_.to_string()))?;\n                }\n\n                let sha = git.current_sha_short()?;\n                pr.finish_with_message(format!(\n                    \"{repo_url}#{}\",\n                    style(&sha).bright().yellow().for_stderr(),\n                ));\n                Ok(())\n            }\n        }\n    }\n}\n\nfn vfox_to_url(name: &str) -> eyre::Result<Url> {\n    let name = name.strip_prefix(\"vfox:\").unwrap_or(name);\n    if let Some(rt) = registry::REGISTRY.get(name.trim_start_matches(\"vfox-\")) {\n        // bun -> version-fox/vfox-bun\n        if let Some((_, tool_name)) = rt.backends.iter().find_map(|f| f.full.split_once(\"vfox:\")) {\n            return vfox_to_url(tool_name);\n        }\n    }\n    let res = if let Some(caps) = regex!(r#\"^([^/]+)/([^/]+)$\"#).captures(name) {\n        let user = caps.get(1).unwrap().as_str();\n        let repo = caps.get(2).unwrap().as_str();\n        format!(\"https://github.com/{user}/{repo}\").parse()\n    } else {\n        name.to_string().parse()\n    };\n    res.wrap_err_with(|| format!(\"Invalid version: {name}\"))\n}\n"
  },
  {
    "path": "src/prepare/engine.rs",
    "content": "use std::collections::{BTreeMap, HashMap, HashSet};\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse eyre::Result;\nuse tokio::sync::Semaphore;\nuse tokio::task::JoinSet;\n\nuse crate::cmd::CmdLineRunner;\nuse crate::config::config_file::ConfigFile;\nuse crate::config::{Config, Settings};\nuse crate::tera::{BASE_CONTEXT, get_tera};\nuse crate::ui::multi_progress_report::MultiProgressReport;\n\ntype StepOutput = (PrepareStepResult, Vec<PathBuf>);\ntype JobOutput = Result<(String, PrepareStepResult, Vec<PathBuf>), (String, eyre::Report)>;\n\nuse super::prepare_deps::PrepareDeps;\nuse super::providers::{\n    BunPrepareProvider, BundlerPrepareProvider, ComposerPrepareProvider, CustomPrepareProvider,\n    GitSubmodulePrepareProvider, GoPrepareProvider, NpmPrepareProvider, PipPrepareProvider,\n    PnpmPrepareProvider, PoetryPrepareProvider, UvPrepareProvider, YarnPrepareProvider,\n};\nuse super::rule::BUILTIN_PROVIDERS;\nuse super::state::{self, PrepareState};\nuse super::{FreshnessResult, PrepareProvider};\n\n/// Options for running prepare steps\n#[derive(Debug, Default)]\npub struct PrepareOptions {\n    /// Only check if prepare is needed, don't run commands\n    pub dry_run: bool,\n    /// Force run all prepare steps even if outputs are fresh\n    pub force: bool,\n    /// Run specific prepare rule(s) only\n    pub only: Option<Vec<String>>,\n    /// Skip specific prepare rule(s)\n    pub skip: Vec<String>,\n    /// Environment variables to pass to prepare commands (e.g., toolset PATH)\n    pub env: BTreeMap<String, String>,\n    /// If true, only run providers with auto=true\n    pub auto_only: bool,\n}\n\n/// Result of a prepare step\n#[derive(Debug)]\npub enum PrepareStepResult {\n    /// Step ran successfully\n    Ran(String),\n    /// Step would have run (dry-run mode), with reason why it's stale\n    WouldRun(String, String),\n    /// Step was skipped because outputs are fresh\n    Fresh(String),\n    /// Step was skipped by user request\n    Skipped(String),\n    /// Step failed\n    Failed(String),\n}\n\n/// Result of running all prepare steps\n#[derive(Debug)]\npub struct PrepareResult {\n    pub steps: Vec<PrepareStepResult>,\n}\n\n/// A prepare job ready to be executed\nstruct PrepareJob {\n    id: String,\n    cmd: super::PrepareCommand,\n    outputs: Vec<PathBuf>,\n    depends: Vec<String>,\n    timeout: Option<std::time::Duration>,\n}\n\nimpl PrepareResult {\n    /// Returns true if any steps ran or would have run\n    pub fn had_work(&self) -> bool {\n        self.steps.iter().any(|s| {\n            matches!(\n                s,\n                PrepareStepResult::Ran(_) | PrepareStepResult::WouldRun(_, _)\n            )\n        })\n    }\n}\n\n/// Engine that discovers and runs prepare providers\npub struct PrepareEngine {\n    providers: Vec<Box<dyn PrepareProvider>>,\n}\n\nimpl PrepareEngine {\n    /// Create a new PrepareEngine, discovering all applicable providers\n    pub fn new(config: &Config) -> Result<Self> {\n        let providers = Self::discover_providers(config)?;\n        // Only require experimental when prepare is actually configured\n        if !providers.is_empty() {\n            Settings::get().ensure_experimental(\"prepare\")?;\n        }\n        Ok(Self { providers })\n    }\n\n    /// Discover all applicable prepare providers for the current project\n    ///\n    /// Each config file's prepare providers are scoped to that config file's directory.\n    /// For example, a `[prepare.pnpm]` defined in the root `mise.toml` only applies when\n    /// running from the root directory, not from subdirectories.\n    fn discover_providers(config: &Config) -> Result<Vec<Box<dyn PrepareProvider>>> {\n        let project_root = config\n            .project_root\n            .clone()\n            .unwrap_or_else(|| std::env::current_dir().unwrap_or_default());\n\n        let mut providers: Vec<Box<dyn PrepareProvider>> = vec![];\n        let mut seen_ids: HashSet<String> = HashSet::new();\n        let mut disabled: Vec<String> = vec![];\n\n        // Process each config file's prepare config independently, using that\n        // config file's directory as the project root for its providers.\n        // Only include config files that belong to the current project root\n        // (skip config files outside the current project root, e.g. from parent directories).\n        for cf in config.config_files.values() {\n            let Some(prepare_config) = cf.prepare_config() else {\n                continue;\n            };\n\n            // Skip config files from parent directories - prepare providers\n            // should only run from the directory where they are defined.\n            // Global/system configs (project_root() == None) are always included.\n            if let Some(cf_project_root) = cf.project_root()\n                && cf_project_root != project_root\n            {\n                continue;\n            }\n\n            // Collect disable list scoped to this project root\n            disabled.extend(prepare_config.disable.iter().cloned());\n\n            let config_root = cf.config_root();\n\n            for (id, provider_config) in &prepare_config.providers {\n                // Skip duplicate provider IDs (first config file wins)\n                if !seen_ids.insert(id.clone()) {\n                    continue;\n                }\n\n                if let Some(provider) =\n                    Self::build_provider(id, &config_root, provider_config.clone())\n                    && provider.is_applicable()\n                {\n                    providers.push(provider);\n                }\n            }\n        }\n\n        // Filter disabled providers\n        providers.retain(|p| !disabled.contains(&p.id().to_string()));\n\n        Ok(providers)\n    }\n\n    /// Build a provider from its ID, config root, and configuration\n    fn build_provider(\n        id: &str,\n        config_root: &Path,\n        provider_config: super::rule::PrepareProviderConfig,\n    ) -> Option<Box<dyn PrepareProvider>> {\n        if BUILTIN_PROVIDERS.contains(&id) {\n            match id {\n                \"npm\" => Some(Box::new(NpmPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"yarn\" => Some(Box::new(YarnPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"pnpm\" => Some(Box::new(PnpmPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"bun\" => Some(Box::new(BunPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"go\" => Some(Box::new(GoPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"pip\" => Some(Box::new(PipPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"poetry\" => Some(Box::new(PoetryPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"uv\" => Some(Box::new(UvPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"bundler\" => Some(Box::new(BundlerPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"composer\" => Some(Box::new(ComposerPrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                \"git-submodule\" => Some(Box::new(GitSubmodulePrepareProvider::new(\n                    config_root,\n                    provider_config,\n                ))),\n                _ => None,\n            }\n        } else {\n            Some(Box::new(CustomPrepareProvider::new(\n                id.to_string(),\n                provider_config,\n                config_root,\n            )))\n        }\n    }\n\n    /// Add providers from additional config files (e.g., monorepo subdirectory configs).\n    ///\n    /// Unlike `discover_providers`, this does NOT filter by project root, since these\n    /// configs are intentionally from different directories (monorepo subdirectories).\n    pub fn add_config_files(\n        &mut self,\n        config_files: impl IntoIterator<Item = Arc<dyn ConfigFile>>,\n    ) {\n        let mut seen_ids: HashSet<String> =\n            self.providers.iter().map(|p| p.id().to_string()).collect();\n        let mut disabled: Vec<String> = vec![];\n\n        for cf in config_files {\n            let Some(prepare_config) = cf.prepare_config() else {\n                continue;\n            };\n\n            disabled.extend(prepare_config.disable.iter().cloned());\n            let config_root = cf.config_root();\n\n            for (id, provider_config) in &prepare_config.providers {\n                if !seen_ids.insert(id.clone()) {\n                    continue;\n                }\n\n                if let Some(provider) =\n                    Self::build_provider(id, &config_root, provider_config.clone())\n                    && provider.is_applicable()\n                {\n                    self.providers.push(provider);\n                }\n            }\n        }\n\n        if !disabled.is_empty() {\n            self.providers\n                .retain(|p| !disabled.contains(&p.id().to_string()));\n        }\n    }\n\n    /// List all discovered providers\n    pub fn list_providers(&self) -> Vec<&dyn PrepareProvider> {\n        self.providers.iter().map(|p| p.as_ref()).collect()\n    }\n\n    /// Find a specific provider by ID\n    pub fn find_provider(&self, id: &str) -> Option<&dyn PrepareProvider> {\n        self.providers\n            .iter()\n            .find(|p| p.id() == id)\n            .map(|p| p.as_ref())\n    }\n\n    /// Check freshness for a specific provider (public API for --explain)\n    pub fn check_provider_freshness(\n        &self,\n        provider: &dyn PrepareProvider,\n    ) -> Result<FreshnessResult> {\n        self.check_freshness(provider)\n    }\n\n    /// Check if any auto-enabled provider has stale outputs (without running)\n    /// Returns the IDs and reasons of stale providers\n    pub fn check_staleness(&self) -> Vec<(&str, String)> {\n        self.providers\n            .iter()\n            .filter(|p| p.is_auto())\n            .filter_map(|p| {\n                let result = self.check_freshness(p.as_ref());\n                match result {\n                    Ok(r) if !r.is_fresh() => Some((p.id(), r.reason().to_string())),\n                    _ => None,\n                }\n            })\n            .collect()\n    }\n\n    /// Run all stale prepare steps, respecting dependency ordering\n    pub async fn run(&self, opts: PrepareOptions) -> Result<PrepareResult> {\n        let mut results = vec![];\n\n        // Collect providers that need to run\n        let mut to_run: Vec<PrepareJob> = vec![];\n        // Track IDs of providers that are fresh/skipped (treated as already satisfied for deps)\n        let mut satisfied_ids: HashSet<String> = HashSet::new();\n\n        for provider in &self.providers {\n            let id = provider.id().to_string();\n\n            // Check auto_only filter\n            if opts.auto_only && !provider.is_auto() {\n                trace!(\"prepare step {} is not auto, skipping\", id);\n                results.push(PrepareStepResult::Skipped(id.clone()));\n                satisfied_ids.insert(id);\n                continue;\n            }\n\n            // Check skip list\n            if opts.skip.contains(&id) {\n                results.push(PrepareStepResult::Skipped(id.clone()));\n                satisfied_ids.insert(id);\n                continue;\n            }\n\n            // Check only list\n            if let Some(ref only) = opts.only\n                && !only.contains(&id)\n            {\n                results.push(PrepareStepResult::Skipped(id.clone()));\n                satisfied_ids.insert(id);\n                continue;\n            }\n\n            let freshness = if opts.force {\n                FreshnessResult::Forced\n            } else {\n                self.check_freshness(provider.as_ref())?\n            };\n\n            if !freshness.is_fresh() {\n                let cmd = provider.prepare_command()?;\n                let outputs = provider.outputs();\n                let depends = provider.depends();\n                let timeout = provider.timeout();\n                let reason = freshness.reason().to_string();\n\n                if opts.dry_run {\n                    results.push(PrepareStepResult::WouldRun(id, reason));\n                } else {\n                    to_run.push(PrepareJob {\n                        id,\n                        cmd,\n                        outputs,\n                        depends,\n                        timeout,\n                    });\n                }\n            } else {\n                trace!(\"prepare step {} is fresh, skipping\", id);\n                results.push(PrepareStepResult::Fresh(id.clone()));\n                satisfied_ids.insert(id);\n            }\n        }\n\n        // Run stale providers with dependency ordering\n        if !to_run.is_empty() {\n            let has_deps = to_run.iter().any(|j| !j.depends.is_empty());\n\n            if has_deps {\n                let run_results = self\n                    .run_with_deps(to_run, &satisfied_ids, &opts.env)\n                    .await?;\n                for (step_result, outputs) in run_results {\n                    for output in &outputs {\n                        super::clear_output_stale(output);\n                    }\n                    results.push(step_result);\n                }\n            } else {\n                // No dependencies — use simple parallel execution\n                let run_results = self.run_parallel(to_run, &opts.env).await?;\n                for (step_result, outputs) in run_results {\n                    for output in &outputs {\n                        super::clear_output_stale(output);\n                    }\n                    results.push(step_result);\n                }\n            }\n\n            // Save content hashes for all successfully ran providers\n            for step in &results {\n                if let PrepareStepResult::Ran(id) = step\n                    && let Some(provider) = self.providers.iter().find(|p| p.id() == id)\n                {\n                    let project_root = &provider.base().project_root;\n                    let sources = provider.sources();\n                    if let Ok(hashes) = state::hash_sources(&sources, project_root) {\n                        let mut st = PrepareState::load(project_root);\n                        st.set_hashes(id, hashes);\n                        if let Err(e) = st.save(project_root) {\n                            warn!(\"failed to save prepare state: {e}\");\n                        }\n                    }\n                }\n            }\n        }\n\n        Ok(PrepareResult { steps: results })\n    }\n\n    /// Simple parallel execution (no dependency ordering)\n    async fn run_parallel(\n        &self,\n        to_run: Vec<PrepareJob>,\n        toolset_env: &BTreeMap<String, String>,\n    ) -> Result<Vec<(PrepareStepResult, Vec<PathBuf>)>> {\n        let mpr = MultiProgressReport::get();\n\n        let to_run_with_context: Vec<_> = to_run\n            .into_iter()\n            .map(|job| (job, mpr.clone(), toolset_env.clone()))\n            .collect();\n\n        crate::parallel::parallel(to_run_with_context, |(job, mpr, toolset_env)| async move {\n            let pr = mpr.add(&job.cmd.description);\n            match Self::execute_prepare_static(&job.cmd, &toolset_env, job.timeout) {\n                Ok(()) => {\n                    pr.finish_with_message(format!(\"{} done\", job.cmd.description));\n                    Ok((PrepareStepResult::Ran(job.id), job.outputs))\n                }\n                Err(e) => {\n                    pr.finish_with_message(format!(\"{} failed: {}\", job.cmd.description, e));\n                    Err(e)\n                }\n            }\n        })\n        .await\n    }\n\n    /// Dependency-aware execution using Kahn's algorithm\n    async fn run_with_deps(\n        &self,\n        to_run: Vec<PrepareJob>,\n        satisfied_ids: &HashSet<String>,\n        toolset_env: &BTreeMap<String, String>,\n    ) -> Result<Vec<StepOutput>> {\n        let mpr = MultiProgressReport::get();\n        let mut results: Vec<StepOutput> = vec![];\n        let mut errors: Vec<(String, String)> = vec![];\n\n        // Build jobs map for lookup\n        let running_ids: HashSet<String> = to_run.iter().map(|j| j.id.clone()).collect();\n        let mut jobs: HashMap<String, PrepareJob> = HashMap::new();\n        let mut dep_specs: Vec<(String, Vec<String>)> = vec![];\n\n        for job in to_run {\n            // Filter depends to only those that are actually running (not fresh/skipped)\n            let filtered_deps: Vec<String> = job\n                .depends\n                .iter()\n                .filter(|dep| {\n                    if satisfied_ids.contains(*dep) {\n                        // Dependency is already satisfied (fresh/skipped)\n                        false\n                    } else if running_ids.contains(*dep) {\n                        // Dependency is in the run set — need to wait\n                        true\n                    } else {\n                        // Unknown dep — warn but don't block\n                        warn!(\n                            \"prepare provider '{}' depends on '{}' which is not configured\",\n                            job.id, dep\n                        );\n                        false\n                    }\n                })\n                .cloned()\n                .collect();\n\n            dep_specs.push((job.id.clone(), filtered_deps));\n            jobs.insert(job.id.clone(), job);\n        }\n\n        let mut deps = PrepareDeps::new(&dep_specs)?;\n\n        // Report blocked providers (cycles)\n        for blocked_id in deps.blocked_providers() {\n            warn!(\n                \"prepare provider '{}' is blocked due to dependency cycle\",\n                blocked_id\n            );\n            if let Some(job) = jobs.remove(&blocked_id) {\n                results.push((PrepareStepResult::Skipped(job.id), vec![]));\n            }\n        }\n\n        let mut rx = deps.subscribe();\n        let semaphore = Arc::new(Semaphore::new(Settings::get().jobs));\n        let mut join_set: JoinSet<JobOutput> = JoinSet::new();\n        // Track which tokio task ID maps to which provider ID for JoinError recovery\n        let mut inflight: HashMap<tokio::task::Id, String> = HashMap::new();\n\n        loop {\n            tokio::select! {\n                biased;\n\n                // Prioritize handling completed tasks\n                Some(join_result) = join_set.join_next() => {\n                    match join_result {\n                        Ok(Ok((id, step_result, outputs))) => {\n                            inflight.retain(|_, v| v != &id);\n                            results.push((step_result, outputs));\n                            deps.complete_success(&id);\n                        }\n                        Ok(Err((id, e))) => {\n                            inflight.retain(|_, v| v != &id);\n                            warn!(\"prepare provider '{}' failed: {}\", id, e);\n                            errors.push((id.clone(), e.to_string()));\n                            results.push((PrepareStepResult::Failed(id.clone()), vec![]));\n                            deps.complete_failure(&id);\n                            for blocked_id in deps.blocked_providers() {\n                                if let Some(job) = jobs.remove(&blocked_id) {\n                                    warn!(\n                                        \"prepare provider '{}' skipped due to failed dependency\",\n                                        job.id\n                                    );\n                                    results.push((PrepareStepResult::Skipped(job.id), vec![]));\n                                }\n                            }\n                        }\n                        Err(e) => {\n                            // JoinError — task panicked or was cancelled\n                            if let Some(id) = inflight.remove(&e.id()) {\n                                warn!(\"prepare provider '{}' panicked: {}\", id, e);\n                                errors.push((id.clone(), e.to_string()));\n                                results.push((PrepareStepResult::Failed(id.clone()), vec![]));\n                                deps.complete_failure(&id);\n                                for blocked_id in deps.blocked_providers() {\n                                    if let Some(job) = jobs.remove(&blocked_id) {\n                                        warn!(\n                                            \"prepare provider '{}' skipped due to failed dependency\",\n                                            job.id\n                                        );\n                                        results.push((PrepareStepResult::Skipped(job.id), vec![]));\n                                    }\n                                }\n                            } else {\n                                warn!(\"prepare task join error (unknown task): {e}\");\n                            }\n                        }\n                    }\n                }\n\n                // Receive next ready provider\n                Some(maybe_id) = rx.recv() => {\n                    let Some(id) = maybe_id else {\n                        // None = all done\n                        break;\n                    };\n\n                    let Some(job) = jobs.remove(&id) else {\n                        continue;\n                    };\n\n                    let permit = semaphore.clone().acquire_owned().await.unwrap();\n                    let mpr = mpr.clone();\n                    let toolset_env = toolset_env.clone();\n\n                    let handle = join_set.spawn(async move {\n                        let pr = mpr.add(&job.cmd.description);\n                        let id = job.id;\n                        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n                            Self::execute_prepare_static(&job.cmd, &toolset_env, job.timeout)\n                        }));\n                        drop(permit);\n\n                        match result {\n                            Ok(Ok(())) => {\n                                pr.finish_with_message(format!(\"{} done\", job.cmd.description));\n                                let step = PrepareStepResult::Ran(id.clone());\n                                Ok((id, step, job.outputs))\n                            }\n                            Ok(Err(e)) => {\n                                pr.finish_with_message(format!(\n                                    \"{} failed: {}\",\n                                    job.cmd.description, e\n                                ));\n                                Err((id, e))\n                            }\n                            Err(_) => {\n                                pr.finish_with_message(format!(\n                                    \"{} panicked\",\n                                    job.cmd.description\n                                ));\n                                Err((id, eyre::eyre!(\"task panicked\")))\n                            }\n                        }\n                    });\n                    inflight.insert(handle.id(), id);\n                }\n\n                else => break,\n            }\n        }\n\n        // Wait for remaining in-flight tasks\n        while let Some(join_result) = join_set.join_next().await {\n            match join_result {\n                Ok(Ok((id, step_result, outputs))) => {\n                    inflight.retain(|_, v| v != &id);\n                    results.push((step_result, outputs));\n                }\n                Ok(Err((id, e))) => {\n                    inflight.retain(|_, v| v != &id);\n                    warn!(\"prepare provider '{}' failed: {}\", id, e);\n                    errors.push((id.clone(), e.to_string()));\n                    results.push((PrepareStepResult::Failed(id), vec![]));\n                }\n                Err(e) => {\n                    if let Some(id) = inflight.remove(&e.id()) {\n                        warn!(\"prepare provider '{}' panicked: {}\", id, e);\n                        errors.push((id.clone(), e.to_string()));\n                        results.push((PrepareStepResult::Failed(id), vec![]));\n                    } else {\n                        warn!(\"prepare task join error (unknown task): {e}\");\n                    }\n                }\n            }\n        }\n\n        if !errors.is_empty() {\n            let details = errors\n                .iter()\n                .map(|(id, msg)| format!(\"  {id}: {msg}\"))\n                .collect::<Vec<_>>()\n                .join(\"\\n\");\n            return Err(eyre::eyre!(\"prepare providers failed:\\n{details}\"));\n        }\n        Ok(results)\n    }\n\n    /// Check if a provider's outputs are fresh relative to its sources.\n    ///\n    /// Uses blake3 content hashing with persistent state. On first run (no stored\n    /// hashes), the provider is always considered stale. Session-based stale\n    /// tracking (venv auto-creation) is always checked first.\n    pub fn check_freshness(&self, provider: &dyn PrepareProvider) -> Result<FreshnessResult> {\n        let sources = provider.sources();\n        let outputs = provider.outputs();\n\n        if outputs.is_empty() {\n            return Ok(FreshnessResult::NoOutputs);\n        }\n\n        // Check if any output was created this session (before prepare ran)\n        for output in &outputs {\n            if super::is_output_stale(output) {\n                return Ok(FreshnessResult::Stale(\n                    \"output created this session\".to_string(),\n                ));\n            }\n        }\n\n        // Check if any output is missing\n        for output in &outputs {\n            if !output.exists() {\n                return Ok(FreshnessResult::OutputsMissing);\n            }\n        }\n\n        if sources.is_empty() {\n            return Ok(FreshnessResult::NoSources);\n        }\n\n        // Use content-hash comparison via persistent state\n        let project_root = &provider.base().project_root;\n        let st = PrepareState::load(project_root);\n        let provider_id = provider.id();\n\n        let current_hashes = state::hash_sources(&sources, project_root)?;\n\n        match st.get_hashes(provider_id) {\n            Some(stored_hashes) => {\n                // Check for changed files\n                for (path, hash) in &current_hashes {\n                    match stored_hashes.get(path.as_str()) {\n                        Some(stored_hash) if stored_hash == hash => {}\n                        Some(_) => {\n                            return Ok(FreshnessResult::Stale(format!(\"{path} changed\")));\n                        }\n                        None => {\n                            return Ok(FreshnessResult::Stale(format!(\"{path} added\")));\n                        }\n                    }\n                }\n                // Check for removed files\n                for path in stored_hashes.keys() {\n                    if !current_hashes.contains_key(path) {\n                        return Ok(FreshnessResult::Stale(format!(\"{path} removed\")));\n                    }\n                }\n                Ok(FreshnessResult::Fresh)\n            }\n            None => {\n                // No stored state — first run, consider stale\n                Ok(FreshnessResult::Stale(\"no previous state\".to_string()))\n            }\n        }\n    }\n\n    /// Execute a prepare command (static version for parallel execution)\n    fn execute_prepare_static(\n        cmd: &super::PrepareCommand,\n        toolset_env: &BTreeMap<String, String>,\n        timeout: Option<std::time::Duration>,\n    ) -> Result<()> {\n        let cwd = match cmd.cwd.clone() {\n            Some(dir) => dir,\n            None => std::env::current_dir()?,\n        };\n\n        let mut runner = CmdLineRunner::new(&cmd.program)\n            .args(&cmd.args)\n            .current_dir(cwd);\n\n        // Apply timeout if configured\n        if let Some(timeout) = timeout {\n            runner = runner.with_timeout(timeout);\n        }\n\n        // Apply toolset environment (includes PATH with installed tools)\n        for (k, v) in toolset_env {\n            runner = runner.env(k, v);\n        }\n\n        // Apply command-specific environment (can override toolset env)\n        // Render tera templates in env values (e.g., \"{{env.baz}}\")\n        let mut tera_ctx = BASE_CONTEXT.clone();\n        // Merge toolset env (which includes [env] directives) into tera context\n        // so templates like \"{{env.MY_VAR}}\" can resolve config-defined vars\n        let mut env_map = crate::env::PRISTINE_ENV.clone();\n        env_map.extend(toolset_env.iter().map(|(k, v)| (k.clone(), v.clone())));\n        tera_ctx.insert(\"env\", &env_map);\n        let mut tera = get_tera(cmd.cwd.as_deref());\n        for (k, v) in &cmd.env {\n            let rendered = if v.contains(\"{{\") || v.contains(\"{%\") || v.contains(\"{#\") {\n                tera.render_str(v, &tera_ctx).unwrap_or_else(|e| {\n                    warn!(\"failed to render template for prepare env {k}: {e}\");\n                    v.clone()\n                })\n            } else {\n                v.clone()\n            };\n            runner = runner.env(k, &rendered);\n        }\n\n        // Use raw output for better UX during dependency installation\n        if Settings::get().raw {\n            runner = runner.raw(true);\n        }\n\n        runner.execute()?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/prepare/mod.rs",
    "content": "use std::collections::{BTreeMap, HashSet};\nuse std::fmt::Debug;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, LazyLock, Mutex};\n\nuse eyre::{Result, bail};\n\nuse crate::config::{Config, Settings};\nuse crate::env;\n\npub use engine::{PrepareEngine, PrepareOptions, PrepareStepResult};\npub use rule::PrepareConfig;\n\nmod engine;\npub(crate) mod prepare_deps;\npub mod providers;\nmod rule;\npub mod state;\n\n/// Result of a freshness check for a prepare provider\n#[derive(Debug, Clone)]\npub enum FreshnessResult {\n    /// Outputs are up to date with sources\n    Fresh,\n    /// Provider has no outputs defined, always run to be safe\n    NoOutputs,\n    /// One or more output paths don't exist\n    OutputsMissing,\n    /// Sources have changed since last successful run\n    Stale(String),\n    /// Provider has no sources, consider fresh\n    NoSources,\n    /// Force flag was used\n    Forced,\n}\n\nimpl FreshnessResult {\n    /// Returns true if the provider should be considered fresh (no work needed)\n    pub fn is_fresh(&self) -> bool {\n        matches!(self, FreshnessResult::Fresh | FreshnessResult::NoSources)\n    }\n\n    /// Human-readable reason string for display\n    pub fn reason(&self) -> &str {\n        match self {\n            FreshnessResult::Fresh => \"outputs are up to date\",\n            FreshnessResult::NoOutputs => \"no outputs defined\",\n            FreshnessResult::OutputsMissing => \"outputs missing\",\n            FreshnessResult::Stale(reason) => reason,\n            FreshnessResult::NoSources => \"no sources to check\",\n            FreshnessResult::Forced => \"forced\",\n        }\n    }\n}\n\n/// A command to execute for preparation\n#[derive(Debug, Clone)]\npub struct PrepareCommand {\n    /// The program to execute\n    pub program: String,\n    /// Arguments to pass to the program\n    pub args: Vec<String>,\n    /// Environment variables to set\n    pub env: BTreeMap<String, String>,\n    /// Working directory (defaults to project root)\n    pub cwd: Option<PathBuf>,\n    /// Human-readable description of what this command does\n    pub description: String,\n}\n\nimpl PrepareCommand {\n    /// Create a PrepareCommand from a run string like \"npm install\"\n    ///\n    /// Wraps the command with `sh -c` (matching task execution behavior)\n    /// so shell features like pipes, redirects, and `&&` work.\n    pub fn from_string(\n        run: &str,\n        project_root: &Path,\n        config: &rule::PrepareProviderConfig,\n    ) -> Result<Self> {\n        if run.trim().is_empty() {\n            bail!(\"prepare run command cannot be empty\");\n        }\n\n        let shell = Settings::get().default_inline_shell()?;\n        let (program, shell_args) = shell.split_first().ok_or_else(|| {\n            eyre::eyre!(\"default inline shell is empty; check unix_default_inline_shell_args / windows_default_inline_shell_args\")\n        })?;\n\n        let mut args: Vec<String> = shell_args.to_vec();\n        args.push(run.to_string());\n\n        Ok(Self {\n            program: program.to_string(),\n            args,\n            env: config.env.clone(),\n            cwd: config\n                .dir\n                .as_ref()\n                .map(|d| project_root.join(d))\n                .or_else(|| Some(project_root.to_path_buf())),\n            description: config\n                .description\n                .clone()\n                .unwrap_or_else(|| run.to_string()),\n        })\n    }\n}\n\n/// Trait for prepare providers that can check and install dependencies\npub trait PrepareProvider: Debug + Send + Sync {\n    /// Access the shared base (project root + config)\n    fn base(&self) -> &providers::ProviderBase;\n\n    /// Unique identifier for this provider (e.g., \"npm\", \"cargo\", \"codegen\")\n    fn id(&self) -> &str {\n        &self.base().id\n    }\n\n    /// Returns the source files to check for freshness (lock files, config files)\n    fn sources(&self) -> Vec<PathBuf>;\n\n    /// Returns the output files/directories that should be newer than sources\n    fn outputs(&self) -> Vec<PathBuf>;\n\n    /// The command to run when outputs are stale relative to sources\n    fn prepare_command(&self) -> Result<PrepareCommand>;\n\n    /// Whether this provider is applicable (e.g., lockfile exists)\n    fn is_applicable(&self) -> bool;\n\n    /// Whether this provider should auto-run before mise x/run\n    fn is_auto(&self) -> bool {\n        self.base().is_auto()\n    }\n\n    /// Other prepare providers that must complete before this one runs\n    fn depends(&self) -> Vec<String> {\n        self.base().config.depends.clone()\n    }\n\n    /// Timeout duration for this provider's run command\n    fn timeout(&self) -> Option<std::time::Duration> {\n        self.base().config.timeout.as_deref().and_then(|t| {\n            match crate::duration::parse_duration(t) {\n                Ok(d) => Some(d),\n                Err(err) => {\n                    warn!(\"prepare: {}: invalid timeout {t:?}: {err}\", self.id());\n                    None\n                }\n            }\n        })\n    }\n}\n\n/// Warn if any auto-enabled prepare providers are stale\npub fn notify_if_stale(config: &Arc<Config>) {\n    // Skip in shims or quiet mode\n    if *env::__MISE_SHIM || Settings::get().quiet {\n        return;\n    }\n\n    // Check if this feature is enabled\n    if !Settings::get().status.show_prepare_stale {\n        return;\n    }\n\n    let Ok(engine) = PrepareEngine::new(config) else {\n        return;\n    };\n\n    let stale = engine.check_staleness();\n    if !stale.is_empty() {\n        let providers: Vec<String> = stale\n            .iter()\n            .map(|(id, reason)| format!(\"{id} ({reason})\"))\n            .collect();\n        let summary = providers.join(\", \");\n        warn!(\"prepare: {summary} — run `mise prep`\");\n    }\n}\n\n/// Tracks directories created during this session that should be considered stale\n/// for prepare freshness checks (e.g., venvs auto-created before prepare runs)\nstatic STALE_OUTPUTS: LazyLock<Mutex<HashSet<PathBuf>>> =\n    LazyLock::new(|| Mutex::new(HashSet::new()));\n\n/// Mark a directory as freshly created (stale for prepare purposes)\npub fn mark_output_stale(path: PathBuf) {\n    if let Ok(mut set) = STALE_OUTPUTS.lock() {\n        set.insert(path);\n    }\n}\n\n/// Check if a directory was created this session\npub fn is_output_stale(path: &PathBuf) -> bool {\n    STALE_OUTPUTS\n        .lock()\n        .map(|set| set.contains(path))\n        .unwrap_or(false)\n}\n\n/// Clear stale status for a path (after prepare runs successfully)\npub fn clear_output_stale(path: &PathBuf) {\n    if let Ok(mut set) = STALE_OUTPUTS.lock() {\n        set.remove(path);\n    }\n}\n\n/// Detect which built-in prepare providers are applicable for a given directory\n///\n/// This checks if the lockfiles/config files for each provider exist.\npub fn detect_applicable_providers(project_root: &Path) -> Vec<String> {\n    use providers::*;\n    use rule::PrepareProviderConfig;\n\n    let default_config = PrepareProviderConfig::default();\n    let mut applicable = Vec::new();\n\n    // Check each built-in provider\n    let checks: &[(&str, Box<dyn PrepareProvider>)] = &[\n        (\n            \"npm\",\n            Box::new(NpmPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"yarn\",\n            Box::new(YarnPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"pnpm\",\n            Box::new(PnpmPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"bun\",\n            Box::new(BunPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"go\",\n            Box::new(GoPrepareProvider::new(project_root, default_config.clone())),\n        ),\n        (\n            \"pip\",\n            Box::new(PipPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"poetry\",\n            Box::new(PoetryPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"uv\",\n            Box::new(UvPrepareProvider::new(project_root, default_config.clone())),\n        ),\n        (\n            \"bundler\",\n            Box::new(BundlerPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"composer\",\n            Box::new(ComposerPrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n        (\n            \"git-submodule\",\n            Box::new(GitSubmodulePrepareProvider::new(\n                project_root,\n                default_config.clone(),\n            )),\n        ),\n    ];\n\n    for (name, provider) in checks {\n        if provider.is_applicable() {\n            applicable.push(name.to_string());\n        }\n    }\n\n    applicable\n}\n"
  },
  {
    "path": "src/prepare/prepare_deps.rs",
    "content": "use eyre::{Result, bail};\nuse tokio::sync::mpsc;\n\nuse crate::deps_graph::DepsGraph;\n\n/// Manages a dependency graph of prepare providers for execution scheduling.\n/// Thin wrapper around `DepsGraph<String, String>` with prepare-specific\n/// validation and error messages.\n#[derive(Debug)]\npub struct PrepareDeps {\n    inner: DepsGraph<String, String>,\n}\n\nimpl PrepareDeps {\n    /// Creates a new PrepareDeps from a list of (provider_id, depends) tuples.\n    pub fn new(providers: &[(String, Vec<String>)]) -> Result<Self> {\n        // Validate that all deps reference known providers before building the graph\n        let known: std::collections::HashSet<&str> =\n            providers.iter().map(|(id, _)| id.as_str()).collect();\n        for (id, deps) in providers {\n            for dep in deps {\n                if !known.contains(dep.as_str()) {\n                    bail!(\n                        \"prepare provider '{}' depends on unknown provider '{}'\",\n                        id,\n                        dep\n                    );\n                }\n            }\n        }\n\n        let nodes: Vec<(String, String)> = providers\n            .iter()\n            .map(|(id, _)| (id.clone(), id.clone()))\n            .collect();\n\n        let edges: Vec<(String, String)> = providers\n            .iter()\n            .flat_map(|(id, deps)| deps.iter().map(move |dep| (id.clone(), dep.clone())))\n            .collect();\n\n        let inner = DepsGraph::new(nodes, edges, |s: &String| s.clone())?;\n        Ok(Self { inner })\n    }\n\n    /// Subscribe to receive providers that are ready to run.\n    pub fn subscribe(&mut self) -> mpsc::UnboundedReceiver<Option<String>> {\n        self.inner.subscribe()\n    }\n\n    /// Mark a provider as successfully completed.\n    pub fn complete_success(&mut self, id: &str) {\n        self.inner.complete_success(&id.to_string());\n    }\n\n    /// Mark a provider as failed and block all transitive dependents.\n    pub fn complete_failure(&mut self, id: &str) {\n        self.inner.complete_failure(&id.to_string());\n    }\n\n    /// Returns the list of blocked provider IDs.\n    pub fn blocked_providers(&self) -> Vec<String> {\n        self.inner.blocked_keys()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_graph() {\n        let _deps = PrepareDeps::new(&[]).unwrap();\n    }\n\n    #[test]\n    fn test_no_deps_all_ready() {\n        let providers = vec![\n            (\"npm\".to_string(), vec![]),\n            (\"pip\".to_string(), vec![]),\n            (\"go\".to_string(), vec![]),\n        ];\n        let mut deps = PrepareDeps::new(&providers).unwrap();\n        let mut rx = deps.subscribe();\n\n        let mut emitted = vec![];\n        while let Ok(Some(id)) = rx.try_recv() {\n            emitted.push(id);\n        }\n        assert_eq!(emitted.len(), 3);\n        assert!(emitted.contains(&\"npm\".to_string()));\n        assert!(emitted.contains(&\"pip\".to_string()));\n        assert!(emitted.contains(&\"go\".to_string()));\n    }\n\n    #[test]\n    fn test_linear_ordering() {\n        let providers = vec![\n            (\"a\".to_string(), vec![]),\n            (\"b\".to_string(), vec![\"a\".to_string()]),\n            (\"c\".to_string(), vec![\"b\".to_string()]),\n        ];\n        let mut deps = PrepareDeps::new(&providers).unwrap();\n        let mut rx = deps.subscribe();\n\n        let first = rx.try_recv().unwrap().unwrap();\n        assert_eq!(first, \"a\");\n        assert!(rx.try_recv().is_err());\n\n        deps.complete_success(\"a\");\n        let second = rx.try_recv().unwrap().unwrap();\n        assert_eq!(second, \"b\");\n\n        deps.complete_success(\"b\");\n        let third = rx.try_recv().unwrap().unwrap();\n        assert_eq!(third, \"c\");\n\n        deps.complete_success(\"c\");\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_failure_blocks_dependents() {\n        let providers = vec![\n            (\"a\".to_string(), vec![]),\n            (\"b\".to_string(), vec![\"a\".to_string()]),\n            (\"c\".to_string(), vec![\"b\".to_string()]),\n            (\"d\".to_string(), vec![]),\n        ];\n        let mut deps = PrepareDeps::new(&providers).unwrap();\n        let mut rx = deps.subscribe();\n\n        let mut initial = vec![];\n        while let Ok(Some(id)) = rx.try_recv() {\n            initial.push(id);\n        }\n        assert_eq!(initial.len(), 2);\n        assert!(initial.contains(&\"a\".to_string()));\n        assert!(initial.contains(&\"d\".to_string()));\n\n        deps.complete_failure(\"a\");\n        let blocked = deps.blocked_providers();\n        assert!(blocked.contains(&\"b\".to_string()));\n        assert!(blocked.contains(&\"c\".to_string()));\n\n        deps.complete_success(\"d\");\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_cycle_detection() {\n        let providers = vec![\n            (\"a\".to_string(), vec![\"b\".to_string()]),\n            (\"b\".to_string(), vec![\"a\".to_string()]),\n            (\"c\".to_string(), vec![]),\n        ];\n        let mut deps = PrepareDeps::new(&providers).unwrap();\n\n        let blocked = deps.blocked_providers();\n        assert!(blocked.contains(&\"a\".to_string()));\n        assert!(blocked.contains(&\"b\".to_string()));\n\n        let mut rx = deps.subscribe();\n        let first = rx.try_recv().unwrap().unwrap();\n        assert_eq!(first, \"c\");\n\n        deps.complete_success(\"c\");\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n\n    #[test]\n    fn test_unknown_dep_error() {\n        let providers = vec![(\"a\".to_string(), vec![\"nonexistent\".to_string()])];\n        let result = PrepareDeps::new(&providers);\n        assert!(result.is_err());\n        assert!(result.unwrap_err().to_string().contains(\"unknown provider\"));\n    }\n\n    #[test]\n    fn test_diamond_deps() {\n        let providers = vec![\n            (\"d\".to_string(), vec![]),\n            (\"b\".to_string(), vec![\"d\".to_string()]),\n            (\"c\".to_string(), vec![\"d\".to_string()]),\n            (\"a\".to_string(), vec![\"b\".to_string(), \"c\".to_string()]),\n        ];\n        let mut deps = PrepareDeps::new(&providers).unwrap();\n        let mut rx = deps.subscribe();\n\n        let first = rx.try_recv().unwrap().unwrap();\n        assert_eq!(first, \"d\");\n        assert!(rx.try_recv().is_err());\n\n        deps.complete_success(\"d\");\n        let mut mid = vec![];\n        while let Ok(Some(id)) = rx.try_recv() {\n            mid.push(id);\n        }\n        assert_eq!(mid.len(), 2);\n        assert!(mid.contains(&\"b\".to_string()));\n        assert!(mid.contains(&\"c\".to_string()));\n\n        deps.complete_success(\"b\");\n        deps.complete_success(\"c\");\n        let last = rx.try_recv().unwrap().unwrap();\n        assert_eq!(last, \"a\");\n\n        deps.complete_success(\"a\");\n        let done = rx.try_recv().unwrap();\n        assert!(done.is_none());\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/bun.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for bun (bun.lockb or bun.lock)\n#[derive(Debug)]\npub struct BunPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl BunPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"bun\", project_root, config),\n        }\n    }\n\n    fn lockfile_path(&self) -> Option<PathBuf> {\n        let root = self.base.config_root();\n        // Bun supports both bun.lockb (binary) and bun.lock (text)\n        let binary_lock = root.join(\"bun.lockb\");\n        if binary_lock.exists() {\n            return Some(binary_lock);\n        }\n        let text_lock = root.join(\"bun.lock\");\n        if text_lock.exists() {\n            return Some(text_lock);\n        }\n        None\n    }\n}\n\nimpl PrepareProvider for BunPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let mut sources = vec![];\n        if let Some(lockfile) = self.lockfile_path() {\n            sources.push(lockfile);\n        }\n        sources.push(self.base.config_root().join(\"package.json\"));\n        sources\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"node_modules\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"bun\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"bun install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.lockfile_path().is_some()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/bundler.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for Ruby Bundler (Gemfile.lock)\n#[derive(Debug)]\npub struct BundlerPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl BundlerPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"bundler\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for BundlerPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"Gemfile.lock\"), root.join(\"Gemfile\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        // Check for vendor/bundle if using --path vendor/bundle\n        let vendor = root.join(\"vendor/bundle\");\n        if vendor.exists() {\n            vec![vendor]\n        } else {\n            // Use .bundle directory as fallback indicator\n            vec![root.join(\".bundle\")]\n        }\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"bundle\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"bundle install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"Gemfile.lock\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/composer.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for PHP Composer (composer.lock)\n#[derive(Debug)]\npub struct ComposerPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl ComposerPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"composer\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for ComposerPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"composer.lock\"), root.join(\"composer.json\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"vendor\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"composer\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"composer install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"composer.lock\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/custom.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\nuse glob::glob;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for user-defined custom rules from mise.toml [prepare.*]\n#[derive(Debug)]\npub struct CustomPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl CustomPrepareProvider {\n    pub fn new(id: String, config: PrepareProviderConfig, project_root: &Path) -> Self {\n        Self {\n            base: ProviderBase::new(id, project_root, config),\n        }\n    }\n\n    /// Expand glob patterns in sources/outputs\n    fn expand_globs(&self, patterns: &[String]) -> Vec<PathBuf> {\n        let mut paths = vec![];\n\n        for pattern in patterns {\n            let base_dir = self.base.config_root();\n            let full_pattern = if PathBuf::from(pattern).is_relative() {\n                base_dir.join(pattern)\n            } else {\n                PathBuf::from(pattern)\n            };\n\n            // Check if it's a glob pattern\n            if pattern.contains('*') || pattern.contains('{') || pattern.contains('?') {\n                if let Ok(entries) = glob(full_pattern.to_string_lossy().as_ref()) {\n                    for entry in entries.flatten() {\n                        paths.push(entry);\n                    }\n                }\n            } else if full_pattern.exists() {\n                paths.push(full_pattern);\n            } else {\n                // Include even if doesn't exist (for outputs that may not exist yet)\n                paths.push(full_pattern);\n            }\n        }\n\n        paths\n    }\n}\n\nimpl PrepareProvider for CustomPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        self.expand_globs(&self.base.config.sources)\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        self.expand_globs(&self.base.config.outputs)\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        let run = self\n            .base\n            .config\n            .run\n            .as_ref()\n            .ok_or_else(|| eyre::eyre!(\"prepare rule {} has no run command\", self.base.id))?;\n\n        PrepareCommand::from_string(run, &self.base.project_root, &self.base.config)\n    }\n\n    fn is_applicable(&self) -> bool {\n        // Custom providers require a run command to be applicable\n        self.base.config.run.is_some()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/git_submodule.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for git submodules (.gitmodules)\n#[derive(Debug)]\npub struct GitSubmodulePrepareProvider {\n    base: ProviderBase,\n}\n\nimpl GitSubmodulePrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"git-submodule\", project_root, config),\n        }\n    }\n\n    /// Parse submodule paths from .gitmodules file\n    ///\n    /// Handles INI-style sections and comments. Only extracts `path` values\n    /// from `[submodule \"...\"]` sections.\n    fn submodule_paths(&self) -> Vec<PathBuf> {\n        let gitmodules = self.base.config_root().join(\".gitmodules\");\n        let Ok(content) = std::fs::read_to_string(&gitmodules) else {\n            return vec![];\n        };\n\n        let mut in_submodule_section = false;\n        content\n            .lines()\n            .filter_map(|line| {\n                let line = line.trim();\n                if line.starts_with('#') || line.starts_with(';') {\n                    return None;\n                }\n                if line.starts_with(\"[submodule \") || line.starts_with(\"[submodule\\\"\") {\n                    in_submodule_section = true;\n                    return None;\n                }\n                if line.starts_with('[') {\n                    in_submodule_section = false;\n                    return None;\n                }\n                if !in_submodule_section {\n                    return None;\n                }\n                if let Some(value) = line.strip_prefix(\"path\") {\n                    let value = value.trim_start();\n                    value\n                        .strip_prefix('=')\n                        .map(|value| self.base.config_root().join(value.trim()))\n                } else {\n                    None\n                }\n            })\n            .collect()\n    }\n}\n\nimpl PrepareProvider for GitSubmodulePrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\".gitmodules\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        self.submodule_paths()\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"git\".to_string(),\n            args: vec![\n                \"submodule\".to_string(),\n                \"update\".to_string(),\n                \"--init\".to_string(),\n                \"--recursive\".to_string(),\n            ],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"git submodule update --init --recursive\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        let gitmodules = self.base.config_root().join(\".gitmodules\");\n        gitmodules.exists() && gitmodules.metadata().map(|m| m.len() > 0).unwrap_or(false)\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/go.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for Go (go.sum)\n#[derive(Debug)]\npub struct GoPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl GoPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"go\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for GoPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        // go.mod defines dependencies - changes here trigger downloads\n        vec![self.base.config_root().join(\"go.mod\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        // Go downloads modules to GOPATH/pkg/mod, but we can check vendor/ if used\n        let vendor = root.join(\"vendor\");\n        if vendor.exists() {\n            vec![vendor]\n        } else {\n            // go.sum gets updated after go mod download completes\n            vec![root.join(\"go.sum\")]\n        }\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        // Use `go mod vendor` if vendor/ exists, otherwise `go mod download`\n        let vendor = self.base.config_root().join(\"vendor\");\n        let (args, desc) = if vendor.exists() {\n            (\n                vec![\"mod\".to_string(), \"vendor\".to_string()],\n                \"go mod vendor\",\n            )\n        } else {\n            (\n                vec![\"mod\".to_string(), \"download\".to_string()],\n                \"go mod download\",\n            )\n        };\n\n        Ok(PrepareCommand {\n            program: \"go\".to_string(),\n            args,\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| desc.to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        // Check for go.mod (the source/lockfile), not go.sum (which may be an output)\n        self.base.config_root().join(\"go.mod\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/mod.rs",
    "content": "mod bun;\nmod bundler;\nmod composer;\nmod custom;\nmod git_submodule;\nmod go;\nmod npm;\nmod pip;\nmod pnpm;\nmod poetry;\nmod uv;\nmod yarn;\n\npub use bun::BunPrepareProvider;\npub use bundler::BundlerPrepareProvider;\npub use composer::ComposerPrepareProvider;\npub use custom::CustomPrepareProvider;\npub use git_submodule::GitSubmodulePrepareProvider;\npub use go::GoPrepareProvider;\npub use npm::NpmPrepareProvider;\npub use pip::PipPrepareProvider;\npub use pnpm::PnpmPrepareProvider;\npub use poetry::PoetryPrepareProvider;\npub use uv::UvPrepareProvider;\npub use yarn::YarnPrepareProvider;\n\nuse std::path::{Path, PathBuf};\n\nuse crate::prepare::rule::PrepareProviderConfig;\n\n/// Shared base for all prepare providers, holding the id, project root, and config.\n/// Provides common implementations for `id` and `is_auto`.\n#[derive(Debug)]\npub struct ProviderBase {\n    pub(crate) id: String,\n    pub(crate) project_root: PathBuf,\n    pub(crate) config: PrepareProviderConfig,\n}\n\nimpl ProviderBase {\n    pub fn new(id: impl Into<String>, project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            id: id.into(),\n            project_root: project_root.to_path_buf(),\n            config,\n        }\n    }\n\n    pub fn is_auto(&self) -> bool {\n        self.config.auto\n    }\n\n    /// Returns the effective root directory for resolving sources/outputs.\n    /// When `dir` is set in config, returns `project_root/dir`; otherwise `project_root`.\n    pub fn config_root(&self) -> PathBuf {\n        match &self.config.dir {\n            Some(dir) => self.project_root.join(dir),\n            None => self.project_root.clone(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/npm.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for npm (package-lock.json)\n#[derive(Debug)]\npub struct NpmPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl NpmPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"npm\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for NpmPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"package-lock.json\"), root.join(\"package.json\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"node_modules\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"npm\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"npm install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"package-lock.json\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/pip.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for pip (requirements.txt)\n#[derive(Debug)]\npub struct PipPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl PipPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"pip\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for PipPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"requirements.txt\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        // Check for .venv directory as output indicator\n        vec![self.base.config_root().join(\".venv\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"pip\".to_string(),\n            args: vec![\n                \"install\".to_string(),\n                \"-r\".to_string(),\n                \"requirements.txt\".to_string(),\n            ],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"pip install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"requirements.txt\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/pnpm.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for pnpm (pnpm-lock.yaml)\n#[derive(Debug)]\npub struct PnpmPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl PnpmPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"pnpm\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for PnpmPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"pnpm-lock.yaml\"), root.join(\"package.json\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"node_modules\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"pnpm\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"pnpm install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"pnpm-lock.yaml\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/poetry.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for Poetry (poetry.lock)\n#[derive(Debug)]\npub struct PoetryPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl PoetryPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"poetry\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for PoetryPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"poetry.lock\"), root.join(\"pyproject.toml\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\".venv\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"poetry\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"poetry install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"poetry.lock\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/uv.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for uv (uv.lock)\n#[derive(Debug)]\npub struct UvPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl UvPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"uv\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for UvPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"uv.lock\"), root.join(\"pyproject.toml\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\".venv\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"uv\".to_string(),\n            args: vec![\"sync\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"uv sync\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"uv.lock\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/providers/yarn.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::prepare::rule::PrepareProviderConfig;\nuse crate::prepare::{PrepareCommand, PrepareProvider};\n\nuse super::ProviderBase;\n\n/// Prepare provider for yarn (yarn.lock)\n#[derive(Debug)]\npub struct YarnPrepareProvider {\n    base: ProviderBase,\n}\n\nimpl YarnPrepareProvider {\n    pub fn new(project_root: &Path, config: PrepareProviderConfig) -> Self {\n        Self {\n            base: ProviderBase::new(\"yarn\", project_root, config),\n        }\n    }\n}\n\nimpl PrepareProvider for YarnPrepareProvider {\n    fn base(&self) -> &ProviderBase {\n        &self.base\n    }\n\n    fn sources(&self) -> Vec<PathBuf> {\n        let root = self.base.config_root();\n        vec![root.join(\"yarn.lock\"), root.join(\"package.json\")]\n    }\n\n    fn outputs(&self) -> Vec<PathBuf> {\n        vec![self.base.config_root().join(\"node_modules\")]\n    }\n\n    fn prepare_command(&self) -> Result<PrepareCommand> {\n        if let Some(run) = &self.base.config.run {\n            return PrepareCommand::from_string(run, &self.base.project_root, &self.base.config);\n        }\n\n        Ok(PrepareCommand {\n            program: \"yarn\".to_string(),\n            args: vec![\"install\".to_string()],\n            env: self.base.config.env.clone(),\n            cwd: Some(self.base.config_root()),\n            description: self\n                .base\n                .config\n                .description\n                .clone()\n                .unwrap_or_else(|| \"yarn install\".to_string()),\n        })\n    }\n\n    fn is_applicable(&self) -> bool {\n        self.base.config_root().join(\"yarn.lock\").exists()\n    }\n}\n"
  },
  {
    "path": "src/prepare/rule.rs",
    "content": "use std::collections::BTreeMap;\n\nuse serde::{Deserialize, Serialize};\n\n/// List of built-in provider names that have specialized implementations\npub const BUILTIN_PROVIDERS: &[&str] = &[\n    \"npm\",\n    \"yarn\",\n    \"pnpm\",\n    \"bun\",           // Node.js\n    \"go\",            // Go\n    \"pip\",           // Python (requirements.txt)\n    \"poetry\",        // Python (poetry)\n    \"uv\",            // Python (uv)\n    \"bundler\",       // Ruby\n    \"composer\",      // PHP\n    \"git-submodule\", // Git\n];\n\n/// Configuration for a prepare provider (both built-in and custom)\n///\n/// Built-in providers have auto-detected sources/outputs and default run commands.\n/// Custom providers require explicit sources, outputs, and run.\n#[derive(Debug, Clone, Default, Deserialize, Serialize)]\n#[serde(deny_unknown_fields)]\npub struct PrepareProviderConfig {\n    /// Whether to auto-run this provider before mise x/run (default: false)\n    #[serde(default)]\n    pub auto: bool,\n    /// Command to run when stale (required for custom, optional override for built-in)\n    pub run: Option<String>,\n    /// Files/patterns to check for changes (required for custom, auto-detected for built-in)\n    #[serde(default)]\n    pub sources: Vec<String>,\n    /// Files/directories that should be newer than sources (required for custom, auto-detected for built-in)\n    #[serde(default)]\n    pub outputs: Vec<String>,\n    /// Environment variables to set\n    #[serde(default)]\n    pub env: BTreeMap<String, String>,\n    /// Working directory\n    pub dir: Option<String>,\n    /// Optional description\n    pub description: Option<String>,\n    /// Other prepare providers that must complete before this one runs\n    #[serde(default)]\n    pub depends: Vec<String>,\n    /// Timeout for the run command (e.g., \"30s\", \"5m\", \"1h\")\n    pub timeout: Option<String>,\n}\n\nimpl PrepareProviderConfig {\n    /// Check if this is a custom rule (has explicit run command and is not a built-in name)\n    pub fn is_custom(&self, name: &str) -> bool {\n        !BUILTIN_PROVIDERS.contains(&name) && self.run.is_some()\n    }\n}\n\n/// Top-level [prepare] configuration section\n///\n/// All providers are configured at the same level:\n/// - `[prepare.npm]` - built-in npm provider\n/// - `[prepare.codegen]` - custom provider\n#[derive(Debug, Clone, Default, Deserialize, Serialize)]\npub struct PrepareConfig {\n    /// List of provider IDs to disable at runtime\n    #[serde(default)]\n    pub disable: Vec<String>,\n    /// All provider configurations (both built-in and custom)\n    #[serde(flatten)]\n    pub providers: BTreeMap<String, PrepareProviderConfig>,\n}\n\nimpl PrepareConfig {\n    /// Merge two PrepareConfigs, with `other` taking precedence\n    pub fn merge(&self, other: &PrepareConfig) -> PrepareConfig {\n        let mut providers = self.providers.clone();\n        for (k, v) in &other.providers {\n            providers.insert(k.clone(), v.clone());\n        }\n\n        let mut disable = self.disable.clone();\n        disable.extend(other.disable.clone());\n\n        PrepareConfig { disable, providers }\n    }\n\n    /// Get a provider config by name\n    pub fn get(&self, name: &str) -> Option<&PrepareProviderConfig> {\n        self.providers.get(name)\n    }\n}\n"
  },
  {
    "path": "src/prepare/state.rs",
    "content": "use std::collections::BTreeMap;\nuse std::path::{Path, PathBuf};\n\nuse eyre::Result;\n\nuse crate::file;\nuse crate::hash::file_hash_blake3;\n\n/// Persistent state for prepare freshness checking.\n///\n/// Stores blake3 content hashes of source files keyed by provider ID.\n/// Persisted to `.mise/prepare-state.toml`.\n#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]\npub struct PrepareState {\n    /// provider_id → (relative_path → blake3_hex)\n    #[serde(default)]\n    pub providers: BTreeMap<String, BTreeMap<String, String>>,\n}\n\nimpl PrepareState {\n    /// Load state from `.mise/prepare-state.toml`, returning default if not found.\n    pub fn load(project_root: &Path) -> Self {\n        let path = state_path(project_root);\n        if !path.exists() {\n            return Self::default();\n        }\n        match file::read_to_string(&path) {\n            Ok(contents) => match toml::from_str(&contents) {\n                Ok(state) => state,\n                Err(e) => {\n                    warn!(\"failed to parse {}: {e}\", path.display());\n                    Self::default()\n                }\n            },\n            Err(e) => {\n                warn!(\"failed to read {}: {e}\", path.display());\n                Self::default()\n            }\n        }\n    }\n\n    /// Save state to `.mise/prepare-state.toml`.\n    pub fn save(&self, project_root: &Path) -> Result<()> {\n        let path = state_path(project_root);\n        file::create_dir_all(path.parent().unwrap())?;\n        let contents = toml::to_string_pretty(self)?;\n        file::write(&path, contents)?;\n        Ok(())\n    }\n\n    /// Get stored hashes for a provider, or None if not previously recorded.\n    pub fn get_hashes(&self, provider_id: &str) -> Option<&BTreeMap<String, String>> {\n        self.providers.get(provider_id)\n    }\n\n    /// Update stored hashes for a provider.\n    pub fn set_hashes(&mut self, provider_id: &str, hashes: BTreeMap<String, String>) {\n        self.providers.insert(provider_id.to_string(), hashes);\n    }\n}\n\n/// Compute blake3 hashes for a list of source files.\n///\n/// Returns a map of relative_path → blake3_hex. Directories are skipped\n/// (only regular files are hashed). Non-existent files are omitted.\npub fn hash_sources(sources: &[PathBuf], project_root: &Path) -> Result<BTreeMap<String, String>> {\n    let mut hashes = BTreeMap::new();\n\n    for source in sources {\n        if !source.exists() {\n            continue;\n        }\n\n        if source.is_dir() {\n            // For directories, hash all files within (up to 3 levels deep)\n            hash_dir_files(&mut hashes, source, project_root, 3)?;\n        } else {\n            let hash = file_hash_blake3(source, None)?;\n            let rel = source\n                .strip_prefix(project_root)\n                .unwrap_or(source)\n                .to_string_lossy()\n                .to_string();\n            hashes.insert(rel, hash);\n        }\n    }\n\n    Ok(hashes)\n}\n\n/// Recursively hash files in a directory up to max_depth levels.\nfn hash_dir_files(\n    hashes: &mut BTreeMap<String, String>,\n    dir: &Path,\n    project_root: &Path,\n    max_depth: usize,\n) -> Result<()> {\n    if max_depth == 0 {\n        return Ok(());\n    }\n    if let Ok(entries) = std::fs::read_dir(dir) {\n        for entry in entries.flatten() {\n            let path = entry.path();\n            if path.is_dir() {\n                hash_dir_files(hashes, &path, project_root, max_depth - 1)?;\n            } else {\n                let hash = file_hash_blake3(&path, None)?;\n                let rel = path\n                    .strip_prefix(project_root)\n                    .unwrap_or(&path)\n                    .to_string_lossy()\n                    .to_string();\n                hashes.insert(rel, hash);\n            }\n        }\n    }\n    Ok(())\n}\n\n/// Path to the state file for a given project root.\nfn state_path(project_root: &Path) -> PathBuf {\n    project_root.join(\".mise\").join(\"prepare-state.toml\")\n}\n"
  },
  {
    "path": "src/rand.rs",
    "content": "use rand::Rng;\nuse rand::distr::Alphanumeric;\n\npub fn random_string(length: usize) -> String {\n    rand::rng()\n        .sample_iter(&Alphanumeric)\n        .take(length)\n        .map(char::from)\n        .collect::<String>()\n}\n"
  },
  {
    "path": "src/redactions.rs",
    "content": "use aho_corasick::AhoCorasick;\nuse indexmap::IndexSet;\nuse std::sync::Arc;\n\n#[derive(Default, Clone, Debug, serde::Deserialize)]\npub struct Redactions(pub IndexSet<String>);\n\nimpl Redactions {\n    pub fn merge(&mut self, other: Self) {\n        self.0.extend(other.0);\n    }\n\n    pub fn render(&mut self, tera: &mut tera::Tera, ctx: &tera::Context) -> eyre::Result<()> {\n        for r in self.0.clone().drain(..) {\n            self.0.insert(tera.render_str(&r, ctx)?);\n        }\n        Ok(())\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\n/// A redactor that uses Aho-Corasick for efficient multi-pattern string replacement.\n///\n/// This is more efficient than iterating through patterns and calling `str::replace()`\n/// for each one, especially when there are many patterns. Aho-Corasick finds all\n/// matches in a single pass through the text - O(n + z) vs O(n * m).\n#[derive(Clone)]\npub struct Redactor {\n    patterns: Arc<IndexSet<String>>,\n    automaton: Option<Arc<AhoCorasick>>,\n}\n\nimpl Default for Redactor {\n    fn default() -> Self {\n        Self {\n            patterns: Arc::new(IndexSet::new()),\n            automaton: None,\n        }\n    }\n}\n\nimpl Redactor {\n    /// Create a new redactor from a set of patterns to redact.\n    pub fn new(patterns: impl IntoIterator<Item = String>) -> Self {\n        let patterns: IndexSet<String> = patterns.into_iter().filter(|p| !p.is_empty()).collect();\n        let automaton = if patterns.is_empty() {\n            None\n        } else {\n            // Build the Aho-Corasick automaton - O(m) where m is total pattern length\n            AhoCorasick::new(patterns.iter()).ok().map(Arc::new)\n        };\n        Self {\n            patterns: Arc::new(patterns),\n            automaton,\n        }\n    }\n\n    /// Create a new redactor by adding more patterns to an existing one.\n    pub fn with_additional(&self, additional: impl IntoIterator<Item = String>) -> Self {\n        let mut patterns = (*self.patterns).clone();\n        for p in additional {\n            if !p.is_empty() {\n                patterns.insert(p);\n            }\n        }\n        Self::new(patterns)\n    }\n\n    /// Returns the patterns being redacted.\n    #[cfg_attr(not(test), allow(dead_code))]\n    pub fn patterns(&self) -> &IndexSet<String> {\n        &self.patterns\n    }\n\n    /// Returns the patterns as an Arc for efficient sharing.\n    pub fn patterns_arc(&self) -> Arc<IndexSet<String>> {\n        Arc::clone(&self.patterns)\n    }\n\n    /// Redact all matching patterns in the input string, replacing them with `[redacted]`.\n    ///\n    /// This is O(n + z) where n is the input length and z is the number of matches,\n    /// compared to O(n * m) for the naive approach of iterating through m patterns.\n    pub fn redact(&self, input: &str) -> String {\n        match &self.automaton {\n            Some(ac) => {\n                // Each pattern needs its own replacement string\n                let replacements: Vec<&str> = vec![\"[redacted]\"; self.patterns.len()];\n                ac.replace_all(input, &replacements)\n            }\n            None if self.patterns.is_empty() => input.to_string(),\n            None => {\n                // Fallback to naive approach if automaton failed to build\n                let mut result = input.to_string();\n                for pattern in self.patterns.iter() {\n                    result = result.replace(pattern, \"[redacted]\");\n                }\n                result\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_redactor() {\n        let r = Redactor::default();\n        assert_eq!(r.redact(\"hello world\"), \"hello world\");\n    }\n\n    #[test]\n    fn test_single_pattern() {\n        let r = Redactor::new([\"secret\".to_string()]);\n        assert_eq!(r.redact(\"my secret value\"), \"my [redacted] value\");\n    }\n\n    #[test]\n    fn test_multiple_patterns() {\n        let r = Redactor::new([\"secret\".to_string(), \"password\".to_string()]);\n        assert_eq!(\n            r.redact(\"secret and password here\"),\n            \"[redacted] and [redacted] here\"\n        );\n    }\n\n    #[test]\n    fn test_overlapping_patterns() {\n        let r = Redactor::new([\"abc\".to_string(), \"bc\".to_string()]);\n        let result = r.redact(\"abcd\");\n        // Should replace \"abc\" first, leaving \"d\"\n        assert_eq!(result, \"[redacted]d\");\n    }\n\n    #[test]\n    fn test_multiple_occurrences() {\n        let r = Redactor::new([\"token\".to_string()]);\n        assert_eq!(r.redact(\"token1 and token2\"), \"[redacted]1 and [redacted]2\");\n    }\n\n    #[test]\n    fn test_with_additional() {\n        let r1 = Redactor::new([\"secret\".to_string()]);\n        let r2 = r1.with_additional([\"password\".to_string()]);\n\n        assert_eq!(r1.redact(\"secret password\"), \"[redacted] password\");\n        assert_eq!(r2.redact(\"secret password\"), \"[redacted] [redacted]\");\n    }\n\n    #[test]\n    fn test_empty_patterns_filtered() {\n        let r = Redactor::new([\"\".to_string(), \"secret\".to_string(), \"\".to_string()]);\n        assert_eq!(r.patterns().len(), 1);\n        assert_eq!(r.redact(\"my secret\"), \"my [redacted]\");\n    }\n}\n"
  },
  {
    "path": "src/registry.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::config::Settings;\nuse crate::toolset::ToolVersionOptions;\nuse heck::ToShoutySnakeCase;\nuse indexmap::IndexMap;\nuse std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};\nuse std::env;\nuse std::env::consts::{ARCH, OS};\nuse std::fmt::Display;\nuse std::iter::Iterator;\nuse std::sync::{LazyLock as Lazy, Mutex};\nuse strum::IntoEnumIterator;\nuse url::Url;\n\n// the registry is generated from registry/ in the project root\npub static REGISTRY: Lazy<BTreeMap<&'static str, RegistryTool>> =\n    Lazy::new(|| include!(concat!(env!(\"OUT_DIR\"), \"/registry.rs\")));\n\n#[derive(Debug, Clone)]\npub struct RegistryTool {\n    pub short: &'static str,\n    pub description: Option<&'static str>,\n    pub backends: &'static [RegistryBackend],\n    #[allow(unused)]\n    pub aliases: &'static [&'static str],\n    pub overrides: &'static [&'static str],\n    pub test: &'static Option<(&'static str, &'static str)>,\n    pub os: &'static [&'static str],\n    pub depends: &'static [&'static str],\n    pub idiomatic_files: &'static [&'static str],\n    pub detect: &'static [&'static str],\n}\n\n#[derive(Debug, Clone)]\npub struct RegistryBackend {\n    pub full: &'static str,\n    pub platforms: &'static [&'static str],\n    pub options: &'static [(&'static str, &'static str)],\n}\n\n// Cache for environment variable overrides\nstatic ENV_BACKENDS: Lazy<Mutex<HashMap<String, &'static str>>> =\n    Lazy::new(|| Mutex::new(HashMap::new()));\n\nimpl RegistryTool {\n    pub fn backends(&self) -> Vec<&'static str> {\n        // Check for environment variable override first\n        // e.g., MISE_BACKENDS_GRAPHITE='github:withgraphite/homebrew-tap[exe=gt]'\n        let env_key = format!(\"MISE_BACKENDS_{}\", self.short.to_shouty_snake_case());\n\n        // Check cache first\n        {\n            let cache = ENV_BACKENDS.lock().unwrap();\n            if let Some(&backend) = cache.get(&env_key) {\n                return vec![backend];\n            }\n        }\n\n        // Check environment variable\n        if let Ok(env_value) = env::var(&env_key) {\n            // Store in cache with 'static lifetime\n            let leaked = Box::leak(env_value.into_boxed_str());\n            let mut cache = ENV_BACKENDS.lock().unwrap();\n            cache.insert(env_key.clone(), leaked);\n            return vec![leaked];\n        }\n\n        static BACKEND_TYPES: Lazy<HashSet<String>> = Lazy::new(|| {\n            let mut backend_types = BackendType::iter()\n                .map(|b| b.to_string())\n                .collect::<HashSet<_>>();\n            time!(\"disable_backends\");\n            for backend in &Settings::get().disable_backends {\n                backend_types.remove(backend);\n            }\n            time!(\"disable_backends\");\n            if cfg!(windows) {\n                backend_types.remove(\"asdf\");\n            }\n            backend_types\n        });\n        let settings = Settings::get();\n        let os = settings.os.clone().unwrap_or(OS.to_string());\n        let arch = settings.arch.clone().unwrap_or(ARCH.to_string());\n        let platform = format!(\"{os}-{arch}\");\n        let experimental = settings.experimental;\n        self.backends\n            .iter()\n            .filter(|rb| {\n                rb.platforms.is_empty()\n                    || rb.platforms.contains(&&*os)\n                    || rb.platforms.contains(&&*arch)\n                    || rb.platforms.contains(&&*platform)\n            })\n            .map(|rb| rb.full)\n            .filter(|full| {\n                full.split(':')\n                    .next()\n                    .is_some_and(|b| BACKEND_TYPES.contains(b))\n            })\n            // Filter out experimental backends if experimental mode is disabled\n            .filter(|full| {\n                if experimental {\n                    return true;\n                }\n                let backend_type = BackendType::guess(full);\n                !backend_type.is_experimental()\n            })\n            .collect()\n    }\n\n    pub fn is_supported_os(&self) -> bool {\n        self.os.is_empty() || self.os.contains(&OS)\n    }\n\n    pub fn ba(&self) -> Option<BackendArg> {\n        self.backends()\n            .first()\n            .map(|f| BackendArg::new(self.short.to_string(), Some(f.to_string())))\n    }\n\n    /// Get RegistryBackend for a specific full backend string\n    pub fn get_backend(&self, full: &str) -> Option<&RegistryBackend> {\n        self.backends.iter().find(|rb| rb.full == full)\n    }\n\n    /// Get options for a specific backend\n    pub fn backend_options(&self, full: &str) -> ToolVersionOptions {\n        let mut opts = IndexMap::new();\n\n        if let Some(backend) = self.get_backend(full) {\n            for (k, v) in backend.options {\n                // Try to parse as TOML to preserve nested table structure\n                // (e.g., platforms with per-platform options like asset_pattern)\n                let value = match toml::from_str::<toml::Value>(v) {\n                    Ok(parsed) if parsed.is_table() => parsed,\n                    _ => toml::Value::String(v.to_string()),\n                };\n                opts.insert(k.to_string(), value);\n            }\n        }\n\n        ToolVersionOptions {\n            opts,\n            ..Default::default()\n        }\n    }\n}\n\npub fn shorts_for_full(full: &str) -> &'static Vec<&'static str> {\n    static EMPTY: Vec<&'static str> = vec![];\n    static FULL_TO_SHORT: Lazy<HashMap<&'static str, Vec<&'static str>>> = Lazy::new(|| {\n        let mut map: HashMap<&'static str, Vec<&'static str>> = HashMap::new();\n        for (short, rt) in REGISTRY.iter() {\n            for full in rt.backends() {\n                map.entry(full).or_default().push(short);\n            }\n        }\n        map\n    });\n    FULL_TO_SHORT.get(full).unwrap_or(&EMPTY)\n}\n\npub fn is_trusted_plugin(name: &str, remote: &str) -> bool {\n    let normalized_url = normalize_remote(remote).unwrap_or(\"INVALID_URL\".into());\n    let is_shorthand = REGISTRY\n        .get(name)\n        .and_then(|tool| tool.backends().first().copied())\n        .map(full_to_url)\n        .is_some_and(|s| normalize_remote(&s).unwrap_or_default() == normalized_url);\n    let is_mise_url = normalized_url.starts_with(\"github.com/mise-plugins/\");\n\n    !is_shorthand || is_mise_url\n}\n\npub fn normalize_remote(remote: &str) -> eyre::Result<String> {\n    let url = Url::parse(remote)?;\n    let host = url\n        .host_str()\n        .ok_or_else(|| eyre::eyre!(\"URL has no host: {remote}\"))?;\n    let path = url.path().trim_end_matches(\".git\");\n    Ok(format!(\"{host}{path}\"))\n}\n\npub fn full_to_url(full: &str) -> String {\n    if url_like(full) {\n        return full.to_string();\n    }\n    let (_backend, url) = full.split_once(':').unwrap_or((\"\", full));\n    if url_like(url) {\n        url.to_string()\n    } else {\n        format!(\"https://github.com/{url}.git\")\n    }\n}\n\nfn url_like(s: &str) -> bool {\n    s.starts_with(\"https://\")\n        || s.starts_with(\"http://\")\n        || s.starts_with(\"git@\")\n        || s.starts_with(\"ssh://\")\n        || s.starts_with(\"git://\")\n}\n\nimpl Display for RegistryTool {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.short)\n    }\n}\n\npub fn tool_enabled<T: Ord>(\n    enable_tools: &BTreeSet<T>,\n    disable_tools: &BTreeSet<T>,\n    name: &T,\n) -> bool {\n    if enable_tools.is_empty() {\n        !disable_tools.contains(name)\n    } else {\n        enable_tools.contains(name)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    #[tokio::test]\n    async fn test_tool_disabled() {\n        let _config = Config::get().await.unwrap();\n        use super::*;\n        let name = \"cargo\";\n\n        assert!(tool_enabled(&BTreeSet::new(), &BTreeSet::new(), &name));\n        assert!(tool_enabled(\n            &BTreeSet::from([\"cargo\"]),\n            &BTreeSet::new(),\n            &name\n        ));\n        assert!(!tool_enabled(\n            &BTreeSet::new(),\n            &BTreeSet::from([\"cargo\"]),\n            &name\n        ));\n    }\n\n    #[tokio::test]\n    async fn test_backend_env_override() {\n        let _config = Config::get().await.unwrap();\n        use super::*;\n\n        // Clear the cache first\n        ENV_BACKENDS.lock().unwrap().clear();\n\n        // Test with a known tool from the registry\n        if let Some(tool) = REGISTRY.get(\"node\") {\n            // First test without env var - should return default backends\n            let default_backends = tool.backends();\n            assert!(!default_backends.is_empty());\n\n            // Test with env var override\n            // SAFETY: This is safe in a test environment\n            unsafe {\n                env::set_var(\"MISE_BACKENDS_NODE\", \"test:backend\");\n            }\n            let overridden_backends = tool.backends();\n            assert_eq!(overridden_backends.len(), 1);\n            assert_eq!(overridden_backends[0], \"test:backend\");\n\n            // Clean up\n            // SAFETY: This is safe in a test environment\n            unsafe {\n                env::remove_var(\"MISE_BACKENDS_NODE\");\n            }\n            ENV_BACKENDS.lock().unwrap().clear();\n        }\n    }\n\n    #[test]\n    fn test_normalize_remote() {\n        use super::*;\n\n        // Standard HTTPS URLs should work\n        let result = normalize_remote(\"https://github.com/mise-plugins/vfox-node.git\");\n        assert!(result.is_ok());\n        assert_eq!(result.unwrap(), \"github.com/mise-plugins/vfox-node\");\n\n        // file:// URLs should return an error (no host)\n        let result = normalize_remote(\"file:///path/to/repo\");\n        assert!(result.is_err());\n\n        // Invalid URLs should return an error\n        let result = normalize_remote(\"not-a-url\");\n        assert!(result.is_err());\n    }\n}\n"
  },
  {
    "path": "src/result.rs",
    "content": "pub type Result<T> = eyre::Result<T>;\n"
  },
  {
    "path": "src/runtime_symlinks.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::sync::Arc;\n\nuse crate::backend::Backend;\nuse crate::config::{Alias, Config};\nuse crate::file::make_symlink_or_file;\nuse crate::plugins::VERSION_REGEX;\nuse crate::semver::split_version_prefix;\nuse crate::{backend, file};\nuse eyre::Result;\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse versions::Versioning;\n\npub async fn rebuild(config: &Config) -> Result<()> {\n    for backend in backend::list() {\n        let symlinks = list_symlinks(config, backend.clone());\n        let installs_dir = &backend.ba().installs_path;\n        for (from, to) in symlinks {\n            let from = installs_dir.join(from);\n            if from.exists() {\n                if is_runtime_symlink(&from)\n                    && file::resolve_symlink(&from)?.unwrap_or_default() != to\n                {\n                    trace!(\"Removing existing symlink: {}\", from.display());\n                    file::remove_file(&from)?;\n                } else {\n                    continue;\n                }\n            }\n            make_symlink_or_file(&to, &from)?;\n        }\n        remove_missing_symlinks(backend.clone())?;\n    }\n    Ok(())\n}\n\nfn list_symlinks(config: &Config, backend: Arc<dyn Backend>) -> IndexMap<String, PathBuf> {\n    // TODO: make this a pure function and add test cases\n    let mut symlinks = IndexMap::new();\n    let rel_path = |x: &String| PathBuf::from(\".\").join(x.clone());\n    for v in installed_versions(&backend) {\n        let (prefix, version) = split_version_prefix(&v);\n        let versions = Versioning::new(version).unwrap_or_default();\n        let mut partial = vec![];\n        while versions.nth(partial.len()).is_some() && versions.nth(partial.len() + 1).is_some() {\n            let version = versions.nth(partial.len()).unwrap();\n            partial.push(version.to_string());\n            let from = format!(\"{}{}\", prefix, partial.join(\".\"));\n            symlinks.insert(from, rel_path(&v));\n        }\n        symlinks.insert(format!(\"{prefix}latest\"), rel_path(&v));\n        for (from, to) in &config\n            .all_aliases\n            .get(&backend.ba().short)\n            .unwrap_or(&Alias::default())\n            .versions\n        {\n            if from.contains('/') {\n                continue;\n            }\n            if !v.starts_with(to) {\n                continue;\n            }\n            symlinks.insert(format!(\"{prefix}{from}\"), rel_path(&v));\n        }\n    }\n    symlinks = symlinks\n        .into_iter()\n        .sorted_by_cached_key(|(k, _)| (Versioning::new(k), k.to_string()))\n        .collect();\n    symlinks\n}\n\nfn installed_versions(backend: &Arc<dyn Backend>) -> Vec<String> {\n    backend\n        .list_installed_versions()\n        .into_iter()\n        .filter(|v| !VERSION_REGEX.is_match(v))\n        .collect()\n}\n\npub fn remove_missing_symlinks(backend: Arc<dyn Backend>) -> Result<()> {\n    let installs_dir = &backend.ba().installs_path;\n    if !installs_dir.exists() {\n        return Ok(());\n    }\n    for entry in std::fs::read_dir(installs_dir)? {\n        let entry = entry?;\n        let path = entry.path();\n        if is_runtime_symlink(&path) && !path.exists() {\n            trace!(\"Removing missing symlink: {}\", path.display());\n            file::remove_file(path)?;\n        }\n    }\n    // remove install dir if empty (ignore metadata)\n    file::remove_dir_ignore(installs_dir, vec![\".mise.backend.json\", \".mise.backend\"])?;\n    Ok(())\n}\n\npub fn is_runtime_symlink(path: &Path) -> bool {\n    if let Ok(Some(link)) = file::resolve_symlink(path) {\n        return link.starts_with(\"./\");\n    }\n    false\n}\n"
  },
  {
    "path": "src/semver.rs",
    "content": "use versions::{Mess, Versioning};\n\n/// splits a version number into an optional prefix and the remaining version string\npub fn split_version_prefix(version: &str) -> (String, String) {\n    version\n        .char_indices()\n        .find_map(|(i, c)| {\n            if c.is_ascii_digit() {\n                if i == 0 {\n                    return Some(i);\n                }\n                // If the previous char is a delimiter or 'v', we found a split point.\n                let prev_char = version.chars().nth(i - 1).unwrap();\n                if ['-', '_', '/', '.', 'v', 'V'].contains(&prev_char) {\n                    return Some(i);\n                }\n            }\n            None\n        })\n        .map_or_else(\n            || (\"\".into(), version.into()),\n            |i| {\n                let (prefix, version) = version.split_at(i);\n                (prefix.into(), version.into())\n            },\n        )\n}\n\n/// split a version number into chunks\n/// given v: \"1.2-3a4\" return [\"1\", \".2\", \"-3a4\"]\npub fn chunkify_version(v: &str) -> Vec<String> {\n    fn chunkify(m: &Mess, sep0: &str, chunks: &mut Vec<String>) {\n        for (i, chunk) in m.chunks.iter().enumerate() {\n            let sep = if i == 0 { sep0 } else { \".\" };\n            chunks.push(format!(\"{sep}{chunk}\"));\n        }\n        if let Some((next_sep, next_mess)) = &m.next {\n            chunkify(next_mess, next_sep.to_string().as_ref(), chunks)\n        }\n    }\n\n    let mut chunks = vec![];\n    // don't parse \"latest\", otherwise bump from latest to any version would have one chunk only\n    if v != \"latest\"\n        && let Some(v) = Versioning::new(v)\n    {\n        let m = match v {\n            Versioning::Ideal(sem_ver) => sem_ver.to_mess(),\n            Versioning::General(version) => version.to_mess(),\n            Versioning::Complex(mess) => mess,\n        };\n        chunkify(&m, \"\", &mut chunks);\n    }\n    chunks\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{chunkify_version, split_version_prefix};\n\n    #[test]\n    fn test_split_version_prefix() {\n        assert_eq!(split_version_prefix(\"latest\"), (\"\".into(), \"latest\".into()));\n        assert_eq!(split_version_prefix(\"v1.2.3\"), (\"v\".into(), \"1.2.3\".into()));\n        assert_eq!(\n            split_version_prefix(\"mountpoint-s3-v1.2.3-5_beta.5\"),\n            (\"mountpoint-s3-v\".into(), \"1.2.3-5_beta.5\".into())\n        );\n        assert_eq!(\n            split_version_prefix(\"cli/1.2.3\"),\n            (\"cli/\".into(), \"1.2.3\".into())\n        );\n        assert_eq!(\n            split_version_prefix(\"temurin-17.0.7+7\"),\n            (\"temurin-\".into(), \"17.0.7+7\".into())\n        );\n        assert_eq!(split_version_prefix(\"1.2\"), (\"\".into(), \"1.2\".into()));\n        assert_eq!(\n            split_version_prefix(\"2:1.2.1\"),\n            (\"\".into(), \"2:1.2.1\".into())\n        );\n        assert_eq!(\n            split_version_prefix(\"2025-05-17\"),\n            (\"\".into(), \"2025-05-17\".into())\n        );\n    }\n\n    #[test]\n    fn test_chunkify_version() {\n        assert_eq!(chunkify_version(\"1.2-3a4\"), vec![\"1\", \".2\", \"-3a4\"]);\n        assert_eq!(chunkify_version(\"latest\"), Vec::<String>::new());\n        assert_eq!(chunkify_version(\"1.0.0\"), vec![\"1\", \".0\", \".0\"]);\n        assert_eq!(\n            chunkify_version(\"2.3.4-beta\"),\n            vec![\"2\", \".3\", \".4\", \"-beta\"]\n        );\n    }\n}\n"
  },
  {
    "path": "src/shell/bash.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::fmt::Display;\n\nuse indoc::formatdoc;\nuse shell_escape::unix::escape;\n\nuse crate::config::Settings;\nuse crate::shell::{self, ActivateOptions, Shell};\n\n#[derive(Default)]\npub struct Bash {}\n\nimpl Bash {}\n\nimpl Shell for Bash {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n        let settings = Settings::get();\n\n        let exe = escape(exe.to_string_lossy());\n\n        let mut out = String::new();\n\n        out.push_str(&shell::build_deactivation_script(self));\n\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n        out.push_str(&formatdoc! {r#\"\n            export MISE_SHELL=bash\n\n            # On first activation, save the original PATH\n            # On re-activation, we keep the saved original\n            if [ -z \"${{__MISE_ORIG_PATH:-}}\" ]; then\n              export __MISE_ORIG_PATH=\"$PATH\"\n            fi\n\n            mise() {{\n              local command\n              command=\"${{1:-}}\"\n              if [ \"$#\" = 0 ]; then\n                command {exe}\n                return\n              fi\n              shift\n\n              case \"$command\" in\n              deactivate|shell|sh)\n                # if argv doesn't contains -h,--help\n                if [[ ! \" $@ \" =~ \" --help \" ]] && [[ ! \" $@ \" =~ \" -h \" ]]; then\n                  eval \"$(command {exe} \"$command\" \"$@\")\"\n                  return $?\n                fi\n                ;;\n              esac\n              command {exe} \"$command\" \"$@\"\n            }}\n\n            _mise_hook() {{\n              local previous_exit_status=$?;\n              eval \"$(mise hook-env{flags} -s bash)\";\n              return $previous_exit_status;\n            }};\n            \"#});\n        if !opts.no_hook_env {\n            out.push_str(&formatdoc! {r#\"\n            if [[ \";${{PROMPT_COMMAND:-}};\" != *\";_mise_hook;\"* ]]; then\n              PROMPT_COMMAND=\"_mise_hook${{PROMPT_COMMAND:+;$PROMPT_COMMAND}}\"\n            fi\n            {chpwd_functions}\n            {chpwd_load}\n            chpwd_functions+=(_mise_hook)\n            _mise_hook\n            \"#,\n            chpwd_functions = include_str!(\"../assets/bash_zsh_support/chpwd/function.sh\"),\n            chpwd_load = include_str!(\"../assets/bash_zsh_support/chpwd/load.sh\")\n            });\n        }\n        if settings.not_found_auto_install {\n            out.push_str(&formatdoc! {r#\"\n            if [ -z \"${{_mise_cmd_not_found:-}}\" ]; then\n                _mise_cmd_not_found=1\n                if [ -n \"$(declare -f command_not_found_handle)\" ]; then\n                    _mise_cmd_not_found_handle=$(declare -f command_not_found_handle)\n                    eval \"${{_mise_cmd_not_found_handle/command_not_found_handle/_command_not_found_handle}}\"\n                fi\n\n                command_not_found_handle() {{\n                    if [[ \"$1\" != \"mise\" && \"$1\" != \"mise-\"* ]] && {exe} hook-not-found -s bash -- \"$1\"; then\n                      _mise_hook\n                      \"$@\"\n                    elif [ -n \"$(declare -f _command_not_found_handle)\" ]; then\n                        _command_not_found_handle \"$@\"\n                    else\n                        echo \"bash: command not found: $1\" >&2\n                        return 127\n                    fi\n                }}\n            fi\n            \"#});\n        }\n\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n            if [[ ${{PROMPT_COMMAND-}} == *_mise_hook* ]]; then\n                PROMPT_COMMAND=\"${{PROMPT_COMMAND//_mise_hook;/}}\"\n                PROMPT_COMMAND=\"${{PROMPT_COMMAND//_mise_hook/}}\"\n            fi\n            unset -f _mise_hook\n            unset -f mise\n            unset MISE_SHELL\n            unset __MISE_DIFF\n            unset __MISE_SESSION\n        \"#}\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        let k = shell_escape::unix::escape(k.into());\n        let v = shell_escape::unix::escape(v.into());\n        format!(\"export {k}={v}\\n\")\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        format!(\"export {k}=\\\"{v}:${k}\\\"\\n\")\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        format!(\"unset {k}\\n\", k = shell_escape::unix::escape(k.into()))\n    }\n\n    fn set_alias(&self, name: &str, cmd: &str) -> String {\n        let name = shell_escape::unix::escape(name.into());\n        let cmd = shell_escape::unix::escape(cmd.into());\n        format!(\"alias {name}={cmd}\\n\")\n    }\n\n    fn unset_alias(&self, name: &str) -> String {\n        let name = shell_escape::unix::escape(name.into());\n        format!(\"unalias {name} 2>/dev/null || true\\n\")\n    }\n}\n\nimpl Display for Bash {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"bash\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_activate() {\n        unsafe {\n            std::env::remove_var(\"__MISE_ORIG_PATH\");\n            std::env::remove_var(\"__MISE_DIFF\");\n        }\n\n        let bash = Bash::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(bash.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Bash::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let bash = Bash::default();\n        assert_snapshot!(replace_path(&bash.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Bash::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Bash::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/elvish.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::fmt::Display;\n\nuse crate::shell::{self, ActivateOptions, Shell};\nuse indoc::formatdoc;\nuse shell_escape::unix::escape;\n\n#[derive(Default)]\npub struct Elvish {}\n\nimpl Shell for Elvish {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n        let exe = escape(exe.to_string_lossy());\n\n        let mut out = String::new();\n        out.push_str(&shell::build_deactivation_script(self));\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n        out.push_str(&formatdoc! {r#\"\n            var hook-enabled = $false\n\n            fn hook-env {{\n              if $hook-enabled {{\n                eval ((external {exe}) hook-env{flags} -s elvish | slurp)\n              }}\n            }}\n\n            set after-chdir = (conj $after-chdir {{|_| hook-env }})\n            set edit:before-readline = (conj $edit:before-readline $hook-env~)\n\n            fn activate {{\n              set-env MISE_SHELL elvish\n              set hook-enabled = ${hook_enabled}\n              hook-env\n            }}\n\n            fn deactivate {{\n              set hook-enabled = $false\n              eval ((external {exe}) deactivate | slurp)\n            }}\n\n            fn mise {{|@a|\n              if (== (count $a) 0) {{\n                (external {exe})\n                return\n              }}\n\n              if (not (or (has-value $a -h) (has-value $a --help))) {{\n                var command = $a[0]\n                if (==s $command shell) {{\n                  try {{ eval ((external {exe}) $@a) }} catch {{ }}\n                  return\n                }} elif (==s $command deactivate) {{\n                  deactivate\n                  return\n                }} elif (==s $command activate) {{\n                  activate\n                  return\n                }}\n              }}\n              (external {exe}) $@a\n            }}\n            \"#, hook_enabled = !opts.no_hook_env});\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n            unset-env MISE_SHELL\n            unset-env __MISE_DIFF\n            unset-env __MISE_SESSION\n        \"#}\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        let k = shell_escape::unix::escape(k.into());\n        let v = shell_escape::unix::escape(v.into());\n        let v = v.replace(\"\\\\n\", \"\\n\");\n        format!(\"set-env {k} {v}\\n\")\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        let k = shell_escape::unix::escape(k.into());\n        let v = shell_escape::unix::escape(v.into());\n        format!(\"set-env {k} {v}(get-env {k})\\n\")\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        format!(\"unset-env {k}\\n\", k = shell_escape::unix::escape(k.into()))\n    }\n}\n\nimpl Display for Elvish {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"elvish\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_hook_init() {\n        let elvish = Elvish::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(elvish.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Elvish::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let sh = Elvish::default();\n        assert_snapshot!(replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Elvish::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Elvish::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/fish.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::fmt::{Display, Formatter};\n\nuse crate::config::Settings;\nuse crate::env::{self};\nuse crate::shell::{self, ActivateOptions, Shell};\nuse indoc::formatdoc;\nuse itertools::Itertools;\nuse shell_escape::unix::escape;\n\n#[derive(Default)]\npub struct Fish {}\n\nimpl Fish {}\n\nimpl Shell for Fish {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n\n        let exe = escape(exe.to_string_lossy());\n        let description = \"'Update mise environment when changing directories'\";\n        let mut out = String::new();\n\n        out.push_str(&shell::build_deactivation_script(self));\n\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n\n        // much of this is from direnv\n        // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_fish.go#L14-L36\n        out.push_str(&formatdoc! {r#\"\n            set -gx MISE_SHELL fish\n            if not set -q __MISE_ORIG_PATH\n                set -gx __MISE_ORIG_PATH $PATH\n            end\n\n            function mise\n              if test (count $argv) -eq 0\n                command {exe}\n                return\n              end\n\n              set command $argv[1]\n              set -e argv[1]\n\n              if contains -- --help $argv\n                command {exe} \"$command\" $argv\n                return $status\n              end\n\n              switch \"$command\"\n              case deactivate shell sh\n                # if help is requested, don't eval\n                if contains -- -h $argv\n                  command {exe} \"$command\" $argv\n                else if contains -- --help $argv\n                  command {exe} \"$command\" $argv\n                else\n                  source (command {exe} \"$command\" $argv |psub)\n                end\n              case '*'\n                command {exe} \"$command\" $argv\n              end\n            end\n        \"#});\n\n        if !opts.no_hook_env {\n            out.push_str(&formatdoc! {r#\"\n\n            function __mise_env_eval --on-event fish_prompt --description {description};\n                {exe} hook-env{flags} -s fish | source;\n\n                if test \"$mise_fish_mode\" != \"disable_arrow\";\n                    function __mise_cd_hook --on-variable PWD --description {description};\n                        if test \"$mise_fish_mode\" = \"eval_after_arrow\";\n                            set -g __mise_env_again 0;\n                        else;\n                            {exe} hook-env{flags} -s fish | source;\n                        end;\n                    end;\n                end;\n            end;\n\n            function __mise_env_eval_2 --on-event fish_preexec --description {description};\n                if set -q __mise_env_again;\n                    set -e __mise_env_again;\n                    {exe} hook-env{flags} -s fish | source;\n                    echo;\n                end;\n\n                functions --erase __mise_cd_hook;\n            end;\n\n            __mise_env_eval\n        \"#});\n        }\n        if Settings::get().not_found_auto_install {\n            out.push_str(&formatdoc! {r#\"\n            if functions -q fish_command_not_found; and not functions -q __mise_fish_command_not_found\n                functions -e __mise_fish_command_not_found\n                functions -c fish_command_not_found __mise_fish_command_not_found\n            end\n\n            function fish_command_not_found\n                if string match -qrv -- '^(?:mise$|mise-)' $argv[1] &&\n                    {exe} hook-not-found -s fish -- $argv[1]\n                    {exe} hook-env{flags} -s fish | source\n                else if functions -q __mise_fish_command_not_found\n                    __mise_fish_command_not_found $argv\n                else\n                    __fish_default_command_not_found_handler $argv\n                end\n            end\n            \"#});\n        }\n\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n          functions --erase __mise_env_eval\n          functions --erase __mise_env_eval_2\n          functions --erase __mise_cd_hook\n          functions --erase mise\n          set -e MISE_SHELL\n          set -e __MISE_DIFF\n          set -e __MISE_SESSION\n        \"#}\n    }\n\n    fn set_env(&self, key: &str, v: &str) -> String {\n        let k = escape(key.into());\n        // Fish uses space-separated list for PATH, not colon-separated string\n        if key == \"PATH\" {\n            let paths = v.split(':').map(|p| escape(p.into())).join(\" \");\n            format!(\"set -gx PATH {paths}\\n\")\n        } else {\n            let v = escape(v.into());\n            format!(\"set -gx {k} {v}\\n\")\n        }\n    }\n\n    fn prepend_env(&self, key: &str, value: &str) -> String {\n        let k = escape(key.into());\n\n        match key {\n            env_key if env_key == *env::PATH_KEY => env::split_paths(value)\n                .filter_map(|path| {\n                    let path_str = path.to_str()?;\n                    if path_str.is_empty() {\n                        None\n                    } else {\n                        Some(format!(\n                            \"fish_add_path --global --path {}\\n\",\n                            escape(path_str.into())\n                        ))\n                    }\n                })\n                .collect::<String>(),\n            _ => {\n                let v = escape(value.into());\n                format!(\"set -gx {k} {v} ${k}\\n\")\n            }\n        }\n    }\n\n    fn move_prepend_env(&self, key: &str, value: &str) -> String {\n        match key {\n            env_key if env_key == *env::PATH_KEY => env::split_paths(value)\n                .filter_map(|path| {\n                    let path_str = path.to_str()?;\n                    if path_str.is_empty() {\n                        None\n                    } else {\n                        Some(format!(\n                            \"fish_add_path --global --move --path {}\\n\",\n                            escape(path_str.into())\n                        ))\n                    }\n                })\n                .collect::<String>(),\n            _ => self.prepend_env(key, value),\n        }\n    }\n\n    fn supports_move_path(&self) -> bool {\n        true\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        format!(\"set -e {k}\\n\", k = escape(k.into()))\n    }\n\n    fn set_alias(&self, name: &str, cmd: &str) -> String {\n        let name = escape(name.into());\n        let cmd = escape(cmd.into());\n        format!(\"complete -e {name}\\nalias {name} {cmd}\\n\")\n    }\n\n    fn unset_alias(&self, name: &str) -> String {\n        let name = escape(name.into());\n        format!(\"complete -e {name}\\nfunctions -e {name}\\n\")\n    }\n}\n\nimpl Display for Fish {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"fish\")\n    }\n}\n\n#[cfg(all(test, not(windows)))]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_activate() {\n        // Unset __MISE_ORIG_PATH to avoid PATH restoration logic in output\n        unsafe {\n            std::env::remove_var(\"__MISE_ORIG_PATH\");\n            std::env::remove_var(\"__MISE_DIFF\");\n        }\n\n        let fish = Fish::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(fish.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Fish::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let sh = Fish::default();\n        assert_snapshot!(replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_move_prepend_env() {\n        let sh = Fish::default();\n        assert_snapshot!(replace_path(\n            &sh.move_prepend_env(\"PATH\", \"/some/dir:/2/dir\")\n        ));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Fish::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Fish::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/mod.rs",
    "content": "use crate::env;\nuse crate::hook_env;\nuse itertools::Itertools;\nuse std::fmt::{Display, Formatter};\nuse std::path::PathBuf;\nuse std::str::FromStr;\n\nmod bash;\nmod elvish;\nmod fish;\nmod nushell;\nmod pwsh;\nmod xonsh;\nmod zsh;\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]\npub enum ShellType {\n    Bash,\n    Elvish,\n    Fish,\n    Nu,\n    Xonsh,\n    Zsh,\n    Pwsh,\n}\n\nimpl ShellType {\n    pub fn as_shell(&self) -> Box<dyn Shell> {\n        match self {\n            Self::Bash => Box::<bash::Bash>::default(),\n            Self::Elvish => Box::<elvish::Elvish>::default(),\n            Self::Fish => Box::<fish::Fish>::default(),\n            Self::Nu => Box::<nushell::Nushell>::default(),\n            Self::Xonsh => Box::<xonsh::Xonsh>::default(),\n            Self::Zsh => Box::<zsh::Zsh>::default(),\n            Self::Pwsh => Box::<pwsh::Pwsh>::default(),\n        }\n    }\n}\n\nimpl Display for ShellType {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Bash => write!(f, \"bash\"),\n            Self::Elvish => write!(f, \"elvish\"),\n            Self::Fish => write!(f, \"fish\"),\n            Self::Nu => write!(f, \"nu\"),\n            Self::Xonsh => write!(f, \"xonsh\"),\n            Self::Zsh => write!(f, \"zsh\"),\n            Self::Pwsh => write!(f, \"pwsh\"),\n        }\n    }\n}\n\nimpl FromStr for ShellType {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let s = s.to_lowercase();\n        let s = s.rsplit_once('/').map(|(_, s)| s).unwrap_or(&s);\n        match s {\n            \"bash\" | \"sh\" => Ok(Self::Bash),\n            \"elvish\" => Ok(Self::Elvish),\n            \"fish\" => Ok(Self::Fish),\n            \"nu\" => Ok(Self::Nu),\n            \"xonsh\" => Ok(Self::Xonsh),\n            \"zsh\" => Ok(Self::Zsh),\n            \"pwsh\" => Ok(Self::Pwsh),\n            _ => Err(format!(\"unsupported shell type: {s}\")),\n        }\n    }\n}\n\npub trait Shell: Display {\n    fn activate(&self, opts: ActivateOptions) -> String;\n    fn deactivate(&self) -> String;\n    fn set_env(&self, k: &str, v: &str) -> String;\n    fn prepend_env(&self, k: &str, v: &str) -> String;\n    /// Prepend env, moving existing entries to the front if already present.\n    /// Default falls back to prepend_env. Fish overrides with --move flag.\n    fn move_prepend_env(&self, k: &str, v: &str) -> String {\n        self.prepend_env(k, v)\n    }\n    /// Whether this shell natively deduplicates/reorders PATH entries.\n    /// When true, activate_shims skips the is_dir_in_path guard and uses\n    /// MovePrependEnv to ensure correct ordering on re-source.\n    fn supports_move_path(&self) -> bool {\n        false\n    }\n    fn unset_env(&self, k: &str) -> String;\n\n    /// Set a shell alias. Returns empty string if not supported by this shell.\n    fn set_alias(&self, name: &str, cmd: &str) -> String {\n        // Default implementation returns empty string (unsupported)\n        let _ = (name, cmd);\n        String::new()\n    }\n\n    /// Unset a shell alias. Returns empty string if not supported by this shell.\n    fn unset_alias(&self, name: &str) -> String {\n        // Default implementation returns empty string (unsupported)\n        let _ = name;\n        String::new()\n    }\n\n    fn format_activate_prelude(&self, prelude: &[ActivatePrelude]) -> String {\n        prelude\n            .iter()\n            .map(|p| match p {\n                ActivatePrelude::SetEnv(k, v) => self.set_env(k, v),\n                ActivatePrelude::PrependEnv(k, v) => self.prepend_env(k, v),\n                ActivatePrelude::MovePrependEnv(k, v) => self.move_prepend_env(k, v),\n            })\n            .join(\"\")\n    }\n}\n\n#[allow(clippy::enum_variant_names)]\npub enum ActivatePrelude {\n    SetEnv(String, String),\n    PrependEnv(String, String),\n    /// Like PrependEnv but moves existing entries to the front (for fish --move).\n    /// Used only by activate_shims to reorder paths on re-source.\n    MovePrependEnv(String, String),\n}\n\npub struct ActivateOptions {\n    pub exe: PathBuf,\n    pub flags: String,\n    pub no_hook_env: bool,\n    pub prelude: Vec<ActivatePrelude>,\n}\n\npub fn build_deactivation_script(shell: &dyn Shell) -> String {\n    if !env::is_activated() {\n        return String::new();\n    }\n\n    let mut out = hook_env::clear_old_env(shell);\n    out.push_str(&hook_env::clear_aliases(shell));\n    out.push_str(&shell.deactivate());\n    out\n}\n\npub fn get_shell(shell: Option<ShellType>) -> Option<Box<dyn Shell>> {\n    shell.or(*env::MISE_SHELL).map(|st| st.as_shell())\n}\n"
  },
  {
    "path": "src/shell/nushell.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::fmt::Display;\n\nuse indoc::formatdoc;\n\nuse crate::shell::{self, ActivateOptions, ActivatePrelude, Shell};\nuse itertools::Itertools;\n\n#[derive(Default)]\npub struct Nushell {}\n\nenum EnvOp<'a> {\n    Set { key: &'a str, val: &'a str },\n    Hide { key: &'a str },\n}\n\nimpl Display for EnvOp<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            EnvOp::Set { key, val } => writeln!(f, \"set,{key},{val}\"),\n            EnvOp::Hide { key } => writeln!(f, \"hide,{key},\"),\n        }\n    }\n}\n\nimpl Nushell {\n    fn escape_csv_value(s: &str) -> String {\n        if s.contains(['\\r', '\\n', '\"', ',']) {\n            format!(\"\\\"{}\\\"\", s.replace('\"', \"\\\"\\\"\"))\n        } else {\n            s.to_owned()\n        }\n    }\n\n    fn format_activate_prelude_inline(&self, prelude: &[ActivatePrelude]) -> String {\n        prelude\n            .iter()\n            .map(|p| match p {\n                ActivatePrelude::SetEnv(k, v) => format!(\"$env.{k} = r#'{v}'#\\n\"),\n                ActivatePrelude::PrependEnv(k, v) | ActivatePrelude::MovePrependEnv(k, v) => {\n                    self.prepend_env(k, v)\n                }\n            })\n            .join(\"\")\n    }\n\n    fn build_deactivation_script(&self) -> String {\n        let deactivation_ops = shell::build_deactivation_script(self);\n        deactivation_ops.trim_end_matches('\\n').to_owned()\n    }\n}\n\nimpl Shell for Nushell {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n        let exe = exe.to_string_lossy().replace('\\\\', r#\"\\\\\"#);\n\n        let mut out = String::new();\n\n        out.push_str(&formatdoc! {r#\"\n          def \"parse vars\" [] {{\n            $in | from csv --noheaders --no-infer | rename 'op' 'name' 'value'\n          }}\n\n          def --env \"update-env\" [] {{\n            for $var in $in {{\n              if $var.op == \"set\" {{\n                if ($var.name | str upcase) == 'PATH' {{\n                  $env.PATH = ($var.value | split row (char esep))\n                }} else {{\n                  load-env {{($var.name): $var.value}}\n                }}\n              }} else if $var.op == \"hide\" and $var.name in $env {{\n                hide-env $var.name\n              }}\n            }}\n          }}\n        \"#});\n\n        let deactivation_ops_csv = self.build_deactivation_script();\n        let inline_prelude = self.format_activate_prelude_inline(&opts.prelude);\n        out.push_str(&formatdoc! {r#\"\n          export-env {{\n            {inline_prelude}\n            '{deactivation_ops_csv}' | parse vars | update-env\n            $env.MISE_SHELL = \"nu\"\n            let mise_hook = {{\n              condition: {{ \"MISE_SHELL\" in $env }}\n              code: {{ mise_hook }}\n            }}\n            add-hook hooks.pre_prompt $mise_hook\n            add-hook hooks.env_change.PWD $mise_hook\n          }}\n\n          def --env add-hook [field: cell-path new_hook: any] {{\n            let field = $field | split cell-path | update optional true | into cell-path\n            let old_config = $env.config? | default {{}}\n            let old_hooks = $old_config | get $field | default []\n            $env.config = ($old_config | upsert $field ($old_hooks ++ [$new_hook]))\n          }}\n\n          export def --env --wrapped main [command?: string, --help, ...rest: string] {{\n            let commands = [\"deactivate\", \"shell\", \"sh\"]\n\n            if ($command == null) {{\n              ^\"{exe}\"\n            }} else if ($command == \"activate\") {{\n              $env.MISE_SHELL = \"nu\"\n            }} else if ($command in $commands) {{\n              ^\"{exe}\" $command ...$rest\n              | parse vars\n              | update-env\n            }} else {{\n              ^\"{exe}\" $command ...$rest\n            }}\n          }}\n\n          def --env mise_hook [] {{\n            ^\"{exe}\" hook-env{flags} -s nu\n              | parse vars\n              | update-env\n          }}\n\n        \"#});\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        [\n            self.unset_env(\"MISE_SHELL\"),\n            self.unset_env(\"__MISE_DIFF\"),\n            self.unset_env(\"__MISE_DIFF\"),\n        ]\n        .join(\"\")\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        let k = Nushell::escape_csv_value(k);\n        let v = Nushell::escape_csv_value(v);\n\n        EnvOp::Set { key: &k, val: &v }.to_string()\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        format!(\"$env.{k} = ($env.{k} | prepend r#'{v}'#)\\n\")\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        let k = Nushell::escape_csv_value(k);\n        EnvOp::Hide { key: k.as_ref() }.to_string()\n    }\n}\n\nimpl Display for Nushell {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"nu\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_hook_init() {\n        let nushell = Nushell::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(nushell.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Nushell::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let sh = Nushell::default();\n        assert_snapshot!(replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Nushell::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Nushell::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/pwsh.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse crate::config::Settings;\nuse std::borrow::Cow;\nuse std::fmt::Display;\n\nuse indoc::formatdoc;\n\nuse crate::shell::{self, ActivateOptions, Shell};\n\n#[derive(Default)]\npub struct Pwsh {}\n\nimpl Pwsh {}\n\nimpl Shell for Pwsh {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n\n        let exe = exe.to_string_lossy();\n        let mut out = String::new();\n\n        out.push_str(&shell::build_deactivation_script(self));\n\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n        out.push_str(&formatdoc! {r#\"\n            $env:MISE_SHELL = 'pwsh'\n            if (-not (Test-Path -Path Env:/__MISE_ORIG_PATH)) {{\n                $env:__MISE_ORIG_PATH = $env:PATH\n            }}\n\n            function mise {{\n                [CmdletBinding()]\n                param(\n                    [Parameter(ValueFromRemainingArguments=$true)]  # Allow any number of arguments, including none\n                    [string[]] $arguments\n                )\n\n                $previous_out_encoding = $OutputEncoding\n                $previous_console_out_encoding = [Console]::OutputEncoding\n                $OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8\n\n                function _reset_output_encoding {{\n                    $OutputEncoding = $previous_out_encoding\n                    [Console]::OutputEncoding = $previous_console_out_encoding\n                }}\n\n                if ($arguments.count -eq 0) {{\n                    & \"{exe}\"\n                    _reset_output_encoding\n                    return\n                }} elseif ($arguments -contains '-h' -or $arguments -contains '--help') {{\n                    & \"{exe}\" @arguments\n                    _reset_output_encoding\n                    return\n                }}\n\n                $command = $arguments[0]\n                if ($arguments.Length -gt 1) {{\n                    $remainingArgs = $arguments[1..($arguments.Length - 1)]\n                }} else {{\n                    $remainingArgs = @()\n                }}\n\n                switch ($command) {{\n                    {{ $_ -in 'deactivate', 'shell', 'sh' }} {{\n                        & \"{exe}\" $command @remainingArgs | Out-String | Invoke-Expression -ErrorAction SilentlyContinue\n                        _reset_output_encoding\n                    }}\n                    default {{\n                        & \"{exe}\" $command @remainingArgs\n                        $status = $LASTEXITCODE\n                        if ($(Test-Path -Path Function:\\_mise_hook)){{\n                            _mise_hook\n                        }}\n                        _reset_output_encoding\n                        # Pass down exit code from mise after _mise_hook\n                        if ($PSVersionTable.PSVersion.Major -ge 7) {{\n                            pwsh -NoProfile -Command exit $status\n                        }} else {{\n                            powershell -NoProfile -Command exit $status\n                        }}\n                    }}\n                }}\n            }}\n            \"#});\n\n        if !opts.no_hook_env {\n            out.push_str(&formatdoc! {r#\"\n\n            function Global:_mise_hook {{\n                if ($env:MISE_SHELL -eq \"pwsh\"){{\n                    $output = & \"{exe}\" hook-env{flags} $args -s pwsh | Out-String\n                    if ($output -and $output.Trim()) {{\n                        $output | Invoke-Expression\n                    }}\n                }}\n            }}\n\n            function __enable_mise_chpwd{{\n                if ($PSVersionTable.PSVersion.Major -lt 7) {{\n                    if ($env:MISE_PWSH_CHPWD_WARNING -ne '0') {{\n                        Write-Warning \"mise: chpwd functionality requires PowerShell version 7 or higher. Your current version is $($PSVersionTable.PSVersion). You can add `$env:MISE_PWSH_CHPWD_WARNING=0` to your environment to disable this warning.\"\n                    }}\n                    return\n                }}\n                if (-not $__mise_pwsh_chpwd){{\n                    $Global:__mise_pwsh_chpwd= $true\n                    $_mise_chpwd_hook = [EventHandler[System.Management.Automation.LocationChangedEventArgs]] {{\n                        param([object] $source, [System.Management.Automation.LocationChangedEventArgs] $eventArgs)\n                        end {{\n                            _mise_hook\n                        }}\n                    }};\n                    $__mise_pwsh_previous_chpwd_function=$ExecutionContext.SessionState.InvokeCommand.LocationChangedAction;\n\n                    if ($__mise_original_pwsh_chpwd_function) {{\n                        $ExecutionContext.SessionState.InvokeCommand.LocationChangedAction = [Delegate]::Combine($__mise_pwsh_previous_chpwd_function, $_mise_chpwd_hook)\n                    }}\n                    else {{\n                        $ExecutionContext.SessionState.InvokeCommand.LocationChangedAction = $_mise_chpwd_hook\n                    }}\n                }}\n            }}\n            __enable_mise_chpwd\n            Remove-Item -ErrorAction SilentlyContinue -Path Function:/__enable_mise_chpwd\n\n            function __enable_mise_prompt {{\n                if (-not $__mise_pwsh_previous_prompt_function){{\n                    $Global:__mise_pwsh_previous_prompt_function=$function:prompt\n                    function global:prompt {{\n                        if (Test-Path -Path Function:\\_mise_hook){{\n                            _mise_hook\n                        }}\n                        & $__mise_pwsh_previous_prompt_function\n                    }}\n                }}\n            }}\n            __enable_mise_prompt\n            Remove-Item -ErrorAction SilentlyContinue -Path Function:/__enable_mise_prompt\n\n            _mise_hook\n            \"#});\n        }\n        if Settings::get().not_found_auto_install {\n            out.push_str(&formatdoc! {r#\"\n            if (-not $__mise_pwsh_command_not_found){{\n                $Global:__mise_pwsh_command_not_found= $true\n                function __enable_mise_command_not_found {{\n                    $_mise_pwsh_cmd_not_found_hook = [EventHandler[System.Management.Automation.CommandLookupEventArgs]] {{\n                        param([object] $Name, [System.Management.Automation.CommandLookupEventArgs] $eventArgs)\n                        end {{\n                            if ([Microsoft.PowerShell.PSConsoleReadLine]::GetHistoryItems()[-1].CommandLine -match ([regex]::Escape($Name))) {{\n                                if (& \"{exe}\" hook-not-found -s pwsh -- $Name){{\n                                    _mise_hook\n                                    if (Get-Command $Name -ErrorAction SilentlyContinue){{\n                                        $EventArgs.Command = Get-Command $Name\n                                        $EventArgs.StopSearch = $true\n                                    }}\n                                }}\n                            }}\n                        }}\n                    }}\n                    $current_command_not_found_function = $ExecutionContext.SessionState.InvokeCommand.CommandNotFoundAction\n                    if ($current_command_not_found_function) {{\n                        $ExecutionContext.SessionState.InvokeCommand.CommandNotFoundAction = [Delegate]::Combine($current_command_not_found_function, $_mise_pwsh_cmd_not_found_hook)\n                    }}\n                    else {{\n                        $ExecutionContext.SessionState.InvokeCommand.CommandNotFoundAction = $_mise_pwsh_cmd_not_found_hook\n                    }}\n                }}\n                __enable_mise_command_not_found\n                Remove-Item -ErrorAction SilentlyContinue -Path Function:/__enable_mise_command_not_found\n            }}\n            \"#});\n        }\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n        Remove-Item -ErrorAction SilentlyContinue function:mise\n        Remove-Item -ErrorAction SilentlyContinue -Path Env:/MISE_SHELL\n        Remove-Item -ErrorAction SilentlyContinue -Path Env:/__MISE_DIFF\n        Remove-Item -ErrorAction SilentlyContinue -Path Env:/__MISE_SESSION\n        \"#}\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        let k = powershell_escape(k.into());\n        let v = powershell_escape(v.into());\n        format!(\"$Env:{k}='{v}'\\n\")\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        let k = powershell_escape(k.into());\n        let v = powershell_escape(v.into());\n        format!(\"$Env:{k}='{v}'+[IO.Path]::PathSeparator+$env:{k}\\n\")\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        let k = powershell_escape(k.into());\n        format!(\"Remove-Item -ErrorAction SilentlyContinue -Path Env:/{k}\\n\")\n    }\n}\n\nimpl Display for Pwsh {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"pwsh\")\n    }\n}\n\nfn powershell_escape(s: Cow<str>) -> Cow<str> {\n    let needs_escape = s.is_empty();\n\n    if !needs_escape {\n        return s;\n    }\n\n    let mut es = String::with_capacity(s.len());\n    let mut chars = s.chars().peekable();\n    loop {\n        match chars.next() {\n            Some('\\t') => {\n                es.push_str(\"`t\");\n            }\n            Some('\\n') => {\n                es.push_str(\"`n\");\n            }\n            Some('\\r') => {\n                es.push_str(\"`r\");\n            }\n            Some('\\'') => {\n                es.push_str(\"`'\");\n            }\n            Some('`') => {\n                es.push_str(\"``\");\n            }\n            Some(c) => {\n                es.push(c);\n            }\n            None => {\n                break;\n            }\n        }\n    }\n    es.into()\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_activate() {\n        // Unset __MISE_ORIG_PATH to avoid PATH restoration logic in output\n        unsafe {\n            std::env::remove_var(\"__MISE_ORIG_PATH\");\n            std::env::remove_var(\"__MISE_DIFF\");\n        }\n\n        let pwsh = Pwsh::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(pwsh.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Pwsh::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let pwsh = Pwsh::default();\n        assert_snapshot!(replace_path(&pwsh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Pwsh::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Pwsh::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/xonsh.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::borrow::Cow;\nuse std::fmt::Display;\n\nuse indoc::formatdoc;\n\nuse crate::shell::{self, ActivateOptions, Shell};\n\n#[derive(Default)]\npub struct Xonsh {}\n\nfn xonsh_escape_sq(input: &str) -> Cow<'_, str> {\n    for (i, ch) in input.char_indices() {\n        if xonsh_escape_char(ch).is_some() {\n            let mut escaped_string = String::with_capacity(input.len());\n\n            escaped_string.push_str(&input[..i]);\n            for ch in input[i..].chars() {\n                match xonsh_escape_char(ch) {\n                    Some(escaped_char) => escaped_string.push_str(escaped_char),\n                    None => escaped_string.push(ch),\n                };\n            }\n            return Cow::Owned(escaped_string);\n        }\n    }\n    Cow::Borrowed(input)\n}\n\nfn xonsh_escape_char(ch: char) -> Option<&'static str> {\n    match ch {\n        // escape ' \\ ␤ (docs.python.org/3/reference/lexical_analysis.html#strings)\n        '\\'' => Some(\"\\\\'\"),\n        '\\\\' => Some(\"\\\\\\\\\"),\n        '\\n' => Some(\"\\\\n\"),\n        _ => None,\n    }\n}\n\nimpl Shell for Xonsh {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n        let exe = exe.display();\n\n        let mut out = String::new();\n        out.push_str(&shell::build_deactivation_script(self));\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n\n        // use xonsh API instead of $.xsh to allow use inside of .py configs, which start faster due to being compiled to .pyc\n        out.push_str(&formatdoc! {r#\"\n            from xonsh.built_ins import XSH\n\n            def _mise(args):\n              if args and args[0] in ('deactivate', 'shell', 'sh'):\n                execx($(mise @(args)))\n              else:\n                mise @(args)\n\n            XSH.env['MISE_SHELL'] = 'xonsh'\n            XSH.aliases['mise'] = _mise\n        \"#});\n\n        if !opts.no_hook_env {\n            out.push_str(&formatdoc! {r#\"\n                import shlex\n                import subprocess\n\n                extra_args = shlex.split('{flags}')\n                def mise_hook(**kwargs): # Hook Events\n                    script = subprocess.run(\n                        ['{exe}', 'hook-env', *extra_args, '-s', 'xonsh'],\n                        env=XSH.env.detype(),\n                        stdout=subprocess.PIPE,\n                    ).stdout.decode()\n                    execx(script)\n\n                XSH.builtins.events.on_pre_prompt(mise_hook) # Activate hook: before showing the prompt\n                XSH.builtins.events.on_chdir(mise_hook) # Activate hook: when the working directory changes\n            \"#});\n        }\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n            import os\n            from xonsh.built_ins import XSH\n\n            hooks = {{\n              'on_pre_prompt' : ['mise_hook'],\n              'on_chdir': ['mise_hook'],\n            }}\n            for hook_type, hook_fns in hooks.items():\n              for hook_fn in hook_fns:\n                hndl = getattr(XSH.builtins.events, hook_type)\n                for fn in hndl:\n                  if fn.__name__ == hook_fn:\n                    hndl.remove(fn)\n                    break\n\n            XSH.aliases.pop('mise', None)\n            XSH.env.pop('MISE_SHELL', None)\n            XSH.env.pop('__MISE_DIFF', None)\n            XSH.env.pop('__MISE_SESSION', None)\n            \"#}\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        formatdoc!(\n            r#\"\n            from xonsh.built_ins import XSH\n            XSH.env['{k}'] = '{v}'\n        \"#,\n            k = shell_escape::unix::escape(k.into()), // todo: drop illegal chars, not escape?\n            v = xonsh_escape_sq(v)\n        )\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        formatdoc!(\n            r#\"\n            from xonsh.built_ins import XSH\n            XSH.env['{k}'].add('{v}', front=True)\n        \"#,\n            k = shell_escape::unix::escape(k.into()),\n            v = xonsh_escape_sq(v)\n        )\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        formatdoc!(\n            r#\"\n            from xonsh.built_ins import XSH\n            XSH.env.pop('{k}',None)\n        \"#,\n            k = shell_escape::unix::escape(k.into()) // todo: drop illegal chars, not escape?\n        )\n    }\n}\n\nimpl Display for Xonsh {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"xonsh\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use pretty_assertions::assert_eq;\n    use std::path::Path;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_hook_init() {\n        let xonsh = Xonsh::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        insta::assert_snapshot!(xonsh.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        insta::assert_snapshot!(Xonsh::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let sh = Xonsh::default();\n        assert_snapshot!(replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        insta::assert_snapshot!(Xonsh::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_xonsh_escape_sq() {\n        assert_eq!(xonsh_escape_sq(\"foo\"), \"foo\");\n        assert_eq!(xonsh_escape_sq(\"foo'bar\"), \"foo\\\\'bar\");\n        assert_eq!(xonsh_escape_sq(\"foo\\\\bar\"), \"foo\\\\\\\\bar\");\n        assert_eq!(xonsh_escape_sq(\"foo\\nbar\"), \"foo\\\\nbar\");\n    }\n\n    #[test]\n    fn test_xonsh_deactivate() {\n        let deactivate = Xonsh::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shell/zsh.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\nuse std::fmt::Display;\n\nuse indoc::formatdoc;\nuse shell_escape::unix::escape;\n\nuse crate::config::Settings;\nuse crate::shell::bash::Bash;\nuse crate::shell::{self, ActivateOptions, Shell};\n\n#[derive(Default)]\npub struct Zsh {}\n\nimpl Zsh {}\n\nimpl Shell for Zsh {\n    fn activate(&self, opts: ActivateOptions) -> String {\n        let exe = opts.exe;\n        let flags = opts.flags;\n\n        let exe = escape(exe.to_string_lossy());\n        let mut out = String::new();\n\n        out.push_str(&shell::build_deactivation_script(self));\n\n        out.push_str(&self.format_activate_prelude(&opts.prelude));\n\n        // much of this is from direnv\n        // https://github.com/direnv/direnv/blob/cb5222442cb9804b1574954999f6073cc636eff0/internal/cmd/shell_zsh.go#L10-L22\n        out.push_str(&formatdoc! {r#\"\n            export MISE_SHELL=zsh\n            if [ -z \"${{__MISE_ORIG_PATH:-}}\" ]; then\n              export __MISE_ORIG_PATH=\"$PATH\"\n            fi\n            export __MISE_ZSH_PRECMD_RUN=0\n\n            mise() {{\n              local command\n              command=\"${{1:-}}\"\n              if [ \"$#\" = 0 ]; then\n                command {exe}\n                return\n              fi\n              shift\n\n              case \"$command\" in\n              deactivate|shell|sh)\n                # if argv doesn't contains -h,--help\n                if [[ ! \" $@ \" =~ \" --help \" ]] && [[ ! \" $@ \" =~ \" -h \" ]]; then\n                  eval \"$(command {exe} \"$command\" \"$@\")\"\n                  return $?\n                fi\n                ;;\n              esac\n              command {exe} \"$command\" \"$@\"\n            }}\n        \"#});\n\n        if !opts.no_hook_env {\n            out.push_str(&formatdoc! {r#\"\n\n            _mise_hook() {{\n              eval \"$({exe} hook-env{flags} -s zsh)\";\n            }}\n            _mise_hook_precmd() {{\n              eval \"$({exe} hook-env{flags} -s zsh --reason precmd)\";\n            }}\n            _mise_hook_chpwd() {{\n              eval \"$({exe} hook-env{flags} -s zsh --reason chpwd)\";\n            }}\n            typeset -ag precmd_functions;\n            if [[ -z \"${{precmd_functions[(r)_mise_hook_precmd]+1}}\" ]]; then\n              precmd_functions=( _mise_hook_precmd ${{precmd_functions[@]}} )\n            fi\n            typeset -ag chpwd_functions;\n            if [[ -z \"${{chpwd_functions[(r)_mise_hook_chpwd]+1}}\" ]]; then\n              chpwd_functions=( _mise_hook_chpwd ${{chpwd_functions[@]}} )\n            fi\n\n            _mise_hook\n            \"#});\n        }\n        if Settings::get().not_found_auto_install {\n            out.push_str(&formatdoc! {r#\"\n            if [ -z \"${{_mise_cmd_not_found:-}}\" ]; then\n                _mise_cmd_not_found=1\n                [ -n \"$(declare -f command_not_found_handler)\" ] && eval \"${{$(declare -f command_not_found_handler)/command_not_found_handler/_command_not_found_handler}}\"\n\n                function command_not_found_handler() {{\n                    if [[ \"$1\" != \"mise\" && \"$1\" != \"mise-\"* ]] && {exe} hook-not-found -s zsh -- \"$1\"; then\n                      _mise_hook\n                      \"$@\"\n                    elif [ -n \"$(declare -f _command_not_found_handler)\" ]; then\n                        _command_not_found_handler \"$@\"\n                    else\n                        echo \"zsh: command not found: $1\" >&2\n                        return 127\n                    fi\n                }}\n            fi\n            \"#});\n        }\n\n        out\n    }\n\n    fn deactivate(&self) -> String {\n        formatdoc! {r#\"\n        precmd_functions=( ${{precmd_functions:#_mise_hook_precmd}} )\n        chpwd_functions=( ${{chpwd_functions:#_mise_hook_chpwd}} )\n        (( $+functions[_mise_hook_precmd] )) && unset -f _mise_hook_precmd\n        (( $+functions[_mise_hook_chpwd] )) && unset -f _mise_hook_chpwd\n        (( $+functions[_mise_hook] )) && unset -f _mise_hook\n        (( $+functions[mise] )) && unset -f mise\n        unset MISE_SHELL\n        unset __MISE_DIFF\n        unset __MISE_SESSION\n        unset __MISE_ZSH_PRECMD_RUN\n        \"#}\n    }\n\n    fn set_env(&self, k: &str, v: &str) -> String {\n        Bash::default().set_env(k, v)\n    }\n\n    fn prepend_env(&self, k: &str, v: &str) -> String {\n        format!(\"export {k}=\\\"{v}:${k}\\\"\\n\")\n    }\n\n    fn unset_env(&self, k: &str) -> String {\n        Bash::default().unset_env(k)\n    }\n\n    fn set_alias(&self, name: &str, cmd: &str) -> String {\n        Bash::default().set_alias(name, cmd)\n    }\n\n    fn unset_alias(&self, name: &str) -> String {\n        Bash::default().unset_alias(name)\n    }\n}\n\nimpl Display for Zsh {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"zsh\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use insta::assert_snapshot;\n    use std::path::Path;\n    use test_log::test;\n\n    use crate::test::replace_path;\n\n    use super::*;\n\n    #[test]\n    fn test_activate() {\n        // Unset __MISE_ORIG_PATH to avoid PATH restoration logic in output\n        unsafe {\n            std::env::remove_var(\"__MISE_ORIG_PATH\");\n            std::env::remove_var(\"__MISE_DIFF\");\n        }\n\n        let zsh = Zsh::default();\n        let exe = Path::new(\"/some/dir/mise\");\n        let opts = ActivateOptions {\n            exe: exe.to_path_buf(),\n            flags: \" --status\".into(),\n            no_hook_env: false,\n            prelude: vec![],\n        };\n        assert_snapshot!(zsh.activate(opts));\n    }\n\n    #[test]\n    fn test_set_env() {\n        assert_snapshot!(Zsh::default().set_env(\"FOO\", \"1\"));\n    }\n\n    #[test]\n    fn test_prepend_env() {\n        let sh = Bash::default();\n        assert_snapshot!(replace_path(&sh.prepend_env(\"PATH\", \"/some/dir:/2/dir\")));\n    }\n\n    #[test]\n    fn test_unset_env() {\n        assert_snapshot!(Zsh::default().unset_env(\"FOO\"));\n    }\n\n    #[test]\n    fn test_deactivate() {\n        let deactivate = Zsh::default().deactivate();\n        assert_snapshot!(replace_path(&deactivate));\n    }\n}\n"
  },
  {
    "path": "src/shims.rs",
    "content": "use crate::exit;\nuse std::fs;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::{\n    collections::{BTreeSet, HashSet},\n    sync::atomic::Ordering,\n};\n\nuse crate::backend::Backend;\nuse crate::cli::exec::Exec;\nuse crate::config::{Config, Settings};\nuse crate::file::display_path;\nuse crate::lock_file::LockFile;\nuse crate::toolset::{ToolVersion, Toolset, ToolsetBuilder};\nuse crate::{backend, dirs, env, fake_asdf, file};\nuse color_eyre::eyre::{Result, bail, eyre};\nuse eyre::WrapErr;\nuse indoc::formatdoc;\nuse itertools::Itertools;\nuse path_absolutize::Absolutize;\nuse tokio::task::JoinSet;\n\n// executes as if it was a shim if the command is not \"mise\", e.g.: \"node\"\npub async fn handle_shim() -> Result<()> {\n    // TODO: instead, check if bin is in shims dir\n    let bin_name = *env::MISE_BIN_NAME;\n    if env::is_mise_binary(bin_name) || cfg!(test) {\n        return Ok(());\n    }\n    let mut config = Config::get().await?;\n    let mut args = env::ARGS.read().unwrap().clone();\n    env::PREFER_OFFLINE.store(true, Ordering::Relaxed);\n    trace!(\"shim[{bin_name}] args: {}\", args.join(\" \"));\n    args[0] = which_shim(&mut config, &env::MISE_BIN_NAME)\n        .await?\n        .to_string_lossy()\n        .to_string();\n    env::set_var(\"__MISE_SHIM\", \"1\");\n    let exec = Exec {\n        tool: vec![],\n        c: None,\n        command: Some(args),\n        jobs: None,\n        raw: false,\n        no_prepare: true, // Skip prepare for shims to avoid performance impact\n        fresh_env: false,\n    };\n    time!(\"shim exec\");\n    exec.run().await?;\n    exit(0);\n}\n\nasync fn which_shim(config: &mut Arc<Config>, bin_name: &str) -> Result<PathBuf> {\n    let mut ts = ToolsetBuilder::new().build(config).await?;\n    if let Some((p, tv)) = ts.which(config, bin_name).await\n        && let Some(bin) = p.which(config, &tv, bin_name).await?\n    {\n        trace!(\n            \"shim[{bin_name}] ToolVersion: {tv} bin: {bin}\",\n            bin = display_path(&bin)\n        );\n        return Ok(bin);\n    }\n    if Settings::get().not_found_auto_install {\n        for tv in ts\n            .install_missing_bin(config, bin_name)\n            .await?\n            .unwrap_or_default()\n        {\n            let p = tv.backend()?;\n            if let Some(bin) = p.which(config, &tv, bin_name).await? {\n                trace!(\n                    \"shim[{bin_name}] NOT_FOUND ToolVersion: {tv} bin: {bin}\",\n                    bin = display_path(&bin)\n                );\n                return Ok(bin);\n            }\n        }\n    }\n    // fallback for \"system\"\n    for path in &*env::PATH {\n        if fs::canonicalize(path).unwrap_or_default()\n            == fs::canonicalize(*dirs::SHIMS).unwrap_or_default()\n        {\n            continue;\n        }\n        let bin = path.join(bin_name);\n        if bin.exists() {\n            trace!(\"shim[{bin_name}] SYSTEM {bin}\", bin = display_path(&bin));\n            return Ok(bin);\n        }\n    }\n    let tvs = ts.list_rtvs_with_bin(config, bin_name).await?;\n    err_no_version_set(config, ts, bin_name, tvs).await\n}\n\npub async fn reshim(config: &Arc<Config>, ts: &Toolset, force: bool) -> Result<()> {\n    let _lock = LockFile::new(&dirs::SHIMS)\n        .with_callback(|l| {\n            trace!(\"reshim callback {}\", l.display());\n        })\n        .lock();\n\n    let mise_bin = file::which(\"mise\").unwrap_or(env::MISE_BIN.clone());\n    let mise_bin = mise_bin.absolutize()?; // relative paths don't work as shims\n\n    #[cfg(windows)]\n    let shim_mode = effective_shim_mode(&mise_bin);\n    #[cfg(not(windows))]\n    let shim_mode = String::new();\n    let shim_mode_changed = cfg!(windows) && {\n        let mode_file = dirs::SHIMS.join(\".mode\");\n        mode_file\n            .exists()\n            .then(|| fs::read_to_string(&mode_file).unwrap_or_default())\n            .is_some_and(|prev| prev.trim() != shim_mode)\n    };\n    if force || shim_mode_changed {\n        // On Windows, .exe shims may be locked by processes or the shell (they\n        // are on PATH).  Instead of removing the entire directory (which fails\n        // with \"Access is denied\"), remove individual files with a rename-first\n        // fallback so locked executables are moved out of the way.\n        if cfg!(windows) {\n            remove_shims_individually(&dirs::SHIMS)?;\n        } else {\n            file::remove_all(*dirs::SHIMS)?;\n        }\n    }\n    file::create_dir_all(*dirs::SHIMS)?;\n    if cfg!(windows) {\n        let mode_file = dirs::SHIMS.join(\".mode\");\n        file::write(&mode_file, &shim_mode)?;\n    }\n\n    let (shims_to_add, shims_to_remove) = if force || shim_mode_changed {\n        // After a full wipe, all desired shims need to be re-created.\n        let desired = get_desired_shims(config, &mise_bin, ts).await?;\n        (\n            desired.into_iter().collect::<BTreeSet<_>>(),\n            BTreeSet::new(),\n        )\n    } else {\n        get_shim_diffs(config, &mise_bin, ts).await?\n    };\n\n    for shim in shims_to_add {\n        let symlink_path = dirs::SHIMS.join(&shim);\n        // On Windows, remove the old shim first (with rename fallback for\n        // locked .exe files) so the new one can be written.\n        if cfg!(windows) && symlink_path.exists() {\n            remove_shim_with_rename_fallback(&symlink_path)?;\n        }\n        add_shim(&mise_bin, &symlink_path, &shim)?;\n    }\n    for shim in shims_to_remove {\n        let symlink_path = dirs::SHIMS.join(shim);\n        if cfg!(windows) {\n            remove_shim_with_rename_fallback(&symlink_path)?;\n        } else {\n            file::remove_all(&symlink_path)?;\n        }\n    }\n    let mut jset = JoinSet::new();\n    for plugin in backend::list() {\n        jset.spawn(async move {\n            if let Ok(files) = dirs::PLUGINS.join(plugin.id()).join(\"shims\").read_dir() {\n                for bin in files {\n                    let bin = bin?;\n                    let bin_name = bin.file_name().into_string().unwrap();\n                    let symlink_path = dirs::SHIMS.join(bin_name);\n                    make_shim(&bin.path(), &symlink_path).await?;\n                }\n            }\n            Ok(())\n        });\n    }\n    jset.join_all()\n        .await\n        .into_iter()\n        .collect::<Result<Vec<_>>>()?;\n\n    Ok(())\n}\n\n/// Remove all shim files from a directory individually, skipping dotfiles like\n/// `.mode`. Uses [`remove_shim_with_rename_fallback`] for each entry so locked\n/// `.exe` files on Windows are renamed out of the way instead of causing a\n/// hard error.\nfn remove_shims_individually(shims_dir: &Path) -> Result<()> {\n    let entries = match shims_dir.read_dir() {\n        Ok(entries) => entries,\n        Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(()),\n        Err(e) => {\n            return Err(e).wrap_err_with(|| {\n                format!(\n                    \"failed to read shims directory: {}\",\n                    display_path(shims_dir)\n                )\n            });\n        }\n    };\n    for entry in entries {\n        let entry = entry?;\n        let name = entry.file_name();\n        // skip dotfiles (e.g. .mode) — these are metadata, not shims\n        if name.to_string_lossy().starts_with('.') {\n            continue;\n        }\n        let path = entry.path();\n        remove_shim_with_rename_fallback(&path)?;\n    }\n    Ok(())\n}\n\n/// Remove a single shim file. On Windows, if deletion fails (e.g. because the\n/// `.exe` is locked by another process), rename it to `<name>.old` so the path\n/// is freed for a new shim. The `.old` file will be cleaned up on the next\n/// reshim or when the lock is released.\nfn remove_shim_with_rename_fallback(path: &Path) -> Result<()> {\n    // First, try to clean up any leftover .old files from a previous run.\n    let old_path = path.with_extension(\"old\");\n    if old_path.exists() {\n        let _ = fs::remove_file(&old_path); // best-effort\n    }\n\n    match fs::remove_file(path) {\n        Ok(()) => Ok(()),\n        Err(e) if cfg!(windows) && matches!(e.raw_os_error(), Some(5) | Some(32)) => {\n            // ERROR_ACCESS_DENIED (5) or ERROR_SHARING_VIOLATION (32): file is\n            // locked by another process, rename it instead.\n            trace!(\n                \"cannot delete locked shim {}, renaming to .old\",\n                display_path(path)\n            );\n            fs::rename(path, &old_path).wrap_err_with(|| {\n                format!(\n                    \"failed to rename locked shim {} to {}\",\n                    display_path(path),\n                    display_path(&old_path)\n                )\n            })?;\n            Ok(())\n        }\n        Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),\n        Err(e) => Err(e).wrap_err_with(|| format!(\"failed to remove shim: {}\", display_path(path))),\n    }\n}\n\n#[cfg(windows)]\nfn find_mise_shim_bin(mise_bin: &Path) -> Option<PathBuf> {\n    // Look next to the mise binary first\n    if let Some(parent) = mise_bin.parent() {\n        let candidate = parent.join(\"mise-shim.exe\");\n        if candidate.is_file() {\n            return Some(candidate);\n        }\n    }\n    // Fall back to searching PATH\n    // Note: file::which on Windows checks extension only, not file existence,\n    // so we must verify the file actually exists.\n    file::which(\"mise-shim.exe\").filter(|p| p.is_file())\n}\n\n/// Resolve the effective Windows shim mode, falling back to \"file\" if \"exe\" is\n/// requested but mise-shim.exe is not available.\n#[cfg(windows)]\nfn effective_shim_mode(mise_bin: &Path) -> String {\n    let mode = Settings::get().windows_shim_mode.clone();\n    if mode == \"exe\" && find_mise_shim_bin(mise_bin).is_none() {\n        warn!(\n            \"mise-shim.exe not found next to {} or on PATH, falling back to \\\"file\\\" shim mode\",\n            display_path(mise_bin)\n        );\n        return \"file\".to_string();\n    }\n    mode\n}\n\n#[cfg(windows)]\nfn add_shim(mise_bin: &Path, symlink_path: &Path, shim: &str) -> Result<()> {\n    match effective_shim_mode(mise_bin).as_ref() {\n        \"exe\" => {\n            if symlink_path.extension().and_then(|s| s.to_str()) == Some(\"exe\") {\n                let mise_shim_bin =\n                    find_mise_shim_bin(mise_bin).ok_or_else(|| eyre!(\"mise-shim.exe not found\"))?;\n                // Copy mise-shim.exe as <tool>.exe\n                fs::copy(&mise_shim_bin, symlink_path).wrap_err_with(|| {\n                    eyre!(\n                        \"Failed to copy {} to {}\",\n                        display_path(&mise_shim_bin),\n                        display_path(symlink_path)\n                    )\n                })?;\n                Ok(())\n            } else {\n                let shim_name = symlink_path\n                    .file_name()\n                    .unwrap_or_default()\n                    .to_string_lossy();\n                // Create extensionless bash script for Git Bash/Cygwin\n                file::write(\n                    symlink_path,\n                    formatdoc! {r#\"\n        #!/bin/bash\n\n        exec mise x -- {shim_name} \"$@\"\n        \"#},\n                )\n                .wrap_err_with(|| {\n                    eyre!(\n                        \"Failed to create shim script for {}\",\n                        display_path(symlink_path)\n                    )\n                })\n            }\n        }\n        \"file\" => {\n            let shim = shim.trim_end_matches(\".cmd\");\n            // write a shim file without extension for use in Git Bash/Cygwin\n            file::write(\n                symlink_path.with_extension(\"\"),\n                formatdoc! {r#\"\n        #!/bin/bash\n\n        exec mise x -- {shim} \"$@\"\n        \"#},\n            )\n            .wrap_err_with(|| {\n                eyre!(\n                    \"Failed to create symlink from {} to {}\",\n                    display_path(mise_bin),\n                    display_path(symlink_path)\n                )\n            })?;\n            file::write(\n                symlink_path.with_extension(\"cmd\"),\n                formatdoc! {r#\"\n        @echo off\n        setlocal\n        mise x -- {shim} %*\n        \"#},\n            )\n            .wrap_err_with(|| {\n                eyre!(\n                    \"Failed to create symlink from {} to {}\",\n                    display_path(mise_bin),\n                    display_path(symlink_path)\n                )\n            })\n        }\n        \"hardlink\" => fs::hard_link(mise_bin, symlink_path).wrap_err_with(|| {\n            eyre!(\n                \"Failed to create hardlink from {} to {}\",\n                display_path(mise_bin),\n                display_path(symlink_path)\n            )\n        }),\n        \"symlink\" => {\n            std::os::windows::fs::symlink_file(mise_bin, symlink_path).wrap_err_with(|| {\n                eyre!(\n                    \"Failed to create symlink from {} to {}\",\n                    display_path(mise_bin),\n                    display_path(symlink_path)\n                )\n            })\n        }\n        _ => panic!(\"Unknown shim mode\"),\n    }\n}\n\n#[cfg(unix)]\nfn add_shim(mise_bin: &Path, symlink_path: &Path, _shim: &str) -> Result<()> {\n    file::make_symlink(mise_bin, symlink_path).wrap_err_with(|| {\n        eyre!(\n            \"Failed to create symlink from {} to {}\",\n            display_path(mise_bin),\n            display_path(symlink_path)\n        )\n    })?;\n    Ok(())\n}\n\n// get_shim_diffs contrasts the actual shims on disk\n// with the desired shims specified by the Toolset\n// and returns a tuple of (missing shims, extra shims)\npub async fn get_shim_diffs(\n    config: &Arc<Config>,\n    mise_bin: impl AsRef<Path>,\n    toolset: &Toolset,\n) -> Result<(BTreeSet<String>, BTreeSet<String>)> {\n    let mise_bin = mise_bin.as_ref();\n    let (actual_shims, desired_shims) = tokio::join!(\n        get_actual_shims(mise_bin),\n        get_desired_shims(config, mise_bin, toolset)\n    );\n    let (actual_shims, desired_shims) = (actual_shims?, desired_shims?);\n    let out: (BTreeSet<String>, BTreeSet<String>) = (\n        desired_shims.difference(&actual_shims).cloned().collect(),\n        actual_shims.difference(&desired_shims).cloned().collect(),\n    );\n    time!(\"get_shim_diffs sizes: ({},{})\", out.0.len(), out.1.len());\n    Ok(out)\n}\n\nasync fn get_actual_shims(mise_bin: impl AsRef<Path>) -> Result<HashSet<String>> {\n    let mise_bin = mise_bin.as_ref();\n\n    Ok(list_shims()?\n        .into_iter()\n        .filter(|bin| {\n            let path = dirs::SHIMS.join(bin);\n\n            !path.is_symlink() || path.read_link().is_ok_and(|p| p == mise_bin)\n        })\n        .collect::<HashSet<_>>())\n}\n\nfn list_executables_in_dir(dir: &Path) -> Result<HashSet<String>> {\n    Ok(dir\n        .read_dir()?\n        .map(|bin| {\n            let bin = bin?;\n            // files and symlinks which are executable\n            if file::is_executable(&bin.path())\n                && (bin.file_type()?.is_file() || bin.file_type()?.is_symlink())\n            {\n                Ok(Some(bin.file_name().into_string().unwrap()))\n            } else {\n                Ok(None)\n            }\n        })\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .flatten()\n        .collect())\n}\n\nfn list_shims() -> Result<HashSet<String>> {\n    Ok(dirs::SHIMS\n        .read_dir()?\n        .map(|bin| {\n            let bin = bin?;\n            let name = bin.file_name();\n            // skip dotfiles (e.g. .mode) — these are metadata, not shims\n            if name.to_string_lossy().starts_with('.') {\n                return Ok(None);\n            }\n            // files and symlinks which are executable or extensionless files (Git Bash/Cygwin)\n            if (file::is_executable(&bin.path()) || bin.path().extension().is_none())\n                && (bin.file_type()?.is_file() || bin.file_type()?.is_symlink())\n            {\n                Ok(Some(bin.file_name().into_string().unwrap()))\n            } else {\n                Ok(None)\n            }\n        })\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .flatten()\n        .collect())\n}\n\nasync fn get_desired_shims(\n    config: &Arc<Config>,\n    mise_bin: &Path,\n    toolset: &Toolset,\n) -> Result<HashSet<String>> {\n    let _mise_bin = mise_bin; // used on Windows only\n    let mut shims = HashSet::new();\n    for (t, tv) in toolset.list_installed_versions(config).await? {\n        let bins = list_tool_bins(config, t.clone(), &tv)\n            .await\n            .unwrap_or_else(|e| {\n                warn!(\"Error listing bin paths for {}: {:#}\", tv, e);\n                Vec::new()\n            });\n        if cfg!(windows) {\n            #[cfg(windows)]\n            let shim_mode = effective_shim_mode(_mise_bin);\n            #[cfg(not(windows))]\n            let shim_mode = String::new();\n            shims.extend(bins.into_iter().flat_map(|b| {\n                let p = PathBuf::from(&b);\n                match shim_mode.as_ref() {\n                    \"hardlink\" | \"symlink\" => {\n                        vec![p.with_extension(\"exe\").to_string_lossy().to_string()]\n                    }\n                    \"exe\" => {\n                        vec![\n                            p.with_extension(\"exe\").to_string_lossy().to_string(),\n                            p.with_extension(\"\").to_string_lossy().to_string(),\n                        ]\n                    }\n                    \"file\" => {\n                        vec![\n                            p.with_extension(\"\").to_string_lossy().to_string(),\n                            p.with_extension(\"cmd\").to_string_lossy().to_string(),\n                        ]\n                    }\n                    _ => panic!(\"Unknown shim mode\"),\n                }\n            }));\n        } else if cfg!(macos) {\n            // some bins might be uppercased but on mac APFS is case insensitive\n            shims.extend(bins.into_iter().map(|b| b.to_lowercase()));\n        } else {\n            shims.extend(bins);\n        }\n    }\n    Ok(shims)\n}\n\n// lists all the paths to bins in a tv that shims will be needed for\nasync fn list_tool_bins(\n    config: &Arc<Config>,\n    t: Arc<dyn Backend>,\n    tv: &ToolVersion,\n) -> Result<Vec<String>> {\n    Ok(t.list_bin_paths(config, tv)\n        .await?\n        .into_iter()\n        .filter(|p| p.parent().is_some())\n        .filter(|path| path.exists())\n        .map(|dir| list_executables_in_dir(&dir))\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .flatten()\n        .collect())\n}\n\nasync fn make_shim(target: &Path, shim: &Path) -> Result<()> {\n    if shim.exists() {\n        file::remove_file_async(shim).await?;\n    }\n    file::write_async(\n        shim,\n        formatdoc! {r#\"\n        #!/bin/sh\n        export ASDF_DATA_DIR={data_dir}\n        export PATH=\"{fake_asdf_dir}:$PATH\"\n        mise x -- {target} \"$@\"\n        \"#,\n        data_dir = dirs::DATA.display(),\n        fake_asdf_dir = fake_asdf::setup()?.display(),\n        target = target.display()},\n    )\n    .await?;\n    file::make_executable_async(shim).await?;\n    trace!(\n        \"shim created from {} to {}\",\n        target.display(),\n        shim.display()\n    );\n    Ok(())\n}\n\nasync fn err_no_version_set(\n    config: &Arc<Config>,\n    ts: Toolset,\n    bin_name: &str,\n    tvs: Vec<ToolVersion>,\n) -> Result<PathBuf> {\n    if tvs.is_empty() {\n        bail!(\n            \"{bin_name} is not a valid shim. This likely means you uninstalled a tool and the shim does not point to anything. Run `mise use <TOOL>` to reinstall the tool.\"\n        );\n    }\n    let missing_plugins = tvs.iter().map(|tv| tv.ba()).collect::<HashSet<_>>();\n    let mut missing_tools = ts\n        .list_missing_versions(config)\n        .await\n        .into_iter()\n        .filter(|t| missing_plugins.contains(t.ba()))\n        .collect_vec();\n    if missing_tools.is_empty() {\n        let mut msg = format!(\"No version is set for shim: {bin_name}\\n\");\n        msg.push_str(\"Set a global default version with one of the following:\\n\");\n        for tv in tvs {\n            msg.push_str(&format!(\"mise use -g {}@{}\\n\", tv.ba(), tv.version));\n        }\n        Err(eyre!(msg.trim().to_string()))\n    } else {\n        let mut msg = format!(\n            \"Tool{} not installed for shim: {}\\n\",\n            if missing_tools.len() > 1 { \"s\" } else { \"\" },\n            bin_name\n        );\n        for t in missing_tools.drain(..) {\n            msg.push_str(&format!(\"Missing tool version: {t}\\n\"));\n        }\n        msg.push_str(\"Install all missing tools with: mise install\\n\");\n        Err(eyre!(msg.trim().to_string()))\n    }\n}\n"
  },
  {
    "path": "src/shorthands.rs",
    "content": "use std::collections::HashMap;\nuse std::path::PathBuf;\n\nuse eyre::Result;\nuse itertools::Itertools;\nuse toml::Table;\n\nuse crate::config::Settings;\nuse crate::registry::REGISTRY;\nuse crate::{dirs, file};\n\npub type Shorthands = HashMap<String, Vec<String>>;\n\npub fn get_shorthands(settings: &Settings) -> Shorthands {\n    let mut shorthands = HashMap::new();\n    if !settings.disable_default_registry {\n        shorthands.extend(\n            REGISTRY\n                .iter()\n                .map(|(id, rt)| {\n                    (\n                        id.to_string(),\n                        rt.backends()\n                            .iter()\n                            .filter(|f| f.starts_with(\"asdf:\") || f.starts_with(\"vfox:\"))\n                            .map(|f| f.to_string())\n                            .collect_vec(),\n                    )\n                })\n                .filter(|(_, fulls)| !fulls.is_empty()),\n        );\n    };\n    if let Some(f) = &settings.shorthands_file {\n        match parse_shorthands_file(f.clone()) {\n            Ok(custom) => {\n                shorthands.extend(custom);\n            }\n            Err(err) => {\n                warn!(\"Failed to read shorthands file: {} {:#}\", &f.display(), err);\n            }\n        }\n    }\n    shorthands\n}\n\nfn parse_shorthands_file(mut f: PathBuf) -> Result<Shorthands> {\n    if f.starts_with(\"~\") {\n        f = dirs::HOME.join(f.strip_prefix(\"~\")?);\n    }\n    let raw = file::read_to_string(&f)?;\n    let toml = raw.parse::<Table>()?;\n\n    let mut shorthands = HashMap::new();\n    for (k, v) in toml {\n        if let Some(v) = v.as_str() {\n            shorthands.insert(k, vec![v.to_string()]);\n        }\n    }\n    Ok(shorthands)\n}\n\n#[cfg(test)]\nmod tests {\n    use std::ops::Deref;\n\n    #[cfg(unix)]\n    use pretty_assertions::assert_str_eq;\n\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_get_shorthands() {\n        use crate::config::Config;\n\n        let _config = Config::get().await.unwrap();\n        Settings::reset(None);\n        let mut settings = Settings::get().deref().clone();\n        settings.shorthands_file = Some(\"../fixtures/shorthands.toml\".into());\n        let shorthands = get_shorthands(&settings);\n        assert_str_eq!(shorthands[\"aapt2\"][0], \"vfox:mise-plugins/vfox-aapt2\");\n        assert_str_eq!(shorthands[\"node\"][0], \"https://node\");\n        assert_str_eq!(shorthands[\"xxxxxx\"][0], \"https://xxxxxx\");\n    }\n\n    #[tokio::test]\n    async fn test_get_shorthands_missing_file() {\n        let _config = Config::get().await.unwrap();\n        Settings::reset(None);\n        let mut settings = Settings::get().deref().clone();\n        settings.shorthands_file = Some(\"test/fixtures/missing.toml\".into());\n        let shorthands = get_shorthands(&settings);\n        assert!(!shorthands.is_empty());\n    }\n}\n"
  },
  {
    "path": "src/sops.rs",
    "content": "use std::sync::Arc;\n\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::file::replace_path;\nuse crate::{dirs, file, result};\nuse eyre::{WrapErr, eyre};\nuse rops::cryptography::cipher::AES256GCM;\nuse rops::cryptography::hasher::SHA512;\nuse rops::file::RopsFile;\nuse rops::file::state::EncryptedFile;\nuse tokio::sync::{Mutex, OnceCell};\n\npub async fn decrypt<PT, F>(\n    config: &Arc<Config>,\n    input: &str,\n    mut parse_template: PT,\n    format: &str,\n) -> result::Result<String>\nwhere\n    PT: FnMut(String) -> result::Result<String>,\n    F: rops::file::format::FileFormat,\n{\n    static AGE_KEY: OnceCell<Option<String>> = OnceCell::const_new();\n    static AGE_KEY_FILE: OnceCell<Option<std::path::PathBuf>> = OnceCell::const_new();\n    static MUTEX: Mutex<()> = Mutex::const_new(());\n\n    let age = AGE_KEY\n        .get_or_init(async || {\n            // 1. Check mise-specific MISE_SOPS_AGE_KEY setting first (highest priority)\n            if let Some(age_key) = &Settings::get().sops.age_key\n                && !age_key.is_empty()\n            {\n                return Some(age_key.clone());\n            }\n\n            // 2. Check mise-specific MISE_SOPS_AGE_KEY_FILE setting\n            if let Some(key_file) = &Settings::get().sops.age_key_file {\n                let p = replace_path(\n                    match parse_template(key_file.to_string_lossy().to_string()) {\n                        Ok(p) => p,\n                        Err(e) => {\n                            warn!(\"failed to parse MISE_SOPS_AGE_KEY_FILE: {}\", e);\n                            return None;\n                        }\n                    },\n                );\n                if p.exists()\n                    && let Ok(raw) = file::read_to_string(&p)\n                {\n                    let key = raw\n                        .trim()\n                        .lines()\n                        .filter(|l| !l.starts_with('#'))\n                        .collect::<String>();\n                    if !key.trim().is_empty() {\n                        // Store the path for later use by sops CLI\n                        let _ = AGE_KEY_FILE.get_or_init(|| async { Some(p.clone()) }).await;\n                        return Some(key);\n                    }\n                }\n            }\n\n            // 3. Check standard SOPS_AGE_KEY_FILE environment variable\n            if let Ok(key_file_path) = env::var(\"SOPS_AGE_KEY_FILE\") {\n                let p = replace_path(match parse_template(key_file_path.clone()) {\n                    Ok(p) => p,\n                    Err(e) => {\n                        warn!(\"failed to parse SOPS_AGE_KEY_FILE: {}\", e);\n                        return None;\n                    }\n                });\n                if p.exists()\n                    && let Ok(raw) = file::read_to_string(&p)\n                {\n                    let key = raw\n                        .trim()\n                        .lines()\n                        .filter(|l| !l.starts_with('#'))\n                        .collect::<String>();\n                    if !key.trim().is_empty() {\n                        // Store the path for later use by sops CLI\n                        let _ = AGE_KEY_FILE.get_or_init(|| async { Some(p.clone()) }).await;\n                        return Some(key);\n                    }\n                }\n            }\n\n            // 4. Check standard SOPS_AGE_KEY environment variable (direct key content)\n            if let Ok(key) = env::var(\"SOPS_AGE_KEY\")\n                && !key.trim().is_empty()\n            {\n                return Some(key.trim().to_string());\n            }\n\n            // 5. Fall back to default path ~/.config/mise/age.txt\n            let p = dirs::CONFIG.join(\"age.txt\");\n            let p = replace_path(match parse_template(p.to_string_lossy().to_string()) {\n                Ok(p) => p,\n                Err(e) => {\n                    warn!(\"failed to parse default sops age key file: {}\", e);\n                    return None;\n                }\n            });\n            if p.exists()\n                && let Ok(raw) = file::read_to_string(p.clone())\n            {\n                let key = raw\n                    .trim()\n                    .lines()\n                    .filter(|l| !l.starts_with('#'))\n                    .collect::<String>();\n                if !key.trim().is_empty() {\n                    // Store the path for later use by sops CLI\n                    let _ = AGE_KEY_FILE.get_or_init(|| async { Some(p.clone()) }).await;\n                    return Some(key);\n                }\n            }\n            None\n        })\n        .await;\n\n    if age.is_none() && !Settings::get().sops.strict {\n        debug!(\"age key not found, skipping decryption in non-strict mode\");\n        return Ok(String::new());\n    }\n\n    let _lock = MUTEX.lock().await; // prevent multiple threads from using the same age key\n    let age_env_key = if Settings::get().sops.rops {\n        \"ROPS_AGE\"\n    } else {\n        \"SOPS_AGE_KEY\"\n    };\n    let prev_age = env::var(age_env_key).ok();\n    let prev_age_key_file = env::var(\"SOPS_AGE_KEY_FILE\").ok();\n\n    // Set SOPS_AGE_KEY_FILE with expanded path if we found one, so sops CLI can use it\n    if let Some(expanded_path) = AGE_KEY_FILE.get().and_then(|f| f.as_ref()) {\n        env::set_var(\n            \"SOPS_AGE_KEY_FILE\",\n            expanded_path.to_string_lossy().to_string(),\n        );\n    }\n\n    if let Some(age) = &age {\n        env::set_var(age_env_key, age.trim());\n    }\n    let output = if Settings::get().sops.rops {\n        match input\n            .parse::<RopsFile<EncryptedFile<AES256GCM, SHA512>, F>>()\n            .wrap_err(\"failed to parse sops file\")\n            .and_then(|file| file.decrypt::<F>().wrap_err(\"failed to decrypt sops file\"))\n        {\n            Ok(decrypted) => Some(decrypted.to_string()),\n            Err(e) => {\n                if Settings::get().sops.strict {\n                    if let Some(age) = prev_age {\n                        env::set_var(age_env_key, age);\n                    } else {\n                        env::remove_var(age_env_key);\n                    }\n                    if let Some(age_key_file) = prev_age_key_file {\n                        env::set_var(\"SOPS_AGE_KEY_FILE\", age_key_file);\n                    } else {\n                        env::remove_var(\"SOPS_AGE_KEY_FILE\");\n                    }\n                    return Err(e);\n                } else {\n                    debug!(\n                        \"sops decryption failed but continuing in non-strict mode: {}\",\n                        e\n                    );\n                    None\n                }\n            }\n        }\n    } else {\n        let mut ts = config\n            .get_tool_request_set()\n            .await\n            .cloned()\n            .unwrap_or_default()\n            .filter_by_tool([\"sops\".into()].into())\n            .into_toolset();\n        Box::pin(ts.resolve(config)).await?;\n        let sops_path = ts.which_bin(config, \"sops\").await;\n\n        match sops_path {\n            None => {\n                if Settings::get().sops.strict {\n                    if let Some(age) = prev_age {\n                        env::set_var(age_env_key, age);\n                    } else {\n                        env::remove_var(age_env_key);\n                    }\n                    if let Some(age_key_file) = prev_age_key_file {\n                        env::set_var(\"SOPS_AGE_KEY_FILE\", age_key_file);\n                    } else {\n                        env::remove_var(\"SOPS_AGE_KEY_FILE\");\n                    }\n                    return Err(eyre!(\"sops command not found\"));\n                } else {\n                    debug!(\"sops command not found, skipping decryption in non-strict mode\");\n                    None\n                }\n            }\n            Some(sops_path) => {\n                let sops = sops_path.to_string_lossy().to_string();\n                // TODO: this obviously won't work on windows\n                match cmd!(\n                    sops,\n                    \"--input-type\",\n                    format,\n                    \"--output-type\",\n                    format,\n                    \"-d\",\n                    \"/dev/stdin\"\n                )\n                .stdin_bytes(input.as_bytes())\n                .read()\n                {\n                    Ok(output) => Some(output),\n                    Err(e) => {\n                        if Settings::get().sops.strict {\n                            if let Some(age) = prev_age {\n                                env::set_var(age_env_key, age);\n                            } else {\n                                env::remove_var(age_env_key);\n                            }\n                            if let Some(age_key_file) = prev_age_key_file {\n                                env::set_var(\"SOPS_AGE_KEY_FILE\", age_key_file);\n                            } else {\n                                env::remove_var(\"SOPS_AGE_KEY_FILE\");\n                            }\n                            return Err(e.into());\n                        } else {\n                            debug!(\n                                \"sops decryption failed but continuing in non-strict mode: {}\",\n                                e\n                            );\n                            None\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    if let Some(age) = prev_age {\n        env::set_var(age_env_key, age);\n    } else {\n        env::remove_var(age_env_key);\n    }\n    if let Some(age_key_file) = prev_age_key_file {\n        env::set_var(\"SOPS_AGE_KEY_FILE\", age_key_file);\n    } else {\n        env::remove_var(\"SOPS_AGE_KEY_FILE\");\n    }\n    Ok(output.unwrap_or_default())\n}\n"
  },
  {
    "path": "src/sysconfig/LICENSE-MIT",
    "content": "MIT License\n\nCopyright (c) 2023 Astral Software Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "src/sysconfig/cursor.rs",
    "content": "#![allow(dead_code)]\n\nuse std::str::Chars;\n\npub(super) const EOF_CHAR: char = '\\0';\n\n/// A cursor represents a pointer in the source code.\n///\n/// Based on [`rustc`'s `Cursor`](https://github.com/rust-lang/rust/blob/d1b7355d3d7b4ead564dbecb1d240fcc74fff21b/compiler/rustc_lexer/src/cursor.rs)\n#[derive(Clone, Debug)]\npub(super) struct Cursor<'src> {\n    /// An iterator over the [`char`]'s of the source code.\n    chars: Chars<'src>,\n\n    /// Stores the previous character for debug assertions.\n    #[cfg(debug_assertions)]\n    prev_char: char,\n}\n\nimpl<'src> Cursor<'src> {\n    pub(super) fn new(source: &'src str) -> Self {\n        Self {\n            chars: source.chars(),\n            #[cfg(debug_assertions)]\n            prev_char: EOF_CHAR,\n        }\n    }\n\n    /// Returns the previous character. Useful for debug assertions.\n    #[cfg(debug_assertions)]\n    pub(super) const fn previous(&self) -> char {\n        self.prev_char\n    }\n\n    /// Peeks the next character from the input stream without consuming it.\n    /// Returns [`EOF_CHAR`] if the position is past the end of the file.\n    pub(super) fn first(&self) -> char {\n        self.chars.clone().next().unwrap_or(EOF_CHAR)\n    }\n\n    /// Peeks the second character from the input stream without consuming it.\n    /// Returns [`EOF_CHAR`] if the position is past the end of the file.\n    pub(super) fn second(&self) -> char {\n        let mut chars = self.chars.clone();\n        chars.next();\n        chars.next().unwrap_or(EOF_CHAR)\n    }\n\n    /// Returns the remaining text to lex.\n    ///\n    /// Use [`Cursor::text_len`] to get the length of the remaining text.\n    pub(super) fn rest(&self) -> &'src str {\n        self.chars.as_str()\n    }\n\n    /// Returns `true` if the cursor is at the end of file.\n    pub(super) fn is_eof(&self) -> bool {\n        self.chars.as_str().is_empty()\n    }\n\n    /// Moves the cursor to the next character, returning the previous character.\n    /// Returns [`None`] if there is no next character.\n    pub(super) fn bump(&mut self) -> Option<char> {\n        let prev = self.chars.next()?;\n\n        #[cfg(debug_assertions)]\n        {\n            self.prev_char = prev;\n        }\n\n        Some(prev)\n    }\n\n    pub(super) fn eat_char(&mut self, c: char) -> bool {\n        if self.first() == c {\n            self.bump();\n            true\n        } else {\n            false\n        }\n    }\n\n    pub(super) fn eat_char2(&mut self, c1: char, c2: char) -> bool {\n        let mut chars = self.chars.clone();\n        if chars.next() == Some(c1) && chars.next() == Some(c2) {\n            self.bump();\n            self.bump();\n            true\n        } else {\n            false\n        }\n    }\n\n    pub(super) fn eat_char3(&mut self, c1: char, c2: char, c3: char) -> bool {\n        let mut chars = self.chars.clone();\n        if chars.next() == Some(c1) && chars.next() == Some(c2) && chars.next() == Some(c3) {\n            self.bump();\n            self.bump();\n            self.bump();\n            true\n        } else {\n            false\n        }\n    }\n\n    pub(super) fn eat_if<F>(&mut self, mut predicate: F) -> Option<char>\n    where\n        F: FnMut(char) -> bool,\n    {\n        if predicate(self.first()) && !self.is_eof() {\n            self.bump()\n        } else {\n            None\n        }\n    }\n\n    /// Eats symbols while predicate returns true or until the end of file is reached.\n    #[inline]\n    pub(super) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {\n        // It was tried making optimized version of this for eg. line comments, but\n        // LLVM can inline all of this and compile it down to fast iteration over bytes.\n        while predicate(self.first()) && !self.is_eof() {\n            self.bump();\n        }\n    }\n\n    /// Skips the next `count` bytes.\n    ///\n    /// ## Panics\n    ///  - If `count` is larger than the remaining bytes in the input stream.\n    ///  - If `count` indexes into a multi-byte character.\n    pub(super) fn skip_bytes(&mut self, count: usize) {\n        #[cfg(debug_assertions)]\n        {\n            self.prev_char = self.chars.as_str()[..count]\n                .chars()\n                .next_back()\n                .unwrap_or('\\0');\n        }\n\n        self.chars = self.chars.as_str()[count..].chars();\n    }\n\n    /// Skips to the end of the input stream.\n    pub(super) fn skip_to_end(&mut self) {\n        self.chars = \"\".chars();\n    }\n}\n"
  },
  {
    "path": "src/sysconfig/mod.rs",
    "content": "//! Patch `sysconfig` data in a Python installation.\n//!\n//! Inspired by: <https://github.com/bluss/sysconfigpatcher/blob/c1ebf8ab9274dcde255484d93ce0f1fd1f76a248/src/sysconfigpatcher.py#L137C1-L140C100>,\n//! available under the MIT license:\n//!\n//! ```text\n//! Copyright 2024 Ulrik Sverdrup \"bluss\"\n//!\n//! Permission is hereby granted, free of charge, to any person obtaining a copy of\n//! this software and associated documentation files (the \"Software\"), to deal in\n//! the Software without restriction, including without limitation the rights to\n//! use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n//! the Software, and to permit persons to whom the Software is furnished to do so,\n//! subject to the following conditions:\n//!\n//! The above copyright notice and this permission notice shall be included in all\n//! copies or substantial portions of the Software.\n//!\n//! THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n//! FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n//! COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n//! IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n//! CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//! ```\n\nuse crate::sysconfig::parser::{Error as ParseError, SysconfigData, Value};\nuse std::collections::BTreeMap;\nuse std::io::Write;\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::sync::LazyLock;\n\nmod cursor;\nmod parser;\n\n/// Replacement mode for sysconfig values.\n#[derive(Debug)]\nenum ReplacementMode {\n    Partial { from: String },\n    Full,\n}\n\n/// A replacement entry to patch in sysconfig data.\n#[derive(Debug)]\nstruct ReplacementEntry {\n    mode: ReplacementMode,\n    to: String,\n}\n\nimpl ReplacementEntry {\n    /// Patches a sysconfig value either partially (replacing a specific word) or fully.\n    fn patch(&self, entry: &str) -> String {\n        match &self.mode {\n            ReplacementMode::Partial { from } => entry\n                .split_whitespace()\n                .map(|word| if word == from { &self.to } else { word })\n                .collect::<Vec<_>>()\n                .join(\" \"),\n            ReplacementMode::Full => self.to.clone(),\n        }\n    }\n}\n\n/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.\nstatic DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, ReplacementEntry>> =\n    LazyLock::new(|| {\n        BTreeMap::from_iter([\n            (\n                \"CC\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang\".to_string(),\n                    },\n                    to: \"cc\".to_string(),\n                },\n            ),\n            (\n                \"CXX\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang++\".to_string(),\n                    },\n                    to: \"c++\".to_string(),\n                },\n            ),\n            (\n                \"BLDSHARED\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang\".to_string(),\n                    },\n                    to: \"cc\".to_string(),\n                },\n            ),\n            (\n                \"LDSHARED\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang\".to_string(),\n                    },\n                    to: \"cc\".to_string(),\n                },\n            ),\n            (\n                \"LDCXXSHARED\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang++\".to_string(),\n                    },\n                    to: \"c++\".to_string(),\n                },\n            ),\n            (\n                \"LINKCC\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Partial {\n                        from: \"clang\".to_string(),\n                    },\n                    to: \"cc\".to_string(),\n                },\n            ),\n            (\n                \"AR\".to_string(),\n                ReplacementEntry {\n                    mode: ReplacementMode::Full,\n                    to: \"ar\".to_string(),\n                },\n            ),\n        ])\n    });\n\n/// Update the `sysconfig` data in a Python installation.\npub(crate) fn update_sysconfig(\n    install_root: &Path,\n    major: u8,\n    minor: u8,\n    suffix: &str,\n) -> Result<(), Error> {\n    // Find the `_sysconfigdata_` file in the Python installation.\n    let real_prefix = std::path::absolute(install_root)?;\n    let sysconfigdata = find_sysconfigdata(&real_prefix, major, minor, suffix)?;\n    trace!(\n        \"Discovered `sysconfig` data at: {}\",\n        sysconfigdata.display()\n    );\n\n    // Update the `_sysconfigdata_` file in-memory.\n    let contents = std::fs::read_to_string(&sysconfigdata)?;\n    let data = SysconfigData::from_str(&contents)?;\n    let data = patch_sysconfigdata(data, &real_prefix);\n    let contents = data.to_string_pretty()?;\n\n    // Write the updated `_sysconfigdata_` file.\n    let mut file = std::fs::OpenOptions::new()\n        .write(true)\n        .truncate(true)\n        .create(true)\n        .open(&sysconfigdata)?;\n    file.write_all(contents.as_bytes())?;\n    file.sync_data()?;\n\n    Ok(())\n}\n\n/// Find the `_sysconfigdata_` file in a Python installation.\n///\n/// For example, on macOS, returns `{real_prefix}/lib/python3.12/_sysconfigdata__darwin_darwin.py\"`.\nfn find_sysconfigdata(\n    real_prefix: &Path,\n    major: u8,\n    minor: u8,\n    suffix: &str,\n) -> Result<PathBuf, Error> {\n    // Find the `lib` directory in the Python installation.\n    let lib_with_suffix = real_prefix\n        .join(\"lib\")\n        .join(format!(\"python{major}.{minor}{suffix}\"));\n    let lib_without_suffix = real_prefix\n        .join(\"lib\")\n        .join(format!(\"python{major}.{minor}\"));\n    let lib = if lib_with_suffix.exists() {\n        lib_with_suffix\n    } else if lib_without_suffix.exists() {\n        lib_without_suffix\n    } else {\n        return Err(Error::MissingLib);\n    };\n\n    // Probe the `lib` directory for `_sysconfigdata_`.\n    for entry in lib.read_dir()? {\n        let entry = entry?;\n\n        if entry.path().extension().is_none_or(|ext| ext != \"py\") {\n            continue;\n        }\n\n        if !entry\n            .path()\n            .file_stem()\n            .and_then(|stem| stem.to_str())\n            .is_some_and(|stem| stem.starts_with(\"_sysconfigdata_\"))\n        {\n            continue;\n        }\n\n        let metadata = entry.metadata()?;\n        if metadata.is_symlink() {\n            continue;\n        };\n\n        if metadata.is_file() {\n            return Ok(entry.path());\n        }\n    }\n\n    Err(Error::MissingSysconfigdata)\n}\n\n/// Patch the given `_sysconfigdata_` contents.\nfn patch_sysconfigdata(mut data: SysconfigData, real_prefix: &Path) -> SysconfigData {\n    /// Update the `/install` prefix in a whitespace-separated string.\n    fn update_prefix(s: &str, real_prefix: &Path) -> String {\n        s.split_whitespace()\n            .map(|part| {\n                if let Some(rest) = part.strip_prefix(\"/install\") {\n                    if rest.is_empty() {\n                        real_prefix.display().to_string()\n                    } else {\n                        real_prefix.join(&rest[1..]).display().to_string()\n                    }\n                } else {\n                    part.to_string()\n                }\n            })\n            .collect::<Vec<_>>()\n            .join(\" \")\n    }\n\n    /// Remove any references to `-isysroot` in a whitespace-separated string.\n    fn remove_isysroot(s: &str) -> String {\n        // If we see `-isysroot`, drop it and the next part.\n        let mut parts = s.split_whitespace().peekable();\n        let mut result = Vec::with_capacity(parts.size_hint().0);\n        while let Some(part) = parts.next() {\n            if part == \"-isysroot\" {\n                parts.next();\n            } else {\n                result.push(part);\n            }\n        }\n        result.join(\" \")\n    }\n\n    // Patch each value, as needed.\n    let mut count = 0;\n    for (key, value) in data.iter_mut() {\n        let Value::String(value) = value else {\n            continue;\n        };\n        let patched = update_prefix(value, real_prefix);\n        let mut patched = remove_isysroot(&patched);\n\n        if let Some(replacement_entry) = DEFAULT_VARIABLE_UPDATES.get(key) {\n            patched = replacement_entry.patch(&patched);\n        }\n\n        if *value != patched {\n            trace!(\"Updated `{key}` from `{value}` to `{patched}`\");\n            count += 1;\n            *value = patched;\n        }\n    }\n\n    match count {\n        0 => trace!(\"No updates required\"),\n        1 => trace!(\"Updated 1 value\"),\n        n => trace!(\"Updated {n} values\"),\n    }\n\n    // Mark the Python installation as standalone.\n    data.insert(\"PYTHON_BUILD_STANDALONE\".to_string(), Value::Int(1));\n\n    data\n}\n\n#[derive(thiserror::Error, Debug)]\npub enum Error {\n    #[error(transparent)]\n    Io(#[from] std::io::Error),\n    #[error(\"Python installation is missing a `lib` directory\")]\n    MissingLib,\n    #[error(\"Python installation is missing a `_sysconfigdata_` file\")]\n    MissingSysconfigdata,\n    #[error(transparent)]\n    Parse(#[from] ParseError),\n    #[error(transparent)]\n    Json(#[from] serde_json::Error),\n}\n\n#[cfg(test)]\n#[cfg(unix)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn update_real_prefix() -> Result<(), Error> {\n        let sysconfigdata = [\n            (\"BASEMODLIBS\", \"\"),\n            (\"BINDIR\", \"/install/bin\"),\n            (\"BINLIBDEST\", \"/install/lib/python3.10\"),\n            (\"BLDLIBRARY\", \"-L. -lpython3.10\"),\n            (\"BUILDPYTHON\", \"python.exe\"),\n            (\"prefix\", \"/install/prefix\"),\n            (\"exec_prefix\", \"/install/exec_prefix\"),\n            (\"base\", \"/install/base\"),\n        ]\n        .into_iter()\n        .map(|(k, v)| (k.to_string(), Value::String(v.to_string())))\n        .collect::<SysconfigData>();\n\n        let real_prefix = Path::new(\"/real/prefix\");\n        let data = patch_sysconfigdata(sysconfigdata, real_prefix);\n\n        insta::assert_snapshot!(data.to_string_pretty()?, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"BASEMODLIBS\": \"\",\n            \"BINDIR\": \"/real/prefix/bin\",\n            \"BINLIBDEST\": \"/real/prefix/lib/python3.10\",\n            \"BLDLIBRARY\": \"-L. -lpython3.10\",\n            \"BUILDPYTHON\": \"python.exe\",\n            \"PYTHON_BUILD_STANDALONE\": 1,\n            \"base\": \"/real/prefix/base\",\n            \"exec_prefix\": \"/real/prefix/exec_prefix\",\n            \"prefix\": \"/real/prefix/prefix\"\n        }\n        \"###);\n\n        Ok(())\n    }\n\n    #[test]\n    fn test_replacements() -> Result<(), Error> {\n        let sysconfigdata = [\n            (\"CC\", \"clang -pthread\"),\n            (\"CXX\", \"clang++ -pthread\"),\n            (\"AR\", \"/tools/llvm/bin/llvm-ar\"),\n        ]\n        .into_iter()\n        .map(|(k, v)| (k.to_string(), Value::String(v.to_string())))\n        .collect::<SysconfigData>();\n\n        let real_prefix = Path::new(\"/real/prefix\");\n        let data = patch_sysconfigdata(sysconfigdata, real_prefix);\n\n        insta::assert_snapshot!(data.to_string_pretty()?, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"AR\": \"ar\",\n            \"CC\": \"cc -pthread\",\n            \"CXX\": \"c++ -pthread\",\n            \"PYTHON_BUILD_STANDALONE\": 1\n        }\n        \"###);\n\n        Ok(())\n    }\n\n    #[test]\n    fn remove_isysroot() -> Result<(), Error> {\n        let sysconfigdata = [\n            (\"BLDSHARED\", \"clang -bundle -undefined dynamic_lookup -arch arm64 -isysroot /Applications/MacOSX14.2.sdk\"),\n        ]\n            .into_iter()\n            .map(|(k, v)| (k.to_string(), Value::String(v.to_string())))\n            .collect::<SysconfigData>();\n\n        let real_prefix = Path::new(\"/real/prefix\");\n        let data = patch_sysconfigdata(sysconfigdata, real_prefix);\n\n        insta::assert_snapshot!(data.to_string_pretty()?, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"BLDSHARED\": \"cc -bundle -undefined dynamic_lookup -arch arm64\",\n            \"PYTHON_BUILD_STANDALONE\": 1\n        }\n        \"###);\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/sysconfig/parser.rs",
    "content": "use std::collections::BTreeMap;\nuse std::str::FromStr;\n\nuse serde::Serialize;\nuse serde_json::ser::PrettyFormatter;\n\nuse crate::sysconfig::cursor::Cursor;\n\n/// A value in the [`SysconfigData`] map.\n///\n/// Values are assumed to be either strings or integers.\n#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize)]\n#[serde(untagged)]\npub(super) enum Value {\n    String(String),\n    Int(i32),\n}\n\n/// The data extracted from a `_sysconfigdata_` file.\n#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize)]\npub(super) struct SysconfigData(BTreeMap<String, Value>);\n\nimpl SysconfigData {\n    /// Returns an iterator over the key-value pairs in the map.\n    pub(super) fn iter_mut(&mut self) -> std::collections::btree_map::IterMut<'_, String, Value> {\n        self.0.iter_mut()\n    }\n\n    /// Inserts a key-value pair into the map.\n    pub(super) fn insert(&mut self, key: String, value: Value) -> Option<Value> {\n        self.0.insert(key, value)\n    }\n\n    /// Formats the `sysconfig` data as a pretty-printed string.\n    pub(super) fn to_string_pretty(&self) -> Result<String, serde_json::Error> {\n        let output = {\n            let mut buf = Vec::new();\n            let mut serializer = serde_json::Serializer::with_formatter(\n                &mut buf,\n                PrettyFormatter::with_indent(b\"    \"),\n            );\n            self.0.serialize(&mut serializer)?;\n            String::from_utf8(buf).unwrap()\n        };\n        Ok(format!(\n            \"# system configuration generated and used by the sysconfig module\\nbuild_time_vars = {output}\\n\",\n        ))\n    }\n}\n\nimpl std::fmt::Display for SysconfigData {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let output = {\n            let mut buf = Vec::new();\n            let mut serializer = serde_json::Serializer::new(&mut buf);\n            self.0.serialize(&mut serializer).unwrap();\n            String::from_utf8(buf).unwrap()\n        };\n        write!(f, \"{output}\",)\n    }\n}\n\nimpl FromIterator<(String, Value)> for SysconfigData {\n    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {\n        Self(iter.into_iter().collect())\n    }\n}\n\n/// Parse the `_sysconfigdata_` file (e.g., `{real_prefix}/lib/python3.12/_sysconfigdata__darwin_darwin.py\"`\n/// on macOS).\n///\n/// `_sysconfigdata_` is structured as follows:\n///\n/// 1. A comment on the first line (e.g., `# system configuration generated and used by the sysconfig module`).\n/// 2. An assignment to `build_time_vars` (e.g., `build_time_vars = { ... }`).\n///\n/// The right-hand side of the assignment is a JSON object. The keys are strings, and the values\n/// are strings or numbers.\nimpl FromStr for SysconfigData {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        // Read the first line of the file.\n        let Some(s) =\n            s.strip_prefix(\"# system configuration generated and used by the sysconfig module\\n\")\n        else {\n            return Err(Error::MissingHeader);\n        };\n\n        // Read the assignment to `build_time_vars`.\n        let Some(s) = s.strip_prefix(\"build_time_vars\") else {\n            return Err(Error::MissingAssignment);\n        };\n\n        let mut cursor = Cursor::new(s);\n\n        cursor.eat_while(is_python_whitespace);\n        if !cursor.eat_char('=') {\n            return Err(Error::MissingAssignment);\n        }\n        cursor.eat_while(is_python_whitespace);\n\n        if !cursor.eat_char('{') {\n            return Err(Error::MissingOpenBrace);\n        }\n\n        let mut map = BTreeMap::new();\n        loop {\n            let Some(next) = cursor.bump() else {\n                return Err(Error::UnexpectedEof);\n            };\n\n            match next {\n                '\\'' | '\"' => {\n                    // Parse key.\n                    let key = parse_string(&mut cursor, next)?;\n\n                    cursor.eat_while(is_python_whitespace);\n                    cursor.eat_char(':');\n                    cursor.eat_while(is_python_whitespace);\n\n                    // Parse value\n                    let value = match cursor.first() {\n                        '\\'' | '\"' => Value::String(parse_concatenated_string(&mut cursor)?),\n                        '-' => {\n                            cursor.bump();\n                            Value::Int(-parse_int(&mut cursor)?)\n                        }\n                        c if c.is_ascii_digit() => Value::Int(parse_int(&mut cursor)?),\n                        c => return Err(Error::UnexpectedCharacter(c)),\n                    };\n\n                    // Insert into map.\n                    map.insert(key, value);\n\n                    // Skip optional comma.\n                    cursor.eat_while(is_python_whitespace);\n                    cursor.eat_char(',');\n                    cursor.eat_while(is_python_whitespace);\n                }\n\n                // Skip whitespace.\n                ' ' | '\\n' | '\\r' | '\\t' => {}\n\n                // When we see a closing brace, we're done.\n                '}' => {\n                    break;\n                }\n\n                c => return Err(Error::UnexpectedCharacter(c)),\n            }\n        }\n\n        Ok(Self(map))\n    }\n}\n\n/// Parse a Python string literal.\n///\n/// Expects the previous character to be the opening quote character.\nfn parse_string(cursor: &mut Cursor, quote: char) -> Result<String, Error> {\n    let mut result = String::new();\n    loop {\n        let Some(c) = cursor.bump() else {\n            return Err(Error::UnexpectedEof);\n        };\n        match c {\n            '\\\\' => {\n                // Handle escaped quotes.\n                if cursor.first() == quote {\n                    // Consume the backslash.\n                    cursor.bump();\n                    result.push(quote);\n                    continue;\n                }\n\n                // Keep the backslash and following character.\n                result.push('\\\\');\n                result.push(cursor.first());\n                cursor.bump();\n            }\n\n            // Consume closing quote.\n            c if c == quote => {\n                break;\n            }\n\n            c => {\n                result.push(c);\n            }\n        }\n    }\n    Ok(result)\n}\n\n/// Parse a Python string, which may be a concatenation of multiple string literals.\n///\n/// Expects the cursor to start at an opening quote character.\nfn parse_concatenated_string(cursor: &mut Cursor) -> Result<String, Error> {\n    let mut result = String::new();\n    loop {\n        let Some(c) = cursor.bump() else {\n            return Err(Error::UnexpectedEof);\n        };\n        match c {\n            '\\'' | '\"' => {\n                // Parse a new string fragment and append it.\n                result.push_str(&parse_string(cursor, c)?);\n            }\n            c if is_python_whitespace(c) => {\n                // Skip whitespace between fragments\n            }\n            c => return Err(Error::UnexpectedCharacter(c)),\n        }\n\n        // Lookahead to the end of the string.\n        if matches!(cursor.first(), ',' | '}') {\n            break;\n        }\n    }\n    Ok(result)\n}\n\n/// Parse an integer literal.\n///\n/// Expects the cursor to start at the first digit of the integer.\nfn parse_int(cursor: &mut Cursor) -> Result<i32, std::num::ParseIntError> {\n    let mut result = String::new();\n    loop {\n        let c = cursor.first();\n        if !c.is_ascii_digit() {\n            break;\n        }\n        result.push(c);\n        cursor.bump();\n    }\n    result.parse()\n}\n\n/// Returns `true` for [whitespace](https://docs.python.org/3/reference/lexical_analysis.html#whitespace-between-tokens)\n/// characters.\nconst fn is_python_whitespace(c: char) -> bool {\n    matches!(\n        c,\n        // Space, tab, form-feed, newline, or carriage return\n        ' ' | '\\t' | '\\x0C' | '\\n' | '\\r'\n    )\n}\n\n#[derive(thiserror::Error, Debug)]\npub enum Error {\n    #[error(\"Missing opening brace\")]\n    MissingOpenBrace,\n    #[error(\"Unexpected character: {0}\")]\n    UnexpectedCharacter(char),\n    #[error(\"Unexpected end of file\")]\n    UnexpectedEof,\n    #[error(\"Failed to parse integer\")]\n    ParseInt(#[from] std::num::ParseIntError),\n    #[error(\"`_sysconfigdata_` is missing a header comment\")]\n    MissingHeader,\n    #[error(\"`_sysconfigdata_` is missing an assignment to `build_time_vars`\")]\n    MissingAssignment,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_string() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": \"value1\",\n                \"key2\": 42,\n                \"key3\": \"multi-part\" \" string\"\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>().expect(\"Parsing failed\");\n        let snapshot = result.to_string_pretty().unwrap();\n\n        insta::assert_snapshot!(snapshot, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"key1\": \"value1\",\n            \"key2\": 42,\n            \"key3\": \"multi-part string\"\n        }\n        \"###);\n    }\n\n    #[test]\n    fn test_parse_trailing_comma() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": \"value1\",\n                \"key2\": 42,\n                \"key3\": \"multi-part\" \" string\",\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>().expect(\"Parsing failed\");\n        let snapshot = result.to_string_pretty().unwrap();\n\n        insta::assert_snapshot!(snapshot, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"key1\": \"value1\",\n            \"key2\": 42,\n            \"key3\": \"multi-part string\"\n        }\n        \"###);\n    }\n\n    #[test]\n    fn test_parse_integer_values() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": 12345,\n                \"key2\": -15\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>().expect(\"Parsing failed\");\n        let snapshot = result.to_string_pretty().unwrap();\n\n        insta::assert_snapshot!(snapshot, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"key1\": 12345,\n            \"key2\": -15\n        }\n        \"###);\n    }\n\n    #[test]\n    fn test_parse_escaped_quotes() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": \"value with \\\"escaped quotes\\\"\",\n                \"key2\": 'single-quoted \\'escaped\\''\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>().expect(\"Parsing failed\");\n        let snapshot = result.to_string_pretty().unwrap();\n\n        insta::assert_snapshot!(snapshot, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"key1\": \"value with \\\"escaped quotes\\\"\",\n            \"key2\": \"single-quoted 'escaped'\"\n        }\n        \"###);\n    }\n\n    #[test]\n    fn test_parse_concatenated_strings() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": \"multi-\"\n                        \"line \"\n                        \"string\"\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>().expect(\"Parsing failed\");\n        let snapshot = result.to_string_pretty().unwrap();\n\n        insta::assert_snapshot!(snapshot, @r###\"\n        # system configuration generated and used by the sysconfig module\n        build_time_vars = {\n            \"key1\": \"multi-line string\"\n        }\n        \"###);\n    }\n\n    #[test]\n    fn test_missing_header_error() {\n        let input = indoc::indoc!(\n            r#\"\n            build_time_vars = {\n                \"key1\": \"value1\"\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>();\n        assert!(matches!(result, Err(Error::MissingHeader)));\n    }\n\n    #[test]\n    fn test_missing_assignment_error() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            {\n                \"key1\": \"value1\"\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>();\n        assert!(matches!(result, Err(Error::MissingAssignment)));\n    }\n\n    #[test]\n    fn test_unexpected_character_error() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": &123\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>();\n        assert!(\n            result.is_err(),\n            \"Expected parsing to fail due to unexpected character\"\n        );\n    }\n\n    #[test]\n    fn test_unexpected_eof() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": 123\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>();\n        assert!(\n            result.is_err(),\n            \"Expected parsing to fail due to unexpected character\"\n        );\n    }\n\n    #[test]\n    fn test_unexpected_comma() {\n        let input = indoc::indoc!(\n            r#\"\n            # system configuration generated and used by the sysconfig module\n            build_time_vars = {\n                \"key1\": 123,,\n            }\n        \"#\n        );\n\n        let result = input.parse::<SysconfigData>();\n        assert!(\n            result.is_err(),\n            \"Expected parsing to fail due to unexpected character\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/task/deps.rs",
    "content": "use crate::config::env_directive::EnvDirective;\nuse crate::task::Task;\nuse crate::{config::Config, task::task_list::resolve_depends};\nuse itertools::Itertools;\nuse petgraph::Direction;\nuse petgraph::graph::DiGraph;\nuse std::{\n    collections::{HashMap, HashSet},\n    sync::Arc,\n};\nuse tokio::sync::mpsc;\n\n/// Unique key for a task instance, including name, args, and env vars\npub type TaskKey = (String, Vec<String>, Vec<(String, String)>);\n\n#[derive(Debug)]\npub struct Deps {\n    pub graph: DiGraph<Task, ()>,\n    sent: HashSet<TaskKey>, // tasks that have already started so should not run again\n    removed: HashSet<TaskKey>, // tasks that have already finished to track if we are in an infinitve loop\n    executed: HashSet<TaskKey>, // tasks that actually began executing (not just scheduled)\n    post_dep_parents: HashMap<TaskKey, HashSet<TaskKey>>, // maps each post-dep to its parent tasks\n    tx: mpsc::UnboundedSender<Option<Task>>,\n    // not clone, notify waiters via tx None\n}\n\n/// Extract a hashable key from a task, including env vars set via dependencies\npub fn task_key(task: &Task) -> TaskKey {\n    // Extract simple key-value env vars for deduplication\n    // This ensures tasks with same name/args but different env are treated as distinct\n    let env_key: Vec<(String, String)> = task\n        .env\n        .0\n        .iter()\n        .filter_map(|d| match d {\n            EnvDirective::Val(k, v, _) => Some((k.clone(), v.clone())),\n            _ => None,\n        })\n        .sorted()\n        .collect();\n    (task.name.clone(), task.args.clone(), env_key)\n}\n\n/// manages a dependency graph of tasks so `mise run` knows what to run next\nimpl Deps {\n    pub async fn new(config: &Arc<Config>, tasks: Vec<Task>) -> eyre::Result<Self> {\n        let mut graph = DiGraph::new();\n        let mut indexes = HashMap::new();\n        let mut stack = vec![];\n        let mut seen = HashSet::new();\n        let mut post_dep_parents: HashMap<TaskKey, HashSet<TaskKey>> = HashMap::new();\n\n        let mut add_idx = |task: &Task, graph: &mut DiGraph<Task, ()>| {\n            *indexes\n                .entry(task_key(task))\n                .or_insert_with(|| graph.add_node(task.clone()))\n        };\n\n        // first we add all tasks to the graph, create a stack of work for this function, and\n        // store the index of each task in the graph\n        for t in &tasks {\n            stack.push(t.clone());\n            add_idx(t, &mut graph);\n        }\n        let all_tasks_to_run = resolve_depends(config, tasks).await?;\n        while let Some(a) = stack.pop() {\n            if seen.contains(&a) {\n                // prevent infinite loop\n                continue;\n            }\n            let a_idx = add_idx(&a, &mut graph);\n            let (pre, post) = a.resolve_depends(config, &all_tasks_to_run).await?;\n            for b in pre {\n                let b_idx = add_idx(&b, &mut graph);\n                graph.update_edge(a_idx, b_idx, ());\n                stack.push(b.clone());\n            }\n            for b in post {\n                let b_idx = add_idx(&b, &mut graph);\n                graph.update_edge(b_idx, a_idx, ());\n                post_dep_parents\n                    .entry(task_key(&b))\n                    .or_default()\n                    .insert(task_key(&a));\n                stack.push(b.clone());\n            }\n            seen.insert(a);\n        }\n        let (tx, _) = mpsc::unbounded_channel();\n        let sent = HashSet::new();\n        let removed = HashSet::new();\n        let executed = HashSet::new();\n        Ok(Self {\n            graph,\n            tx,\n            sent,\n            removed,\n            executed,\n            post_dep_parents,\n        })\n    }\n\n    /// Create a sub-graph that prunes tasks already completed by the caller.\n    /// `completed` is a snapshot of task keys that have finished in the parent\n    /// graph — these are removed from the sub-graph so they don't run again.\n    pub async fn new_pruned(\n        config: &Arc<Config>,\n        tasks: Vec<Task>,\n        completed: &HashSet<TaskKey>,\n    ) -> eyre::Result<Self> {\n        let mut deps = Self::new(config, tasks).await?;\n        let mut to_remove = vec![];\n        for idx in deps.graph.node_indices() {\n            let key = task_key(&deps.graph[idx]);\n            if completed.contains(&key) {\n                to_remove.push(idx);\n            }\n        }\n        // Remove in reverse index order so petgraph swap-remove\n        // doesn't invalidate indices we haven't processed yet\n        to_remove.sort_unstable_by(|a, b| b.cmp(a));\n        for idx in to_remove {\n            deps.graph.remove_node(idx);\n        }\n        deps.mark_ambiguous_prefixes();\n        Ok(deps)\n    }\n\n    /// main method to emit tasks that no longer have dependencies being waited on\n    fn emit_leaves(&mut self) {\n        let leaves = leaves(&self.graph);\n        let leaves_is_empty = leaves.is_empty();\n\n        for task in leaves {\n            let key = task_key(&task);\n\n            if self.sent.insert(key) {\n                trace!(\"Scheduling task {0}\", task.name);\n                if let Err(e) = self.tx.send(Some(task)) {\n                    trace!(\"Error sending task: {e:?}\");\n                }\n            }\n        }\n\n        if self.is_empty() {\n            trace!(\"All tasks finished\");\n            if let Err(e) = self.tx.send(None) {\n                trace!(\"Error closing task stream: {e:?}\");\n            }\n        } else if leaves_is_empty && self.sent.len() == self.removed.len() {\n            panic!(\n                \"Infinitive loop detected, all tasks are finished but the graph isn't empty {0} {1:#?}\",\n                self.all().map(|t| t.name.clone()).join(\", \"),\n                self.graph\n            )\n        }\n    }\n\n    /// listened to by `mise run` which gets a stream of tasks to run\n    pub fn subscribe(&mut self) -> mpsc::UnboundedReceiver<Option<Task>> {\n        let (tx, rx) = mpsc::unbounded_channel();\n        self.tx = tx;\n        self.emit_leaves();\n        rx\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.graph.node_count() == 0\n    }\n\n    /// Snapshot of task keys that have completed (removed from the graph).\n    /// Used by `new_pruned` so sub-graphs skip tasks the parent already ran.\n    /// Only includes confirmed-complete tasks, not in-flight ones, to\n    /// preserve dependency ordering in the sub-graph.\n    pub fn handled_task_keys(&self) -> HashSet<TaskKey> {\n        self.removed.clone()\n    }\n\n    /// Check if a post-dep task should actually run: it must be a post-dependency\n    /// AND its parent must have actually started executing (not just been scheduled).\n    /// Returns false for non-post-dep tasks or post-deps whose parent was never executed.\n    pub fn is_runnable_post_dep(&self, task: &Task) -> bool {\n        let key = task_key(task);\n        match self.post_dep_parents.get(&key) {\n            Some(parent_keys) => parent_keys.iter().any(|pk| self.executed.contains(pk)),\n            None => false,\n        }\n    }\n\n    /// Mark a task as having actually started execution.\n    /// This is distinct from being scheduled (sent) — a task may be scheduled as a\n    /// graph leaf but then skipped because an earlier task failed.\n    pub fn mark_executed(&mut self, task: &Task) {\n        self.executed.insert(task_key(task));\n    }\n\n    /// Remove multiple tasks from the graph in a batch, emitting leaves only once at the end.\n    /// This prevents intermediate emit_leaves from scheduling tasks that will be removed later.\n    pub fn remove_batch(&mut self, tasks: &[Task]) {\n        for task in tasks {\n            if let Some(idx) = self.node_idx(task) {\n                self.graph.remove_node(idx);\n                let key = task_key(task);\n                self.removed.insert(key);\n            }\n        }\n        self.emit_leaves();\n    }\n\n    // use contracts::{ensures, requires};\n    // #[requires(self.graph.node_count() > 0)]\n    // #[ensures(self.graph.node_count() == old(self.graph.node_count()) - 1)]\n    pub fn remove(&mut self, task: &Task) {\n        if let Some(idx) = self.node_idx(task) {\n            self.graph.remove_node(idx);\n            let key = task_key(task);\n            self.removed.insert(key);\n            self.emit_leaves();\n        }\n    }\n\n    fn node_idx(&self, task: &Task) -> Option<petgraph::graph::NodeIndex> {\n        self.graph\n            .node_indices()\n            .find(|&idx| &self.graph[idx] == task)\n    }\n\n    pub fn all(&self) -> impl Iterator<Item = &Task> {\n        self.graph.node_indices().map(|idx| &self.graph[idx])\n    }\n\n    /// Mark tasks that share a display_name so their prefix includes args\n    /// for disambiguation (e.g. `[test-docker 4.1]` vs `[test-docker 4.2]`).\n    pub fn mark_ambiguous_prefixes(&mut self) {\n        let mut name_to_indices: HashMap<String, Vec<petgraph::graph::NodeIndex>> = HashMap::new();\n        for idx in self.graph.node_indices() {\n            name_to_indices\n                .entry(self.graph[idx].display_name.clone())\n                .or_default()\n                .push(idx);\n        }\n        for indices in name_to_indices.values() {\n            if indices.len() > 1 {\n                for &idx in indices {\n                    self.graph[idx].show_args_in_prefix = true;\n                }\n            }\n        }\n    }\n\n    pub fn is_linear(&self) -> bool {\n        let mut graph = self.graph.clone();\n        // pop dependencies off, if we get multiple dependencies at once it's not linear\n        loop {\n            let leaves = leaves(&graph);\n            if leaves.is_empty() {\n                return true;\n            } else if leaves.len() > 1 {\n                return false;\n            } else {\n                let idx = self\n                    .graph\n                    .node_indices()\n                    .find(|&idx| graph[idx] == leaves[0])\n                    .unwrap();\n                graph.remove_node(idx);\n            }\n        }\n    }\n}\n\nfn leaves(graph: &DiGraph<Task, ()>) -> Vec<Task> {\n    graph\n        .externals(Direction::Outgoing)\n        .map(|idx| graph[idx].clone())\n        .collect()\n}\n"
  },
  {
    "path": "src/task/mod.rs",
    "content": "use crate::config::config_file::mise_toml::EnvList;\nuse crate::config::config_file::toml::{TrackingTomlParser, deserialize_arr};\nuse crate::config::env_directive::{EnvDirective, EnvResolveOptions, EnvResults, ToolsFilter};\nuse crate::config::{self, Config};\nuse crate::path_env::PathEnv;\nuse crate::task::task_script_parser::TaskScriptParser;\nuse crate::tera::get_tera;\nuse crate::ui::tree::TreeItem;\nuse crate::{dirs, env, file};\nuse console::{Color, measure_text_width, truncate_str};\nuse eyre::{Result, bail, eyre};\nuse fuzzy_matcher::FuzzyMatcher;\nuse fuzzy_matcher::skim::SkimMatcherV2;\nuse globset::GlobBuilder;\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse petgraph::prelude::*;\nuse serde::{Deserialize, Serialize};\nuse std::borrow::Cow;\nuse std::cmp::Ordering;\nuse std::collections::BTreeMap;\nuse std::collections::HashSet;\nuse std::fmt::{Debug, Display, Formatter};\nuse std::hash::{Hash, Hasher};\nuse std::iter::once;\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::sync::LazyLock as Lazy;\nuse std::{ffi, fmt, path};\nuse xx::regex;\n\nstatic FUZZY_MATCHER: Lazy<SkimMatcherV2> =\n    Lazy::new(|| SkimMatcherV2::default().use_cache(true).smart_case());\nstatic TASK_VARS_CACHE: Lazy<std::sync::Mutex<IndexMap<PathBuf, IndexMap<String, String>>>> =\n    Lazy::new(|| std::sync::Mutex::new(IndexMap::new()));\n\npub(crate) fn reset() {\n    TASK_VARS_CACHE.lock().unwrap().clear();\n}\n\n/// Type alias for tracking failed tasks with their exit codes\npub type FailedTasks = Arc<std::sync::Mutex<Vec<(Task, Option<i32>)>>>;\n\nmod deps;\npub mod task_context_builder;\nmod task_dep;\npub mod task_executor;\npub mod task_fetcher;\npub mod task_file_providers;\npub mod task_helpers;\npub mod task_list;\nmod task_load_context;\npub mod task_output;\npub mod task_output_handler;\npub mod task_results_display;\npub mod task_scheduler;\nmod task_script_parser;\npub mod task_source_checker;\npub mod task_sources;\npub mod task_template;\npub mod task_tool_installer;\n\npub use task_load_context::{TaskLoadContext, expand_colon_task_syntax};\npub use task_output::TaskOutput;\npub use task_script_parser::has_any_args_defined;\npub use task_template::TaskTemplate;\n\nuse crate::config::config_file::ConfigFile;\nuse crate::env_diff::EnvMap;\nuse crate::file::display_path;\nuse crate::toolset::Toolset;\nuse crate::ui::style;\npub use deps::{Deps, TaskKey};\nuse task_dep::TaskDep;\nuse task_sources::{RawOutputTemplates, TaskOutputs};\n\n#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]\n#[serde(untagged)]\npub enum RunEntry {\n    /// Shell script entry\n    Script(String),\n    /// Run a single task with optional args\n    SingleTask { task: String },\n    /// Run multiple tasks in parallel\n    TaskGroup { tasks: Vec<String> },\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]\npub enum Silent {\n    #[default]\n    Off,\n    Bool(bool),\n    Stdout,\n    Stderr,\n}\n\nimpl Silent {\n    pub fn is_silent(&self) -> bool {\n        matches!(self, Silent::Bool(true) | Silent::Stdout | Silent::Stderr)\n    }\n\n    pub fn suppresses_stdout(&self) -> bool {\n        matches!(self, Silent::Bool(true) | Silent::Stdout)\n    }\n\n    pub fn suppresses_stderr(&self) -> bool {\n        matches!(self, Silent::Bool(true) | Silent::Stderr)\n    }\n\n    pub fn suppresses_both(&self) -> bool {\n        matches!(self, Silent::Bool(true))\n    }\n}\n\nimpl Serialize for Silent {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        match self {\n            Silent::Off | Silent::Bool(false) => serializer.serialize_bool(false),\n            Silent::Bool(true) => serializer.serialize_bool(true),\n            Silent::Stdout => serializer.serialize_str(\"stdout\"),\n            Silent::Stderr => serializer.serialize_str(\"stderr\"),\n        }\n    }\n}\n\nimpl From<bool> for Silent {\n    fn from(b: bool) -> Self {\n        if b { Silent::Bool(true) } else { Silent::Off }\n    }\n}\n\nimpl std::str::FromStr for Silent {\n    type Err = String;\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"true\" => Ok(Silent::Bool(true)),\n            \"false\" => Ok(Silent::Off),\n            \"stdout\" => Ok(Silent::Stdout),\n            \"stderr\" => Ok(Silent::Stderr),\n            _ => Err(format!(\n                \"invalid silent value: {}, expected true, false, 'stdout', or 'stderr'\",\n                s\n            )),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for Silent {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        struct SilentVisitor;\n\n        impl<'de> serde::de::Visitor<'de> for SilentVisitor {\n            type Value = Silent;\n\n            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {\n                formatter.write_str(\"a boolean or a string ('stdout' or 'stderr')\")\n            }\n\n            fn visit_bool<E>(self, value: bool) -> Result<Silent, E>\n            where\n                E: serde::de::Error,\n            {\n                Ok(Silent::from(value))\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<Silent, E>\n            where\n                E: serde::de::Error,\n            {\n                match value {\n                    \"stdout\" => Ok(Silent::Stdout),\n                    \"stderr\" => Ok(Silent::Stderr),\n                    _ => Err(E::custom(format!(\n                        \"invalid silent value: '{}', expected 'stdout' or 'stderr'\",\n                        value\n                    ))),\n                }\n            }\n        }\n\n        deserializer.deserialize_any(SilentVisitor)\n    }\n}\n\nimpl std::str::FromStr for RunEntry {\n    type Err = String;\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(RunEntry::Script(s.to_string()))\n    }\n}\n\nimpl Display for RunEntry {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        match self {\n            RunEntry::Script(s) => write!(f, \"{}\", s),\n            RunEntry::SingleTask { task } => write!(f, \"task: {task}\"),\n            RunEntry::TaskGroup { tasks } => write!(f, \"tasks: {}\", tasks.join(\", \")),\n        }\n    }\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct Task {\n    #[serde(skip)]\n    pub name: String,\n    #[serde(skip)]\n    pub display_name: String,\n    #[serde(default)]\n    pub description: String,\n    #[serde(default, rename = \"alias\", deserialize_with = \"deserialize_arr\")]\n    pub aliases: Vec<String>,\n    #[serde(skip)]\n    pub config_source: PathBuf,\n    #[serde(skip)]\n    pub cf: Option<Arc<dyn ConfigFile>>,\n    #[serde(skip)]\n    pub config_root: Option<PathBuf>,\n    #[serde(default)]\n    pub confirm: Option<String>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub depends: Vec<TaskDep>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub depends_post: Vec<TaskDep>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub wait_for: Vec<TaskDep>,\n    #[serde(default)]\n    pub env: EnvList,\n    #[serde(default)]\n    pub vars: EnvList,\n    /// Env vars inherited from parent tasks at runtime (not used for task identity/deduplication)\n    #[serde(skip)]\n    pub inherited_env: EnvList,\n    #[serde(default)]\n    pub dir: Option<String>,\n    #[serde(default)]\n    pub hide: bool,\n    #[serde(default)]\n    pub global: bool,\n    #[serde(default)]\n    pub raw: bool,\n    #[serde(default)]\n    pub interactive: bool,\n    #[serde(default)]\n    pub sources: Vec<String>,\n    #[serde(default)]\n    pub outputs: TaskOutputs,\n    #[serde(skip)]\n    pub raw_outputs: RawOutputTemplates,\n    #[serde(default)]\n    pub shell: Option<String>,\n    #[serde(default)]\n    pub quiet: bool,\n    #[serde(default)]\n    pub silent: Silent,\n    #[serde(default)]\n    pub tools: IndexMap<String, String>,\n    #[serde(default)]\n    pub usage: String,\n    #[serde(default)]\n    pub timeout: Option<String>,\n\n    // normal type\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub run: Vec<RunEntry>,\n\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub run_windows: Vec<RunEntry>,\n\n    // command type\n    // pub command: Option<String>,\n    #[serde(default)]\n    pub args: Vec<String>,\n\n    // script type\n    // pub script: Option<String>,\n\n    // file type\n    #[serde(default)]\n    pub file: Option<PathBuf>,\n\n    // Store the original remote file source (git::/http:/https:) before it's replaced with local path\n    // This is used to determine if the task should use monorepo config file context\n    #[serde(skip)]\n    pub remote_file_source: Option<String>,\n\n    /// Name of the task template to extend (requires experimental = true)\n    #[serde(default)]\n    pub extends: Option<String>,\n\n    /// When true, include args in the output prefix to disambiguate tasks\n    /// with the same display_name but different arguments.\n    #[serde(skip)]\n    pub show_args_in_prefix: bool,\n}\n\nimpl Task {\n    pub fn new(path: &Path, prefix: &Path, config_root: &Path) -> Result<Task> {\n        Ok(Self {\n            name: name_from_path(prefix, path)?,\n            config_source: path.to_path_buf(),\n            config_root: Some(config_root.to_path_buf()),\n            ..Default::default()\n        })\n    }\n\n    pub async fn from_path(\n        config: &Arc<Config>,\n        path: &Path,\n        prefix: &Path,\n        config_root: &Path,\n    ) -> Result<Task> {\n        let mut task = Task::new(path, prefix, config_root)?;\n        let info = file::read_to_string(path)?\n            .lines()\n            .filter_map(|line| {\n                regex!(r\"^(?:#|//|::)(?:MISE| ?\\[MISE\\]) ([a-z0-9_.-]+\\s*=\\s*[^\\n]+)$\")\n                    .captures(line)\n            })\n            .map(|captures| captures.extract().1)\n            .map(|[toml]| {\n                toml::de::from_str::<toml::Value>(toml)\n                    .map_err(|e| eyre::eyre!(\"failed to parse task header TOML {toml:?}: {e}\"))\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .filter_map(|toml| toml.as_table().cloned())\n            .flatten()\n            .fold(toml::Table::new(), |mut map, (key, value)| {\n                // Deep-merge tables when both existing and new values are tables\n                // This allows multiple #MISE lines like:\n                //   #MISE tools.terraform=\"1\"\n                //   #MISE tools.tflint=\"0\"\n                // to be merged into a single tools table\n                // See: https://github.com/jdx/mise/discussions/7839\n                if let Some(existing) = map.get_mut(&key) {\n                    if let (toml::Value::Table(existing_table), toml::Value::Table(new_table)) =\n                        (existing, &value)\n                    {\n                        for (k, v) in new_table {\n                            existing_table.insert(k.clone(), v.clone());\n                        }\n                    } else {\n                        map.insert(key, value);\n                    }\n                } else {\n                    map.insert(key, value);\n                }\n                map\n            });\n        let info = toml::Value::Table(info);\n\n        let mut p = TrackingTomlParser::new(&info);\n        // trace!(\"task info: {:#?}\", info);\n\n        task.description = p.parse_str(\"description\").unwrap_or_default();\n        // Check for multiple alias fields before parsing\n        let alias_fields: Vec<&str> = [\"alias\", \"aliases\"]\n            .iter()\n            .filter(|&field| info.get(field).is_some())\n            .copied()\n            .collect();\n\n        if alias_fields.len() > 1 {\n            return Err(eyre::eyre!(\n                \"Cannot define both 'alias' and 'aliases' fields in task file header: {}. Use only one.\",\n                display_path(path)\n            ));\n        }\n\n        task.aliases = p\n            .parse_array(\"alias\")\n            .or(p.parse_array(\"aliases\"))\n            .or(p.parse_str(\"alias\").map(|s| vec![s]))\n            .or(p.parse_str(\"aliases\").map(|s| vec![s]))\n            .unwrap_or_default();\n        task.confirm = p.parse_str(\"confirm\");\n        task.depends = p.parse_array(\"depends\").unwrap_or_default();\n        task.depends_post = p.parse_array(\"depends_post\").unwrap_or_default();\n        task.wait_for = p.parse_array(\"wait_for\").unwrap_or_default();\n        task.env = p.parse_env(\"env\")?.unwrap_or_default();\n        task.dir = p.parse_str(\"dir\");\n        task.hide = !file::is_executable(path) || p.parse_bool(\"hide\").unwrap_or_default();\n        task.raw = p.parse_bool(\"raw\").unwrap_or_default();\n        task.interactive = p.parse_bool(\"interactive\").unwrap_or_default();\n        task.sources = p.parse_array(\"sources\").unwrap_or_default();\n        task.outputs = p.get_raw(\"outputs\").map(|to| to.into()).unwrap_or_default();\n        task.file = Some(path.to_path_buf());\n        task.shell = p.parse_str(\"shell\");\n        task.quiet = p.parse_bool(\"quiet\").unwrap_or_default();\n        task.silent = p\n            .get_raw(\"silent\")\n            .and_then(|v| Silent::deserialize(v.clone()).ok())\n            .unwrap_or_default();\n        task.tools = p\n            .parse_table(\"tools\")\n            .map(|t| {\n                t.into_iter()\n                    .filter_map(|(k, v)| v.as_str().map(|vs| (k, vs.to_string())))\n                    .collect()\n            })\n            .unwrap_or_default();\n\n        let mut unparsed = p.unparsed_keys();\n        unparsed.sort();\n\n        if !unparsed.is_empty() {\n            return Err(eyre::eyre!(\n                \"unknown field(s) {:?} in task file header: {}\",\n                unparsed,\n                display_path(path)\n            ));\n        }\n\n        #[cfg(test)]\n        {\n            let fields: Vec<String> = p.parsed_keys().map(|s| s.to_string()).collect();\n            tests::capture_parsed_fields(fields);\n        }\n        task.render(config, config_root).await?;\n        Ok(task)\n    }\n\n    /// Add env vars that were inherited from parent tasks (e.g., via `run = [{ task = \"...\" }]`)\n    /// These do NOT affect task identity/deduplication\n    pub fn derive_env(&self, env_directives: &[EnvDirective]) -> Self {\n        let mut new_task = self.clone();\n        new_task.inherited_env.0.extend_from_slice(env_directives);\n        new_task\n    }\n\n    /// Add env vars specified in dependency declarations (e.g., `depends = [\"FOO=bar task\"]`)\n    /// These DO affect task identity/deduplication\n    pub fn with_dependency_env(&self, env_directives: &[EnvDirective]) -> Self {\n        let mut new_task = self.clone();\n        new_task.env.0.extend_from_slice(env_directives);\n        new_task\n    }\n\n    /// prints the task name without an extension\n    pub fn display_name(&self, all_tasks: &BTreeMap<String, Task>) -> String {\n        // For task names, only strip extensions after the last colon (:)\n        // This handles monorepo task names like \"//projects/my.app:build.sh\"\n        // where we want to strip \".sh\" but keep \"my.app\" intact\n        let display_name = if let Some((prefix, task_part)) = self.name.rsplit_once(':') {\n            // Has a colon separator (e.g., \"//projects/my.app:build.sh\")\n            // Strip extension from the task part only\n            let task_without_ext = task_part.rsplitn(2, '.').last().unwrap_or_default();\n            format!(\"{}:{}\", prefix, task_without_ext)\n        } else {\n            // No colon separator (e.g., \"build.sh\")\n            // Strip extension from the whole name\n            self.name\n                .rsplitn(2, '.')\n                .last()\n                .unwrap_or_default()\n                .to_string()\n        };\n\n        if all_tasks.contains_key(&display_name) {\n            // this means another task has the name without an extension so use the full name\n            self.name.clone()\n        } else {\n            display_name\n        }\n    }\n\n    pub fn is_match(&self, pat: &str) -> bool {\n        if self.name == pat || self.aliases.contains(&pat.to_string()) {\n            return true;\n        }\n\n        // For pattern matching, we need to handle several cases:\n        // 1. Simple pattern (e.g., \"build\") should match monorepo tasks (e.g., \"//projects/my.app:build\")\n        // 2. Full pattern (e.g., \"//projects/my.app:build\") should only match exact path\n        // 3. Extensions should be stripped for comparison\n\n        let matches = if let Some((prefix, task_part)) = self.name.rsplit_once(':') {\n            // Task name has a colon (e.g., \"//projects/my.app:build.sh\")\n            let task_stripped = task_part.rsplitn(2, '.').last().unwrap_or_default();\n\n            if let Some((pat_prefix, pat_task)) = pat.rsplit_once(':') {\n                // Pattern also has a colon - compare full paths\n                let pat_task_stripped = pat_task.rsplitn(2, '.').last().unwrap_or_default();\n                prefix == pat_prefix && task_stripped == pat_task_stripped\n            } else {\n                // Pattern is simple (no colon) - just compare task names\n                let pat_stripped = pat.rsplitn(2, '.').last().unwrap_or_default();\n                task_stripped == pat_stripped\n            }\n        } else {\n            // Simple task name without colon (e.g., \"build.sh\")\n            let name_stripped = self.name.rsplitn(2, '.').last().unwrap_or_default();\n            let pat_stripped = pat.rsplitn(2, '.').last().unwrap_or_default();\n            name_stripped == pat_stripped\n        };\n\n        matches || self.aliases.contains(&pat.to_string())\n    }\n\n    pub async fn task_dir() -> PathBuf {\n        let config = Config::get().await.unwrap();\n        let cwd = dirs::CWD.clone().unwrap_or_default();\n        let project_root = config.project_root.clone().unwrap_or(cwd);\n        for dir in config::task_includes_for_dir(&project_root, &config.config_files) {\n            if dir.is_dir() && project_root.join(&dir).exists() {\n                return project_root.join(dir);\n            }\n        }\n        project_root.join(\"mise-tasks\")\n    }\n\n    pub fn with_args(mut self, args: Vec<String>) -> Self {\n        self.args = args;\n        self\n    }\n\n    pub fn prefix(&self) -> String {\n        let max_width = 40;\n        let inner = if self.show_args_in_prefix && !self.args.is_empty() {\n            let s = format!(\"{} {}\", self.display_name, self.args.join(\" \"));\n            s.trim().to_string()\n        } else {\n            self.display_name.clone()\n        };\n        format!(\"[{}]\", console::truncate_str(&inner, max_width, \"…\"))\n    }\n\n    pub fn run(&self) -> &Vec<RunEntry> {\n        if cfg!(windows) && !self.run_windows.is_empty() {\n            &self.run_windows\n        } else {\n            &self.run\n        }\n    }\n\n    /// Returns only the script strings from the run entries (without rendering)\n    pub fn run_script_strings(&self) -> Vec<String> {\n        self.run()\n            .iter()\n            .filter_map(|e| match e {\n                RunEntry::Script(s) => Some(s.clone()),\n                _ => None,\n            })\n            .collect()\n    }\n\n    pub fn all_depends(&self, tasks: &BTreeMap<String, Task>) -> Result<Vec<Task>> {\n        let tasks_ref = build_task_ref_map(tasks.iter());\n        let mut path = vec![self.name.clone()];\n        self.all_depends_recursive(&tasks_ref, &mut path)\n    }\n\n    fn all_depends_recursive(\n        &self,\n        tasks: &BTreeMap<String, &Task>,\n        path: &mut Vec<String>,\n    ) -> Result<Vec<Task>> {\n        let mut depends: Vec<Task> = self\n            .depends\n            .iter()\n            .chain(self.depends_post.iter())\n            .map(|td| match_tasks_with_context(tasks, td, Some(self)))\n            .flatten_ok()\n            .filter_ok(|t| t.name != self.name)\n            .collect::<Result<Vec<_>>>()?;\n\n        // Collect transitive dependencies with cycle detection\n        for dep in depends.clone() {\n            if path.contains(&dep.name) {\n                // Circular dependency detected - build path string for error message\n                let cycle_path = path\n                    .iter()\n                    .skip_while(|&name| name != &dep.name)\n                    .chain(std::iter::once(&dep.name))\n                    .join(\" -> \");\n                return Err(eyre!(\"circular dependency detected: {}\", cycle_path));\n            }\n            path.push(dep.name.clone());\n            let mut extra = dep.all_depends_recursive(tasks, path)?;\n            path.pop(); // Remove from path after processing this branch\n            extra.retain(|t| t.name != self.name); // prevent depending on ourself\n            depends.extend(extra);\n        }\n        let depends = depends.into_iter().unique().collect();\n        Ok(depends)\n    }\n\n    pub async fn resolve_depends(\n        &self,\n        config: &Arc<Config>,\n        tasks_to_run: &[Task],\n    ) -> Result<(Vec<Task>, Vec<Task>)> {\n        use crate::task::TaskLoadContext;\n\n        let tasks_to_run: HashSet<&Task> = tasks_to_run.iter().collect();\n\n        // Build context with path hints from self, tasks_to_run, and dependency patterns\n        // Resolve patterns before extracting paths to handle local deps (e.g., \":A\")\n        let path_hints: Vec<String> = once(&self.name)\n            .chain(tasks_to_run.iter().map(|t| &t.name))\n            .filter_map(|name| extract_monorepo_path(name))\n            .chain(\n                self.depends\n                    .iter()\n                    .chain(self.wait_for.iter())\n                    .chain(self.depends_post.iter())\n                    .map(|td| resolve_task_pattern(&td.task, Some(self)))\n                    .filter_map(|resolved| extract_monorepo_path(&resolved)),\n            )\n            .unique()\n            .collect();\n\n        let ctx = if !path_hints.is_empty() {\n            Some(TaskLoadContext {\n                path_hints,\n                load_all: false,\n            })\n        } else {\n            None\n        };\n\n        let all_tasks = config.tasks_with_context(ctx.as_ref()).await?;\n        let tasks = build_task_ref_map(all_tasks.iter());\n        let depends = self\n            .depends\n            .iter()\n            .map(|td| match_tasks_with_context(&tasks, td, Some(self)))\n            .flatten_ok()\n            .collect_vec();\n        let wait_for = self\n            .wait_for\n            .iter()\n            .map(|td| {\n                match_tasks_with_context(&tasks, td, Some(self))\n                    .map(|tasks| tasks.into_iter().map(|t| (t, td)).collect_vec())\n            })\n            .flatten_ok()\n            .filter_map_ok(|(t, td)| {\n                if td.env.is_empty() && td.args.is_empty() {\n                    // Name-based matching: wait for any running instance of this task\n                    // regardless of env/args variant (e.g., \"VERBOSE=1 setup\" matches \"setup\").\n                    // Return the actual task from tasks_to_run so the dependency graph\n                    // gets the correct env/args-variant node.\n                    tasks_to_run\n                        .iter()\n                        .find(|tr| tr.name == t.name)\n                        .map(|tr| (*tr).clone())\n                } else {\n                    // Full identity matching: user explicitly wants a specific env/args variant\n                    tasks_to_run.contains(&t).then_some(t)\n                }\n            })\n            .collect_vec();\n        let depends_post = self\n            .depends_post\n            .iter()\n            .map(|td| match_tasks_with_context(&tasks, td, Some(self)))\n            .flatten_ok()\n            .filter_ok(|t| t.name != self.name)\n            .collect::<Result<Vec<_>>>()?;\n        let depends = depends\n            .into_iter()\n            .chain(wait_for)\n            .filter_ok(|t| t.name != self.name)\n            .collect::<Result<_>>()?;\n        Ok((depends, depends_post))\n    }\n\n    fn populate_spec_metadata(&self, spec: &mut usage::Spec) {\n        spec.name = self.display_name.clone();\n        spec.bin = self.display_name.clone();\n        if spec.cmd.help.is_none() {\n            spec.cmd.help = Some(self.description.clone());\n        }\n        spec.cmd.name = self.display_name.clone();\n        spec.cmd.aliases = self.aliases.clone();\n        if spec.cmd.before_help.is_none()\n            && spec.cmd.before_help_long.is_none()\n            && !self.depends.is_empty()\n        {\n            spec.cmd.before_help_long =\n                Some(format!(\"- Depends: {}\", self.depends.iter().join(\", \")));\n        }\n        spec.cmd.usage = spec.cmd.usage();\n    }\n    pub async fn parse_usage_spec_with_vars(\n        &self,\n        config: &Arc<Config>,\n        cwd: Option<PathBuf>,\n        env: &EnvMap,\n        extra_vars: Option<IndexMap<String, String>>,\n    ) -> Result<(usage::Spec, Vec<String>)> {\n        let (mut spec, scripts) = if let Some(file) = self.file_path(config).await? {\n            let spec = usage::Spec::parse_script(&file)\n                .inspect_err(|e| {\n                    warn!(\n                        \"failed to parse task file {} with usage: {e:?}\",\n                        file::display_path(&file)\n                    )\n                })\n                .unwrap_or_default();\n            (spec, vec![])\n        } else {\n            let scripts_only = self.run_script_strings();\n            let (scripts, spec) = Self::make_script_parser(cwd, extra_vars)\n                .parse_run_scripts(config, self, &scripts_only, env)\n                .await?;\n            (spec, scripts)\n        };\n        self.populate_spec_metadata(&mut spec);\n        Ok((spec, scripts))\n    }\n\n    fn make_script_parser(\n        cwd: Option<PathBuf>,\n        extra_vars: Option<IndexMap<String, String>>,\n    ) -> TaskScriptParser {\n        let parser = TaskScriptParser::new(cwd);\n        match extra_vars {\n            Some(vars) => parser.with_extra_vars(vars),\n            None => parser,\n        }\n    }\n\n    /// Parse usage spec for display purposes without expensive environment rendering\n    pub async fn parse_usage_spec_for_display(&self, config: &Arc<Config>) -> Result<usage::Spec> {\n        let dir = self.dir(config).await?;\n        let mut spec = if let Some(file) = self.file_path(config).await? {\n            usage::Spec::parse_script(&file)\n                .inspect_err(|e| {\n                    warn!(\n                        \"failed to parse task file {} with usage: {e:?}\",\n                        file::display_path(&file)\n                    )\n                })\n                .unwrap_or_default()\n        } else {\n            let scripts_only = self.run_script_strings();\n            TaskScriptParser::new(dir)\n                .parse_run_scripts_for_spec_only(config, self, &scripts_only)\n                .await?\n        };\n        self.populate_spec_metadata(&mut spec);\n        Ok(spec)\n    }\n\n    pub async fn render_run_scripts_with_args(\n        &self,\n        config: &Arc<Config>,\n        cwd: Option<PathBuf>,\n        args: &[String],\n        env: &EnvMap,\n        extra_vars: Option<IndexMap<String, String>>,\n    ) -> Result<Vec<(String, Vec<String>)>> {\n        let (spec, scripts) = self\n            .parse_usage_spec_with_vars(config, cwd.clone(), env, extra_vars.clone())\n            .await?;\n        if has_any_args_defined(&spec) {\n            let scripts_only = self.run_script_strings();\n            let scripts = Self::make_script_parser(cwd, extra_vars)\n                .parse_run_scripts_with_args(config, self, &scripts_only, env, args, &spec)\n                .await?;\n            Ok(scripts.into_iter().map(|s| (s, vec![])).collect())\n        } else {\n            Ok(scripts\n                .iter()\n                .enumerate()\n                .map(|(i, script)| {\n                    // only pass args to the last script if no formal args are defined\n                    match i == self.run_script_strings().len() - 1 {\n                        true => (script.clone(), args.iter().cloned().collect_vec()),\n                        false => (script.clone(), vec![]),\n                    }\n                })\n                .collect())\n        }\n    }\n\n    pub async fn render_markdown(&self, config: &Arc<Config>) -> Result<String> {\n        let spec = self.parse_usage_spec_for_display(config).await?;\n        let ctx = usage::docs::markdown::MarkdownRenderer::new(spec)\n            .with_replace_pre_with_code_fences(true)\n            .with_header_level(2);\n        Ok(ctx.render_spec()?)\n    }\n\n    pub fn estyled_prefix(&self) -> String {\n        static COLORS: Lazy<Vec<Color>> = Lazy::new(|| {\n            vec![\n                Color::Blue,\n                Color::Magenta,\n                Color::Cyan,\n                Color::Green,\n                Color::Yellow,\n                Color::Red,\n            ]\n        });\n        let idx = self.display_name.chars().map(|c| c as usize).sum::<usize>() % COLORS.len();\n\n        style::ereset() + &style::estyle(self.prefix()).fg(COLORS[idx]).to_string()\n    }\n\n    pub async fn dir(&self, config: &Arc<Config>) -> Result<Option<PathBuf>> {\n        if let Some(dir) = self.dir.clone().or_else(|| {\n            self.cf(config)\n                .as_ref()\n                .and_then(|cf| cf.task_config().dir.clone())\n        }) {\n            let config_root = self.config_root.clone().unwrap_or_default();\n            let mut tera = get_tera(Some(&config_root));\n            let tera_ctx = self.tera_ctx(config).await?;\n            let dir = tera.render_str(&dir, &tera_ctx)?;\n            let dir = file::replace_path(&dir);\n            if dir.is_absolute() {\n                Ok(Some(dir.to_path_buf()))\n            } else if let Some(root) = &self.config_root {\n                Ok(Some(root.join(dir)))\n            } else {\n                Ok(Some(dir.clone()))\n            }\n        } else {\n            Ok(self.config_root.clone())\n        }\n    }\n\n    pub async fn file_path(&self, config: &Arc<Config>) -> Result<Option<PathBuf>> {\n        if let Some(file) = &self.file {\n            let file_str = file.to_string_lossy().to_string();\n            let config_root = self.config_root.clone().unwrap_or_default();\n            let mut tera = get_tera(Some(&config_root));\n            let tera_ctx = self.tera_ctx(config).await?;\n            let rendered = tera.render_str(&file_str, &tera_ctx)?;\n            let rendered_path = file::replace_path(&rendered);\n            if rendered_path.is_absolute() {\n                Ok(Some(rendered_path))\n            } else if let Some(root) = &self.config_root {\n                Ok(Some(root.join(rendered_path)))\n            } else {\n                Ok(Some(rendered_path))\n            }\n        } else {\n            Ok(None)\n        }\n    }\n\n    /// Get file path without templating (for display purposes)\n    /// This is a non-async version used when we just need the path for display\n    fn file_path_raw(&self) -> Option<PathBuf> {\n        self.file.as_ref().map(|file| {\n            if file.is_absolute() {\n                file.clone()\n            } else if let Some(root) = &self.config_root {\n                root.join(file)\n            } else {\n                file.clone()\n            }\n        })\n    }\n\n    pub async fn tera_ctx(&self, config: &Arc<Config>) -> Result<tera::Context> {\n        let ts = config.get_toolset().await?;\n        let mut tera_ctx = ts.tera_ctx(config).await?.clone();\n        let mut vars = self.resolve_base_vars(config).await?;\n        // Insert base vars first so that task-level var templates can reference them\n        // (e.g. a task var `foo = \"{{vars.bar}}\"` can read a config-level `bar`).\n        tera_ctx.insert(\"vars\", &vars);\n        vars.extend(self.resolve_task_vars(config, ts, &tera_ctx).await?);\n        // Re-insert with task-level vars merged in so callers see the final combined map,\n        // with task-level values taking precedence over config-level ones.\n        tera_ctx.insert(\"vars\", &vars);\n        tera_ctx.insert(\"config_root\", &self.config_root);\n        Ok(tera_ctx)\n    }\n\n    async fn resolve_base_vars(&self, config: &Arc<Config>) -> Result<IndexMap<String, String>> {\n        let Some(task_cf) = self.cf(config) else {\n            return Ok(config.vars.clone());\n        };\n\n        if task_cf.project_root() == config.project_root {\n            return Ok(config.vars.clone());\n        }\n\n        let config_path = task_cf.get_path().to_path_buf();\n        if let Some(vars) = TASK_VARS_CACHE.lock().unwrap().get(&config_path) {\n            return Ok(vars.clone());\n        }\n\n        let task_dir = task_cf.get_path().parent().unwrap_or(task_cf.get_path());\n        let config_paths = crate::config::load_config_hierarchy_from_dir(task_dir)?;\n        let task_config_files = crate::config::load_config_files_from_paths(&config_paths).await?;\n        let vars_results =\n            crate::config::resolve_vars_from_config_files(config, &task_config_files).await?;\n        let vars: IndexMap<String, String> = vars_results\n            .vars\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect();\n        TASK_VARS_CACHE\n            .lock()\n            .unwrap()\n            .insert(config_path, vars.clone());\n        Ok(vars)\n    }\n\n    async fn resolve_task_vars(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n        tera_ctx: &tera::Context,\n    ) -> Result<IndexMap<String, String>> {\n        if self.vars.0.is_empty() {\n            return Ok(IndexMap::new());\n        }\n\n        let env_map = ts.full_env(config).await?;\n        let results = EnvResults::resolve(\n            config,\n            tera_ctx.clone(),\n            &env_map,\n            self.vars\n                .0\n                .iter()\n                .cloned()\n                .map(|directive| (directive, self.config_source.clone()))\n                .collect(),\n            EnvResolveOptions {\n                vars: true,\n                tools: ToolsFilter::NonToolsOnly,\n                warn_on_missing_required: false,\n            },\n        )\n        .await?;\n\n        Ok(results\n            .vars\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect())\n    }\n\n    pub fn cf<'a>(&'a self, config: &'a Config) -> Option<&'a Arc<dyn ConfigFile>> {\n        // For monorepo tasks, use the stored config file reference\n        if let Some(ref cf) = self.cf {\n            return Some(cf);\n        }\n        // Fallback to looking up in config.config_files\n        config.config_files.get(&self.config_source)\n    }\n\n    /// Check if this task is a remote task (loaded from git:// or http:// URL)\n    /// Remote tasks should not use monorepo config file context because they need\n    /// access to tools from the full config hierarchy, not just the local config file\n    pub fn is_remote(&self) -> bool {\n        // Check the stored remote file source (set before file is replaced with local path)\n        if let Some(source) = &self.remote_file_source {\n            return source.starts_with(\"git::\")\n                || source.starts_with(\"http://\")\n                || source.starts_with(\"https://\");\n        }\n        false\n    }\n\n    pub fn shell(&self) -> Option<Vec<String>> {\n        self.shell.as_ref().and_then(|shell| {\n            let shell_cmd = shell\n                .split_whitespace()\n                .map(|s| s.to_string())\n                .collect::<Vec<_>>();\n            if shell_cmd.is_empty() || shell_cmd[0].trim().is_empty() {\n                warn!(\"invalid shell '{shell}', expected '<program> <argument>' (e.g. sh -c)\");\n                None\n            } else {\n                Some(shell_cmd)\n            }\n        })\n    }\n\n    pub async fn render(&mut self, config: &Arc<Config>, config_root: &Path) -> Result<()> {\n        let mut tera = get_tera(Some(config_root));\n        let tera_ctx = self.tera_ctx(config).await?;\n        for a in &mut self.aliases {\n            *a = tera.render_str(a, &tera_ctx)?;\n        }\n\n        self.description = tera.render_str(&self.description, &tera_ctx)?;\n        for s in &mut self.sources {\n            *s = tera.render_str(s, &tera_ctx)?;\n        }\n        if !self.sources.is_empty() && self.outputs.is_empty() {\n            self.outputs = TaskOutputs::Auto;\n        }\n        self.raw_outputs = self.outputs.render(&mut tera, &tera_ctx)?;\n        for d in &mut self.depends {\n            d.render(&mut tera, &tera_ctx)?;\n        }\n        for d in &mut self.depends_post {\n            d.render(&mut tera, &tera_ctx)?;\n        }\n        for d in &mut self.wait_for {\n            d.render(&mut tera, &tera_ctx)?;\n        }\n        if let Some(dir) = &mut self.dir {\n            *dir = tera.render_str(dir, &tera_ctx)?;\n        }\n        if let Some(shell) = &mut self.shell {\n            *shell = tera.render_str(shell, &tera_ctx)?;\n        }\n        for (_, v) in &mut self.tools {\n            *v = tera.render_str(v, &tera_ctx)?;\n        }\n        Ok(())\n    }\n\n    pub fn name_to_path(&self) -> PathBuf {\n        self.name.replace(':', path::MAIN_SEPARATOR_STR).into()\n    }\n\n    pub async fn render_env(\n        &self,\n        config: &Arc<Config>,\n        ts: &Toolset,\n    ) -> Result<(EnvMap, Vec<(String, String)>)> {\n        let mut tera_ctx = ts.tera_ctx(config).await?.clone();\n        let mut env = ts.full_env(config).await?;\n        if let Some(root) = &config.project_root {\n            tera_ctx.insert(\"config_root\", &root);\n        }\n\n        // Convert task env directives to (EnvDirective, PathBuf) pairs\n        // Use the config file path as source for proper path resolution\n        // Include inherited_env first (so task's own env can override it)\n        let env_directives: Vec<_> = self\n            .inherited_env\n            .0\n            .iter()\n            .chain(self.env.0.iter())\n            .map(|directive| (directive.clone(), self.config_source.clone()))\n            .collect();\n\n        // Resolve environment directives using the same system as global env\n        let env_results = EnvResults::resolve(\n            config,\n            tera_ctx.clone(),\n            &env,\n            env_directives,\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::Both,\n                warn_on_missing_required: false,\n            },\n        )\n        .await?;\n        // Register task-specific redactions with the global redactor\n        // Include config-level redaction patterns so they also cover task-specific env vars\n        let redact_keys = config\n            .redaction_keys()\n            .into_iter()\n            .chain(env_results.redactions.iter().cloned());\n        let task_env_map: EnvMap = env_results\n            .env\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect();\n        config.add_redactions(redact_keys, &task_env_map);\n\n        let task_env = env_results.env.into_iter().map(|(k, (v, _))| (k, v));\n        // Apply the resolved environment variables\n        env.extend(task_env.clone());\n\n        // Remove environment variables that were explicitly unset\n        for key in &env_results.env_remove {\n            env.remove(key);\n        }\n\n        // Apply path additions from _.path directives\n        if !env_results.env_paths.is_empty() {\n            let mut path_env = PathEnv::from_iter(env::split_paths(\n                &env.get(&*env::PATH_KEY).cloned().unwrap_or_default(),\n            ));\n            for path in env_results.env_paths {\n                path_env.add(path);\n            }\n            env.insert(env::PATH_KEY.to_string(), path_env.to_string());\n        }\n\n        Ok((env, task_env.collect()))\n    }\n}\n\nfn name_from_path(prefix: impl AsRef<Path>, path: impl AsRef<Path>) -> Result<String> {\n    let name = path\n        .as_ref()\n        .strip_prefix(prefix)\n        .map(|p| match p {\n            p if p.starts_with(\"mise-tasks\") => p.strip_prefix(\"mise-tasks\"),\n            p if p.starts_with(\".mise-tasks\") => p.strip_prefix(\".mise-tasks\"),\n            p if p.starts_with(\".mise/tasks\") => p.strip_prefix(\".mise/tasks\"),\n            p if p.starts_with(\"mise/tasks\") => p.strip_prefix(\"mise/tasks\"),\n            p if p.starts_with(\".config/mise/tasks\") => p.strip_prefix(\".config/mise/tasks\"),\n            _ => Ok(p),\n        })??\n        .components()\n        .map(path::Component::as_os_str)\n        .map(ffi::OsStr::to_string_lossy)\n        .map(|s| s.replace(':', \"_\"))\n        .join(\":\");\n    if let Some((parent, last)) = name.rsplit_once(':')\n        && strip_extension(last) == \"_default\"\n    {\n        return Ok(parent.to_string());\n    }\n    Ok(name)\n}\n\n/// Extract monorepo path from a task name\n/// e.g., \"//projects/frontend:test\" -> Some(\"projects/frontend\")\n/// e.g., \"//projects/frontend:test:nested\" -> Some(\"projects/frontend\")\n/// Returns None if the task name doesn't have monorepo syntax\npub(crate) fn extract_monorepo_path(name: &str) -> Option<String> {\n    name.strip_prefix(\"//\").and_then(|stripped| {\n        // Find the FIRST colon after \"//\" prefix to handle task names with colons like \"do:item-1\"\n        stripped.find(':').map(|idx| stripped[..idx].to_string())\n    })\n}\n\n/// Build a map of task names and aliases to task references\n/// For monorepo tasks, creates entries for both prefixed and unprefixed aliases\n/// e.g., task \"//:format\" with alias \"fmt\" creates both \"//:fmt\" and \"fmt\"\npub(crate) fn build_task_ref_map<'a, I>(tasks: I) -> BTreeMap<String, &'a Task>\nwhere\n    I: Iterator<Item = (&'a String, &'a Task)> + 'a,\n{\n    tasks\n        .flat_map(|(_, t)| {\n            t.aliases\n                .iter()\n                .flat_map(|a| {\n                    // For monorepo tasks, create entries for both prefixed and unprefixed aliases\n                    // This allows references like \"fmt\" to resolve to \"//:format\"\n                    if let Some(path) = extract_monorepo_path(&t.name) {\n                        vec![(format!(\"//{}:{}\", path, a), t), (a.to_string(), t)]\n                    } else {\n                        // Non-monorepo task, use alias as-is\n                        vec![(a.to_string(), t)]\n                    }\n                })\n                .chain(once((t.name.clone(), t)))\n                .collect::<Vec<_>>()\n        })\n        .collect()\n}\n\n/// Resolve a task dependency pattern, optionally relative to a parent task\n/// If pattern starts with \":\" and parent_task is provided, resolve relative to parent's path\n/// For example: parent \"//projects/frontend:test\" with pattern \":build\" -> \"//projects/frontend:build\"\npub(crate) fn resolve_task_pattern(pattern: &str, parent_task: Option<&Task>) -> String {\n    // Check if this is a bare task name that should be treated as relative\n    let is_bare_name =\n        !pattern.starts_with(\"//\") && !pattern.starts_with(\"::\") && !pattern.starts_with(':');\n\n    // If pattern starts with \":\" or is a bare name in monorepo context, resolve relatively\n    let should_resolve_relatively = pattern.starts_with(':') && !pattern.starts_with(\"::\")\n        || (is_bare_name && parent_task.is_some_and(|p| p.name.starts_with(\"//\")));\n\n    if should_resolve_relatively && let Some(parent) = parent_task {\n        // Extract the path portion from the parent task name\n        // For monorepo tasks like \"//projects/frontend:test:nested\", we need to extract \"//projects/frontend\"\n        // by finding the FIRST colon after the \"//\" prefix, not the last one\n        if let Some(stripped) = parent.name.strip_prefix(\"//\") {\n            // Find the first colon after \"//\" prefix\n            if let Some(colon_idx) = stripped.find(':') {\n                let path = format!(\"//{}\", &stripped[..colon_idx]);\n                // If pattern is a bare name, add the colon prefix\n                return if is_bare_name {\n                    format!(\"{}:{}\", path, pattern)\n                } else {\n                    format!(\"{}{}\", path, pattern)\n                };\n            }\n        } else if let Some((path, _)) = parent.name.rsplit_once(':') {\n            // For non-monorepo tasks, use the old logic\n            return format!(\"{}{}\", path, pattern);\n        }\n    }\n    pattern.to_string()\n}\n\nfn match_tasks_with_context(\n    tasks: &BTreeMap<String, &Task>,\n    td: &TaskDep,\n    parent_task: Option<&Task>,\n) -> Result<Vec<Task>> {\n    let resolved_pattern = resolve_task_pattern(&td.task, parent_task);\n    let matches = tasks\n        .get_matching(&resolved_pattern)?\n        .into_iter()\n        .map(|t| {\n            let mut t = (*t).clone();\n            t.args = td.args.clone();\n            // Apply env vars from dependency - these affect task identity/deduplication\n            if !td.env.is_empty() {\n                let env_directives: Vec<EnvDirective> = td\n                    .env\n                    .iter()\n                    .map(|(k, v)| EnvDirective::Val(k.clone(), v.clone(), Default::default()))\n                    .collect();\n                t = t.with_dependency_env(&env_directives);\n                if let Some(config_root) = &t.config_root {\n                    let config_root = config_root.clone();\n                    t.outputs\n                        .re_render_with_env(&t.raw_outputs.clone(), &td.env, &config_root)?;\n                }\n            }\n            Ok(t)\n        })\n        .collect::<Result<Vec<_>>>()?;\n    if matches.is_empty() {\n        let mut err_msg = format!(\"task not found: {}\", td.task);\n\n        // In monorepo mode, suggest similar tasks using fuzzy matching\n        if resolved_pattern.starts_with(\"//\") {\n            let similar: Vec<String> = tasks\n                .keys()\n                .filter(|k| k.starts_with(\"//\"))\n                .filter_map(|k| {\n                    FUZZY_MATCHER\n                        .fuzzy_match(&k.to_lowercase(), &resolved_pattern.to_lowercase())\n                        .map(|score| (score, k.clone()))\n                })\n                .sorted_by_key(|(score, _)| -1 * *score)\n                .take(5)\n                .map(|(_, k)| k)\n                .collect();\n\n            if !similar.is_empty() {\n                err_msg.push_str(\"\\n\\nDid you mean one of these?\");\n                for task_name in similar {\n                    err_msg.push_str(&format!(\"\\n  - {}\", task_name));\n                }\n            }\n        }\n\n        return Err(eyre!(err_msg));\n    };\n\n    Ok(matches)\n}\n\nimpl Default for Task {\n    fn default() -> Self {\n        Task {\n            name: \"\".to_string(),\n            display_name: \"\".to_string(),\n            description: \"\".to_string(),\n            aliases: vec![],\n            config_source: PathBuf::new(),\n            cf: None,\n            config_root: None,\n            confirm: None,\n            depends: vec![],\n            depends_post: vec![],\n            wait_for: vec![],\n            env: Default::default(),\n            vars: Default::default(),\n            inherited_env: Default::default(),\n            dir: None,\n            hide: false,\n            global: false,\n            raw: false,\n            interactive: false,\n            sources: vec![],\n            outputs: Default::default(),\n            raw_outputs: Default::default(),\n            shell: None,\n            silent: Silent::Off,\n            run: vec![],\n            run_windows: vec![],\n            args: vec![],\n            file: None,\n            quiet: false,\n            tools: Default::default(),\n            usage: \"\".to_string(),\n            timeout: None,\n            remote_file_source: None,\n            extends: None,\n            show_args_in_prefix: false,\n        }\n    }\n}\n\nimpl Display for Task {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        let cmd = self\n            .run()\n            .iter()\n            .map(|e| e.to_string())\n            .next()\n            .or_else(|| self.file_path_raw().as_ref().map(display_path));\n\n        if let Some(cmd) = cmd {\n            let cmd = cmd.lines().next().unwrap_or_default();\n            let prefix = self.prefix();\n            let prefix_len = measure_text_width(&prefix);\n            // Ensure we have at least 20 characters for the command, even with very long prefixes\n            let available_width = (*env::TERM_WIDTH).saturating_sub(prefix_len + 4); // 4 chars buffer for spacing and ellipsis\n            let max_width = available_width.max(20); // Always show at least 20 chars of command\n            let truncated_cmd = truncate_str(cmd, max_width, \"…\");\n            write!(f, \"{} {}\", prefix, truncated_cmd)\n        } else {\n            write!(f, \"{}\", self.prefix())\n        }\n    }\n}\n\nimpl PartialOrd for Task {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\n/// Extract sorted env key-value pairs from task's own env (not inherited_env)\n/// Used for consistent comparison/hashing of task identity\nfn env_key(task: &Task) -> Vec<(&String, &String)> {\n    task.env\n        .0\n        .iter()\n        .filter_map(|d| match d {\n            EnvDirective::Val(k, v, _) => Some((k, v)),\n            _ => None,\n        })\n        .sorted()\n        .collect()\n}\n\nimpl Ord for Task {\n    fn cmp(&self, other: &Self) -> Ordering {\n        match self.name.cmp(&other.name) {\n            Ordering::Equal => match self.args.cmp(&other.args) {\n                Ordering::Equal => env_key(self).cmp(&env_key(other)),\n                o => o,\n            },\n            o => o,\n        }\n    }\n}\n\nimpl Hash for Task {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.name.hash(state);\n        self.args.iter().for_each(|arg| arg.hash(state));\n        // Include task's own env (not inherited_env) for deduplication\n        for (k, v) in env_key(self) {\n            k.hash(state);\n            v.hash(state);\n        }\n    }\n}\n\nimpl Eq for Task {}\nimpl PartialEq for Task {\n    fn eq(&self, other: &Self) -> bool {\n        self.name == other.name && self.args == other.args && env_key(self) == env_key(other)\n    }\n}\n\nimpl TreeItem for (&Graph<Task, ()>, NodeIndex) {\n    type Child = Self;\n\n    fn write_self(&self) -> std::io::Result<()> {\n        if let Some(w) = self.0.node_weight(self.1) {\n            miseprint!(\"{}\", w.display_name)?;\n        }\n        Ok(())\n    }\n\n    fn children(&self) -> Cow<'_, [Self::Child]> {\n        let v: Vec<_> = self.0.neighbors(self.1).map(|i| (self.0, i)).collect();\n        Cow::from(v)\n    }\n}\n\npub trait GetMatchingExt<T> {\n    fn get_matching(&self, pat: &str) -> Result<Vec<&T>>;\n}\n\n/// Helper function to strip file extension from a task name\n/// e.g., \"test.js\" -> \"test\", \"build\" -> \"build\"\n/// Special case: hidden files like \".hidden\" are preserved to avoid empty strings\nfn strip_extension(name: &str) -> &str {\n    let result = name.rsplitn(2, '.').last().unwrap_or(name);\n    // Don't strip extension if it would result in empty string (hidden files)\n    if result.is_empty() { name } else { result }\n}\n\nimpl<T> GetMatchingExt<T> for BTreeMap<String, T>\nwhere\n    T: Eq + Hash,\n{\n    fn get_matching(&self, pat: &str) -> Result<Vec<&T>> {\n        // === Monorepo pattern matching ===\n        // Only patterns starting with '//' or ':' are monorepo patterns\n        // Reject patterns that look like monorepo paths but use wrong syntax (have / and : but don't start with // or :)\n        if !pat.starts_with(\"//\") && !pat.starts_with(':') {\n            // Check if this looks like an attempt at a monorepo path with wrong syntax\n            if pat.contains('/') && pat.contains(':') {\n                bail!(\n                    \"relative path syntax '{}' is not supported, use '//{}'  or ':task' for current directory\",\n                    pat,\n                    pat\n                )\n            }\n            // If it doesn't contain wildcards or ':', it's a simple task name\n            if !pat.contains('*') && !pat.contains(\"...\") && !pat.contains(':') {\n                return Ok(self\n                    .iter()\n                    .filter(|(k, _)| {\n                        // Check if task name exactly matches, or matches without extension\n                        k.as_str() == pat || strip_extension(k) == pat\n                    })\n                    .map(|(_, v)| v)\n                    .collect());\n            }\n            // Has wildcards or colon but no /, so it's a regular task pattern like \"render:*\" or \"build:linux\"\n            // Process with glob matching below\n        }\n\n        // === Parse monorepo pattern ===\n        let normalized_pat = if pat.starts_with(\"//\") {\n            pat.to_string()\n        } else if pat.starts_with(':') {\n            // Special case: :task should have been expanded before calling get_matching\n            // If we reach here, it means the expansion didn't happen properly\n            bail!(\"':task' pattern should be expanded before matching\")\n        } else {\n            pat.to_string()\n        };\n\n        // Split pattern into path and task parts\n        // Pattern format: //path/...:task* or //path:task*\n        let parts: Vec<&str> = normalized_pat.splitn(2, ':').collect();\n        let has_explicit_task_glob = parts.len() > 1;\n        let (path_pattern, task_pattern) = match parts.as_slice() {\n            [path, task] => (*path, *task),\n            [path] => (*path, \"*\"),\n            _ => (normalized_pat.as_str(), \"*\"),\n        };\n\n        // === Convert ellipsis to glob syntax ===\n        // Convert ellipsis (...) to glob pattern (**)\n        // //... matches everything, //foo/... matches foo and all subdirs\n        let path_glob = path_pattern.replace(\"...\", \"**\");\n\n        // For task patterns, * only matches within the task name portion (after final :)\n        // e.g., test:* matches test:unit, test:integration, etc.\n        let task_glob = task_pattern;\n\n        // === Build glob matchers once (performance optimization) ===\n        // Build path matcher for absolute patterns\n        let path_matcher = GlobBuilder::new(&path_glob)\n            .literal_separator(true)\n            .build()\n            .ok()\n            .map(|b| b.compile_matcher());\n\n        // Build task matcher if not wildcard\n        let task_matcher = if task_glob != \"*\" {\n            GlobBuilder::new(task_glob)\n                .literal_separator(false) // Allow * to match : in task names\n                .build()\n                .ok()\n                .map(|b| b.compile_matcher())\n        } else {\n            None\n        };\n\n        // Build relative pattern matchers if needed\n        let (rel_path_matcher, rel_task_matcher) = if !pat.starts_with(\"//\") {\n            let rel_path_pattern = path_pattern.strip_prefix(\"//\").unwrap_or(path_pattern);\n            let rel_path_glob = rel_path_pattern.replace(\"...\", \"**\");\n\n            let rel_path = GlobBuilder::new(&rel_path_glob)\n                .literal_separator(true)\n                .build()\n                .ok()\n                .map(|b| b.compile_matcher());\n\n            let rel_task = if task_glob != \"*\" {\n                GlobBuilder::new(task_glob)\n                    .literal_separator(false)\n                    .build()\n                    .ok()\n                    .map(|b| b.compile_matcher())\n            } else {\n                None\n            };\n\n            (rel_path, rel_task)\n        } else {\n            (None, None)\n        };\n\n        // === Match tasks with extension stripping ===\n        Ok(self\n            .iter()\n            .filter(|(k, _)| {\n                // Split task name into path and task parts\n                let key_parts: Vec<&str> = k.splitn(2, ':').collect();\n                let (key_path, key_task) = match key_parts.as_slice() {\n                    [path, task] => (*path, *task),\n                    [path] => (*path, \"\"),\n                    _ => (k.as_str(), \"\"),\n                };\n\n                // Match path part with ellipsis support\n                let path_matches = if let Some(ref matcher) = path_matcher {\n                    matcher.is_match(key_path)\n                } else {\n                    false\n                };\n\n                // Match task part with asterisk support and extension stripping\n                // When the pattern explicitly uses a wildcard after `:` (e.g., \"test:*\"),\n                // require the key to actually have a task part (i.e., contain a `:`\n                // separator). This prevents \"test\" from matching \"test:*\", which would\n                // cause circular dependencies. Implicit wildcards (bare names like \"test\")\n                // should still match the exact task.\n                let task_matches = if task_glob == \"*\" {\n                    !has_explicit_task_glob || !key_task.is_empty()\n                } else if let Some(ref matcher) = task_matcher {\n                    // Check exact match OR match without extension\n                    matcher.is_match(key_task) || matcher.is_match(strip_extension(key_task))\n                } else {\n                    false\n                };\n\n                // Try matching without // prefix for relative patterns\n                let relative_match = if !pat.starts_with(\"//\") {\n                    let stripped_key = k.strip_prefix(\"//\").unwrap_or(k);\n                    let stripped_parts: Vec<&str> = stripped_key.splitn(2, ':').collect();\n                    let (stripped_path, stripped_task) = match stripped_parts.as_slice() {\n                        [path, task] => (*path, *task),\n                        [path] => (*path, \"\"),\n                        _ => (stripped_key, \"\"),\n                    };\n\n                    let rel_path_matches = if let Some(ref matcher) = rel_path_matcher {\n                        matcher.is_match(stripped_path)\n                    } else {\n                        false\n                    };\n\n                    let rel_task_matches = if task_glob == \"*\" {\n                        !has_explicit_task_glob || !stripped_task.is_empty()\n                    } else if let Some(ref matcher) = rel_task_matcher {\n                        // Check exact match OR match without extension\n                        matcher.is_match(stripped_task)\n                            || matcher.is_match(strip_extension(stripped_task))\n                    } else {\n                        false\n                    };\n\n                    rel_path_matches && rel_task_matches\n                } else {\n                    false\n                };\n\n                (path_matches && task_matches) || relative_match\n            })\n            .map(|(_, t)| t)\n            .unique()\n            .collect())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(unix)]\n    use std::os::unix::fs::PermissionsExt;\n    use std::path::Path;\n    use std::sync::Mutex;\n\n    use crate::task::Task;\n    use crate::{config::Config, dirs};\n    use pretty_assertions::assert_eq;\n\n    use super::name_from_path;\n\n    // Thread-local storage to capture parser state during tests\n    thread_local! {\n        static CAPTURED_PARSER_FIELDS: Mutex<Option<Vec<String>>> = const { Mutex::new(None) };\n    }\n\n    pub(super) fn capture_parsed_fields(fields: Vec<String>) {\n        CAPTURED_PARSER_FIELDS.with(|captured| {\n            *captured.lock().unwrap() = Some(fields);\n        });\n    }\n\n    fn take_captured_fields() -> Option<Vec<String>> {\n        CAPTURED_PARSER_FIELDS.with(|captured| captured.lock().unwrap().take())\n    }\n\n    #[tokio::test]\n    async fn test_from_path() {\n        let test_cases = [(\".mise/tasks/filetask\", \"filetask\", vec![\"ft\"])];\n        let config = Config::get().await.unwrap();\n        for (path, name, aliases) in test_cases {\n            let t = Task::from_path(\n                &config,\n                Path::new(path),\n                Path::new(\".mise/tasks\"),\n                Path::new(dirs::CWD.as_ref().unwrap()),\n            )\n            .await\n            .unwrap();\n            assert_eq!(t.name, name);\n            assert_eq!(t.aliases, aliases);\n        }\n    }\n\n    #[test]\n    #[cfg(unix)]\n    fn test_name_from_path() {\n        let test_cases = [\n            ((\"/.mise/tasks\", \"/.mise/tasks/a\"), \"a\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/b\"), \"a:b\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/b/c\"), \"a:b:c\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a:b\"), \"a_b\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a:b/c\"), \"a_b:c\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/_default\"), \"a\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/_default.sh\"), \"a\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/_default.js\"), \"a\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/b/_default\"), \"a:b\"),\n            ((\"/.mise/tasks\", \"/.mise/tasks/a/b/_default.sh\"), \"a:b\"),\n        ];\n\n        for ((root, path), expected) in test_cases {\n            assert_eq!(name_from_path(root, path).unwrap(), expected)\n        }\n    }\n\n    #[test]\n    fn test_name_from_path_invalid() {\n        let test_cases = [(\"/some/other/dir\", \"/.mise/tasks/a\")];\n\n        for (root, path) in test_cases {\n            assert!(name_from_path(root, path).is_err())\n        }\n    }\n\n    // This test verifies that resolve_depends correctly uses self.depends_post\n    // instead of iterating through all tasks_to_run (which was the bug)\n    #[tokio::test]\n    async fn test_resolve_depends_post_uses_self_only() {\n        use crate::task::task_dep::TaskDep;\n\n        // Create a task with depends_post\n        let task_with_post_deps = Task {\n            name: \"task_with_post\".to_string(),\n            depends_post: vec![\n                TaskDep {\n                    task: \"post1\".to_string(),\n                    args: vec![],\n                    env: Default::default(),\n                },\n                TaskDep {\n                    task: \"post2\".to_string(),\n                    args: vec![],\n                    env: Default::default(),\n                },\n            ],\n            ..Default::default()\n        };\n\n        // Create another task with different depends_post\n        let other_task = Task {\n            name: \"other_task\".to_string(),\n            depends_post: vec![TaskDep {\n                task: \"other_post\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        // Verify that task_with_post_deps has the expected depends_post\n        assert_eq!(task_with_post_deps.depends_post.len(), 2);\n        assert_eq!(task_with_post_deps.depends_post[0].task, \"post1\");\n        assert_eq!(task_with_post_deps.depends_post[1].task, \"post2\");\n\n        // Verify that other_task doesn't interfere (would have before the fix)\n        assert_eq!(other_task.depends_post.len(), 1);\n        assert_eq!(other_task.depends_post[0].task, \"other_post\");\n    }\n\n    #[tokio::test]\n    async fn test_from_path_toml_headers() {\n        use std::fs;\n        use tempfile::tempdir;\n\n        let config = Config::get().await.unwrap();\n        let temp_dir = tempdir().unwrap();\n        let task_path = temp_dir.path().join(\"test_task\");\n\n        fs::write(\n            &task_path,\n            r#\"#!/bin/bash\n#MISE description=\"Build the CLI\"\n# MISE alias=\"b\"\n# [MISE] sources=[\"Cargo.toml\", \"src/**/*.rs\"]\necho \"hello world\"\n\"#,\n        )\n        .unwrap();\n\n        let result = Task::from_path(&config, &task_path, temp_dir.path(), temp_dir.path()).await;\n        let mut expected = Task::new(&task_path, temp_dir.path(), temp_dir.path()).unwrap();\n        expected.description = \"Build the CLI\".to_string();\n        expected.aliases = vec![\"b\".to_string()];\n        expected.sources = vec![\"Cargo.toml\".to_string(), \"src/**/*.rs\".to_string()];\n        assert_eq!(result.unwrap(), expected);\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_from_path_env_file_with_spaces_around_equals() {\n        use std::fs;\n        use tempfile::tempdir;\n\n        let config = Config::get().await.unwrap();\n        let ts = config.get_toolset().await.unwrap();\n        let temp_dir = tempdir().unwrap();\n        let task_path = temp_dir.path().join(\"hello\");\n        let env_path = temp_dir.path().join(\"env.yaml\");\n\n        fs::write(&env_path, \"USR: World!\\n\").unwrap();\n        fs::write(\n            &task_path,\n            r#\"#!/usr/bin/env bash\n#MISE env._.file = \"env.yaml\"\necho \"Hello $USR\"\n\"#,\n        )\n        .unwrap();\n\n        let task = Task::from_path(&config, &task_path, temp_dir.path(), temp_dir.path())\n            .await\n            .unwrap();\n        let (env, task_env) = task.render_env(&config, ts).await.unwrap();\n\n        assert_eq!(task_env, vec![(\"USR\".to_string(), \"World!\".to_string())]);\n        assert_eq!(env.get(\"USR\"), Some(&\"World!\".to_string()));\n    }\n\n    #[tokio::test]\n    async fn test_from_path_invalid_toml() {\n        use std::fs;\n        use tempfile::tempdir;\n\n        let config = Config::get().await.unwrap();\n        let temp_dir = tempdir().unwrap();\n        let task_path = temp_dir.path().join(\"test_task\");\n\n        // Create a task file with invalid TOML in the header\n        fs::write(\n            &task_path,\n            r#\"#!/bin/bash\n#MISE description=\"test task\"\n#MISE env={invalid=toml=here}\necho \"hello world\"\n\"#,\n        )\n        .unwrap();\n\n        let result = Task::from_path(&config, &task_path, temp_dir.path(), temp_dir.path()).await;\n\n        assert!(result.is_err());\n        let error = result.unwrap_err();\n        assert!(\n            error\n                .to_string()\n                .contains(\"failed to parse task header TOML\")\n        );\n    }\n\n    #[test]\n    fn test_resolve_task_pattern() {\n        use super::resolve_task_pattern;\n\n        // Test 1: Relative pattern with monorepo parent task\n        let parent_task = Task {\n            name: \"//projects/frontend:test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":build\", Some(&parent_task)),\n            \"//projects/frontend:build\"\n        );\n\n        // Test 2: Relative pattern with different parent\n        let parent_task = Task {\n            name: \"//libs/shared:lint\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":compile\", Some(&parent_task)),\n            \"//libs/shared:compile\"\n        );\n\n        // Test 3: Absolute pattern should not be modified\n        let parent_task = Task {\n            name: \"//projects/frontend:test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"//projects/backend:build\", Some(&parent_task)),\n            \"//projects/backend:build\"\n        );\n\n        // Test 4: Simple task name with monorepo parent should resolve relatively (NEW BEHAVIOR)\n        assert_eq!(\n            resolve_task_pattern(\"build\", Some(&parent_task)),\n            \"//projects/frontend:build\"\n        );\n\n        // Test 5: Relative pattern without parent task (no resolution)\n        assert_eq!(resolve_task_pattern(\":build\", None), \":build\");\n\n        // Test 6: Non-monorepo task - colon pattern should not resolve\n        let parent_task = Task {\n            name: \"test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(resolve_task_pattern(\":build\", Some(&parent_task)), \":build\");\n\n        // Test 6a: Non-monorepo task - bare name should not resolve\n        assert_eq!(resolve_task_pattern(\"build\", Some(&parent_task)), \"build\");\n\n        // Test 7: Root monorepo task (empty path)\n        let parent_task = Task {\n            name: \"//:root-task\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":other\", Some(&parent_task)),\n            \"//:other\"\n        );\n\n        // Test 8: Double colon should not be treated as relative\n        let parent_task = Task {\n            name: \"//projects/frontend:test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"::global\", Some(&parent_task)),\n            \"::global\"\n        );\n\n        // Test 9: Pattern with wildcards\n        let parent_task = Task {\n            name: \"//projects/frontend:test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":test*\", Some(&parent_task)),\n            \"//projects/frontend:test*\"\n        );\n\n        // Test 10: Deep nested path\n        let parent_task = Task {\n            name: \"//a/b/c/d:task\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":dep\", Some(&parent_task)),\n            \"//a/b/c/d:dep\"\n        );\n\n        // Test 11: Task name with colon (e.g., \"do:item-1\")\n        // This is the bug that was fixed - we need to split on the FIRST colon after //\n        let parent_task = Task {\n            name: \"//submodule:do:item-1\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":before\", Some(&parent_task)),\n            \"//submodule:before\"\n        );\n\n        // Test 12: Another task name with multiple colons\n        let parent_task = Task {\n            name: \"//project:test:unit:fast\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\":setup\", Some(&parent_task)),\n            \"//project:setup\"\n        );\n\n        // Test 13: Bare name without parent task (no resolution)\n        assert_eq!(resolve_task_pattern(\"build\", None), \"build\");\n\n        // Test 14: Bare name with different monorepo parent\n        let parent_task = Task {\n            name: \"//libs/shared:lint\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"compile\", Some(&parent_task)),\n            \"//libs/shared:compile\"\n        );\n\n        // Test 15: Bare name with root monorepo task\n        let parent_task = Task {\n            name: \"//:root-task\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"other\", Some(&parent_task)),\n            \"//:other\"\n        );\n\n        // Test 16: Bare name with task containing colons\n        let parent_task = Task {\n            name: \"//submodule:do:item-1\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"before\", Some(&parent_task)),\n            \"//submodule:before\"\n        );\n\n        // Test 17: Absolute path should not be modified even with monorepo parent\n        let parent_task = Task {\n            name: \"//projects/frontend:test\".to_string(),\n            ..Default::default()\n        };\n        assert_eq!(\n            resolve_task_pattern(\"//other/module:task\", Some(&parent_task)),\n            \"//other/module:task\"\n        );\n\n        // Test 18: Global task (::) should not be modified\n        assert_eq!(\n            resolve_task_pattern(\"::global\", Some(&parent_task)),\n            \"::global\"\n        );\n    }\n\n    #[test]\n    fn test_extract_monorepo_path() {\n        use super::extract_monorepo_path;\n\n        // Test 1: Simple monorepo task\n        assert_eq!(\n            extract_monorepo_path(\"//projects/frontend:test\"),\n            Some(\"projects/frontend\".to_string())\n        );\n\n        // Test 2: Root level task\n        assert_eq!(extract_monorepo_path(\"//:root-task\"), Some(\"\".to_string()));\n\n        // Test 3: Deep nested path\n        assert_eq!(\n            extract_monorepo_path(\"//a/b/c/d:task\"),\n            Some(\"a/b/c/d\".to_string())\n        );\n\n        // Test 4: Non-monorepo task (no // prefix)\n        assert_eq!(extract_monorepo_path(\"regular-task\"), None);\n\n        // Test 5: Task name with colon (e.g., \"do:item-1\")\n        // This was the bug - we need to extract based on FIRST colon after //\n        assert_eq!(\n            extract_monorepo_path(\"//submodule:do:item-1\"),\n            Some(\"submodule\".to_string())\n        );\n\n        // Test 6: Multiple colons in task name\n        assert_eq!(\n            extract_monorepo_path(\"//project:test:unit:fast\"),\n            Some(\"project\".to_string())\n        );\n\n        // Test 7: Complex path with colons in task name\n        assert_eq!(\n            extract_monorepo_path(\"//apps/backend:build:prod\"),\n            Some(\"apps/backend\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_strip_extension() {\n        use super::strip_extension;\n\n        // Test 1: Single extension\n        assert_eq!(strip_extension(\"task.sh\"), \"task\");\n        assert_eq!(strip_extension(\"build.js\"), \"build\");\n        assert_eq!(strip_extension(\"test.py\"), \"test\");\n\n        // Test 2: Multiple extensions (only strips rightmost one)\n        assert_eq!(strip_extension(\"backup.test.js\"), \"backup.test\");\n        assert_eq!(strip_extension(\"file.tar.gz\"), \"file.tar\");\n        assert_eq!(strip_extension(\"archive.tar.bz2\"), \"archive.tar\");\n\n        // Test 3: No extension\n        assert_eq!(strip_extension(\"task\"), \"task\");\n        assert_eq!(strip_extension(\"build\"), \"build\");\n\n        // Test 4: Hidden files (starting with dot)\n        // Now preserved to avoid empty strings\n        assert_eq!(strip_extension(\".hidden\"), \".hidden\");\n        assert_eq!(strip_extension(\".gitignore\"), \".gitignore\");\n\n        // Test 5: Hidden files with extension\n        assert_eq!(strip_extension(\".hidden.sh\"), \".hidden\");\n        assert_eq!(strip_extension(\".config.json\"), \".config\");\n\n        // Test 6: Empty string\n        assert_eq!(strip_extension(\"\"), \"\");\n\n        // Test 7: Only extension separator (preserved to avoid empty string)\n        assert_eq!(strip_extension(\".\"), \".\");\n\n        // Test 8: Multiple dots with extension\n        assert_eq!(strip_extension(\"my.task.name.js\"), \"my.task.name\");\n\n        // Test 9: Path-like names (shouldn't treat / as special)\n        assert_eq!(strip_extension(\"path/to/task.sh\"), \"path/to/task\");\n        assert_eq!(strip_extension(\"path/task\"), \"path/task\");\n\n        // Test 10: Task names with dots in the middle\n        assert_eq!(strip_extension(\"test.unit\"), \"test\");\n        assert_eq!(strip_extension(\"build.prod.js\"), \"build.prod\");\n    }\n\n    #[test]\n    fn test_circular_dependency_detection() {\n        use super::Task;\n        use std::collections::BTreeMap;\n\n        let mut tasks = BTreeMap::new();\n\n        // Create circular dependency: task_a -> task_b -> task_a\n        let task_a = Task {\n            name: \"task_a\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"task_b\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        let task_b = Task {\n            name: \"task_b\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"task_a\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        tasks.insert(\"task_a\".to_string(), task_a.clone());\n        tasks.insert(\"task_b\".to_string(), task_b);\n\n        // Should detect circular dependency\n        let result = task_a.all_depends(&tasks);\n        assert!(result.is_err());\n        let err_msg = format!(\"{}\", result.unwrap_err());\n        assert!(err_msg.contains(\"circular dependency detected\"));\n    }\n\n    #[test]\n    fn test_transitive_circular_dependency_detection() {\n        use super::Task;\n        use std::collections::BTreeMap;\n\n        let mut tasks = BTreeMap::new();\n\n        // Create transitive circular dependency: a -> b -> c -> a\n        let task_a = Task {\n            name: \"task_a\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"task_b\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        let task_b = Task {\n            name: \"task_b\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"task_c\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        let task_c = Task {\n            name: \"task_c\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"task_a\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        tasks.insert(\"task_a\".to_string(), task_a.clone());\n        tasks.insert(\"task_b\".to_string(), task_b);\n        tasks.insert(\"task_c\".to_string(), task_c);\n\n        // Should detect circular dependency\n        let result = task_a.all_depends(&tasks);\n        assert!(result.is_err());\n        let err_msg = format!(\"{}\", result.unwrap_err());\n        assert!(err_msg.contains(\"circular dependency detected\"));\n    }\n\n    #[test]\n    fn test_no_false_positive_for_diamond_dependency() {\n        use super::Task;\n        use std::collections::BTreeMap;\n\n        let mut tasks = BTreeMap::new();\n\n        // Create diamond dependency (NOT circular): root -> [a, b] -> common\n        let root = Task {\n            name: \"root\".to_string(),\n            depends: vec![\n                crate::task::task_dep::TaskDep {\n                    task: \"task_a\".to_string(),\n                    args: vec![],\n                    env: Default::default(),\n                },\n                crate::task::task_dep::TaskDep {\n                    task: \"task_b\".to_string(),\n                    args: vec![],\n                    env: Default::default(),\n                },\n            ],\n            ..Default::default()\n        };\n\n        let task_a = Task {\n            name: \"task_a\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"common\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        let task_b = Task {\n            name: \"task_b\".to_string(),\n            depends: vec![crate::task::task_dep::TaskDep {\n                task: \"common\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        let common = Task {\n            name: \"common\".to_string(),\n            ..Default::default()\n        };\n\n        tasks.insert(\"root\".to_string(), root.clone());\n        tasks.insert(\"task_a\".to_string(), task_a);\n        tasks.insert(\"task_b\".to_string(), task_b);\n        tasks.insert(\"common\".to_string(), common);\n\n        // Should NOT detect circular dependency (diamond is OK)\n        let result = root.all_depends(&tasks);\n        assert!(result.is_ok());\n        let deps = result.unwrap();\n        // Should have task_a, task_b, and common (deduplicated)\n        assert_eq!(deps.len(), 3);\n    }\n\n    #[test]\n    fn test_file_path_raw_absolute() {\n        use std::path::PathBuf;\n\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"/absolute/path/script.sh\")),\n            config_root: Some(PathBuf::from(\"/project/root\")),\n            ..Default::default()\n        };\n\n        let result = task.file_path_raw();\n        assert_eq!(result, Some(PathBuf::from(\"/absolute/path/script.sh\")));\n    }\n\n    #[test]\n    fn test_file_path_raw_relative() {\n        use std::path::PathBuf;\n\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"scripts/test.sh\")),\n            config_root: Some(PathBuf::from(\"/project/root\")),\n            ..Default::default()\n        };\n\n        let result = task.file_path_raw();\n        assert_eq!(result, Some(PathBuf::from(\"/project/root/scripts/test.sh\")));\n    }\n\n    #[test]\n    fn test_file_path_raw_relative_no_config_root() {\n        use std::path::PathBuf;\n\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"scripts/test.sh\")),\n            config_root: None,\n            ..Default::default()\n        };\n\n        let result = task.file_path_raw();\n        assert_eq!(result, Some(PathBuf::from(\"scripts/test.sh\")));\n    }\n\n    #[test]\n    fn test_file_path_raw_none() {\n        let task = Task {\n            name: \"test\".to_string(),\n            file: None,\n            config_root: None,\n            ..Default::default()\n        };\n\n        let result = task.file_path_raw();\n        assert_eq!(result, None);\n    }\n\n    #[tokio::test]\n    async fn test_file_path_absolute() {\n        use std::path::PathBuf;\n\n        let config = Config::get().await.unwrap();\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"/absolute/path/script.sh\")),\n            config_root: Some(PathBuf::from(\"/project/root\")),\n            ..Default::default()\n        };\n\n        let result = task.file_path(&config).await.unwrap();\n        assert_eq!(result, Some(PathBuf::from(\"/absolute/path/script.sh\")));\n    }\n\n    #[tokio::test]\n    async fn test_file_path_relative() {\n        use std::path::PathBuf;\n\n        let config = Config::get().await.unwrap();\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"scripts/test.sh\")),\n            config_root: Some(PathBuf::from(\"/project/root\")),\n            ..Default::default()\n        };\n\n        let result = task.file_path(&config).await.unwrap();\n        assert_eq!(result, Some(PathBuf::from(\"/project/root/scripts/test.sh\")));\n    }\n\n    #[tokio::test]\n    async fn test_file_path_none() {\n        let config = Config::get().await.unwrap();\n        let task = Task {\n            name: \"test\".to_string(),\n            file: None,\n            config_root: None,\n            ..Default::default()\n        };\n\n        let result = task.file_path(&config).await.unwrap();\n        assert_eq!(result, None);\n    }\n\n    #[tokio::test]\n    async fn test_file_path_with_templating() {\n        use std::path::PathBuf;\n\n        let config = Config::get().await.unwrap();\n        let task = Task {\n            name: \"test\".to_string(),\n            file: Some(PathBuf::from(\"scripts/{{config_root}}/test.sh\")),\n            config_root: Some(PathBuf::from(\"/project/root\")),\n            ..Default::default()\n        };\n\n        // This test verifies that templating is processed in file_path\n        let result = task.file_path(&config).await;\n        // Should succeed (not error on template rendering)\n        assert!(result.is_ok());\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_parses_all_fields() {\n        use std::fs;\n        use tempfile::tempdir;\n\n        // Create a temporary directory for the test\n        let temp_dir = tempdir().unwrap();\n        let tasks_dir = temp_dir.path().join(\"tasks\");\n        fs::create_dir(&tasks_dir).unwrap();\n        let task_file = tasks_dir.join(\"test-task\");\n\n        // Create a file task with ALL possible header fields\n        let script_content = r#\"#!/usr/bin/env bash\n#MISE description=\"Test task with all fields\"\n#MISE aliases=[\"alias1\", \"alias2\"]\n#MISE depends=[\"dep1\", \"dep2\"]\n#MISE depends_post=[\"post1\"]\n#MISE wait_for=[\"wait1\"]\n#MISE env={TEST_VAR=\"value\"}\n#MISE dir=\"/some/dir\"\n#MISE hide=true\n#MISE raw=true\n#MISE interactive=true\n#MISE sources=[\"src1.txt\", \"src2.txt\"]\n#MISE outputs=[\"out1.txt\"]\n#MISE shell=\"bash -c\"\n#MISE quiet=true\n#MISE silent=true\n#MISE tools={node=\"20\", python=\"3.11\"}\n#MISE confirm=\"Are you sure?\"\necho \"test\"\n\"#;\n        fs::write(&task_file, script_content).unwrap();\n        fs::set_permissions(&task_file, std::fs::Permissions::from_mode(0o755)).unwrap();\n\n        let config = Config::get().await.unwrap();\n        let task = Task::from_path(&config, &task_file, &tasks_dir, temp_dir.path())\n            .await\n            .unwrap();\n\n        assert_eq!(task.description, \"Test task with all fields\");\n        assert_eq!(task.aliases, vec![\"alias1\", \"alias2\"]);\n        assert_eq!(task.depends.len(), 2);\n        assert_eq!(task.depends_post.len(), 1);\n        assert_eq!(task.wait_for.len(), 1);\n        assert_eq!(task.dir, Some(\"/some/dir\".to_string()));\n        assert_eq!(task.hide, true);\n        assert_eq!(task.raw, true);\n        assert_eq!(task.interactive, true);\n        assert_eq!(task.sources, vec![\"src1.txt\", \"src2.txt\"]);\n        assert_eq!(task.shell, Some(\"bash -c\".to_string()));\n        assert_eq!(task.quiet, true);\n        assert!(!task.tools.is_empty());\n        assert_eq!(task.confirm, Some(\"Are you sure?\".to_string()));\n\n        let mut parsed_fields =\n            take_captured_fields().expect(\"Parser fields should have been captured\");\n\n        // Group \"alias\" and \"aliases\" as they are alternate forms (count as 1)\n        let has_alias = parsed_fields.iter().any(|k| k == \"alias\");\n        parsed_fields.retain(|k| k != \"aliases\" || !has_alias);\n\n        // Count property lines in script (exclude shebang and echo command)\n        let script_lines = script_content.lines().count() - 2;\n\n        assert_eq!(\n            parsed_fields.len(),\n            script_lines,\n            \"Parser looks for {} properties but test script has {} field lines.\\n\\\n             If you added (or removed) parseable fields, add it to the test script.\\n\\\n             Parser fields: {:?}\",\n            parsed_fields.len(),\n            script_lines,\n            parsed_fields\n        );\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_multi_line_tools_merge() {\n        // Regression test for https://github.com/jdx/mise/discussions/7839\n        // Multiple #MISE tools.X=Y lines should be merged into a single tools table\n        use std::fs;\n        use std::os::unix::fs::PermissionsExt;\n        use tempfile::tempdir;\n\n        let temp_dir = tempdir().unwrap();\n        let tasks_dir = temp_dir.path().join(\"tasks\");\n        fs::create_dir(&tasks_dir).unwrap();\n        let task_file = tasks_dir.join(\"multi-tools-task\");\n\n        // Create a file task with multiple tools on separate lines\n        let script_content = r#\"#!/usr/bin/env bash\n#MISE tools.node=\"20\"\n#MISE tools.python=\"3.11\"\n#MISE tools.ruby=\"3.2\"\necho \"test\"\n\"#;\n        fs::write(&task_file, script_content).unwrap();\n        fs::set_permissions(&task_file, std::fs::Permissions::from_mode(0o755)).unwrap();\n\n        let config = Config::get().await.unwrap();\n        let task = Task::from_path(&config, &task_file, &tasks_dir, temp_dir.path())\n            .await\n            .unwrap();\n\n        // All three tools should be present\n        assert_eq!(\n            task.tools.len(),\n            3,\n            \"Expected 3 tools, got: {:?}\",\n            task.tools\n        );\n        assert!(\n            task.tools.contains_key(\"node\"),\n            \"Expected 'node' in tools: {:?}\",\n            task.tools\n        );\n        assert!(\n            task.tools.contains_key(\"python\"),\n            \"Expected 'python' in tools: {:?}\",\n            task.tools\n        );\n        assert!(\n            task.tools.contains_key(\"ruby\"),\n            \"Expected 'ruby' in tools: {:?}\",\n            task.tools\n        );\n        assert_eq!(task.tools.get(\"node\").unwrap(), \"20\");\n        assert_eq!(task.tools.get(\"python\").unwrap(), \"3.11\");\n        assert_eq!(task.tools.get(\"ruby\").unwrap(), \"3.2\");\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_hyphenated_and_numeric_tool_names() {\n        // Test that tool names with hyphens and numbers are parsed correctly\n        // e.g., git-cliff, 1password\n        use std::fs;\n        use std::os::unix::fs::PermissionsExt;\n        use tempfile::tempdir;\n\n        let temp_dir = tempdir().unwrap();\n        let tasks_dir = temp_dir.path().join(\"tasks\");\n        fs::create_dir(&tasks_dir).unwrap();\n        let task_file = tasks_dir.join(\"hyphenated-tools-task\");\n\n        // Create a file task with hyphenated and numeric tool names\n        let script_content = r#\"#!/usr/bin/env bash\n#MISE tools.git-cliff=\"1.0\"\n#MISE tools.1password-cli=\"2.0\"\necho \"test\"\n\"#;\n        fs::write(&task_file, script_content).unwrap();\n        fs::set_permissions(&task_file, std::fs::Permissions::from_mode(0o755)).unwrap();\n\n        let config = Config::get().await.unwrap();\n        let task = Task::from_path(&config, &task_file, &tasks_dir, temp_dir.path())\n            .await\n            .unwrap();\n\n        // Both tools should be present\n        assert_eq!(\n            task.tools.len(),\n            2,\n            \"Expected 2 tools, got: {:?}\",\n            task.tools\n        );\n        assert!(\n            task.tools.contains_key(\"git-cliff\"),\n            \"Expected 'git-cliff' in tools: {:?}\",\n            task.tools\n        );\n        assert!(\n            task.tools.contains_key(\"1password-cli\"),\n            \"Expected '1password-cli' in tools: {:?}\",\n            task.tools\n        );\n        assert_eq!(task.tools.get(\"git-cliff\").unwrap(), \"1.0\");\n        assert_eq!(task.tools.get(\"1password-cli\").unwrap(), \"2.0\");\n    }\n\n    #[test]\n    fn test_get_matching_wildcard_does_not_match_parent() {\n        use std::collections::BTreeMap;\n\n        use super::GetMatchingExt;\n\n        let mut tasks: BTreeMap<String, String> = BTreeMap::new();\n        tasks.insert(\"test\".to_string(), \"test\".to_string());\n        tasks.insert(\"test:foo\".to_string(), \"test:foo\".to_string());\n        tasks.insert(\"test:bar\".to_string(), \"test:bar\".to_string());\n\n        // \"test:*\" should match \"test:foo\" and \"test:bar\" but NOT \"test\" itself\n        let matches = tasks.get_matching(\"test:*\").unwrap();\n        assert_eq!(\n            matches,\n            vec![&\"test:bar\".to_string(), &\"test:foo\".to_string()]\n        );\n\n        // Bare name \"test\" should still match the \"test\" task (implicit wildcard)\n        let matches = tasks.get_matching(\"test\").unwrap();\n        assert!(matches.contains(&&\"test\".to_string()));\n    }\n}\n"
  },
  {
    "path": "src/task/task_context_builder.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::config::Config;\nuse crate::config::config_file::ConfigFile;\nuse crate::config::env_directive::{EnvDirective, EnvResolveOptions, EnvResults, ToolsFilter};\nuse crate::env;\nuse crate::task::Task;\nuse crate::task::task_helpers::canonicalize_path;\nuse crate::toolset::{Toolset, ToolsetBuilder};\nuse eyre::Result;\nuse indexmap::IndexMap;\nuse std::collections::BTreeMap;\nuse std::path::PathBuf;\nuse std::sync::{Arc, RwLock};\n\ntype EnvResolutionResult = (\n    BTreeMap<String, String>,\n    Vec<(String, String)>,\n    Option<IndexMap<String, String>>,\n);\n\n/// Builds toolset and environment context for task execution\n///\n/// Handles:\n/// - Toolset caching for monorepo tasks\n/// - Environment resolution with config file contexts\n/// - Tool request set caching\npub struct TaskContextBuilder {\n    toolset_cache: RwLock<IndexMap<PathBuf, Arc<Toolset>>>,\n    tool_request_set_cache: RwLock<IndexMap<PathBuf, Arc<crate::toolset::ToolRequestSet>>>,\n    env_resolution_cache: RwLock<IndexMap<PathBuf, EnvResolutionResult>>,\n}\n\nimpl Clone for TaskContextBuilder {\n    fn clone(&self) -> Self {\n        // Clone by creating a new instance with the same cache contents\n        Self {\n            toolset_cache: RwLock::new(self.toolset_cache.read().unwrap().clone()),\n            tool_request_set_cache: RwLock::new(\n                self.tool_request_set_cache.read().unwrap().clone(),\n            ),\n            env_resolution_cache: RwLock::new(self.env_resolution_cache.read().unwrap().clone()),\n        }\n    }\n}\n\nimpl TaskContextBuilder {\n    pub fn new() -> Self {\n        Self {\n            toolset_cache: RwLock::new(IndexMap::new()),\n            tool_request_set_cache: RwLock::new(IndexMap::new()),\n            env_resolution_cache: RwLock::new(IndexMap::new()),\n        }\n    }\n\n    /// Build toolset for a task, with caching for monorepo tasks\n    pub async fn build_toolset_for_task(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        task_cf: Option<&Arc<dyn ConfigFile>>,\n        tools: &[ToolArg],\n    ) -> Result<Toolset> {\n        // Only use task-specific config file context for monorepo tasks\n        // (tasks with self.cf set, not just those with a config_source)\n        if let (Some(task_cf), Some(_)) = (task_cf, &task.cf) {\n            let config_path = canonicalize_path(task_cf.get_path());\n\n            trace!(\n                \"task {} using monorepo config file context from {}\",\n                task.name,\n                config_path.display()\n            );\n\n            // Check cache first if no task-specific tools or CLI args\n            if tools.is_empty() && task.tools.is_empty() {\n                let cache = self\n                    .toolset_cache\n                    .read()\n                    .expect(\"toolset_cache RwLock poisoned\");\n                if let Some(cached_ts) = cache.get(&config_path) {\n                    trace!(\n                        \"task {} using cached toolset from {}\",\n                        task.name,\n                        config_path.display()\n                    );\n                    // Clone Arc, not the entire Toolset\n                    return Ok(Arc::unwrap_or_clone(Arc::clone(cached_ts)));\n                }\n            }\n\n            let task_dir = task_cf.get_path().parent().unwrap_or(task_cf.get_path());\n            trace!(\n                \"Loading config hierarchy for monorepo task {} toolset from {}\",\n                task.name,\n                task_dir.display()\n            );\n\n            let config_paths = crate::config::load_config_hierarchy_from_dir(task_dir)?;\n            trace!(\n                \"task {} found {} config files in hierarchy\",\n                task.name,\n                config_paths.len()\n            );\n\n            let task_config_files =\n                crate::config::load_config_files_from_paths(&config_paths).await?;\n\n            let task_ts = ToolsetBuilder::new()\n                .with_config_files(task_config_files)\n                .with_args(tools)\n                .build(config)\n                .await?;\n\n            trace!(\"task {} final toolset: {:?}\", task.name, task_ts);\n\n            // Cache the toolset if no task-specific tools or CLI args\n            if tools.is_empty() && task.tools.is_empty() {\n                let mut cache = self\n                    .toolset_cache\n                    .write()\n                    .expect(\"toolset_cache RwLock poisoned\");\n                cache.insert(config_path.clone(), Arc::new(task_ts.clone()));\n                trace!(\n                    \"task {} cached toolset to {}\",\n                    task.name,\n                    config_path.display()\n                );\n            }\n\n            Ok(task_ts)\n        } else {\n            trace!(\"task {} using standard toolset build\", task.name);\n            // Standard toolset build - includes all config files\n            ToolsetBuilder::new().with_args(tools).build(config).await\n        }\n    }\n\n    /// Resolve environment variables for a task using its config file context\n    /// This is used for monorepo tasks to load env vars from subdirectory mise.toml files\n    /// Returns (env, task_env, resolved_vars) where resolved_vars contains vars from the\n    /// task's config hierarchy (for injecting into tera context during script rendering)\n    pub async fn resolve_task_env_with_config(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        task_cf: &Arc<dyn ConfigFile>,\n        ts: &Toolset,\n    ) -> Result<(\n        BTreeMap<String, String>,\n        Vec<(String, String)>,\n        Option<IndexMap<String, String>>,\n    )> {\n        // Determine if this is a monorepo task (task config differs from current project root)\n        let is_monorepo_task = task_cf.project_root() != config.project_root;\n\n        // Check if task runs in the current working directory\n        let task_runs_in_cwd = task\n            .dir(config)\n            .await?\n            .and_then(|dir| config.project_root.as_ref().map(|pr| dir == *pr))\n            .unwrap_or(false);\n\n        // Load task config files for monorepo tasks (reused for both vars and env resolution)\n        let task_config_files = if is_monorepo_task && !task_runs_in_cwd {\n            let task_dir = task_cf.get_path().parent().unwrap_or(task_cf.get_path());\n\n            trace!(\n                \"Loading config hierarchy for monorepo task {} from {}\",\n                task.name,\n                task_dir.display()\n            );\n\n            let config_paths = crate::config::load_config_hierarchy_from_dir(task_dir)?;\n            trace!(\"Found {} config files in hierarchy\", config_paths.len());\n\n            Some(crate::config::load_config_files_from_paths(&config_paths).await?)\n        } else {\n            None\n        };\n\n        // Get env entries - load the FULL config hierarchy for monorepo tasks\n        let all_config_env_entries: Vec<(EnvDirective, PathBuf)> =\n            if let Some(ref task_config_files) = task_config_files {\n                // Extract env entries from all config files in the task's hierarchy\n                task_config_files\n                    .iter()\n                    .rev()\n                    .filter_map(|(source, cf)| {\n                        cf.env_entries()\n                            .ok()\n                            .map(|entries| entries.into_iter().map(move |e| (e, source.clone())))\n                    })\n                    .flatten()\n                    .collect()\n            } else {\n                // For regular tasks OR monorepo tasks that run in cwd:\n                // Use ALL config files from the current project (including MISE_ENV-specific ones)\n                // This fixes env inheritance for tasks with dir=\"{{cwd}}\"\n                config\n                    .config_files\n                    .iter()\n                    .rev()\n                    .filter_map(|(source, cf)| {\n                        cf.env_entries()\n                            .ok()\n                            .map(|entries| entries.into_iter().map(move |e| (e, source.clone())))\n                    })\n                    .flatten()\n                    .collect()\n            };\n\n        // Early return if no special context needed\n        // Check using task_cf entries for compatibility with existing logic\n        let task_cf_env_entries = task_cf.env_entries()?;\n        if self.should_use_standard_env_resolution(task, task_cf, config, &task_cf_env_entries) {\n            let (env, task_env) = task.render_env(config, ts).await?;\n            return Ok((env, task_env, None));\n        }\n\n        let config_path = canonicalize_path(task_cf.get_path());\n\n        // Check cache first if task has no task-specific env directives or tools\n        if task.env.0.is_empty() && task.inherited_env.0.is_empty() && task.tools.is_empty() {\n            let cache = self\n                .env_resolution_cache\n                .read()\n                .expect(\"env_resolution_cache RwLock poisoned\");\n            if let Some(cached) = cache.get(&config_path) {\n                trace!(\n                    \"task {} using cached env resolution from {}\",\n                    task.name,\n                    config_path.display()\n                );\n                return Ok(cached.clone());\n            }\n        }\n\n        let mut env = ts.full_env(config).await?;\n        let (tera_ctx, resolved_vars) = self\n            .build_tera_context(task_cf, ts, config, task_config_files.as_ref())\n            .await?;\n\n        // Resolve config-level env from ALL config files, not just task_cf\n        let config_env_results = self\n            .resolve_env_directives(config, &tera_ctx, &env, all_config_env_entries)\n            .await?;\n        Self::apply_env_results(&mut env, &config_env_results);\n\n        // Register config-level redactions resolved through the task context\n        if !config_env_results.redactions.is_empty() {\n            config.add_redactions(config_env_results.redactions.iter().cloned(), &env);\n        }\n\n        let task_env_directives = self.build_task_env_directives(task);\n        let task_env_results = self\n            .resolve_env_directives(config, &tera_ctx, &env, task_env_directives)\n            .await?;\n\n        let task_env = self.extract_task_env(&task_env_results);\n        Self::apply_env_results(&mut env, &task_env_results);\n\n        // Register task-specific redactions with the global redactor\n        // Include both task-level redact=true keys and config-level redaction patterns\n        // so that config-level `redactions = [\"PATTERN\"]` also covers task-specific env vars\n        let task_redact_keys = config\n            .redaction_keys()\n            .into_iter()\n            .chain(task_env_results.redactions.iter().cloned());\n        config.add_redactions(task_redact_keys, &env);\n\n        // Cache the result if no task-specific env directives or tools\n        if task.env.0.is_empty() && task.inherited_env.0.is_empty() && task.tools.is_empty() {\n            let mut cache = self\n                .env_resolution_cache\n                .write()\n                .expect(\"env_resolution_cache RwLock poisoned\");\n            // Double-check: another thread may have populated while we were resolving\n            cache.entry(config_path.clone()).or_insert_with(|| {\n                trace!(\n                    \"task {} cached env resolution to {}\",\n                    task.name,\n                    config_path.display()\n                );\n                (env.clone(), task_env.clone(), resolved_vars.clone())\n            });\n        }\n\n        Ok((env, task_env, resolved_vars))\n    }\n\n    /// Check if standard env resolution should be used instead of special context\n    fn should_use_standard_env_resolution(\n        &self,\n        task: &Task,\n        task_cf: &Arc<dyn ConfigFile>,\n        config: &Arc<Config>,\n        config_env_entries: &[EnvDirective],\n    ) -> bool {\n        if let (Some(task_config_root), Some(current_config_root)) =\n            (task_cf.project_root(), config.project_root.as_ref())\n            && task_config_root == *current_config_root\n            && config_env_entries.is_empty()\n        {\n            trace!(\n                \"task {} config root matches current and no config env, using standard env resolution\",\n                task.name\n            );\n            return true;\n        }\n        false\n    }\n\n    /// Build tera context with config_root for monorepo tasks\n    /// If task_config_files is provided, resolves vars from the task's config hierarchy\n    /// and merges them into the tera context so env directives can reference {{ vars.X }}\n    /// Returns (tera_context, resolved_vars) where resolved_vars is Some if task-specific\n    /// vars were resolved (for passing to script rendering)\n    async fn build_tera_context(\n        &self,\n        task_cf: &Arc<dyn ConfigFile>,\n        ts: &Toolset,\n        config: &Arc<Config>,\n        task_config_files: Option<&IndexMap<PathBuf, Arc<dyn ConfigFile>>>,\n    ) -> Result<(tera::Context, Option<IndexMap<String, String>>)> {\n        let mut tera_ctx = ts.tera_ctx(config).await?.clone();\n        if let Some(root) = task_cf.project_root() {\n            tera_ctx.insert(\"config_root\", &root);\n        }\n        let mut resolved_vars = None;\n        // If we have task-specific config files, resolve vars from them\n        if let Some(task_config_files) = task_config_files {\n            let vars_entries: Vec<(EnvDirective, PathBuf)> = task_config_files\n                .iter()\n                .rev()\n                .map(|(source, cf)| {\n                    cf.vars_entries()\n                        .map(|ee| ee.into_iter().map(|e| (e, source.clone())))\n                })\n                .collect::<Result<Vec<_>>>()?\n                .into_iter()\n                .flatten()\n                .collect();\n\n            if !vars_entries.is_empty() {\n                let vars_results = EnvResults::resolve(\n                    config,\n                    tera_ctx.clone(),\n                    &env::PRISTINE_ENV,\n                    vars_entries,\n                    EnvResolveOptions {\n                        vars: true,\n                        tools: ToolsFilter::NonToolsOnly,\n                        warn_on_missing_required: false,\n                    },\n                )\n                .await?;\n                // Merge task vars with existing global vars\n                let mut vars: IndexMap<String, String> = config.vars.clone();\n                for (k, (v, _)) in &vars_results.vars {\n                    vars.insert(k.clone(), v.clone());\n                }\n                tera_ctx.insert(\"vars\", &vars);\n                resolved_vars = Some(vars);\n            }\n        }\n        Ok((tera_ctx, resolved_vars))\n    }\n\n    /// Build env directives from task-specific env (including inherited env)\n    fn build_task_env_directives(&self, task: &Task) -> Vec<(EnvDirective, PathBuf)> {\n        // Include inherited_env first (so task's own env can override it)\n        task.inherited_env\n            .0\n            .iter()\n            .chain(task.env.0.iter())\n            .map(|directive| (directive.clone(), task.config_source.clone()))\n            .collect()\n    }\n\n    /// Resolve env directives using EnvResults\n    async fn resolve_env_directives(\n        &self,\n        config: &Arc<Config>,\n        tera_ctx: &tera::Context,\n        env: &BTreeMap<String, String>,\n        directives: Vec<(EnvDirective, PathBuf)>,\n    ) -> Result<EnvResults> {\n        EnvResults::resolve(\n            config,\n            tera_ctx.clone(),\n            env,\n            directives,\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::Both,\n                warn_on_missing_required: false,\n            },\n        )\n        .await\n    }\n\n    /// Extract task env from EnvResults (only task-specific directives)\n    fn extract_task_env(&self, task_env_results: &EnvResults) -> Vec<(String, String)> {\n        task_env_results\n            .env\n            .iter()\n            .map(|(k, (v, _))| (k.clone(), v.clone()))\n            .collect()\n    }\n\n    /// Apply EnvResults to an environment map\n    /// Handles env vars, env_remove, and env_paths (PATH modifications)\n    fn apply_env_results(env: &mut BTreeMap<String, String>, results: &EnvResults) {\n        // Apply environment variables\n        for (k, (v, _)) in &results.env {\n            env.insert(k.clone(), v.clone());\n        }\n\n        // Remove explicitly unset variables\n        for key in &results.env_remove {\n            env.remove(key);\n        }\n\n        // Apply path additions\n        if !results.env_paths.is_empty() {\n            use crate::path_env::PathEnv;\n            let mut path_env = PathEnv::from_iter(env::split_paths(\n                &env.get(&*env::PATH_KEY).cloned().unwrap_or_default(),\n            ));\n            for path in &results.env_paths {\n                path_env.add(path.clone());\n            }\n            env.insert(env::PATH_KEY.to_string(), path_env.to_string());\n        }\n    }\n\n    /// Get access to the tool request set cache for collecting tools\n    pub fn tool_request_set_cache(\n        &self,\n    ) -> &RwLock<IndexMap<PathBuf, Arc<crate::toolset::ToolRequestSet>>> {\n        &self.tool_request_set_cache\n    }\n}\n\nimpl Default for TaskContextBuilder {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_task_context_builder_new() {\n        let builder = TaskContextBuilder::new();\n        assert!(builder.toolset_cache.read().unwrap().is_empty());\n        assert!(builder.tool_request_set_cache.read().unwrap().is_empty());\n        assert!(builder.env_resolution_cache.read().unwrap().is_empty());\n    }\n\n    #[test]\n    fn test_apply_env_results_basic() {\n        let mut env = BTreeMap::new();\n        env.insert(\"EXISTING\".to_string(), \"value\".to_string());\n\n        let mut results = EnvResults::default();\n        results.env.insert(\n            \"NEW_VAR\".to_string(),\n            (\"new_value\".to_string(), PathBuf::from(\"/test\")),\n        );\n\n        TaskContextBuilder::apply_env_results(&mut env, &results);\n\n        assert_eq!(env.get(\"EXISTING\"), Some(&\"value\".to_string()));\n        assert_eq!(env.get(\"NEW_VAR\"), Some(&\"new_value\".to_string()));\n    }\n\n    #[test]\n    fn test_apply_env_results_removes_vars() {\n        let mut env = BTreeMap::new();\n        env.insert(\"TO_REMOVE\".to_string(), \"value\".to_string());\n        env.insert(\"TO_KEEP\".to_string(), \"value\".to_string());\n\n        let mut results = EnvResults::default();\n        results.env_remove.insert(\"TO_REMOVE\".to_string());\n\n        TaskContextBuilder::apply_env_results(&mut env, &results);\n\n        assert_eq!(env.get(\"TO_REMOVE\"), None);\n        assert_eq!(env.get(\"TO_KEEP\"), Some(&\"value\".to_string()));\n    }\n\n    #[test]\n    fn test_apply_env_results_path_handling() {\n        let mut env = BTreeMap::new();\n        env.insert(env::PATH_KEY.to_string(), \"/existing/path\".to_string());\n\n        let mut results = EnvResults::default();\n        results\n            .env_paths\n            .push(PathBuf::from(\"/new/path\").to_path_buf());\n\n        TaskContextBuilder::apply_env_results(&mut env, &results);\n\n        let path = env.get(&*env::PATH_KEY).unwrap();\n        assert!(path.contains(\"/new/path\"));\n    }\n\n    #[test]\n    fn test_extract_task_env() {\n        let builder = TaskContextBuilder::new();\n        let mut results = EnvResults::default();\n        results.env.insert(\n            \"VAR1\".to_string(),\n            (\"value1\".to_string(), PathBuf::from(\"/test\")),\n        );\n        results.env.insert(\n            \"VAR2\".to_string(),\n            (\"value2\".to_string(), PathBuf::from(\"/test\")),\n        );\n\n        let task_env = builder.extract_task_env(&results);\n\n        assert_eq!(task_env.len(), 2);\n        assert!(task_env.contains(&(\"VAR1\".to_string(), \"value1\".to_string())));\n        assert!(task_env.contains(&(\"VAR2\".to_string(), \"value2\".to_string())));\n    }\n}\n"
  },
  {
    "path": "src/task/task_dep.rs",
    "content": "use indexmap::IndexMap;\nuse serde::de::{self, MapAccess, SeqAccess, Visitor};\nuse serde::ser::SerializeMap;\nuse serde::{Deserialize, Deserializer, Serialize};\nuse std::fmt;\nuse std::fmt::{Display, Formatter};\nuse std::str::FromStr;\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct TaskDep {\n    pub task: String,\n    pub args: Vec<String>,\n    pub env: IndexMap<String, String>,\n}\n\nimpl TaskDep {\n    pub fn render(\n        &mut self,\n        tera: &mut tera::Tera,\n        tera_ctx: &tera::Context,\n    ) -> crate::Result<&mut Self> {\n        self.task = tera.render_str(&self.task, tera_ctx)?;\n        for a in &mut self.args {\n            *a = tera.render_str(a, tera_ctx)?;\n        }\n        // Render env values through Tera\n        for v in self.env.values_mut() {\n            *v = tera.render_str(v, tera_ctx)?;\n        }\n        // Parse shell-style \"FOO=bar BAZ=qux taskname arg1 arg2\" if args/env not already set\n        if self.args.is_empty() && self.env.is_empty() {\n            let s = self.task.clone();\n            let parts: Vec<String> = shell_words::split(&s)\n                .unwrap_or_else(|_| s.split_whitespace().map(String::from).collect());\n\n            // Only parse env vars if there are multiple parts\n            // Single token like \"build=release\" should be treated as task name, not env var\n            if parts.len() > 1 {\n                let mut task_found = false;\n\n                for part in parts {\n                    if !task_found {\n                        // Check if this looks like KEY=value (env var)\n                        if let Some((key, value)) = part.split_once('=') {\n                            // Only treat as env var if key looks like a valid env var name\n                            if !key.is_empty()\n                                && key.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')\n                            {\n                                self.env.insert(key.to_string(), value.to_string());\n                                continue;\n                            }\n                        }\n                        // First non-env-var token is the task name\n                        self.task = part;\n                        task_found = true;\n                    } else {\n                        self.args.push(part);\n                    }\n                }\n\n                // Validate that a task name was found (not just env vars)\n                if !task_found {\n                    return Err(eyre::eyre!(\n                        \"invalid task dependency '{}': missing task name (only environment variables found)\",\n                        s\n                    ));\n                }\n            } else if let Some(task) = parts.into_iter().next() {\n                // Single token - use as task name directly (even if it contains '=')\n                self.task = task;\n            }\n        }\n        Ok(self)\n    }\n}\n\nimpl Display for TaskDep {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        for (k, v) in &self.env {\n            write!(f, \"{}={} \", k, v)?;\n        }\n        write!(f, \"{}\", self.task)?;\n        if !self.args.is_empty() {\n            write!(f, \" {}\", self.args.join(\" \"))?;\n        }\n        Ok(())\n    }\n}\n\nimpl From<String> for TaskDep {\n    fn from(s: String) -> Self {\n        s.parse().unwrap()\n    }\n}\n\nimpl FromStr for TaskDep {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self {\n            task: s.to_string(),\n            args: Default::default(),\n            env: Default::default(),\n        })\n    }\n}\n\nimpl<'de> Deserialize<'de> for TaskDep {\n    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {\n        struct TaskDepVisitor;\n\n        impl<'de> Visitor<'de> for TaskDepVisitor {\n            type Value = TaskDep;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a string, array, or object\")\n            }\n\n            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {\n                Ok(TaskDep {\n                    task: v.to_string(),\n                    args: Default::default(),\n                    env: Default::default(),\n                })\n            }\n\n            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {\n                let mut items: Vec<String> = Vec::new();\n                while let Some(item) = seq.next_element()? {\n                    items.push(item);\n                }\n                if items.is_empty() {\n                    return Err(de::Error::custom(\"Task name is required\"));\n                }\n                Ok(TaskDep {\n                    task: items[0].clone(),\n                    args: items[1..].to_vec(),\n                    env: Default::default(),\n                })\n            }\n\n            fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Self::Value, M::Error> {\n                let mut task: Option<String> = None;\n                let mut args: Vec<String> = Vec::new();\n                let mut env: IndexMap<String, String> = IndexMap::new();\n\n                while let Some(key) = map.next_key::<String>()? {\n                    match key.as_str() {\n                        \"task\" => task = Some(map.next_value()?),\n                        \"args\" => args = map.next_value()?,\n                        \"env\" => env = map.next_value()?,\n                        _ => {\n                            return Err(de::Error::unknown_field(&key, &[\"task\", \"args\", \"env\"]));\n                        }\n                    }\n                }\n\n                Ok(TaskDep {\n                    task: task.ok_or_else(|| de::Error::missing_field(\"task\"))?,\n                    args,\n                    env,\n                })\n            }\n        }\n\n        deserializer.deserialize_any(TaskDepVisitor)\n    }\n}\n\nimpl Serialize for TaskDep {\n    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {\n        if !self.env.is_empty() {\n            // Use object format when env is present\n            let mut map = serializer.serialize_map(None)?;\n            map.serialize_entry(\"task\", &self.task)?;\n            if !self.args.is_empty() {\n                map.serialize_entry(\"args\", &self.args)?;\n            }\n            map.serialize_entry(\"env\", &self.env)?;\n            map.end()\n        } else if self.args.is_empty() {\n            serializer.serialize_str(&self.task)\n        } else {\n            // TODO: it would be possible to track if the user specified a string and if so, continue that format\n            use serde::ser::SerializeSeq;\n            let mut seq = serializer.serialize_seq(Some(1 + self.args.len()))?;\n            seq.serialize_element(&self.task)?;\n            for arg in &self.args {\n                seq.serialize_element(arg)?;\n            }\n            seq.end()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_task_dep_from_str() {\n        let td: TaskDep = \"task\".parse().unwrap();\n        assert_eq!(td.task, \"task\");\n        assert!(td.args.is_empty());\n        assert!(td.env.is_empty());\n    }\n\n    #[test]\n    fn test_task_dep_display() {\n        let td = TaskDep {\n            task: \"task\".to_string(),\n            args: vec![\"arg1\".to_string(), \"arg2\".to_string()],\n            env: Default::default(),\n        };\n        assert_eq!(td.to_string(), \"task arg1 arg2\");\n\n        // With env vars\n        let mut env = IndexMap::new();\n        env.insert(\"FOO\".to_string(), \"bar\".to_string());\n        let td = TaskDep {\n            task: \"task\".to_string(),\n            args: vec![],\n            env,\n        };\n        assert_eq!(td.to_string(), \"FOO=bar task\");\n    }\n\n    #[test]\n    fn test_task_dep_deserialize_string() {\n        let td: TaskDep = serde_json::from_str(r#\"\"task\"\"#).unwrap();\n        assert_eq!(td.task, \"task\");\n        assert!(td.args.is_empty());\n        assert!(td.env.is_empty());\n        assert_eq!(&serde_json::to_string(&td).unwrap(), r#\"\"task\"\"#);\n    }\n\n    #[test]\n    fn test_task_dep_deserialize_array() {\n        let td: TaskDep = serde_json::from_str(r#\"[\"task\", \"arg1\", \"arg2\"]\"#).unwrap();\n        assert_eq!(td.task, \"task\");\n        assert_eq!(td.args, vec![\"arg1\", \"arg2\"]);\n        assert!(td.env.is_empty());\n        assert_eq!(\n            &serde_json::to_string(&td).unwrap(),\n            r#\"[\"task\",\"arg1\",\"arg2\"]\"#\n        );\n    }\n\n    #[test]\n    fn test_task_dep_deserialize_object() {\n        let td: TaskDep =\n            serde_json::from_str(r#\"{\"task\": \"mytask\", \"env\": {\"FOO\": \"bar\"}, \"args\": [\"arg1\"]}\"#)\n                .unwrap();\n        assert_eq!(td.task, \"mytask\");\n        assert_eq!(td.args, vec![\"arg1\"]);\n        assert_eq!(td.env.get(\"FOO\"), Some(&\"bar\".to_string()));\n    }\n\n    #[test]\n    fn test_task_dep_deserialize_object_env_only() {\n        let td: TaskDep =\n            serde_json::from_str(r#\"{\"task\": \"mytask\", \"env\": {\"FOO\": \"bar\", \"BAZ\": \"qux\"}}\"#)\n                .unwrap();\n        assert_eq!(td.task, \"mytask\");\n        assert!(td.args.is_empty());\n        assert_eq!(td.env.get(\"FOO\"), Some(&\"bar\".to_string()));\n        assert_eq!(td.env.get(\"BAZ\"), Some(&\"qux\".to_string()));\n    }\n\n    #[test]\n    fn test_task_dep_serialize_with_env() {\n        let mut env = IndexMap::new();\n        env.insert(\"FOO\".to_string(), \"bar\".to_string());\n        let td = TaskDep {\n            task: \"mytask\".to_string(),\n            args: vec![],\n            env,\n        };\n        let json = serde_json::to_string(&td).unwrap();\n        assert!(json.contains(r#\"\"task\":\"mytask\"\"#));\n        assert!(json.contains(r#\"\"env\"\"#));\n        assert!(json.contains(r#\"\"FOO\":\"bar\"\"#));\n    }\n\n    #[test]\n    fn test_task_dep_render_shell_style_env() {\n        let mut td: TaskDep = \"FOO=bar mytask arg1\".parse().unwrap();\n        let mut tera = tera::Tera::default();\n        let ctx = tera::Context::new();\n        td.render(&mut tera, &ctx).unwrap();\n\n        assert_eq!(td.task, \"mytask\");\n        assert_eq!(td.args, vec![\"arg1\"]);\n        assert_eq!(td.env.get(\"FOO\"), Some(&\"bar\".to_string()));\n    }\n\n    #[test]\n    fn test_task_dep_render_multiple_env() {\n        let mut td: TaskDep = \"FOO=bar BAZ=qux mytask\".parse().unwrap();\n        let mut tera = tera::Tera::default();\n        let ctx = tera::Context::new();\n        td.render(&mut tera, &ctx).unwrap();\n\n        assert_eq!(td.task, \"mytask\");\n        assert!(td.args.is_empty());\n        assert_eq!(td.env.get(\"FOO\"), Some(&\"bar\".to_string()));\n        assert_eq!(td.env.get(\"BAZ\"), Some(&\"qux\".to_string()));\n    }\n\n    #[test]\n    fn test_task_dep_render_no_env() {\n        let mut td: TaskDep = \"mytask arg1 arg2\".parse().unwrap();\n        let mut tera = tera::Tera::default();\n        let ctx = tera::Context::new();\n        td.render(&mut tera, &ctx).unwrap();\n\n        assert_eq!(td.task, \"mytask\");\n        assert_eq!(td.args, vec![\"arg1\", \"arg2\"]);\n        assert!(td.env.is_empty());\n    }\n\n    #[test]\n    fn test_task_dep_single_token_with_equals() {\n        // Single token like \"build=release\" should be treated as task name, not env var\n        let mut td: TaskDep = \"build=release\".parse().unwrap();\n        let mut tera = tera::Tera::default();\n        let ctx = tera::Context::new();\n        td.render(&mut tera, &ctx).unwrap();\n\n        assert_eq!(td.task, \"build=release\");\n        assert!(td.args.is_empty());\n        assert!(td.env.is_empty());\n    }\n\n    #[test]\n    fn test_task_dep_only_env_vars_error() {\n        // Only env vars without task name should error\n        let mut td: TaskDep = \"FOO=bar BAZ=qux\".parse().unwrap();\n        let mut tera = tera::Tera::default();\n        let ctx = tera::Context::new();\n        let result = td.render(&mut tera, &ctx);\n\n        assert!(result.is_err());\n        let err = result.unwrap_err().to_string();\n        assert!(err.contains(\"missing task name\"));\n    }\n}\n"
  },
  {
    "path": "src/task/task_executor.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::cmd::CmdLineRunner;\nuse crate::config::{Config, Settings, env_directive::EnvDirective};\nuse crate::duration;\nuse crate::file::{display_path, is_executable};\nuse crate::task::TaskKey;\nuse crate::task::task_context_builder::TaskContextBuilder;\nuse crate::task::task_list::split_task_spec;\nuse crate::task::task_output::{TaskOutput, trunc};\nuse crate::task::task_output_handler::OutputHandler;\nuse crate::task::task_source_checker::{save_checksum, sources_are_fresh, task_cwd};\nuse crate::task::{Deps, FailedTasks, GetMatchingExt, Task};\nuse crate::toolset::env_cache::CachedEnv;\nuse crate::ui::{style, time};\nuse duct::IntoExecutablePath;\nuse eyre::{Report, Result, ensure, eyre};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\n#[cfg(unix)]\nuse nix::errno::Errno;\nuse std::collections::{BTreeMap, HashSet};\nuse std::iter::once;\nuse std::ops::Deref;\nuse std::path::{Path, PathBuf};\nuse std::process::Stdio;\nuse std::sync::{Arc, LazyLock, Mutex as StdMutex};\nuse std::time::{Duration, SystemTime};\nuse tokio::sync::Mutex;\nuse tokio::sync::RwLock;\nuse tokio::sync::{mpsc, oneshot};\nuse xx::file;\n\n/// Global lock for interactive task exclusivity.\n/// Interactive tasks acquire a write lock (exclusive), non-interactive tasks acquire a read lock (shared).\nstatic TASK_RUNTIME_LOCK: LazyLock<RwLock<()>> = LazyLock::new(|| RwLock::new(()));\n\n#[allow(dead_code)] // Guards are held for their Drop impl, not read\nenum RuntimeLockGuard<'a> {\n    Read(tokio::sync::RwLockReadGuard<'a, ()>),\n    Write(tokio::sync::RwLockWriteGuard<'a, ()>),\n}\n\nasync fn acquire_runtime_lock(interactive: bool) -> RuntimeLockGuard<'static> {\n    if interactive {\n        RuntimeLockGuard::Write(TASK_RUNTIME_LOCK.write().await)\n    } else {\n        RuntimeLockGuard::Read(TASK_RUNTIME_LOCK.read().await)\n    }\n}\n\n/// Configuration for TaskExecutor\npub struct TaskExecutorConfig {\n    pub force: bool,\n    pub cd: Option<PathBuf>,\n    pub shell: Option<String>,\n    pub tool: Vec<ToolArg>,\n    pub timings: bool,\n    pub continue_on_error: bool,\n    pub dry_run: bool,\n    pub skip_deps: bool,\n}\n\n/// Executes tasks with proper context, environment, and output handling\npub struct TaskExecutor {\n    pub context_builder: TaskContextBuilder,\n    pub output_handler: OutputHandler,\n    pub failed_tasks: FailedTasks,\n\n    // CLI flags\n    pub force: bool,\n    pub cd: Option<PathBuf>,\n    pub shell: Option<String>,\n    pub tool: Vec<ToolArg>,\n    pub timings: bool,\n    pub continue_on_error: bool,\n    pub dry_run: bool,\n    pub skip_deps: bool,\n}\n\nimpl TaskExecutor {\n    pub fn new(\n        context_builder: TaskContextBuilder,\n        output_handler: OutputHandler,\n        config: TaskExecutorConfig,\n    ) -> Self {\n        Self {\n            context_builder,\n            output_handler,\n            failed_tasks: Arc::new(StdMutex::new(Vec::new())),\n            force: config.force,\n            cd: config.cd,\n            shell: config.shell,\n            tool: config.tool,\n            timings: config.timings,\n            continue_on_error: config.continue_on_error,\n            dry_run: config.dry_run,\n            skip_deps: config.skip_deps,\n        }\n    }\n\n    pub fn is_stopping(&self) -> bool {\n        !self.failed_tasks.lock().unwrap().is_empty()\n    }\n\n    pub fn add_failed_task(&self, task: Task, status: Option<i32>) {\n        let mut failed = self.failed_tasks.lock().unwrap();\n        failed.push((task, status.or(Some(1))));\n    }\n\n    fn eprint(&self, task: &Task, prefix: &str, line: &str) {\n        self.output_handler.eprint(task, prefix, line);\n    }\n\n    fn output(&self, task: Option<&Task>) -> crate::task::task_output::TaskOutput {\n        self.output_handler.output(task)\n    }\n\n    fn quiet(&self, task: Option<&Task>) -> bool {\n        self.output_handler.quiet(task)\n    }\n\n    fn raw(&self, task: Option<&Task>) -> bool {\n        self.output_handler.raw(task)\n    }\n\n    pub fn task_timings(&self) -> bool {\n        let output_mode = self.output_handler.output(None);\n        self.timings\n            || Settings::get().task.timings.unwrap_or(\n                output_mode == TaskOutput::Prefix\n                    || output_mode == TaskOutput::Timed\n                    || output_mode == TaskOutput::KeepOrder,\n            )\n    }\n\n    pub async fn run_task_sched(\n        &self,\n        task: &Task,\n        config: &Arc<Config>,\n        sched_tx: Arc<mpsc::UnboundedSender<(Task, Arc<Mutex<Deps>>)>>,\n        completed_tasks: HashSet<TaskKey>,\n    ) -> Result<()> {\n        let prefix = task.estyled_prefix();\n        let total_start = std::time::Instant::now();\n        if Settings::get().task.skip.contains(&task.name) {\n            if !self.quiet(Some(task)) {\n                self.eprint(task, &prefix, \"skipping task\");\n            }\n            return Ok(());\n        }\n        if !self.force && sources_are_fresh(task, config).await? {\n            if !self.quiet(Some(task)) {\n                self.eprint(task, &prefix, \"sources up-to-date, skipping\");\n            }\n            return Ok(());\n        }\n\n        let mut tools = self.tool.clone();\n        for (k, v) in &task.tools {\n            tools.push(format!(\"{k}@{v}\").parse()?);\n        }\n        let ts_build_start = std::time::Instant::now();\n\n        // Check if we need special handling for monorepo tasks with config file context\n        // Remote tasks (from git::/http:/https: URLs) should NOT use config file context\n        // because they need tools from the full config hierarchy, not just the local config\n        let task_cf = if task.is_remote() {\n            None\n        } else {\n            task.cf(config)\n        };\n\n        // Build toolset - either from task's config file or standard way\n        let ts = self\n            .context_builder\n            .build_toolset_for_task(config, task, task_cf, &tools)\n            .await?;\n\n        trace!(\n            \"task {} ToolsetBuilder::build took {}ms\",\n            task.name,\n            ts_build_start.elapsed().as_millis()\n        );\n        let env_render_start = std::time::Instant::now();\n\n        // Build environment - either from task's config file context or standard way\n        // extra_vars contains resolved vars from the task's config hierarchy (for monorepo tasks)\n        let (mut env, task_env, extra_vars) = if let Some(task_cf) = task_cf {\n            self.context_builder\n                .resolve_task_env_with_config(config, task, task_cf, &ts)\n                .await?\n        } else {\n            // Fallback to standard behavior\n            let (env, task_env) = task.render_env(config, &ts).await?;\n            (env, task_env, None)\n        };\n\n        trace!(\n            \"task {} render_env took {}ms\",\n            task.name,\n            env_render_start.elapsed().as_millis()\n        );\n        if !self.timings {\n            env.insert(\"MISE_TASK_TIMINGS\".to_string(), \"0\".to_string());\n        }\n        // Propagate MISE_ENV to child tasks so -E flag works for nested mise invocations\n        if !crate::env::MISE_ENV.is_empty() {\n            env.insert(\"MISE_ENV\".to_string(), crate::env::MISE_ENV.join(\",\"));\n        }\n        if let Some(cwd) = &*crate::dirs::CWD {\n            env.insert(\"MISE_ORIGINAL_CWD\".into(), cwd.display().to_string());\n        }\n        if let Some(root) = config.project_root.clone().or(task.config_root.clone()) {\n            env.insert(\"MISE_PROJECT_ROOT\".into(), root.display().to_string());\n        }\n        env.insert(\"MISE_TASK_NAME\".into(), task.name.clone());\n        let task_file = task\n            .file_path(config)\n            .await?\n            .unwrap_or(task.config_source.clone());\n        env.insert(\"MISE_TASK_FILE\".into(), task_file.display().to_string());\n        if let Some(dir) = task_file.parent() {\n            env.insert(\"MISE_TASK_DIR\".into(), dir.display().to_string());\n        }\n        if let Some(config_root) = &task.config_root {\n            env.insert(\"MISE_CONFIG_ROOT\".into(), config_root.display().to_string());\n        }\n\n        // Ensure cache key exists for task subprocesses for nested mise invocations\n        // This matches exec.rs behavior - enables caching for subprocesses\n        if Settings::get().env_cache {\n            let key = CachedEnv::ensure_encryption_key();\n            env.insert(\"__MISE_ENV_CACHE_KEY\".into(), key);\n        }\n\n        let timer = std::time::Instant::now();\n\n        if let Some(file) = task.file_path(config).await? {\n            let exec_start = std::time::Instant::now();\n            self.exec_file(config, &file, task, &env, &prefix, extra_vars)\n                .await?;\n            trace!(\n                \"task {} exec_file took {}ms (total {}ms)\",\n                task.name,\n                exec_start.elapsed().as_millis(),\n                total_start.elapsed().as_millis()\n            );\n        } else {\n            let rendered_run_scripts = task\n                .render_run_scripts_with_args(\n                    config,\n                    self.cd.clone(),\n                    &task.args,\n                    &env,\n                    extra_vars.clone(),\n                )\n                .await?;\n\n            let get_args = || {\n                [String::new()]\n                    .iter()\n                    .chain(task.args.iter())\n                    .cloned()\n                    .collect()\n            };\n            self.parse_usage_spec_and_init_env(config, task, &mut env, get_args, extra_vars)\n                .await?;\n\n            // For interactive tasks, acquire the lock before confirmation so the\n            // prompt gets exclusive terminal access (consistent with exec_file path).\n            let confirm_guard = if task.interactive {\n                Some(acquire_runtime_lock(task.interactive).await)\n            } else {\n                None\n            };\n\n            // Check confirmation after usage args are parsed\n            self.check_confirmation(config, task, &env).await?;\n\n            let exec_start = std::time::Instant::now();\n            self.exec_task_run_entries(\n                config,\n                task,\n                (&env, &task_env),\n                &prefix,\n                rendered_run_scripts,\n                sched_tx,\n                confirm_guard,\n                &completed_tasks,\n            )\n            .await?;\n            trace!(\n                \"task {} exec_task_run_entries took {}ms (total {}ms)\",\n                task.name,\n                exec_start.elapsed().as_millis(),\n                total_start.elapsed().as_millis()\n            );\n        }\n\n        if self.task_timings()\n            && (task.file.as_ref().is_some() || !task.run_script_strings().is_empty())\n        {\n            self.eprint(\n                task,\n                &prefix,\n                &format!(\"Finished in {}\", time::format_duration(timer.elapsed())),\n            );\n        }\n\n        save_checksum(task, config).await?;\n\n        Ok(())\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    async fn exec_task_run_entries(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        full_env: (&BTreeMap<String, String>, &[(String, String)]),\n        prefix: &str,\n        rendered_scripts: Vec<(String, Vec<String>)>,\n        sched_tx: Arc<mpsc::UnboundedSender<(Task, Arc<Mutex<Deps>>)>>,\n        existing_guard: Option<RuntimeLockGuard<'static>>,\n        completed_tasks: &HashSet<TaskKey>,\n    ) -> Result<()> {\n        let (env, task_env) = full_env;\n        use crate::task::RunEntry;\n        let mut script_iter = rendered_scripts.into_iter();\n        // Use an existing guard (e.g. from confirmation) or acquire a new one.\n        // The lock is held across consecutive script entries for exclusivity\n        // and temporarily dropped around inject_and_wait to avoid deadlocking.\n        let mut guard = match existing_guard {\n            Some(g) => Some(g),\n            None => Some(acquire_runtime_lock(task.interactive).await),\n        };\n        for entry in task.run() {\n            match entry {\n                RunEntry::Script(_) => {\n                    if let Some((script, args)) = script_iter.next() {\n                        if guard.is_none() {\n                            guard = Some(acquire_runtime_lock(task.interactive).await);\n                        }\n                        self.exec_script(&script, &args, task, env, prefix).await?;\n                    }\n                }\n                RunEntry::SingleTask { task: spec } => {\n                    let resolved_spec = crate::task::resolve_task_pattern(spec, Some(task));\n                    guard = None; // drop lock before waiting on sub-tasks\n                    self.inject_and_wait(\n                        config,\n                        &[resolved_spec],\n                        task_env,\n                        sched_tx.clone(),\n                        completed_tasks,\n                    )\n                    .await?;\n                }\n                RunEntry::TaskGroup { tasks } => {\n                    let resolved_tasks: Vec<String> = tasks\n                        .iter()\n                        .map(|t| crate::task::resolve_task_pattern(t, Some(task)))\n                        .collect();\n                    guard = None; // drop lock before waiting on sub-tasks\n                    self.inject_and_wait(\n                        config,\n                        &resolved_tasks,\n                        task_env,\n                        sched_tx.clone(),\n                        completed_tasks,\n                    )\n                    .await?;\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn inject_and_wait(\n        &self,\n        config: &Arc<Config>,\n        specs: &[String],\n        task_env: &[(String, String)],\n        sched_tx: Arc<mpsc::UnboundedSender<(Task, Arc<Mutex<Deps>>)>>,\n        completed_tasks: &HashSet<TaskKey>,\n    ) -> Result<()> {\n        use crate::task::TaskLoadContext;\n        trace!(\"inject start: {}\", specs.join(\", \"));\n        // Build tasks list from specs\n        // Create a TaskLoadContext from the specs to ensure project tasks are loaded\n        let ctx = TaskLoadContext::from_patterns(specs.iter().map(|s| {\n            let (name, _) = split_task_spec(s);\n            name\n        }));\n        let tasks = config.tasks_with_context(Some(&ctx)).await?;\n        let tasks_map: BTreeMap<String, Task> = tasks\n            .iter()\n            .flat_map(|(_, t)| {\n                t.aliases\n                    .iter()\n                    .map(|a| (a.to_string(), t.clone()))\n                    .chain(once((t.name.clone(), t.clone())))\n                    .collect::<Vec<_>>()\n            })\n            .collect();\n        let mut to_run: Vec<Task> = vec![];\n        for spec in specs {\n            let (name, args) = split_task_spec(spec);\n            let matches = tasks_map.get_matching(name)?;\n            ensure!(!matches.is_empty(), \"task not found: {}\", name);\n            for t in matches {\n                let mut t = (*t).clone();\n                t.args = args.clone();\n                if self.skip_deps {\n                    t.depends.clear();\n                    t.depends_post.clear();\n                    t.wait_for.clear();\n                }\n                to_run.push(t);\n            }\n        }\n        let sub_deps = Deps::new_pruned(config, to_run, completed_tasks).await?;\n        let sub_deps = Arc::new(Mutex::new(sub_deps));\n\n        // Pump subgraph into scheduler and signal completion via oneshot when done\n        let (done_tx, mut done_rx) = oneshot::channel::<()>();\n        let task_env_directives: Vec<EnvDirective> =\n            task_env.iter().cloned().map(Into::into).collect();\n        {\n            let sub_deps_clone = sub_deps.clone();\n            let sched_tx = sched_tx.clone();\n            // forward initial leaves synchronously\n            {\n                let mut rx = sub_deps_clone.lock().await.subscribe();\n                let mut any = false;\n                loop {\n                    match rx.try_recv() {\n                        Ok(Some(task)) => {\n                            any = true;\n                            let task = task.derive_env(&task_env_directives);\n                            trace!(\"inject initial leaf: {} {}\", task.name, task.args.join(\" \"));\n                            let _ = sched_tx.send((task, sub_deps_clone.clone()));\n                        }\n                        Ok(None) => {\n                            trace!(\"inject initial done\");\n                            break;\n                        }\n                        Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {\n                            break;\n                        }\n                        Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => {\n                            break;\n                        }\n                    }\n                }\n                if !any {\n                    trace!(\"inject had no initial leaves\");\n                }\n            }\n            // then forward remaining leaves asynchronously\n            tokio::spawn(async move {\n                let mut rx = sub_deps_clone.lock().await.subscribe();\n                while let Some(msg) = rx.recv().await {\n                    match msg {\n                        Some(task) => {\n                            trace!(\n                                \"inject leaf scheduled: {} {}\",\n                                task.name,\n                                task.args.join(\" \")\n                            );\n                            let task = task.derive_env(&task_env_directives);\n                            let _ = sched_tx.send((task, sub_deps_clone.clone()));\n                        }\n                        None => {\n                            let _ = done_tx.send(());\n                            trace!(\"inject complete\");\n                            break;\n                        }\n                    }\n                }\n            });\n        }\n\n        // Wait for completion with a check for early stopping\n        loop {\n            // Check if we should stop early due to failure\n            if self.is_stopping() && !self.continue_on_error {\n                trace!(\"inject_and_wait: stopping early due to failure\");\n                // Clean up the dependency graph to ensure completion\n                let mut deps = sub_deps.lock().await;\n                let tasks_to_remove: Vec<Task> = deps.all().cloned().collect();\n                for task in tasks_to_remove {\n                    deps.remove(&task);\n                }\n                drop(deps);\n                // Give a short time for the spawned task to finish cleanly\n                let _ = tokio::time::timeout(Duration::from_millis(100), done_rx).await;\n                return Err(eyre!(\"task sequence aborted due to failure\"));\n            }\n\n            // Try to receive the done signal with a short timeout\n            match tokio::time::timeout(Duration::from_millis(100), &mut done_rx).await {\n                Ok(Ok(())) => {\n                    trace!(\"inject_and_wait: received done signal\");\n                    break;\n                }\n                Ok(Err(e)) => {\n                    return Err(eyre!(e));\n                }\n                Err(_) => {\n                    // Timeout, check again if we should stop\n                    continue;\n                }\n            }\n        }\n\n        // Final check if we failed during the execution\n        if self.is_stopping() && !self.continue_on_error {\n            return Err(eyre!(\"task sequence aborted due to failure\"));\n        }\n\n        Ok(())\n    }\n\n    async fn exec_script(\n        &self,\n        script: &str,\n        args: &[String],\n        task: &Task,\n        env: &BTreeMap<String, String>,\n        prefix: &str,\n    ) -> Result<()> {\n        let config = Config::get().await?;\n        let script = script.trim_start();\n        let cmd = format!(\"$ {script} {args}\", args = args.join(\" \")).to_string();\n        if !self.quiet(Some(task)) {\n            let msg = style::ebold(trunc(prefix, config.redact(&cmd).trim()))\n                .bright()\n                .to_string();\n            self.eprint(task, prefix, &msg)\n        }\n\n        if script.starts_with(\"#!\") {\n            let dir = tempfile::tempdir()?;\n            let file = dir.path().join(\"script\");\n            tokio::fs::write(&file, script.as_bytes()).await?;\n            file::make_executable(&file)?;\n            self.exec_with_text_file_busy_retry(&file, args, task, env, prefix)\n                .await\n        } else {\n            let (program, args) = self.get_cmd_program_and_args(script, task, args)?;\n            self.exec_program(&program, &args, task, env, prefix).await\n        }\n    }\n\n    fn get_file_program_and_args(\n        &self,\n        file: &Path,\n        task: &Task,\n        args: &[String],\n    ) -> Result<(String, Vec<String>)> {\n        let display = file.display().to_string();\n        if !Settings::get().use_file_shell_for_executable_tasks && can_execute_directly(file) {\n            return Ok((display, args.to_vec()));\n        }\n        let shell = task\n            .shell()\n            .or_else(|| shell_from_shebang(file))\n            .or_else(|| shell_from_extension(file))\n            .unwrap_or(Settings::get().default_file_shell()?);\n        trace!(\"using shell: {}\", shell.join(\" \"));\n        let mut full_args = shell.clone();\n        full_args.push(display);\n        if !args.is_empty() {\n            full_args.extend(args.iter().cloned());\n        }\n        Ok((shell[0].clone(), full_args[1..].to_vec()))\n    }\n\n    fn get_cmd_program_and_args(\n        &self,\n        script: &str,\n        task: &Task,\n        args: &[String],\n    ) -> Result<(String, Vec<String>)> {\n        let shell = task.shell().unwrap_or(self.clone_default_inline_shell()?);\n        trace!(\"using shell: {}\", shell.join(\" \"));\n        let mut full_args = shell.clone();\n\n        #[cfg(windows)]\n        {\n            full_args.push(script.to_string());\n            full_args.extend(args.iter().cloned());\n        }\n\n        #[cfg(unix)]\n        {\n            let mut script = script.to_string();\n            if !args.is_empty() {\n                script = format!(\"{script} {}\", shell_words::join(args));\n            }\n            full_args.push(script);\n        }\n        Ok((full_args[0].clone(), full_args[1..].to_vec()))\n    }\n\n    fn clone_default_inline_shell(&self) -> Result<Vec<String>> {\n        if let Some(shell) = &self.shell {\n            Ok(shell_words::split(shell)?)\n        } else {\n            Settings::get().default_inline_shell()\n        }\n    }\n\n    async fn exec_file(\n        &self,\n        config: &Arc<Config>,\n        file: &Path,\n        task: &Task,\n        env: &BTreeMap<String, String>,\n        prefix: &str,\n        extra_vars: Option<IndexMap<String, String>>,\n    ) -> Result<()> {\n        let mut env = env.clone();\n        let command = file.to_string_lossy().to_string();\n        let args = task.args.iter().cloned().collect_vec();\n        let get_args = || once(command.clone()).chain(args.clone()).collect_vec();\n        self.parse_usage_spec_and_init_env(config, task, &mut env, get_args, extra_vars)\n            .await?;\n\n        // For interactive tasks, acquire the lock before confirmation so the\n        // prompt gets exclusive terminal access. For non-interactive tasks,\n        // acquire after confirmation to avoid blocking the task graph.\n        let guard = if task.interactive {\n            Some(acquire_runtime_lock(task.interactive).await)\n        } else {\n            None\n        };\n\n        // Check confirmation after usage args are parsed\n        self.check_confirmation(config, task, &env).await?;\n\n        if !self.quiet(Some(task)) {\n            let cmd = format!(\"{} {}\", display_path(file), args.join(\" \"))\n                .trim()\n                .to_string();\n            let cmd = style::ebold(format!(\"$ {cmd}\")).bright().to_string();\n            let cmd = trunc(prefix, config.redact(&cmd).trim());\n            self.eprint(task, prefix, &cmd);\n        }\n\n        let _guard = if guard.is_some() {\n            guard\n        } else {\n            Some(acquire_runtime_lock(task.interactive).await)\n        };\n        self.exec(file, &args, task, &env, prefix).await\n    }\n\n    async fn exec(\n        &self,\n        file: &Path,\n        args: &[String],\n        task: &Task,\n        env: &BTreeMap<String, String>,\n        prefix: &str,\n    ) -> Result<()> {\n        let (program, args) = self.get_file_program_and_args(file, task, args)?;\n        self.exec_program(&program, &args, task, env, prefix).await\n    }\n\n    async fn exec_with_text_file_busy_retry(\n        &self,\n        file: &Path,\n        args: &[String],\n        task: &Task,\n        env: &BTreeMap<String, String>,\n        prefix: &str,\n    ) -> Result<()> {\n        const ETXTBUSY_RETRIES: usize = 3;\n        const ETXTBUSY_SLEEP_MS: u64 = 50;\n\n        let mut attempt = 0;\n        loop {\n            match self.exec(file, args, task, env, prefix).await {\n                Ok(()) => break Ok(()),\n                Err(err) if Self::is_text_file_busy(&err) && attempt < ETXTBUSY_RETRIES => {\n                    attempt += 1;\n                    trace!(\n                        \"retrying execution of {} after ETXTBUSY (attempt {}/{})\",\n                        display_path(file),\n                        attempt,\n                        ETXTBUSY_RETRIES\n                    );\n                    // Exponential backoff: 50ms, 100ms, 200ms\n                    let sleep_ms = ETXTBUSY_SLEEP_MS * (1 << (attempt - 1));\n                    tokio::time::sleep(Duration::from_millis(sleep_ms)).await;\n                }\n                Err(err) => break Err(err),\n            }\n        }\n    }\n\n    async fn exec_program(\n        &self,\n        program: &str,\n        args: &[String],\n        task: &Task,\n        env: &BTreeMap<String, String>,\n        prefix: &str,\n    ) -> Result<()> {\n        let config = Config::get().await?;\n        let program = program.to_executable();\n        let redactions = config.redactions();\n        let raw = self.raw(Some(task));\n        let mut cmd = CmdLineRunner::new(program.clone())\n            .args(args)\n            .envs(env)\n            .redact(redactions.deref().clone())\n            .raw(raw);\n        if raw && !redactions.is_empty() {\n            if task.interactive && !task.raw && !Settings::get().raw {\n                hint!(\n                    \"interactive_redactions\",\n                    \"interactive tasks bypass redactions—secrets may appear in terminal output\",\n                    \"\"\n                );\n            } else {\n                hint!(\n                    \"raw_redactions\",\n                    \"--raw will prevent mise from being able to use redactions\",\n                    \"\"\n                );\n            }\n        }\n        let output = self.output(Some(task));\n        cmd.with_pass_signals();\n        match output {\n            TaskOutput::Prefix => {\n                if !task.silent.suppresses_stdout() {\n                    cmd = cmd.with_on_stdout(|line| {\n                        if console::colors_enabled() {\n                            prefix_println!(prefix, \"{line}\\x1b[0m\");\n                        } else {\n                            prefix_println!(prefix, \"{line}\");\n                        }\n                    });\n                } else {\n                    cmd = cmd.stdout(Stdio::null());\n                }\n                if !task.silent.suppresses_stderr() {\n                    cmd = cmd.with_on_stderr(|line| {\n                        if console::colors_enabled() {\n                            self.eprint(task, prefix, &format!(\"{line}\\x1b[0m\"));\n                        } else {\n                            self.eprint(task, prefix, &line);\n                        }\n                    });\n                } else {\n                    cmd = cmd.stderr(Stdio::null());\n                }\n            }\n            TaskOutput::KeepOrder => {\n                if !task.silent.suppresses_stdout() {\n                    let state = self.output_handler.keep_order_state.clone();\n                    let task_clone = task.clone();\n                    let prefix_str = prefix.to_string();\n                    cmd = cmd.with_on_stdout(move |line| {\n                        state\n                            .lock()\n                            .unwrap()\n                            .on_stdout(&task_clone, prefix_str.clone(), line);\n                    });\n                } else {\n                    cmd = cmd.stdout(Stdio::null());\n                }\n                if !task.silent.suppresses_stderr() {\n                    let state = self.output_handler.keep_order_state.clone();\n                    let task_clone = task.clone();\n                    let prefix_str = prefix.to_string();\n                    cmd = cmd.with_on_stderr(move |line| {\n                        state\n                            .lock()\n                            .unwrap()\n                            .on_stderr(&task_clone, prefix_str.clone(), line);\n                    });\n                } else {\n                    cmd = cmd.stderr(Stdio::null());\n                }\n            }\n            TaskOutput::Replacing => {\n                // Replacing mode shows a progress indicator unless both streams are suppressed\n                if task.silent.suppresses_stdout() {\n                    cmd = cmd.stdout(Stdio::null());\n                }\n                if task.silent.suppresses_stderr() {\n                    cmd = cmd.stderr(Stdio::null());\n                }\n                // Show progress indicator except when both streams are fully suppressed\n                if !task.silent.suppresses_both() {\n                    let pr = self.output_handler.task_prs.get(task).unwrap().clone();\n                    cmd = cmd.with_pr_arc(pr);\n                }\n            }\n            TaskOutput::Timed => {\n                if !task.silent.suppresses_stdout() {\n                    let timed_outputs = self.output_handler.timed_outputs.clone();\n                    cmd = cmd.with_on_stdout(move |line| {\n                        timed_outputs\n                            .lock()\n                            .unwrap()\n                            .insert(prefix.to_string(), (SystemTime::now(), line));\n                    });\n                } else {\n                    cmd = cmd.stdout(Stdio::null());\n                }\n                if !task.silent.suppresses_stderr() {\n                    cmd = cmd.with_on_stderr(|line| {\n                        if console::colors_enabled() {\n                            self.eprint(task, prefix, &format!(\"{line}\\x1b[0m\"));\n                        } else {\n                            self.eprint(task, prefix, &line);\n                        }\n                    });\n                } else {\n                    cmd = cmd.stderr(Stdio::null());\n                }\n            }\n            TaskOutput::Silent => {\n                cmd = cmd.stdout(Stdio::null()).stderr(Stdio::null());\n            }\n            TaskOutput::Quiet | TaskOutput::Interleave => {\n                if raw || redactions.is_empty() {\n                    cmd = cmd.stdin(Stdio::inherit());\n                    if !task.silent.suppresses_stdout() {\n                        cmd = cmd.stdout(Stdio::inherit());\n                    } else {\n                        cmd = cmd.stdout(Stdio::null());\n                    }\n                    if !task.silent.suppresses_stderr() {\n                        cmd = cmd.stderr(Stdio::inherit());\n                    } else {\n                        cmd = cmd.stderr(Stdio::null());\n                    }\n                }\n            }\n        }\n        let dir = task_cwd(task, &config).await?;\n        if !dir.exists() {\n            self.eprint(\n                task,\n                prefix,\n                &format!(\n                    \"{} task directory does not exist: {}\",\n                    style::eyellow(\"WARN\"),\n                    display_path(&dir)\n                ),\n            );\n        }\n        cmd = cmd.current_dir(dir);\n        if self.dry_run {\n            return Ok(());\n        }\n        let effective_timeout =\n            task.timeout\n                .as_ref()\n                .and_then(|s| match duration::parse_duration(s) {\n                    Ok(d) => Some(d),\n                    Err(e) => {\n                        warn!(\"invalid timeout {:?} for task {}: {e}\", s, task.name);\n                        None\n                    }\n                });\n        if let Some(timeout) = effective_timeout {\n            cmd = cmd.with_timeout(timeout);\n        }\n        // cmd.execute() is blocking (calls cp.wait()), so use block_in_place\n        // to avoid starving the tokio runtime while holding the TASK_RUNTIME_LOCK guard.\n        tokio::task::block_in_place(|| cmd.execute())?;\n        trace!(\"{prefix} exited successfully\");\n        Ok(())\n    }\n\n    #[cfg(unix)]\n    fn is_text_file_busy(err: &Report) -> bool {\n        err.chain().any(|cause| {\n            if let Some(io_err) = cause.downcast_ref::<std::io::Error>()\n                && let Some(code) = io_err.raw_os_error()\n            {\n                // ETXTBUSY (Text file busy) on Unix\n                return code == Errno::ETXTBSY as i32;\n            }\n            false\n        })\n    }\n\n    #[cfg(not(unix))]\n    #[allow(unused_variables)]\n    fn is_text_file_busy(err: &Report) -> bool {\n        false\n    }\n\n    async fn check_confirmation(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        env: &BTreeMap<String, String>,\n    ) -> Result<()> {\n        if let Some(confirm_template) = &task.confirm\n            && !Settings::get().yes\n        {\n            let config_root = task.config_root.clone().unwrap_or_default();\n            let mut tera = crate::tera::get_tera(Some(&config_root));\n            let mut tera_ctx = task.tera_ctx(config).await?;\n\n            // Add usage values from parsed environment\n            let mut usage_ctx = std::collections::HashMap::new();\n            for (key, value) in env {\n                if let Some(usage_key) = key.strip_prefix(\"usage_\") {\n                    usage_ctx.insert(usage_key.to_string(), tera::Value::String(value.clone()));\n                }\n            }\n            tera_ctx.insert(\"usage\", &usage_ctx);\n\n            let message = tera.render_str(confirm_template, &tera_ctx)?;\n            if !crate::ui::confirm(&message).unwrap_or(false) {\n                return Err(eyre!(\"aborted by user\"));\n            }\n        }\n        Ok(())\n    }\n\n    async fn parse_usage_spec_and_init_env(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        env: &mut BTreeMap<String, String>,\n        get_args: impl Fn() -> Vec<String>,\n        extra_vars: Option<IndexMap<String, String>>,\n    ) -> Result<()> {\n        let (spec, _) = task\n            .parse_usage_spec_with_vars(config, self.cd.clone(), env, extra_vars)\n            .await?;\n        if !spec.cmd.args.is_empty() || !spec.cmd.flags.is_empty() {\n            let args: Vec<String> = get_args();\n            trace!(\"Parsing usage spec for {:?}\", args);\n            // Pass env vars to Parser so it can resolve env= defaults in usage specs\n            let env_map: std::collections::HashMap<String, String> =\n                env.iter().map(|(k, v)| (k.clone(), v.clone())).collect();\n            let po = usage::Parser::new(&spec)\n                .with_env(env_map)\n                .parse(&args)\n                .map_err(|err| eyre!(err))?;\n            for (k, v) in po.as_env() {\n                trace!(\"Adding key {} value {} in env\", k, v);\n                env.insert(k, v);\n            }\n        } else {\n            trace!(\"Usage spec has no args or flags\");\n        }\n\n        Ok(())\n    }\n}\n\n/// Check if a file can be executed directly by the OS without a shell wrapper.\n/// On Unix, this checks the executable permission bit.\n/// On Windows, this checks for a known executable extension (.bat, .ps1, etc.)\n/// — shebang-only files need to be run through a shell.\nfn can_execute_directly(path: &Path) -> bool {\n    #[cfg(windows)]\n    {\n        // .ps1 files need pwsh -File, they can't be executed directly\n        if path.extension().is_some_and(|e| e == \"ps1\") {\n            return false;\n        }\n        crate::file::has_known_executable_extension(path)\n    }\n    #[cfg(not(windows))]\n    {\n        is_executable(path)\n    }\n}\n\n/// Determine the shell from a file's extension.\n/// e.g. `.ps1` → `[\"pwsh\", \"-File\"]`\nfn shell_from_extension(path: &Path) -> Option<Vec<String>> {\n    match path.extension()?.to_str()? {\n        \"ps1\" => Some(vec![\"pwsh\".to_string(), \"-File\".to_string()]),\n        _ => None,\n    }\n}\n\n/// Read the shebang from a file and parse it into a shell command.\n/// e.g. `#!/usr/bin/env bash` → `[\"bash\"]`\n/// e.g. `#!/bin/bash` → `[\"/bin/bash\"]`\nfn shell_from_shebang(path: &Path) -> Option<Vec<String>> {\n    use std::io::{BufRead, BufReader};\n    let f = std::fs::File::open(path).ok()?;\n    let mut reader = BufReader::new(f);\n    let mut first_line = String::new();\n    reader.read_line(&mut first_line).ok()?;\n    let shebang = first_line.strip_prefix(\"#!\")?;\n    let shebang = shebang.strip_prefix(\"/usr/bin/env -S\").unwrap_or(shebang);\n    let shebang = shebang.strip_prefix(\"/usr/bin/env\").unwrap_or(shebang);\n    let mut parts = shebang.split_whitespace();\n    let shell = parts.next()?;\n    // On Windows, convert unix paths like /bin/bash to just the binary name\n    let shell = if cfg!(windows) {\n        shell.rsplit('/').next().unwrap_or(shell)\n    } else {\n        shell\n    };\n    let args: Vec<String> = parts.map(|s| s.to_string()).collect();\n    Some(once(shell.to_string()).chain(args).collect())\n}\n"
  },
  {
    "path": "src/task/task_fetcher.rs",
    "content": "use crate::config::Settings;\nuse crate::task::Task;\nuse crate::task::task_file_providers::TaskFileProvidersBuilder;\nuse eyre::{Result, bail};\n\n/// Handles fetching remote task files and converting them to local paths\npub struct TaskFetcher {\n    no_cache: bool,\n}\n\nimpl TaskFetcher {\n    pub fn new(no_cache: bool) -> Self {\n        Self { no_cache }\n    }\n\n    /// Fetch remote task files, converting remote paths to local cached paths\n    pub async fn fetch_tasks(&self, tasks: &mut Vec<Task>) -> Result<()> {\n        let no_cache = self.no_cache || Settings::get().task.remote_no_cache.unwrap_or(false);\n        let task_file_providers = TaskFileProvidersBuilder::new()\n            .with_cache(!no_cache)\n            .build();\n\n        for t in tasks {\n            if let Some(file) = &t.file {\n                let source = file.to_string_lossy().to_string();\n\n                // Skip local files - they don't need provider resolution\n                if !Self::is_remote_source(&source) {\n                    continue;\n                }\n\n                let provider = task_file_providers.get_provider(&source);\n\n                if provider.is_none() {\n                    bail!(\"No provider found for file: {}\", source);\n                }\n\n                let local_path = provider.unwrap().get_local_path(&source).await?;\n\n                // Store the original remote source before replacing with local path\n                // This is used to determine if the task should use monorepo config file context\n                t.remote_file_source = Some(source);\n                t.file = Some(local_path);\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Check if a source path is a remote task file (git or http/https)\n    fn is_remote_source(source: &str) -> bool {\n        source.starts_with(\"git::\")\n            || source.starts_with(\"http://\")\n            || source.starts_with(\"https://\")\n    }\n}\n"
  },
  {
    "path": "src/task/task_file_providers/local_task.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse async_trait::async_trait;\n\nuse crate::Result;\n\nuse super::TaskFileProvider;\n\n#[derive(Debug)]\npub struct LocalTask;\n\n#[async_trait]\nimpl TaskFileProvider for LocalTask {\n    fn is_match(&self, file: &str) -> bool {\n        let path = Path::new(file);\n\n        path.is_relative() || path.is_absolute()\n    }\n\n    async fn get_local_path(&self, file: &str) -> Result<PathBuf> {\n        Ok(PathBuf::from(file))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[test]\n    fn test_is_match() {\n        let provider = LocalTask;\n        assert!(provider.is_match(\"filetask.bat\"));\n        assert!(provider.is_match(\"filetask\"));\n        assert!(provider.is_match(\"/test.txt\"));\n        assert!(provider.is_match(\"./test.txt\"));\n        assert!(provider.is_match(\"../test.txt\"));\n    }\n\n    #[tokio::test]\n    async fn test_get_local_path() {\n        let provider = LocalTask;\n        assert_eq!(\n            provider.get_local_path(\"/test.txt\").await.unwrap(),\n            PathBuf::from(\"/test.txt\")\n        );\n        assert_eq!(\n            provider.get_local_path(\"./test.txt\").await.unwrap(),\n            PathBuf::from(\"./test.txt\")\n        );\n        assert_eq!(\n            provider.get_local_path(\"../test.txt\").await.unwrap(),\n            PathBuf::from(\"../test.txt\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/task/task_file_providers/mod.rs",
    "content": "use std::{fmt::Debug, path::PathBuf};\n\nmod local_task;\nmod remote_task_git;\nmod remote_task_http;\nuse crate::Result;\nuse async_trait::async_trait;\nuse local_task::LocalTask;\nuse remote_task_git::RemoteTaskGitBuilder;\nuse remote_task_http::RemoteTaskHttpBuilder;\n\n#[async_trait]\npub trait TaskFileProvider: Debug + Send + Sync {\n    fn is_match(&self, file: &str) -> bool;\n    async fn get_local_path(&self, file: &str) -> Result<PathBuf>;\n}\n\npub struct TaskFileProvidersBuilder {\n    use_cache: bool,\n}\n\nimpl TaskFileProvidersBuilder {\n    pub fn new() -> Self {\n        Self { use_cache: false }\n    }\n\n    pub fn with_cache(mut self, use_cache: bool) -> Self {\n        self.use_cache = use_cache;\n        self\n    }\n\n    pub fn build(self) -> TaskFileProviders {\n        TaskFileProviders::new(self.use_cache)\n    }\n}\n\npub struct TaskFileProviders {\n    use_cache: bool,\n}\n\nimpl TaskFileProviders {\n    pub fn new(use_cache: bool) -> Self {\n        Self { use_cache }\n    }\n\n    fn get_providers(&self) -> Vec<Box<dyn TaskFileProvider>> {\n        vec![\n            Box::new(\n                RemoteTaskGitBuilder::new()\n                    .with_cache(self.use_cache)\n                    .build(),\n            ),\n            Box::new(\n                RemoteTaskHttpBuilder::new()\n                    .with_cache(self.use_cache)\n                    .build(),\n            ),\n            Box::new(LocalTask), // Must be the last provider\n        ]\n    }\n\n    pub fn get_provider(&self, file: &str) -> Option<Box<dyn TaskFileProvider>> {\n        self.get_providers().into_iter().find(|p| p.is_match(file))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[test]\n    fn test_get_providers() {\n        let task_file_providers = TaskFileProvidersBuilder::new().build();\n        let providers = task_file_providers.get_providers();\n        assert_eq!(providers.len(), 3);\n    }\n\n    #[test]\n    fn test_local_file_match_local_provider() {\n        let task_file_providers = TaskFileProvidersBuilder::new().build();\n        let cases = vec![\"file.txt\", \"./file.txt\", \"../file.txt\", \"/file.txt\"];\n\n        for file in cases {\n            let provider = task_file_providers.get_provider(file);\n            assert!(provider.is_some());\n            let provider_name = format!(\"{:?}\", provider.unwrap());\n            assert!(provider_name.contains(\"LocalTask\"));\n        }\n    }\n\n    #[test]\n    fn test_http_file_match_http_remote_task_provider() {\n        let task_file_providers = TaskFileProvidersBuilder::new().build();\n        let cases = vec![\n            \"http://example.com/file.txt\",\n            \"https://example.com/file.txt\",\n            \"https://example.com/subfolder/file.txt\",\n        ];\n\n        for file in cases {\n            let provider = task_file_providers.get_provider(file);\n            assert!(provider.is_some());\n            let provider_name = format!(\"{:?}\", provider.unwrap());\n            assert!(provider_name.contains(\"RemoteTaskHttp\"));\n        }\n    }\n\n    #[test]\n    fn test_git_file_match_git_remote_task_provider() {\n        let task_file_providers = TaskFileProvidersBuilder::new().build();\n        let cases = vec![\n            \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n            \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n            \"git::ssh://user@myserver.com/example.git//subfolder/myfile.py\",\n            \"git::https://myserver.com/example.git//subfolder/myfile.sh\",\n        ];\n\n        for file in cases {\n            let provider = task_file_providers.get_provider(file);\n            assert!(provider.is_some());\n            let provider_name = format!(\"{:?}\", provider.unwrap());\n            assert!(provider_name.contains(\"RemoteTaskGit\"));\n        }\n    }\n}\n"
  },
  {
    "path": "src/task/task_file_providers/remote_task_git.rs",
    "content": "use crate::Result;\nuse once_cell::sync::Lazy;\nuse regex::Regex;\nuse std::path::PathBuf;\n\nuse async_trait::async_trait;\n\nuse crate::{\n    dirs, env,\n    file::display_path,\n    git::{self, CloneOptions},\n    hash,\n    lock_file::LockFile,\n};\n\nuse super::TaskFileProvider;\n\nstatic SSH_REGEX: Lazy<Regex> = Lazy::new(|| {\n    Regex::new(r\"^git::(?P<url>ssh://((?P<user>[^@]+)@)(?P<host>[^/]+)/(?P<repo>.+)\\.git)//(?P<path>[^?]+)(\\?ref=(?P<branch>[^?]+))?$\").unwrap()\n});\n\nstatic HTTPS_REGEX: Lazy<Regex> = Lazy::new(|| {\n    Regex::new(r\"^git::(?P<url>https?://(?P<host>[^/]+)/(?P<repo>.+)\\.git)//(?P<path>[^?]+)(\\?ref=(?P<branch>[^?]+))?$\").unwrap()\n});\n\n#[derive(Debug)]\npub struct RemoteTaskGitBuilder {\n    store_path: PathBuf,\n    use_cache: bool,\n}\n\nimpl RemoteTaskGitBuilder {\n    pub fn new() -> Self {\n        Self {\n            store_path: env::temp_dir(),\n            use_cache: false,\n        }\n    }\n\n    pub fn with_cache(mut self, use_cache: bool) -> Self {\n        if use_cache {\n            self.store_path = dirs::CACHE.join(\"remote-git-tasks-cache\");\n            self.use_cache = true;\n        }\n        self\n    }\n\n    pub fn build(self) -> RemoteTaskGit {\n        RemoteTaskGit {\n            storage_path: self.store_path,\n            is_cached: self.use_cache,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct RemoteTaskGit {\n    storage_path: PathBuf,\n    is_cached: bool,\n}\n\n#[derive(Debug, Clone)]\nstruct GitRepoStructure {\n    url_without_path: String,\n    path: String,\n    branch: Option<String>,\n}\n\nimpl GitRepoStructure {\n    pub fn new(url_without_path: &str, path: &str, branch: Option<String>) -> Self {\n        Self {\n            url_without_path: url_without_path.to_string(),\n            path: path.to_string(),\n            branch,\n        }\n    }\n}\n\nimpl RemoteTaskGit {\n    fn get_cache_key(&self, repo_structure: &GitRepoStructure) -> String {\n        let key = format!(\n            \"{}{}\",\n            &repo_structure.url_without_path,\n            &repo_structure.branch.to_owned().unwrap_or(\"\".to_string())\n        );\n        hash::hash_sha256_to_str(&key)\n    }\n\n    fn get_repo_structure(&self, file: &str) -> GitRepoStructure {\n        if let Some(repo) = Self::parse_ssh(file) {\n            return repo;\n        }\n        Self::parse_https(file).unwrap()\n    }\n\n    fn parse_ssh(file: &str) -> Option<GitRepoStructure> {\n        let captures = SSH_REGEX.captures(file)?;\n        let url_without_path = captures.name(\"url\").unwrap().as_str();\n        let path = captures.name(\"path\").unwrap().as_str();\n        let branch = captures.name(\"branch\").map(|m| m.as_str().to_string());\n        Some(GitRepoStructure::new(url_without_path, path, branch))\n    }\n\n    fn parse_https(file: &str) -> Option<GitRepoStructure> {\n        let captures = HTTPS_REGEX.captures(file)?;\n        let url_without_path = captures.name(\"url\").unwrap().as_str();\n        let path = captures.name(\"path\").unwrap().as_str();\n        let branch = captures.name(\"branch\").map(|m| m.as_str().to_string());\n        Some(GitRepoStructure::new(url_without_path, path, branch))\n    }\n}\n\n#[async_trait]\nimpl TaskFileProvider for RemoteTaskGit {\n    fn is_match(&self, file: &str) -> bool {\n        SSH_REGEX.is_match(file) || HTTPS_REGEX.is_match(file)\n    }\n\n    async fn get_local_path(&self, file: &str) -> Result<PathBuf> {\n        let repo_structure = self.get_repo_structure(file);\n        let cache_key = self.get_cache_key(&repo_structure);\n        let destination = self.storage_path.join(&cache_key);\n        let repo_file_path = repo_structure.path.clone();\n        let full_path = destination.join(&repo_file_path);\n\n        debug!(\"Repo structure: {:?}\", repo_structure);\n\n        let _lock = LockFile::new(&destination)\n            .with_callback(|l| {\n                debug!(\n                    \"waiting for lock on remote git task cache: {}\",\n                    display_path(l)\n                );\n            })\n            .lock()?;\n\n        if self.is_cached {\n            trace!(\"Cache mode enabled\");\n            if full_path.exists() {\n                debug!(\"Using cached file: {:?}\", full_path);\n                return Ok(full_path);\n            }\n        } else {\n            trace!(\"Cache mode disabled\");\n        }\n\n        let tmp_destination = self.storage_path.join(format!(\"{}.clone-tmp\", &cache_key));\n        if tmp_destination.exists() {\n            crate::file::remove_all(&tmp_destination)?;\n        }\n\n        let git_repo = git::Git::new(&tmp_destination);\n\n        let mut clone_options = CloneOptions::default();\n\n        if let Some(branch) = &repo_structure.branch {\n            trace!(\"Use specific branch {}\", branch);\n            clone_options = clone_options.branch(branch);\n        }\n\n        match git_repo.clone(repo_structure.url_without_path.as_str(), clone_options) {\n            Ok(()) => {\n                if destination.exists()\n                    && let Err(e) = crate::file::remove_all(&destination)\n                {\n                    let _ = crate::file::remove_all(&tmp_destination);\n                    return Err(e);\n                }\n                if let Err(e) = std::fs::rename(&tmp_destination, &destination) {\n                    let _ = crate::file::remove_all(&tmp_destination);\n                    return Err(eyre::eyre!(\n                        \"failed to move cloned repo into cache at {}: {e}\",\n                        display_path(&destination)\n                    ));\n                }\n            }\n            Err(e) => {\n                let _ = crate::file::remove_all(&tmp_destination);\n                return Err(e);\n            }\n        }\n\n        Ok(full_path)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[test]\n    fn test_valid_parse_ssh() {\n        let test_cases = vec![\n            \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n            \"git::ssh://git@github.com/myorg/example.git//terraform/myfile?ref=master\",\n            \"git::ssh://git@git.acme.com:1222/myorg/example.git//terraform/myfile?ref=master\",\n            \"git::ssh://git@myserver.com/example.git//terraform/myfile\",\n            \"git::ssh://user@myserver.com/example.git//myfile?ref=master\",\n        ];\n\n        for url in test_cases {\n            assert!(\n                RemoteTaskGit::parse_ssh(url).is_some(),\n                \"Failed for: {}\",\n                url\n            );\n        }\n    }\n\n    #[test]\n    fn test_invalid_parse_ssh() {\n        let test_cases = vec![\n            \"git::ssh://myserver.com/example.git//myfile?ref=master\",\n            \"git::ssh://user@myserver.com/example.git?ref=master\",\n            \"git::ssh://user@myserver.com/example.git\",\n            \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n        ];\n\n        for url in test_cases {\n            assert!(\n                RemoteTaskGit::parse_ssh(url).is_none(),\n                \"Should fail for: {}\",\n                url\n            );\n        }\n    }\n\n    #[test]\n    fn test_valid_parse_https() {\n        let test_cases = vec![\n            \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n            \"git::https://github.com/myorg/example.git//terraform/myfile?ref=master\",\n            \"git::https://git.acme.com:8080/myorg/example.git//terraform/myfile?ref=master\",\n            \"git::https://myserver.com/example.git//terraform/myfile\",\n            \"git::https://myserver.com/example.git//myfile?ref=master\",\n            \"git::http://localhost:8080/repo.git//xtasks/lint/ripgrep\", // HTTP support for local testing\n        ];\n\n        for url in test_cases {\n            assert!(\n                RemoteTaskGit::parse_https(url).is_some(),\n                \"Failed for: {}\",\n                url\n            );\n        }\n    }\n\n    #[test]\n    fn test_invalid_parse_https() {\n        let test_cases = vec![\n            \"git::https://myserver.com/example.git?ref=master\",\n            \"git::https://user@myserver.com/example.git\",\n            \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n        ];\n\n        for url in test_cases {\n            assert!(\n                RemoteTaskGit::parse_https(url).is_none(),\n                \"Should fail for: {}\",\n                url\n            );\n        }\n    }\n\n    #[test]\n    fn test_extract_ssh_url_information() {\n        let test_cases: Vec<(&str, &str, &str, Option<String>)> = vec![\n            (\n                \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"ssh://git@github.com/myorg/example.git\",\n                \"myfile\",\n                Some(\"v1.0.0\".to_string()),\n            ),\n            (\n                \"git::ssh://git@github.com/myorg/example.git//terraform/myfile?ref=master\",\n                \"ssh://git@github.com/myorg/example.git\",\n                \"terraform/myfile\",\n                Some(\"master\".to_string()),\n            ),\n            (\n                \"git::ssh://git@myserver.com/example.git//terraform/myfile\",\n                \"ssh://git@myserver.com/example.git\",\n                \"terraform/myfile\",\n                None,\n            ),\n        ];\n\n        for (url, expected_repo, expected_path, expected_branch) in test_cases {\n            let repo = RemoteTaskGit::parse_ssh(url).unwrap();\n            assert_eq!(expected_repo, repo.url_without_path);\n            assert_eq!(expected_path, repo.path);\n            assert_eq!(expected_branch, repo.branch);\n        }\n    }\n\n    #[test]\n    fn test_extract_https_url_information() {\n        let test_cases: Vec<(&str, &str, &str, Option<String>)> = vec![\n            (\n                \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"https://github.com/myorg/example.git\",\n                \"myfile\",\n                Some(\"v1.0.0\".to_string()),\n            ),\n            (\n                \"git::https://github.com/myorg/example.git//terraform/myfile?ref=master\",\n                \"https://github.com/myorg/example.git\",\n                \"terraform/myfile\",\n                Some(\"master\".to_string()),\n            ),\n            (\n                \"git::https://myserver.com/example.git//terraform/myfile\",\n                \"https://myserver.com/example.git\",\n                \"terraform/myfile\",\n                None,\n            ),\n        ];\n\n        for (url, expected_repo, expected_path, expected_branch) in test_cases {\n            let repo = RemoteTaskGit::parse_https(url).unwrap();\n            assert_eq!(expected_repo, repo.url_without_path);\n            assert_eq!(expected_path, repo.path);\n            assert_eq!(expected_branch, repo.branch);\n        }\n    }\n\n    #[test]\n    fn test_compare_ssh_get_cache_key() {\n        let remote_task_git = RemoteTaskGitBuilder::new().build();\n\n        let test_cases = vec![\n            (\n                \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v2.0.0\",\n                false,\n            ),\n            (\n                \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::ssh://user@myserver.com/example.git//myfile?ref=master\",\n                false,\n            ),\n            (\n                \"git::ssh://git@github.com/example.git//myfile?ref=v1.0.0\",\n                \"git::ssh://git@github.com/example.git//subfolder/mysecondfile?ref=v1.0.0\",\n                true,\n            ),\n            (\n                \"git::ssh://git@github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::ssh://git@github.com/myorg/example.git//subfolder/mysecondfile?ref=v1.0.0\",\n                true,\n            ),\n        ];\n\n        for (first_url, second_url, expected) in test_cases {\n            let first_repo = RemoteTaskGit::parse_ssh(first_url).unwrap();\n            let second_repo = RemoteTaskGit::parse_ssh(second_url).unwrap();\n            let first_cache_key = remote_task_git.get_cache_key(&first_repo);\n            let second_cache_key = remote_task_git.get_cache_key(&second_repo);\n            assert_eq!(expected, first_cache_key == second_cache_key);\n        }\n    }\n\n    #[test]\n    fn test_compare_https_get_cache_key() {\n        let remote_task_git = RemoteTaskGitBuilder::new().build();\n\n        let test_cases = vec![\n            (\n                \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::https://github.com/myorg/example.git//myfile?ref=v2.0.0\",\n                false,\n            ),\n            (\n                \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::https://bitbucket.com/myorg/example.git//myfile?ref=v1.0.0\",\n                false,\n            ),\n            (\n                \"git::https://github.com/myorg/example.git//myfile?ref=v1.0.0\",\n                \"git::https://github.com/myorg/example.git//subfolder/myfile?ref=v1.0.0\",\n                true,\n            ),\n            (\n                \"git::https://github.com/example.git//myfile?ref=v1.0.0\",\n                \"git::https://github.com/example.git//subfolder/myfile?ref=v1.0.0\",\n                true,\n            ),\n        ];\n\n        for (first_url, second_url, expected) in test_cases {\n            let first_repo = RemoteTaskGit::parse_https(first_url).unwrap();\n            let second_repo = RemoteTaskGit::parse_https(second_url).unwrap();\n            let first_cache_key = remote_task_git.get_cache_key(&first_repo);\n            let second_cache_key = remote_task_git.get_cache_key(&second_repo);\n            assert_eq!(expected, first_cache_key == second_cache_key);\n        }\n    }\n}\n"
  },
  {
    "path": "src/task/task_file_providers/remote_task_http.rs",
    "content": "use std::path::PathBuf;\n\nuse async_trait::async_trait;\n\nuse crate::{Result, dirs, env, file, hash, http::HTTP};\n\nuse super::TaskFileProvider;\n\n#[derive(Debug)]\npub struct RemoteTaskHttpBuilder {\n    store_path: PathBuf,\n    use_cache: bool,\n}\n\nimpl RemoteTaskHttpBuilder {\n    pub fn new() -> Self {\n        Self {\n            store_path: env::temp_dir(),\n            use_cache: false,\n        }\n    }\n\n    pub fn with_cache(mut self, use_cache: bool) -> Self {\n        if use_cache {\n            self.store_path = dirs::CACHE.join(\"remote-http-tasks-cache\");\n            self.use_cache = true;\n        }\n        self\n    }\n\n    pub fn build(self) -> RemoteTaskHttp {\n        RemoteTaskHttp {\n            storage_path: self.store_path,\n            is_cached: self.use_cache,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct RemoteTaskHttp {\n    storage_path: PathBuf,\n    is_cached: bool,\n}\n\nimpl RemoteTaskHttp {\n    fn get_cache_key(&self, file: &str) -> String {\n        hash::hash_sha256_to_str(file)\n    }\n\n    async fn download_file(&self, file: &str, destination: &PathBuf) -> Result<()> {\n        trace!(\"Downloading file: {}\", file);\n        HTTP.download_file(file, destination, None).await?;\n        file::make_executable(destination)?;\n        Ok(())\n    }\n}\n\n#[async_trait]\nimpl TaskFileProvider for RemoteTaskHttp {\n    fn is_match(&self, file: &str) -> bool {\n        let url = url::Url::parse(file);\n\n        // Check if the URL is valid and the scheme is http or https\n        // and the path is not empty\n        // and the path is not a directory\n        url.is_ok_and(|url| {\n            (url.scheme() == \"http\" || url.scheme() == \"https\")\n                && url.path().len() > 1\n                && !url.path().ends_with('/')\n        })\n    }\n\n    async fn get_local_path(&self, file: &str) -> Result<PathBuf> {\n        let cache_key = self.get_cache_key(file);\n        let destination = self.storage_path.join(&cache_key);\n\n        match self.is_cached {\n            true => {\n                trace!(\"Cache mode enabled\");\n\n                if destination.exists() {\n                    debug!(\"Using cached file: {:?}\", destination);\n                    return Ok(destination);\n                }\n            }\n            false => {\n                trace!(\"Cache mode disabled\");\n\n                if destination.exists() {\n                    file::remove_file(&destination)?;\n                }\n            }\n        }\n\n        self.download_file(file, &destination).await?;\n        Ok(destination)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_is_match() {\n        let provider = RemoteTaskHttpBuilder::new().build();\n\n        // Positive cases\n        assert!(provider.is_match(\"http://myhost.com/test.txt\"));\n        assert!(provider.is_match(\"https://myhost.com/test.txt\"));\n        assert!(provider.is_match(\"https://mydomain.com/myfile.py\"));\n        assert!(provider.is_match(\"https://subdomain.mydomain.com/myfile.sh\"));\n        assert!(provider.is_match(\"https://subdomain.mydomain.com/myfile.sh?query=1\"));\n\n        // Negative cases\n        assert!(!provider.is_match(\"https://myhost.com/js/\"));\n        assert!(!provider.is_match(\"https://myhost.com\"));\n        assert!(!provider.is_match(\"https://myhost.com/\"));\n    }\n\n    #[tokio::test]\n    async fn test_http_remote_task_get_local_path_without_cache() {\n        let paths = vec![\n            \"/myfile.py\",\n            \"/subpath/myfile.sh\",\n            \"/myfile.sh?query=1&sdfsdf=2\",\n        ];\n        let mut server = mockito::Server::new_async().await;\n\n        for request_path in paths {\n            let mocked_server: mockito::Mock = server\n                .mock(\"GET\", request_path)\n                .with_status(200)\n                .with_body(\"Random content\")\n                .expect(2)\n                .create_async()\n                .await;\n\n            let provider = RemoteTaskHttpBuilder::new().build();\n            let request_url = format!(\"{}{}\", server.url(), request_path);\n            let cache_key = provider.get_cache_key(&request_url);\n\n            for _ in 0..2 {\n                let local_path = provider.get_local_path(&request_url).await.unwrap();\n                assert!(local_path.exists());\n                assert!(local_path.is_file());\n                assert!(local_path.ends_with(&cache_key));\n            }\n\n            mocked_server.assert();\n        }\n    }\n\n    #[tokio::test]\n    async fn test_http_remote_task_get_local_path_with_cache() {\n        let paths = vec![\n            \"/myfile.py\",\n            \"/subpath/myfile.sh\",\n            \"/myfile.sh?query=1&sdfsdf=2\",\n        ];\n        let mut server = mockito::Server::new_async().await;\n\n        for request_path in paths {\n            let mocked_server = server\n                .mock(\"GET\", request_path)\n                .with_status(200)\n                .with_body(\"Random content\")\n                .expect(1)\n                .create_async()\n                .await;\n\n            let provider = RemoteTaskHttpBuilder::new().with_cache(true).build();\n            let request_url = format!(\"{}{}\", server.url(), request_path);\n            let cache_key = provider.get_cache_key(&request_url);\n\n            for _ in 0..2 {\n                let path = provider.get_local_path(&request_url).await.unwrap();\n                assert!(path.exists());\n                assert!(path.is_file());\n                assert!(path.ends_with(&cache_key));\n            }\n\n            mocked_server.assert();\n        }\n    }\n}\n"
  },
  {
    "path": "src/task/task_helpers.rs",
    "content": "use crate::task::Task;\nuse std::path::{Path, PathBuf};\n\n/// Check if a task needs a permit from the semaphore\n/// Only shell/script tasks execute external commands and need a concurrency slot.\n/// Orchestrator-only tasks (pure groups of sub-tasks) do not.\npub fn task_needs_permit(task: &Task) -> bool {\n    task.file.is_some() || !task.run_script_strings().is_empty()\n}\n\n/// Canonicalize a path for use as cache key\n/// Falls back to original path if canonicalization fails\npub fn canonicalize_path(path: &Path) -> PathBuf {\n    path.canonicalize().unwrap_or_else(|_| path.to_path_buf())\n}\n"
  },
  {
    "path": "src/task/task_list.rs",
    "content": "use crate::config::{self, Config, Settings};\nuse crate::file::display_path;\nuse crate::task::{\n    GetMatchingExt, Task, TaskLoadContext, extract_monorepo_path, resolve_task_pattern,\n};\nuse crate::ui::ctrlc;\nuse crate::ui::{prompt, style};\nuse crate::{dirs, file};\nuse console::Term;\nuse demand::{DemandOption, Select};\nuse eyre::{Result, bail, ensure, eyre};\nuse fuzzy_matcher::{FuzzyMatcher, skim::SkimMatcherV2};\nuse itertools::Itertools;\nuse std::collections::HashSet;\nuse std::iter::once;\nuse std::path::PathBuf;\nuse std::sync::Arc;\n\n/// Split a task spec into name and args\n/// e.g., \"task arg1 arg2\" -> (\"task\", vec![\"arg1\", \"arg2\"])\npub fn split_task_spec(spec: &str) -> (&str, Vec<String>) {\n    let mut parts = spec.split_whitespace();\n    let name = parts.next().unwrap_or(\"\");\n    let args = parts.map(|s| s.to_string()).collect_vec();\n    (name, args)\n}\n\n/// Validate that monorepo features are properly configured\nfn validate_monorepo_setup(config: &Arc<Config>) -> Result<()> {\n    // Check if experimental mode is enabled\n    if !Settings::get().experimental {\n        bail!(\n            \"Monorepo task paths (like `//path:task` or `:task`) require experimental mode.\\n\\\n            \\n\\\n            To enable experimental features, set:\\n\\\n            {}\\n\\\n            \\n\\\n            Or run with: {}\",\n            style::eyellow(\"  export MISE_EXPERIMENTAL=true\"),\n            style::eyellow(\"MISE_EXPERIMENTAL=1 mise run ...\")\n        );\n    }\n\n    // Check if a monorepo root is configured\n    if !config.is_monorepo() {\n        bail!(\n            \"Monorepo task paths (like `//path:task` or `:task`) require a monorepo root configuration.\\n\\\n            \\n\\\n            To set up monorepo support, add this to your root mise.toml:\\n\\\n            {}\\n\\\n            \\n\\\n            Then create task files in subdirectories that will be automatically discovered.\\n\\\n            See {} for more information.\",\n            style::eyellow(\"  experimental_monorepo_root = true\"),\n            style::eunderline(\n                \"https://mise.jdx.dev/tasks/task-configuration.html#monorepo-support\"\n            )\n        );\n    }\n\n    Ok(())\n}\n\n/// Check if a name is similar to any known CLI subcommands using fuzzy matching\nfn suggest_similar_commands(name: &str) -> Vec<String> {\n    use clap::CommandFactory;\n    let cmd = crate::cli::Cli::command();\n    let matcher = SkimMatcherV2::default().use_cache(true).smart_case();\n    cmd.get_subcommands()\n        .flat_map(|s| std::iter::once(s.get_name()).chain(s.get_all_aliases()))\n        .filter_map(|subcmd| {\n            matcher\n                .fuzzy_match(subcmd, name)\n                .filter(|&score| score > 0)\n                .map(|score| (score, subcmd.to_string()))\n        })\n        .sorted_by_key(|(score, _)| -1 * *score)\n        .take(3)\n        .map(|(_, subcmd)| subcmd)\n        .collect()\n}\n\n/// Show an error when a task is not found, with helpful suggestions\nasync fn err_no_task(config: &Config, name: &str) -> Result<()> {\n    // Check early if the name looks like a mistyped CLI subcommand\n    let similar_cmds = suggest_similar_commands(name);\n\n    if config.tasks().await.is_ok_and(|t| t.is_empty()) {\n        // If the name matches a CLI subcommand closely, suggest that instead of\n        // the confusing \"no tasks defined\" message\n        if !similar_cmds.is_empty() {\n            let mut err_msg = format!(\"unknown command: {}\", style::ered(name));\n            err_msg.push_str(\"\\n\\nDid you mean:\");\n            for cmd_name in &similar_cmds {\n                err_msg.push_str(&format!(\"\\n  mise {cmd_name}\"));\n            }\n            bail!(err_msg);\n        }\n\n        // Check if there are any untrusted config files in the current directory\n        // that might contain tasks\n        if let Some(cwd) = &*dirs::CWD {\n            use crate::config::config_file::{config_trust_root, is_trusted};\n            use crate::config::config_files_in_dir;\n\n            let config_files = config_files_in_dir(cwd);\n            let untrusted_configs: Vec<_> = config_files\n                .iter()\n                .filter(|p| !is_trusted(&config_trust_root(p)) && !is_trusted(p))\n                .collect();\n\n            if !untrusted_configs.is_empty() {\n                let paths = untrusted_configs\n                    .iter()\n                    .map(display_path)\n                    .collect::<Vec<_>>()\n                    .join(\", \");\n                bail!(\n                    \"Config file(s) in {} are not trusted: {}\\nTrust them with `mise trust`. See https://mise.jdx.dev/cli/trust.html for more information.\",\n                    display_path(cwd),\n                    paths\n                );\n            }\n        }\n\n        bail!(\n            \"no tasks defined in {}. Are you in a project directory?\",\n            display_path(dirs::CWD.clone().unwrap_or_default())\n        );\n    }\n    if let Some(cwd) = &*dirs::CWD {\n        let includes = config::task_includes_for_dir(cwd, &config.config_files);\n        let path = includes\n            .iter()\n            .map(|d| d.join(name))\n            .find(|d| d.is_file() && !file::is_executable(d));\n        if let Some(path) = path\n            && !cfg!(windows)\n        {\n            warn!(\n                \"no task {} found, but a non-executable file exists at {}\",\n                style::ered(name),\n                display_path(&path)\n            );\n            let yn =\n                prompt::confirm(\"Mark this file as executable to allow it to be run as a task?\")?;\n            if yn {\n                file::make_executable(&path)?;\n                info!(\"marked as executable, try running this task again\");\n            }\n        }\n    }\n\n    // Suggest similar tasks using fuzzy matching for monorepo tasks\n    let mut err_msg = format!(\"no task {} found\", style::ered(name));\n    if name.starts_with(\"//\") {\n        // Load ALL monorepo tasks for suggestions\n        if let Ok(tasks) = config\n            .tasks_with_context(Some(&TaskLoadContext::all()))\n            .await\n        {\n            let matcher = SkimMatcherV2::default().use_cache(true).smart_case();\n            let similar: Vec<String> = tasks\n                .keys()\n                .filter(|k| k.starts_with(\"//\"))\n                .filter_map(|k| {\n                    matcher\n                        .fuzzy_match(&k.to_lowercase(), &name.to_lowercase())\n                        .map(|score| (score, k.clone()))\n                })\n                .sorted_by_key(|(score, _)| -1 * *score)\n                .take(5)\n                .map(|(_, k)| k)\n                .collect();\n\n            if !similar.is_empty() {\n                err_msg.push_str(\"\\n\\nDid you mean one of these?\");\n                for task_name in similar {\n                    err_msg.push_str(&format!(\"\\n  - {}\", task_name));\n                }\n            }\n        }\n    }\n\n    if !similar_cmds.is_empty() {\n        err_msg.push_str(\"\\n\\nDid you mean the command:\");\n        for cmd_name in &similar_cmds {\n            err_msg.push_str(&format!(\"\\n  mise {cmd_name}\"));\n        }\n    }\n\n    bail!(err_msg);\n}\n\n/// Prompt the user to select a task interactively\nasync fn prompt_for_task() -> Result<Task> {\n    let config = Config::get().await?;\n    let tasks = config.tasks().await?;\n    ensure!(\n        !tasks.is_empty(),\n        \"no tasks defined. see {url}\",\n        url = style::eunderline(\"https://mise.jdx.dev/tasks/\")\n    );\n    let theme = crate::ui::theme::get_theme();\n    let mut s = Select::new(\"Tasks\")\n        .description(\"Select a task to run\")\n        .filtering(true)\n        .filterable(true)\n        .theme(&theme);\n    for t in tasks.values().filter(|t| !t.hide) {\n        // Truncate description to first line only, like tasks ls does\n        let desc = t.description.lines().next().unwrap_or_default();\n        s = s.option(\n            DemandOption::new(&t.name)\n                .label(&t.display_name)\n                .description(desc),\n        );\n    }\n    ctrlc::show_cursor_after_ctrl_c();\n    match s.run() {\n        Ok(name) => match tasks.get(name) {\n            Some(task) => Ok(task.clone()),\n            None => bail!(\"no tasks {} found\", style::ered(name)),\n        },\n        Err(err) => {\n            Term::stderr().show_cursor()?;\n            Err(eyre!(err))\n        }\n    }\n}\n\n/// Get a list of tasks to run from command-line arguments\n/// Handles task patterns, monorepo paths, and interactive selection\npub async fn get_task_lists(\n    config: &Arc<Config>,\n    args: &[String],\n    prompt: bool,\n    only: bool,\n) -> Result<Vec<Task>> {\n    let args = args\n        .iter()\n        .map(|s| vec![s.to_string()])\n        .coalesce(|a, b| {\n            if b == vec![\":::\".to_string()] {\n                Err((a, b))\n            } else if a == vec![\":::\".to_string()] {\n                Ok(b)\n            } else {\n                Ok(a.into_iter().chain(b).collect_vec())\n            }\n        })\n        .flat_map(|args| args.split_first().map(|(t, a)| (t.clone(), a.to_vec())))\n        .collect::<Vec<_>>();\n\n    // Determine the appropriate task loading context based on patterns\n    // For monorepo patterns, we need to load tasks from the relevant parts of the monorepo\n    let task_context = if args.is_empty() {\n        None\n    } else {\n        // Collect all monorepo patterns\n        let monorepo_patterns: Vec<&str> = args\n            .iter()\n            .filter_map(|(t, _)| {\n                if t.starts_with(\"//\") || t.contains(\"...\") || t.starts_with(':') {\n                    Some(t.as_str())\n                } else {\n                    None\n                }\n            })\n            .collect();\n\n        if monorepo_patterns.is_empty() {\n            None\n        } else {\n            // Validate monorepo setup before attempting to load tasks\n            validate_monorepo_setup(config)?;\n\n            // Merge all path hints from the patterns into a single context\n            Some(TaskLoadContext::from_patterns(\n                monorepo_patterns.into_iter(),\n            ))\n        }\n    };\n\n    let mut tasks = vec![];\n    let arg_re = xx::regex!(r#\"^((\\.*|~)(/|\\\\)|\\w:\\\\)\"#);\n    for (t, args) in args {\n        // Expand :task pattern to match tasks in current directory's config root\n        let original_name = t.clone();\n        let t = crate::task::expand_colon_task_syntax(&t, config)?;\n\n        // A path starting with \"//\" on Windows will be treated as a UNC path by\n        // PathBuf, but \"//\" in UNIX will be collapsed to \"/\" by PathBuf.\n        // Checking a non-existent UNC path for Windows will incur a large\n        // hiccup (~2.8s) due to Windows trying to resolve the UNC path.\n        let t_for_path_check = t\n            .strip_prefix(\"//\")\n            .map(|s| format!(\"/{s}\"))\n            .unwrap_or_else(|| t.clone());\n\n        // can be any of the following:\n        // - ./path/to/script\n        // - ~/path/to/script\n        // - /path/to/script\n        // - ../path/to/script\n        // - C:\\path\\to\\script\n        // - .\\path\\to\\script\n        if arg_re.is_match(&t_for_path_check) {\n            let path = PathBuf::from(&t_for_path_check);\n            if path.exists() {\n                let config_root = config\n                    .project_root\n                    .clone()\n                    .or_else(|| dirs::CWD.clone())\n                    .unwrap_or_default();\n                let task = Task::from_path(config, &path, &PathBuf::new(), &config_root).await?;\n                return Ok(vec![task.with_args(args)]);\n            }\n        }\n        // Load tasks with the appropriate context\n        // If the task was expanded to monorepo syntax (e.g., bare \"build\" -> \"//packages/foo:build\"),\n        // we need to create a context from the expanded name to load tasks from that location\n        let effective_context = if task_context.is_some() {\n            task_context.clone()\n        } else if t.starts_with(\"//\") {\n            // Task was expanded to monorepo syntax, create context from the expanded name\n            Some(TaskLoadContext::from_pattern(&t))\n        } else {\n            None\n        };\n\n        let all_tasks = if let Some(ref ctx) = effective_context {\n            config.tasks_with_context(Some(ctx)).await?\n        } else {\n            config.tasks().await?\n        };\n\n        let tasks_with_aliases = crate::task::build_task_ref_map(all_tasks.iter());\n\n        let mut cur_tasks = tasks_with_aliases\n            .get_matching(&t)?\n            .into_iter()\n            .cloned()\n            .collect_vec();\n        // If the task name was auto-expanded to monorepo syntax (e.g., \"hello\" -> \"//:hello\")\n        // but no monorepo task matched, fall back to the original bare name to find global tasks\n        if cur_tasks.is_empty()\n            && t != original_name\n            && !original_name.starts_with(\"//\")\n            && !original_name.starts_with(':')\n        {\n            cur_tasks = tasks_with_aliases\n                .get_matching(&original_name)?\n                .into_iter()\n                .cloned()\n                .collect_vec();\n        }\n        if cur_tasks.is_empty() {\n            // Check if this is a \"default\" task (either plain \"default\" or monorepo syntax like \"//:default\")\n            // For monorepo tasks, ensure it starts with \"//\" and has exactly one \":\" before \"default\"\n            // This matches \"//:default\" and \"//subfolder:default\" but not \"//subfolder:task-group:default\"\n            let is_default_task = t == \"default\" || {\n                t.starts_with(\"//\") && t.ends_with(\":default\") && t[2..].matches(':').count() == 1\n            };\n            if !is_default_task || !prompt || !console::user_attended_stderr() {\n                err_no_task(config, &t).await?;\n            }\n            tasks.push(prompt_for_task().await?);\n        } else {\n            cur_tasks\n                .into_iter()\n                .map(|t| t.clone().with_args(args.to_vec()))\n                .for_each(|t| tasks.push(t));\n        }\n    }\n    if only {\n        for task in &mut tasks {\n            task.depends.clear();\n            task.depends_post.clear();\n            task.wait_for.clear();\n        }\n    }\n    Ok(tasks)\n}\n\n/// Resolve all dependencies for a list of tasks\n/// Iteratively discovers path hints by loading tasks and their dependencies\npub async fn resolve_depends(config: &Arc<Config>, tasks: Vec<Task>) -> Result<Vec<Task>> {\n    // Iteratively discover all path hints by loading tasks and their dependencies\n    // This handles chains like: //A:B -> :C -> :D -> //E:F where we need to discover E\n    let mut all_path_hints = HashSet::new();\n    let mut tasks_to_process: Vec<Task> = tasks.clone();\n    let mut processed_tasks = HashSet::new();\n\n    // Iteratively discover paths until no new paths are found\n    while !tasks_to_process.is_empty() {\n        // Extract path hints from current batch of tasks\n        let new_hints: Vec<String> = tasks_to_process\n            .iter()\n            .filter_map(|t| extract_monorepo_path(&t.name))\n            .chain(tasks_to_process.iter().flat_map(|t| {\n                t.depends\n                    .iter()\n                    .chain(t.wait_for.iter())\n                    .chain(t.depends_post.iter())\n                    .map(|td| resolve_task_pattern(&td.task, Some(t)))\n                    .filter_map(|resolved| extract_monorepo_path(&resolved))\n            }))\n            .collect();\n\n        // Check if we found any new paths\n        let mut had_new_hints = false;\n        for h in &new_hints {\n            if all_path_hints.insert(h.clone()) {\n                had_new_hints = true;\n            }\n        }\n        if !had_new_hints {\n            break;\n        }\n\n        // Load tasks with current path hints to discover dependencies\n        let ctx = Some(TaskLoadContext {\n            path_hints: all_path_hints.iter().cloned().collect(),\n            load_all: false,\n        });\n\n        let loaded_tasks = config.tasks_with_context(ctx.as_ref()).await?;\n\n        // Find new tasks that haven't been processed yet\n        tasks_to_process = loaded_tasks\n            .values()\n            .filter(|t| processed_tasks.insert(t.name.clone()))\n            .cloned()\n            .collect();\n    }\n\n    // Now load all tasks with the complete set of path hints\n    let ctx = if !all_path_hints.is_empty() {\n        Some(TaskLoadContext {\n            path_hints: all_path_hints.into_iter().collect(),\n            load_all: false,\n        })\n    } else {\n        None\n    };\n\n    let all_tasks = config.tasks_with_context(ctx.as_ref()).await?;\n\n    tasks\n        .into_iter()\n        .map(|t| {\n            let depends = t.all_depends(&all_tasks)?;\n            Ok(once(t).chain(depends).collect::<Vec<_>>())\n        })\n        .flatten_ok()\n        .collect()\n}\n"
  },
  {
    "path": "src/task/task_load_context.rs",
    "content": "use eyre::bail;\n\n/// Context for loading tasks with optional filtering hints\n#[derive(Debug, Clone, Default, Hash, Eq, PartialEq)]\npub struct TaskLoadContext {\n    /// Specific paths to load tasks from\n    /// e.g., [\"foo/bar\", \"baz/qux\"] from patterns \"//foo/bar:task\" and \"//baz/qux:task\"\n    pub path_hints: Vec<String>,\n\n    /// If true, load all tasks from the entire monorepo (for `mise tasks ls --all`)\n    /// If false (default), only load tasks from current directory hierarchy\n    pub load_all: bool,\n}\n\nimpl TaskLoadContext {\n    /// Create a new context that loads all tasks\n    pub fn all() -> Self {\n        Self {\n            path_hints: vec![],\n            load_all: true,\n        }\n    }\n\n    /// Create a context from a task pattern like \"//foo/bar:task\" or \"//foo/bar/...\"\n    pub fn from_pattern(pattern: &str) -> Self {\n        // Extract path hint from pattern\n        let path_hints = if let Some(hint) = Self::extract_path_hint(pattern) {\n            vec![hint]\n        } else {\n            vec![]\n        };\n\n        Self {\n            path_hints,\n            load_all: false,\n        }\n    }\n\n    /// Create a context from multiple patterns, merging their path hints\n    pub fn from_patterns<'a>(patterns: impl Iterator<Item = &'a str>) -> Self {\n        use std::collections::HashSet;\n\n        let mut path_hints_set = HashSet::new();\n        let mut load_all = false;\n\n        for pattern in patterns {\n            if let Some(hint) = Self::extract_path_hint(pattern) {\n                path_hints_set.insert(hint);\n            } else {\n                // If any pattern has no hint, we need to load all\n                load_all = true;\n            }\n        }\n\n        Self {\n            path_hints: path_hints_set.into_iter().collect(),\n            load_all,\n        }\n    }\n\n    /// Extract path hint from a monorepo pattern\n    /// Returns None if the pattern doesn't provide useful filtering information\n    fn extract_path_hint(pattern: &str) -> Option<String> {\n        const MONOREPO_PREFIX: &str = \"//\";\n        const TASK_SEPARATOR: &str = \":\";\n        const ELLIPSIS: &str = \"...\";\n\n        if !pattern.starts_with(MONOREPO_PREFIX) {\n            return None;\n        }\n\n        // Remove the // prefix\n        let without_prefix = pattern.strip_prefix(MONOREPO_PREFIX)?;\n\n        // Split on : to separate path from task name\n        let parts: Vec<&str> = without_prefix.splitn(2, TASK_SEPARATOR).collect();\n        let path_part = parts.first()?;\n\n        // If it's just \"//...\" or \"//\" we need everything\n        if path_part.is_empty() || *path_part == ELLIPSIS {\n            return None;\n        }\n\n        // Remove trailing ellipsis if present (e.g., \"foo/bar/...\")\n        let path_part = path_part.strip_suffix('/').unwrap_or(path_part);\n        let path_part = path_part.strip_suffix(ELLIPSIS).unwrap_or(path_part);\n        let path_part = path_part.strip_suffix('/').unwrap_or(path_part);\n\n        // If the path still contains \"...\" anywhere, it's a wildcard pattern\n        // that could match many paths, so we can't use it as a specific hint\n        // e.g., \".../graph\" or \"foo/.../bar\" should load all subdirectories\n        if path_part.contains(ELLIPSIS) {\n            return None;\n        }\n\n        // If we have a non-empty path hint, return it\n        if !path_part.is_empty() {\n            Some(path_part.to_string())\n        } else {\n            None\n        }\n    }\n\n    /// Check if a subdirectory should be loaded based on the context\n    pub fn should_load_subdir(&self, subdir: &str, _monorepo_root: &str) -> bool {\n        use std::path::Path;\n\n        // If load_all is true, load everything\n        if self.load_all {\n            return true;\n        }\n\n        // If no path hints, don't load anything (unless load_all is true)\n        if self.path_hints.is_empty() {\n            return false;\n        }\n\n        // Use Path APIs for more robust path comparison\n        let subdir_path = Path::new(subdir);\n\n        // Check if subdir matches or is a parent/child of any hint\n        for hint in &self.path_hints {\n            let hint_path = Path::new(hint);\n\n            // Check if subdir matches or is a parent/child of this hint\n            // e.g., hint \"foo/bar\" should match:\n            // - \"foo/bar\" (exact match)\n            // - \"foo/bar/baz\" (child - subdir starts with hint)\n            // - \"foo\" (parent - hint starts with subdir, might contain the target)\n            if subdir_path == hint_path\n                || subdir_path.starts_with(hint_path)\n                || hint_path.starts_with(subdir_path)\n            {\n                return true;\n            }\n        }\n\n        false\n    }\n}\n\n/// Expands :task syntax to //path:task based on current directory relative to monorepo root\n///\n/// This function handles the special `:task` syntax that refers to tasks in the current\n/// config_root within a monorepo. It converts `:build` to either `//:build` (if at monorepo root)\n/// or `//project:build` (if in a subdirectory).\n///\n/// # Arguments\n/// * `task` - The task pattern to expand (e.g., \":build\")\n/// * `config` - The configuration containing monorepo information\n///\n/// # Returns\n/// * `Ok(String)` - The expanded task pattern (e.g., \"//project:build\")\n/// * `Err` - If monorepo is not configured or current directory is outside monorepo root\npub fn expand_colon_task_syntax(\n    task: &str,\n    config: &crate::config::Config,\n) -> eyre::Result<String> {\n    // Skip expansion for absolute monorepo paths or explicit global tasks\n    if task.starts_with(\"//\") || task.starts_with(\"::\") {\n        return Ok(task.to_string());\n    }\n\n    // Check if this is a colon pattern or a bare name\n    let is_colon_pattern = task.starts_with(':');\n\n    // Reject patterns that look like monorepo paths with wrong syntax (have / and : but don't start with // or :)\n    if !is_colon_pattern && task.contains('/') && task.contains(':') {\n        bail!(\n            \"relative path syntax '{}' is not supported, use '//{}' or ':task' for current directory\",\n            task,\n            task\n        );\n    }\n\n    // Get the monorepo root (the config file with experimental_monorepo_root = true)\n    let monorepo_root = config\n        .config_files\n        .values()\n        .find(|cf| cf.experimental_monorepo_root() == Some(true))\n        .and_then(|cf| cf.project_root());\n\n    // If not in monorepo context, only expand if it's a colon pattern (error), otherwise return as-is\n    if monorepo_root.is_none() {\n        if is_colon_pattern {\n            bail!(\"Cannot use :task syntax without a monorepo root\");\n        }\n        return Ok(task.to_string());\n    }\n\n    // We're in a monorepo context\n    let monorepo_root = monorepo_root.unwrap();\n\n    // Determine the current directory relative to monorepo root\n    if let Some(cwd) = &*crate::dirs::CWD {\n        if let Ok(rel_path) = cwd.strip_prefix(monorepo_root) {\n            // For bare task names, only expand if we're actually in the monorepo\n            // For colon patterns, always expand (and error if outside monorepo)\n\n            // Convert relative path to monorepo path format\n            let path_str = rel_path\n                .to_string_lossy()\n                .replace(std::path::MAIN_SEPARATOR, \"/\");\n\n            if path_str.is_empty() {\n                // We're at the root\n                if is_colon_pattern {\n                    // :task -> //:task (task already has colon)\n                    Ok(format!(\"//{}\", task))\n                } else {\n                    // bare task -> //:task (add colon)\n                    Ok(format!(\"//:{}\", task))\n                }\n            } else {\n                // We're in a subdirectory\n                if is_colon_pattern {\n                    // :task -> //path:task\n                    Ok(format!(\"//{}{}\", path_str, task))\n                } else {\n                    // bare name -> //path:task\n                    Ok(format!(\"//{}:{}\", path_str, task))\n                }\n            }\n        } else {\n            if is_colon_pattern {\n                bail!(\"Cannot use :task syntax outside of monorepo root directory\");\n            }\n            // Bare name outside monorepo - return as-is for global matching\n            Ok(task.to_string())\n        }\n    } else {\n        if is_colon_pattern {\n            bail!(\"Cannot use :task syntax without a current working directory\");\n        }\n        Ok(task.to_string())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_extract_path_hint() {\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//foo/bar:task\"),\n            Some(\"foo/bar\".to_string())\n        );\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//foo/bar/...:task\"),\n            Some(\"foo/bar\".to_string())\n        );\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//foo:task\"),\n            Some(\"foo\".to_string())\n        );\n        assert_eq!(TaskLoadContext::extract_path_hint(\"//:task\"), None);\n        assert_eq!(TaskLoadContext::extract_path_hint(\"//...:task\"), None);\n        assert_eq!(TaskLoadContext::extract_path_hint(\"foo:task\"), None);\n\n        // Test patterns with ... in different positions (wildcard patterns)\n\n        // ... at the START of path\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//.../api:task\"),\n            None,\n            \"Pattern with ... at start should load all subdirs\"\n        );\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//.../services/api:task\"),\n            None,\n            \"Pattern with ... at start and more path should load all subdirs\"\n        );\n\n        // ... in the MIDDLE of path\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//projects/.../api:task\"),\n            None,\n            \"Pattern with ... in middle should load all subdirs\"\n        );\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//libs/.../utils:task\"),\n            None,\n            \"Pattern with ... in middle should load all subdirs\"\n        );\n\n        // Multiple ... in path\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//projects/.../api/...:task\"),\n            None,\n            \"Pattern with multiple ... should load all subdirs\"\n        );\n        assert_eq!(\n            TaskLoadContext::extract_path_hint(\"//.../foo/.../bar:task\"),\n            None,\n            \"Pattern with ... at start and middle should load all subdirs\"\n        );\n    }\n\n    #[test]\n    fn test_should_load_subdir() {\n        let ctx = TaskLoadContext::from_pattern(\"//foo/bar:task\");\n\n        // Should load exact match\n        assert!(ctx.should_load_subdir(\"foo/bar\", \"/root\"));\n\n        // Should load children\n        assert!(ctx.should_load_subdir(\"foo/bar/baz\", \"/root\"));\n\n        // Should load parent (might contain target)\n        assert!(ctx.should_load_subdir(\"foo\", \"/root\"));\n\n        // Should not load unrelated paths\n        assert!(!ctx.should_load_subdir(\"baz/qux\", \"/root\"));\n    }\n\n    #[test]\n    fn test_should_load_subdir_multiple_hints() {\n        let ctx =\n            TaskLoadContext::from_patterns([\"//foo/bar:task\", \"//baz/qux:task\"].iter().copied());\n\n        // Should load exact matches for both hints\n        assert!(ctx.should_load_subdir(\"foo/bar\", \"/root\"));\n        assert!(ctx.should_load_subdir(\"baz/qux\", \"/root\"));\n\n        // Should load children of both hints\n        assert!(ctx.should_load_subdir(\"foo/bar/child\", \"/root\"));\n        assert!(ctx.should_load_subdir(\"baz/qux/child\", \"/root\"));\n\n        // Should load parents of both hints\n        assert!(ctx.should_load_subdir(\"foo\", \"/root\"));\n        assert!(ctx.should_load_subdir(\"baz\", \"/root\"));\n\n        // Should not load unrelated paths\n        assert!(!ctx.should_load_subdir(\"other/path\", \"/root\"));\n    }\n\n    #[test]\n    fn test_load_all_context() {\n        let ctx = TaskLoadContext::all();\n        assert!(ctx.load_all);\n        assert!(ctx.should_load_subdir(\"any/path\", \"/root\"));\n    }\n\n    #[test]\n    fn test_expand_colon_task_syntax() {\n        // Note: This is a basic structure test. Full integration testing is done in e2e tests\n        // because it requires a real config with monorepo root setup and CWD manipulation.\n\n        // Test that non-colon patterns are returned as-is\n        // We can't easily test the full expansion here without setting up a real config\n        // and manipulating CWD, so we just verify the function signature and basic behavior\n        let task = \"regular-task\";\n        // For non-colon tasks, this should work even with empty config\n        // The actual expansion logic is tested via e2e tests\n        assert!(!task.starts_with(':'));\n    }\n}\n"
  },
  {
    "path": "src/task/task_output.rs",
    "content": "use crate::config::Settings;\nuse crate::env;\nuse console;\n\n#[derive(\n    Debug,\n    Default,\n    Clone,\n    Copy,\n    PartialEq,\n    strum::Display,\n    strum::EnumString,\n    strum::EnumIs,\n    serde::Serialize,\n    serde::Deserialize,\n)]\n#[serde(rename_all = \"kebab-case\")]\n#[strum(serialize_all = \"kebab-case\")]\npub enum TaskOutput {\n    Interleave,\n    KeepOrder,\n    #[default]\n    Prefix,\n    Replacing,\n    Timed,\n    Quiet,\n    Silent,\n}\n\n/// Returns the first line of a message for display unless task_show_full_cmd is true\n/// In CI mode, returns the full first line without truncation\n/// Otherwise, truncates to terminal width with ellipsis\npub fn trunc(prefix: &str, msg: &str) -> String {\n    let settings = Settings::get();\n\n    // Skip width truncation when explicitly disabled\n    if settings.task.show_full_cmd {\n        return msg.to_string();\n    }\n    let msg = msg.lines().next().unwrap_or_default();\n    if settings.ci {\n        return msg.to_string();\n    }\n    let prefix_len = console::measure_text_width(prefix);\n    // Ensure we have at least 20 characters for the message, even with very long prefixes\n    let available_width = (*env::TERM_WIDTH).saturating_sub(prefix_len + 1);\n    let max_width = available_width.max(20); // Always show at least 20 chars of message\n    console::truncate_str(msg, max_width, \"…\").to_string()\n}\n"
  },
  {
    "path": "src/task/task_output_handler.rs",
    "content": "use crate::config::Settings;\nuse crate::task::Task;\nuse crate::task::task_helpers::task_needs_permit;\nuse crate::task::task_output::TaskOutput;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::ui::progress_report::SingleReport;\nuse indexmap::IndexMap;\nuse std::sync::{Arc, Mutex};\nuse std::time::SystemTime;\n\n/// A single line of output, tagged by stream.\npub enum KeepOrderLine {\n    Stdout(String, String), // (prefix, line)\n    Stderr(String, String), // (prefix, line)\n}\n\n/// Streaming state for keep-order mode.\n///\n/// One task at a time is \"active\" and streams output in real-time.\n/// Other tasks buffer their output. When the active task finishes,\n/// any already-finished tasks' buffers are flushed, then the next\n/// running task with buffered output is promoted to stream live.\npub struct KeepOrderState {\n    /// The task whose output is currently being streamed live\n    active: Option<Task>,\n    /// Buffered output for non-active tasks (insertion order preserved)\n    buffers: IndexMap<Task, Vec<KeepOrderLine>>,\n    /// Tasks that finished while not active (in order of completion)\n    finished: Vec<Task>,\n    /// Set after flush_all — further output prints directly\n    done: bool,\n}\n\nimpl KeepOrderState {\n    pub fn new() -> Self {\n        Self {\n            active: None,\n            buffers: IndexMap::new(),\n            finished: Vec::new(),\n            done: false,\n        }\n    }\n\n    pub fn init_task(&mut self, task: &Task) {\n        self.buffers.entry(task.clone()).or_default();\n    }\n\n    /// Whether this task should stream live (is active, or is first in\n    /// definition order when no task is active yet).\n    fn is_active(&self, task: &Task) -> bool {\n        if let Some(active) = &self.active {\n            active == task\n        } else {\n            // No active task yet — only the first task in definition order may claim it\n            self.buffers.first().map(|(t, _)| t) == Some(task)\n        }\n    }\n\n    /// Called when a stdout line is produced by a task's process.\n    pub fn on_stdout(&mut self, task: &Task, prefix: String, line: String) {\n        if self.done || self.is_active(task) {\n            self.active = Some(task.clone());\n            print_stdout(&prefix, &line);\n        } else {\n            self.buffers\n                .entry(task.clone())\n                .or_default()\n                .push(KeepOrderLine::Stdout(prefix, line));\n        }\n    }\n\n    /// Called when a stderr line is produced by a task's process,\n    /// or when metadata (command echo, timing) is emitted for a task.\n    pub fn on_stderr(&mut self, task: &Task, prefix: String, line: String) {\n        if self.done || self.is_active(task) {\n            self.active = Some(task.clone());\n            print_stderr(&prefix, &line);\n        } else {\n            self.buffers\n                .entry(task.clone())\n                .or_default()\n                .push(KeepOrderLine::Stderr(prefix, line));\n        }\n    }\n\n    /// Called when a task finishes execution.\n    pub fn on_task_finished(&mut self, task: &Task) {\n        if !self.buffers.contains_key(task) {\n            return; // Not a keep-order task\n        }\n        if self.is_active(task) {\n            // Active task finished — clear it, flush waiting tasks, promote next\n            self.active = None;\n            self.buffers.shift_remove(task);\n            self.flush_finished();\n            self.promote_next();\n        } else {\n            // Non-active task finished — remember it for later flushing\n            self.finished.push(task.clone());\n        }\n    }\n\n    /// Flush contiguous finished tasks from the front of the buffer.\n    /// Stops at the first non-finished task to preserve definition order.\n    fn flush_finished(&mut self) {\n        let mut finished: std::collections::HashSet<_> = self.finished.drain(..).collect();\n        loop {\n            let Some((task, _)) = self.buffers.first() else {\n                break;\n            };\n            if !finished.remove(task) {\n                break; // Hit a non-finished task, stop\n            }\n            let task = task.clone();\n            if let Some(lines) = self.buffers.shift_remove(&task) {\n                Self::print_lines(&lines);\n            }\n        }\n        // Re-add finished tasks we couldn't flush (behind a still-running task)\n        self.finished.extend(finished);\n    }\n\n    /// Promote the next buffered (still-running) task to active and\n    /// flush its current buffer so it can stream live going forward.\n    fn promote_next(&mut self) {\n        if let Some((task, _)) = self.buffers.first() {\n            let task = task.clone();\n            self.active = Some(task.clone());\n            if let Some(lines) = self.buffers.get_mut(&task) {\n                let lines = std::mem::take(lines);\n                Self::print_lines(&lines);\n            }\n        }\n    }\n\n    fn print_lines(lines: &[KeepOrderLine]) {\n        for line in lines {\n            match line {\n                KeepOrderLine::Stdout(prefix, line) => print_stdout(prefix, line),\n                KeepOrderLine::Stderr(prefix, line) => print_stderr(prefix, line),\n            }\n        }\n    }\n\n    /// Safety-net: flush any remaining output (called at the very end).\n    /// After this, any further output prints directly.\n    pub fn flush_all(&mut self) {\n        self.active = None;\n        self.flush_finished();\n        for (_, lines) in self.buffers.drain(..) {\n            Self::print_lines(&lines);\n        }\n        self.done = true;\n    }\n}\n\nfn print_stdout(prefix: &str, line: &str) {\n    if console::colors_enabled() {\n        prefix_println!(prefix, \"{line}\\x1b[0m\");\n    } else {\n        prefix_println!(prefix, \"{line}\");\n    }\n}\n\nfn print_stderr(prefix: &str, line: &str) {\n    if console::colors_enabled_stderr() {\n        prefix_eprintln!(prefix, \"{line}\\x1b[0m\");\n    } else {\n        prefix_eprintln!(prefix, \"{line}\");\n    }\n}\n\n/// Configuration for OutputHandler\npub struct OutputHandlerConfig {\n    pub prefix: bool,\n    pub interleave: bool,\n    pub output: Option<TaskOutput>,\n    pub silent: bool,\n    pub quiet: bool,\n    pub raw: bool,\n    pub is_linear: bool,\n    pub jobs: Option<usize>,\n}\n\n/// Handles task output routing, formatting, and display\npub struct OutputHandler {\n    pub keep_order_state: Arc<Mutex<KeepOrderState>>,\n    pub task_prs: IndexMap<Task, Arc<Box<dyn SingleReport>>>,\n    pub timed_outputs: Arc<Mutex<IndexMap<String, (SystemTime, String)>>>,\n\n    // Configuration from CLI args\n    prefix: bool,\n    interleave: bool,\n    output: Option<TaskOutput>,\n    silent: bool,\n    quiet: bool,\n    raw: bool,\n    is_linear: bool,\n    jobs: Option<usize>,\n}\n\nimpl Clone for OutputHandler {\n    fn clone(&self) -> Self {\n        Self {\n            keep_order_state: self.keep_order_state.clone(),\n            task_prs: self.task_prs.clone(),\n            timed_outputs: self.timed_outputs.clone(),\n            prefix: self.prefix,\n            interleave: self.interleave,\n            output: self.output,\n            silent: self.silent,\n            quiet: self.quiet,\n            raw: self.raw,\n            is_linear: self.is_linear,\n            jobs: self.jobs,\n        }\n    }\n}\n\nimpl OutputHandler {\n    pub fn new(config: OutputHandlerConfig) -> Self {\n        Self {\n            keep_order_state: Arc::new(Mutex::new(KeepOrderState::new())),\n            task_prs: IndexMap::new(),\n            timed_outputs: Arc::new(Mutex::new(IndexMap::new())),\n            prefix: config.prefix,\n            interleave: config.interleave,\n            output: config.output,\n            silent: config.silent,\n            quiet: config.quiet,\n            raw: config.raw,\n            is_linear: config.is_linear,\n            jobs: config.jobs,\n        }\n    }\n\n    /// Initialize output handling for a task\n    pub fn init_task(&mut self, task: &Task) {\n        match self.output(Some(task)) {\n            TaskOutput::KeepOrder => {\n                // Only add tasks that produce output (not orchestrator-only tasks)\n                if task_needs_permit(task) {\n                    self.keep_order_state.lock().unwrap().init_task(task);\n                }\n            }\n            TaskOutput::Replacing => {\n                let pr = MultiProgressReport::get().add(&task.estyled_prefix());\n                self.task_prs.insert(task.clone(), Arc::new(pr));\n            }\n            _ => {}\n        }\n    }\n\n    /// Determine the output mode for a task\n    pub fn output(&self, task: Option<&Task>) -> TaskOutput {\n        // Check for full silent mode (both streams)\n        // Only Silent::Bool(true) means completely silent, not Silent::Stdout or Silent::Stderr\n        if let Some(task_ref) = task\n            && matches!(task_ref.silent, crate::task::Silent::Bool(true))\n        {\n            return TaskOutput::Silent;\n        }\n\n        // Check global output settings\n        if let Some(o) = self.output {\n            return o;\n        } else if let Some(task_ref) = task {\n            // Fall through to other checks if silent is Off\n            if self.silent_bool() {\n                return TaskOutput::Silent;\n            }\n            if self.quiet(Some(task_ref)) {\n                return TaskOutput::Quiet;\n            }\n        } else if self.silent_bool() {\n            return TaskOutput::Silent;\n        } else if self.quiet(task) {\n            return TaskOutput::Quiet;\n        }\n\n        // CLI flags (--prefix, --interleave) override config settings\n        if self.prefix {\n            TaskOutput::Prefix\n        } else if self.interleave {\n            TaskOutput::Interleave\n        } else if let Some(output) = Settings::get().task.output {\n            // Silent/quiet from config override raw (output suppression takes precedence)\n            // Other modes (prefix, etc.) allow raw to take precedence for stdin/stdout\n            if output.is_silent() || output.is_quiet() {\n                output\n            } else if self.raw(task) {\n                TaskOutput::Interleave\n            } else {\n                output\n            }\n        } else if self.raw(task) || self.jobs() == 1 || self.is_linear {\n            TaskOutput::Interleave\n        } else {\n            TaskOutput::Prefix\n        }\n    }\n\n    /// Print error/metadata message for a task.\n    /// For keep-order mode, routes through the streaming state so messages\n    /// stay ordered with the task's stdout/stderr.\n    pub fn eprint(&self, task: &Task, prefix: &str, line: &str) {\n        match self.output(Some(task)) {\n            TaskOutput::KeepOrder => {\n                self.keep_order_state.lock().unwrap().on_stderr(\n                    task,\n                    prefix.to_string(),\n                    line.to_string(),\n                );\n            }\n            TaskOutput::Replacing => {\n                let pr = self.task_prs.get(task).unwrap().clone();\n                pr.set_message(format!(\"{prefix} {line}\"));\n            }\n            _ => {\n                prefix_eprintln!(prefix, \"{line}\");\n            }\n        }\n    }\n\n    fn silent_bool(&self) -> bool {\n        self.silent\n            || Settings::get().silent\n            || self.output.is_some_and(|o| o.is_silent())\n            || Settings::get().task.output.is_some_and(|o| o.is_silent())\n    }\n\n    pub fn silent(&self, task: Option<&Task>) -> bool {\n        self.silent_bool() || task.is_some_and(|t| t.silent.is_silent())\n    }\n\n    pub fn quiet(&self, task: Option<&Task>) -> bool {\n        self.quiet\n            || Settings::get().quiet\n            || self.output.is_some_and(|o| o.is_quiet())\n            || Settings::get().task.output.is_some_and(|o| o.is_quiet())\n            || task.is_some_and(|t| t.quiet)\n            || self.silent(task)\n    }\n\n    pub fn raw(&self, task: Option<&Task>) -> bool {\n        // Interactive tasks are treated as raw for I/O (stdin/stdout/stderr inherit).\n        // This means CmdLineRunner will also acquire its internal RAW_LOCK — that's\n        // intentional and harmless since TASK_RUNTIME_LOCK already provides exclusivity.\n        self.raw || Settings::get().raw || task.is_some_and(|t| t.raw || t.interactive)\n    }\n\n    pub fn jobs(&self) -> usize {\n        if self.raw {\n            1\n        } else {\n            self.jobs.unwrap_or(Settings::get().jobs)\n        }\n    }\n}\n"
  },
  {
    "path": "src/task/task_results_display.rs",
    "content": "use crate::exit;\nuse crate::task::task_output::TaskOutput;\nuse crate::task::task_output_handler::OutputHandler;\nuse crate::task::{FailedTasks, Task};\nuse crate::ui::{style, time};\n\n/// Handles display of task execution results and failure summaries\npub struct TaskResultsDisplay {\n    output_handler: OutputHandler,\n    failed_tasks: FailedTasks,\n    continue_on_error: bool,\n    show_timings: bool,\n}\n\nimpl TaskResultsDisplay {\n    pub fn new(\n        output_handler: OutputHandler,\n        failed_tasks: FailedTasks,\n        continue_on_error: bool,\n        show_timings: bool,\n    ) -> Self {\n        Self {\n            output_handler,\n            failed_tasks,\n            continue_on_error,\n            show_timings,\n        }\n    }\n\n    /// Display final results and handle failures\n    pub fn display_results(&self, num_tasks: usize, timer: std::time::Instant) {\n        self.display_keep_order_output();\n        self.display_timing_summary(num_tasks, timer);\n        self.maybe_print_failure_summary();\n        self.exit_if_failed();\n    }\n\n    /// Flush any remaining keep-order output (safety net)\n    fn display_keep_order_output(&self) {\n        if self.output_handler.output(None) != TaskOutput::KeepOrder {\n            return;\n        }\n        self.output_handler\n            .keep_order_state\n            .lock()\n            .unwrap()\n            .flush_all();\n    }\n\n    /// Display timing summary if enabled\n    fn display_timing_summary(&self, num_tasks: usize, timer: std::time::Instant) {\n        if self.show_timings && num_tasks > 1 {\n            let msg = format!(\"Finished in {}\", time::format_duration(timer.elapsed()));\n            let _ = calm_io::stderrln!(\"{}\", style::edim(msg));\n        }\n    }\n\n    /// Print failure summary if in continue-on-error mode\n    fn maybe_print_failure_summary(&self) {\n        if !self.continue_on_error {\n            return;\n        }\n\n        let failed = self.failed_tasks.lock().unwrap().clone();\n        if failed.is_empty() {\n            return;\n        }\n\n        let count = failed.len();\n        let _ = calm_io::stderrln!(\"{} {} task(s) failed:\", style::ered(\"ERROR\"), count);\n        for (task, status) in &failed {\n            let prefix = task.estyled_prefix();\n            let status_str = status\n                .map(|s| s.to_string())\n                .unwrap_or_else(|| \"unknown\".to_string());\n            self.eprint(task, &prefix, &format!(\"exited with status {}\", status_str));\n        }\n    }\n\n    /// Exit if any tasks failed\n    fn exit_if_failed(&self) {\n        if let Some((task, status)) = self.failed_tasks.lock().unwrap().first() {\n            let prefix = task.estyled_prefix();\n            self.eprint(\n                task,\n                &prefix,\n                &format!(\"{} task failed\", style::ered(\"ERROR\")),\n            );\n            exit(status.unwrap_or(1));\n        }\n    }\n\n    /// Print error message for a task\n    fn eprint(&self, task: &Task, prefix: &str, line: &str) {\n        self.output_handler.eprint(task, prefix, line);\n    }\n}\n"
  },
  {
    "path": "src/task/task_scheduler.rs",
    "content": "use crate::cmd::CmdLineRunner;\nuse crate::config::Config;\nuse crate::task::{Deps, Task};\nuse eyre::Result;\nuse std::sync::Arc;\nuse std::sync::atomic::{AtomicUsize, Ordering};\nuse tokio::sync::{Mutex, Semaphore, mpsc};\nuse tokio::task::JoinSet;\n\n#[cfg(unix)]\nuse nix::sys::signal::SIGTERM;\n\npub type SchedMsg = (Task, Arc<Mutex<Deps>>);\n\n/// Schedules and executes tasks with concurrency control\npub struct Scheduler {\n    pub semaphore: Arc<Semaphore>,\n    pub jset: Arc<Mutex<JoinSet<Result<()>>>>,\n    pub sched_tx: Arc<mpsc::UnboundedSender<SchedMsg>>,\n    pub sched_rx: Option<mpsc::UnboundedReceiver<SchedMsg>>,\n    pub in_flight: Arc<AtomicUsize>,\n}\n\nimpl Scheduler {\n    pub fn new(jobs: usize) -> Self {\n        let (sched_tx, sched_rx) = mpsc::unbounded_channel::<SchedMsg>();\n        Self {\n            semaphore: Arc::new(Semaphore::new(jobs)),\n            jset: Arc::new(Mutex::new(JoinSet::new())),\n            sched_tx: Arc::new(sched_tx),\n            sched_rx: Some(sched_rx),\n            in_flight: Arc::new(AtomicUsize::new(0)),\n        }\n    }\n\n    /// Take ownership of the receiver (can only be called once)\n    pub fn take_receiver(&mut self) -> Option<mpsc::UnboundedReceiver<SchedMsg>> {\n        self.sched_rx.take()\n    }\n\n    /// Wait for all spawned tasks to complete\n    pub async fn join_all(&self, continue_on_error: bool) -> Result<()> {\n        while let Some(result) = self.jset.lock().await.join_next().await {\n            if result.is_ok() || continue_on_error {\n                continue;\n            }\n            #[cfg(unix)]\n            CmdLineRunner::kill_all(SIGTERM);\n            #[cfg(windows)]\n            CmdLineRunner::kill_all();\n            break;\n        }\n        Ok(())\n    }\n\n    /// Create a spawn context\n    pub fn spawn_context(&self, config: Arc<Config>) -> SpawnContext {\n        SpawnContext {\n            semaphore: self.semaphore.clone(),\n            config,\n            sched_tx: self.sched_tx.clone(),\n            jset: self.jset.clone(),\n            in_flight: self.in_flight.clone(),\n        }\n    }\n\n    /// Get the in-flight task count\n    pub fn in_flight_count(&self) -> usize {\n        self.in_flight.load(Ordering::SeqCst)\n    }\n\n    /// Pump dependency graph leaves into the scheduler\n    ///\n    /// Forwards initial leaves synchronously, then spawns an async task to forward\n    /// remaining leaves as they become available. Returns a watch receiver that signals\n    /// when all dependencies are complete.\n    pub async fn pump_deps(&self, deps: Arc<Mutex<Deps>>) -> tokio::sync::watch::Receiver<bool> {\n        let (main_done_tx, main_done_rx) = tokio::sync::watch::channel(false);\n        let sched_tx = self.sched_tx.clone();\n        let deps_clone = deps.clone();\n\n        // Forward initial leaves synchronously\n        {\n            let mut rx = deps_clone.lock().await.subscribe();\n            loop {\n                match rx.try_recv() {\n                    Ok(Some(task)) => {\n                        trace!(\n                            \"main deps initial leaf: {} {}\",\n                            task.name,\n                            task.args.join(\" \")\n                        );\n                        let _ = sched_tx.send((task, deps_clone.clone()));\n                    }\n                    Ok(None) => {\n                        trace!(\"main deps initial done\");\n                        break;\n                    }\n                    Err(mpsc::error::TryRecvError::Empty) => {\n                        break;\n                    }\n                    Err(mpsc::error::TryRecvError::Disconnected) => {\n                        break;\n                    }\n                }\n            }\n        }\n\n        // Forward remaining leaves asynchronously\n        tokio::spawn(async move {\n            let mut rx = deps_clone.lock().await.subscribe();\n            while let Some(msg) = rx.recv().await {\n                match msg {\n                    Some(task) => {\n                        trace!(\n                            \"main deps leaf scheduled: {} {}\",\n                            task.name,\n                            task.args.join(\" \")\n                        );\n                        let _ = sched_tx.send((task, deps_clone.clone()));\n                    }\n                    None => {\n                        trace!(\"main deps completed\");\n                        let _ = main_done_tx.send(true);\n                        break;\n                    }\n                }\n            }\n        });\n\n        main_done_rx\n    }\n\n    /// Run the scheduler loop, draining tasks and spawning them via the callback\n    ///\n    /// The loop continues until:\n    /// - main_done signal is received AND\n    /// - no tasks are in-flight AND\n    /// - no tasks were recently drained\n    ///\n    /// Or if should_stop returns true (for early exit due to failures)\n    pub async fn run_loop<F, Fut>(\n        &mut self,\n        main_done_rx: &mut tokio::sync::watch::Receiver<bool>,\n        main_deps: Arc<Mutex<Deps>>,\n        should_stop: impl Fn() -> bool,\n        continue_on_error: bool,\n        mut spawn_job: F,\n    ) -> Result<()>\n    where\n        F: FnMut(Task, Arc<Mutex<Deps>>) -> Fut,\n        Fut: std::future::Future<Output = Result<()>>,\n    {\n        let mut sched_rx = self.take_receiver().expect(\"receiver already taken\");\n        let mut failure_cleanup_done = false;\n\n        loop {\n            // Drain ready tasks without awaiting\n            let mut drained_any = false;\n            loop {\n                match sched_rx.try_recv() {\n                    Ok((task, deps_for_remove)) => {\n                        drained_any = true;\n                        trace!(\"scheduler received: {} {}\", task.name, task.args.join(\" \"));\n                        if should_stop() && !continue_on_error {\n                            // Still allow post-dep (cleanup) tasks to run on failure,\n                            // but only if their parent was actually started\n                            let mut deps = deps_for_remove.lock().await;\n                            if !deps.is_runnable_post_dep(&task) {\n                                deps.remove(&task);\n                                continue;\n                            }\n                            drop(deps);\n                        }\n                        spawn_job(task, deps_for_remove).await?;\n                    }\n                    Err(mpsc::error::TryRecvError::Empty) => break,\n                    Err(mpsc::error::TryRecvError::Disconnected) => break,\n                }\n            }\n\n            // Check if we should stop early due to failure (run cleanup only once)\n            if should_stop() && !continue_on_error && !failure_cleanup_done {\n                failure_cleanup_done = true;\n                trace!(\"scheduler: stopping early due to failure, cleaning up non-post-dep tasks\");\n                // Clean up tasks that shouldn't run: non-post-deps and post-deps whose\n                // parent was never started. Use batch removal so intermediate emit_leaves\n                // calls don't schedule post-deps of never-started tasks.\n                let mut deps = main_deps.lock().await;\n                let tasks_to_remove: Vec<Task> = deps\n                    .all()\n                    .filter(|t| !deps.is_runnable_post_dep(t))\n                    .cloned()\n                    .collect();\n                deps.remove_batch(&tasks_to_remove);\n                if deps.is_empty() {\n                    drop(deps);\n                    break;\n                }\n                drop(deps);\n                // Don't break — continue loop to process remaining post-dep tasks\n            }\n\n            // Exit if main deps finished and nothing is running/queued\n            if *main_done_rx.borrow() && self.in_flight_count() == 0 && !drained_any {\n                trace!(\"scheduler drain complete; exiting loop\");\n                break;\n            }\n\n            // Await either new work or main_done change\n            tokio::select! {\n                m = sched_rx.recv() => {\n                    if let Some((task, deps_for_remove)) = m {\n                        trace!(\"scheduler received: {} {}\", task.name, task.args.join(\" \"));\n                        if should_stop() && !continue_on_error {\n                            let mut deps = deps_for_remove.lock().await;\n                            if !deps.is_runnable_post_dep(&task) {\n                                deps.remove(&task);\n                                continue;\n                            }\n                            drop(deps);\n                        }\n                        spawn_job(task, deps_for_remove).await?;\n                    } else {\n                        // channel closed; rely on main_done/in_flight to exit soon\n                    }\n                }\n                _ = main_done_rx.changed() => {\n                    trace!(\"main_done changed: {}\", *main_done_rx.borrow());\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\n/// Context passed to spawned tasks\n#[derive(Clone)]\npub struct SpawnContext {\n    pub semaphore: Arc<Semaphore>,\n    pub config: Arc<Config>,\n    pub sched_tx: Arc<mpsc::UnboundedSender<SchedMsg>>,\n    pub jset: Arc<Mutex<JoinSet<Result<()>>>>,\n    pub in_flight: Arc<AtomicUsize>,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_scheduler_new() {\n        let scheduler = Scheduler::new(4);\n        // Verify basic initialization\n        assert_eq!(\n            scheduler.in_flight_count(),\n            0,\n            \"in_flight should start at 0\"\n        );\n    }\n\n    #[tokio::test]\n    async fn test_spawn_context_clone() {\n        let scheduler = Scheduler::new(4);\n        let config = Config::get().await.unwrap();\n        let ctx = scheduler.spawn_context(config.clone());\n        let ctx2 = ctx.clone();\n        // Verify cloning works\n        assert!(Arc::ptr_eq(&ctx.config, &ctx2.config));\n    }\n\n    #[tokio::test]\n    async fn test_scheduler_receiver_take() {\n        let mut scheduler = Scheduler::new(4);\n        let rx = scheduler.take_receiver();\n        assert!(rx.is_some(), \"should be able to take receiver once\");\n        let rx2 = scheduler.take_receiver();\n        assert!(rx2.is_none(), \"should not be able to take receiver twice\");\n    }\n}\n"
  },
  {
    "path": "src/task/task_script_parser.rs",
    "content": "use crate::config::{Config, Settings};\nuse crate::env_diff::EnvMap;\nuse crate::exit::exit;\nuse crate::shell::ShellType;\nuse crate::task::Task;\nuse crate::tera::get_tera;\nuse eyre::{Context, Result};\nuse heck::ToSnakeCase;\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse std::collections::{HashMap, HashSet};\nuse std::iter::once;\nuse std::path::PathBuf;\nuse std::sync::{Arc, Mutex};\n\ntype TeraSpecParsingResult = (\n    tera::Tera,\n    Arc<Mutex<HashMap<String, usize>>>,\n    Arc<Mutex<Vec<usage::SpecArg>>>,\n    Arc<Mutex<Vec<usage::SpecFlag>>>,\n);\n\npub struct TaskScriptParser {\n    dir: Option<PathBuf>,\n    /// Extra vars to inject into the tera context (for monorepo task vars resolution)\n    extra_vars: Option<IndexMap<String, String>>,\n}\n\nimpl TaskScriptParser {\n    pub fn new(dir: Option<PathBuf>) -> Self {\n        TaskScriptParser {\n            dir,\n            extra_vars: None,\n        }\n    }\n\n    pub fn with_extra_vars(mut self, vars: IndexMap<String, String>) -> Self {\n        self.extra_vars = Some(vars);\n        self\n    }\n\n    fn get_tera(&self) -> tera::Tera {\n        get_tera(self.dir.as_deref())\n    }\n\n    /// Inject extra vars (from monorepo task config hierarchy) into the tera context\n    fn inject_extra_vars(&self, tera_ctx: &mut tera::Context) {\n        if let Some(extra_vars) = &self.extra_vars {\n            // Merge extra_vars (base config-level vars from the config hierarchy) with any\n            // vars already set in the context by task.tera_ctx() (which includes per-task\n            // vars). Per-task vars take precedence over config-level vars.\n            let existing: IndexMap<String, String> = tera_ctx\n                .get(\"vars\")\n                .and_then(|v| serde_json::from_value(v.clone()).ok())\n                .unwrap_or_default();\n            let mut merged = extra_vars.clone();\n            merged.extend(existing);\n            tera_ctx.insert(\"vars\", &merged);\n        }\n    }\n\n    fn render_script_with_context(\n        tera: &mut tera::Tera,\n        script: &str,\n        ctx: &tera::Context,\n    ) -> Result<String> {\n        tera.render_str(script.trim(), ctx)\n            .with_context(|| format!(\"Failed to render task script: {}\", script))\n    }\n\n    fn render_usage_with_context(\n        tera: &mut tera::Tera,\n        usage: &str,\n        ctx: &tera::Context,\n    ) -> Result<String> {\n        tera.render_str(usage.trim(), ctx)\n            .with_context(|| format!(\"Failed to render task usage: {}\", usage))\n    }\n\n    fn check_tera_args_deprecation(\n        task_name: &str,\n        args: &[usage::SpecArg],\n        flags: &[usage::SpecFlag],\n    ) {\n        // Check if any args or flags were defined via Tera templates\n        if args.is_empty() && flags.is_empty() {\n            return;\n        }\n\n        deprecated_at!(\n            \"2026.5.0\",\n            \"2027.5.0\",\n            \"tera_template_task_args\",\n            \"Task '{}' uses deprecated Tera template functions (arg(), option(), flag()) in run scripts. \\\n             Use the 'usage' field instead. See https://mise.jdx.dev/tasks/task-arguments.html\",\n            task_name\n        );\n    }\n\n    // Helper functions for tera error handling\n    fn expect_string(value: &tera::Value, param_name: &str) -> tera::Result<String> {\n        value.as_str().map(|s| s.to_string()).ok_or_else(|| {\n            tera::Error::msg(format!(\n                \"expected string for '{}', got {:?}\",\n                param_name, value\n            ))\n        })\n    }\n\n    fn expect_opt_string(\n        value: Option<&tera::Value>,\n        param_name: &str,\n    ) -> tera::Result<Option<String>> {\n        value\n            .map(|v| Self::expect_string(v, param_name))\n            .transpose()\n    }\n\n    fn expect_opt_bool(\n        value: Option<&tera::Value>,\n        param_name: &str,\n    ) -> tera::Result<Option<bool>> {\n        value.map(|v| Self::expect_bool(v, param_name)).transpose()\n    }\n\n    fn expect_bool(value: &tera::Value, param_name: &str) -> tera::Result<bool> {\n        value.as_bool().ok_or_else(|| {\n            tera::Error::msg(format!(\n                \"expected boolean for '{}', got {:?}\",\n                param_name, value\n            ))\n        })\n    }\n\n    fn expect_i64(value: &tera::Value, param_name: &str) -> tera::Result<i64> {\n        value.as_i64().ok_or_else(|| {\n            tera::Error::msg(format!(\n                \"expected integer for '{}', got {:?}\",\n                param_name, value\n            ))\n        })\n    }\n\n    fn expect_opt_i64(value: Option<&tera::Value>, param_name: &str) -> tera::Result<Option<i64>> {\n        value.map(|v| Self::expect_i64(v, param_name)).transpose()\n    }\n\n    fn expect_array<'a>(\n        value: &'a tera::Value,\n        param_name: &str,\n    ) -> tera::Result<&'a Vec<tera::Value>> {\n        value.as_array().ok_or_else(|| {\n            tera::Error::msg(format!(\n                \"expected array for '{}', got {:?}\",\n                param_name, value\n            ))\n        })\n    }\n\n    fn expect_opt_array<'a>(\n        value: Option<&'a tera::Value>,\n        param_name: &str,\n    ) -> tera::Result<Option<&'a Vec<tera::Value>>> {\n        value.map(|v| Self::expect_array(v, param_name)).transpose()\n    }\n\n    fn lock_error(e: impl std::fmt::Display) -> tera::Error {\n        tera::Error::msg(format!(\"failed to lock: {}\", e))\n    }\n\n    fn setup_tera_for_spec_parsing(&self, task: &Task) -> TeraSpecParsingResult {\n        let mut tera = self.get_tera();\n        let arg_order = Arc::new(Mutex::new(HashMap::new()));\n        let input_args = Arc::new(Mutex::new(vec![]));\n        let input_flags = Arc::new(Mutex::new(vec![]));\n        // override throw function to do nothing\n        tera.register_function(\"throw\", {\n            move |_args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                Ok(tera::Value::Null)\n            }\n        });\n        // render args, options, and flags as null\n        // these functions are only used to collect the spec\n        tera.register_function(\"arg\", {\n            let input_args = input_args.clone();\n            let arg_order = arg_order.clone();\n            move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                let i = Self::expect_i64(\n                    args.get(\"i\").unwrap_or(&tera::Value::from(\n                        input_args.lock().map_err(Self::lock_error)?.len(),\n                    )),\n                    \"i\",\n                )? as usize;\n\n                let required =\n                    Self::expect_opt_bool(args.get(\"required\"), \"required\")?.unwrap_or(true);\n                let var = Self::expect_opt_bool(args.get(\"var\"), \"var\")?.unwrap_or(false);\n                let name =\n                    Self::expect_opt_string(args.get(\"name\"), \"name\")?.unwrap_or(i.to_string());\n\n                let mut arg_order = arg_order.lock().map_err(Self::lock_error)?;\n\n                if arg_order.contains_key(&name) {\n                    trace!(\"already seen {name}\");\n                    return Ok(tera::Value::String(\"\".to_string()));\n                }\n                arg_order.insert(name.clone(), i);\n\n                let usage =\n                    Self::expect_opt_string(args.get(\"usage\"), \"usage\")?.unwrap_or_default();\n                let help = Self::expect_opt_string(args.get(\"help\"), \"help\")?;\n                let help_long = Self::expect_opt_string(args.get(\"help_long\"), \"help_long\")?;\n                let help_md = Self::expect_opt_string(args.get(\"help_md\"), \"help_md\")?;\n\n                let var_min =\n                    Self::expect_opt_i64(args.get(\"var_min\"), \"var_min\")?.map(|v| v as usize);\n                let var_max =\n                    Self::expect_opt_i64(args.get(\"var_max\"), \"var_max\")?.map(|v| v as usize);\n\n                let hide = Self::expect_opt_bool(args.get(\"hide\"), \"hide\")?.unwrap_or(false);\n\n                let default = Self::expect_opt_string(args.get(\"default\"), \"default\")?\n                    .map(|s| vec![s])\n                    .unwrap_or_default();\n\n                let choices = Self::expect_opt_array(args.get(\"choices\"), \"choices\")?\n                    .map(|array| {\n                        tera::Result::Ok(usage::SpecChoices {\n                            choices: array\n                                .iter()\n                                .map(|v| Self::expect_string(v, \"choice\"))\n                                .collect::<Result<Vec<String>, tera::Error>>()?,\n                        })\n                    })\n                    .transpose()?;\n\n                let env = Self::expect_opt_string(args.get(\"env\"), \"env\")?;\n\n                let help_first_line = match &help {\n                    Some(h) => {\n                        if h.is_empty() {\n                            None\n                        } else {\n                            h.lines().next().map(|line| line.to_string())\n                        }\n                    }\n                    None => None,\n                };\n\n                let mut arg = usage::SpecArg {\n                    name: name.clone(),\n                    usage,\n                    help_first_line,\n                    help,\n                    help_long,\n                    help_md,\n                    required,\n                    var,\n                    var_min,\n                    var_max,\n                    hide,\n                    default,\n                    choices,\n                    env,\n                    ..Default::default()\n                };\n                arg.usage = arg.usage();\n\n                input_args.lock().map_err(Self::lock_error)?.push(arg);\n                Ok(tera::Value::String(\"\".to_string()))\n            }\n        });\n\n        tera.register_function(\"option\", {\n            let input_flags = input_flags.clone();\n            move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                let name = match args.get(\"name\") {\n                    Some(n) => Self::expect_string(n, \"name\")?,\n                    None => return Err(tera::Error::msg(\"missing required 'name' parameter\")),\n                };\n\n                let short = args\n                    .get(\"short\")\n                    .map(|s| s.to_string().chars().collect())\n                    .unwrap_or_default();\n\n                let long = match args.get(\"long\") {\n                    Some(l) => {\n                        let s = Self::expect_string(l, \"long\")?;\n                        s.split_whitespace().map(|s| s.to_string()).collect()\n                    }\n                    None => vec![name.clone()],\n                };\n\n                let default = Self::expect_opt_string(args.get(\"default\"), \"default\")?\n                    .map(|s| vec![s])\n                    .unwrap_or_default();\n\n                let var = Self::expect_opt_bool(args.get(\"var\"), \"var\")?.unwrap_or(false);\n\n                let deprecated = Self::expect_opt_string(args.get(\"deprecated\"), \"deprecated\")?;\n                let help = Self::expect_opt_string(args.get(\"help\"), \"help\")?;\n                let help_long = Self::expect_opt_string(args.get(\"help_long\"), \"help_long\")?;\n                let help_md = Self::expect_opt_string(args.get(\"help_md\"), \"help_md\")?;\n\n                let hide = Self::expect_opt_bool(args.get(\"hide\"), \"hide\")?.unwrap_or(false);\n\n                let global = Self::expect_opt_bool(args.get(\"global\"), \"global\")?.unwrap_or(false);\n\n                let count = Self::expect_opt_bool(args.get(\"count\"), \"count\")?.unwrap_or(false);\n\n                let usage =\n                    Self::expect_opt_string(args.get(\"usage\"), \"usage\")?.unwrap_or_default();\n\n                let required =\n                    Self::expect_opt_bool(args.get(\"required\"), \"required\")?.unwrap_or(false);\n\n                let negate = Self::expect_opt_string(args.get(\"negate\"), \"negate\")?;\n\n                let choices = match args.get(\"choices\") {\n                    Some(c) => {\n                        let array = Self::expect_array(c, \"choices\")?;\n                        let mut choices_vec = Vec::new();\n                        for choice in array {\n                            let s = Self::expect_string(choice, \"choice\")?;\n                            choices_vec.push(s);\n                        }\n                        Some(usage::SpecChoices {\n                            choices: choices_vec,\n                        })\n                    }\n                    None => None,\n                };\n\n                let env = Self::expect_opt_string(args.get(\"env\"), \"env\")?;\n\n                let help_first_line = match &help {\n                    Some(h) => {\n                        if h.is_empty() {\n                            None\n                        } else {\n                            h.lines().next().map(|line| line.to_string())\n                        }\n                    }\n                    None => None,\n                };\n\n                let mut flag = usage::SpecFlag {\n                    name: name.clone(),\n                    short,\n                    long,\n                    default,\n                    var,\n                    var_min: None,\n                    var_max: None,\n                    hide,\n                    global,\n                    count,\n                    deprecated,\n                    help_first_line,\n                    help,\n                    usage,\n                    help_long,\n                    help_md,\n                    required,\n                    negate,\n                    env: env.clone(),\n                    arg: Some(usage::SpecArg {\n                        name: name.clone(),\n                        var,\n                        choices,\n                        env,\n                        ..Default::default()\n                    }),\n                };\n                flag.usage = flag.usage();\n\n                input_flags.lock().map_err(Self::lock_error)?.push(flag);\n\n                Ok(tera::Value::String(\"\".to_string()))\n            }\n        });\n\n        tera.register_function(\"flag\", {\n            let input_flags = input_flags.clone();\n            move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                let name = match args.get(\"name\") {\n                    Some(n) => Self::expect_string(n, \"name\")?,\n                    None => return Err(tera::Error::msg(\"missing required 'name' parameter\")),\n                };\n\n                let short = args\n                    .get(\"short\")\n                    .map(|s| s.to_string().chars().collect())\n                    .unwrap_or_default();\n\n                let long = match args.get(\"long\") {\n                    Some(l) => {\n                        let s = Self::expect_string(l, \"long\")?;\n                        s.split_whitespace().map(|s| s.to_string()).collect()\n                    }\n                    None => vec![name.clone()],\n                };\n\n                let default = Self::expect_opt_string(args.get(\"default\"), \"default\")?\n                    .map(|s| vec![s])\n                    .unwrap_or_default();\n\n                let var = Self::expect_opt_bool(args.get(\"var\"), \"var\")?.unwrap_or(false);\n\n                let deprecated = Self::expect_opt_string(args.get(\"deprecated\"), \"deprecated\")?;\n                let help = Self::expect_opt_string(args.get(\"help\"), \"help\")?;\n                let help_long = Self::expect_opt_string(args.get(\"help_long\"), \"help_long\")?;\n                let help_md = Self::expect_opt_string(args.get(\"help_md\"), \"help_md\")?;\n\n                let hide = Self::expect_opt_bool(args.get(\"hide\"), \"hide\")?.unwrap_or(false);\n\n                let global = Self::expect_opt_bool(args.get(\"global\"), \"global\")?.unwrap_or(false);\n\n                let count = Self::expect_opt_bool(args.get(\"count\"), \"count\")?.unwrap_or(false);\n\n                let usage =\n                    Self::expect_opt_string(args.get(\"usage\"), \"usage\")?.unwrap_or_default();\n\n                let required =\n                    Self::expect_opt_bool(args.get(\"required\"), \"required\")?.unwrap_or(false);\n\n                let negate = Self::expect_opt_string(args.get(\"negate\"), \"negate\")?;\n\n                let choices = match args.get(\"choices\") {\n                    Some(c) => {\n                        let array = Self::expect_array(c, \"choices\")?;\n                        let mut choices_vec = Vec::new();\n                        for choice in array {\n                            let s = Self::expect_string(choice, \"choice\")?;\n                            choices_vec.push(s);\n                        }\n                        Some(usage::SpecChoices {\n                            choices: choices_vec,\n                        })\n                    }\n                    None => None,\n                };\n\n                let env = Self::expect_opt_string(args.get(\"env\"), \"env\")?;\n\n                let help_first_line = match &help {\n                    Some(h) => {\n                        if h.is_empty() {\n                            None\n                        } else {\n                            h.lines().next().map(|line| line.to_string())\n                        }\n                    }\n                    None => None,\n                };\n\n                // Create SpecArg when any arg-level properties are set (choices, env)\n                // This matches the behavior of option() which always creates SpecArg\n                let arg = if choices.is_some() || env.is_some() {\n                    Some(usage::SpecArg {\n                        name: name.clone(),\n                        var,\n                        choices,\n                        env: env.clone(),\n                        ..Default::default()\n                    })\n                } else {\n                    None\n                };\n\n                let mut flag = usage::SpecFlag {\n                    name: name.clone(),\n                    short,\n                    long,\n                    default,\n                    var,\n                    var_min: None,\n                    var_max: None,\n                    hide,\n                    global,\n                    count,\n                    deprecated,\n                    help_first_line,\n                    help,\n                    usage,\n                    help_long,\n                    help_md,\n                    required,\n                    negate,\n                    env,\n                    arg,\n                };\n                flag.usage = flag.usage();\n\n                input_flags.lock().map_err(Self::lock_error)?.push(flag);\n\n                Ok(tera::Value::String(\"\".to_string()))\n            }\n        });\n\n        tera.register_function(\"task_source_files\", {\n            let sources = Arc::new(task.sources.clone());\n\n            move |_: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n               if sources.is_empty() {\n                   trace!(\"tera::render::resolve_task_sources `task_source_files` called in task with empty sources array\");\n                   return Ok(tera::Value::Array(Default::default()));\n               };\n\n                let mut resolved = Vec::with_capacity(sources.len());\n\n                for pattern in sources.iter() {\n                    // pattern is considered a tera template string if it contains opening tags:\n                    // - \"{#\" for comments\n                    // - \"{{\" for expressions\n                    // - \"{%\" for statements\n                    if pattern.contains(\"{#\") || pattern.contains(\"{{\") || pattern.contains(\"{%\") {\n                        trace!(\n                            \"tera::render::resolve_task_sources including tera template string in resolved task sources: {pattern}\"\n                        );\n                        resolved.push(tera::Value::String(pattern.clone()));\n                        continue;\n                    }\n\n                    match glob::glob_with(\n                        pattern,\n                        glob::MatchOptions {\n                            case_sensitive: false,\n                            require_literal_separator: false,\n                            require_literal_leading_dot: false,\n                        },\n                    ) {\n                        Err(error) => {\n                            warn!(\n                                \"tera::render::resolve_task_sources including '{pattern}' in resolved task sources, ignoring glob parsing error: {error:#?}\"\n                            );\n                            resolved.push(tera::Value::String(pattern.clone()));\n                        }\n                        Ok(expanded) => {\n                            let mut source_found = false;\n\n                            for path in expanded {\n                                source_found = true;\n\n                                match path {\n                                    Ok(path) => {\n                                        let source = path.display();\n                                        trace!(\n                                            \"tera::render::resolve_task_sources resolved source from pattern '{pattern}': {source}\"\n                                        );\n                                        resolved.push(tera::Value::String(source.to_string()));\n                                    }\n                                    Err(error) => {\n                                        let source = error.path().display();\n                                        warn!(\n                                            \"tera::render::resolve_task_sources omitting '{source}' from resolved task sources due to: {:#?}\",\n                                            error.error()\n                                        );\n                                    }\n                                }\n                            }\n\n                            if !source_found {\n                                warn!(\n                                    \"tera::render::resolve_task_sources no source file(s) resolved for pattern: '{pattern}'\"\n                                );\n                            }\n                        }\n                    }\n                }\n\n                Ok(tera::Value::Array(resolved))\n            }\n        });\n\n        (tera, arg_order, input_args, input_flags)\n    }\n\n    pub async fn parse_run_scripts_for_spec_only(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        scripts: &[String],\n    ) -> Result<usage::Spec> {\n        let (mut tera, arg_order, input_args, input_flags) = self.setup_tera_for_spec_parsing(task);\n        let mut tera_ctx = task.tera_ctx(config).await?;\n        // First render the usage field to collect the spec\n        let rendered_usage = Self::render_usage_with_context(&mut tera, &task.usage, &tera_ctx)?;\n        let spec_from_field: usage::Spec = rendered_usage.parse()?;\n\n        if Settings::get().task.disable_spec_from_run_scripts {\n            return Ok(spec_from_field);\n        }\n\n        // Make the arg/flag names available as snake_case in the template context, using\n        // default values from the spec (or sensible fallbacks when no default is provided).\n        let usage_ctx = Self::make_usage_ctx_from_spec_defaults(&spec_from_field);\n        tera_ctx.insert(\"usage\", &usage_ctx);\n\n        // Don't insert env for spec-only parsing to avoid expensive environment rendering\n        // Render scripts to trigger spec collection via Tera template functions\n        // (arg/option/flag), but discard the results. Ignore rendering errors since we only\n        // care about collecting arg/flag definitions from the deprecated Tera syntax.\n        for script in scripts {\n            let _ = Self::render_script_with_context(&mut tera, script, &tera_ctx);\n        }\n        let mut cmd = usage::SpecCommand::default();\n        // TODO: ensure no gaps in args, e.g.: 1,2,3,4,5\n        let arg_order = arg_order.lock().unwrap();\n        cmd.args = input_args\n            .lock()\n            .unwrap()\n            .iter()\n            .cloned()\n            .sorted_by_key(|arg| {\n                arg_order\n                    .get(&arg.name)\n                    .unwrap_or_else(|| panic!(\"missing arg order for {}\", arg.name.as_str()))\n            })\n            .collect();\n        cmd.flags = input_flags.lock().unwrap().clone();\n\n        // Check for deprecated Tera template args usage\n        Self::check_tera_args_deprecation(&task.name, &cmd.args, &cmd.flags);\n\n        let mut spec = usage::Spec {\n            cmd,\n            ..Default::default()\n        };\n        spec.merge(spec_from_field);\n\n        Ok(spec)\n    }\n\n    pub async fn parse_run_scripts(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        scripts: &[String],\n        env: &EnvMap,\n    ) -> Result<(Vec<String>, usage::Spec)> {\n        let (mut tera, arg_order, input_args, input_flags) = self.setup_tera_for_spec_parsing(task);\n        let mut tera_ctx = task.tera_ctx(config).await?;\n        self.inject_extra_vars(&mut tera_ctx);\n        tera_ctx.insert(\"env\", &env);\n        // First render the usage field to collect the spec and build a default\n        // usage map, so that `{{ usage.* }}` references in run scripts do not\n        // fail during this initial parsing phase (e.g. for inline tasks).\n        let rendered_usage = Self::render_usage_with_context(&mut tera, &task.usage, &tera_ctx)?;\n        let spec_from_field: usage::Spec = rendered_usage.parse()?;\n        let usage_ctx = Self::make_usage_ctx_from_spec_defaults(&spec_from_field);\n        tera_ctx.insert(\"usage\", &usage_ctx);\n\n        let scripts = scripts\n            .iter()\n            .map(|s| Self::render_script_with_context(&mut tera, s, &tera_ctx))\n            .collect::<Result<Vec<String>>>()?;\n        let mut cmd = usage::SpecCommand::default();\n        // TODO: ensure no gaps in args, e.g.: 1,2,3,4,5\n        let arg_order = arg_order.lock().unwrap();\n        cmd.args = input_args\n            .lock()\n            .unwrap()\n            .iter()\n            .cloned()\n            .sorted_by_key(|arg| {\n                arg_order\n                    .get(&arg.name)\n                    .unwrap_or_else(|| panic!(\"missing arg order for {}\", arg.name.as_str()))\n            })\n            .collect();\n        cmd.flags = input_flags.lock().unwrap().clone();\n\n        // Check for deprecated Tera template args usage\n        Self::check_tera_args_deprecation(&task.name, &cmd.args, &cmd.flags);\n        let mut spec = usage::Spec {\n            cmd,\n            ..Default::default()\n        };\n        spec.merge(spec_from_field);\n\n        Ok((scripts, spec))\n    }\n\n    pub async fn parse_run_scripts_with_args(\n        &self,\n        config: &Arc<Config>,\n        task: &Task,\n        scripts: &[String],\n        env: &EnvMap,\n        args: &[String],\n        spec: &usage::Spec,\n    ) -> Result<Vec<String>> {\n        let args = vec![\"\".to_string()]\n            .into_iter()\n            .chain(args.iter().cloned())\n            .collect::<Vec<_>>();\n        // Pass env vars to Parser so it can resolve env= defaults in usage specs\n        // This is needed for monorepo tasks where child config env vars aren't in the process env\n        let env_map: std::collections::HashMap<String, String> =\n            env.iter().map(|(k, v)| (k.clone(), v.clone())).collect();\n        let m = match usage::Parser::new(spec).with_env(env_map).parse(&args) {\n            Ok(m) => m,\n            Err(e) => {\n                // just print exactly what usage returns so the error output isn't double-wrapped\n                // this could be displaying help or a parse error\n                eprintln!(\"{}\", format!(\"{e}\").trim_end());\n                exit(1);\n            }\n        };\n\n        let mut out: Vec<String> = vec![];\n        for script in scripts {\n            let shell_type = shell_from_shebang(script)\n                .or(task.shell())\n                .unwrap_or(Settings::get().default_inline_shell()?)[0]\n                .parse()\n                .ok();\n            let escape = {\n                move |v: &usage::parse::ParseValue| match v {\n                    usage::parse::ParseValue::MultiString(_) => {\n                        // these are already escaped\n                        v.to_string()\n                    }\n                    _ => match shell_type {\n                        Some(ShellType::Zsh | ShellType::Bash | ShellType::Fish) => {\n                            shell_words::quote(&v.to_string()).to_string()\n                        }\n                        _ => v.to_string(),\n                    },\n                }\n            };\n            let mut tera = self.get_tera();\n            tera.register_function(\"arg\", {\n                {\n                    let usage_args = m.args.clone();\n                    move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                        let seen_args = Arc::new(Mutex::new(HashSet::new()));\n                        {\n                            let mut seen_args = seen_args.lock().unwrap();\n                            let i = args\n                                .get(\"i\")\n                                .map(|i| i.as_i64().unwrap() as usize)\n                                .unwrap_or_else(|| seen_args.len());\n                            let name = args\n                                .get(\"name\")\n                                .map(|n| n.as_str().unwrap().to_string())\n                                .unwrap_or(i.to_string());\n                            seen_args.insert(name.clone());\n                            Ok(tera::Value::String(\n                                usage_args\n                                    .iter()\n                                    .find(|(arg, _)| arg.name == name)\n                                    .map(|(_, value)| escape(value))\n                                    .unwrap_or(\"\".to_string()),\n                            ))\n                        }\n                    }\n                }\n            });\n            let flag_func = {\n                |default_value: String| {\n                    let usage_flags = m.flags.clone();\n                    move |args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {\n                        let name = args\n                            .get(\"name\")\n                            .map(|n| n.as_str().unwrap().to_string())\n                            .unwrap();\n                        Ok(tera::Value::String(\n                            usage_flags\n                                .iter()\n                                .find(|(flag, _)| flag.name == name)\n                                .map(|(_, value)| escape(value))\n                                .unwrap_or(default_value.clone()),\n                        ))\n                    }\n                }\n            };\n            tera.register_function(\"option\", flag_func(\"\".to_string()));\n            tera.register_function(\"flag\", flag_func(false.to_string()));\n            let mut tera_ctx = task.tera_ctx(config).await?;\n            self.inject_extra_vars(&mut tera_ctx);\n            tera_ctx.insert(\"env\", &env);\n            tera_ctx.insert(\"usage\", &Self::make_usage_ctx(&m));\n            out.push(Self::render_script_with_context(\n                &mut tera, script, &tera_ctx,\n            )?);\n        }\n        Ok(out)\n    }\n\n    fn make_usage_ctx(usage: &usage::parse::ParseOutput) -> HashMap<String, tera::Value> {\n        let mut usage_ctx: HashMap<String, tera::Value> = HashMap::new();\n\n        // These values are not escaped or shell-quoted.\n        let to_tera_value = |val: &usage::parse::ParseValue| -> tera::Value {\n            use tera::Value;\n            use usage::parse::ParseValue::*;\n            match val {\n                MultiBool(v) => Value::Array(v.iter().map(|b| Value::Bool(*b)).collect()),\n                MultiString(v) => {\n                    Value::Array(v.iter().map(|s| Value::String(s.clone())).collect())\n                }\n                Bool(v) => Value::Bool(*v),\n                String(v) => Value::String(v.clone()),\n            }\n        };\n\n        // The names are converted to snake_case (hyphens become underscores).\n        // For example, a flag like \"--dry-run\" becomes accessible as {{ usage.dry_run }}.\n        for (arg, val) in &usage.args {\n            let tera_val = to_tera_value(val);\n            usage_ctx.insert(arg.name.to_snake_case(), tera_val);\n        }\n        for (flag, val) in &usage.flags {\n            let tera_val = to_tera_value(val);\n            usage_ctx.insert(flag.name.to_snake_case(), tera_val);\n        }\n        usage_ctx\n    }\n\n    /// Build a usage context hashmap from a `usage::Spec`, using default values\n    /// defined in the spec or sensible fallbacks when no defaults are provided.\n    /// Only needed for deprecated parsing of run scripts for collecting the spec.\n    ///\n    /// - Args:\n    ///   - Non-var args use an empty string.\n    ///   - Var args use an empty array.\n    /// - Flags:\n    ///   - Value flags (`var = true`) use an empty array.\n    ///   - Count flags (`count = true`) use a `Vec<bool>` whose length is\n    ///     derived from the default (parsed as a usize) or an empty array.\n    ///   - Simple flags use `false`.\n    pub fn make_usage_ctx_from_spec_defaults(spec: &usage::Spec) -> HashMap<String, tera::Value> {\n        let mut usage_ctx: HashMap<String, tera::Value> = HashMap::new();\n\n        // Args\n        for arg in &spec.cmd.args {\n            let name = arg.name.to_snake_case();\n            let value = if arg.var {\n                // Variadic args are arrays (possibly with defaults)\n                let defaults: Vec<tera::Value> = arg\n                    .default\n                    .iter()\n                    .map(|s| tera::Value::String(s.clone()))\n                    .collect();\n                tera::Value::Array(defaults)\n            } else if let Some(default) = arg.default.first() {\n                tera::Value::String(default.clone())\n            } else {\n                tera::Value::String(String::new())\n            };\n            usage_ctx.insert(name, value);\n        }\n\n        // Flags\n        for flag in &spec.cmd.flags {\n            let name = flag.name.to_snake_case();\n            let value = if flag.var {\n                // Variadic flags are arrays (possibly with defaults)\n                let defaults: Vec<tera::Value> = flag\n                    .default\n                    .iter()\n                    .map(|s| tera::Value::String(s.clone()))\n                    .collect();\n                tera::Value::Array(defaults)\n            } else if flag.count {\n                // Count flags: represent as an array of bools\n                tera::Value::Array(Vec::new())\n            } else if let Some(default) = flag.default.first() {\n                // if it is not parseable as a boolean, treat it as a string\n                default\n                    .parse::<bool>()\n                    .map_or_else(|_| tera::Value::String(default.clone()), tera::Value::Bool)\n            } else {\n                tera::Value::Bool(false)\n            };\n            usage_ctx.insert(name, value);\n        }\n\n        usage_ctx\n    }\n}\n\npub fn has_any_args_defined(spec: &usage::Spec) -> bool {\n    !spec.cmd.args.is_empty() || !spec.cmd.flags.is_empty()\n}\n\nfn shell_from_shebang(script: &str) -> Option<Vec<String>> {\n    let shebang = script.lines().next()?.strip_prefix(\"#!\")?;\n    let shebang = shebang.strip_prefix(\"/usr/bin/env -S\").unwrap_or(shebang);\n    let shebang = shebang.strip_prefix(\"/usr/bin/env\").unwrap_or(shebang);\n    let mut parts = shebang.split_whitespace();\n    let shell = parts.next()?;\n    let args = parts.map(|s| s.to_string()).collect_vec();\n    Some(once(shell.to_string()).chain(args).collect())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use pretty_assertions::assert_eq;\n\n    #[tokio::test]\n    async fn test_task_parse_arg() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\"echo {{ arg(i=0, name='foo') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let arg0 = spec.cmd.args.first().unwrap();\n        assert_eq!(arg0.name, \"foo\");\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &Default::default(),\n                &[\"abc\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo abc\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_multi_use_arg() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\n            \"echo {{ arg(name='foo') }}; echo {{ arg(name='bar') }}; echo {{ arg(name='foo') }}\"\n                .to_string(),\n        ];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo ; echo ; echo \"]);\n        let arg0 = spec.cmd.args.first().unwrap();\n        let arg1 = spec.cmd.args.get(1).unwrap();\n        assert_eq!(arg0.name, \"foo\");\n        assert_eq!(arg1.name, \"bar\");\n        assert_eq!(spec.cmd.args.len(), 2);\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &Default::default(),\n                &[\"abc\".to_string(), \"def\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo abc; echo def; echo abc\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_arg_var() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\"echo {{ arg(var=true) }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let arg0 = spec.cmd.args.first().unwrap();\n        assert_eq!(arg0.name, \"0\");\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &Default::default(),\n                &[\"abc\".to_string(), \"def\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo abc def\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_flag() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\"echo {{ flag(name='foo') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let flag = spec.cmd.flags.iter().find(|f| &f.name == \"foo\").unwrap();\n        assert_eq!(&flag.name, \"foo\");\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &Default::default(),\n                &[\"--foo\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo true\"]);\n\n        let scripts = vec![\"echo {{ flag(name='foo') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(&config, &task, &scripts, &Default::default(), &[], &spec)\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo false\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_option() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\"echo {{ option(name='foo') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let option = spec.cmd.flags.iter().find(|f| &f.name == \"foo\").unwrap();\n        assert_eq!(&option.name, \"foo\");\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &Default::default(),\n                &[\"--foo\".to_string(), \"abc\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo abc\"]);\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(&config, &task, &scripts, &Default::default(), &[], &spec)\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_nested_template() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts =\n            vec![\"echo {% if flag(name=env.FLAG_NAME) == 'true' %}TRUE{% endif %}\".to_string()];\n        let env = EnvMap::from_iter(vec![(\"FLAG_NAME\".to_string(), \"foo\".to_string())]);\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &env)\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let flag = spec.cmd.flags.first().unwrap();\n        assert_eq!(&flag.name, \"foo\");\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts,\n                &env,\n                &[\"--foo\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo TRUE\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_empty_help() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n\n        // Test with empty help string for arg\n        let scripts = vec![\"echo {{ arg(name='foo', help='') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let arg = spec.cmd.args.first().unwrap();\n        assert_eq!(arg.name, \"foo\");\n        assert_eq!(arg.help, Some(\"\".to_string()));\n        assert_eq!(arg.help_first_line, None);\n\n        // Test with empty help string for option\n        let scripts = vec![\"echo {{ option(name='bar', help='') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let option = spec.cmd.flags.iter().find(|f| &f.name == \"bar\").unwrap();\n        assert_eq!(&option.name, \"bar\");\n        assert_eq!(option.help, Some(\"\".to_string()));\n        assert_eq!(option.help_first_line, None);\n\n        // Test with empty help string for flag\n        let scripts = vec![\"echo {{ flag(name='baz', help='') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let flag = spec.cmd.flags.iter().find(|f| &f.name == \"baz\").unwrap();\n        assert_eq!(&flag.name, \"baz\");\n        assert_eq!(flag.help, Some(\"\".to_string()));\n        assert_eq!(flag.help_first_line, None);\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_option_env() {\n        let config = Config::get().await.unwrap();\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n        let scripts = vec![\"echo {{ option(name='profile', env='BUILD_PROFILE') }}\".to_string()];\n        let (parsed_scripts, spec) = parser\n            .parse_run_scripts(&config, &task, &scripts, &Default::default())\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo \"]);\n        let option = spec\n            .cmd\n            .flags\n            .iter()\n            .find(|f| &f.name == \"profile\")\n            .unwrap();\n        assert_eq!(&option.name, \"profile\");\n        assert_eq!(option.env, Some(\"BUILD_PROFILE\".to_string()));\n        // Verify the nested SpecArg also has the env field set\n        let arg = option.arg.as_ref().unwrap();\n        assert_eq!(arg.env, Some(\"BUILD_PROFILE\".to_string()));\n    }\n\n    #[tokio::test]\n    async fn test_task_parse_task_source_files() {\n        let cases: &[(&[&str], &str, &str)] = &[\n            (&[], \"echo {{ task_source_files() }}\", \"echo []\"),\n            (\n                &[\"**/filetask\"],\n                \"echo {{ task_source_files() | first }}\",\n                \"echo .mise/tasks/filetask\", // created by constructor in `src/test.rs`, guaranteed to exist\n            ),\n            (\n                &[\"nonexistent/*.xyz\"],\n                \"echo {{ task_source_files() }}\",\n                \"echo []\",\n            ),\n            (\n                &[\"../../Cargo.toml\"],\n                \"echo {{ task_source_files() | first }}\",\n                \"echo ../../Cargo.toml\",\n            ),\n            (\n                &[concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/Cargo.toml\")],\n                \"echo {{ task_source_files() | first }}\",\n                concat!(\"echo \", env!(\"CARGO_MANIFEST_DIR\"), \"/Cargo.toml\"),\n            ),\n            #[cfg(not(windows))] // TODO: this cases panics on windows currently\n            (\n                &[\"{{ env.HOME }}/file.txt\", \"src/*.rs\"],\n                \"echo {{ task_source_files() | first }}\",\n                \"echo {{ env.HOME }}/file.txt\",\n            ),\n            (\n                &[\"[invalid\"],\n                \"echo {{ task_source_files() | first }}\",\n                \"echo [invalid\",\n            ),\n            (\n                &[\n                    concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/Cargo.toml\"),\n                    concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/README.md\"),\n                ],\n                \"{% for file in task_source_files() %}echo {{ file }}; {% endfor %}\",\n                concat!(\n                    \"echo \",\n                    env!(\"CARGO_MANIFEST_DIR\"),\n                    \"/Cargo.toml; echo \",\n                    env!(\"CARGO_MANIFEST_DIR\"),\n                    \"/README.md; \",\n                ),\n            ),\n        ];\n\n        for (sources, template, expected) in cases {\n            let (sources, template, expected) = (*sources, *template, *expected);\n\n            let (mut task, scripts, parser, config) = (\n                Task::default(),\n                vec![template.into()],\n                TaskScriptParser::new(None),\n                Config::get().await.unwrap(),\n            );\n\n            task.sources = sources.iter().map(ToString::to_string).collect();\n\n            let (parsed, _) = parser\n                .parse_run_scripts(&config, &task, &scripts, &Default::default())\n                .await\n                .unwrap();\n\n            #[cfg(windows)]\n            let expected = expected.replace(\"/\", r\"\\\"); // 🙄\n\n            assert_eq!(parsed, vec![expected]);\n        }\n    }\n\n    #[tokio::test]\n    async fn test_task_usage_hashmap() {\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n\n        // Manually construct a spec with one arg (\"foo\") and one flag (\"bar\")\n        // so this test does not rely on run-script parsing.\n        let mut cmd = usage::SpecCommand::default();\n        cmd.args.push(usage::SpecArg {\n            name: \"foo\".to_string(),\n            ..Default::default()\n        });\n        cmd.flags.push(usage::SpecFlag {\n            name: \"bar\".to_string(),\n            // Ensure the flag is recognized as `--bar` by the usage parser\n            long: vec![\"bar\".to_string()],\n            ..Default::default()\n        });\n        let spec = usage::Spec {\n            cmd,\n            ..Default::default()\n        };\n\n        let config = Config::get().await.unwrap();\n\n        // Now test that the usage hashmap is accessible in templates when values are provided\n        let scripts_with_usage = vec![\"echo arg:{{ usage.foo }} flag:{{ usage.bar }}\".to_string()];\n\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts_with_usage,\n                &Default::default(),\n                &[\"test_value\".to_string(), \"--bar\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n\n        // The usage hashmap should contain the parsed values\n        // For a string arg, it should be \"test_value\"\n        // For a bool flag, it should be \"true\"\n        assert_eq!(parsed_scripts, vec![\"echo arg:test_value flag:true\"]);\n\n        // Test without the flag – usage.foo should still be available, but usage.bar\n        // should be undefined (accessing it in the template would error), so we only\n        // reference usage.foo here.\n        let scripts_with_usage_arg_only = vec![\"echo arg:{{ usage.foo }}\".to_string()];\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts_with_usage_arg_only,\n                &Default::default(),\n                &[\"test_value2\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n\n        assert_eq!(parsed_scripts, vec![\"echo arg:test_value2\"]);\n\n        // Negative case: referencing an undefined usage flag should cause rendering to fail\n        let scripts_with_missing_flag = vec![\"echo flag:{{ usage.bar }}\".to_string()];\n        let result = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts_with_missing_flag,\n                &Default::default(),\n                &[\"only_arg_value\".to_string()], // no --bar flag provided\n                &spec,\n            )\n            .await;\n        assert!(\n            result.is_err(),\n            \"expected parsing to fail when template references usage.bar but flag was not provided\"\n        );\n        // Need to explicitly set default value for flags to avoid errors when accessing undefined usage flags\n        // If a default value is set in the usage spec, referencing the flag in the script should not error,\n        // and the value should be the default when the flag is not provided.\n        let mut spec_with_default_flag = spec.clone();\n        if let Some(bar_flag) = spec_with_default_flag\n            .cmd\n            .flags\n            .iter_mut()\n            .find(|f| f.name == \"bar\")\n        {\n            bar_flag.default = vec![\"false\".to_string()];\n        }\n        // Now referencing usage.bar should render successfully, resolving to the default\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts_with_missing_flag,\n                &Default::default(),\n                &[\"only_arg_value\".to_string()],\n                &spec_with_default_flag,\n            )\n            .await\n            .unwrap();\n        assert_eq!(parsed_scripts, vec![\"echo flag:false\"]);\n    }\n\n    #[tokio::test]\n    async fn test_task_usage_multistring() {\n        let task = Task::default();\n        let parser = TaskScriptParser::new(None);\n\n        // Manually construct a spec with a var=true arg so usage-lib will produce a MultiString value\n        let mut cmd = usage::SpecCommand::default();\n        cmd.args.push(usage::SpecArg {\n            name: \"tags\".to_string(),\n            var: true,\n            ..Default::default()\n        });\n        let spec = usage::Spec {\n            cmd,\n            ..Default::default()\n        };\n\n        let config = Config::get().await.unwrap();\n\n        // The script only uses the usage map, it does not rely on run-script parsing to build the spec\n        let scripts_with_usage = vec![\n            \"echo count={{ usage.tags | length }} first={{ usage.tags[0] }} second={{ usage.tags[1] }}\"\n                .to_string(),\n        ];\n        let parsed_scripts = parser\n            .parse_run_scripts_with_args(\n                &config,\n                &task,\n                &scripts_with_usage,\n                &Default::default(),\n                &[\"one\".to_string(), \"two\".to_string()],\n                &spec,\n            )\n            .await\n            .unwrap();\n\n        assert_eq!(\n            parsed_scripts,\n            vec![\"echo count=2 first=one second=two\"],\n            \"expected MultiString arg to be exposed as an array in the usage map\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/task/task_source_checker.rs",
    "content": "use crate::config::{Config, Settings};\nuse crate::dirs;\nuse crate::file::{self, display_path};\nuse crate::hash;\nuse crate::task::Task;\nuse eyre::{Result, eyre};\nuse glob::glob;\nuse itertools::Itertools;\nuse std::collections::BTreeMap;\nuse std::fs;\nuse std::hash::{DefaultHasher, Hash, Hasher};\nuse std::path::{Path, PathBuf};\nuse std::sync::Arc;\nuse std::time::{SystemTime, UNIX_EPOCH};\n\n/// Check if a path is a glob pattern\npub fn is_glob_pattern(path: &str) -> bool {\n    // This is the character set used for glob detection by glob\n    let glob_chars = ['*', '{', '}'];\n    path.chars().any(|c| glob_chars.contains(&c))\n}\n\n/// Get the last modified time from a list of paths\npub(crate) fn last_modified_path(root: &Path, paths: &[&String]) -> Result<Option<SystemTime>> {\n    let files = paths.iter().map(|p| {\n        let base = Path::new(p);\n        if base.is_relative() {\n            Path::new(&root).join(base)\n        } else {\n            base.to_path_buf()\n        }\n    });\n\n    last_modified_file(files)\n}\n\n/// Get the last modified time from files matching glob patterns\npub(crate) fn last_modified_glob_match(\n    root: impl AsRef<Path>,\n    patterns: &[&String],\n) -> Result<Option<SystemTime>> {\n    if patterns.is_empty() {\n        return Ok(None);\n    }\n    let files = patterns\n        .iter()\n        .flat_map(|pattern| {\n            glob(\n                root.as_ref()\n                    .join(pattern)\n                    .to_str()\n                    .expect(\"Conversion to string path failed\"),\n            )\n            .unwrap()\n        })\n        .filter_map(|e| e.ok())\n        .filter(|e| {\n            e.metadata()\n                .expect(\"Metadata call failed\")\n                .file_type()\n                .is_file()\n        });\n\n    last_modified_file(files)\n}\n\n/// Get the last modified time from an iterator of file paths\npub(crate) fn last_modified_file(\n    files: impl IntoIterator<Item = PathBuf>,\n) -> Result<Option<SystemTime>> {\n    Ok(files\n        .into_iter()\n        .unique()\n        .filter(|p| p.exists())\n        .map(|p| {\n            p.metadata()\n                .map_err(|err| eyre!(\"{}: {}\", display_path(p), err))\n        })\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .map(|m| m.modified().map_err(|err| eyre!(err)))\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .max())\n}\n\n/// Get the working directory for a task\npub async fn task_cwd(task: &Task, config: &Arc<Config>) -> Result<PathBuf> {\n    if let Some(d) = task.dir(config).await? {\n        Ok(d)\n    } else {\n        Ok(config\n            .project_root\n            .clone()\n            .or_else(|| dirs::CWD.clone())\n            .unwrap_or_default())\n    }\n}\n\n/// Check if task sources are up to date (fresher than outputs)\npub async fn sources_are_fresh(task: &Task, config: &Arc<Config>) -> Result<bool> {\n    if task.sources.is_empty() {\n        return Ok(false);\n    }\n    let settings = Settings::get();\n    let use_content_hash = settings.task.source_freshness_hash_contents;\n    let equal_mtime_is_fresh = settings.task.source_freshness_equal_mtime_is_fresh;\n\n    // TODO: We should benchmark this and find out if it might be possible to do some caching around this or something\n    // perhaps using some manifest in a state directory or something, maybe leveraging atime?\n    let run = async || -> Result<bool> {\n        let root = task_cwd(task, config).await?;\n        let mut sources = task.sources.clone();\n        sources.push(task.config_source.to_string_lossy().to_string());\n        let source_metadatas = get_file_metadatas(&root, &sources)?;\n\n        // Check if sources resolved to no files (likely a config mistake)\n        if source_metadatas.is_empty() {\n            warn!(\n                \"task {} has sources defined but no matching files found\",\n                task.name\n            );\n            return Ok(false);\n        }\n\n        // Check for epoch timestamps (files extracted from tarballs without preserved timestamps)\n        // These are considered stale since we can't trust the mtime\n        for (path, metadata) in &source_metadatas {\n            if let Ok(mtime) = metadata.modified()\n                && mtime == UNIX_EPOCH\n            {\n                debug!(\n                    \"source file {} has epoch timestamp, treating as stale\",\n                    display_path(path)\n                );\n                return Ok(false);\n            }\n        }\n\n        let source_hash = if use_content_hash {\n            file_contents_to_hash(&source_metadatas)?\n        } else {\n            file_metadatas_to_hash(&source_metadatas)\n        };\n        let source_hash_path = sources_hash_path(task, &root, use_content_hash);\n        if let Some(dir) = source_hash_path.parent() {\n            file::create_dir_all(dir)?;\n        }\n        if source_existing_hash(task, &root, use_content_hash).is_some_and(|h| h != source_hash) {\n            debug!(\n                \"source {} hash mismatch in {}\",\n                if use_content_hash {\n                    \"content\"\n                } else {\n                    \"metadata\"\n                },\n                source_hash_path.display()\n            );\n            file::write(&source_hash_path, &source_hash)?;\n            return Ok(false);\n        }\n        let sources = get_last_modified_from_metadatas(&source_metadatas);\n        let outputs = get_last_modified(&root, &task.outputs.paths(task, &root))?;\n        file::write(&source_hash_path, &source_hash)?;\n        trace!(\"sources: {sources:?}, outputs: {outputs:?}\");\n        match (sources, outputs) {\n            (Some(sources), Some(outputs)) => {\n                if equal_mtime_is_fresh {\n                    Ok(sources <= outputs)\n                } else {\n                    Ok(sources < outputs)\n                }\n            }\n            _ => Ok(false),\n        }\n    };\n    Ok(run().await.unwrap_or_else(|err| {\n        warn!(\"sources_are_fresh: {err:?}\");\n        false\n    }))\n}\n\n/// Save a checksum file after a task completes successfully\npub async fn save_checksum(task: &Task, config: &Arc<Config>) -> Result<()> {\n    if task.sources.is_empty() {\n        return Ok(());\n    }\n    if task.outputs.is_auto() {\n        let root = task_cwd(task, config).await?;\n        for p in task.outputs.paths(task, &root) {\n            debug!(\"touching auto output file: {p}\");\n            file::touch_file(&PathBuf::from(&p))?;\n        }\n    } else {\n        // Check if explicitly defined outputs were generated\n        // Use task_cwd to respect the task's dir setting, matching sources_are_fresh behavior\n        let root = task_cwd(task, config).await?;\n        for output in task.outputs.paths(task, &root) {\n            let output_exists = if is_glob_pattern(&output) {\n                // For glob patterns, check if any files match\n                let pattern = root.join(&output);\n                glob(pattern.to_str().unwrap_or_default())\n                    .map(|paths| paths.flatten().next().is_some())\n                    .unwrap_or(false)\n            } else {\n                // For regular paths, check if file exists\n                let path = Path::new(&output);\n                let full_path = if path.is_relative() {\n                    root.join(path)\n                } else {\n                    path.to_path_buf()\n                };\n                full_path.exists()\n            };\n            if !output_exists {\n                warn!(\n                    \"task {} did not generate expected output: {}\",\n                    task.name, output\n                );\n            }\n        }\n    }\n    Ok(())\n}\n\n/// Get the path to store source hashes for a task\nfn sources_hash_path(task: &Task, root: &Path, content_hash: bool) -> PathBuf {\n    let mut hasher = DefaultHasher::new();\n    task.hash(&mut hasher);\n    task.config_source.hash(&mut hasher);\n    root.hash(&mut hasher);\n    let hash = format!(\"{:x}\", hasher.finish());\n    let suffix = if content_hash { \"-content\" } else { \"\" };\n    dirs::STATE\n        .join(\"task-sources\")\n        .join(format!(\"{hash}{suffix}\"))\n}\n\n/// Get the existing source hash for a task, if it exists\nfn source_existing_hash(task: &Task, root: &Path, content_hash: bool) -> Option<String> {\n    let path = sources_hash_path(task, root, content_hash);\n    if path.exists() {\n        Some(file::read_to_string(&path).unwrap_or_default())\n    } else {\n        None\n    }\n}\n\n/// Get file metadata for a list of patterns or paths\nfn get_file_metadatas(\n    root: &Path,\n    patterns_or_paths: &[String],\n) -> Result<Vec<(PathBuf, fs::Metadata)>> {\n    if patterns_or_paths.is_empty() {\n        return Ok(vec![]);\n    }\n    let (patterns, paths): (Vec<&String>, Vec<&String>) =\n        patterns_or_paths.iter().partition(|p| is_glob_pattern(p));\n\n    let mut metadatas = BTreeMap::new();\n    for pattern in patterns {\n        let files = glob(root.join(pattern).to_str().unwrap())?;\n        for file in files.flatten() {\n            if let Ok(metadata) = file.metadata() {\n                metadatas.insert(file, metadata);\n            }\n        }\n    }\n\n    for path in paths {\n        let file = root.join(path);\n        if let Ok(metadata) = file.metadata() {\n            metadatas.insert(file, metadata);\n        }\n    }\n\n    let metadatas = metadatas\n        .into_iter()\n        .filter(|(_, m)| m.is_file())\n        .collect_vec();\n\n    Ok(metadatas)\n}\n\n/// Convert file metadata to a hash string for comparison\n/// Includes path and file size to detect changes even when mtimes are unreliable\nfn file_metadatas_to_hash(metadatas: &[(PathBuf, fs::Metadata)]) -> String {\n    let path_and_sizes: Vec<_> = metadatas.iter().map(|(p, m)| (p, m.len())).collect();\n    hash::hash_to_str(&path_and_sizes)\n}\n\n/// Convert file contents to a hash string for comparison using blake3\n/// More accurate than metadata hashing but slower since it reads all file contents\nfn file_contents_to_hash(metadatas: &[(PathBuf, fs::Metadata)]) -> Result<String> {\n    let mut content_hashes: Vec<(&PathBuf, String)> = Vec::new();\n    for (path, _) in metadatas {\n        let file_hash = hash::file_hash_blake3(path, None)?;\n        content_hashes.push((path, file_hash));\n    }\n    Ok(hash::hash_to_str(&content_hashes))\n}\n\n/// Get the last modified time from file metadata\nfn get_last_modified_from_metadatas(metadatas: &[(PathBuf, fs::Metadata)]) -> Option<SystemTime> {\n    metadatas.iter().flat_map(|(_, m)| m.modified()).max()\n}\n\n/// Get the last modified time from a list of patterns or paths\nfn get_last_modified(root: &Path, patterns_or_paths: &[String]) -> Result<Option<SystemTime>> {\n    if patterns_or_paths.is_empty() {\n        return Ok(None);\n    }\n    let (patterns, paths): (Vec<&String>, Vec<&String>) =\n        patterns_or_paths.iter().partition(|p| is_glob_pattern(p));\n\n    let last_mod = std::cmp::max(\n        last_modified_glob_match(root, &patterns)?,\n        last_modified_path(root, &paths)?,\n    );\n\n    trace!(\n        \"last_modified of {}: {last_mod:?}\",\n        patterns_or_paths.iter().join(\" \")\n    );\n    Ok(last_mod)\n}\n"
  },
  {
    "path": "src/task/task_sources.rs",
    "content": "use crate::dirs;\nuse crate::task::Task;\nuse serde::ser::{SerializeMap, SerializeSeq};\nuse serde::{Deserialize, Deserializer, Serialize};\nuse std::hash::{DefaultHasher, Hash, Hasher};\nuse std::path::Path;\n\n#[derive(Debug, Clone, Eq, PartialEq, strum::EnumIs)]\npub enum TaskOutputs {\n    Files(Vec<String>),\n    Auto,\n}\n\n/// Stores raw (pre-render) output templates and the original env context so they\n/// can be re-rendered when dependency env overrides are applied after initial rendering.\n#[derive(Debug, Clone, Default)]\npub struct RawOutputTemplates {\n    pub templates: Option<Vec<String>>,\n    pub original_env: Option<std::collections::BTreeMap<String, String>>,\n}\n\nimpl Default for TaskOutputs {\n    fn default() -> Self {\n        TaskOutputs::Files(vec![])\n    }\n}\n\nimpl TaskOutputs {\n    pub fn is_empty(&self) -> bool {\n        match self {\n            TaskOutputs::Files(files) => files.is_empty(),\n            TaskOutputs::Auto => false,\n        }\n    }\n\n    pub fn patterns(&self) -> Vec<String> {\n        match self {\n            TaskOutputs::Files(files) => files.clone(),\n            TaskOutputs::Auto => vec![],\n        }\n    }\n\n    pub fn paths(&self, task: &Task, root: &Path) -> Vec<String> {\n        match self {\n            TaskOutputs::Files(files) => files.clone(),\n            TaskOutputs::Auto => vec![self.auto_path(task, root)],\n        }\n    }\n\n    fn auto_path(&self, task: &Task, root: &Path) -> String {\n        let mut hasher = DefaultHasher::new();\n        task.hash(&mut hasher);\n        task.config_source.hash(&mut hasher);\n        root.hash(&mut hasher);\n        let hash = format!(\"{:x}\", hasher.finish());\n        dirs::STATE\n            .join(\"task-auto-outputs\")\n            .join(&hash)\n            .to_string_lossy()\n            .to_string()\n    }\n\n    pub fn render(\n        &mut self,\n        tera: &mut tera::Tera,\n        ctx: &tera::Context,\n    ) -> eyre::Result<RawOutputTemplates> {\n        match self {\n            TaskOutputs::Files(files) => {\n                let raw = files.clone();\n                let original_env = ctx\n                    .get(\"env\")\n                    .and_then(|v| serde_json::from_value(v.clone()).ok());\n                for file in files.iter_mut() {\n                    *file = tera.render_str(file, ctx)?;\n                }\n                Ok(RawOutputTemplates {\n                    templates: Some(raw),\n                    original_env,\n                })\n            }\n            TaskOutputs::Auto => Ok(RawOutputTemplates::default()),\n        }\n    }\n\n    /// Re-render output templates with additional env vars injected into the\n    /// tera context. Used after dependency env overrides are applied.\n    pub fn re_render_with_env(\n        &mut self,\n        raw: &RawOutputTemplates,\n        env: &indexmap::IndexMap<String, String>,\n        config_root: &std::path::Path,\n    ) -> eyre::Result<()> {\n        if let TaskOutputs::Files(files) = self\n            && let Some(raw_templates) = raw.templates.as_ref()\n        {\n            let mut tera = crate::tera::get_tera(Some(config_root));\n            let mut ctx = tera::Context::new();\n            // Start with original env from initial render, then overlay dependency env\n            let mut env_map = raw.original_env.clone().unwrap_or_default();\n            for (k, v) in env {\n                env_map.insert(k.clone(), v.clone());\n            }\n            ctx.insert(\"env\", &env_map);\n            ctx.insert(\"config_root\", &config_root.to_string_lossy().to_string());\n            *files = raw_templates\n                .iter()\n                .map(|tmpl| tera.render_str(tmpl, &ctx))\n                .collect::<Result<Vec<_>, _>>()?;\n        }\n        Ok(())\n    }\n}\n\nimpl From<&toml::Value> for TaskOutputs {\n    fn from(value: &toml::Value) -> Self {\n        match value {\n            toml::Value::String(file) => TaskOutputs::Files(vec![file.to_string()]),\n            toml::Value::Array(files) => TaskOutputs::Files(\n                files\n                    .iter()\n                    .map(|v| v.as_str().unwrap().to_string())\n                    .collect(),\n            ),\n            toml::Value::Table(table) => {\n                let auto = table\n                    .get(\"auto\")\n                    .and_then(|v| v.as_bool())\n                    .unwrap_or_default();\n                if auto {\n                    TaskOutputs::Auto\n                } else {\n                    TaskOutputs::default()\n                }\n            }\n            _ => TaskOutputs::default(),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for TaskOutputs {\n    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {\n        struct TaskOutputsVisitor;\n\n        impl<'de> serde::de::Visitor<'de> for TaskOutputsVisitor {\n            type Value = TaskOutputs;\n\n            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {\n                formatter.write_str(\"a string, a sequence of strings, or a map\")\n            }\n\n            fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {\n                Ok(TaskOutputs::Files(vec![value.to_string()]))\n            }\n\n            fn visit_seq<A: serde::de::SeqAccess<'de>>(\n                self,\n                mut seq: A,\n            ) -> Result<Self::Value, A::Error> {\n                let mut files = vec![];\n                while let Some(file) = seq.next_element()? {\n                    files.push(file);\n                }\n                Ok(TaskOutputs::Files(files))\n            }\n\n            fn visit_map<A: serde::de::MapAccess<'de>>(\n                self,\n                mut map: A,\n            ) -> Result<Self::Value, A::Error> {\n                if let Some(key) = map.next_key::<String>()? {\n                    if key == \"auto\" {\n                        if map.next_value::<bool>()? {\n                            Ok(TaskOutputs::Auto)\n                        } else {\n                            Ok(TaskOutputs::default())\n                        }\n                    } else {\n                        Err(serde::de::Error::custom(\"Invalid TaskOutputs map\"))\n                    }\n                } else {\n                    Ok(TaskOutputs::default())\n                }\n            }\n        }\n\n        deserializer.deserialize_any(TaskOutputsVisitor)\n    }\n}\n\nimpl Serialize for TaskOutputs {\n    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {\n        match self {\n            TaskOutputs::Files(files) => {\n                let mut seq = serializer.serialize_seq(Some(files.len()))?;\n                for file in files {\n                    seq.serialize_element(file)?;\n                }\n                seq.end()\n            }\n            TaskOutputs::Auto => {\n                let mut m = serializer.serialize_map(Some(1))?;\n                m.serialize_entry(\"auto\", &true)?;\n                m.end()\n            }\n        }\n    }\n}\n\nmod tests {\n    #[allow(unused_imports)]\n    use super::*;\n\n    #[test]\n    fn test_task_outputs_from_toml() {\n        let value: toml::Table = toml::from_str(\"outputs = \\\"file1\\\"\").unwrap();\n        let value = value.get(\"outputs\").unwrap();\n        let outputs = TaskOutputs::from(value);\n        assert_eq!(outputs, TaskOutputs::Files(vec![\"file1\".to_string()]));\n\n        let value: toml::Table = toml::from_str(\"outputs = [\\\"file1\\\"]\").unwrap();\n        let value = value.get(\"outputs\").unwrap();\n        let outputs = TaskOutputs::from(value);\n        assert_eq!(outputs, TaskOutputs::Files(vec![\"file1\".to_string()]));\n\n        let value: toml::Table = toml::from_str(\"outputs = { auto = true }\").unwrap();\n        let value = value.get(\"outputs\").unwrap();\n        let outputs = TaskOutputs::from(value);\n        assert_eq!(outputs, TaskOutputs::Auto);\n    }\n\n    #[test]\n    fn test_task_outputs_serialize() {\n        let outputs = TaskOutputs::Files(vec![\"file1\".to_string()]);\n        let serialized = serde_json::to_string(&outputs).unwrap();\n        assert_eq!(serialized, \"[\\\"file1\\\"]\");\n\n        let outputs = TaskOutputs::Auto;\n        let serialized = serde_json::to_string(&outputs).unwrap();\n        assert_eq!(serialized, \"{\\\"auto\\\":true}\");\n    }\n\n    #[test]\n    fn test_task_outputs_deserialize() {\n        let deserialized: TaskOutputs = serde_json::from_str(\"\\\"file1\\\"\").unwrap();\n        assert_eq!(deserialized, TaskOutputs::Files(vec![\"file1\".to_string()]));\n\n        let deserialized: TaskOutputs = serde_json::from_str(\"[\\\"file1\\\"]\").unwrap();\n        assert_eq!(deserialized, TaskOutputs::Files(vec![\"file1\".to_string()]));\n\n        let deserialized: TaskOutputs = serde_json::from_str(\"{ \\\"auto\\\": true }\").unwrap();\n        assert_eq!(deserialized, TaskOutputs::Auto);\n    }\n}\n"
  },
  {
    "path": "src/task/task_template.rs",
    "content": "use crate::config::config_file::mise_toml::EnvList;\nuse crate::config::config_file::toml::deserialize_arr;\nuse crate::task::task_sources::TaskOutputs;\nuse crate::task::{RunEntry, Silent, Task, TaskDep};\nuse indexmap::IndexMap;\nuse serde::Deserialize;\n\n/// A task template definition that can be extended by tasks via `extends`\n/// Templates are defined in [task_templates.*] sections of mise.toml\n#[derive(Debug, Clone, Default, Deserialize)]\npub struct TaskTemplate {\n    #[serde(default)]\n    pub description: String,\n    #[serde(default, rename = \"alias\", deserialize_with = \"deserialize_arr\")]\n    pub aliases: Vec<String>,\n    #[serde(default)]\n    pub confirm: Option<String>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub depends: Vec<TaskDep>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub depends_post: Vec<TaskDep>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub wait_for: Vec<TaskDep>,\n    #[serde(default)]\n    pub env: EnvList,\n    #[serde(default)]\n    pub vars: EnvList,\n    #[serde(default)]\n    pub dir: Option<String>,\n    #[serde(default)]\n    pub hide: Option<bool>,\n    #[serde(default)]\n    pub raw: Option<bool>,\n    #[serde(default)]\n    pub sources: Vec<String>,\n    #[serde(default)]\n    pub outputs: TaskOutputs,\n    #[serde(default)]\n    pub shell: Option<String>,\n    #[serde(default)]\n    pub quiet: Option<bool>,\n    #[serde(default)]\n    pub silent: Option<Silent>,\n    #[serde(default)]\n    pub tools: IndexMap<String, String>,\n    #[serde(default)]\n    pub usage: String,\n    #[serde(default)]\n    pub timeout: Option<String>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub run: Vec<RunEntry>,\n    #[serde(default, deserialize_with = \"deserialize_arr\")]\n    pub run_windows: Vec<RunEntry>,\n    #[serde(default)]\n    pub file: Option<String>,\n}\n\nimpl Task {\n    /// Merge a template into this task, using template values only where the task\n    /// doesn't already have values set. This allows tasks to override template values.\n    ///\n    /// Merge semantics:\n    /// - run, run_windows: Local overrides completely (if non-empty)\n    /// - tools: Deep merge (local tools added/override template)\n    /// - env: Deep merge (template first, then local overrides)\n    /// - vars: Deep merge (template first, then local overrides)\n    /// - depends, depends_post, wait_for: Local overrides completely (if non-empty)\n    /// - dir: Local overrides; defaults to None if not in template\n    /// - sources, outputs: Local overrides completely (if non-empty)\n    /// - Other fields: Local overrides template (if set)\n    pub fn merge_template(&mut self, template: &TaskTemplate) {\n        // run: only use template if local is empty\n        if self.run.is_empty() {\n            self.run = template.run.clone();\n        }\n\n        // run_windows: only use template if local is empty\n        if self.run_windows.is_empty() {\n            self.run_windows = template.run_windows.clone();\n        }\n\n        // tools: deep merge (template first, then local overrides)\n        let mut merged_tools = template.tools.clone();\n        for (tool, version) in &self.tools {\n            merged_tools.insert(tool.clone(), version.clone());\n        }\n        self.tools = merged_tools;\n\n        // env: deep merge (template first, then local overrides)\n        let mut merged_env = template.env.clone();\n        merged_env.0.extend(self.env.0.clone());\n        self.env = merged_env;\n\n        // vars: deep merge (template first, then local overrides)\n        let mut merged_vars = template.vars.clone();\n        merged_vars.0.extend(self.vars.0.clone());\n        self.vars = merged_vars;\n\n        // depends: local overrides completely if non-empty\n        if self.depends.is_empty() && !template.depends.is_empty() {\n            self.depends = template.depends.clone();\n        }\n\n        // depends_post: local overrides completely if non-empty\n        if self.depends_post.is_empty() && !template.depends_post.is_empty() {\n            self.depends_post = template.depends_post.clone();\n        }\n\n        // wait_for: local overrides completely if non-empty\n        if self.wait_for.is_empty() && !template.wait_for.is_empty() {\n            self.wait_for = template.wait_for.clone();\n        }\n\n        // dir: local overrides; use template only if local not set\n        if self.dir.is_none() {\n            self.dir = template.dir.clone();\n        }\n\n        // description: use template only if local is empty\n        if self.description.is_empty() && !template.description.is_empty() {\n            self.description = template.description.clone();\n        }\n\n        // aliases: local overrides completely if non-empty\n        if self.aliases.is_empty() && !template.aliases.is_empty() {\n            self.aliases = template.aliases.clone();\n        }\n\n        // confirm: use template only if local not set\n        if self.confirm.is_none() {\n            self.confirm = template.confirm.clone();\n        }\n\n        // sources: local overrides completely if non-empty\n        if self.sources.is_empty() && !template.sources.is_empty() {\n            self.sources = template.sources.clone();\n        }\n\n        // outputs: local overrides completely if default\n        if self.outputs == TaskOutputs::default() && template.outputs != TaskOutputs::default() {\n            self.outputs = template.outputs.clone();\n        }\n\n        // shell: use template only if local not set\n        if self.shell.is_none() {\n            self.shell = template.shell.clone();\n        }\n\n        // Note: quiet, hide, and raw are `bool` in Task (not Option<bool>), so we cannot\n        // distinguish between \"not set\" (defaults to false) and \"explicitly set to false\".\n        // Therefore, we do NOT merge these boolean fields from templates to avoid the case\n        // where a task explicitly sets `quiet = false` but gets overridden by a template's\n        // `quiet = true`. Users must explicitly set these in their task if needed.\n\n        // silent: use template only if local is Off (Silent is an enum, so we can distinguish)\n        if matches!(self.silent, Silent::Off)\n            && let Some(ref silent) = template.silent\n        {\n            self.silent = silent.clone();\n        }\n\n        // usage: use template only if local is empty\n        if self.usage.is_empty() && !template.usage.is_empty() {\n            self.usage = template.usage.clone();\n        }\n\n        // timeout: use template only if local not set\n        if self.timeout.is_none() {\n            self.timeout = template.timeout.clone();\n        }\n\n        // file: use template only if local not set\n        if self.file.is_none()\n            && let Some(ref file) = template.file\n        {\n            self.file = Some(file.into());\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_merge_template_run_override() {\n        let mut task = Task {\n            run: vec![RunEntry::Script(\"local command\".to_string())],\n            ..Default::default()\n        };\n        let template = TaskTemplate {\n            run: vec![RunEntry::Script(\"template command\".to_string())],\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Local run should be preserved\n        assert_eq!(task.run.len(), 1);\n        assert!(matches!(&task.run[0], RunEntry::Script(s) if s == \"local command\"));\n    }\n\n    #[test]\n    fn test_merge_template_run_from_template() {\n        let mut task = Task::default();\n        let template = TaskTemplate {\n            run: vec![RunEntry::Script(\"template command\".to_string())],\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Template run should be used when local is empty\n        assert_eq!(task.run.len(), 1);\n        assert!(matches!(&task.run[0], RunEntry::Script(s) if s == \"template command\"));\n    }\n\n    #[test]\n    fn test_merge_template_tools_deep_merge() {\n        let mut task = Task {\n            tools: IndexMap::from([(\"node\".to_string(), \"20\".to_string())]),\n            ..Default::default()\n        };\n        let template = TaskTemplate {\n            tools: IndexMap::from([\n                (\"python\".to_string(), \"3.12\".to_string()),\n                (\"node\".to_string(), \"18\".to_string()), // Should be overridden by task\n            ]),\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Should have both tools, with task's node version\n        assert_eq!(task.tools.len(), 2);\n        assert_eq!(task.tools.get(\"node\"), Some(&\"20\".to_string()));\n        assert_eq!(task.tools.get(\"python\"), Some(&\"3.12\".to_string()));\n    }\n\n    #[test]\n    fn test_merge_template_description() {\n        let mut task = Task::default();\n        let template = TaskTemplate {\n            description: \"Template description\".to_string(),\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        assert_eq!(task.description, \"Template description\");\n\n        // Now test that local description is preserved\n        let mut task2 = Task {\n            description: \"Local description\".to_string(),\n            ..Default::default()\n        };\n        task2.merge_template(&template);\n        assert_eq!(task2.description, \"Local description\");\n    }\n\n    #[test]\n    fn test_merge_template_depends_override() {\n        let mut task = Task {\n            depends: vec![TaskDep {\n                task: \"local-dep\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n        let template = TaskTemplate {\n            depends: vec![TaskDep {\n                task: \"template-dep\".to_string(),\n                args: vec![],\n                env: Default::default(),\n            }],\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Local depends should be completely preserved (not merged)\n        assert_eq!(task.depends.len(), 1);\n        assert_eq!(task.depends[0].task, \"local-dep\");\n    }\n\n    #[test]\n    fn test_merge_template_vars_deep_merge() {\n        let mut task = Task {\n            vars: EnvList(vec![crate::config::env_directive::EnvDirective::Val(\n                \"target\".to_string(),\n                \"linux\".to_string(),\n                Default::default(),\n            )]),\n            ..Default::default()\n        };\n        let template = TaskTemplate {\n            vars: EnvList(vec![crate::config::env_directive::EnvDirective::Val(\n                \"profile\".to_string(),\n                \"release\".to_string(),\n                Default::default(),\n            )]),\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Should contain template vars + local vars (local appended)\n        assert_eq!(task.vars.0.len(), 2);\n    }\n\n    #[test]\n    fn test_merge_template_vars_override() {\n        let mut task = Task {\n            vars: EnvList(vec![\n                crate::config::env_directive::EnvDirective::Val(\n                    \"target\".to_string(),\n                    \"linux\".to_string(),\n                    Default::default(),\n                ),\n                crate::config::env_directive::EnvDirective::Val(\n                    \"shared\".to_string(),\n                    \"task_value\".to_string(),\n                    Default::default(),\n                ),\n            ]),\n            ..Default::default()\n        };\n        let template = TaskTemplate {\n            vars: EnvList(vec![\n                crate::config::env_directive::EnvDirective::Val(\n                    \"profile\".to_string(),\n                    \"release\".to_string(),\n                    Default::default(),\n                ),\n                crate::config::env_directive::EnvDirective::Val(\n                    \"shared\".to_string(),\n                    \"template_value\".to_string(),\n                    Default::default(),\n                ),\n            ]),\n            ..Default::default()\n        };\n\n        task.merge_template(&template);\n\n        // Last matching directive should win when vars are resolved.\n        let shared_val = task.vars.0.iter().rev().find_map(|d| match d {\n            crate::config::env_directive::EnvDirective::Val(name, value, _) if name == \"shared\" => {\n                Some(value.as_str())\n            }\n            _ => None,\n        });\n        assert_eq!(shared_val, Some(\"task_value\"));\n    }\n}\n"
  },
  {
    "path": "src/task/task_tool_installer.rs",
    "content": "use crate::cli::args::ToolArg;\nuse crate::config::{Config, Settings};\nuse crate::task::Deps;\nuse crate::task::task_context_builder::TaskContextBuilder;\nuse crate::task::task_helpers::canonicalize_path;\nuse crate::toolset::{InstallOptions, ToolSource, Toolset};\nuse eyre::Result;\nuse std::path::Path;\nuse std::sync::Arc;\n\n/// Handles collection and installation of tools required by tasks\npub struct TaskToolInstaller<'a> {\n    context_builder: &'a TaskContextBuilder,\n    cli_tools: &'a [ToolArg],\n}\n\nimpl<'a> TaskToolInstaller<'a> {\n    pub fn new(context_builder: &'a TaskContextBuilder, cli_tools: &'a [ToolArg]) -> Self {\n        Self {\n            context_builder,\n            cli_tools,\n        }\n    }\n\n    /// Collect and install all tools needed by tasks\n    pub async fn install_tools(&self, config: &mut Arc<Config>, tasks: &Deps) -> Result<()> {\n        let mut all_tools = self.cli_tools.to_vec();\n        let mut all_tool_requests = vec![];\n        let all_tasks: Vec<_> = tasks.all().collect();\n\n        trace!(\"Collecting tools from {} tasks\", all_tasks.len());\n\n        // Collect tools from tasks\n        for t in &all_tasks {\n            // Collect tools from task.tools (task-level tool overrides)\n            for (k, v) in &t.tools {\n                all_tools.push(format!(\"{k}@{v}\").parse()?);\n            }\n\n            // Collect tools from monorepo task config files\n            if let Some(task_cf) = t.cf(config) {\n                let tool_requests = self\n                    .collect_tools_from_config_file(task_cf.clone(), &t.name)\n                    .await?;\n                all_tool_requests.extend(tool_requests);\n            } else if let Some(config_root) = &t.config_root {\n                // For file tasks without a config file (e.g. scripts in .mise-tasks/),\n                // fall back to loading tools from the project's config hierarchy\n                let tool_requests = self.collect_tools_from_dir(config_root, &t.name).await?;\n                all_tool_requests.extend(tool_requests);\n            }\n        }\n\n        // Build and install toolset\n        let toolset = self\n            .build_toolset(config, all_tools, all_tool_requests)\n            .await?;\n        self.install_toolset(config, toolset).await?;\n\n        Ok(())\n    }\n\n    /// Collect tools from a task's config file hierarchy\n    async fn collect_tools_from_config_file(\n        &self,\n        task_cf: Arc<dyn crate::config::config_file::ConfigFile>,\n        task_name: &str,\n    ) -> Result<Vec<crate::toolset::ToolRequest>> {\n        let task_dir = task_cf.config_root();\n        self.collect_tools_from_dir(&task_dir, task_name).await\n    }\n\n    /// Collect tools from config files found in a directory hierarchy\n    async fn collect_tools_from_dir(\n        &self,\n        dir: &Path,\n        task_name: &str,\n    ) -> Result<Vec<crate::toolset::ToolRequest>> {\n        let config_paths = crate::config::load_config_hierarchy_from_dir(dir)?;\n        let task_config_files = crate::config::load_config_files_from_paths(&config_paths).await?;\n\n        let mut tool_requests: Vec<crate::toolset::ToolRequest> = vec![];\n        let mut seen_tools: std::collections::HashSet<String> = std::collections::HashSet::new();\n\n        for (source, cf) in task_config_files.iter() {\n            let config_path = canonicalize_path(source);\n\n            // Check cache first for this config file's tool request set\n            let trs = {\n                let cache = self\n                    .context_builder\n                    .tool_request_set_cache()\n                    .read()\n                    .expect(\"tool_request_set_cache RwLock poisoned\");\n                cache.get(&config_path).cloned()\n            };\n\n            let trs = if let Some(cached) = trs {\n                trace!(\n                    \"Using cached tool request set from {}\",\n                    config_path.display()\n                );\n                cached\n            } else {\n                match cf.to_tool_request_set() {\n                    Ok(trs) => {\n                        let trs = Arc::new(trs);\n                        let mut cache = self\n                            .context_builder\n                            .tool_request_set_cache()\n                            .write()\n                            .expect(\"tool_request_set_cache RwLock poisoned\");\n                        cache.insert(config_path.clone(), Arc::clone(&trs));\n                        trace!(\"Cached tool request set from {}\", config_path.display());\n                        trs\n                    }\n                    Err(e) => {\n                        warn!(\n                            \"Failed to parse tools from {} for task {}: {}\",\n                            source.display(),\n                            task_name,\n                            e\n                        );\n                        continue;\n                    }\n                }\n            };\n\n            for (ba, reqs) in trs.tools.iter() {\n                let tool_key = ba.to_string();\n                if !seen_tools.contains(&tool_key) {\n                    trace!(\n                        \"Adding tool {} from {} for task {}\",\n                        ba,\n                        source.display(),\n                        task_name\n                    );\n                    tool_requests.extend(reqs.iter().cloned());\n                    seen_tools.insert(tool_key);\n                }\n            }\n        }\n\n        trace!(\n            \"Found {} tool requests in config hierarchy for task {}\",\n            tool_requests.len(),\n            task_name\n        );\n\n        Ok(tool_requests)\n    }\n\n    /// Build a toolset from CLI tools and collected tool requests\n    async fn build_toolset(\n        &self,\n        config: &Arc<Config>,\n        all_tools: Vec<ToolArg>,\n        all_tool_requests: Vec<crate::toolset::ToolRequest>,\n    ) -> Result<Toolset> {\n        let source = ToolSource::Argument;\n        let mut ts = Toolset::new(source.clone());\n\n        // Add tools from CLI args and task.tools\n        for tool_arg in all_tools {\n            if let Some(tvr) = tool_arg.tvr {\n                ts.add_version(tvr);\n            }\n        }\n\n        // Add tools from config files\n        for tr in all_tool_requests {\n            trace!(\"Adding tool from config: {}\", tr);\n            ts.add_version(tr);\n        }\n\n        ts.resolve(config).await?;\n\n        Ok(ts)\n    }\n\n    /// Install missing versions from the toolset\n    async fn install_toolset(&self, config: &mut Arc<Config>, mut ts: Toolset) -> Result<()> {\n        let _ = ts\n            .install_missing_versions(\n                config,\n                &InstallOptions {\n                    missing_args_only: !Settings::get().task.run_auto_install,\n                    skip_auto_install: !Settings::get().task.run_auto_install\n                        || !Settings::get().auto_install,\n                    ..Default::default()\n                },\n            )\n            .await?;\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_task_tool_installer_new() {\n        let context_builder = TaskContextBuilder::new();\n        let cli_tools: Vec<ToolArg> = vec![];\n        let installer = TaskToolInstaller::new(&context_builder, &cli_tools);\n        assert_eq!(installer.cli_tools.len(), 0);\n    }\n}\n"
  },
  {
    "path": "src/tera.rs",
    "content": "use std::collections::HashMap;\nuse std::iter::once;\nuse std::path::{Path, PathBuf};\nuse std::sync::Mutex;\n\nuse heck::{\n    ToKebabCase, ToLowerCamelCase, ToShoutyKebabCase, ToShoutySnakeCase, ToSnakeCase,\n    ToUpperCamelCase,\n};\nuse path_absolutize::Absolutize;\nuse rand::prelude::*;\nuse std::sync::LazyLock as Lazy;\nuse tera::{Context, Tera, Value};\nuse versions::{Requirement, Versioning};\n\nuse crate::cache::CacheManagerBuilder;\nuse crate::cmd::cmd;\nuse crate::config::Settings;\nuse crate::env_diff::EnvMap;\nuse crate::{dirs, duration, env, hash};\n\n/// Global tracker for files accessed during tera template rendering.\n/// Functions like `read_file`, `hash_file`, `file_size`, and `last_modified`\n/// push paths here so that hook-env can watch them for changes.\nstatic TERA_ACCESSED_FILES: Mutex<Vec<PathBuf>> = Mutex::new(Vec::new());\n\nfn track_tera_file(path: &Path) {\n    if let Ok(mut files) = TERA_ACCESSED_FILES.lock() {\n        files.push(path.to_path_buf());\n    }\n}\n\n/// Take all tracked files, clearing the global list.\npub fn take_tera_accessed_files() -> Vec<PathBuf> {\n    let mut files = TERA_ACCESSED_FILES\n        .lock()\n        .map(|mut f| std::mem::take(&mut *f))\n        .unwrap_or_default();\n    files.sort();\n    files.dedup();\n    files\n}\n\npub static BASE_CONTEXT: Lazy<Context> = Lazy::new(|| {\n    let mut context = Context::new();\n    context.insert(\"env\", &*env::PRISTINE_ENV);\n    context.insert(\"mise_bin\", &*env::MISE_BIN);\n    context.insert(\"mise_pid\", &*env::MISE_PID);\n    if !(*env::MISE_ENV).is_empty() {\n        context.insert(\"mise_env\", &*env::MISE_ENV);\n    }\n    if let Ok(dir) = env::current_dir() {\n        context.insert(\"cwd\", &dir);\n    }\n    context.insert(\"xdg_cache_home\", &*env::XDG_CACHE_HOME);\n    context.insert(\"xdg_config_home\", &*env::XDG_CONFIG_HOME);\n    context.insert(\"xdg_data_home\", &*env::XDG_DATA_HOME);\n    context.insert(\"xdg_state_home\", &*env::XDG_STATE_HOME);\n    context\n});\n\nstatic TERA: Lazy<Tera> = Lazy::new(|| {\n    let mut tera = Tera::default();\n    tera.register_function(\n        \"arch\",\n        move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n            let arch = if cfg!(target_arch = \"x86_64\") {\n                \"x64\"\n            } else if cfg!(target_arch = \"aarch64\") {\n                \"arm64\"\n            } else {\n                env::consts::ARCH\n            };\n            // Check if there's a remap for this arch\n            if let Some(remapped) = args.get(arch)\n                && let Some(s) = remapped.as_str()\n            {\n                return Ok(Value::String(s.to_string()));\n            }\n            Ok(Value::String(arch.to_string()))\n        },\n    );\n    tera.register_function(\n        \"num_cpus\",\n        move |_args: &HashMap<String, Value>| -> tera::Result<Value> {\n            let num = num_cpus::get();\n            Ok(Value::String(num.to_string()))\n        },\n    );\n    tera.register_function(\n        \"os\",\n        move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n            let os = env::consts::OS;\n            // Check if there's a remap for this OS\n            if let Some(remapped) = args.get(os)\n                && let Some(s) = remapped.as_str()\n            {\n                return Ok(Value::String(s.to_string()));\n            }\n            Ok(Value::String(os.to_string()))\n        },\n    );\n    tera.register_function(\n        \"os_family\",\n        move |_args: &HashMap<String, Value>| -> tera::Result<Value> {\n            Ok(Value::String(env::consts::FAMILY.to_string()))\n        },\n    );\n    tera.register_function(\n        \"choice\",\n        move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n            match args.get(\"n\") {\n                Some(Value::Number(n)) => {\n                    let n = n.as_u64().unwrap();\n                    match args.get(\"alphabet\") {\n                        Some(Value::String(alphabet)) => {\n                            let alphabet = alphabet.chars().collect::<Vec<char>>();\n                            let mut rng = rand::rng();\n                            let result =\n                                (0..n).map(|_| alphabet.choose(&mut rng).unwrap()).collect();\n                            Ok(Value::String(result))\n                        }\n                        _ => Err(\"choice alphabet must be an string\".into()),\n                    }\n                }\n                _ => Err(\"choice n must be an integer\".into()),\n            }\n        },\n    );\n    tera.register_function(\n        \"haiku\",\n        move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n            let words = args\n                .get(\"words\")\n                .and_then(Value::as_u64)\n                .unwrap_or(2)\n                .max(1) as usize;\n            let separator = args.get(\"separator\").and_then(Value::as_str).unwrap_or(\"-\");\n            let digits = args.get(\"digits\").and_then(Value::as_u64).unwrap_or(2) as usize;\n\n            let result = xx::rand::haiku(&xx::rand::HaikuOptions {\n                words,\n                separator,\n                digits,\n            });\n\n            Ok(Value::String(result))\n        },\n    );\n    tera.register_filter(\n        \"hash_file\",\n        move |input: &Value, args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let path = Path::new(s);\n                track_tera_file(path);\n                let mut hash = hash::file_hash_blake3(path, None).unwrap();\n                if let Some(len) = args.get(\"len\").and_then(Value::as_u64) {\n                    hash = hash.chars().take(len as usize).collect();\n                }\n                Ok(Value::String(hash))\n            }\n            _ => Err(\"hash input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"hash\",\n        move |input: &Value, args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                // Get the algorithm, default to sha256\n                let algorithm = args\n                    .get(\"algorithm\")\n                    .and_then(Value::as_str)\n                    .unwrap_or(\"sha256\");\n\n                let mut hash = match algorithm {\n                    \"sha256\" => hash::hash_sha256_to_str(s),\n                    \"blake3\" => hash::hash_blake3_to_str(s),\n                    _ => return Err(format!(\"unknown hash algorithm: {algorithm}\").into()),\n                };\n\n                if let Some(len) = args.get(\"len\").and_then(Value::as_u64) {\n                    hash = hash.chars().take(len as usize).collect();\n                }\n                Ok(Value::String(hash))\n            }\n            _ => Err(\"hash input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"absolute\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let p = Path::new(s).absolutize()?;\n                Ok(Value::String(p.to_string_lossy().to_string()))\n            }\n            _ => Err(\"absolute input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"canonicalize\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let p = Path::new(s).canonicalize()?;\n                Ok(Value::String(p.to_string_lossy().to_string()))\n            }\n            _ => Err(\"canonicalize input must be a string\".into()),\n        },\n    );\n    // Helper to create path filters that handle empty strings gracefully\n    fn path_filter<F>(input: &Value, name: &'static str, f: F) -> tera::Result<Value>\n    where\n        F: FnOnce(&Path) -> Option<String>,\n    {\n        match input {\n            Value::String(s) if s.is_empty() => Ok(Value::String(String::new())),\n            Value::String(s) => Ok(Value::String(f(Path::new(s)).unwrap_or_default())),\n            _ => Err(format!(\"{name} input must be a string\").into()),\n        }\n    }\n    tera.register_filter(\n        \"dirname\",\n        move |input: &Value, _args: &HashMap<String, Value>| {\n            path_filter(input, \"dirname\", |p| {\n                p.parent().map(|p| p.to_string_lossy().to_string())\n            })\n        },\n    );\n    tera.register_filter(\n        \"basename\",\n        move |input: &Value, _args: &HashMap<String, Value>| {\n            path_filter(input, \"basename\", |p| {\n                p.file_name().map(|p| p.to_string_lossy().to_string())\n            })\n        },\n    );\n    tera.register_filter(\n        \"extname\",\n        move |input: &Value, _args: &HashMap<String, Value>| {\n            path_filter(input, \"extname\", |p| {\n                p.extension().map(|p| p.to_string_lossy().to_string())\n            })\n        },\n    );\n    tera.register_filter(\n        \"file_stem\",\n        move |input: &Value, _args: &HashMap<String, Value>| {\n            path_filter(input, \"file_stem\", |p| {\n                p.file_stem().map(|p| p.to_string_lossy().to_string())\n            })\n        },\n    );\n    tera.register_filter(\n        \"file_size\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let p = Path::new(s);\n                track_tera_file(p);\n                let metadata = p.metadata()?;\n                let size = metadata.len();\n                Ok(Value::Number(size.into()))\n            }\n            _ => Err(\"file_size input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"last_modified\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let p = Path::new(s);\n                track_tera_file(p);\n                let metadata = p.metadata()?;\n                let modified = metadata.modified()?;\n                let modified = modified.duration_since(std::time::UNIX_EPOCH).unwrap();\n                Ok(Value::Number(modified.as_secs().into()))\n            }\n            _ => Err(\"last_modified input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"join_path\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::Array(arr) => arr\n                .iter()\n                .map(Value::as_str)\n                .collect::<Option<PathBuf>>()\n                .ok_or(\"join_path input must be an array of strings\".into())\n                .map(|p| Value::String(p.to_string_lossy().to_string())),\n            _ => Err(\"join_path input must be an array of strings\".into()),\n        },\n    );\n    tera.register_filter(\n        \"quote\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => {\n                let result = format!(\"'{}'\", s.replace(\"'\", \"\\\\'\"));\n\n                Ok(Value::String(result))\n            }\n            _ => Err(\"quote input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"kebabcase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_kebab_case())),\n            _ => Err(\"kebabcase input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"lowercamelcase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_lower_camel_case())),\n            _ => Err(\"lowercamelcase input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"shoutykebabcase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_shouty_kebab_case())),\n            _ => Err(\"shoutykebabcase input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"shoutysnakecase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_shouty_snake_case())),\n            _ => Err(\"shoutysnakecase input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"snakecase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_snake_case())),\n            _ => Err(\"snakecase input must be a string\".into()),\n        },\n    );\n    tera.register_filter(\n        \"uppercamelcase\",\n        move |input: &Value, _args: &HashMap<String, Value>| match input {\n            Value::String(s) => Ok(Value::String(s.to_upper_camel_case())),\n            _ => Err(\"uppercamelcase input must be a string\".into()),\n        },\n    );\n    tera.register_tester(\n        \"dir\",\n        move |input: Option<&Value>, _args: &[Value]| match input {\n            Some(Value::String(s)) => Ok(Path::new(s).is_dir()),\n            _ => Err(\"is_dir input must be a string\".into()),\n        },\n    );\n    tera.register_tester(\n        \"file\",\n        move |input: Option<&Value>, _args: &[Value]| match input {\n            Some(Value::String(s)) => Ok(Path::new(s).is_file()),\n            _ => Err(\"is_file input must be a string\".into()),\n        },\n    );\n    tera.register_tester(\n        \"exists\",\n        move |input: Option<&Value>, _args: &[Value]| match input {\n            Some(Value::String(s)) => Ok(Path::new(s).exists()),\n            _ => Err(\"exists input must be a string\".into()),\n        },\n    );\n    tera.register_tester(\n        \"semver_matching\",\n        move |input: Option<&Value>, args: &[Value]| match input {\n            Some(Value::String(version)) => match args.first() {\n                Some(Value::String(requirement)) => {\n                    println!(\"{requirement}\");\n                    let result = Requirement::new(requirement)\n                        .unwrap()\n                        .matches(&Versioning::new(version).unwrap());\n                    Ok(result)\n                }\n                _ => Err(\"semver_matching argument must be a string\".into()),\n            },\n            _ => Err(\"semver_matching input must be a string\".into()),\n        },\n    );\n\n    tera\n});\n\npub fn get_tera(dir: Option<&Path>) -> Tera {\n    let mut tera = TERA.clone();\n    let dir = dir.map(PathBuf::from);\n    tera.register_function(\"exec\", tera_exec(dir.clone(), env::PRISTINE_ENV.clone()));\n    tera.register_function(\"read_file\", tera_read_file(dir));\n\n    tera\n}\n\npub fn tera_exec(\n    dir: Option<PathBuf>,\n    env: EnvMap,\n) -> impl Fn(&HashMap<String, Value>) -> tera::Result<Value> {\n    move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n        let cache = match args.get(\"cache_key\") {\n            Some(Value::String(cache)) => Some(cache),\n            None => None,\n            _ => return Err(\"exec cache_key must be a string\".into()),\n        };\n        let cache_duration = match args.get(\"cache_duration\") {\n            Some(Value::String(duration)) => {\n                match duration::parse_duration(&duration.to_string()) {\n                    Ok(duration) => Some(duration),\n                    Err(e) => return Err(format!(\"exec cache_duration: {e}\").into()),\n                }\n            }\n            None => None,\n            _ => return Err(\"exec cache_duration must be an integer\".into()),\n        };\n        match args.get(\"command\") {\n            Some(Value::String(command)) => {\n                let shell = Settings::get()\n                    .default_inline_shell()\n                    .map_err(|e| tera::Error::msg(e.to_string()))?;\n                let args = shell\n                    .iter()\n                    .skip(1)\n                    .chain(once(command))\n                    .collect::<Vec<&String>>();\n                let mut cmd: duct::Expression = cmd(&shell[0], args).full_env(&env);\n                if let Some(dir) = &dir {\n                    cmd = cmd.dir(dir);\n                }\n                let result = if cache.is_some() || cache_duration.is_some() {\n                    let cachehash = hash::hash_blake3_to_str(\n                        &(dir\n                            .as_ref()\n                            .map(|d| d.to_string_lossy().to_string())\n                            .unwrap_or_default()\n                            + command),\n                    )[..8]\n                        .to_string();\n                    let mut cacheman =\n                        CacheManagerBuilder::new(dirs::CACHE.join(\"exec\").join(cachehash));\n                    if let Some(cache) = cache {\n                        cacheman = cacheman.with_cache_key(cache.clone());\n                    }\n                    if let Some(cache_duration) = cache_duration {\n                        cacheman = cacheman.with_fresh_duration(Some(cache_duration));\n                    }\n                    let cache = cacheman.build();\n                    match cache.get_or_try_init(|| Ok(cmd.read()?)) {\n                        Ok(result) => result.clone(),\n                        Err(e) => return Err(format!(\"exec command: {e}\").into()),\n                    }\n                } else {\n                    cmd.read()?\n                };\n                Ok(Value::String(result))\n            }\n            _ => Err(\"exec command must be a string\".into()),\n        }\n    }\n}\n\npub fn tera_read_file(\n    dir: Option<PathBuf>,\n) -> impl Fn(&HashMap<String, Value>) -> tera::Result<Value> {\n    move |args: &HashMap<String, Value>| -> tera::Result<Value> {\n        match args.get(\"path\") {\n            Some(Value::String(path_str)) => {\n                let path = if let Some(ref base_dir) = dir {\n                    // Resolve relative to config directory\n                    base_dir.join(path_str)\n                } else {\n                    // Use path as-is if no directory context\n                    PathBuf::from(path_str)\n                };\n\n                track_tera_file(&path);\n                match std::fs::read_to_string(&path) {\n                    Ok(contents) => Ok(Value::String(contents)),\n                    Err(e) => {\n                        Err(format!(\"Failed to read file '{}': {}\", path.display(), e).into())\n                    }\n                }\n            }\n            _ => Err(\"read_file path must be a string\".into()),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n    use pretty_assertions::assert_str_eq;\n\n    #[tokio::test]\n    async fn test_config_root() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(render(\"{{config_root}}\"), \"/\");\n    }\n\n    #[tokio::test]\n    async fn test_mise_env() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(render(\"{% if mise_env %}{{mise_env}}{% endif %}\"), \"\");\n    }\n\n    #[tokio::test]\n    async fn test_cwd() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(render(\"{{cwd}}\"), \"/\");\n    }\n\n    #[tokio::test]\n    async fn test_mise_bin() {\n        let _config = Config::get().await.unwrap();\n        assert_eq!(\n            render(\"{{mise_bin}}\"),\n            env::current_exe()\n                .unwrap()\n                .into_os_string()\n                .into_string()\n                .unwrap()\n        );\n    }\n\n    #[tokio::test]\n    async fn test_mise_pid() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{mise_pid}}\");\n        let pid = s.trim().parse::<u32>().unwrap();\n        assert!(pid > 0);\n    }\n\n    #[tokio::test]\n    async fn test_xdg_cache_home() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{xdg_cache_home}}\");\n        assert_str_eq!(s, env::XDG_CACHE_HOME.to_string_lossy());\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_xdg_config_home() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{xdg_config_home}}\");\n        assert!(s.ends_with(\"/.config\")); // test dir is not deterministic\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_xdg_data_home() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{xdg_data_home}}\");\n        assert!(s.ends_with(\"/.local/share\")); // test dir is not deterministic\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_xdg_state_home() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{xdg_state_home}}\");\n        assert!(s.ends_with(\"/.local/state\")); // test dir is not deterministic\n    }\n\n    #[tokio::test]\n    async fn test_arch() {\n        let _config = Config::get().await.unwrap();\n        if cfg!(target_arch = \"x86_64\") {\n            assert_eq!(render(\"{{arch()}}\"), \"x64\");\n        } else if cfg!(target_arch = \"aarch64\") {\n            assert_eq!(render(\"{{arch()}}\"), \"arm64\");\n        } else {\n            assert_eq!(render(\"{{arch()}}\"), env::consts::ARCH);\n        }\n    }\n\n    #[tokio::test]\n    async fn test_num_cpus() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ num_cpus() }}\");\n        let num = s.parse::<u32>().unwrap();\n        assert!(num > 0);\n    }\n\n    #[tokio::test]\n    async fn test_os() {\n        let _config = Config::get().await.unwrap();\n        if cfg!(target_os = \"linux\") {\n            assert_eq!(render(\"{{os()}}\"), \"linux\");\n        } else if cfg!(target_os = \"macos\") {\n            assert_eq!(render(\"{{os()}}\"), \"macos\");\n        } else if cfg!(target_os = \"windows\") {\n            assert_eq!(render(\"{{os()}}\"), \"windows\");\n        }\n    }\n\n    #[tokio::test]\n    async fn test_os_family() {\n        let _config = Config::get().await.unwrap();\n        if cfg!(target_family = \"unix\") {\n            assert_eq!(render(\"{{os_family()}}\"), \"unix\");\n        } else if cfg!(target_os = \"windows\") {\n            assert_eq!(render(\"{{os_family()}}\"), \"windows\");\n        }\n    }\n\n    #[tokio::test]\n    async fn test_choice() {\n        let _config = Config::get().await.unwrap();\n        let result = render(\"{{choice(n=8, alphabet=\\\"abcdefgh\\\")}}\");\n        assert_eq!(result.trim().len(), 8);\n    }\n\n    #[tokio::test]\n    async fn test_haiku() {\n        let _config = Config::get().await.unwrap();\n        // Default: 2 words + number\n        let result = render(\"{{haiku()}}\");\n        let parts: Vec<&str> = result.split('-').collect();\n        assert_eq!(parts.len(), 3);\n        assert!(!parts[0].is_empty());\n        assert!(!parts[1].is_empty());\n        assert!(parts[2].parse::<u32>().is_ok());\n\n        // Custom: 3 words, no digits, underscore separator\n        let result = render(\"{{haiku(words=3, digits=0, separator=\\\"_\\\")}}\");\n        let parts: Vec<&str> = result.split('_').collect();\n        assert_eq!(parts.len(), 3);\n        assert!(parts.iter().all(|p| p.parse::<u32>().is_err())); // no numbers\n    }\n\n    #[tokio::test]\n    async fn test_quote() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"quoted'str\\\" | quote }}\");\n        assert_eq!(s, \"'quoted\\\\'str'\");\n    }\n\n    #[tokio::test]\n    async fn test_kebabcase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"thisFilter\\\" | kebabcase }}\");\n        assert_eq!(s, \"this-filter\");\n    }\n\n    #[tokio::test]\n    async fn test_lowercamelcase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"Camel-case\\\" | lowercamelcase }}\");\n        assert_eq!(s, \"camelCase\");\n    }\n\n    #[tokio::test]\n    async fn test_shoutykebabcase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"kebabCase\\\" | shoutykebabcase }}\");\n        assert_eq!(s, \"KEBAB-CASE\");\n    }\n\n    #[tokio::test]\n    async fn test_shoutysnakecase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"snakeCase\\\" | shoutysnakecase }}\");\n        assert_eq!(s, \"SNAKE_CASE\");\n    }\n\n    #[tokio::test]\n    async fn test_snakecase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"snakeCase\\\" | snakecase }}\");\n        assert_eq!(s, \"snake_case\");\n    }\n\n    #[tokio::test]\n    async fn test_uppercamelcase() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"CamelCase\\\" | uppercamelcase }}\");\n        assert_eq!(s, \"CamelCase\");\n    }\n\n    #[tokio::test]\n    async fn test_hash() {\n        let _config = Config::get().await.unwrap();\n        // SHA256 of \"foo\" is 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae\n        let s = render(\"{{ \\\"foo\\\" | hash(len=8) }}\");\n        assert_eq!(s, \"2c26b46b\");\n        // Test explicit sha256\n        let s = render(\"{{ \\\"foo\\\" | hash(algorithm=\\\"sha256\\\", len=8) }}\");\n        assert_eq!(s, \"2c26b46b\");\n        // Test blake3 - BLAKE3 of \"foo\" starts with 04e0bb39\n        let s = render(\"{{ \\\"foo\\\" | hash(algorithm=\\\"blake3\\\", len=8) }}\");\n        assert_eq!(s, \"04e0bb39\");\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_hash_file() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"../fixtures/shorthands.toml\\\" | hash_file(len=64) }}\");\n        insta::assert_snapshot!(s, @\"ce17f44735ea2083038e61c4b291ed31593e6cf4d93f5dc147e97e62962ac4e6\");\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_absolute() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"/a/b/../c\\\" | absolute }}\");\n        assert_eq!(s, \"/a/c\");\n        // relative path\n        let s = render(\"{{ \\\"a/b/../c\\\" | absolute }}\");\n        assert!(s.ends_with(\"/a/c\"));\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_canonicalize() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\"{{ \\\"../fixtures/shorthands.toml\\\" | canonicalize }}\");\n        assert!(s.ends_with(\"/fixtures/shorthands.toml\")); // test dir is not deterministic\n    }\n\n    #[tokio::test]\n    async fn test_dirname() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"a/b/c\" | dirname }}\"#);\n        assert_eq!(s, \"a/b\");\n    }\n\n    #[tokio::test]\n    async fn test_basename() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"a/b/c\" | basename }}\"#);\n        assert_eq!(s, \"c\");\n    }\n\n    #[tokio::test]\n    async fn test_extname() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"a/b/c.txt\" | extname }}\"#);\n        assert_eq!(s, \"txt\");\n    }\n\n    #[tokio::test]\n    async fn test_file_stem() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"a/b/c.txt\" | file_stem }}\"#);\n        assert_eq!(s, \"c\");\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_file_size() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"../fixtures/shorthands.toml\" | file_size }}\"#);\n        assert_eq!(s, \"48\");\n    }\n\n    #[tokio::test]\n    async fn test_last_modified() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ \"../fixtures/shorthands.toml\" | last_modified }}\"#);\n        let timestamp = s.parse::<u64>().unwrap();\n        assert!((1725000000..=2725000000).contains(&timestamp));\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_join_path() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{{ [\"..\", \"fixtures\", \"shorthands.toml\"] | join_path }}\"#);\n        assert_eq!(s, \"../fixtures/shorthands.toml\");\n    }\n\n    #[tokio::test]\n    async fn test_is_dir() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{% set p = \".mise\" %}{% if p is dir %} ok {% endif %}\"#);\n        assert_eq!(s.trim(), \"ok\");\n    }\n\n    #[tokio::test]\n    async fn test_is_file() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{% set p = \".test-tool-versions\" %}{% if p is file %} ok {% endif %}\"#);\n        assert_eq!(s.trim(), \"ok\");\n    }\n\n    #[tokio::test]\n    async fn test_exists() {\n        let _config = Config::get().await.unwrap();\n        let s = render(r#\"{% set p = \".test-tool-versions\" %}{% if p is exists %} ok {% endif %}\"#);\n        assert_eq!(s.trim(), \"ok\");\n    }\n\n    #[tokio::test]\n    async fn test_semver_matching() {\n        let _config = Config::get().await.unwrap();\n        let s = render(\n            r#\"{% set p = \"1.10.2\" %}{% if p is semver_matching(\"^1.10.0\") %} ok {% endif %}\"#,\n        );\n        assert_eq!(s.trim(), \"ok\");\n    }\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_read_file() {\n        use std::fs;\n        use tempfile::TempDir;\n\n        let _config = Config::get().await.unwrap();\n\n        // Create a temp directory and test file\n        let temp_dir = TempDir::new().unwrap();\n        let test_file_path = temp_dir.path().join(\"test.txt\");\n        fs::write(&test_file_path, \"test content\\nwith multiple lines\").unwrap();\n\n        // Test with the temp file\n        let mut tera_ctx = BASE_CONTEXT.clone();\n        tera_ctx.insert(\"config_root\", &temp_dir.path().to_str().unwrap());\n        tera_ctx.insert(\"cwd\", temp_dir.path().to_str().unwrap());\n        let mut tera = get_tera(Some(temp_dir.path()));\n\n        let s = tera\n            .render_str(r#\"{{ read_file(path=\"test.txt\") }}\"#, &tera_ctx)\n            .unwrap();\n        assert_eq!(s, \"test content\\nwith multiple lines\");\n\n        // Test with trim filter\n        let s = tera\n            .render_str(r#\"{{ read_file(path=\"test.txt\") | trim }}\"#, &tera_ctx)\n            .unwrap();\n        assert_eq!(s, \"test content\\nwith multiple lines\");\n    }\n\n    fn render(s: &str) -> String {\n        let config_root = Path::new(\"/\");\n        let mut tera_ctx = BASE_CONTEXT.clone();\n        tera_ctx.insert(\"config_root\", &config_root);\n        tera_ctx.insert(\"cwd\", \"/\");\n        let mut tera = get_tera(Option::from(config_root));\n        tera.render_str(s, &tera_ctx).unwrap()\n    }\n}\n"
  },
  {
    "path": "src/test.rs",
    "content": "use std::env::join_paths;\nuse std::path::PathBuf;\n\nuse indoc::indoc;\n\nuse crate::{env, file};\n\n#[ctor::ctor]\nfn init() {\n    if env::var(\"RUST_LOG\").is_err() {\n        env::set_var(\"RUST_LOG\", \"debug\")\n    }\n    console::set_colors_enabled(false);\n    console::set_colors_enabled_stderr(false);\n    env::set_var(\n        \"HOME\",\n        PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"test\"),\n    );\n    env::remove_var(\"MISE_TRUSTED_CONFIG_PATHS\");\n    env::remove_var(\"MISE_DISABLE_TOOLS\");\n    env::set_var(\"NO_COLOR\", \"1\");\n    env::set_var(\"MISE_CACHE_PRUNE_AGE\", \"0\");\n    env::set_var(\"MISE_CACHE_DIR\", env::HOME.join(\"data\").join(\"cache\"));\n    env::set_var(\"MISE_CONFIG_DIR\", env::HOME.join(\"config\"));\n    env::set_var(\"MISE_ENV\", \"\");\n    env::set_var(\"MISE_DATA_DIR\", env::HOME.join(\"data\"));\n    env::set_var(\"MISE_GLOBAL_CONFIG_FILE\", \"~/config/config.toml\");\n    env::set_var(\"MISE_SYSTEM_CONFIG_FILE\", \"doesntexist\");\n    env::set_var(\n        \"MISE_OVERRIDE_CONFIG_FILENAMES\",\n        \".test.mise.toml:test.config.toml\",\n    );\n    env::set_var(\n        \"MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES\",\n        \".test-tool-versions\",\n    );\n    env::set_var(\"MISE_STATE_DIR\", env::HOME.join(\"state\"));\n    env::set_var(\"MISE_USE_TOML\", \"0\");\n    env::set_var(\"MISE_YES\", \"1\");\n    file::remove_all(&*env::HOME.join(\"cwd\")).unwrap();\n    file::create_dir_all(&*env::HOME.join(\"cwd\").join(\".mise\").join(\"tasks\")).unwrap();\n    env::set_current_dir(env::HOME.join(\"cwd\")).unwrap();\n    file::write(\n        env::HOME.join(\"config\").join(\"config.toml\"),\n        indoc! {r#\"\n            [env]\n            TEST_ENV_VAR = 'test-123'\n\n            [alias.tiny.versions]\n            \"my/alias\" = '3.0'\n\n            [tasks.configtask]\n            run = 'echo \"configtask:\"'\n            [tasks.lint]\n            run = 'echo \"linting!\"'\n            [tasks.test]\n            run = 'echo \"testing!\"'\n            [settings]\n            always_keep_download = true\n            always_keep_install = true\n            idiomatic_version_file = true\n            plugin_autoupdate_last_check_duration = \"20m\"\n            jobs = 2\n            \"#},\n    )\n    .unwrap();\n    file::write(\n        env::HOME.join(\".test-tool-versions\"),\n        indoc! {r#\"\n            tiny  2\n            dummy ref:master\n            \"#},\n    )\n    .unwrap();\n    file::write(\n        env::current_dir().unwrap().join(\".test-tool-versions\"),\n        indoc! {r#\"\n            tiny 3\n            \"#},\n    )\n    .unwrap();\n    file::write(\n        \".mise/tasks/filetask\",\n        indoc! {r#\"#!/usr/bin/env bash\n        #MISE alias=\"ft\"\n        #MISE description=\"This is a test build script\"\n        #MISE depends=[\"lint\", \"test\"]\n        #MISE sources=[\".test-tool-versions\"]\n        #MISE outputs=[\"$MISE_PROJECT_ROOT/test/test-build-output.txt\"]\n        #MISE env={TEST_BUILDSCRIPT_ENV_VAR = \"VALID\", BOOLEAN_VAR = true}\n\n        #USAGE flag \"--user <user>\" help=\"The user to run as\"\n\n        set -exo pipefail\n        cd \"$MISE_PROJECT_ROOT\" || exit 1\n        echo \"running test-build script\"\n        echo \"TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR\" > test-build-output.txt\n        echo \"user=$usage_user\"\n        \"#},\n    )\n    .unwrap();\n    file::make_executable(\".mise/tasks/filetask\").unwrap();\n}\n\npub fn replace_path(input: &str) -> String {\n    let path = join_paths(&*env::PATH)\n        .unwrap()\n        .to_string_lossy()\n        .to_string();\n    let home = env::HOME.to_string_lossy().to_string();\n    input\n        .replace(&path, \"$PATH\")\n        .replace(&home, \"~\")\n        .replace(&*env::MISE_BIN.to_string_lossy(), \"mise\")\n}\n\n#[macro_export]\nmacro_rules! with_settings {\n    ($body:block) => {{\n        let home = $crate::env::HOME.to_string_lossy().to_string();\n        insta::with_settings!({sort_maps => true, filters => vec![\n            (home.as_str(), \"~\"),\n        ]}, {$body})\n    }}\n}\n"
  },
  {
    "path": "src/timeout.rs",
    "content": "use std::sync::mpsc;\nuse std::thread;\nuse std::time::Duration;\n\nuse crate::ui::time::format_duration;\nuse color_eyre::eyre::{Report, Result};\nuse std::fmt::{Display, Formatter};\n\n#[derive(Debug, Clone, Copy)]\npub struct TimeoutError {\n    pub duration: Duration,\n}\n\nimpl Display for TimeoutError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"timed out after {}\", format_duration(self.duration))\n    }\n}\n\nimpl std::error::Error for TimeoutError {}\n\npub fn run_with_timeout<F, T>(f: F, timeout: Duration) -> Result<T>\nwhere\n    F: FnOnce() -> Result<T> + Send,\n    T: Send,\n{\n    let (tx, rx) = mpsc::channel();\n    thread::scope(|s| {\n        s.spawn(move || {\n            let result = f();\n            // If sending fails, the timeout has already been reached.\n            let _ = tx.send(result);\n        });\n        let recv: Result<T> = rx\n            .recv_timeout(timeout)\n            .map_err(|_| Report::from(TimeoutError { duration: timeout }))?;\n        recv\n    })\n}\n\npub async fn run_with_timeout_async<F, Fut, T>(f: F, timeout: Duration) -> Result<T>\nwhere\n    Fut: Future<Output = Result<T>> + Send,\n    T: Send,\n    F: FnOnce() -> Fut,\n{\n    match tokio::time::timeout(timeout, f()).await {\n        Ok(Ok(output)) => Ok(output),\n        Ok(Err(e)) => Err(e),\n        Err(_) => Err(TimeoutError { duration: timeout }.into()),\n    }\n}\n"
  },
  {
    "path": "src/timings.rs",
    "content": "use crate::env;\nuse crate::ui::{style, time};\nuse std::time::{Duration, Instant};\n\npub fn start(module: &str) -> impl FnOnce() {\n    let start = Instant::now();\n    let module = module.to_string();\n    move || {\n        let diff = start.elapsed();\n        eprintln!(\"{}\", render(module.as_str(), diff));\n    }\n}\n\nstatic START: std::sync::Mutex<Option<Instant>> = std::sync::Mutex::new(None);\n\npub fn get_time_diff(module: &str) -> String {\n    if *env::MISE_TIMINGS == 0 {\n        return \"\".to_string();\n    }\n    static PREV: std::sync::Mutex<Option<Instant>> = std::sync::Mutex::new(None);\n    let now = Instant::now();\n    if PREV.lock().unwrap().is_none() {\n        *START.lock().unwrap() = Some(now);\n        *PREV.lock().unwrap() = Some(now);\n    }\n    let mut prev = PREV.lock().unwrap();\n    let diff = now.duration_since(prev.unwrap());\n    *prev = Some(now);\n    render(module, diff)\n}\n\nfn render(module: &str, diff: Duration) -> String {\n    let diff_str = if *env::MISE_TIMINGS == 2 {\n        let relative = time::format_duration(diff);\n        let from_start =\n            time::format_duration(Instant::now().duration_since(START.lock().unwrap().unwrap()));\n        format!(\"{relative} {from_start}\")\n    } else {\n        time::format_duration(diff)\n    };\n    let thread_id = crate::logger::thread_id();\n    let out = format!(\"[TIME] {thread_id} {module} {diff_str}\")\n        .trim()\n        .to_string();\n    if diff.as_micros() > 8000 {\n        style::eblack(out).on_red().bold()\n    } else if diff.as_micros() > 4000 {\n        style::eblack(out).on_red()\n    } else if diff.as_micros() > 2000 {\n        style::ered(out).bright()\n    } else if diff.as_micros() > 1000 {\n        style::eyellow(out).bright()\n    } else if diff.as_micros() > 500 {\n        style::eyellow(out).dim()\n    } else if diff.as_micros() > 100 {\n        style::ecyan(out).dim()\n    } else {\n        style::edim(out)\n    }\n    .to_string()\n}\n\n#[macro_export]\nmacro_rules! time {\n    ($fn:expr) => {{\n        if *$crate::env::MISE_TIMINGS > 1 {\n            let module = format!(\"{}::{}\", module_path!(), format!($fn));\n            eprintln!(\"{}\", $crate::timings::get_time_diff(&module));\n        } else {\n            trace!($fn);\n        }\n    }};\n    ($fn:expr, $($arg:tt)+) => {{\n        if *$crate::env::MISE_TIMINGS > 1 {\n            let module = format!(\"{}::{}\", module_path!(), format!($fn, $($arg)+));\n            eprintln!(\"{}\", $crate::timings::get_time_diff(&module));\n        } else {\n            trace!($fn, $($arg)+);\n        }\n    }};\n}\n\n#[macro_export]\nmacro_rules! progress_trace {\n    ($($arg:tt)+) => {{\n        if *$crate::env::MISE_PROGRESS_TRACE {\n            eprintln!(\"[PROGRESS] {}\", format!($($arg)+));\n        }\n    }};\n}\n\n#[macro_export]\nmacro_rules! measure {\n    ($fmt:expr, $block:block) => {{\n        if *$crate::env::MISE_TIMINGS > 0 {\n            let module = format!(\"{}::{}\", module_path!(), format!($fmt));\n            let end = $crate::timings::start(&module);\n            let result = $block;\n            end();\n            result\n        } else if log::log_enabled!(log::Level::Trace) {\n            let msg = format!($fmt);\n            trace!(\"{msg} start\");\n            let result = $block;\n            trace!(\"{msg} done\");\n            result\n        } else {\n            $block\n        }\n    }};\n}\n"
  },
  {
    "path": "src/toml.rs",
    "content": "use std::collections::HashSet;\n\n#[macro_export]\nmacro_rules! parse_error {\n    ($key:expr, $val:expr, $t:expr) => {{\n        use eyre::bail;\n\n        bail!(\n            r#\"expected value of {} to be a {}, got: {}\"#,\n            $crate::ui::style::eyellow($key),\n            $crate::ui::style::ecyan($t),\n            $crate::ui::style::eblue($val.to_string().trim()),\n        )\n    }};\n}\n\npub fn dedup_toml_array(array: &toml_edit::Array) -> toml_edit::Array {\n    let mut seen = HashSet::new();\n    let mut deduped = toml_edit::Array::new();\n    for item in array.iter() {\n        if seen.insert(item.as_str()) {\n            deduped.push(item.clone());\n        }\n    }\n    deduped\n}\n"
  },
  {
    "path": "src/toolset/builder.rs",
    "content": "use std::sync::Arc;\n\nuse eyre::Result;\nuse itertools::Itertools;\n\nuse crate::cli::args::{BackendArg, ToolArg};\nuse crate::config::{Config, ConfigMap};\nuse crate::env_diff::EnvMap;\nuse crate::errors::Error;\nuse crate::toolset::{ResolveOptions, ToolRequest, ToolSource, Toolset};\nuse crate::{config, env};\n\n#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]\npub enum ConfigScope {\n    /// Include tools from all config files\n    #[default]\n    All,\n    /// Only include tools from local (non-global) config files\n    LocalOnly,\n    /// Only include tools from the global config file\n    GlobalOnly,\n}\n\n#[derive(Debug, Default)]\npub struct ToolsetBuilder {\n    args: Vec<ToolArg>,\n    scope: ConfigScope,\n    default_to_latest: bool,\n    resolve_options: ResolveOptions,\n    config_files: Option<ConfigMap>,\n}\n\nimpl ToolsetBuilder {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn with_args(mut self, args: &[ToolArg]) -> Self {\n        self.args = args.to_vec();\n        self\n    }\n\n    pub fn with_default_to_latest(mut self, default_to_latest: bool) -> Self {\n        self.default_to_latest = default_to_latest;\n        self\n    }\n\n    pub fn with_scope(mut self, scope: ConfigScope) -> Self {\n        self.scope = scope;\n        self\n    }\n\n    pub fn with_resolve_options(mut self, resolve_options: ResolveOptions) -> Self {\n        self.resolve_options = resolve_options;\n        self\n    }\n\n    /// Use custom config files instead of config.config_files\n    pub fn with_config_files(mut self, config_files: ConfigMap) -> Self {\n        self.config_files = Some(config_files);\n        self\n    }\n\n    pub async fn build(self, config: &Arc<Config>) -> Result<Toolset> {\n        let mut toolset = Toolset {\n            ..Default::default()\n        };\n        measure!(\"toolset_builder::build::load_config_files\", {\n            self.load_config_files(config, &mut toolset)?;\n        });\n        measure!(\"toolset_builder::build::load_runtime_env\", {\n            self.load_runtime_env(&mut toolset, env::vars_safe().collect())?;\n        });\n        measure!(\"toolset_builder::build::load_runtime_args\", {\n            self.load_runtime_args(&mut toolset)?;\n        });\n        measure!(\"toolset_builder::build::resolve\", {\n            if let Err(err) = toolset\n                .resolve_with_opts(config, &self.resolve_options)\n                .await\n            {\n                if Error::is_argument_err(&err) {\n                    return Err(err);\n                }\n                warn!(\"failed to resolve toolset: {err}\");\n            }\n        });\n\n        time!(\"toolset::builder::build\");\n        Ok(toolset)\n    }\n\n    fn load_config_files(&self, config: &Arc<Config>, ts: &mut Toolset) -> eyre::Result<()> {\n        let config_files = self.config_files.as_ref().unwrap_or(&config.config_files);\n\n        for cf in config_files.values().rev() {\n            let is_global = config::is_global_config(cf.get_path());\n            match self.scope {\n                ConfigScope::GlobalOnly if !is_global => continue,\n                ConfigScope::LocalOnly if is_global => continue,\n                _ => {}\n            }\n            ts.merge(cf.to_toolset()?);\n        }\n        Ok(())\n    }\n\n    fn load_runtime_env(&self, ts: &mut Toolset, env: EnvMap) -> eyre::Result<()> {\n        if self.scope == ConfigScope::LocalOnly {\n            // LocalOnly excludes env-based tool versions (MISE_*_VERSION).\n            return Ok(());\n        }\n        for (k, v) in env {\n            if k.starts_with(\"MISE_\") && k.ends_with(\"_VERSION\") && k != \"MISE_VERSION\" {\n                let plugin_name = k\n                    .trim_start_matches(\"MISE_\")\n                    .trim_end_matches(\"_VERSION\")\n                    .to_lowercase();\n                if plugin_name == \"install\" {\n                    // ignore MISE_INSTALL_VERSION\n                    continue;\n                }\n                let ba: Arc<BackendArg> = Arc::new(plugin_name.as_str().into());\n                let source = ToolSource::Environment(k, v.clone());\n                let mut env_ts = Toolset::new(source.clone());\n                for v in v.split_whitespace() {\n                    let tvr = ToolRequest::new(ba.clone(), v, source.clone())?;\n                    env_ts.add_version(tvr);\n                }\n                ts.merge(env_ts);\n            }\n        }\n        Ok(())\n    }\n\n    fn load_runtime_args(&self, ts: &mut Toolset) -> eyre::Result<()> {\n        for (_, args) in self.args.iter().into_group_map_by(|arg| arg.ba.clone()) {\n            let mut arg_ts = Toolset::new(ToolSource::Argument);\n            for arg in args {\n                if let Some(tvr) = &arg.tvr {\n                    arg_ts.add_version(tvr.clone());\n                } else if self.default_to_latest {\n                    // this logic is required for `mise x` because with that specific command mise\n                    // should default to installing the \"latest\" version if no version is specified\n                    // in mise.toml\n\n                    // determine if we already have some active version in config\n                    let current_active = ts\n                        .list_current_requests()\n                        .into_iter()\n                        .find(|tvr| tvr.ba() == &arg.ba);\n\n                    if let Some(current_active) = current_active {\n                        // active version, so don't set \"latest\"\n                        arg_ts.add_version(ToolRequest::new(\n                            arg.ba.clone(),\n                            &current_active.version(),\n                            ToolSource::Argument,\n                        )?);\n                    } else {\n                        // no active version, so use \"latest\"\n                        arg_ts.add_version(ToolRequest::new(\n                            arg.ba.clone(),\n                            \"latest\",\n                            ToolSource::Argument,\n                        )?);\n                    }\n                }\n            }\n            ts.merge(arg_ts);\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/toolset/env_cache.rs",
    "content": "use std::collections::{BTreeMap, BTreeSet};\nuse std::path::{Path, PathBuf};\nuse std::time::SystemTime;\n\nuse base64::Engine;\nuse base64::prelude::BASE64_STANDARD;\nuse blake3::Hasher;\nuse chacha20poly1305::{\n    ChaCha20Poly1305, KeyInit, Nonce,\n    aead::{Aead, AeadCore, OsRng},\n};\nuse eyre::{Result, bail};\nuse indexmap::IndexMap;\nuse serde::{Deserialize, Serialize};\n\nuse crate::config::Settings;\nuse crate::dirs;\nuse crate::file;\n\nfn get_encryption_key() -> Option<[u8; 32]> {\n    std::env::var(\"__MISE_ENV_CACHE_KEY\").ok().and_then(|s| {\n        let bytes = BASE64_STANDARD.decode(&s).ok()?;\n        bytes.try_into().ok()\n    })\n}\n\nfn encrypt_data(data: &[u8], key: &[u8; 32]) -> Result<Vec<u8>> {\n    let cipher = ChaCha20Poly1305::new_from_slice(key)\n        .map_err(|e| eyre::eyre!(\"failed to create cipher: {}\", e))?;\n    let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);\n    let ciphertext = cipher\n        .encrypt(&nonce, data)\n        .map_err(|e| eyre::eyre!(\"encryption failed: {}\", e))?;\n\n    // Format: nonce || ciphertext\n    let mut result = nonce.to_vec();\n    result.extend(ciphertext);\n    Ok(result)\n}\n\nfn decrypt_data(data: &[u8], key: &[u8; 32]) -> Result<Vec<u8>> {\n    if data.len() < 12 {\n        bail!(\"data too short to contain nonce\");\n    }\n\n    let nonce = Nonce::from_slice(&data[..12]);\n    let ciphertext = &data[12..];\n\n    let cipher = ChaCha20Poly1305::new_from_slice(key)\n        .map_err(|e| eyre::eyre!(\"failed to create cipher: {}\", e))?;\n\n    let plaintext = cipher\n        .decrypt(nonce, ciphertext)\n        .map_err(|e| eyre::eyre!(\"decryption failed: {}\", e))?;\n    Ok(plaintext)\n}\n\nfn validate_watch_files(watch_files: &[PathBuf], expected_mtimes: &[u64]) -> Result<()> {\n    if watch_files.len() != expected_mtimes.len() {\n        bail!(\"watch file count mismatch\");\n    }\n    for (path, expected_mtime) in watch_files.iter().zip(expected_mtimes.iter()) {\n        if !path.exists() {\n            // mtime=0 means file didn't exist when cached - skip if still doesn't exist\n            if *expected_mtime == 0 {\n                continue;\n            }\n            bail!(\"watch file no longer exists: {}\", path.display());\n        }\n        if let Some(current_mtime) = get_file_mtime(path) {\n            if current_mtime != *expected_mtime {\n                bail!(\n                    \"watch file mtime changed: {} (expected: {}, current: {})\",\n                    path.display(),\n                    expected_mtime,\n                    current_mtime\n                );\n            }\n        } else {\n            bail!(\"could not get mtime for watch file: {}\", path.display());\n        }\n    }\n    Ok(())\n}\n\n/// Represents the cached environment data\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct CachedEnv {\n    /// Cached environment variables\n    pub env: BTreeMap<String, String>,\n    /// User-configured paths from env._.path directives\n    pub user_paths: Vec<PathBuf>,\n    /// Tool paths from installations\n    pub tool_paths: Vec<PathBuf>,\n    /// Time when the cache was created\n    pub created_at: u64,\n    /// Files to watch for changes (from modules and _.source directives)\n    pub watch_files: Vec<PathBuf>,\n    /// mtimes of watch files at cache creation time\n    pub watch_file_mtimes: Vec<u64>,\n    /// mise version when cache was created\n    pub mise_version: String,\n    /// SHA256 of the original cache key inputs (for debugging)\n    pub cache_key_debug: String,\n}\n\n/// Cached environment data for non-tool env results (config-time env resolution)\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct CachedNonToolEnv {\n    /// Environment variables resolved from non-tool directives\n    pub env: IndexMap<String, (String, PathBuf)>,\n    /// Variables removed by env directives\n    pub env_remove: BTreeSet<String>,\n    /// dotenv files used\n    pub env_files: Vec<PathBuf>,\n    /// paths added by env directives\n    pub env_paths: Vec<PathBuf>,\n    /// scripts sourced by env directives\n    pub env_scripts: Vec<PathBuf>,\n    /// redaction patterns contributed by env directives\n    pub redactions: Vec<String>,\n    /// Files to watch for changes (from modules and _.source directives)\n    pub watch_files: Vec<PathBuf>,\n    /// mtimes of watch files at cache creation time\n    pub watch_file_mtimes: Vec<u64>,\n    /// Time when the cache was created\n    pub created_at: u64,\n    /// mise version when cache was created\n    pub mise_version: String,\n    /// SHA256 of the original cache key inputs (for debugging)\n    pub cache_key_debug: String,\n}\n\nimpl CachedEnv {\n    /// Returns the directory where env cache files are stored\n    pub fn cache_dir() -> PathBuf {\n        dirs::STATE.join(\"env-cache\")\n    }\n\n    /// Computes the cache key based on config files, settings, tool versions, etc.\n    pub fn compute_cache_key(\n        config_files: &[(PathBuf, u64)],    // (path, mtime)\n        tool_versions: &[(String, String)], // (tool, version)\n        settings_hash: &str,\n        base_path: &str,\n    ) -> String {\n        let mut hasher = Hasher::new();\n\n        // mise version\n        hasher.update(env!(\"CARGO_PKG_VERSION\").as_bytes());\n\n        // config files and their mtimes\n        for (path, mtime) in config_files {\n            hasher.update(path.to_string_lossy().as_bytes());\n            hasher.update(&mtime.to_le_bytes());\n        }\n\n        // tool versions\n        for (tool, version) in tool_versions {\n            hasher.update(tool.as_bytes());\n            hasher.update(version.as_bytes());\n        }\n\n        // settings hash\n        hasher.update(settings_hash.as_bytes());\n\n        // base PATH\n        hasher.update(base_path.as_bytes());\n\n        let hash = hasher.finalize();\n        hex::encode(hash.as_bytes())\n    }\n\n    /// Generates a new encryption key and returns it as a base64 string\n    pub fn generate_encryption_key() -> String {\n        let key = ChaCha20Poly1305::generate_key(&mut OsRng);\n        BASE64_STANDARD.encode(key)\n    }\n\n    /// Ensures an encryption key exists, returns one if not set\n    pub fn ensure_encryption_key() -> String {\n        std::env::var(\"__MISE_ENV_CACHE_KEY\").unwrap_or_else(|_| Self::generate_encryption_key())\n    }\n\n    /// Loads a cached environment from disk\n    pub fn load(cache_key: &str) -> Result<Option<Self>> {\n        let key = match get_encryption_key() {\n            Some(k) => k,\n            None => {\n                trace!(\"env_cache: no encryption key set, skipping cache load\");\n                return Ok(None);\n            }\n        };\n\n        let cache_file = Self::cache_dir().join(cache_key);\n        if !cache_file.exists() {\n            trace!(\n                \"env_cache: cache file does not exist: {}\",\n                cache_file.display()\n            );\n            return Ok(None);\n        }\n\n        let encrypted_data = file::read(&cache_file)?;\n        let decrypted_data = match decrypt_data(&encrypted_data, &key) {\n            Ok(data) => data,\n            Err(e) => {\n                debug!(\"env_cache: decryption failed (key changed?): {}\", e);\n                // Remove stale cache file\n                let _ = file::remove_file(&cache_file);\n                return Ok(None);\n            }\n        };\n\n        let cached: CachedEnv = match rmp_serde::from_slice(&decrypted_data) {\n            Ok(c) => c,\n            Err(e) => {\n                debug!(\"env_cache: deserialization failed: {}\", e);\n                let _ = file::remove_file(&cache_file);\n                return Ok(None);\n            }\n        };\n\n        // Validate mise version\n        if cached.mise_version != env!(\"CARGO_PKG_VERSION\") {\n            debug!(\n                \"env_cache: mise version mismatch (cached: {}, current: {})\",\n                cached.mise_version,\n                env!(\"CARGO_PKG_VERSION\")\n            );\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        // Check TTL\n        let now = SystemTime::now()\n            .duration_since(SystemTime::UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_secs();\n        let ttl = Settings::get().env_cache_ttl().as_secs();\n        let age = now.saturating_sub(cached.created_at);\n        if age > ttl {\n            debug!(\"env_cache: cache expired (age: {}s, ttl: {}s)\", age, ttl);\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        // Check watch files mtimes\n        if let Err(e) = validate_watch_files(&cached.watch_files, &cached.watch_file_mtimes) {\n            debug!(\"env_cache: watch file validation failed: {}\", e);\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        trace!(\"env_cache: loaded cache for key {}\", cache_key);\n        Ok(Some(cached))\n    }\n\n    /// Saves a cached environment to disk\n    pub fn save(&self, cache_key: &str) -> Result<()> {\n        let key = match get_encryption_key() {\n            Some(k) => k,\n            None => {\n                trace!(\"env_cache: no encryption key set, skipping cache save\");\n                return Ok(());\n            }\n        };\n\n        let cache_dir = Self::cache_dir();\n        file::create_dir_all(&cache_dir)?;\n\n        let serialized = rmp_serde::to_vec(self)?;\n        let encrypted = encrypt_data(&serialized, &key)?;\n\n        let cache_file = cache_dir.join(cache_key);\n        file::write(&cache_file, &encrypted)?;\n\n        trace!(\"env_cache: saved cache for key {}\", cache_key);\n        Ok(())\n    }\n\n    /// Returns true if env caching is enabled and we have an encryption key\n    pub fn is_enabled() -> bool {\n        Settings::get().env_cache && get_encryption_key().is_some()\n    }\n\n    /// Clears all env cache files\n    pub fn clear() -> Result<()> {\n        let cache_dir = Self::cache_dir();\n        if cache_dir.exists() {\n            file::remove_all(&cache_dir)?;\n        }\n        Ok(())\n    }\n}\n\nimpl CachedNonToolEnv {\n    /// Returns the directory where env cache files are stored\n    pub fn cache_dir() -> PathBuf {\n        CachedEnv::cache_dir()\n    }\n\n    /// Computes the cache key based on config files and settings\n    pub fn compute_cache_key(\n        config_files: &[(PathBuf, u64)], // (path, mtime)\n        settings_hash: &str,\n        base_path: &str,\n    ) -> String {\n        let mut hasher = Hasher::new();\n\n        // scope to non-tool env cache\n        hasher.update(b\"non-tool-env\");\n\n        // mise version\n        hasher.update(env!(\"CARGO_PKG_VERSION\").as_bytes());\n\n        // config files and their mtimes\n        for (path, mtime) in config_files {\n            hasher.update(path.to_string_lossy().as_bytes());\n            hasher.update(&mtime.to_le_bytes());\n        }\n\n        // settings hash\n        hasher.update(settings_hash.as_bytes());\n\n        // base PATH\n        hasher.update(base_path.as_bytes());\n\n        let hash = hasher.finalize();\n        hex::encode(hash.as_bytes())\n    }\n\n    /// Loads cached non-tool env data if it exists and is valid\n    pub fn load(cache_key: &str) -> Result<Option<Self>> {\n        let key = match get_encryption_key() {\n            Some(k) => k,\n            None => {\n                trace!(\"env_cache: no encryption key set, skipping cache load\");\n                return Ok(None);\n            }\n        };\n\n        let cache_file = Self::cache_dir().join(cache_key);\n        if !cache_file.exists() {\n            trace!(\n                \"env_cache: cache file does not exist: {}\",\n                cache_file.display()\n            );\n            return Ok(None);\n        }\n\n        let encrypted_data = file::read(&cache_file)?;\n        let decrypted_data = match decrypt_data(&encrypted_data, &key) {\n            Ok(data) => data,\n            Err(e) => {\n                debug!(\"env_cache: decryption failed: {}\", e);\n                let _ = file::remove_file(&cache_file);\n                return Ok(None);\n            }\n        };\n\n        let cached: CachedNonToolEnv = match rmp_serde::from_slice(&decrypted_data) {\n            Ok(c) => c,\n            Err(e) => {\n                debug!(\"env_cache: deserialization failed: {}\", e);\n                let _ = file::remove_file(&cache_file);\n                return Ok(None);\n            }\n        };\n\n        // Validate mise version\n        if cached.mise_version != env!(\"CARGO_PKG_VERSION\") {\n            debug!(\n                \"env_cache: mise version mismatch (cached: {}, current: {})\",\n                cached.mise_version,\n                env!(\"CARGO_PKG_VERSION\")\n            );\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        // Check TTL\n        let now = SystemTime::now()\n            .duration_since(SystemTime::UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_secs();\n        let ttl = Settings::get().env_cache_ttl().as_secs();\n        let age = now.saturating_sub(cached.created_at);\n        if age > ttl {\n            debug!(\"env_cache: cache expired (age: {}s, ttl: {}s)\", age, ttl);\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        // Check watch files mtimes\n        if let Err(e) = validate_watch_files(&cached.watch_files, &cached.watch_file_mtimes) {\n            debug!(\"env_cache: watch file validation failed: {}\", e);\n            let _ = file::remove_file(&cache_file);\n            return Ok(None);\n        }\n\n        trace!(\"env_cache: loaded non-tool env cache for key {}\", cache_key);\n        Ok(Some(cached))\n    }\n\n    /// Saves cached non-tool env data to disk\n    pub fn save(&self, cache_key: &str) -> Result<()> {\n        let key = match get_encryption_key() {\n            Some(k) => k,\n            None => {\n                trace!(\"env_cache: no encryption key set, skipping cache save\");\n                return Ok(());\n            }\n        };\n\n        let cache_dir = Self::cache_dir();\n        file::create_dir_all(&cache_dir)?;\n\n        let serialized = rmp_serde::to_vec(self)?;\n        let encrypted = encrypt_data(&serialized, &key)?;\n\n        let cache_file = cache_dir.join(cache_key);\n        file::write(&cache_file, &encrypted)?;\n\n        trace!(\"env_cache: saved non-tool env cache for key {}\", cache_key);\n        Ok(())\n    }\n\n    /// Returns true if env caching is enabled and we have an encryption key\n    pub fn is_enabled() -> bool {\n        Settings::get().env_cache && get_encryption_key().is_some()\n    }\n}\n\n/// Helper to get the mtime of a file as seconds since UNIX epoch\npub fn get_file_mtime(path: &Path) -> Option<u64> {\n    std::fs::metadata(path)\n        .ok()\n        .and_then(|m| m.modified().ok())\n        .and_then(|t| t.duration_since(SystemTime::UNIX_EPOCH).ok())\n        .map(|d| d.as_secs())\n}\n\n/// Computes a hash of the current settings that affect env computation\npub fn compute_settings_hash() -> String {\n    let settings = Settings::get();\n    let mut hasher = Hasher::new();\n\n    // Add settings that affect env computation\n    hasher.update(settings.experimental.to_string().as_bytes());\n    hasher.update(settings.all_compile.to_string().as_bytes());\n\n    // Add any other relevant settings\n    if let Some(env_file) = &settings.env_file {\n        hasher.update(env_file.to_string_lossy().as_bytes());\n    }\n\n    let hash = hasher.finalize();\n    hex::encode(&hash.as_bytes()[..8]) // Short hash for debugging\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cache_key_computation() {\n        let config_files = vec![(PathBuf::from(\"/home/user/project/mise.toml\"), 1234567890u64)];\n        let tool_versions = vec![(\"node\".to_string(), \"20.0.0\".to_string())];\n        let settings_hash = \"abc123\";\n        let base_path = \"/usr/bin:/bin\";\n\n        let key1 =\n            CachedEnv::compute_cache_key(&config_files, &tool_versions, settings_hash, base_path);\n\n        // Same inputs should produce same key\n        let key2 =\n            CachedEnv::compute_cache_key(&config_files, &tool_versions, settings_hash, base_path);\n        assert_eq!(key1, key2);\n\n        // Different mtime should produce different key\n        let config_files_changed =\n            vec![(PathBuf::from(\"/home/user/project/mise.toml\"), 1234567891u64)];\n        let key3 = CachedEnv::compute_cache_key(\n            &config_files_changed,\n            &tool_versions,\n            settings_hash,\n            base_path,\n        );\n        assert_ne!(key1, key3);\n    }\n\n    #[test]\n    fn test_encryption_roundtrip() {\n        let key: [u8; 32] = rand::random();\n        let data = b\"hello world\";\n\n        let encrypted = encrypt_data(data, &key).unwrap();\n        let decrypted = decrypt_data(&encrypted, &key).unwrap();\n\n        assert_eq!(data.as_slice(), decrypted.as_slice());\n    }\n\n    #[test]\n    fn test_generate_encryption_key() {\n        let key1 = CachedEnv::generate_encryption_key();\n        let key2 = CachedEnv::generate_encryption_key();\n\n        // Keys should be different\n        assert_ne!(key1, key2);\n\n        // Keys should be valid base64\n        assert!(BASE64_STANDARD.decode(&key1).is_ok());\n        assert!(BASE64_STANDARD.decode(&key2).is_ok());\n\n        // Decoded keys should be 32 bytes\n        assert_eq!(BASE64_STANDARD.decode(&key1).unwrap().len(), 32);\n    }\n}\n"
  },
  {
    "path": "src/toolset/helpers.rs",
    "content": "use std::sync::Arc;\n\nuse crate::backend::Backend;\nuse crate::toolset::tool_request::ToolRequest;\nuse crate::toolset::tool_version::ToolVersion;\n\npub(super) type TVTuple = (Arc<dyn Backend>, ToolVersion);\n\npub(super) fn show_python_install_hint(versions: &[ToolRequest]) {\n    let num_python = versions\n        .iter()\n        .filter(|tr| tr.ba().tool_name == \"python\")\n        .count();\n    if num_python != 1 {\n        return;\n    }\n    hint!(\n        \"python_multi\",\n        \"use multiple versions simultaneously with\",\n        \"mise use python@3.12 python@3.11\"\n    );\n}\n"
  },
  {
    "path": "src/toolset/install_options.rs",
    "content": "use std::path::PathBuf;\n\nuse crate::config::settings::Settings;\nuse crate::toolset::tool_version::ResolveOptions;\n\n#[derive(Debug, Clone)]\npub struct InstallOptions {\n    pub reason: String,\n    pub force: bool,\n    pub jobs: Option<usize>,\n    pub raw: bool,\n    /// only install missing tools if passed as arguments\n    pub missing_args_only: bool,\n    /// completely disable auto-installation when auto_install setting is false\n    pub skip_auto_install: bool,\n    pub auto_install_disable_tools: Option<Vec<String>>,\n    pub resolve_options: ResolveOptions,\n    pub dry_run: bool,\n    /// require lockfile URLs to be present; fail if not\n    pub locked: bool,\n    /// Override the install directory (e.g. for --system or --shared)\n    pub install_dir: Option<PathBuf>,\n}\n\nimpl Default for InstallOptions {\n    fn default() -> Self {\n        InstallOptions {\n            jobs: Some(Settings::get().jobs),\n            raw: Settings::get().raw,\n            reason: \"install\".to_string(),\n            force: false,\n            missing_args_only: true,\n            skip_auto_install: false,\n            auto_install_disable_tools: Settings::get().auto_install_disable_tools.clone(),\n            resolve_options: Default::default(),\n            dry_run: false,\n            locked: Settings::get().locked,\n            install_dir: None,\n        }\n    }\n}\n"
  },
  {
    "path": "src/toolset/install_state.rs",
    "content": "use crate::backend::backend_type::BackendType;\nuse crate::cli::args::BackendArg;\nuse crate::file::display_path;\nuse crate::git::Git;\nuse crate::plugins::PluginType;\nuse crate::toolset::{EPHEMERAL_OPT_KEYS, parse_tool_options};\nuse crate::{dirs, env, file, runtime_symlinks};\nuse eyre::{Ok, Result};\nuse heck::ToKebabCase;\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize};\nuse std::collections::BTreeMap;\nuse std::ops::Deref;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, Mutex};\nuse versions::Versioning;\n\n/// Normalize a version string for sorting by stripping leading 'v' or 'V' prefix.\n/// This ensures \"v1.0.0\" and \"1.0.0\" are sorted together correctly.\nfn normalize_version_for_sort(v: &str) -> &str {\n    v.strip_prefix('v')\n        .or_else(|| v.strip_prefix('V'))\n        .unwrap_or(v)\n}\n\ntype InstallStatePlugins = BTreeMap<String, PluginType>;\ntype InstallStateTools = BTreeMap<String, InstallStateTool>;\ntype MutexResult<T> = Result<Arc<T>>;\n\n#[derive(Debug, Clone)]\npub struct InstallStateTool {\n    pub short: String,\n    pub full: Option<String>,\n    pub versions: Vec<String>,\n    pub explicit_backend: bool,\n    pub opts: BTreeMap<String, toml::Value>,\n    pub installs_path: Option<PathBuf>,\n}\n\n/// Entry in the consolidated manifest file (.mise-installs.toml).\n/// Versions are NOT stored here — they come from the filesystem.\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct ManifestTool {\n    /// Original short name (e.g. \"github:jdx/mise-test-fixtures\").\n    /// May differ from the manifest key (which is the kebab-cased dir name).\n    short: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    full: Option<String>,\n    #[serde(default = \"default_true\")]\n    explicit_backend: bool,\n    #[serde(default, skip_serializing_if = \"BTreeMap::is_empty\")]\n    opts: BTreeMap<String, toml::Value>,\n}\n\nfn default_true() -> bool {\n    true\n}\n\n/// In-memory representation of the manifest keyed by short name.\ntype Manifest = BTreeMap<String, ManifestTool>;\n\nstatic INSTALL_STATE_PLUGINS: Mutex<Option<Arc<InstallStatePlugins>>> = Mutex::new(None);\nstatic INSTALL_STATE_TOOLS: Mutex<Option<Arc<InstallStateTools>>> = Mutex::new(None);\nstatic MANIFEST_LOCK: Mutex<()> = Mutex::new(());\n\nfn manifest_path() -> PathBuf {\n    dirs::INSTALLS.join(\".mise-installs.toml\")\n}\n\n/// Read the consolidated manifest file. Returns empty map if it doesn't exist.\nfn read_manifest() -> Manifest {\n    read_manifest_from(&manifest_path())\n}\n\nfn read_manifest_from(path: &Path) -> Manifest {\n    match file::read_to_string(path) {\n        std::result::Result::Ok(body) => match toml::from_str(&body) {\n            std::result::Result::Ok(m) => m,\n            Err(err) => {\n                warn!(\n                    \"failed to parse manifest at {}: {err:#}\",\n                    display_path(path)\n                );\n                Default::default()\n            }\n        },\n        Err(_) => Default::default(),\n    }\n}\n\n/// Write the consolidated manifest file.\nfn write_manifest(manifest: &Manifest) -> Result<()> {\n    write_manifest_to(&manifest_path(), manifest)\n}\n\nfn write_manifest_to(path: &Path, manifest: &Manifest) -> Result<()> {\n    let body = toml::to_string_pretty(manifest)?;\n    file::write(path, body.trim())?;\n    Ok(())\n}\n\n/// Read a legacy `.mise.backend` file for migration purposes.\n///\n/// Returns `Some((short, full, explicit_backend))` if legacy metadata is found.\nfn read_legacy_backend_meta(short: &str) -> Option<(String, Option<String>, bool)> {\n    // Try .mise.backend.json first (oldest format)\n    let json_path = dirs::INSTALLS.join(short).join(\".mise.backend.json\");\n    if json_path.exists()\n        && let std::result::Result::Ok(f) = file::open(&json_path)\n        && let std::result::Result::Ok(json) = serde_json::from_reader::<_, serde_json::Value>(f)\n    {\n        let full = json.get(\"id\").and_then(|id| id.as_str()).map(String::from);\n        let s = json\n            .get(\"short\")\n            .and_then(|s| s.as_str())\n            .unwrap_or(short)\n            .to_string();\n        return Some((s, full, true));\n    }\n\n    // Try .mise.backend (text format)\n    let path = dirs::INSTALLS\n        .join(short.to_kebab_case())\n        .join(\".mise.backend\");\n    if !path.exists() {\n        return None;\n    }\n    let body = match file::read_to_string(&path) {\n        std::result::Result::Ok(body) => body,\n        Err(err) => {\n            warn!(\n                \"failed to read backend meta at {}: {err:?}\",\n                display_path(&path)\n            );\n            return None;\n        }\n    };\n    let lines: Vec<&str> = body.lines().filter(|f| !f.is_empty()).collect();\n    let s = lines.first().unwrap_or(&short).to_string();\n    let full = lines.get(1).map(|f| f.to_string());\n    let explicit_backend = lines.get(2).is_some_and(|v| *v == \"1\");\n    Some((s, full, explicit_backend))\n}\n\npub(crate) async fn init() -> Result<()> {\n    let (plugins, tools) = tokio::join!(\n        tokio::task::spawn(async { measure!(\"init_plugins\", { init_plugins().await }) }),\n        tokio::task::spawn(async { measure!(\"init_tools\", { init_tools().await }) }),\n    );\n    plugins??;\n    tools??;\n    Ok(())\n}\n\nasync fn init_plugins() -> MutexResult<InstallStatePlugins> {\n    if let Some(plugins) = INSTALL_STATE_PLUGINS\n        .lock()\n        .expect(\"INSTALL_STATE_PLUGINS lock failed\")\n        .clone()\n    {\n        return Ok(plugins);\n    }\n    let dirs = file::dir_subdirs(&dirs::PLUGINS)?;\n    let plugins: InstallStatePlugins = dirs\n        .into_iter()\n        .filter_map(|d| {\n            time!(\"init_plugins {d}\");\n            let path = dirs::PLUGINS.join(&d);\n            if is_banned_plugin(&path) {\n                info!(\"removing banned plugin {d}\");\n                let _ = file::remove_all(&path);\n                None\n            } else if path.join(\"metadata.lua\").exists() {\n                if has_backend_methods(&path) {\n                    Some((d, PluginType::VfoxBackend))\n                } else {\n                    Some((d, PluginType::Vfox))\n                }\n            } else if path.join(\"bin\").join(\"list-all\").exists() {\n                Some((d, PluginType::Asdf))\n            } else {\n                None\n            }\n        })\n        .collect();\n    let plugins = Arc::new(plugins);\n    *INSTALL_STATE_PLUGINS\n        .lock()\n        .expect(\"INSTALL_STATE_PLUGINS lock failed\") = Some(plugins.clone());\n    Ok(plugins)\n}\n\nasync fn init_tools() -> MutexResult<InstallStateTools> {\n    if let Some(tools) = INSTALL_STATE_TOOLS\n        .lock()\n        .expect(\"INSTALL_STATE_TOOLS lock failed\")\n        .clone()\n    {\n        return Ok(tools);\n    }\n\n    // 1. Read manifest (1 syscall)\n    let manifest = read_manifest();\n\n    // 2. List install dirs (1 syscall)\n    let subdirs = file::dir_subdirs(&dirs::INSTALLS)?;\n\n    // 3. For each dir, read versions from filesystem and merge with manifest metadata.\n    //    Only clone the manifest for mutation if we actually need to migrate legacy entries.\n    let mut updated_manifest: Option<Manifest> = None;\n    let mut tools = BTreeMap::new();\n    for dir_name in subdirs {\n        let dir = dirs::INSTALLS.join(&dir_name);\n\n        // Read versions from filesystem (1 syscall per tool — unavoidable)\n        let versions: Vec<String> = file::dir_subdirs(&dir)\n            .unwrap_or_else(|err| {\n                warn!(\"reading versions in {} failed: {err:?}\", display_path(&dir));\n                Default::default()\n            })\n            .into_iter()\n            .filter(|v| !v.starts_with('.'))\n            .filter(|v| !runtime_symlinks::is_runtime_symlink(&dir.join(v)))\n            .filter(|v| !dir.join(v).join(\"incomplete\").exists())\n            .sorted_by_cached_key(|v| {\n                let normalized = normalize_version_for_sort(v);\n                (Versioning::new(normalized), v.to_string())\n            })\n            .collect();\n\n        if versions.is_empty() {\n            continue;\n        }\n\n        // Get metadata: prefer manifest, fall back to legacy .mise.backend\n        let (short, full, explicit_backend, opts) = if let Some(mt) = manifest.get(&dir_name) {\n            let mut full = mt.full.clone();\n            let mut opts = mt.opts.clone();\n            // Backward compat: if opts is empty but full contains [...], extract opts\n            if opts.is_empty()\n                && let Some(ref f) = full\n                && let Some((stripped_str, opts_str)) = crate::cli::args::split_bracketed_opts(f)\n            {\n                let stripped = stripped_str.to_string();\n                let parsed = parse_tool_options(opts_str);\n                for (k, v) in &parsed.opts {\n                    if EPHEMERAL_OPT_KEYS.contains(&k.as_str()) {\n                        continue;\n                    }\n                    opts.insert(k.clone(), v.clone());\n                }\n                full = Some(stripped);\n                // Schedule manifest rewrite to migrate to new format\n                let m = updated_manifest.get_or_insert_with(|| manifest.clone());\n                m.insert(\n                    dir_name.clone(),\n                    ManifestTool {\n                        short: mt.short.clone(),\n                        full: full.clone(),\n                        explicit_backend: mt.explicit_backend,\n                        opts: opts.clone(),\n                    },\n                );\n            }\n            (mt.short.clone(), full, mt.explicit_backend, opts)\n        } else if let Some((s, full, explicit)) = read_legacy_backend_meta(&dir_name) {\n            // Migration: absorb into manifest (clone on first migration)\n            let m = updated_manifest.get_or_insert_with(|| manifest.clone());\n            m.insert(\n                dir_name.clone(),\n                ManifestTool {\n                    short: s.clone(),\n                    full: full.clone(),\n                    explicit_backend: explicit,\n                    opts: BTreeMap::new(),\n                },\n            );\n            (s, full, explicit, BTreeMap::new())\n        } else {\n            (dir_name.clone(), None, true, BTreeMap::new())\n        };\n\n        let tool = InstallStateTool {\n            short: short.clone(),\n            full,\n            versions,\n            explicit_backend,\n            opts,\n            installs_path: Some(dir),\n        };\n        time!(\"init_tools {short}\");\n        tools.insert(short, tool);\n    }\n\n    // Write updated manifest if we migrated any legacy entries\n    if let Some(ref m) = updated_manifest {\n        let _lock = MANIFEST_LOCK.lock().expect(\"MANIFEST_LOCK lock failed\");\n        if let Err(err) = write_manifest(m) {\n            warn!(\"failed to write install manifest: {err:#}\");\n        }\n    }\n\n    // Scan shared install directories (read-only fallback directories)\n    for shared_dir in env::shared_install_dirs_early() {\n        if !shared_dir.is_dir() {\n            continue;\n        }\n        let shared_manifest_path = shared_dir.join(\".mise-installs.toml\");\n        let shared_manifest = read_manifest_from(&shared_manifest_path);\n        let shared_subdirs = match file::dir_subdirs(&shared_dir) {\n            std::result::Result::Ok(d) => d,\n            Err(err) => {\n                warn!(\n                    \"reading shared install dir {} failed: {err:?}\",\n                    display_path(&shared_dir)\n                );\n                continue;\n            }\n        };\n        for dir_name in shared_subdirs {\n            let dir = shared_dir.join(&dir_name);\n            let versions: Vec<String> = file::dir_subdirs(&dir)\n                .unwrap_or_else(|err| {\n                    warn!(\"reading versions in {} failed: {err:?}\", display_path(&dir));\n                    Default::default()\n                })\n                .into_iter()\n                .filter(|v| !v.starts_with('.'))\n                .filter(|v| !runtime_symlinks::is_runtime_symlink(&dir.join(v)))\n                .filter(|v| !dir.join(v).join(\"incomplete\").exists())\n                .sorted_by_cached_key(|v| {\n                    let normalized = normalize_version_for_sort(v);\n                    (Versioning::new(normalized), v.to_string())\n                })\n                .collect();\n\n            if versions.is_empty() {\n                continue;\n            }\n\n            let (short, full, explicit_backend, opts) =\n                if let Some(mt) = shared_manifest.get(&dir_name) {\n                    (\n                        mt.short.clone(),\n                        mt.full.clone(),\n                        mt.explicit_backend,\n                        mt.opts.clone(),\n                    )\n                } else {\n                    (dir_name.clone(), None, true, BTreeMap::new())\n                };\n\n            // Merge with existing tool entry or create new one\n            let tool = tools\n                .entry(short.clone())\n                .or_insert_with(|| InstallStateTool {\n                    short: short.clone(),\n                    full: full.clone(),\n                    versions: Vec::new(),\n                    explicit_backend,\n                    opts: opts.clone(),\n                    installs_path: Some(dir),\n                });\n            // Add versions from shared dir that aren't already present\n            for v in versions {\n                if !tool.versions.contains(&v) {\n                    tool.versions.push(v);\n                }\n            }\n            // Re-sort after merging\n            tool.versions.sort_by_cached_key(|v| {\n                let normalized = normalize_version_for_sort(v);\n                (Versioning::new(normalized), v.to_string())\n            });\n            // Fill in metadata if not yet set\n            if tool.full.is_none() {\n                tool.full = full;\n            }\n        }\n    }\n\n    for (short, pt) in init_plugins().await?.iter() {\n        let full = match pt {\n            PluginType::Asdf => format!(\"asdf:{short}\"),\n            PluginType::Vfox => format!(\"vfox:{short}\"),\n            PluginType::VfoxBackend => short.clone(),\n        };\n        let tool = tools\n            .entry(short.clone())\n            .or_insert_with(|| InstallStateTool {\n                short: short.clone(),\n                full: Some(full.clone()),\n                versions: Default::default(),\n                explicit_backend: true,\n                opts: BTreeMap::new(),\n                installs_path: None,\n            });\n        tool.full = Some(full);\n    }\n    let tools = Arc::new(tools);\n    *INSTALL_STATE_TOOLS\n        .lock()\n        .expect(\"INSTALL_STATE_TOOLS lock failed\") = Some(tools.clone());\n    Ok(tools)\n}\n\npub fn list_plugins() -> Arc<BTreeMap<String, PluginType>> {\n    INSTALL_STATE_PLUGINS\n        .lock()\n        .expect(\"INSTALL_STATE_PLUGINS lock failed\")\n        .as_ref()\n        .expect(\"INSTALL_STATE_PLUGINS is None\")\n        .clone()\n}\n\nfn is_banned_plugin(path: &Path) -> bool {\n    if path.ends_with(\"gradle\") {\n        let repo = Git::new(path);\n        if let Some(url) = repo.get_remote_url() {\n            return url == \"https://github.com/rfrancis/asdf-gradle.git\";\n        }\n    }\n    false\n}\n\nfn has_backend_methods(plugin_path: &Path) -> bool {\n    // to be a backend plugin, it must have a backend_install.lua file so we don't need to check for other files\n    plugin_path\n        .join(\"hooks\")\n        .join(\"backend_install.lua\")\n        .exists()\n}\n\npub fn get_tool_full(short: &str) -> Option<String> {\n    list_tools().get(short).and_then(|t| t.full.clone())\n}\n\npub fn get_plugin_type(short: &str) -> Option<PluginType> {\n    list_plugins().get(short).cloned()\n}\n\npub fn list_tools() -> Arc<BTreeMap<String, InstallStateTool>> {\n    INSTALL_STATE_TOOLS\n        .lock()\n        .expect(\"INSTALL_STATE_TOOLS lock failed\")\n        .as_ref()\n        .expect(\"INSTALL_STATE_TOOLS is None\")\n        .clone()\n}\n\npub fn backend_type(short: &str) -> Result<Option<BackendType>> {\n    let backend_type = list_tools()\n        .get(short)\n        .and_then(|ist| ist.full.as_ref())\n        .map(|full| BackendType::guess(full));\n    if let Some(BackendType::Unknown) = backend_type\n        && let Some((plugin_name, _)) = short.split_once(':')\n        && let Some(PluginType::VfoxBackend) = get_plugin_type(plugin_name)\n    {\n        return Ok(Some(BackendType::VfoxBackend(plugin_name.to_string())));\n    }\n    Ok(backend_type)\n}\n\npub fn list_versions(short: &str) -> Vec<String> {\n    list_tools()\n        .get(short)\n        .map(|tool| tool.versions.clone())\n        .unwrap_or_default()\n}\n\npub async fn add_plugin(short: &str, plugin_type: PluginType) -> Result<()> {\n    let mut plugins = init_plugins().await?.deref().clone();\n    plugins.insert(short.to_string(), plugin_type);\n    *INSTALL_STATE_PLUGINS\n        .lock()\n        .expect(\"INSTALL_STATE_PLUGINS lock failed\") = Some(Arc::new(plugins));\n    Ok(())\n}\n\n/// Writes backend metadata to the consolidated manifest file.\n/// Uses the primary installs dir manifest by default.\npub fn write_backend_meta(ba: &BackendArg) -> Result<()> {\n    write_backend_meta_to(ba, &manifest_path())\n}\n\n/// Writes backend metadata to a manifest at a specific install path.\npub fn write_backend_meta_to(ba: &BackendArg, path: &Path) -> Result<()> {\n    let full = ba.full_without_opts();\n    let explicit = ba.has_explicit_backend();\n\n    // Store opts as native TOML values, filtering out ephemeral keys.\n    let mut opts_map: BTreeMap<String, toml::Value> = BTreeMap::new();\n    if let Some(o) = ba.opts.as_ref() {\n        for (k, v) in &o.opts {\n            if !EPHEMERAL_OPT_KEYS.contains(&k.as_str()) {\n                opts_map.insert(k.clone(), v.clone());\n            }\n        }\n    }\n\n    let _lock = MANIFEST_LOCK.lock().expect(\"MANIFEST_LOCK lock failed\");\n    let mut manifest = read_manifest_from(path);\n    manifest.insert(\n        ba.short.to_kebab_case(),\n        ManifestTool {\n            short: ba.short.clone(),\n            full: Some(full),\n            explicit_backend: explicit,\n            opts: opts_map,\n        },\n    );\n    write_manifest_to(path, &manifest)?;\n    Ok(())\n}\n\npub fn incomplete_file_path(short: &str, v: &str) -> PathBuf {\n    dirs::CACHE\n        .join(short.to_kebab_case())\n        .join(v)\n        .join(\"incomplete\")\n}\n\n/// Path to the checksum file for a specific tool version\n/// Used to track changes in rolling releases (like \"nightly\")\nfn checksum_file_path(short: &str, v: &str) -> PathBuf {\n    dirs::INSTALLS\n        .join(short.to_kebab_case())\n        .join(v)\n        .join(\".mise.checksum\")\n}\n\n/// Store the checksum for a tool version (used for rolling release tracking)\npub fn write_checksum(short: &str, v: &str, checksum: &str) -> Result<()> {\n    let path = checksum_file_path(short, v);\n    file::write(&path, checksum)?;\n    Ok(())\n}\n\n/// Read the stored checksum for a tool version\npub fn read_checksum(short: &str, v: &str) -> Option<String> {\n    let path = checksum_file_path(short, v);\n    if path.exists() {\n        file::read_to_string(&path).ok()\n    } else {\n        None\n    }\n}\n\npub fn reset() {\n    *INSTALL_STATE_PLUGINS\n        .lock()\n        .expect(\"INSTALL_STATE_PLUGINS lock failed\") = None;\n    *INSTALL_STATE_TOOLS\n        .lock()\n        .expect(\"INSTALL_STATE_TOOLS lock failed\") = None;\n    super::tool_version::reset_install_path_cache();\n}\n\n#[cfg(test)]\nmod tests {\n    use super::normalize_version_for_sort;\n    use itertools::Itertools;\n    use std::collections::BTreeMap;\n    use versions::Versioning;\n\n    #[test]\n    fn test_normalize_version_for_sort() {\n        assert_eq!(normalize_version_for_sort(\"v1.0.0\"), \"1.0.0\");\n        assert_eq!(normalize_version_for_sort(\"V1.0.0\"), \"1.0.0\");\n        assert_eq!(normalize_version_for_sort(\"1.0.0\"), \"1.0.0\");\n        assert_eq!(normalize_version_for_sort(\"latest\"), \"latest\");\n    }\n\n    #[test]\n    fn test_version_sorting_with_v_prefix() {\n        // Test that mixed v-prefix and non-v-prefix versions sort correctly\n        let versions = [\"v2.0.51\", \"2.0.35\", \"2.0.52\"];\n\n        // Without normalization - demonstrates the problem\n        let sorted_without_norm: Vec<_> = versions\n            .iter()\n            .sorted_by_cached_key(|v| (Versioning::new(v), v.to_string()))\n            .collect();\n        println!(\"Without normalization: {:?}\", sorted_without_norm);\n\n        // With normalization - the fix\n        let sorted_with_norm: Vec<_> = versions\n            .iter()\n            .sorted_by_cached_key(|v| {\n                let normalized = normalize_version_for_sort(v);\n                (Versioning::new(normalized), v.to_string())\n            })\n            .collect();\n        println!(\"With normalization: {:?}\", sorted_with_norm);\n\n        // With the fix, v2.0.51 should sort between 2.0.35 and 2.0.52\n        // The highest version should be 2.0.52\n        assert_eq!(**sorted_with_norm.last().unwrap(), \"2.0.52\");\n\n        // v2.0.51 should be second to last\n        assert_eq!(**sorted_with_norm.get(1).unwrap(), \"v2.0.51\");\n\n        // 2.0.35 should be first\n        assert_eq!(**sorted_with_norm.first().unwrap(), \"2.0.35\");\n    }\n\n    #[test]\n    fn test_manifest_roundtrip() {\n        use super::{Manifest, ManifestTool};\n\n        let mut manifest = Manifest::new();\n        manifest.insert(\n            \"node\".to_string(),\n            ManifestTool {\n                short: \"node\".to_string(),\n                full: Some(\"core:node\".to_string()),\n                explicit_backend: true,\n                opts: BTreeMap::new(),\n            },\n        );\n        manifest.insert(\n            \"bun\".to_string(),\n            ManifestTool {\n                short: \"bun\".to_string(),\n                full: Some(\"aqua:oven-sh/bun\".to_string()),\n                explicit_backend: false,\n                opts: BTreeMap::new(),\n            },\n        );\n        manifest.insert(\n            \"tiny\".to_string(),\n            ManifestTool {\n                short: \"tiny\".to_string(),\n                full: None,\n                explicit_backend: true,\n                opts: BTreeMap::new(),\n            },\n        );\n\n        let serialized = toml::to_string_pretty(&manifest).unwrap();\n        let deserialized: Manifest = toml::from_str(&serialized).unwrap();\n\n        assert_eq!(deserialized.len(), 3);\n        assert_eq!(deserialized[\"node\"].full.as_deref(), Some(\"core:node\"));\n        assert!(deserialized[\"node\"].explicit_backend);\n        assert_eq!(\n            deserialized[\"bun\"].full.as_deref(),\n            Some(\"aqua:oven-sh/bun\")\n        );\n        assert!(!deserialized[\"bun\"].explicit_backend);\n        assert!(deserialized[\"tiny\"].full.is_none());\n        assert!(deserialized[\"tiny\"].explicit_backend);\n    }\n\n    #[test]\n    fn test_manifest_with_opts_roundtrip() {\n        use super::{Manifest, ManifestTool};\n\n        let mut opts = BTreeMap::new();\n        opts.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/tool.tar.gz\".to_string()),\n        );\n        opts.insert(\n            \"bin_path\".to_string(),\n            toml::Value::String(\"bin\".to_string()),\n        );\n\n        // Nested table for platforms\n        let mut platforms = toml::map::Map::new();\n        let mut linux = toml::map::Map::new();\n        linux.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/linux.tar.gz\".to_string()),\n        );\n        platforms.insert(\"linux-x64\".to_string(), toml::Value::Table(linux));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n\n        let mut manifest = Manifest::new();\n        manifest.insert(\n            \"hello\".to_string(),\n            ManifestTool {\n                short: \"hello\".to_string(),\n                full: Some(\"http:hello\".to_string()),\n                explicit_backend: true,\n                opts,\n            },\n        );\n\n        let serialized = toml::to_string_pretty(&manifest).unwrap();\n        let deserialized: Manifest = toml::from_str(&serialized).unwrap();\n\n        assert_eq!(deserialized[\"hello\"].full.as_deref(), Some(\"http:hello\"));\n        assert_eq!(\n            deserialized[\"hello\"].opts.get(\"url\"),\n            Some(&toml::Value::String(\n                \"https://example.com/tool.tar.gz\".to_string()\n            ))\n        );\n        assert_eq!(\n            deserialized[\"hello\"].opts.get(\"bin_path\"),\n            Some(&toml::Value::String(\"bin\".to_string()))\n        );\n        // Verify nested platforms table survived round-trip\n        let platforms = deserialized[\"hello\"].opts.get(\"platforms\").unwrap();\n        assert!(platforms.is_table());\n        let linux = platforms.get(\"linux-x64\").unwrap();\n        assert_eq!(\n            linux.get(\"url\").unwrap().as_str(),\n            Some(\"https://example.com/linux.tar.gz\")\n        );\n    }\n\n    #[test]\n    fn test_manifest_backward_compat_bracketed_full() {\n        use super::Manifest;\n\n        // Old format: full contains bracketed opts\n        let toml_str = r#\"\n[hello]\nshort = \"hello\"\nfull = \"http:hello[url = \\\"https://example.com/tool.tar.gz\\\", bin_path = \\\"bin\\\"]\"\nexplicit_backend = true\n\"#;\n        let manifest: Manifest = toml::from_str(toml_str).unwrap();\n        let mt = &manifest[\"hello\"];\n        // Old format should deserialize with opts empty and brackets in full\n        assert!(mt.opts.is_empty());\n        assert!(mt.full.as_ref().unwrap().contains('['));\n    }\n}\n"
  },
  {
    "path": "src/toolset/mod.rs",
    "content": "use crate::backend::Backend;\nuse crate::cli::args::BackendArg;\nuse crate::config::Config;\nuse crate::config::settings::{Settings, SettingsStatusMissingTools};\nuse crate::env::TERM_WIDTH;\nuse crate::registry::REGISTRY;\nuse crate::registry::tool_enabled;\nuse crate::{backend, parallel};\npub use builder::{ConfigScope, ToolsetBuilder};\nuse console::truncate_str;\nuse eyre::{Result, bail};\nuse helpers::TVTuple;\nuse indexmap::IndexMap;\nuse itertools::Itertools;\nuse outdated_info::OutdatedInfo;\npub use outdated_info::is_outdated_version;\nuse petgraph::Direction;\nuse petgraph::graphmap::DiGraphMap;\nuse serde::Serialize;\nuse std::collections::HashSet;\nuse std::fmt::{Display, Formatter};\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse std::{\n    cmp::Reverse,\n    collections::{BinaryHeap, HashMap},\n};\nuse tokio::sync::OnceCell;\n\npub use install_options::InstallOptions;\npub use tool_request::ToolRequest;\npub use tool_request_set::{ToolRequestSet, ToolRequestSetBuilder};\npub use tool_source::ToolSource;\npub use tool_version::{ResolveOptions, ToolVersion};\npub use tool_version_list::ToolVersionList;\npub use tool_version_options::{EPHEMERAL_OPT_KEYS, ToolVersionOptions, parse_tool_options};\n\nmod builder;\npub mod env_cache;\nmod helpers;\nmod install_options;\npub(crate) mod install_state;\npub(crate) mod outdated_info;\nmod tool_deps;\npub(crate) mod tool_request;\nmod tool_request_set;\nmod tool_source;\nmod tool_version;\nmod tool_version_list;\nmod tool_version_options;\nmod toolset_env;\nmod toolset_install;\nmod toolset_paths;\n\n#[derive(Debug, Clone, Serialize)]\npub struct ToolInfo {\n    pub version: String,\n    pub path: String,\n}\n\n#[derive(Debug, Clone, Serialize)]\n#[serde(untagged)]\npub enum ToolInfos {\n    Single(ToolInfo),\n    Multiple(Vec<ToolInfo>),\n}\n\n/// a toolset is a collection of tools for various plugins\n///\n/// one example is a .tool-versions file\n/// the idea is that we start with an empty toolset, then\n/// merge in other toolsets from various sources\n#[derive(Debug, Default, Clone)]\npub struct Toolset {\n    pub versions: IndexMap<Arc<BackendArg>, ToolVersionList>,\n    pub source: Option<ToolSource>,\n    tera_ctx: OnceCell<tera::Context>,\n}\n\nimpl Toolset {\n    pub fn new(source: ToolSource) -> Self {\n        Self {\n            source: Some(source),\n            ..Default::default()\n        }\n    }\n\n    pub fn add_version(&mut self, tvr: ToolRequest) {\n        let ba = tvr.ba();\n        if self.is_disabled(ba) {\n            return;\n        }\n        let tvl = self\n            .versions\n            .entry(tvr.ba().clone())\n            .or_insert_with(|| ToolVersionList::new(ba.clone(), self.source.clone().unwrap()));\n        tvl.requests.push(tvr);\n    }\n\n    pub fn merge(&mut self, other: Toolset) {\n        let mut versions = other.versions;\n        for (plugin, tvl) in self.versions.clone() {\n            if !versions.contains_key(&plugin) {\n                versions.insert(plugin, tvl);\n            }\n        }\n        versions.retain(|_, tvl| !self.is_disabled(&tvl.backend));\n        self.versions = versions;\n        self.source = other.source;\n    }\n\n    #[async_backtrace::framed]\n    pub async fn resolve(&mut self, config: &Arc<Config>) -> eyre::Result<()> {\n        self.resolve_with_opts(config, &Default::default()).await\n    }\n\n    #[async_backtrace::framed]\n    pub async fn resolve_with_opts(\n        &mut self,\n        config: &Arc<Config>,\n        opts: &ResolveOptions,\n    ) -> eyre::Result<()> {\n        self.list_missing_plugins();\n        let versions = self\n            .versions\n            .clone()\n            .into_iter()\n            .map(|(ba, tvl)| (config.clone(), ba, tvl.clone(), opts.clone()))\n            .collect::<Vec<_>>();\n        let tvls = parallel::parallel(versions, |(config, ba, mut tvl, opts)| async move {\n            if let Err(err) = tvl.resolve(&config, &opts).await {\n                warn!(\"Failed to resolve tool version list for {ba}: {err}\");\n            }\n            Ok((ba, tvl))\n        })\n        .await?;\n        self.versions = tvls.into_iter().collect();\n        Ok(())\n    }\n\n    pub fn list_missing_plugins(&self) -> Vec<String> {\n        self.versions\n            .iter()\n            .filter(|(_, tvl)| {\n                tvl.versions\n                    .first()\n                    .map(|tv| tv.request.is_os_supported())\n                    .unwrap_or_default()\n            })\n            .map(|(ba, _)| ba)\n            .flat_map(|ba| ba.backend())\n            .filter(|b| b.plugin().is_some_and(|p| !p.is_installed()))\n            .map(|p| p.id().into())\n            .collect()\n    }\n\n    pub async fn list_missing_versions(&self, config: &Arc<Config>) -> Vec<ToolVersion> {\n        trace!(\"list_missing_versions\");\n        measure!(\"toolset::list_missing_versions\", {\n            self.list_current_versions()\n                .into_iter()\n                .filter(|(p, tv)| !p.is_version_installed(config, tv, true))\n                .map(|(_, tv)| tv)\n                .collect()\n        })\n    }\n\n    pub async fn list_installed_versions(&self, config: &Arc<Config>) -> Result<Vec<TVTuple>> {\n        let current_versions: HashMap<(String, String), TVTuple> = self\n            .list_current_versions()\n            .into_iter()\n            .map(|(p, tv)| ((p.id().into(), tv.version.clone()), (p.clone(), tv)))\n            .collect();\n        let current_versions = Arc::new(current_versions);\n        let mut versions = vec![];\n        for b in backend::list().into_iter() {\n            for v in b.list_installed_versions() {\n                if let Some((p, tv)) = current_versions.get(&(b.id().into(), v.clone())) {\n                    versions.push((p.clone(), tv.clone()));\n                } else {\n                    let tv = ToolRequest::new(b.ba().clone(), &v, ToolSource::Unknown)?\n                        .resolve(config, &Default::default())\n                        .await?;\n                    versions.push((b.clone(), tv));\n                }\n            }\n        }\n        Ok(versions)\n    }\n\n    pub fn list_current_requests(&self) -> Vec<&ToolRequest> {\n        self.versions\n            .values()\n            .flat_map(|tvl| &tvl.requests)\n            .collect()\n    }\n\n    pub fn list_versions_by_plugin(&self) -> Vec<(Arc<dyn Backend>, &Vec<ToolVersion>)> {\n        self.versions\n            .iter()\n            .flat_map(|(ba, v)| eyre::Ok((ba.backend()?, &v.versions)))\n            .collect()\n    }\n\n    pub fn list_current_versions(&self) -> Vec<(Arc<dyn Backend>, ToolVersion)> {\n        trace!(\"list_current_versions\");\n        self.list_versions_by_plugin()\n            .iter()\n            .flat_map(|(p, v)| {\n                v.iter().filter(|v| v.request.is_os_supported()).map(|v| {\n                    // map cargo backend specific prefixes to ref\n                    let tv = match v.version.split_once(':') {\n                        Some((ref_type @ (\"tag\" | \"branch\" | \"rev\"), r)) => {\n                            let request = ToolRequest::Ref {\n                                backend: p.ba().clone(),\n                                ref_: r.to_string(),\n                                ref_type: ref_type.to_string(),\n                                options: v.request.options().clone(),\n                                source: v.request.source().clone(),\n                            };\n                            let version = format!(\"ref:{r}\");\n                            ToolVersion::new(request, version)\n                        }\n                        _ => v.clone(),\n                    };\n                    (p.clone(), tv)\n                })\n            })\n            .collect()\n    }\n\n    pub async fn list_all_versions(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Vec<(Arc<dyn Backend>, ToolVersion)>> {\n        use itertools::Itertools;\n        let versions = self\n            .list_current_versions()\n            .into_iter()\n            .chain(self.list_installed_versions(config).await?)\n            .unique_by(|(ba, tv)| (ba.clone(), tv.tv_pathname().to_string()))\n            .collect();\n        Ok(versions)\n    }\n\n    pub fn list_current_installed_versions(\n        &self,\n        config: &Arc<Config>,\n    ) -> Vec<(Arc<dyn Backend>, ToolVersion)> {\n        self.list_current_versions()\n            .into_iter()\n            .filter(|(p, tv)| p.is_version_installed(config, tv, true))\n            .collect()\n    }\n\n    pub async fn list_outdated_versions(\n        &self,\n        config: &Arc<Config>,\n        bump: bool,\n        opts: &ResolveOptions,\n    ) -> Vec<OutdatedInfo> {\n        self.list_outdated_versions_filtered(config, bump, opts, None, None)\n            .await\n    }\n\n    pub async fn list_outdated_versions_filtered(\n        &self,\n        config: &Arc<Config>,\n        bump: bool,\n        opts: &ResolveOptions,\n        filter_tools: Option<&[crate::cli::args::ToolArg]>,\n        exclude_tools: Option<&[crate::cli::args::ToolArg]>,\n    ) -> Vec<OutdatedInfo> {\n        let versions = self\n            .list_current_versions()\n            .into_iter()\n            // Filter to only check specified tools if provided\n            .filter(|(_, tv)| {\n                // Exclude tools if specified\n                if let Some(exclude) = exclude_tools\n                    && exclude.iter().any(|t| t.ba.as_ref() == tv.ba())\n                {\n                    return false;\n                }\n                // Include only specified tools if provided\n                if let Some(tools) = filter_tools {\n                    tools.iter().any(|t| t.ba.as_ref() == tv.ba())\n                } else {\n                    true\n                }\n            })\n            .map(|(t, tv)| (config.clone(), t, tv, bump, opts.clone()))\n            .collect::<Vec<_>>();\n        let outdated = parallel::parallel(versions, |(config, t, tv, bump, opts)| async move {\n            let mut outdated = HashSet::new();\n            match t.outdated_info(&config, &tv, bump, &opts).await {\n                Ok(Some(oi)) => {\n                    outdated.insert(oi);\n                }\n                Ok(None) => {}\n                Err(e) => {\n                    warn!(\"Error getting outdated info for {tv}: {e:#}\");\n                }\n            }\n            if t.symlink_path(&tv).is_some() {\n                trace!(\"skipping symlinked version {tv}\");\n                // do not consider symlinked versions to be outdated\n                return Ok(outdated);\n            }\n            match OutdatedInfo::resolve(&config, tv.clone(), bump, &opts).await {\n                Ok(Some(oi)) => {\n                    outdated.insert(oi);\n                }\n                Ok(None) => {}\n                Err(e) => {\n                    warn!(\"Error creating OutdatedInfo for {tv}: {e:#}\");\n                }\n            }\n            Ok(outdated)\n        })\n        .await\n        .unwrap_or_else(|e| {\n            warn!(\"Error in parallel outdated version check: {e:#}\");\n            vec![]\n        });\n        outdated.into_iter().flatten().collect()\n    }\n\n    pub fn build_tools_tera_map(&self, config: &Arc<Config>) -> HashMap<String, ToolInfos> {\n        let mut tools_map: HashMap<String, Vec<ToolInfo>> = HashMap::new();\n        for (_, tv) in self.list_current_installed_versions(config) {\n            let tool_name = tv.ba().tool_name.clone();\n            let short = tv.ba().short.clone();\n            let info = ToolInfo {\n                version: tv.version.clone(),\n                path: tv.install_path().to_string_lossy().to_string(),\n            };\n            tools_map\n                .entry(tool_name.clone())\n                .or_default()\n                .push(info.clone());\n            if short != tool_name {\n                tools_map.entry(short).or_default().push(info);\n            }\n        }\n        tools_map\n            .into_iter()\n            .map(|(k, v)| {\n                let infos = if v.len() == 1 {\n                    ToolInfos::Single(v.into_iter().next().unwrap())\n                } else {\n                    ToolInfos::Multiple(v)\n                };\n                (k, infos)\n            })\n            .collect()\n    }\n\n    pub async fn tera_ctx(&self, config: &Arc<Config>) -> Result<&tera::Context> {\n        self.tera_ctx\n            .get_or_try_init(async || {\n                let env = self.full_env(config).await?;\n                let mut ctx = config.tera_ctx.clone();\n                ctx.insert(\"env\", &env);\n                ctx.insert(\"tools\", &self.build_tools_tera_map(config));\n                Ok(ctx)\n            })\n            .await\n    }\n\n    /// Sort installed tools so that tools with `overrides` in the registry\n    /// appear before the tools they override. e.g., npm overrides node so that\n    /// the explicitly-installed npm binary is found before node's bundled npm.\n    pub(crate) fn sort_by_overrides(\n        installed: &mut Vec<(Arc<dyn Backend>, ToolVersion)>,\n    ) -> Result<()> {\n        let mut graph = DiGraphMap::<&str, ()>::new();\n\n        // Collect unique IDs to build the graph (deduplicates multi-version tools)\n        let unique_ids: HashSet<String> =\n            installed.iter().map(|(b, _)| b.id().to_string()).collect();\n        let unique_ids: Vec<String> = unique_ids.into_iter().collect();\n\n        let mut original_index: HashMap<&str, usize> = HashMap::new();\n        for (i, (b, _)) in installed.iter().enumerate() {\n            let id = b.id();\n            original_index.entry(id).or_insert(i);\n        }\n\n        for id in &unique_ids {\n            graph.add_node(id.as_str());\n        }\n\n        for id in &unique_ids {\n            let id_str = id.as_str();\n            if let Some(tool) = REGISTRY.get(id_str) {\n                for overridden in tool.overrides {\n                    // Edge: id -> overridden (overrider -> overridden)\n                    // Only add edge if overridden tool is also in the list\n                    if graph.contains_node(overridden) {\n                        graph.add_edge(id_str, overridden, ());\n                    }\n                }\n            }\n        }\n\n        if graph.edge_count() == 0 {\n            return Ok(());\n        }\n\n        // Priority = min(priority, priority_of_dependencies)\n        let mut priorities: HashMap<&str, usize> = original_index.clone();\n        let mut changed = true;\n        while changed {\n            changed = false;\n            for (overrider, overridden, _) in graph.all_edges() {\n                let p_overridden = *priorities.get(overridden).unwrap_or(&usize::MAX);\n                let p_overrider = *priorities.get(overrider).unwrap_or(&usize::MAX);\n                if p_overridden < p_overrider {\n                    priorities.insert(overrider, p_overridden);\n                    changed = true;\n                }\n            }\n        }\n\n        // Topological Sort with Priority Queue\n        let mut in_degree: HashMap<&str, usize> = graph\n            .nodes()\n            .map(|node| {\n                (\n                    node,\n                    graph.neighbors_directed(node, Direction::Incoming).count(),\n                )\n            })\n            .collect();\n\n        let mut pq = BinaryHeap::new();\n        for (&node, &deg) in &in_degree {\n            if deg == 0 {\n                let p = priorities[node];\n                let idx = original_index[node];\n                pq.push(Reverse((p, idx, node)));\n            }\n        }\n\n        let mut sorted_ids: Vec<&str> = Vec::with_capacity(graph.node_count());\n        while let Some(Reverse((_, _, id))) = pq.pop() {\n            sorted_ids.push(id);\n\n            for neighbor in graph.neighbors(id) {\n                if let Some(deg) = in_degree.get_mut(neighbor) {\n                    *deg -= 1;\n                    if *deg == 0 {\n                        let p = priorities[neighbor];\n                        let idx = original_index[neighbor];\n                        pq.push(Reverse((p, idx, neighbor)));\n                    }\n                }\n            }\n        }\n\n        if sorted_ids.len() != graph.node_count() {\n            bail!(\"Cycle detected in tool overrides\");\n        }\n\n        let order: HashMap<&str, usize> = sorted_ids\n            .iter()\n            .enumerate()\n            .map(|(i, &id)| (id, i))\n            .collect();\n        installed.sort_by_cached_key(|(b, _)| order.get(b.id()).copied().unwrap_or(usize::MAX));\n\n        Ok(())\n    }\n\n    pub async fn which(\n        &self,\n        config: &Arc<Config>,\n        bin_name: &str,\n    ) -> Option<(Arc<dyn Backend>, ToolVersion)> {\n        let mut installed = self.list_current_installed_versions(config);\n        Self::sort_by_overrides(&mut installed).unwrap();\n        for (p, tv) in installed {\n            match Box::pin(p.which(config, &tv, bin_name)).await {\n                Ok(Some(_bin)) => return Some((p, tv)),\n                Ok(None) => {}\n                Err(e) => {\n                    debug!(\"Error running which: {:#}\", e);\n                }\n            }\n        }\n        None\n    }\n\n    pub async fn which_bin(&self, config: &Arc<Config>, bin_name: &str) -> Option<PathBuf> {\n        let mut installed = self.list_current_installed_versions(config);\n        Self::sort_by_overrides(&mut installed).unwrap();\n        for (p, tv) in installed {\n            if let Ok(Some(bin)) = Box::pin(p.which(config, &tv, bin_name)).await {\n                return Some(bin);\n            }\n        }\n        None\n    }\n\n    pub async fn list_rtvs_with_bin(\n        &self,\n        config: &Arc<Config>,\n        bin_name: &str,\n    ) -> Result<Vec<ToolVersion>> {\n        let mut rtvs = vec![];\n        for (p, tv) in self.list_installed_versions(config).await? {\n            match p.which(config, &tv, bin_name).await {\n                Ok(Some(_bin)) => rtvs.push(tv),\n                Ok(None) => {}\n                Err(e) => {\n                    warn!(\"Error running which: {:#}\", e);\n                }\n            }\n        }\n        Ok(rtvs)\n    }\n\n    pub async fn notify_if_versions_missing(&self, config: &Arc<Config>) {\n        let missing_versions = self.list_missing_versions(config).await;\n        self.notify_missing_versions(missing_versions);\n    }\n\n    pub fn notify_missing_versions(&self, missing_versions: Vec<ToolVersion>) {\n        if Settings::get().status.missing_tools() == SettingsStatusMissingTools::Never {\n            return;\n        }\n        let mut missing = vec![];\n        for tv in missing_versions.into_iter() {\n            if Settings::get().status.missing_tools() == SettingsStatusMissingTools::Always {\n                missing.push(tv);\n                continue;\n            }\n            if let Ok(backend) = tv.backend() {\n                let installed = backend.list_installed_versions();\n                if !installed.is_empty() {\n                    missing.push(tv);\n                }\n            }\n        }\n        if missing.is_empty() || *crate::env::__MISE_SHIM {\n            return;\n        }\n        let versions = missing\n            .iter()\n            .map(|tv| tv.style())\n            .collect::<Vec<_>>()\n            .join(\" \");\n        warn!(\n            \"missing: {}\",\n            truncate_str(&versions, *TERM_WIDTH - 14, \"…\"),\n        );\n    }\n\n    fn is_disabled(&self, ba: &BackendArg) -> bool {\n        !ba.is_os_supported()\n            || !tool_enabled(\n                &Settings::get().enable_tools(),\n                &Settings::get().disable_tools(),\n                &ba.short.to_string(),\n            )\n    }\n}\n\nimpl Display for Toolset {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        let plugins = &self\n            .versions\n            .iter()\n            .map(|(_, v)| v.requests.iter().map(|tvr| tvr.to_string()).join(\" \"))\n            .collect_vec();\n        write!(f, \"{}\", plugins.join(\", \"))\n    }\n}\n\nimpl From<ToolRequestSet> for Toolset {\n    fn from(trs: ToolRequestSet) -> Self {\n        let mut ts = Toolset::default();\n        for (ba, versions, source) in trs.into_iter() {\n            ts.source = Some(source.clone());\n            let mut tvl = ToolVersionList::new(ba.clone(), source);\n            for tr in versions {\n                tvl.requests.push(tr);\n            }\n            ts.versions.insert(ba, tvl);\n        }\n        ts\n    }\n}\n\n/// Get all tool versions that are needed by tracked config files.\n/// Returns a set of (short_name, tv_pathname) pairs.\n/// This is used by both `mise prune` and `mise upgrade` to avoid\n/// uninstalling versions that other projects still need.\npub async fn get_versions_needed_by_tracked_configs(\n    config: &Arc<Config>,\n) -> Result<std::collections::HashSet<(String, String)>> {\n    let mut needed = std::collections::HashSet::new();\n    // Use use_locked_version: false to resolve based on what config files actually\n    // request, not what was previously locked. This is important during upgrade\n    // because the lockfile hasn't been updated yet when this is called.\n    let opts = ResolveOptions {\n        use_locked_version: false,\n        ..Default::default()\n    };\n    for cf in config.get_tracked_config_files().await?.values() {\n        let mut ts = Toolset::from(cf.to_tool_request_set()?);\n        ts.resolve_with_opts(config, &opts).await?;\n        for (_, tv) in ts.list_current_versions() {\n            needed.insert((tv.ba().short.to_string(), tv.tv_pathname()));\n        }\n    }\n    Ok(needed)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::backend::arg_to_backend;\n    use crate::cli::args::BackendArg;\n    use crate::toolset::{ToolRequest, ToolSource, ToolVersion};\n\n    #[tokio::test]\n    async fn test_sort_by_overrides() {\n        crate::toolset::install_state::init().await.unwrap();\n        let node = arg_to_backend(BackendArg::from(\"node\")).unwrap();\n        let npm = arg_to_backend(BackendArg::from(\"npm\")).unwrap();\n        let jc = arg_to_backend(BackendArg::from(\"jc\")).unwrap();\n        let jq = arg_to_backend(BackendArg::from(\"jq\")).unwrap();\n\n        let mk_tv = |backend: Arc<dyn Backend>, version: &str| {\n            let ba = backend.ba().clone();\n            let req = ToolRequest::System {\n                backend: ba,\n                source: ToolSource::Argument,\n                options: Default::default(),\n            };\n            ToolVersion::new(req, version.into())\n        };\n\n        let tv_node = mk_tv(node.clone(), \"20.0.0\");\n        let tv_npm = mk_tv(npm.clone(), \"10.2.5\");\n        let tv_jc = mk_tv(jc.clone(), \"1.0.0\");\n        let tv_jq = mk_tv(jq.clone(), \"1.0.0\");\n\n        let mut input = vec![\n            (node.clone(), tv_node.clone()),\n            (jc.clone(), tv_jc.clone()),\n            (jq.clone(), tv_jq.clone()),\n            (npm.clone(), tv_npm.clone()),\n        ];\n        Toolset::sort_by_overrides(&mut input).unwrap();\n        let ids: Vec<&str> = input.iter().map(|(b, _)| b.id()).collect();\n        assert_eq!(ids, vec![\"npm\", \"node\", \"jc\", \"jq\"]);\n\n        let mut input = vec![\n            (node.clone(), tv_node.clone()),\n            (jq.clone(), tv_jq.clone()),\n            (npm.clone(), tv_npm.clone()),\n            (jc.clone(), tv_jc.clone()),\n        ];\n        Toolset::sort_by_overrides(&mut input).unwrap();\n        let ids: Vec<&str> = input.iter().map(|(b, _)| b.id()).collect();\n        assert_eq!(ids, vec![\"npm\", \"node\", \"jq\", \"jc\"]);\n\n        let mut input = vec![\n            (jc.clone(), tv_jc.clone()),\n            (npm.clone(), tv_npm.clone()),\n            (jq.clone(), tv_jq.clone()),\n            (node.clone(), tv_node.clone()),\n        ];\n        Toolset::sort_by_overrides(&mut input).unwrap();\n        let ids: Vec<&str> = input.iter().map(|(b, _)| b.id()).collect();\n        assert_eq!(ids, vec![\"jc\", \"npm\", \"jq\", \"node\"]);\n\n        // Test with multiple versions of the same tool\n        let tv_node_18 = mk_tv(node.clone(), \"18.0.0\");\n        let tv_node_20 = mk_tv(node.clone(), \"20.0.0\");\n        let tv_npm_9 = mk_tv(npm.clone(), \"9.0.0\");\n\n        let mut input = vec![\n            (node.clone(), tv_node_20.clone()),\n            (node.clone(), tv_node_18.clone()),\n            (jc.clone(), tv_jc.clone()),\n            (npm.clone(), tv_npm_9.clone()),\n            (npm.clone(), tv_npm.clone()),\n        ];\n        Toolset::sort_by_overrides(&mut input).unwrap();\n\n        // npm should come before node (due to override)\n        // Multiple versions of same tool should maintain original order\n        let result: Vec<(&str, &str)> = input\n            .iter()\n            .map(|(b, tv)| (b.id(), tv.version.as_str()))\n            .collect();\n        assert_eq!(\n            result,\n            vec![\n                (\"npm\", \"9.0.0\"),\n                (\"npm\", \"10.2.5\"),\n                (\"node\", \"20.0.0\"),\n                (\"node\", \"18.0.0\"),\n                (\"jc\", \"1.0.0\"),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "src/toolset/outdated_info.rs",
    "content": "use crate::semver::{chunkify_version, split_version_prefix};\nuse crate::toolset;\nuse crate::toolset::{ResolveOptions, ToolRequest, ToolSource, ToolVersion};\nuse crate::{Result, config::Config};\nuse serde_derive::Serialize;\nuse std::{\n    fmt::{Display, Formatter},\n    sync::Arc,\n};\nuse tabled::Tabled;\nuse versions::Version;\n\n#[derive(Debug, Serialize, Clone, Tabled, PartialEq, Eq, Hash)]\npub struct OutdatedInfo {\n    pub name: String,\n    #[serde(skip)]\n    #[tabled(skip)]\n    pub tool_request: ToolRequest,\n    #[serde(skip)]\n    #[tabled(skip)]\n    pub tool_version: ToolVersion,\n    pub requested: String,\n    #[tabled(display(\"Self::display_current\"))]\n    pub current: Option<String>,\n    #[tabled(display(\"Self::display_bump\"))]\n    pub bump: Option<String>,\n    pub latest: String,\n    pub source: ToolSource,\n}\n\nimpl OutdatedInfo {\n    pub fn new(config: &Arc<Config>, tv: ToolVersion, latest: String) -> Result<Self> {\n        let t = tv.backend()?;\n        let current = if t.is_version_installed(config, &tv, true) {\n            Some(tv.version.clone())\n        } else {\n            None\n        };\n        let oi = Self {\n            source: tv.request.source().clone(),\n            name: tv.ba().short.to_string(),\n            current,\n            requested: tv.request.version(),\n            tool_request: tv.request.clone(),\n            tool_version: tv,\n            bump: None,\n            latest,\n        };\n        Ok(oi)\n    }\n\n    pub async fn resolve(\n        config: &Arc<Config>,\n        tv: ToolVersion,\n        bump: bool,\n        opts: &ResolveOptions,\n    ) -> eyre::Result<Option<Self>> {\n        let t = tv.backend()?;\n        // prefix is something like \"temurin-\" or \"corretto-\"\n        let (prefix, _) = split_version_prefix(&tv.request.version());\n        let latest_result = if bump {\n            // Note: Backend's latest_version_with_opts takes individual parameters,\n            // not a ResolveOptions struct like ToolVersion's method\n            t.latest_version_with_opts(\n                config,\n                Some(prefix.clone()).filter(|s| !s.is_empty()),\n                opts.before_date,\n            )\n            .await\n        } else {\n            tv.latest_version_with_opts(config, opts)\n                .await\n                .map(Option::from)\n        };\n        let latest = match latest_result {\n            Ok(Some(latest)) => latest,\n            Ok(None) => {\n                warn!(\"Error getting latest version for {t}: no latest version found\");\n                return Ok(None);\n            }\n            Err(e) => {\n                warn!(\"Error getting latest version for {t}: {e:#}\");\n                return Ok(None);\n            }\n        };\n        let mut oi = Self::new(config, tv, latest)?;\n        if oi\n            .current\n            .as_ref()\n            .is_some_and(|c| !toolset::is_outdated_version(c, &oi.latest))\n        {\n            // Check if this is a rolling version (like \"nightly\") with a new checksum\n            let rolling_outdated = t\n                .is_rolling_version_outdated(config, &oi.tool_version.request.version())\n                .await;\n            if !rolling_outdated {\n                trace!(\"skipping up-to-date version {}\", oi.tool_version);\n                return Ok(None);\n            }\n            trace!(\n                \"rolling version {} has updates (checksum changed)\",\n                oi.tool_version.request.version()\n            );\n        }\n        if bump {\n            let old = oi.tool_version.request.version();\n            let old = old.strip_prefix(&prefix).unwrap_or_default();\n            let new = oi.latest.strip_prefix(&prefix).unwrap_or_default();\n            if let Some(bumped_version) = check_semver_bump(old, new)\n                && bumped_version != oi.tool_version.request.version()\n            {\n                oi.bump = match oi.tool_request.clone() {\n                    ToolRequest::Version {\n                        version: _version,\n                        backend,\n                        options,\n                        source,\n                    } => {\n                        oi.tool_request = ToolRequest::Version {\n                            backend,\n                            options,\n                            source,\n                            version: format!(\"{prefix}{bumped_version}\"),\n                        };\n                        Some(oi.tool_request.version())\n                    }\n                    ToolRequest::Prefix {\n                        prefix: _prefix,\n                        backend,\n                        options,\n                        source,\n                    } => {\n                        oi.tool_request = ToolRequest::Prefix {\n                            backend,\n                            options,\n                            source,\n                            prefix: format!(\"{prefix}{bumped_version}\"),\n                        };\n                        Some(oi.tool_request.version())\n                    }\n                    _ => {\n                        warn!(\"upgrading non-version tool requests\");\n                        None\n                    }\n                }\n            }\n        }\n        Ok(Some(oi))\n    }\n\n    fn display_current(current: &Option<String>) -> String {\n        if let Some(current) = current {\n            current.to_string()\n        } else {\n            \"[MISSING]\".to_string()\n        }\n    }\n\n    fn display_bump(bump: &Option<String>) -> String {\n        if let Some(bump) = bump {\n            bump.to_string()\n        } else {\n            \"[NONE]\".to_string()\n        }\n    }\n}\n\nimpl Display for OutdatedInfo {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"{:<20} \", self.name)?;\n        if let Some(current) = &self.current {\n            write!(f, \"{current:<20} \")?;\n        } else {\n            write!(f, \"{:<20} \", \"MISSING\")?;\n        }\n        write!(f, \"-> {:<10} (\", self.latest)?;\n        if let Some(bump) = &self.bump {\n            write!(f, \"bump to {bump} in \")?;\n        }\n        write!(f, \"{})\", self.source)\n    }\n}\n\n/// check if the new version is a bump from the old version and return the new version\n/// at the same specificity level as the old version\n/// used with `mise outdated --bump` to determine what new semver range to use\n/// given old: \"20\" and new: \"21.2.3\", return Some(\"21\")\nfn check_semver_bump(old: &str, new: &str) -> Option<String> {\n    // Preserve known channel names as-is\n    const CHANNEL_NAMES: &[&str] = &[\n        \"latest\", \"nightly\", \"stable\", \"beta\", \"dev\", \"canary\", \"edge\", \"lts\",\n    ];\n    if CHANNEL_NAMES.iter().any(|&c| c.eq_ignore_ascii_case(old)) {\n        return Some(old.to_string());\n    }\n    if let Some((\"prefix\", old_)) = old.split_once(':') {\n        return check_semver_bump(old_, new);\n    }\n    let old_chunks = chunkify_version(old);\n    let new_chunks = chunkify_version(new);\n    // If old has no semver chunks but is non-empty, it's likely a channel name\n    // that we didn't recognize - preserve it as-is\n    if old_chunks.is_empty() && !old.is_empty() {\n        return Some(old.to_string());\n    }\n    if !old_chunks.is_empty() && !new_chunks.is_empty() {\n        if old_chunks.len() > new_chunks.len() {\n            warn!(\n                \"something weird happened with versioning, old: {old:?}, new: {new:?}\",\n                old = old_chunks,\n                new = new_chunks,\n            );\n        }\n        let bump = new_chunks\n            .into_iter()\n            .take(old_chunks.len())\n            .collect::<Vec<_>>();\n        if bump == old_chunks {\n            None\n        } else {\n            Some(bump.join(\"\"))\n        }\n    } else {\n        Some(new.to_string())\n    }\n}\n\npub fn is_outdated_version(current: &str, latest: &str) -> bool {\n    if let (Some(c), Some(l)) = (Version::new(current), Version::new(latest)) {\n        c.lt(&l)\n    } else {\n        current != latest\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n    use test_log::test;\n\n    use super::{check_semver_bump, is_outdated_version};\n\n    #[test]\n    fn test_is_outdated_version() {\n        assert_eq!(is_outdated_version(\"1.10.0\", \"1.12.0\"), true);\n        assert_eq!(is_outdated_version(\"1.12.0\", \"1.10.0\"), false);\n\n        assert_eq!(\n            is_outdated_version(\"1.10.0-SNAPSHOT\", \"1.12.0-SNAPSHOT\"),\n            true\n        );\n        assert_eq!(\n            is_outdated_version(\"1.12.0-SNAPSHOT\", \"1.10.0-SNAPSHOT\"),\n            false\n        );\n\n        assert_eq!(\n            is_outdated_version(\"temurin-17.0.0\", \"temurin-17.0.1\"),\n            true\n        );\n        assert_eq!(\n            is_outdated_version(\"temurin-17.0.1\", \"temurin-17.0.0\"),\n            false\n        );\n    }\n\n    #[test]\n    fn test_check_semver_bump() {\n        std::assert_eq!(check_semver_bump(\"20\", \"20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"20.0\", \"20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"20.0.0\", \"20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"20\", \"21.0.0\"), Some(\"21\".to_string()));\n        std::assert_eq!(\n            check_semver_bump(\"20.0\", \"20.1.0\"),\n            Some(\"20.1\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"20.0.0\", \"20.0.1\"),\n            Some(\"20.0.1\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"20.0.1\", \"20.1\"),\n            Some(\"20.1\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"2024-09-16\", \"2024-10-21\"),\n            Some(\"2024-10-21\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"20.0a1\", \"20.0a2\"),\n            Some(\"20.0a2\".to_string())\n        );\n        std::assert_eq!(check_semver_bump(\"v20\", \"v20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"v20.0\", \"v20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"v20.0.0\", \"v20.0.0\"), None);\n        std::assert_eq!(check_semver_bump(\"v20\", \"v21.0.0\"), Some(\"v21\".to_string()));\n        std::assert_eq!(\n            check_semver_bump(\"v20.0.0\", \"v20.0.1\"),\n            Some(\"v20.0.1\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"latest\", \"20.0.0\"),\n            Some(\"latest\".to_string())\n        );\n        // Channel names like \"nightly\", \"stable\", \"beta\" should be preserved\n        std::assert_eq!(\n            check_semver_bump(\"nightly\", \"0.10.0\"),\n            Some(\"nightly\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"stable\", \"0.10.0\"),\n            Some(\"stable\".to_string())\n        );\n        std::assert_eq!(\n            check_semver_bump(\"beta\", \"1.0.0-beta.1\"),\n            Some(\"beta\".to_string())\n        );\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_deps.rs",
    "content": "use std::collections::HashSet;\n\nuse eyre::Result;\nuse tokio::sync::mpsc;\n\nuse crate::deps_graph::DepsGraph;\nuse crate::toolset::tool_request::ToolRequest;\n\n/// Unique key for a tool request (backend full name + version)\npub type ToolKey = String;\n\n/// Creates a unique key for a ToolRequest\nfn tool_key(tr: &ToolRequest) -> ToolKey {\n    format!(\"{}@{}\", tr.ba().full(), tr.version())\n}\n\n/// Manages a dependency graph of tools for installation scheduling.\n/// Thin wrapper around `DepsGraph<ToolKey, ToolRequest>` with\n/// tool-specific dependency resolution.\n#[derive(Debug)]\npub struct ToolDeps {\n    inner: DepsGraph<ToolKey, ToolRequest>,\n}\n\nimpl ToolDeps {\n    /// Creates a new ToolDeps from a list of tool requests.\n    /// Builds the dependency graph based on each tool's dependencies.\n    /// Duplicate tool requests (same backend and version) are deduplicated.\n    pub fn new(requests: Vec<ToolRequest>) -> Result<Self> {\n        // Build nodes\n        let nodes: Vec<(ToolKey, ToolRequest)> = requests\n            .iter()\n            .map(|tr| (tool_key(tr), tr.clone()))\n            .collect();\n\n        // Build a set of all tool identifiers being installed for dependency lookup\n        let versions_hash: HashSet<String> =\n            requests.iter().flat_map(|tr| tr.ba().all_fulls()).collect();\n\n        // Compute edges from backend dependencies\n        let mut edges: Vec<(ToolKey, ToolKey)> = vec![];\n        for tr in &requests {\n            let tr_key = tool_key(tr);\n\n            if let Ok(backend) = tr.backend()\n                && let Ok(deps) = backend.get_all_dependencies(true)\n            {\n                for dep_ba in deps {\n                    let dep_fulls = dep_ba.all_fulls();\n                    if dep_fulls.iter().any(|full| versions_hash.contains(full)) {\n                        for other_tr in &requests {\n                            let other_fulls = other_tr.ba().all_fulls();\n                            if dep_fulls.iter().any(|f| other_fulls.contains(f)) {\n                                let other_key = tool_key(other_tr);\n                                if tr_key != other_key {\n                                    edges.push((tr_key.clone(), other_key));\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        let inner = DepsGraph::new(nodes, edges, tool_key)?;\n        Ok(Self { inner })\n    }\n\n    /// Subscribe to receive tools that are ready to install.\n    pub fn subscribe(&mut self) -> mpsc::UnboundedReceiver<Option<ToolRequest>> {\n        self.inner.subscribe()\n    }\n\n    /// Mark a tool as successfully installed and emit any newly-ready tools.\n    pub fn complete_success(&mut self, tr: &ToolRequest) {\n        self.inner.complete_success(&tool_key(tr));\n    }\n\n    /// Mark a tool as failed and block all transitive dependents.\n    pub fn complete_failure(&mut self, tr: &ToolRequest) {\n        self.inner.complete_failure(&tool_key(tr));\n    }\n\n    /// Returns the list of blocked tools (those whose dependencies failed or are in cycles)\n    pub fn blocked_tools(&self) -> Vec<ToolRequest> {\n        self.inner.blocked_nodes()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_empty_deps() {\n        let _deps = ToolDeps::new(vec![]).unwrap();\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_request.rs",
    "content": "use std::collections::BTreeMap;\nuse std::path::PathBuf;\nuse std::{\n    fmt::{Display, Formatter},\n    sync::Arc,\n};\n\nuse eyre::{Result, bail};\nuse versions::{Chunk, Version};\nuse xx::file;\n\nuse crate::backend::platform_target::PlatformTarget;\nuse crate::cli::args::BackendArg;\nuse crate::env;\nuse crate::lockfile::LockfileTool;\nuse crate::runtime_symlinks::is_runtime_symlink;\nuse crate::toolset::tool_version::ResolveOptions;\nuse crate::toolset::{ToolSource, ToolVersion, ToolVersionOptions};\nuse crate::{backend, lockfile};\nuse crate::{backend::ABackend, config::Config};\n\n#[derive(Debug, Clone, Hash, PartialEq, Eq)]\npub enum ToolRequest {\n    Version {\n        backend: Arc<BackendArg>,\n        version: String,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    },\n    Prefix {\n        backend: Arc<BackendArg>,\n        prefix: String,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    },\n    Ref {\n        backend: Arc<BackendArg>,\n        ref_: String,\n        ref_type: String,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    },\n    Sub {\n        backend: Arc<BackendArg>,\n        sub: String,\n        orig_version: String,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    },\n    Path {\n        backend: Arc<BackendArg>,\n        path: PathBuf,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    },\n    System {\n        backend: Arc<BackendArg>,\n        source: ToolSource,\n        options: ToolVersionOptions,\n    },\n}\n\nimpl ToolRequest {\n    pub fn new(backend: Arc<BackendArg>, s: &str, source: ToolSource) -> eyre::Result<Self> {\n        let s = match s.split_once('-') {\n            Some((ref_type @ (\"ref\" | \"tag\" | \"branch\" | \"rev\"), r)) => format!(\"{ref_type}:{r}\"),\n            _ => s.to_string(),\n        };\n        Ok(match s.split_once(':') {\n            Some((ref_type @ (\"ref\" | \"tag\" | \"branch\" | \"rev\"), r)) => Self::Ref {\n                ref_: r.to_string(),\n                ref_type: ref_type.to_string(),\n                options: backend.opts(),\n                backend,\n                source,\n            },\n            Some((\"prefix\", p)) => Self::Prefix {\n                prefix: p.to_string(),\n                options: backend.opts(),\n                backend,\n                source,\n            },\n            Some((\"path\", p)) => Self::Path {\n                path: PathBuf::from(p),\n                options: backend.opts(),\n                backend,\n                source,\n            },\n            Some((p, v)) if p.starts_with(\"sub-\") => Self::Sub {\n                sub: p.split_once('-').unwrap().1.to_string(),\n                options: backend.opts(),\n                orig_version: v.to_string(),\n                backend,\n                source,\n            },\n            None => {\n                if s == \"system\" {\n                    Self::System {\n                        options: backend.opts(),\n                        backend,\n                        source,\n                    }\n                } else {\n                    Self::Version {\n                        version: s,\n                        options: backend.opts(),\n                        backend,\n                        source,\n                    }\n                }\n            }\n            _ => bail!(\"invalid tool version request: {s}\"),\n        })\n    }\n    pub fn new_opts(\n        backend: Arc<BackendArg>,\n        s: &str,\n        options: ToolVersionOptions,\n        source: ToolSource,\n    ) -> eyre::Result<Self> {\n        let mut tvr = Self::new(backend, s, source)?;\n        match &mut tvr {\n            Self::Version { options: o, .. }\n            | Self::Prefix { options: o, .. }\n            | Self::Ref { options: o, .. } => *o = options,\n            _ => Default::default(),\n        }\n        Ok(tvr)\n    }\n    pub fn set_source(&mut self, source: ToolSource) -> Self {\n        match self {\n            Self::Version { source: s, .. }\n            | Self::Prefix { source: s, .. }\n            | Self::Ref { source: s, .. }\n            | Self::Path { source: s, .. }\n            | Self::Sub { source: s, .. }\n            | Self::System { source: s, .. } => *s = source,\n        }\n        self.clone()\n    }\n    pub fn ba(&self) -> &Arc<BackendArg> {\n        match self {\n            Self::Version { backend, .. }\n            | Self::Prefix { backend, .. }\n            | Self::Ref { backend, .. }\n            | Self::Path { backend, .. }\n            | Self::Sub { backend, .. }\n            | Self::System { backend, .. } => backend,\n        }\n    }\n    pub fn backend(&self) -> Result<ABackend> {\n        self.ba().backend()\n    }\n    pub fn source(&self) -> &ToolSource {\n        match self {\n            Self::Version { source, .. }\n            | Self::Prefix { source, .. }\n            | Self::Ref { source, .. }\n            | Self::Path { source, .. }\n            | Self::Sub { source, .. }\n            | Self::System { source, .. } => source,\n        }\n    }\n    pub fn os(&self) -> &Option<Vec<String>> {\n        match self {\n            Self::Version { options, .. }\n            | Self::Prefix { options, .. }\n            | Self::Ref { options, .. }\n            | Self::Path { options, .. }\n            | Self::Sub { options, .. }\n            | Self::System { options, .. } => &options.os,\n        }\n    }\n    pub fn set_options(&mut self, options: ToolVersionOptions) -> &mut Self {\n        match self {\n            Self::Version { options: o, .. }\n            | Self::Prefix { options: o, .. }\n            | Self::Ref { options: o, .. }\n            | Self::Sub { options: o, .. }\n            | Self::Path { options: o, .. }\n            | Self::System { options: o, .. } => *o = options,\n        }\n        self\n    }\n    pub fn version(&self) -> String {\n        match self {\n            Self::Version { version: v, .. } => v.clone(),\n            Self::Prefix { prefix: p, .. } => format!(\"prefix:{p}\"),\n            Self::Ref {\n                ref_: r, ref_type, ..\n            } => format!(\"{ref_type}:{r}\"),\n            Self::Path { path: p, .. } => format!(\"path:{}\", p.display()),\n            Self::Sub {\n                sub, orig_version, ..\n            } => format!(\"sub-{sub}:{orig_version}\"),\n            Self::System { .. } => \"system\".to_string(),\n        }\n    }\n\n    pub fn options(&self) -> ToolVersionOptions {\n        match self {\n            Self::Version { options: o, .. }\n            | Self::Prefix { options: o, .. }\n            | Self::Ref { options: o, .. }\n            | Self::Sub { options: o, .. }\n            | Self::Path { options: o, .. }\n            | Self::System { options: o, .. } => o.clone(),\n        }\n    }\n\n    pub async fn is_installed(&self, config: &Arc<Config>) -> bool {\n        if let Some(backend) = backend::get(self.ba()) {\n            match self.resolve(config, &Default::default()).await {\n                Ok(tv) => backend.is_version_installed(config, &tv, false),\n                Err(e) => {\n                    debug!(\"ToolRequest.is_installed: {e:#}\");\n                    false\n                }\n            }\n        } else {\n            false\n        }\n    }\n\n    pub fn install_path(&self, config: &Config) -> Option<PathBuf> {\n        match self {\n            Self::Version {\n                backend, version, ..\n            } => {\n                let path = backend.installs_path.join(version);\n                Some(env::find_in_shared_installs(\n                    path,\n                    &backend.tool_dir_name(),\n                    version,\n                ))\n            }\n            Self::Ref {\n                backend,\n                ref_,\n                ref_type,\n                ..\n            } => {\n                let pathname = format!(\"{ref_type}-{ref_}\");\n                let path = backend.installs_path.join(&pathname);\n                Some(env::find_in_shared_installs(\n                    path,\n                    &backend.tool_dir_name(),\n                    &pathname,\n                ))\n            }\n            Self::Sub {\n                backend,\n                sub,\n                orig_version,\n                ..\n            } => self\n                .local_resolve(config, orig_version)\n                .inspect_err(|e| warn!(\"ToolRequest.local_resolve: {e:#}\"))\n                .unwrap_or_default()\n                .map(|v| {\n                    let pathname = version_sub(&v, sub.as_str());\n                    let path = backend.installs_path.join(&pathname);\n                    env::find_in_shared_installs(path, &backend.tool_dir_name(), &pathname)\n                }),\n            Self::Prefix {\n                backend, prefix, ..\n            } => {\n                // Check primary install path first\n                let found = match file::ls(&backend.installs_path) {\n                    Ok(installs) => installs\n                        .iter()\n                        .find(|p| {\n                            !is_runtime_symlink(p)\n                                && p.file_name().unwrap().to_string_lossy().starts_with(prefix)\n                        })\n                        .cloned(),\n                    Err(_) => None,\n                };\n                // Fall back to shared install directories\n                found.or_else(|| {\n                    let tool_dir_name = backend.tool_dir_name();\n                    for shared_dir in env::shared_install_dirs().iter() {\n                        let shared_tool_dir = shared_dir.join(&tool_dir_name);\n                        if let Ok(installs) = file::ls(&shared_tool_dir)\n                            && let Some(p) = installs.iter().find(|p| {\n                                !is_runtime_symlink(p)\n                                    && p.file_name().unwrap().to_string_lossy().starts_with(prefix)\n                            })\n                        {\n                            return Some(p.clone());\n                        }\n                    }\n                    None\n                })\n            }\n            Self::Path { path, .. } => Some(path.clone()),\n            Self::System { .. } => None,\n        }\n    }\n\n    pub fn lockfile_resolve(&self, config: &Config) -> Result<Option<LockfileTool>> {\n        self.lockfile_resolve_with_prefix(config, &self.version())\n    }\n\n    /// Like lockfile_resolve but uses a custom prefix instead of self.version().\n    /// This is used after alias resolution (e.g., \"lts\" → \"24\") so the lockfile\n    /// prefix match can find entries like \"24.13.0\".starts_with(\"24\").\n    pub fn lockfile_resolve_with_prefix(\n        &self,\n        config: &Config,\n        prefix: &str,\n    ) -> Result<Option<LockfileTool>> {\n        let request_options = if let Ok(backend) = self.backend() {\n            let target = PlatformTarget::from_current();\n            backend.resolve_lockfile_options(self, &target)\n        } else {\n            BTreeMap::new()\n        };\n        let path = match self.source() {\n            ToolSource::MiseToml(path) => Some(path),\n            _ => None,\n        };\n        lockfile::get_locked_version(\n            config,\n            path.map(|p| p.as_path()),\n            &self.ba().short,\n            prefix,\n            &request_options,\n        )\n    }\n\n    pub fn local_resolve(&self, config: &Config, v: &str) -> eyre::Result<Option<String>> {\n        if let Some(lt) = self.lockfile_resolve(config)? {\n            return Ok(Some(lt.version));\n        }\n        if let Some(backend) = backend::get(self.ba()) {\n            let matches = backend.list_installed_versions_matching(v);\n            if matches.iter().any(|m| m == v) {\n                return Ok(Some(v.to_string()));\n            }\n            if let Some(v) = matches.last() {\n                return Ok(Some(v.to_string()));\n            }\n        }\n        Ok(None)\n    }\n\n    pub async fn resolve(\n        &self,\n        config: &Arc<Config>,\n        opts: &ResolveOptions,\n    ) -> Result<ToolVersion> {\n        ToolVersion::resolve(config, self.clone(), opts).await\n    }\n\n    pub fn is_os_supported(&self) -> bool {\n        if let Some(os) = self.os()\n            && !os.contains(&crate::cli::version::OS)\n        {\n            return false;\n        }\n        self.ba().is_os_supported()\n    }\n}\n\n/// subtracts sub from orig and removes suffix\n/// e.g. version_sub(\"18.2.3\", \"2\") -> \"16\"\n/// e.g. version_sub(\"18.2.3\", \"0.1\") -> \"18.1\"\n/// e.g. version_sub(\"2.79.0\", \"0.0.1\") -> \"2.78\" (underflow, returns prefix)\npub fn version_sub(orig: &str, sub: &str) -> String {\n    let mut orig = Version::new(orig).unwrap();\n    let sub = Version::new(sub).unwrap();\n    while orig.chunks.0.len() > sub.chunks.0.len() {\n        orig.chunks.0.pop();\n    }\n    for i in 0..orig.chunks.0.len() {\n        let m = sub.nth(i).unwrap();\n        let orig_val = orig.chunks.0[i].single_digit().unwrap();\n\n        if orig_val < m {\n            // Handle underflow with borrowing from higher digits\n            for j in (0..i).rev() {\n                let prev_val = orig.chunks.0[j].single_digit().unwrap();\n                if prev_val > 0 {\n                    orig.chunks.0[j] = Chunk::Numeric(prev_val - 1);\n                    orig.chunks.0.truncate(j + 1);\n                    return orig.to_string();\n                }\n            }\n            return \"0\".to_string();\n        }\n\n        orig.chunks.0[i] = Chunk::Numeric(orig_val - m);\n    }\n    orig.to_string()\n}\n\nimpl Display for ToolRequest {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"{}@{}\", &self.ba(), self.version())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::version_sub;\n    use pretty_assertions::assert_str_eq;\n    use test_log::test;\n\n    #[test]\n    fn test_version_sub() {\n        assert_str_eq!(version_sub(\"18.2.3\", \"2\"), \"16\");\n        assert_str_eq!(version_sub(\"18.2.3\", \"0.1\"), \"18.1\");\n        assert_str_eq!(version_sub(\"18.2.3\", \"0.0.1\"), \"18.2.2\");\n    }\n\n    #[test]\n    fn test_version_sub_underflow() {\n        // Test cases that would cause underflow return prefix for higher digit\n        assert_str_eq!(version_sub(\"2.0.0\", \"0.0.1\"), \"1\");\n        assert_str_eq!(version_sub(\"2.79.0\", \"0.0.1\"), \"2.78\");\n        assert_str_eq!(version_sub(\"1.0.0\", \"0.1.0\"), \"0\");\n        assert_str_eq!(version_sub(\"0.1.0\", \"1\"), \"0\");\n        assert_str_eq!(version_sub(\"1.2.3\", \"0.2.4\"), \"0\");\n        assert_str_eq!(version_sub(\"1.3.3\", \"0.2.4\"), \"1.0\");\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_request_set.rs",
    "content": "use std::fmt::{Debug, Display};\nuse std::{\n    collections::{BTreeMap, BTreeSet, HashSet},\n    sync::Arc,\n};\n\nuse crate::backend::backend_type::BackendType;\nuse crate::cli::args::{BackendArg, ToolArg};\nuse crate::config::{Config, Settings};\nuse crate::env;\nuse crate::registry::{REGISTRY, tool_enabled};\nuse crate::toolset::{ToolRequest, ToolSource, Toolset};\nuse indexmap::IndexMap;\nuse itertools::Itertools;\n\n#[derive(Debug, Default, Clone)]\npub struct ToolRequestSet {\n    pub tools: IndexMap<Arc<BackendArg>, Vec<ToolRequest>>,\n    pub sources: BTreeMap<Arc<BackendArg>, ToolSource>,\n    /// Tools that were filtered out because they don't exist in the registry (BackendType::Unknown)\n    pub unknown_tools: Vec<Arc<BackendArg>>,\n}\n\nimpl ToolRequestSet {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    // pub fn tools_with_sources(&self) -> Vec<(&BackendArg, &Vec<ToolRequest>, &ToolSource)> {\n    //     self.tools\n    //         .iter()\n    //         .map(|(backend, tvr)| (backend, tvr, self.sources.get(backend).unwrap()))\n    //         .collect()\n    // }\n\n    // pub fn installed_tools(&self) -> eyre::Result<Vec<&ToolRequest>> {\n    //     self.tools\n    //         .values()\n    //         .flatten()\n    //         .map(|tvr| match tvr.is_installed()? {\n    //             true => Ok(Some(tvr)),\n    //             false => Ok(None),\n    //         })\n    //         .flatten_ok()\n    //         .collect()\n    // }\n\n    pub async fn missing_tools(&self, config: &Arc<Config>) -> Vec<&ToolRequest> {\n        let mut tools = vec![];\n        for tr in self.tools.values().flatten() {\n            if tr.is_os_supported() && !tr.is_installed(config).await {\n                tools.push(tr);\n            }\n        }\n        tools\n    }\n\n    pub fn list_tools(&self) -> Vec<&Arc<BackendArg>> {\n        self.tools.keys().collect()\n    }\n\n    pub fn add_version(&mut self, tr: ToolRequest, source: &ToolSource) {\n        let fa = tr.ba();\n        if !self.tools.contains_key(fa) {\n            self.sources.insert(fa.clone(), source.clone());\n        }\n        let list = self.tools.entry(tr.ba().clone()).or_default();\n        list.push(tr);\n    }\n\n    pub fn iter(&self) -> impl Iterator<Item = (&Arc<BackendArg>, &Vec<ToolRequest>, &ToolSource)> {\n        self.tools\n            .iter()\n            .map(|(backend, tvr)| (backend, tvr, self.sources.get(backend).unwrap()))\n    }\n\n    pub fn into_iter(\n        self,\n    ) -> impl Iterator<Item = (Arc<BackendArg>, Vec<ToolRequest>, ToolSource)> {\n        self.tools.into_iter().map(move |(ba, tvr)| {\n            let source = self.sources.get(&ba).unwrap().clone();\n            (ba, tvr, source)\n        })\n    }\n\n    pub fn filter_by_tool(&self, mut tools: HashSet<String>) -> ToolRequestSet {\n        // add in the full names so something like cargo:cargo-binstall can be used in place of cargo-binstall\n        for short in tools.clone().iter() {\n            if let Some(rt) = REGISTRY.get(short.as_str()) {\n                tools.extend(rt.backends().iter().map(|s| s.to_string()));\n            }\n        }\n        self.iter()\n            .filter(|(ba, ..)| tools.contains(&ba.short) || tools.contains(&ba.full()))\n            .map(|(ba, trl, ts)| (ba.clone(), trl.clone(), ts.clone()))\n            .collect::<ToolRequestSet>()\n    }\n\n    pub fn into_toolset(self) -> Toolset {\n        self.into()\n    }\n}\n\nimpl Display for ToolRequestSet {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let versions = self.tools.values().flatten().join(\" \");\n        if versions.is_empty() {\n            write!(f, \"ToolRequestSet: <empty>\")?;\n        } else {\n            write!(f, \"ToolRequestSet: {versions}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl FromIterator<(Arc<BackendArg>, Vec<ToolRequest>, ToolSource)> for ToolRequestSet {\n    fn from_iter<T>(iter: T) -> Self\n    where\n        T: IntoIterator<Item = (Arc<BackendArg>, Vec<ToolRequest>, ToolSource)>,\n    {\n        let mut trs = ToolRequestSet::new();\n        for (_ba, tvr, source) in iter {\n            for tr in tvr {\n                trs.add_version(tr.clone(), &source);\n            }\n        }\n        trs\n    }\n}\n\n#[derive(Debug, Default)]\npub struct ToolRequestSetBuilder {\n    /// cli tool args\n    args: Vec<ToolArg>,\n    /// default to latest version if no version is specified (for `mise x`)\n    default_to_latest: bool,\n    /// tools which will be disabled\n    disable_tools: BTreeSet<BackendArg>,\n    /// tools which will be enabled\n    enable_tools: BTreeSet<BackendArg>,\n}\n\nimpl ToolRequestSetBuilder {\n    pub fn new() -> Self {\n        let settings = Settings::get();\n        Self {\n            disable_tools: settings.disable_tools().iter().map(|s| s.into()).collect(),\n            enable_tools: settings.enable_tools().iter().map(|s| s.into()).collect(),\n            ..Default::default()\n        }\n    }\n\n    // pub fn add_arg(mut self, arg: ToolArg) -> Self {\n    //     self.args.push(arg);\n    //     self\n    // }\n    //\n    // pub fn default_to_latest(mut self) -> Self {\n    //     self.default_to_latest = true;\n    //     self\n    // }\n    //\n\n    pub async fn build(&self, config: &Arc<Config>) -> eyre::Result<ToolRequestSet> {\n        let mut trs = ToolRequestSet::default();\n        trs = self.load_config_files(config, trs).await?;\n        trs = self.load_runtime_env(trs)?;\n        trs = self.load_runtime_args(trs)?;\n\n        for ba in trs.tools.keys().cloned().collect_vec() {\n            if self.is_disabled(&ba) {\n                // Track tools that don't exist in the registry\n                if ba.backend_type() == BackendType::Unknown {\n                    trs.unknown_tools.push(ba.clone());\n                }\n                trs.tools.shift_remove(&ba);\n                trs.sources.remove(&ba);\n            }\n        }\n\n        time!(\"tool_request_set::build\");\n        Ok(trs)\n    }\n\n    fn is_disabled(&self, ba: &BackendArg) -> bool {\n        let backend_type = ba.backend_type();\n        backend_type == BackendType::Unknown\n            || (cfg!(windows) && backend_type == BackendType::Asdf)\n            || !ba.is_os_supported()\n            || !tool_enabled(&self.enable_tools, &self.disable_tools, ba)\n    }\n\n    async fn load_config_files(\n        &self,\n        config: &Arc<Config>,\n        mut trs: ToolRequestSet,\n    ) -> eyre::Result<ToolRequestSet> {\n        for cf in config.config_files.values().rev() {\n            trs = merge(trs, cf.to_tool_request_set()?);\n        }\n        Ok(trs)\n    }\n\n    fn load_runtime_env(&self, mut trs: ToolRequestSet) -> eyre::Result<ToolRequestSet> {\n        for (k, v) in env::vars_safe() {\n            if k.starts_with(\"MISE_\") && k.ends_with(\"_VERSION\") && k != \"MISE_VERSION\" {\n                let plugin_name = k\n                    .trim_start_matches(\"MISE_\")\n                    .trim_end_matches(\"_VERSION\")\n                    .to_lowercase();\n                if plugin_name == \"install\" || plugin_name == \"tool\" {\n                    // ignore MISE_INSTALL_VERSION and MISE_TOOL_VERSION (set during hooks)\n                    continue;\n                }\n                let ba: Arc<BackendArg> = Arc::new(plugin_name.as_str().into());\n                let source = ToolSource::Environment(k, v.clone());\n                let mut env_ts = ToolRequestSet::new();\n                for v in v.split_whitespace() {\n                    let tvr = ToolRequest::new(ba.clone(), v, source.clone())?;\n                    env_ts.add_version(tvr, &source);\n                }\n                trs = merge(trs, env_ts);\n            }\n        }\n        Ok(trs)\n    }\n\n    fn load_runtime_args(&self, mut trs: ToolRequestSet) -> eyre::Result<ToolRequestSet> {\n        for (_, args) in self.args.iter().into_group_map_by(|arg| arg.ba.clone()) {\n            let mut arg_ts = ToolRequestSet::new();\n            for arg in args {\n                if let Some(tvr) = &arg.tvr {\n                    arg_ts.add_version(tvr.clone(), &ToolSource::Argument);\n                } else if self.default_to_latest {\n                    // this logic is required for `mise x` because with that specific command mise\n                    // should default to installing the \"latest\" version if no version is specified\n                    // in mise.toml\n\n                    if !trs.tools.contains_key(&arg.ba) {\n                        // no active version, so use \"latest\"\n                        let tr = ToolRequest::new(arg.ba.clone(), \"latest\", ToolSource::Argument)?;\n                        arg_ts.add_version(tr, &ToolSource::Argument);\n                    }\n                }\n            }\n            trs = merge(trs, arg_ts);\n        }\n\n        let tool_args = env::TOOL_ARGS.read().unwrap();\n        let mut arg_trs = ToolRequestSet::new();\n        for arg in tool_args.iter() {\n            if let Some(tvr) = &arg.tvr {\n                let mut tvr = tvr.clone();\n                // When CLI specifies a version for a tool that's in config,\n                // merge config options (e.g. postinstall) into the CLI request\n                if tvr.options().is_empty()\n                    && let Some(config_tvr) = trs.tools.get(&arg.ba).and_then(|v| v.first())\n                {\n                    let config_opts = config_tvr.options();\n                    if !config_opts.is_empty() {\n                        tvr.set_options(config_opts);\n                    }\n                }\n                arg_trs.add_version(tvr, &ToolSource::Argument);\n            } else if !trs.tools.contains_key(&arg.ba) {\n                // no active version, so use \"latest\"\n                let tr = ToolRequest::new(arg.ba.clone(), \"latest\", ToolSource::Argument)?;\n                arg_trs.add_version(tr, &ToolSource::Argument);\n            }\n        }\n        trs = merge(trs, arg_trs);\n\n        Ok(trs)\n    }\n}\n\nfn merge(mut a: ToolRequestSet, mut b: ToolRequestSet) -> ToolRequestSet {\n    // move things around such that the tools are in the config order\n    a.tools.retain(|ba, _| !b.tools.contains_key(ba));\n    a.sources.retain(|ba, _| !b.sources.contains_key(ba));\n    b.tools.extend(a.tools);\n    b.sources.extend(a.sources);\n    b\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_load_runtime_env_with_valid_utf8() {\n        // This test verifies that valid UTF-8 MISE_*_VERSION variables work correctly\n        unsafe {\n            std::env::set_var(\"MISE_NODE_VERSION\", \"20.0.0\");\n            std::env::set_var(\"MISE_PYTHON_VERSION\", \"3.11\");\n        }\n\n        let builder = ToolRequestSetBuilder::new();\n        let trs = builder.load_runtime_env(ToolRequestSet::new());\n\n        // Should not panic and should successfully load the versions\n        assert!(trs.is_ok());\n        let trs = trs.unwrap();\n        assert!(trs.tools.len() >= 2 || trs.tools.is_empty()); // May be empty if backends are disabled\n\n        unsafe {\n            std::env::remove_var(\"MISE_NODE_VERSION\");\n            std::env::remove_var(\"MISE_PYTHON_VERSION\");\n        }\n    }\n\n    #[test]\n    fn test_load_runtime_env_ignores_non_mise_vars() {\n        // Non-MISE variables should be ignored, even with special characters\n        unsafe {\n            std::env::set_var(\"HOMEBREW_INSTALL_BADGE\", \"✅\");\n            std::env::set_var(\"SOME_OTHER_VAR\", \"value\");\n        }\n\n        let builder = ToolRequestSetBuilder::new();\n        let result = builder.load_runtime_env(ToolRequestSet::new());\n\n        // Should not panic when non-MISE vars are present\n        assert!(result.is_ok());\n\n        unsafe {\n            std::env::remove_var(\"HOMEBREW_INSTALL_BADGE\");\n            std::env::remove_var(\"SOME_OTHER_VAR\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_source.rs",
    "content": "use serde::ser::{Serialize, SerializeStruct, Serializer};\nuse std::fmt::{Display, Formatter};\nuse std::path::{Path, PathBuf};\n\nuse indexmap::{IndexMap, indexmap};\n\nuse crate::file::display_path;\n\n/// where a tool version came from (e.g.: .tool-versions)\n#[derive(Debug, Default, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, strum::EnumIs)]\npub enum ToolSource {\n    ToolVersions(PathBuf),\n    MiseToml(PathBuf),\n    IdiomaticVersionFile(PathBuf),\n    ToolStub(PathBuf),\n    Argument,\n    Environment(String, String),\n    #[default]\n    Unknown,\n}\n\nimpl Display for ToolSource {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        match self {\n            ToolSource::ToolVersions(path) => write!(f, \"{}\", display_path(path)),\n            ToolSource::MiseToml(path) => write!(f, \"{}\", display_path(path)),\n            ToolSource::IdiomaticVersionFile(path) => write!(f, \"{}\", display_path(path)),\n            ToolSource::ToolStub(path) => write!(f, \"{}\", display_path(path)),\n            ToolSource::Argument => write!(f, \"--runtime\"),\n            ToolSource::Environment(k, v) => write!(f, \"{k}={v}\"),\n            ToolSource::Unknown => write!(f, \"unknown\"),\n        }\n    }\n}\n\nimpl ToolSource {\n    pub fn path(&self) -> Option<&Path> {\n        match self {\n            ToolSource::ToolVersions(path) => Some(path),\n            ToolSource::MiseToml(path) => Some(path),\n            ToolSource::IdiomaticVersionFile(path) => Some(path),\n            ToolSource::ToolStub(path) => Some(path),\n            _ => None,\n        }\n    }\n\n    pub fn as_json(&self) -> IndexMap<String, String> {\n        match self {\n            ToolSource::ToolVersions(path) => indexmap! {\n                \"type\".to_string() => \".tool-versions\".to_string(),\n                \"path\".to_string() => path.to_string_lossy().to_string(),\n            },\n            ToolSource::MiseToml(path) => indexmap! {\n                \"type\".to_string() => \"mise.toml\".to_string(),\n                \"path\".to_string() => path.to_string_lossy().to_string(),\n            },\n            ToolSource::IdiomaticVersionFile(path) => indexmap! {\n                \"type\".to_string() => \"idiomatic-version-file\".to_string(),\n                \"path\".to_string() => path.to_string_lossy().to_string(),\n            },\n            ToolSource::ToolStub(path) => indexmap! {\n                \"type\".to_string() => \"tool-stub\".to_string(),\n                \"path\".to_string() => path.to_string_lossy().to_string(),\n            },\n            ToolSource::Argument => indexmap! {\n                \"type\".to_string() => \"argument\".to_string(),\n            },\n            ToolSource::Environment(key, value) => indexmap! {\n                \"type\".to_string() => \"environment\".to_string(),\n                \"key\".to_string() => key.to_string(),\n                \"value\".to_string() => value.to_string(),\n            },\n            ToolSource::Unknown => indexmap! {\n                \"type\".to_string() => \"unknown\".to_string(),\n            },\n        }\n    }\n}\n\nimpl Serialize for ToolSource {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        let mut s = serializer.serialize_struct(\"ToolSource\", 3)?;\n        match self {\n            ToolSource::ToolVersions(path) => {\n                s.serialize_field(\"type\", \".tool-versions\")?;\n                s.serialize_field(\"path\", path)?;\n            }\n            ToolSource::MiseToml(path) => {\n                s.serialize_field(\"type\", \"mise.toml\")?;\n                s.serialize_field(\"path\", path)?;\n            }\n            ToolSource::IdiomaticVersionFile(path) => {\n                s.serialize_field(\"type\", \"idiomatic-version-file\")?;\n                s.serialize_field(\"path\", path)?;\n            }\n            ToolSource::ToolStub(path) => {\n                s.serialize_field(\"type\", \"tool-stub\")?;\n                s.serialize_field(\"path\", path)?;\n            }\n            ToolSource::Argument => {\n                s.serialize_field(\"type\", \"argument\")?;\n            }\n            ToolSource::Environment(key, value) => {\n                s.serialize_field(\"type\", \"environment\")?;\n                s.serialize_field(\"key\", key)?;\n                s.serialize_field(\"value\", value)?;\n            }\n            ToolSource::Unknown => {\n                s.serialize_field(\"type\", \"unknown\")?;\n            }\n        }\n\n        s.end()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::{assert_eq, assert_str_eq};\n\n    use super::*;\n\n    #[test]\n    fn test_tool_source_display() {\n        let path = PathBuf::from(\"/home/user/.test-tool-versions\");\n\n        let ts = ToolSource::ToolVersions(path);\n        assert_str_eq!(ts.to_string(), \"/home/user/.test-tool-versions\");\n\n        let ts = ToolSource::MiseToml(PathBuf::from(\"/home/user/.mise.toml\"));\n        assert_str_eq!(ts.to_string(), \"/home/user/.mise.toml\");\n\n        let ts = ToolSource::IdiomaticVersionFile(PathBuf::from(\"/home/user/.node-version\"));\n        assert_str_eq!(ts.to_string(), \"/home/user/.node-version\");\n\n        let ts = ToolSource::Argument;\n        assert_str_eq!(ts.to_string(), \"--runtime\");\n\n        let ts = ToolSource::Environment(\"MISE_NODE_VERSION\".to_string(), \"18\".to_string());\n        assert_str_eq!(ts.to_string(), \"MISE_NODE_VERSION=18\");\n    }\n\n    #[test]\n    fn test_tool_source_as_json() {\n        let ts = ToolSource::ToolVersions(PathBuf::from(\"/home/user/.test-tool-versions\"));\n        assert_eq!(\n            ts.as_json(),\n            indexmap! {\n                \"type\".to_string() => \".tool-versions\".to_string(),\n                \"path\".to_string() => \"/home/user/.test-tool-versions\".to_string(),\n            }\n        );\n\n        let ts = ToolSource::MiseToml(PathBuf::from(\"/home/user/.mise.toml\"));\n        assert_eq!(\n            ts.as_json(),\n            indexmap! {\n                \"type\".to_string() => \"mise.toml\".to_string(),\n                \"path\".to_string() => \"/home/user/.mise.toml\".to_string(),\n            }\n        );\n\n        let ts = ToolSource::IdiomaticVersionFile(PathBuf::from(\"/home/user/.node-version\"));\n        assert_eq!(\n            ts.as_json(),\n            indexmap! {\n                \"type\".to_string() => \"idiomatic-version-file\".to_string(),\n                \"path\".to_string() => \"/home/user/.node-version\".to_string(),\n            }\n        );\n\n        let ts = ToolSource::Argument;\n        assert_eq!(\n            ts.as_json(),\n            indexmap! {\n                \"type\".to_string() => \"argument\".to_string(),\n            }\n        );\n\n        let ts = ToolSource::Environment(\"MISE_NODE_VERSION\".to_string(), \"18\".to_string());\n        assert_eq!(\n            ts.as_json(),\n            indexmap! {\n                \"type\".to_string() => \"environment\".to_string(),\n                \"key\".to_string() => \"MISE_NODE_VERSION\".to_string(),\n                \"value\".to_string() => \"18\".to_string(),\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_version.rs",
    "content": "use std::fmt::{Display, Formatter};\nuse std::fs;\nuse std::hash::{Hash, Hasher};\nuse std::path::PathBuf;\nuse std::{cmp::Ordering, sync::LazyLock};\nuse std::{collections::BTreeMap, sync::Arc};\n\nuse crate::backend::ABackend;\nuse crate::cli::args::BackendArg;\nuse crate::config::{Config, Settings};\nuse crate::env;\n#[cfg(windows)]\nuse crate::file;\nuse crate::hash::hash_to_str;\nuse crate::lockfile::{CondaPackageInfo, LockfileTool, PlatformInfo};\nuse crate::toolset::{ToolRequest, ToolVersionOptions, tool_request};\nuse console::style;\nuse dashmap::DashMap;\nuse eyre::{Result, bail};\nuse jiff::Timestamp;\n#[cfg(windows)]\nuse path_absolutize::Absolutize;\n\nstatic INSTALL_PATH_CACHE: LazyLock<DashMap<ToolVersion, PathBuf>> = LazyLock::new(DashMap::new);\n\n/// Clear the install_path cache. Called when install state is reset\n/// to avoid stale paths (e.g. shared dir paths after a new install).\npub fn reset_install_path_cache() {\n    INSTALL_PATH_CACHE.clear();\n}\n\n/// represents a single version of a tool for a particular plugin\n#[derive(Debug, Clone)]\npub struct ToolVersion {\n    pub request: ToolRequest,\n    pub version: String,\n    pub lock_platforms: BTreeMap<String, PlatformInfo>,\n    pub install_path: Option<PathBuf>,\n    /// Conda packages resolved during installation: (platform, basename) -> CondaPackageInfo\n    pub conda_packages: BTreeMap<(String, String), CondaPackageInfo>,\n}\n\nimpl ToolVersion {\n    pub fn new(request: ToolRequest, version: String) -> Self {\n        ToolVersion {\n            request,\n            version,\n            lock_platforms: Default::default(),\n            install_path: None,\n            conda_packages: Default::default(),\n        }\n    }\n\n    pub async fn resolve(\n        config: &Arc<Config>,\n        request: ToolRequest,\n        opts: &ResolveOptions,\n    ) -> Result<Self> {\n        trace!(\"resolving {} {}\", &request, opts);\n        if opts.use_locked_version\n            && !has_linked_version(request.ba())\n            && let Some(lt) = request.lockfile_resolve(config)?\n        {\n            return Ok(Self::from_lockfile(request.clone(), lt));\n        }\n        let backend = request.ba().backend()?;\n        if let Some(plugin) = backend.plugin()\n            && !plugin.is_installed()\n        {\n            let tv = Self::new(request.clone(), request.version());\n            return Ok(tv);\n        }\n        let tv = match request.clone() {\n            ToolRequest::Version { version: v, .. } => {\n                Self::resolve_version(config, request, &v, opts).await?\n            }\n            ToolRequest::Prefix { prefix, .. } => {\n                Self::resolve_prefix(config, request, &prefix, opts).await?\n            }\n            ToolRequest::Sub {\n                sub, orig_version, ..\n            } => Self::resolve_sub(config, request, &sub, &orig_version, opts).await?,\n            _ => {\n                let version = request.version();\n                Self::new(request, version)\n            }\n        };\n        trace!(\"resolved: {tv}\");\n        Ok(tv)\n    }\n\n    fn from_lockfile(request: ToolRequest, lt: LockfileTool) -> Self {\n        let mut tv = Self::new(request, lt.version);\n        tv.lock_platforms = lt.platforms;\n        tv\n    }\n\n    pub fn ba(&self) -> &BackendArg {\n        self.request.ba()\n    }\n\n    pub fn backend(&self) -> Result<ABackend> {\n        self.ba().backend()\n    }\n\n    pub fn short(&self) -> &str {\n        &self.ba().short\n    }\n\n    pub fn install_path(&self) -> PathBuf {\n        if let Some(p) = &self.install_path {\n            return p.clone();\n        }\n        if let Some(p) = INSTALL_PATH_CACHE.get(self) {\n            return p.clone();\n        }\n        let pathname = match &self.request {\n            ToolRequest::Path { path: p, .. } => p.to_string_lossy().to_string(),\n            _ => self.tv_pathname(),\n        };\n        let path = self.ba().installs_path.join(&pathname);\n\n        // handle non-symlinks on windows\n        // TODO: make this a utility function in xx\n        #[cfg(windows)]\n        if path.is_file() {\n            if let Ok(p) = file::read_to_string(&path).map(PathBuf::from) {\n                let path = self.ba().installs_path.join(p);\n                if path.exists() {\n                    return path\n                        .absolutize()\n                        .expect(\"failed to absolutize path\")\n                        .to_path_buf();\n                }\n            }\n        }\n\n        // Check shared install directories if the primary path doesn't exist\n        let path = if matches!(&self.request, ToolRequest::Path { .. }) {\n            path\n        } else {\n            env::find_in_shared_installs(path, &self.ba().tool_dir_name(), &pathname)\n        };\n\n        INSTALL_PATH_CACHE.insert(self.clone(), path.clone());\n        path\n    }\n    pub fn cache_path(&self) -> PathBuf {\n        self.ba().cache_path.join(self.tv_pathname())\n    }\n    pub fn download_path(&self) -> PathBuf {\n        self.request.ba().downloads_path.join(self.tv_pathname())\n    }\n    pub async fn latest_version(&self, config: &Arc<Config>) -> Result<String> {\n        self.latest_version_with_opts(config, &ResolveOptions::default())\n            .await\n    }\n\n    pub async fn latest_version_with_opts(\n        &self,\n        config: &Arc<Config>,\n        base_opts: &ResolveOptions,\n    ) -> Result<String> {\n        // Note: We always use latest_versions=true and use_locked_version=false for latest version lookup,\n        // but we preserve before_date from base_opts to respect date-based filtering\n        let opts = ResolveOptions {\n            latest_versions: true,\n            use_locked_version: false,\n            before_date: base_opts.before_date,\n        };\n        let tv = self.request.resolve(config, &opts).await?;\n        // map cargo backend specific prefixes to ref\n        let version = match tv.request.version().split_once(':') {\n            Some((_ref_type @ (\"tag\" | \"branch\" | \"rev\"), r)) => {\n                format!(\"ref:{r}\")\n            }\n            _ => tv.version,\n        };\n        Ok(version)\n    }\n    pub fn style(&self) -> String {\n        format!(\n            \"{}{}\",\n            style(&self.ba().short).blue().for_stderr(),\n            style(&format!(\"@{}\", &self.version)).for_stderr()\n        )\n    }\n    pub fn tv_pathname(&self) -> String {\n        match &self.request {\n            ToolRequest::Version { .. } => self.version.to_string(),\n            ToolRequest::Prefix { .. } => self.version.to_string(),\n            ToolRequest::Sub { .. } => self.version.to_string(),\n            ToolRequest::Ref { ref_: r, .. } => format!(\"ref-{r}\"),\n            ToolRequest::Path { path: p, .. } => format!(\"path-{}\", hash_to_str(p)),\n            ToolRequest::System { .. } => {\n                // Only show deprecation warning if not from .tool-versions file\n                if !matches!(\n                    self.request.source(),\n                    crate::toolset::ToolSource::ToolVersions(_)\n                ) {\n                    deprecated!(\n                        \"system_tool_version\",\n                        \"@system is deprecated, use MISE_DISABLE_TOOLS instead\"\n                    );\n                }\n                \"system\".to_string()\n            }\n        }\n        .replace([':', '/'], \"-\")\n    }\n    async fn resolve_version(\n        config: &Arc<Config>,\n        request: ToolRequest,\n        v: &str,\n        opts: &ResolveOptions,\n    ) -> Result<ToolVersion> {\n        let backend = request.backend()?;\n        let v = config.resolve_alias(&backend, v).await?;\n\n        // Re-check the lockfile after alias resolution (e.g., \"lts\" → \"24\")\n        // The initial lockfile check in resolve() uses the unresolved alias which\n        // won't match lockfile entries like \"24.13.0\".starts_with(\"lts\")\n        if opts.use_locked_version\n            && !has_linked_version(request.ba())\n            && let Some(lt) = request.lockfile_resolve_with_prefix(config, &v)?\n        {\n            return Ok(Self::from_lockfile(request.clone(), lt));\n        }\n        let settings = Settings::get();\n        if settings.locked\n            && opts.use_locked_version\n            && settings.lockfile_enabled()\n            && !has_linked_version(request.ba())\n            && request.source().path().is_some()\n        {\n            bail!(\n                \"{}@{} is not in the lockfile\\nhint: Run `mise install` without --locked to update the lockfile\",\n                request.ba().short,\n                request.version()\n            );\n        }\n\n        match v.split_once(':') {\n            Some((ref_type @ (\"ref\" | \"tag\" | \"branch\" | \"rev\"), r)) => {\n                return Ok(Self::resolve_ref(\n                    r.to_string(),\n                    ref_type.to_string(),\n                    request.options(),\n                    &request,\n                ));\n            }\n            Some((\"path\", p)) => {\n                return Self::resolve_path(PathBuf::from(p), &request);\n            }\n            Some((\"prefix\", p)) => {\n                return Self::resolve_prefix(config, request, p, opts).await;\n            }\n            Some((part, v)) if part.starts_with(\"sub-\") => {\n                let sub = part.split_once('-').unwrap().1;\n                return Self::resolve_sub(config, request, sub, v, opts).await;\n            }\n            _ => (),\n        }\n\n        let build = |v| Ok(Self::new(request.clone(), v));\n\n        if let Some(plugin) = backend.plugin()\n            && !plugin.is_installed()\n        {\n            return build(v);\n        }\n\n        let settings = Settings::get();\n        let is_offline = settings.offline();\n\n        if v == \"latest\" {\n            if !opts.latest_versions\n                && let Some(v) = backend.latest_installed_version(None)?\n            {\n                return build(v);\n            }\n            if !is_offline\n                && let Some(v) = backend\n                    .latest_version_with_opts(config, None, opts.before_date)\n                    .await?\n            {\n                return build(v);\n            }\n        }\n        if !opts.latest_versions {\n            let matches = backend.list_installed_versions_matching(&v);\n            if matches.contains(&v) {\n                return build(v);\n            }\n            if let Some(v) = matches.last() {\n                return build(v.clone());\n            }\n        }\n        // When OFFLINE, skip ALL remote version fetching regardless of version format\n        if is_offline {\n            return build(v);\n        }\n        // In prefer-offline mode (hook-env, activate, exec), skip remote version\n        // fetching for fully-qualified versions (e.g. \"2.3.2\") that aren't installed.\n        // Prefix versions like \"2\" still need remote resolution to find e.g. \"2.1.0\".\n        // \"latest\" also needs remote resolution but is handled in the block above.\n        if settings.prefer_offline() && v.matches('.').count() >= 2 {\n            return build(v);\n        }\n        // First try with date filter (common case)\n        let matches = backend\n            .list_versions_matching_with_opts(config, &v, opts.before_date)\n            .await?;\n        if matches.contains(&v) {\n            return build(v);\n        }\n        // If date filter is active and exact version not found, check without filter.\n        // Explicit pinned versions like \"22.5.0\" should not be filtered by date.\n        if opts.before_date.is_some() {\n            let all_versions = backend.list_versions_matching(config, &v).await?;\n            if all_versions.contains(&v) {\n                // Exact match exists but was filtered by date - use it anyway\n                return build(v);\n            }\n        }\n        Self::resolve_prefix(config, request, &v, opts).await\n    }\n\n    /// resolve a version like `sub-1:12.0.0` which becomes `11.0.0`, `sub-0.1:12.1.0` becomes `12.0.0`\n    async fn resolve_sub(\n        config: &Arc<Config>,\n        request: ToolRequest,\n        sub: &str,\n        v: &str,\n        opts: &ResolveOptions,\n    ) -> Result<Self> {\n        let backend = request.backend()?;\n        let v = match v {\n            \"latest\" => backend\n                .latest_version_with_opts(config, None, opts.before_date)\n                .await?\n                .ok_or_else(|| {\n                    let msg = if opts.before_date.is_some() {\n                        format!(\n                            \"no versions found for {} matching date filter\",\n                            backend.id()\n                        )\n                    } else {\n                        format!(\"no versions found for {}\", backend.id())\n                    };\n                    eyre::eyre!(msg)\n                })?,\n            _ => config.resolve_alias(&backend, v).await?,\n        };\n        let v = tool_request::version_sub(&v, sub);\n        Box::pin(Self::resolve_version(config, request, &v, opts)).await\n    }\n\n    async fn resolve_prefix(\n        config: &Arc<Config>,\n        request: ToolRequest,\n        prefix: &str,\n        opts: &ResolveOptions,\n    ) -> Result<Self> {\n        let backend = request.backend()?;\n        if !opts.latest_versions\n            && let Some(v) = backend.list_installed_versions_matching(prefix).last()\n        {\n            return Ok(Self::new(request, v.to_string()));\n        }\n        let matches = backend\n            .list_versions_matching_with_opts(config, prefix, opts.before_date)\n            .await?;\n        let v = match matches.last() {\n            Some(v) => v,\n            None => prefix,\n            // None => Err(VersionNotFound(plugin.name.clone(), prefix.to_string()))?,\n        };\n        Ok(Self::new(request, v.to_string()))\n    }\n\n    fn resolve_ref(\n        ref_: String,\n        ref_type: String,\n        opts: ToolVersionOptions,\n        tr: &ToolRequest,\n    ) -> Self {\n        let request = ToolRequest::Ref {\n            backend: tr.ba().clone(),\n            ref_,\n            ref_type,\n            options: opts.clone(),\n            source: tr.source().clone(),\n        };\n        let version = request.version();\n        Self::new(request, version)\n    }\n\n    fn resolve_path(path: PathBuf, tr: &ToolRequest) -> Result<ToolVersion> {\n        let path = fs::canonicalize(path)?;\n        let request = ToolRequest::Path {\n            backend: tr.ba().clone(),\n            path,\n            source: tr.source().clone(),\n            options: tr.options().clone(),\n        };\n        let version = request.version();\n        Ok(Self::new(request, version))\n    }\n}\n\nimpl Display for ToolVersion {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        write!(f, \"{}@{}\", &self.ba().full(), &self.version)\n    }\n}\n\nimpl PartialEq for ToolVersion {\n    fn eq(&self, other: &Self) -> bool {\n        self.ba() == other.ba() && self.version == other.version\n    }\n}\n\nimpl Eq for ToolVersion {}\n\nimpl PartialOrd for ToolVersion {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for ToolVersion {\n    fn cmp(&self, other: &Self) -> Ordering {\n        match self.request.ba().as_ref().cmp(other.ba()) {\n            Ordering::Equal => self.version.cmp(&other.version),\n            o => o,\n        }\n    }\n}\n\nimpl Hash for ToolVersion {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.ba().hash(state);\n        self.version.hash(state);\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct ResolveOptions {\n    pub latest_versions: bool,\n    pub use_locked_version: bool,\n    /// Only consider versions released before this timestamp\n    pub before_date: Option<Timestamp>,\n}\n\nimpl Default for ResolveOptions {\n    fn default() -> Self {\n        Self {\n            latest_versions: false,\n            use_locked_version: true,\n            before_date: None,\n        }\n    }\n}\n\n/// Check if a tool has any user-linked versions (created by `mise link`).\n/// A linked version is an installed version whose path is a symlink to an absolute path,\n/// as opposed to runtime symlinks which point to relative paths (starting with \"./\").\nfn has_linked_version(ba: &BackendArg) -> bool {\n    let installs_dir = &ba.installs_path;\n    let Ok(entries) = std::fs::read_dir(installs_dir) else {\n        return false;\n    };\n    for entry in entries.flatten() {\n        let path = entry.path();\n        if let Ok(Some(target)) = crate::file::resolve_symlink(&path) {\n            // Runtime symlinks start with \"./\" (e.g., latest -> ./1.35.0)\n            // User-linked symlinks point to absolute paths (e.g., brew -> /opt/homebrew/opt/hk)\n            if target.is_absolute() {\n                return true;\n            }\n        }\n    }\n    false\n}\n\nimpl Display for ResolveOptions {\n    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {\n        let mut opts = vec![];\n        if self.latest_versions {\n            opts.push(\"latest_versions\".to_string());\n        }\n        if self.use_locked_version {\n            opts.push(\"use_locked_version\".to_string());\n        }\n        if let Some(ts) = &self.before_date {\n            opts.push(format!(\"before_date={ts}\"));\n        }\n        write!(f, \"({})\", opts.join(\", \"))\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_version_list.rs",
    "content": "use std::sync::Arc;\n\nuse crate::errors::Error;\nuse crate::toolset::tool_request::ToolRequest;\nuse crate::toolset::tool_version::ResolveOptions;\nuse crate::toolset::{ToolSource, ToolVersion};\nuse crate::{cli::args::BackendArg, config::Config};\n\n/// represents several versions of a tool for a particular plugin\n#[derive(Debug, Clone)]\npub struct ToolVersionList {\n    pub backend: Arc<BackendArg>,\n    pub versions: Vec<ToolVersion>,\n    pub requests: Vec<ToolRequest>,\n    pub source: ToolSource,\n}\n\nimpl ToolVersionList {\n    pub fn new(backend: Arc<BackendArg>, source: ToolSource) -> Self {\n        Self {\n            backend,\n            versions: Vec::new(),\n            requests: vec![],\n            source,\n        }\n    }\n    pub async fn resolve(\n        &mut self,\n        config: &Arc<Config>,\n        opts: &ResolveOptions,\n    ) -> eyre::Result<()> {\n        self.versions.clear();\n        for tvr in &mut self.requests {\n            // Only use special options (latest_versions) for requests that\n            // explicitly specify \"latest\". This ensures `mise x node@20 npm@latest` only\n            // fetches latest for npm, not node.\n            // However, we always respect the caller's use_locked_version setting.\n            let request_opts = if tvr.version() == \"latest\" {\n                opts.clone()\n            } else {\n                ResolveOptions {\n                    latest_versions: false,\n                    use_locked_version: opts.use_locked_version,\n                    ..opts.clone()\n                }\n            };\n            match tvr.resolve(config, &request_opts).await {\n                Ok(v) => self.versions.push(v),\n                Err(err) => {\n                    return Err(Error::FailedToResolveVersion {\n                        tr: Box::new(tvr.clone()),\n                        ts: self.source.clone(),\n                        source: err,\n                    }\n                    .into());\n                }\n            }\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use pretty_assertions::assert_eq;\n\n    use crate::{dirs, env, file};\n\n    use super::*;\n\n    #[tokio::test]\n    #[cfg(unix)]\n    async fn test_tool_version_list() {\n        let config = Config::get().await.unwrap();\n        let ba: Arc<BackendArg> = Arc::new(\"tiny\".into());\n        let mut tvl = ToolVersionList::new(ba.clone(), ToolSource::Argument);\n        tvl.requests\n            .push(ToolRequest::new(ba, \"latest\", ToolSource::Argument).unwrap());\n        tvl.resolve(\n            &config,\n            &ResolveOptions {\n                latest_versions: true,\n                use_locked_version: false,\n                ..Default::default()\n            },\n        )\n        .await\n        .unwrap();\n        assert_eq!(tvl.versions.len(), 1);\n    }\n\n    #[tokio::test]\n    async fn test_tool_version_list_failure() {\n        env::set_var(\"MISE_FAILURE\", \"1\");\n        file::remove_all(dirs::CACHE.join(\"dummy\")).unwrap();\n        let config = Config::reset().await.unwrap();\n        let ba: Arc<BackendArg> = Arc::new(\"dummy\".into());\n        let mut tvl = ToolVersionList::new(ba.clone(), ToolSource::Argument);\n        tvl.requests\n            .push(ToolRequest::new(ba, \"latest\", ToolSource::Argument).unwrap());\n        let _ = tvl\n            .resolve(\n                &config,\n                &ResolveOptions {\n                    latest_versions: true,\n                    use_locked_version: false,\n                    ..Default::default()\n                },\n            )\n            .await;\n        assert_eq!(tvl.versions.len(), 0);\n        env::remove_var(\"MISE_FAILURE\");\n        Config::reset().await.unwrap();\n    }\n}\n"
  },
  {
    "path": "src/toolset/tool_version_options.rs",
    "content": "use indexmap::IndexMap;\n\n/// Option keys that are only relevant during initial installation and should not\n/// be persisted in the manifest or included in `full_with_opts()`.\n// install_env is a named field on ToolVersionOptions (serde puts it in self.install_env),\n// but parse_tool_options() can still place it in opts, so we filter it here as well.\npub const EPHEMERAL_OPT_KEYS: &[&str] = &[\"postinstall\", \"install_env\"];\n\n#[derive(Debug, Default, Clone, PartialEq, serde::Deserialize, serde::Serialize)]\npub struct ToolVersionOptions {\n    pub os: Option<Vec<String>>,\n    pub install_env: IndexMap<String, String>,\n    #[serde(flatten)]\n    pub opts: IndexMap<String, toml::Value>,\n}\n\n// toml::Value doesn't implement Eq (due to floats), but we control the values\n// and won't have NaN, so this is safe in practice.\nimpl Eq for ToolVersionOptions {}\n\n// Implement Hash manually to ensure deterministic hashing across IndexMap\nimpl std::hash::Hash for ToolVersionOptions {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        self.os.hash(state);\n\n        // Hash install_env in sorted order for deterministic hashing\n        let mut install_env_sorted: Vec<_> = self.install_env.iter().collect();\n        install_env_sorted.sort_by_key(|(k, _)| *k);\n        install_env_sorted.hash(state);\n\n        // Hash opts in sorted order for deterministic hashing\n        let mut opts_sorted: Vec<_> = self.opts.iter().collect();\n        opts_sorted.sort_by_key(|(k, _)| k.as_str());\n        for (k, v) in opts_sorted {\n            k.hash(state);\n            hash_toml_value(v, state);\n        }\n    }\n}\n\nfn hash_toml_value<H: std::hash::Hasher>(v: &toml::Value, state: &mut H) {\n    use std::hash::Hash;\n    match v {\n        toml::Value::Table(t) => {\n            let mut sorted: Vec<_> = t.iter().collect();\n            sorted.sort_by_key(|(k, _)| k.as_str());\n            for (k, v) in sorted {\n                k.hash(state);\n                hash_toml_value(v, state);\n            }\n        }\n        toml::Value::Array(arr) => {\n            for v in arr {\n                hash_toml_value(v, state);\n            }\n        }\n        _ => v.to_string().hash(state),\n    }\n}\n\nimpl ToolVersionOptions {\n    pub fn is_empty(&self) -> bool {\n        self.install_env.is_empty() && self.opts.is_empty()\n    }\n\n    /// Get a string value for a key. Returns the str for String values,\n    /// or None for non-string values.\n    pub fn get(&self, key: &str) -> Option<&str> {\n        self.opts.get(key).and_then(|v| v.as_str())\n    }\n\n    /// Convert opts to string values, extracting inner strings from\n    /// `toml::Value::String` and calling `to_string()` on other types.\n    pub fn opts_as_strings(&self) -> IndexMap<String, String> {\n        self.opts\n            .iter()\n            .map(|(k, v)| {\n                (\n                    k.clone(),\n                    match v {\n                        toml::Value::String(s) => s.clone(),\n                        _ => v.to_string(),\n                    },\n                )\n            })\n            .collect()\n    }\n\n    pub fn merge(&mut self, other: &IndexMap<String, toml::Value>) {\n        for (key, value) in other {\n            self.opts.entry(key.to_string()).or_insert(value.clone());\n        }\n    }\n\n    pub fn contains_key(&self, key: &str) -> bool {\n        if self.opts.contains_key(key) {\n            return true;\n        }\n\n        // Check if it's a nested key that exists\n        self.get_nested_value_exists(key)\n    }\n\n    pub fn iter(&self) -> impl Iterator<Item = (&String, &toml::Value)> {\n        self.opts.iter()\n    }\n\n    // Check if a nested value exists without returning a reference\n    fn get_nested_value_exists(&self, key: &str) -> bool {\n        // Split the key by dots to navigate nested structure\n        let parts: Vec<&str> = key.split('.').collect();\n        if parts.len() < 2 {\n            return false;\n        }\n\n        let root_key = parts[0];\n        let nested_path = &parts[1..];\n\n        if let Some(value) = self.opts.get(root_key) {\n            return Self::value_exists_at_path(value, nested_path);\n        }\n\n        false\n    }\n\n    fn value_exists_at_path(value: &toml::Value, path: &[&str]) -> bool {\n        if path.is_empty() {\n            return matches!(value, toml::Value::String(_));\n        }\n\n        match value {\n            toml::Value::Table(table) => {\n                if let Some(next_value) = table.get(path[0]) {\n                    Self::value_exists_at_path(next_value, &path[1..])\n                } else {\n                    false\n                }\n            }\n            _ => false,\n        }\n    }\n\n    /// Get nested values as owned Strings by navigating the toml::Value tree.\n    pub fn get_nested_string(&self, key: &str) -> Option<String> {\n        let parts: Vec<&str> = key.split('.').collect();\n        if parts.len() < 2 {\n            return None;\n        }\n\n        let root_key = parts[0];\n        let nested_path = &parts[1..];\n\n        if let Some(value) = self.opts.get(root_key) {\n            return Self::get_string_at_path(value, nested_path);\n        }\n\n        None\n    }\n\n    fn get_string_at_path(value: &toml::Value, path: &[&str]) -> Option<String> {\n        if path.is_empty() {\n            return match value {\n                toml::Value::String(s) => Some(s.clone()),\n                toml::Value::Integer(i) => Some(i.to_string()),\n                toml::Value::Boolean(b) => Some(b.to_string()),\n                toml::Value::Float(f) => Some(f.to_string()),\n                _ => None,\n            };\n        }\n\n        match value {\n            toml::Value::Table(table) => {\n                if let Some(next_value) = table.get(path[0]) {\n                    Self::get_string_at_path(next_value, &path[1..])\n                } else {\n                    None\n                }\n            }\n            _ => None,\n        }\n    }\n}\n\npub fn parse_tool_options(s: &str) -> ToolVersionOptions {\n    // Try TOML parsing first (handles nested structures like platforms={...} correctly)\n    if let Some(tvo) = try_parse_as_toml(s) {\n        return tvo;\n    }\n    // Fall back to manual parsing for legacy formats with unquoted values\n    parse_tool_options_manual(s)\n}\n\n/// Try parsing an options string as a TOML inline table.\n/// Returns `Some(opts)` if the string is valid TOML, `None` otherwise.\nfn try_parse_as_toml(s: &str) -> Option<ToolVersionOptions> {\n    let toml_str = format!(\"_x_ = {{ {s} }}\");\n    let value: toml::Value = toml::from_str(&toml_str).ok()?;\n    let table = value.get(\"_x_\")?.as_table()?;\n    let mut tvo = ToolVersionOptions::default();\n    for (k, v) in table {\n        match v {\n            toml::Value::Table(_) | toml::Value::Array(_) => {\n                tvo.opts.insert(k.clone(), v.clone());\n            }\n            toml::Value::String(_) => {\n                tvo.opts.insert(k.clone(), v.clone());\n            }\n            _ => {\n                // Convert scalar values (ints, bools, floats) to strings\n                tvo.opts.insert(\n                    k.clone(),\n                    toml::Value::String(v.to_string().trim_matches('\"').to_string()),\n                );\n            }\n        }\n    }\n    Some(tvo)\n}\n\n/// Legacy manual parser for option strings with unquoted values (e.g. `exe=rg,match=musl`).\n/// Splits by commas, but segments without `=` are appended to the previous key's value.\nfn parse_tool_options_manual(s: &str) -> ToolVersionOptions {\n    let mut tvo = ToolVersionOptions::default();\n    let mut current_key: Option<String> = None;\n    for opt in s.split(',') {\n        if let Some((k, v)) = opt.split_once('=') {\n            if !k.trim().is_empty() {\n                tvo.opts\n                    .insert(k.trim().to_string(), toml::Value::String(v.to_string()));\n                current_key = Some(k.trim().to_string());\n            }\n        } else if !opt.is_empty() {\n            // No '=' found, append to the previous value or create a new key\n            if let Some(key) = &current_key\n                && let Some(existing_value) = tvo.opts.get_mut(key)\n                && let toml::Value::String(s) = existing_value\n            {\n                s.push(',');\n                s.push_str(opt);\n            }\n        }\n    }\n    tvo\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use pretty_assertions::assert_eq;\n    use test_log::test;\n\n    fn s(v: &str) -> toml::Value {\n        toml::Value::String(v.to_string())\n    }\n\n    #[test]\n    fn test_parse_tool_options() {\n        let t = |input, expected| {\n            let opts = parse_tool_options(input);\n            assert_eq!(opts, expected);\n        };\n\n        t(\"\", ToolVersionOptions::default());\n        t(\n            \"exe=rg\",\n            ToolVersionOptions {\n                opts: [(\"exe\".to_string(), s(\"rg\"))].iter().cloned().collect(),\n                ..Default::default()\n            },\n        );\n        t(\n            \"exe=rg,match=musl\",\n            ToolVersionOptions {\n                opts: [\n                    (\"exe\".to_string(), s(\"rg\")),\n                    (\"match\".to_string(), s(\"musl\")),\n                ]\n                .iter()\n                .cloned()\n                .collect(),\n                ..Default::default()\n            },\n        );\n        t(\n            \"profile=minimal,components=rust-src,llvm-tools,targets=wasm32-unknown-unknown,thumbv2-none-eabi\",\n            ToolVersionOptions {\n                opts: [\n                    (\"profile\".to_string(), s(\"minimal\")),\n                    (\"components\".to_string(), s(\"rust-src,llvm-tools\")),\n                    (\n                        \"targets\".to_string(),\n                        s(\"wasm32-unknown-unknown,thumbv2-none-eabi\"),\n                    ),\n                ]\n                .iter()\n                .cloned()\n                .collect(),\n                ..Default::default()\n            },\n        );\n        // test trimming of key whitespace\n        t(\n            \"  exe =  rg  ,  match = musl  \",\n            ToolVersionOptions {\n                opts: [\n                    (\"exe\".to_string(), s(\"  rg  \")),\n                    (\"match\".to_string(), s(\" musl  \")),\n                ]\n                .iter()\n                .cloned()\n                .collect(),\n                ..Default::default()\n            },\n        );\n        // test value-less keys\n        t(\n            \"foo=,bar=baz,baz=\",\n            ToolVersionOptions {\n                opts: [\n                    (\"foo\".to_string(), s(\"\")),\n                    (\"bar\".to_string(), s(\"baz\")),\n                    (\"baz\".to_string(), s(\"\")),\n                ]\n                .iter()\n                .cloned()\n                .collect(),\n                ..Default::default()\n            },\n        );\n    }\n\n    #[test]\n    fn test_parse_tool_options_with_nested_braces() {\n        let input = r#\"platforms={ linux-x64 = { url = \"https://example.com/linux.tar.gz\" }, macos-arm64 = { url = \"https://example.com/macos.tar.gz\" } }\"#;\n        let opts = parse_tool_options(input);\n        assert_eq!(opts.opts.len(), 1, \"should have exactly one key\");\n        assert!(opts.opts.get(\"platforms\").unwrap().is_table());\n\n        assert_eq!(\n            opts.get_nested_string(\"platforms.linux-x64.url\"),\n            Some(\"https://example.com/linux.tar.gz\".to_string())\n        );\n        assert_eq!(\n            opts.get_nested_string(\"platforms.macos-arm64.url\"),\n            Some(\"https://example.com/macos.tar.gz\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_parse_tool_options_mixed_braces_and_simple() {\n        let input = r#\"bin_path=\"bin\",platforms={ linux-x64 = { url = \"https://example.com/linux.tar.gz\" } },strip_components=\"1\"\"#;\n        let opts = parse_tool_options(input);\n        assert_eq!(opts.get(\"bin_path\"), Some(\"bin\"));\n        assert_eq!(opts.get(\"strip_components\"), Some(\"1\"));\n        assert!(opts.opts.get(\"platforms\").is_some());\n    }\n\n    #[test]\n    fn test_parse_tool_options_integer_strip_components() {\n        // strip_components=1 (integer, not string) should be converted to string\n        let input = r#\"bin_path=\"bin\",strip_components=1\"#;\n        let opts = parse_tool_options(input);\n        assert_eq!(opts.get(\"bin_path\"), Some(\"bin\"));\n        assert_eq!(opts.get(\"strip_components\"), Some(\"1\"));\n    }\n\n    #[test]\n    fn test_nested_option_with_os_arch_dash() {\n        let mut opts = IndexMap::new();\n        let mut platforms = toml::map::Map::new();\n        let mut macos = toml::map::Map::new();\n        macos.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x64.tar.gz\".to_string()),\n        );\n        macos.insert(\n            \"checksum\".to_string(),\n            toml::Value::String(\"sha256:abc123\".to_string()),\n        );\n        platforms.insert(\"macos-x64\".to_string(), toml::Value::Table(macos));\n\n        let mut linux = toml::map::Map::new();\n        linux.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/linux-x64.tar.gz\".to_string()),\n        );\n        linux.insert(\n            \"checksum\".to_string(),\n            toml::Value::String(\"sha256:def456\".to_string()),\n        );\n        platforms.insert(\"linux-x64\".to_string(), toml::Value::Table(linux));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.macos-x64.url\"),\n            Some(\"https://example.com/macos-x64.tar.gz\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.macos-x64.checksum\"),\n            Some(\"sha256:abc123\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.linux-x64.url\"),\n            Some(\"https://example.com/linux-x64.tar.gz\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.linux-x64.checksum\"),\n            Some(\"sha256:def456\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_generic_nested_options() {\n        let mut opts = IndexMap::new();\n        let mut config = toml::map::Map::new();\n        let mut database = toml::map::Map::new();\n        database.insert(\n            \"host\".to_string(),\n            toml::Value::String(\"localhost\".to_string()),\n        );\n        database.insert(\"port\".to_string(), toml::Value::Integer(5432));\n        config.insert(\"database\".to_string(), toml::Value::Table(database));\n\n        let mut cache = toml::map::Map::new();\n        let mut redis = toml::map::Map::new();\n        redis.insert(\n            \"host\".to_string(),\n            toml::Value::String(\"redis.example.com\".to_string()),\n        );\n        redis.insert(\"port\".to_string(), toml::Value::Integer(6379));\n        cache.insert(\"redis\".to_string(), toml::Value::Table(redis));\n        config.insert(\"cache\".to_string(), toml::Value::Table(cache));\n\n        opts.insert(\"config\".to_string(), toml::Value::Table(config));\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert_eq!(\n            tool_opts.get_nested_string(\"config.database.host\"),\n            Some(\"localhost\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"config.database.port\"),\n            Some(\"5432\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"config.cache.redis.host\"),\n            Some(\"redis.example.com\".to_string())\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"config.cache.redis.port\"),\n            Some(\"6379\".to_string())\n        );\n    }\n\n    #[test]\n    fn test_direct_and_nested_options() {\n        let mut opts = IndexMap::new();\n        let mut platforms = toml::map::Map::new();\n        let mut macos = toml::map::Map::new();\n        macos.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x64.tar.gz\".to_string()),\n        );\n        platforms.insert(\"macos-x64\".to_string(), toml::Value::Table(macos));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n        opts.insert(\n            \"simple_option\".to_string(),\n            toml::Value::String(\"value\".to_string()),\n        );\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.macos-x64.url\"),\n            Some(\"https://example.com/macos-x64.tar.gz\".to_string())\n        );\n        assert_eq!(tool_opts.get(\"simple_option\"), Some(\"value\"));\n    }\n\n    #[test]\n    fn test_contains_key_with_nested_options() {\n        let mut opts = IndexMap::new();\n        let mut platforms = toml::map::Map::new();\n        let mut macos = toml::map::Map::new();\n        macos.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x64.tar.gz\".to_string()),\n        );\n        platforms.insert(\"macos-x64\".to_string(), toml::Value::Table(macos));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert!(tool_opts.contains_key(\"platforms.macos-x64.url\"));\n        assert!(!tool_opts.contains_key(\"platforms.linux-x64.url\"));\n        assert!(!tool_opts.contains_key(\"nonexistent\"));\n    }\n\n    #[test]\n    fn test_merge_functionality() {\n        let mut opts = IndexMap::new();\n        let mut platforms = toml::map::Map::new();\n        let mut macos = toml::map::Map::new();\n        macos.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x64.tar.gz\".to_string()),\n        );\n        platforms.insert(\"macos-x64\".to_string(), toml::Value::Table(macos));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n\n        let mut tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert!(tool_opts.contains_key(\"platforms.macos-x64.url\"));\n\n        let mut new_opts = IndexMap::new();\n        new_opts.insert(\n            \"simple_option\".to_string(),\n            toml::Value::String(\"value\".to_string()),\n        );\n        tool_opts.merge(&new_opts);\n\n        assert!(tool_opts.contains_key(\"platforms.macos-x64.url\"));\n        assert!(tool_opts.contains_key(\"simple_option\"));\n    }\n\n    #[test]\n    fn test_non_existent_nested_paths() {\n        let mut opts = IndexMap::new();\n        let mut platforms = toml::map::Map::new();\n        let mut macos = toml::map::Map::new();\n        macos.insert(\n            \"url\".to_string(),\n            toml::Value::String(\"https://example.com/macos-x64.tar.gz\".to_string()),\n        );\n        platforms.insert(\"macos-x64\".to_string(), toml::Value::Table(macos));\n        opts.insert(\"platforms\".to_string(), toml::Value::Table(platforms));\n\n        let tool_opts = ToolVersionOptions {\n            opts,\n            ..Default::default()\n        };\n\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.windows-x64.url\"),\n            None\n        );\n        assert_eq!(\n            tool_opts.get_nested_string(\"platforms.macos-x64.checksum\"),\n            None\n        );\n        assert_eq!(tool_opts.get_nested_string(\"config.database.host\"), None);\n    }\n\n    #[test]\n    fn test_indexmap_preserves_order() {\n        let mut tvo = ToolVersionOptions::default();\n\n        tvo.opts.insert(\"zebra\".to_string(), s(\"last\"));\n        tvo.opts.insert(\"alpha\".to_string(), s(\"first\"));\n        tvo.opts.insert(\"beta\".to_string(), s(\"second\"));\n\n        let keys: Vec<_> = tvo.opts.keys().collect();\n        assert_eq!(keys, vec![\"zebra\", \"alpha\", \"beta\"]);\n    }\n}\n"
  },
  {
    "path": "src/toolset/toolset_env.rs",
    "content": "use std::collections::BTreeMap;\nuse std::path::PathBuf;\nuse std::sync::Arc;\nuse std::time::SystemTime;\n\nuse eyre::Result;\n\nuse crate::config::env_directive::{EnvResolveOptions, EnvResults, ToolsFilter};\nuse crate::config::{Config, Settings};\nuse crate::env::{PATH_KEY, WARN_ON_MISSING_REQUIRED_ENV};\nuse crate::env_diff::EnvMap;\nuse crate::path_env::PathEnv;\nuse crate::toolset::Toolset;\nuse crate::toolset::env_cache::{CachedEnv, compute_settings_hash, get_file_mtime};\nuse crate::toolset::tool_request::ToolRequest;\nuse crate::{env, parallel, uv};\n\nimpl Toolset {\n    pub async fn full_env(&self, config: &Arc<Config>) -> Result<EnvMap> {\n        let mut env = env::PRISTINE_ENV.clone().into_iter().collect::<EnvMap>();\n        env.extend(self.env_with_path(config).await?.clone());\n        Ok(env)\n    }\n\n    /// Like full_env but skips `tools=true` env directives (load_post_env).\n    /// Used for preinstall hooks where tool-dependent env vars aren't available yet.\n    pub async fn full_env_without_tools(&self, config: &Arc<Config>) -> Result<EnvMap> {\n        let mut env = env::PRISTINE_ENV.clone().into_iter().collect::<EnvMap>();\n        env.extend(self.env_with_path_without_tools(config).await?);\n        Ok(env)\n    }\n\n    /// Like env_with_path but skips `tools=true` env directives.\n    /// Used during tool installation where tool-dependent env vars\n    /// may reference tools that aren't installed yet.\n    pub async fn env_with_path_without_tools(&self, config: &Arc<Config>) -> Result<EnvMap> {\n        let (mut env, add_paths) = self.env(config).await?;\n        let mut path_env = PathEnv::from_iter(env::PATH.clone());\n        for p in config.path_dirs().await?.clone() {\n            path_env.add(p);\n        }\n        for p in &add_paths {\n            path_env.add(p.clone());\n        }\n        for p in self.list_paths(config).await {\n            path_env.add(p);\n        }\n        env.insert(PATH_KEY.to_string(), path_env.to_string());\n        Ok(env)\n    }\n\n    /// the full mise environment including all tool paths\n    pub async fn env_with_path(&self, config: &Arc<Config>) -> Result<EnvMap> {\n        // Try to load from cache if enabled\n        if CachedEnv::is_enabled()\n            && let Some(cached) = self.try_load_env_cache(config)?\n        {\n            trace!(\"env_cache: using cached environment\");\n            return Ok(cached);\n        }\n\n        let (mut env, env_results) = self.final_env(config).await?;\n        let mut path_env = PathEnv::from_iter(env::PATH.clone());\n        // Use split paths so we save a cache compatible with env_with_path_and_split\n        let (user_paths, tool_paths) = self\n            .list_final_paths_split(config, env_results.clone())\n            .await?;\n        for p in user_paths.iter().chain(tool_paths.iter()) {\n            path_env.add(p.clone());\n        }\n        env.insert(PATH_KEY.to_string(), path_env.to_string());\n\n        // Save to cache if enabled and no uncacheable directives\n        // Use save_env_cache_split to ensure cache is compatible with env_with_path_and_split\n        if CachedEnv::is_enabled()\n            && !env_results.has_uncacheable\n            && let Err(e) =\n                self.save_env_cache_split(config, &env, &user_paths, &tool_paths, &env_results)\n        {\n            debug!(\"env_cache: failed to save: {}\", e);\n        }\n\n        Ok(env)\n    }\n\n    /// Get environment with split paths (user_paths and tool_paths separate)\n    /// This method uses the env cache when available and returns paths separately\n    /// for proper handling in hook_env.\n    pub async fn env_with_path_and_split(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<(EnvMap, Vec<PathBuf>, Vec<PathBuf>)> {\n        // Try to load from cache if enabled\n        if CachedEnv::is_enabled()\n            && let Some(cached) = self.try_load_env_cache_full(config)?\n        {\n            trace!(\"env_cache: using cached environment with split paths\");\n            let mut env = cached.env;\n            // Reconstruct PATH from cached paths\n            let mut path_env = PathEnv::from_iter(env::PATH.clone());\n            for p in cached.user_paths.iter().chain(cached.tool_paths.iter()) {\n                path_env.add(p.clone());\n            }\n            env.insert(PATH_KEY.to_string(), path_env.to_string());\n            return Ok((env, cached.user_paths, cached.tool_paths));\n        }\n\n        // Compute fresh\n        let (mut env, env_results) = self.final_env(config).await?;\n        let (user_paths, tool_paths) = self\n            .list_final_paths_split(config, env_results.clone())\n            .await?;\n\n        // Build PATH\n        let mut path_env = PathEnv::from_iter(env::PATH.clone());\n        for p in user_paths.iter().chain(tool_paths.iter()) {\n            path_env.add(p.clone());\n        }\n        env.insert(PATH_KEY.to_string(), path_env.to_string());\n\n        // Save to cache if enabled and no uncacheable directives\n        if CachedEnv::is_enabled()\n            && !env_results.has_uncacheable\n            && let Err(e) =\n                self.save_env_cache_split(config, &env, &user_paths, &tool_paths, &env_results)\n        {\n            debug!(\"env_cache: failed to save: {}\", e);\n        }\n\n        Ok((env, user_paths, tool_paths))\n    }\n\n    /// Try to load environment from cache (returns full CachedEnv)\n    pub(crate) fn try_load_env_cache_full(\n        &self,\n        config: &Arc<Config>,\n    ) -> Result<Option<CachedEnv>> {\n        let cache_key = self.compute_env_cache_key(config)?;\n        CachedEnv::load(&cache_key)\n    }\n\n    /// Try to load environment from cache (returns reconstructed EnvMap)\n    fn try_load_env_cache(&self, config: &Arc<Config>) -> Result<Option<EnvMap>> {\n        match self.try_load_env_cache_full(config)? {\n            Some(cached) => {\n                let mut env = cached.env;\n                // Reconstruct PATH from cached paths\n                let mut path_env = PathEnv::from_iter(env::PATH.clone());\n                for p in cached.user_paths.into_iter().chain(cached.tool_paths) {\n                    path_env.add(p);\n                }\n                env.insert(PATH_KEY.to_string(), path_env.to_string());\n                Ok(Some(env))\n            }\n            None => Ok(None),\n        }\n    }\n\n    /// Save environment to cache with split paths\n    fn save_env_cache_split(\n        &self,\n        config: &Arc<Config>,\n        env: &EnvMap,\n        user_paths: &[PathBuf],\n        tool_paths: &[PathBuf],\n        env_results: &EnvResults,\n    ) -> Result<()> {\n        let cache_key = self.compute_env_cache_key(config)?;\n        let now = SystemTime::now()\n            .duration_since(SystemTime::UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_secs();\n\n        // Collect all files to watch (config files + module watch_files + env_files)\n        let mut watch_files: Vec<PathBuf> = config.config_files.keys().cloned().collect();\n        watch_files.extend(env_results.watch_files.clone());\n        watch_files.extend(env_results.env_files.clone());\n        watch_files.extend(env_results.env_scripts.clone());\n\n        // Add mise.lock files to watch_files\n        for p in config.config_files.keys() {\n            if let Some(parent) = p.parent() {\n                watch_files.push(parent.join(\"mise.lock\"));\n            }\n        }\n\n        // Get mtimes for watch files\n        let watch_file_mtimes: Vec<u64> = watch_files\n            .iter()\n            .map(|p| get_file_mtime(p).unwrap_or(0))\n            .collect();\n\n        // Remove PATH from env before caching (we store paths separately)\n        let env_without_path: BTreeMap<String, String> = env\n            .iter()\n            .filter(|(k, _)| k.as_str() != PATH_KEY.as_str())\n            .map(|(k, v)| (k.clone(), v.clone()))\n            .collect();\n\n        let cached = CachedEnv {\n            env: env_without_path,\n            user_paths: user_paths.to_vec(),\n            tool_paths: tool_paths.to_vec(),\n            created_at: now,\n            watch_files,\n            watch_file_mtimes,\n            mise_version: env!(\"CARGO_PKG_VERSION\").to_string(),\n            cache_key_debug: cache_key.clone(),\n        };\n\n        cached.save(&cache_key)\n    }\n\n    /// Compute the cache key for the current configuration\n    fn compute_env_cache_key(&self, config: &Arc<Config>) -> Result<String> {\n        // Collect config files with their mtimes\n        let config_files: Vec<(PathBuf, u64)> = config\n            .config_files\n            .keys()\n            .map(|p| (p.clone(), get_file_mtime(p).unwrap_or(0)))\n            .collect();\n\n        // Collect tool versions\n        let tool_versions: Vec<(String, String)> = self\n            .list_current_versions()\n            .into_iter()\n            .map(|(b, tv)| (b.id().to_string(), tv.version.clone()))\n            .collect();\n\n        // Get settings hash\n        let settings_hash = compute_settings_hash();\n\n        // Get base PATH using platform-appropriate separator\n        let base_path = std::env::join_paths(env::PATH.iter())\n            .map(|p| p.to_string_lossy().to_string())\n            .unwrap_or_default();\n\n        Ok(CachedEnv::compute_cache_key(\n            &config_files,\n            &tool_versions,\n            &settings_hash,\n            &base_path,\n        ))\n    }\n\n    pub async fn env_from_tools(&self, config: &Arc<Config>) -> Vec<(String, String, String)> {\n        let this = Arc::new(self.clone());\n        let items: Vec<_> = self\n            .list_current_installed_versions(config)\n            .into_iter()\n            .filter(|(_, tv)| !matches!(tv.request, ToolRequest::System { .. }))\n            .map(|(b, tv)| (config.clone(), this.clone(), b, tv))\n            .collect();\n\n        let envs = parallel::parallel(items, |(config, this, b, tv)| async move {\n            let backend_id = b.id().to_string();\n            match b.exec_env(&config, &this, &tv).await {\n                Ok(env) => Ok(env\n                    .into_iter()\n                    .map(|(k, v)| (k, v, backend_id.clone()))\n                    .collect::<Vec<_>>()),\n                Err(e) => {\n                    warn!(\"Error running exec-env: {:#}\", e);\n                    Ok(Vec::new())\n                }\n            }\n        })\n        .await\n        .unwrap_or_default();\n\n        envs.into_iter()\n            .flatten()\n            .filter(|(k, _, _)| k.to_uppercase() != \"PATH\")\n            .collect()\n    }\n\n    pub async fn env(&self, config: &Arc<Config>) -> Result<(EnvMap, Vec<PathBuf>)> {\n        time!(\"env start\");\n        let entries = self\n            .env_from_tools(config)\n            .await\n            .into_iter()\n            .map(|(k, v, _)| (k, v))\n            .collect::<Vec<(String, String)>>();\n\n        // Collect and process MISE_ADD_PATH values into paths\n        let paths_to_add: Vec<PathBuf> = entries\n            .iter()\n            .filter(|(k, _)| k == \"MISE_ADD_PATH\" || k == \"RTX_ADD_PATH\")\n            .flat_map(|(_, v)| env::split_paths(v))\n            .collect();\n\n        let mut env: EnvMap = entries\n            .into_iter()\n            .filter(|(k, _)| k != \"RTX_ADD_PATH\")\n            .filter(|(k, _)| k != \"MISE_ADD_PATH\")\n            .filter(|(k, _)| !k.starts_with(\"RTX_TOOL_OPTS__\"))\n            .filter(|(k, _)| !k.starts_with(\"MISE_TOOL_OPTS__\"))\n            .rev()\n            .collect();\n\n        env.extend(config.env().await?.clone());\n        if let Some(venv) = uv::uv_venv(config, self).await {\n            for (k, v) in venv.env.clone() {\n                env.insert(k, v);\n            }\n        }\n        time!(\"env end\");\n        Ok((env, paths_to_add))\n    }\n\n    pub async fn final_env(&self, config: &Arc<Config>) -> Result<(EnvMap, EnvResults)> {\n        let (mut env, add_paths) = self.env(config).await?;\n        let mut tera_env = env::PRISTINE_ENV.clone().into_iter().collect::<EnvMap>();\n        tera_env.extend(env.clone());\n        let mut path_env = PathEnv::from_iter(env::PATH.clone());\n\n        for p in config.path_dirs().await?.clone() {\n            path_env.add(p);\n        }\n        for p in &add_paths {\n            path_env.add(p.clone());\n        }\n        for p in self.list_paths(config).await {\n            path_env.add(p);\n        }\n        tera_env.insert(PATH_KEY.to_string(), path_env.to_string());\n        let mut ctx = config.tera_ctx.clone();\n        ctx.insert(\"env\", &tera_env);\n        ctx.insert(\"tools\", &self.build_tools_tera_map(config));\n        let mut env_results = self.load_post_env(config, ctx, &tera_env).await?;\n\n        // Store add_paths separately to maintain consistent PATH ordering\n        env_results.tool_add_paths = add_paths;\n\n        env.extend(\n            env_results\n                .env\n                .iter()\n                .map(|(k, v)| (k.clone(), v.0.clone())),\n        );\n\n        // Apply redactions from tools-only env vars (e.g. redact=true + tools=true)\n        if !env_results.redactions.is_empty() {\n            config.add_redactions(env_results.redactions.iter().cloned(), &env);\n        }\n\n        Ok((env, env_results))\n    }\n\n    pub(super) async fn load_post_env(\n        &self,\n        config: &Arc<Config>,\n        ctx: tera::Context,\n        env: &EnvMap,\n    ) -> Result<EnvResults> {\n        if Settings::no_env() || Settings::get().no_env.unwrap_or(false) {\n            return Ok(EnvResults::default());\n        }\n        let entries = config\n            .config_files\n            .iter()\n            .rev()\n            .map(|(source, cf)| {\n                cf.env_entries()\n                    .map(|ee| ee.into_iter().map(|e| (e, source.clone())))\n            })\n            .collect::<Result<Vec<_>>>()?\n            .into_iter()\n            .flatten()\n            .collect();\n        // trace!(\"load_env: entries: {:#?}\", entries);\n        let env_results = EnvResults::resolve(\n            config,\n            ctx,\n            env,\n            entries,\n            EnvResolveOptions {\n                vars: false,\n                tools: ToolsFilter::ToolsOnly,\n                warn_on_missing_required: *WARN_ON_MISSING_REQUIRED_ENV,\n            },\n        )\n        .await?;\n        if log::log_enabled!(log::Level::Trace) {\n            trace!(\"{env_results:#?}\");\n        } else if !env_results.is_empty() {\n            debug!(\"{env_results:?}\");\n        }\n        Ok(env_results)\n    }\n}\n"
  },
  {
    "path": "src/toolset/toolset_install.rs",
    "content": "use std::collections::{HashMap, HashSet};\nuse std::sync::Arc;\n\nuse eyre::Result;\nuse indexmap::IndexSet;\nuse itertools::Itertools;\nuse tokio::sync::{Mutex, Semaphore};\nuse tokio::task::JoinSet;\n\nuse crate::config::Config;\nuse crate::config::settings::Settings;\nuse crate::errors::Error;\nuse crate::hooks::{Hooks, InstalledToolInfo};\nuse crate::install_context::InstallContext;\nuse crate::plugins::PluginType;\nuse crate::toolset::Toolset;\nuse crate::toolset::helpers::show_python_install_hint;\nuse crate::toolset::install_options::InstallOptions;\nuse crate::toolset::tool_deps::ToolDeps;\nuse crate::toolset::tool_request::ToolRequest;\nuse crate::toolset::tool_source::ToolSource;\nuse crate::toolset::tool_version::ToolVersion;\nuse crate::ui::multi_progress_report::MultiProgressReport;\nuse crate::{config, hooks};\n\nimpl Toolset {\n    #[async_backtrace::framed]\n    /// Installs missing tool versions and returns (installed_versions, still_missing_versions).\n    /// This avoids callers needing to re-compute the missing versions list.\n    pub async fn install_missing_versions(\n        &mut self,\n        config: &mut Arc<Config>,\n        opts: &InstallOptions,\n    ) -> Result<(Vec<ToolVersion>, Vec<ToolVersion>)> {\n        let missing = self.list_missing_versions(config).await;\n\n        // If auto-install is explicitly disabled, skip installation but return what's missing\n        if opts.skip_auto_install {\n            return Ok((vec![], missing));\n        }\n\n        let mut versions = missing\n            .iter()\n            .filter(|tv| {\n                !opts.missing_args_only\n                    || matches!(self.versions[tv.ba()].source, ToolSource::Argument)\n            })\n            .filter(|tv| {\n                if let Some(tools) = &opts.auto_install_disable_tools {\n                    !tools.contains(&tv.ba().short)\n                } else {\n                    true\n                }\n            })\n            .map(|tv| tv.request.clone())\n            .collect_vec();\n        // Ensure options from toolset are preserved during auto-install\n        self.init_request_options(&mut versions);\n        let installed = self.install_all_versions(config, versions, opts).await?;\n        if !installed.is_empty() {\n            let ts = config.get_toolset().await?;\n            config::rebuild_shims_and_runtime_symlinks(config, ts, &installed).await?;\n            // Re-check what's still missing after installation\n            let still_missing = self.list_missing_versions(config).await;\n            return Ok((installed, still_missing));\n        }\n        // Nothing was installed, the missing list is unchanged\n        Ok((installed, missing))\n    }\n\n    /// sets the options on incoming requests to install to whatever is already in the toolset\n    /// this handles the use-case where you run `mise use ubi:cilium/cilium-cli` (without CLi options)\n    /// but this tool has options inside mise.toml\n    pub(super) fn init_request_options(&self, requests: &mut Vec<ToolRequest>) {\n        for tr in requests {\n            if let Some(tvl) = self.versions.get(tr.ba()) {\n                if tvl.requests.len() != 1 {\n                    // TODO: handle this case with multiple versions\n                    continue;\n                }\n                // Use config request options if available, falling back to backend arg opts.\n                // This ensures tool options like postinstall from mise.toml are preserved\n                // when installing with an explicit CLI version (e.g. `mise install tool@latest`).\n                let options = tvl\n                    .requests\n                    .first()\n                    .map(|r| r.options())\n                    .filter(|opts| !opts.is_empty())\n                    .unwrap_or_else(|| tvl.backend.opts());\n                if tr.options().is_empty() || tr.options() != options {\n                    tr.set_options(options);\n                }\n            }\n        }\n    }\n\n    #[async_backtrace::framed]\n    pub async fn install_all_versions(\n        &mut self,\n        config: &mut Arc<Config>,\n        mut versions: Vec<ToolRequest>,\n        opts: &InstallOptions,\n    ) -> Result<Vec<ToolVersion>> {\n        // Install all plugins from [plugins] config section first\n        // This must happen before the empty check so plugins are installed\n        // even when there are no tools to install (e.g., env-only plugins)\n        Self::ensure_config_plugins_installed(config, opts.dry_run).await?;\n\n        if versions.is_empty() {\n            return Ok(vec![]);\n        }\n\n        // Initialize a footer for the entire install session once (before batching)\n        let mpr = MultiProgressReport::get();\n        let footer_reason = if opts.dry_run {\n            format!(\"{} (dry-run)\", opts.reason)\n        } else {\n            opts.reason.clone()\n        };\n        mpr.init_footer(opts.dry_run, &footer_reason, versions.len());\n\n        // Skip hooks in dry-run mode\n        if !opts.dry_run {\n            // Run pre-install hook\n            hooks::run_one_hook(config, self, Hooks::Preinstall, None).await;\n        }\n\n        self.init_request_options(&mut versions);\n        show_python_install_hint(&versions);\n\n        // Ensure plugins are installed before building dependency graph\n        let plugin_errors = self.ensure_plugins_installed(config, &versions, opts).await;\n\n        // Filter out tools with plugin errors\n        let tools_with_plugin_errors: HashSet<_> =\n            plugin_errors.iter().map(|(tr, _)| tr.clone()).collect();\n        let versions_to_install: Vec<_> = versions\n            .into_iter()\n            .filter(|tr| !tools_with_plugin_errors.contains(tr))\n            .collect();\n\n        // Build dependency graph and install using Kahn's algorithm\n        let (installed, failed) = self\n            .install_with_deps(config, versions_to_install, opts)\n            .await;\n\n        // Update footer for plugin errors\n        let plugin_error_count = plugin_errors.len();\n        if plugin_error_count > 0 {\n            mpr.footer_inc(plugin_error_count);\n        }\n\n        // Combine plugin errors with installation failures\n        let mut all_failed = plugin_errors;\n        all_failed.extend(failed);\n\n        // Skip config reload and resolve in dry-run mode\n        if !opts.dry_run {\n            // Reload config and resolve (ignoring errors like the original does)\n            trace!(\"install: reloading config\");\n            *config = Config::reset().await?;\n            trace!(\"install: resolving\");\n            if let Err(err) = self.resolve(config).await {\n                debug!(\"error resolving versions after install: {err:#}\");\n            }\n        }\n\n        // Debug logging for successful installations\n        if log::log_enabled!(log::Level::Debug) {\n            for tv in installed.iter() {\n                let backend = tv.backend()?;\n                let bin_paths = backend\n                    .list_bin_paths(config, tv)\n                    .await\n                    .map_err(|e| {\n                        warn!(\"Error listing bin paths for {tv}: {e:#}\");\n                    })\n                    .unwrap_or_default();\n                debug!(\"[{tv}] list_bin_paths: {bin_paths:?}\");\n                let env = backend\n                    .exec_env(config, self, tv)\n                    .await\n                    .map_err(|e| {\n                        warn!(\"Error running exec-env: {e:#}\");\n                    })\n                    .unwrap_or_default();\n                if !env.is_empty() {\n                    debug!(\"[{tv}] exec_env: {env:?}\");\n                }\n            }\n        }\n\n        // Finish the global footer before running hooks so output isn't masked\n        if !opts.dry_run {\n            mpr.footer_finish();\n        }\n\n        // Skip hooks in dry-run mode\n        if !opts.dry_run {\n            // Run post-install hook with installed tools info\n            // Use the full resolved toolset so all installed tools are on PATH\n            // Fall back to self if toolset resolution fails (e.g. due to config issues)\n            let installed_tools: Vec<InstalledToolInfo> =\n                installed.iter().map(InstalledToolInfo::from).collect();\n            let ts = match config.get_toolset().await {\n                Ok(ts) => ts,\n                Err(e) => {\n                    debug!(\"error resolving toolset for postinstall hook: {e:#}\");\n                    self\n                }\n            };\n            hooks::run_one_hook_with_context(\n                config,\n                ts,\n                Hooks::Postinstall,\n                None,\n                Some(&installed_tools),\n            )\n            .await;\n        }\n\n        // Return appropriate result\n        if all_failed.is_empty() {\n            Ok(installed)\n        } else {\n            Err(Error::InstallFailed {\n                successful_installations: installed,\n                failed_installations: all_failed,\n            }\n            .into())\n        }\n    }\n\n    /// Ensure all plugins for the requested tools are installed\n    async fn ensure_plugins_installed(\n        &self,\n        config: &Arc<Config>,\n        versions: &[ToolRequest],\n        opts: &InstallOptions,\n    ) -> Vec<(ToolRequest, eyre::Error)> {\n        let mut plugin_errors = Vec::new();\n        let mut checked_backends = HashSet::new();\n\n        for tr in versions {\n            let ba = tr.ba();\n            if checked_backends.contains(ba) {\n                continue;\n            }\n            checked_backends.insert(ba.clone());\n\n            if let Ok(backend) = tr.backend()\n                && let Some(plugin) = backend.plugin()\n                && !plugin.is_installed()\n            {\n                let mpr = MultiProgressReport::get();\n                if let Err(e) = plugin\n                    .ensure_installed(config, &mpr, false, opts.dry_run)\n                    .await\n                    .or_else(|err| {\n                        if let Some(&Error::PluginNotInstalled(_)) = err.downcast_ref::<Error>() {\n                            Ok(())\n                        } else {\n                            Err(err)\n                        }\n                    })\n                {\n                    // Collect errors for all tools using this plugin\n                    for tr2 in versions {\n                        if tr2.ba() == ba {\n                            plugin_errors.push((\n                                tr2.clone(),\n                                eyre::eyre!(\"Plugin '{}' installation failed: {}\", ba.short, e),\n                            ));\n                        }\n                    }\n                }\n            }\n        }\n\n        plugin_errors\n    }\n\n    /// Install tools using Kahn's algorithm for dependency ordering.\n    /// Returns (successful_installations, failed_installations).\n    async fn install_with_deps(\n        &self,\n        config: &Arc<Config>,\n        versions: Vec<ToolRequest>,\n        opts: &InstallOptions,\n    ) -> (Vec<ToolVersion>, Vec<(ToolRequest, eyre::Error)>) {\n        if versions.is_empty() {\n            return (vec![], vec![]);\n        }\n\n        // Build index map to preserve original request order\n        let request_order: HashMap<String, usize> = versions\n            .iter()\n            .enumerate()\n            .map(|(i, tr)| (format!(\"{}@{}\", tr.ba().full(), tr.version()), i))\n            .collect();\n\n        // Build dependency graph\n        let tool_deps = match ToolDeps::new(versions.clone()) {\n            Ok(deps) => Arc::new(Mutex::new(deps)),\n            Err(e) => {\n                // If we can't build the graph, return error for all versions\n                let failed: Vec<_> = versions\n                    .into_iter()\n                    .map(|tr| (tr, eyre::eyre!(\"Failed to build dependency graph: {}\", e)))\n                    .collect();\n                return (vec![], failed);\n            }\n        };\n\n        let mut rx = tool_deps.lock().await.subscribe();\n\n        let raw = opts.raw || Settings::get().raw;\n        let jobs = match raw {\n            true => 1,\n            false => opts.jobs.unwrap_or(Settings::get().jobs),\n        };\n        let semaphore = Arc::new(Semaphore::new(jobs));\n        let ts = Arc::new(self.clone());\n        let opts = Arc::new(opts.clone());\n\n        let mut installed = vec![];\n        let mut failed = vec![];\n        let mut jset: JoinSet<(ToolRequest, Result<ToolVersion>)> = JoinSet::new();\n        // Track in-flight tools to recover from task panics\n        let mut in_flight: HashMap<tokio::task::Id, ToolRequest> = HashMap::new();\n\n        loop {\n            tokio::select! {\n                // Use `biased` to ensure completed installations are handled before starting new ones.\n                // This priority ordering ensures dependency tracking stays correct: we must process\n                // completions (which may unblock dependents) before spawning new installations.\n                biased;\n\n                // Handle completed installations first (higher priority)\n                Some(result) = jset.join_next() => {\n                    let mpr = MultiProgressReport::get();\n                    match result {\n                        Ok((tr, Ok(tv))) => {\n                            mpr.footer_inc(1);\n                            installed.push(tv);\n                            tool_deps.lock().await.complete_success(&tr);\n                        }\n                        Ok((tr, Err(e))) => {\n                            mpr.footer_inc(1);\n                            failed.push((tr.clone(), e));\n                            tool_deps.lock().await.complete_failure(&tr);\n                        }\n                        Err(e) => {\n                            // Task panicked - try to recover the tool request from in_flight tracking\n                            mpr.footer_inc(1);\n                            if let Some(tr) = in_flight.remove(&e.id()) {\n                                failed.push((tr.clone(), eyre::eyre!(\"Installation task panicked: {e:#}\")));\n                                tool_deps.lock().await.complete_failure(&tr);\n                            } else {\n                                warn!(\"Task panicked but tool request not found: {e:#}\");\n                            }\n                        }\n                    }\n                }\n\n                // Receive new tools to install\n                Some(maybe_tr) = rx.recv() => {\n                    match maybe_tr {\n                        Some(tr) => {\n                            // Spawn installation task\n                            let permit = match semaphore.clone().acquire_owned().await {\n                                Ok(p) => p,\n                                Err(e) => {\n                                    // Mark as failed and notify tool_deps so dependents are blocked\n                                    MultiProgressReport::get().footer_inc(1);\n                                    failed.push((tr.clone(), eyre::eyre!(\"Failed to acquire semaphore: {}\", e)));\n                                    tool_deps.lock().await.complete_failure(&tr);\n                                    continue;\n                                }\n                            };\n\n                            let config = config.clone();\n                            let ts = ts.clone();\n                            let opts = opts.clone();\n                            let tr_clone = tr.clone();\n\n                            let handle = jset.spawn(async move {\n                                let _permit = permit;\n                                let result = Self::install_single_tool(&config, &ts, &tr, &opts).await;\n                                (tr, result)\n                            });\n                            in_flight.insert(handle.id(), tr_clone);\n                        }\n                        None => {\n                            // All tools have been emitted, wait for remaining tasks\n                            break;\n                        }\n                    }\n                }\n\n                else => break,\n            }\n        }\n\n        // Wait for all remaining tasks to complete\n        while let Some(result) = jset.join_next().await {\n            let mpr = MultiProgressReport::get();\n            match result {\n                Ok((tr, Ok(tv))) => {\n                    mpr.footer_inc(1);\n                    installed.push(tv);\n                    tool_deps.lock().await.complete_success(&tr);\n                }\n                Ok((tr, Err(e))) => {\n                    mpr.footer_inc(1);\n                    failed.push((tr.clone(), e));\n                    tool_deps.lock().await.complete_failure(&tr);\n                }\n                Err(e) => {\n                    mpr.footer_inc(1);\n                    if let Some(tr) = in_flight.remove(&e.id()) {\n                        failed.push((tr.clone(), eyre::eyre!(\"Installation task panicked: {e:#}\")));\n                        tool_deps.lock().await.complete_failure(&tr);\n                    } else {\n                        warn!(\"Task panicked but tool request not found: {e:#}\");\n                    }\n                }\n            }\n        }\n\n        // Add blocked tools to failures\n        let blocked = tool_deps.lock().await.blocked_tools();\n        for tr in blocked {\n            failed.push((tr.clone(), eyre::eyre!(\"Skipped due to failed dependency\")));\n            MultiProgressReport::get().footer_inc(1);\n        }\n\n        // Sort installed versions by original request order to preserve user's intended ordering\n        installed.sort_by_key(|tv| {\n            let key = format!(\"{}@{}\", tv.ba().full(), tv.request.version());\n            request_order.get(&key).copied().unwrap_or(usize::MAX)\n        });\n\n        (installed, failed)\n    }\n\n    /// Install a single tool\n    async fn install_single_tool(\n        config: &Arc<Config>,\n        ts: &Arc<Toolset>,\n        tr: &ToolRequest,\n        opts: &Arc<InstallOptions>,\n    ) -> Result<ToolVersion> {\n        let mpr = MultiProgressReport::get();\n\n        let mut tv = tr.resolve(config, &opts.resolve_options).await?;\n        if let Some(dir) = &opts.install_dir {\n            let tool_dir_name = tv.ba().tool_dir_name();\n            tv.install_path = Some(dir.join(tool_dir_name).join(tv.tv_pathname()));\n        }\n        let backend = tr.backend()?;\n\n        let ctx = InstallContext {\n            config: config.clone(),\n            ts: ts.clone(),\n            pr: mpr.add_with_options(&tv.style(), opts.dry_run),\n            force: opts.force,\n            dry_run: opts.dry_run,\n            locked: opts.locked,\n        };\n\n        backend.install_version(ctx, tv).await\n    }\n\n    pub async fn install_missing_bin(\n        &mut self,\n        config: &mut Arc<Config>,\n        bin_name: &str,\n    ) -> Result<Option<Vec<ToolVersion>>> {\n        // Strategy: Find backends that could provide this bin by checking:\n        // 1. Any currently installed versions that provide the bin\n        // 2. Any requested backends with installed versions (even if not current)\n        let mut plugins = IndexSet::new();\n\n        // First check currently active installed versions\n        for (p, tv) in self.list_current_installed_versions(config) {\n            if let Ok(Some(_bin)) = p.which(config, &tv, bin_name).await {\n                plugins.insert(p);\n            }\n        }\n\n        // Also check backends that are requested but not currently active\n        // This handles the case where a user has tool@v1 globally and tool@v2 locally (not installed)\n        // When looking for a bin provided by the tool, we check if any installed version provides it\n        let all_installed = self.list_installed_versions(config).await?;\n        for (backend, _versions) in self.list_versions_by_plugin() {\n            // Skip if we already found this backend\n            if plugins.contains(&backend) {\n                continue;\n            }\n\n            // Check if this backend has ANY installed version that provides the bin\n            let backend_versions: Vec<_> = all_installed\n                .iter()\n                .filter(|(p, _)| p.ba() == backend.ba())\n                .collect();\n\n            for (_, tv) in backend_versions {\n                if let Ok(Some(_bin)) = backend.which(config, tv, bin_name).await {\n                    plugins.insert(backend.clone());\n                    break;\n                }\n            }\n        }\n\n        // Install missing versions for backends that provide this bin\n        for plugin in plugins {\n            let versions = self\n                .list_missing_versions(config)\n                .await\n                .into_iter()\n                .filter(|tv| tv.ba() == &**plugin.ba())\n                .filter(|tv| match &Settings::get().auto_install_disable_tools {\n                    Some(disable_tools) => !disable_tools.contains(&tv.ba().short),\n                    None => true,\n                })\n                .map(|tv| tv.request)\n                .collect_vec();\n            if !versions.is_empty() {\n                let versions = self\n                    .install_all_versions(config, versions.clone(), &InstallOptions::default())\n                    .await?;\n                if !versions.is_empty() {\n                    let ts = config.get_toolset().await?;\n                    config::rebuild_shims_and_runtime_symlinks(config, ts, &versions).await?;\n                }\n                return Ok(Some(versions));\n            }\n        }\n        Ok(None)\n    }\n\n    /// Install all plugins defined in [plugins] config section\n    pub async fn ensure_config_plugins_installed(\n        config: &Arc<Config>,\n        dry_run: bool,\n    ) -> Result<()> {\n        if config.repo_urls.is_empty() {\n            return Ok(());\n        }\n\n        let mpr = MultiProgressReport::get();\n\n        for (plugin_key, url) in &config.repo_urls {\n            let (plugin_type, name) = Self::parse_plugin_key(plugin_key, url);\n\n            // Skip empty plugin names (e.g., from malformed keys like \"\" or \"vfox:\")\n            if name.is_empty() {\n                warn!(\"skipping empty plugin name from key: {plugin_key}\");\n                continue;\n            }\n\n            let plugin = plugin_type.plugin(name.to_string());\n\n            if !plugin.is_installed() {\n                plugin\n                    .ensure_installed(config, &mpr, false, dry_run)\n                    .await?;\n            }\n        }\n        Ok(())\n    }\n\n    fn parse_plugin_key<'a>(key: &'a str, url: &str) -> (PluginType, &'a str) {\n        if let Some(name) = key.strip_prefix(\"vfox:\") {\n            (PluginType::Vfox, name)\n        } else if let Some(name) = key.strip_prefix(\"vfox-backend:\") {\n            (PluginType::VfoxBackend, name)\n        } else if let Some(name) = key.strip_prefix(\"asdf:\") {\n            (PluginType::Asdf, name)\n        } else if url.contains(\"vfox-\") {\n            // Match existing behavior from config/mod.rs:226-228\n            (PluginType::Vfox, key)\n        } else {\n            (PluginType::Asdf, key)\n        }\n    }\n}\n"
  },
  {
    "path": "src/toolset/toolset_paths.rs",
    "content": "use std::path::PathBuf;\nuse std::sync::Arc;\n\nuse dashmap::DashMap;\nuse eyre::Result;\nuse std::sync::LazyLock as Lazy;\n\nuse crate::config::Config;\nuse crate::config::env_directive::EnvResults;\nuse crate::toolset::Toolset;\nuse crate::uv;\nuse itertools::Itertools;\n\n// Cache Toolset::list_paths results across identical toolsets within a process.\n// Keyed by project_root plus sorted list of backend@version pairs currently installed.\npub(super) static LIST_PATHS_CACHE: Lazy<DashMap<String, Vec<PathBuf>>> = Lazy::new(DashMap::new);\n\nimpl Toolset {\n    pub async fn list_paths(&self, config: &Arc<Config>) -> Vec<PathBuf> {\n        // Build a stable cache key based on project_root and current installed versions\n        let mut key_parts = vec![];\n        if let Some(root) = &config.project_root {\n            key_parts.push(root.to_string_lossy().to_string());\n        }\n        let mut installed = self.list_current_installed_versions(config);\n\n        let installed_strs: Vec<String> = installed\n            .iter()\n            .map(|(p, tv)| format!(\"{}@{}\", p.id(), tv.version))\n            .sorted()\n            .collect();\n        key_parts.extend(installed_strs);\n\n        let cache_key = key_parts.join(\"|\");\n        if let Some(entry) = LIST_PATHS_CACHE.get(&cache_key) {\n            trace!(\"toolset.list_paths hit cache\");\n            return entry.clone();\n        }\n\n        Self::sort_by_overrides(&mut installed).unwrap();\n\n        let mut paths: Vec<PathBuf> = Vec::new();\n        for (p, tv) in installed {\n            let start = std::time::Instant::now();\n            let new_paths = p.list_bin_paths(config, &tv).await.unwrap_or_else(|e| {\n                warn!(\"Error listing bin paths for {tv}: {e:#}\");\n                Vec::new()\n            });\n            trace!(\n                \"toolset.list_paths {}@{} list_bin_paths took {}ms\",\n                p.id(),\n                tv.version,\n                start.elapsed().as_millis()\n            );\n            paths.extend(new_paths);\n        }\n        LIST_PATHS_CACHE.insert(cache_key, paths.clone());\n        paths\n            .into_iter()\n            .filter(|p| p.parent().is_some()) // TODO: why?\n            .collect()\n    }\n\n    /// same as list_paths but includes config.list_paths, venv paths, and MISE_ADD_PATHs from self.env()\n    pub async fn list_final_paths(\n        &self,\n        config: &Arc<Config>,\n        env_results: EnvResults,\n    ) -> Result<Vec<PathBuf>> {\n        let mut paths = Vec::new();\n\n        // Match the tera_env PATH ordering from final_env():\n        // 1. Original system PATH is handled by PathEnv::from_iter() in env_with_path()\n\n        // 2. Config path dirs\n        paths.extend(config.path_dirs().await?.clone());\n\n        // 3. UV venv path (if any) - ensure project venv takes precedence over tool and tool_add_paths\n        if let Some(venv) = uv::uv_venv(config, self).await {\n            paths.push(venv.venv_path.clone());\n        }\n\n        // 4. tool_add_paths (MISE_ADD_PATH/RTX_ADD_PATH from tools)\n        paths.extend(env_results.tool_add_paths);\n\n        // 5. Tool paths\n        paths.extend(self.list_paths(config).await);\n\n        // 6. env_results.env_paths (from load_post_env like _.path directives) - these go at the front\n        let paths = env_results.env_paths.into_iter().chain(paths).collect();\n        Ok(paths)\n    }\n\n    /// Returns paths separated by their source: (user_configured_paths, tool_paths)\n    /// User-configured paths should never be filtered, while tool paths should be filtered\n    /// if they duplicate entries in the original PATH.\n    pub async fn list_final_paths_split(\n        &self,\n        config: &Arc<Config>,\n        env_results: EnvResults,\n    ) -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {\n        // User-configured paths from env._.path directives\n        // IMPORTANT: There are TWO sources of env paths:\n        // 1. config.path_dirs() - from config.env_results() (cached, no tera context)\n        // 2. env_results.env_paths - from ts.final_env() (fresh, with tera context applied)\n        // env_results.env_paths must come FIRST for highest precedence\n        let mut user_paths = env_results.env_paths;\n        user_paths.extend(config.path_dirs().await?.clone());\n\n        // Tool paths start empty\n        let mut tool_paths = Vec::new();\n\n        // UV venv path (if any) - these are tool-managed paths\n        if let Some(venv) = uv::uv_venv(config, self).await {\n            tool_paths.push(venv.venv_path.clone());\n        }\n\n        // tool_add_paths (MISE_ADD_PATH/RTX_ADD_PATH from tools)\n        tool_paths.extend(env_results.tool_add_paths);\n\n        // Tool installation paths\n        tool_paths.extend(self.list_paths(config).await);\n\n        Ok((user_paths, tool_paths))\n    }\n}\n"
  },
  {
    "path": "src/ui/ctrlc.rs",
    "content": "use crate::exit;\nuse std::sync::atomic::{AtomicBool, Ordering};\n\nuse crate::cmd::CmdLineRunner;\nuse console::Term;\n\nstatic EXIT: AtomicBool = AtomicBool::new(true);\nstatic SHOW_CURSOR: AtomicBool = AtomicBool::new(false);\nstatic CANCELLED: AtomicBool = AtomicBool::new(false);\n// static HANDLERS: OnceCell<Vec<Box<dyn Fn() + Send + Sync + 'static>>> = OnceCell::new();\n\npub fn init() {\n    tokio::spawn(async move {\n        loop {\n            tokio::signal::ctrl_c().await.unwrap();\n            if SHOW_CURSOR.load(Ordering::Relaxed) {\n                let _ = Term::stderr().show_cursor();\n            }\n            CmdLineRunner::kill_all(nix::sys::signal::SIGINT);\n            if EXIT.load(Ordering::Relaxed) || CANCELLED.load(Ordering::Relaxed) {\n                debug!(\"Ctrl-C pressed, exiting...\");\n                exit(1);\n            }\n            // First ctrl-c when EXIT is false: mark as cancelled so a second\n            // ctrl-c will force-exit and in-process operations can check the flag.\n            CANCELLED.store(true, Ordering::Relaxed);\n        }\n    });\n}\n\npub fn exit_on_ctrl_c(do_exit: bool) {\n    EXIT.store(do_exit, Ordering::Relaxed);\n    CANCELLED.store(false, Ordering::Relaxed);\n}\n\n/// Returns true if ctrl-c has been received\npub fn is_cancelled() -> bool {\n    CANCELLED.load(Ordering::Relaxed)\n}\n\n/// ensures cursor is displayed on ctrl-c\npub fn show_cursor_after_ctrl_c() {\n    SHOW_CURSOR.store(true, Ordering::Relaxed);\n}\n"
  },
  {
    "path": "src/ui/ctrlc_stub.rs",
    "content": "pub fn init() {}\n\n// pub fn add_handler(_func: impl Fn() + Send + Sync + 'static) {}\n\npub fn exit_on_ctrl_c(_do_exit: bool) {}\n\npub fn is_cancelled() -> bool {\n    false\n}\n\n/// ensures cursor is displayed on ctrl-c\npub fn show_cursor_after_ctrl_c() {}\n"
  },
  {
    "path": "src/ui/info.rs",
    "content": "use crate::file;\nuse console::style;\nuse indenter::indented;\nuse std::fmt::{Display, Write};\n\npub fn section<S: Display>(header: &str, body: S) -> eyre::Result<()> {\n    let body = file::replace_paths_in_string(body);\n    let out = format!(\"\\n{}: \\n{}\", style(header).bold(), indent_by(body, \"  \"));\n    miseprintln!(\"{}\", trim_line_end_whitespace(&out));\n    Ok(())\n}\n\npub fn inline_section<S: Display>(header: &str, body: S) -> eyre::Result<()> {\n    let body = file::replace_paths_in_string(body);\n    let out = format!(\"{}: {body}\", style(header).bold());\n    miseprintln!(\"{}\", trim_line_end_whitespace(&out));\n    Ok(())\n}\n\npub fn indent_by<S: Display>(s: S, ind: &'static str) -> String {\n    let mut out = String::new();\n    write!(indented(&mut out).with_str(ind), \"{s}\").unwrap();\n    out\n}\n\npub fn trim_line_end_whitespace(s: &str) -> String {\n    s.lines().map(str::trim_end).collect::<Vec<_>>().join(\"\\n\")\n}\n"
  },
  {
    "path": "src/ui/mod.rs",
    "content": "pub use prompt::confirm;\n\n#[cfg_attr(any(test, windows), path = \"ctrlc_stub.rs\")]\npub mod ctrlc;\npub(crate) mod info;\npub mod multi_progress_report;\npub mod progress_report;\npub mod prompt;\npub mod style;\npub mod table;\npub mod theme;\npub mod time;\npub mod tree;\n"
  },
  {
    "path": "src/ui/multi_progress_report.rs",
    "content": "use std::sync::{Arc, Mutex};\n\nuse clx::progress::{self, ProgressJobBuilder, ProgressOutput};\n\nuse crate::cli::version::VERSION_PLAIN;\nuse crate::config::Settings;\nuse crate::env;\nuse crate::ui::progress_report::{ProgressReport, QuietReport, SingleReport, VerboseReport};\n\n#[derive(Debug)]\npub struct MultiProgressReport {\n    quiet: bool,\n    verbose: bool,\n    raw: bool,\n    has_stderr: bool,\n    force_progress: bool,\n    total_count: Mutex<usize>,\n    completed_count: Mutex<usize>,\n    /// Header job for updating progress display\n    header_job: Mutex<Option<Arc<progress::ProgressJob>>>,\n}\n\nstatic INSTANCE: Mutex<Option<Arc<MultiProgressReport>>> = Mutex::new(None);\n\nimpl MultiProgressReport {\n    pub fn try_get() -> Option<Arc<Self>> {\n        INSTANCE.lock().unwrap().as_ref().cloned()\n    }\n\n    pub fn get() -> Arc<Self> {\n        let mut guard = INSTANCE.lock().unwrap();\n        if let Some(existing) = guard.as_ref() {\n            return existing.clone();\n        }\n        let mpr = Arc::new(Self::new());\n        *guard = Some(mpr.clone());\n        mpr\n    }\n\n    fn new() -> Self {\n        let settings = Settings::get();\n        let has_stderr = console::user_attended_stderr();\n        let force_progress = *env::MISE_FORCE_PROGRESS;\n\n        progress_trace!(\n            \"MultiProgressReport::new: raw={}, quiet={}, verbose={}, has_stderr={}, force_progress={}\",\n            settings.raw,\n            settings.quiet,\n            settings.verbose,\n            has_stderr,\n            force_progress,\n        );\n\n        // Configure clx output mode based on settings\n        // MISE_FORCE_PROGRESS=1 forces progress UI even in non-TTY (for debugging)\n        let use_progress_ui =\n            !settings.raw && !settings.quiet && !settings.verbose && (has_stderr || force_progress);\n        if !use_progress_ui {\n            progress::set_output(ProgressOutput::Text);\n        }\n\n        // Configure OSC progress based on settings\n        if !settings.terminal_progress {\n            // Disable OSC progress if terminal_progress is disabled\n            // clx::osc::configure panics if called more than once (singleton pattern),\n            // so we use catch_unwind to safely ignore duplicate calls\n            let _ = std::panic::catch_unwind(|| {\n                clx::osc::configure(false);\n            });\n        }\n\n        MultiProgressReport {\n            quiet: settings.quiet,\n            verbose: settings.verbose,\n            raw: settings.raw,\n            has_stderr,\n            force_progress,\n            total_count: Mutex::new(0),\n            completed_count: Mutex::new(0),\n            header_job: Mutex::new(None),\n        }\n    }\n\n    /// Check if we should use UI-style progress (not quiet/verbose/raw)\n    fn use_progress_ui(&self) -> bool {\n        !self.raw && !self.quiet && !self.verbose && (self.has_stderr || self.force_progress)\n    }\n\n    pub fn add(&self, prefix: &str) -> Box<dyn SingleReport> {\n        self.add_with_options(prefix, false)\n    }\n\n    pub fn add_with_options(&self, prefix: &str, dry_run: bool) -> Box<dyn SingleReport> {\n        if self.quiet {\n            progress_trace!(\n                \"add_with_options[{}]: creating QuietReport (quiet=true)\",\n                prefix\n            );\n            Box::new(QuietReport::new())\n        } else if self.use_progress_ui() && !dry_run {\n            progress_trace!(\n                \"add_with_options[{}]: creating ProgressReport with clx\",\n                prefix\n            );\n            Box::new(ProgressReport::new(prefix.into()))\n        } else {\n            progress_trace!(\n                \"add_with_options[{}]: creating VerboseReport (use_progress_ui={}, dry_run={})\",\n                prefix,\n                self.use_progress_ui(),\n                dry_run\n            );\n            Box::new(VerboseReport::new(prefix.to_string()))\n        }\n    }\n\n    pub fn init_footer(&self, dry_run: bool, _message: &str, total_count: usize) {\n        // Only create header once - check if already initialized\n        if self.header_job.lock().unwrap().is_some() {\n            return;\n        }\n\n        // Set total count for progress tracking\n        *self.total_count.lock().unwrap() = total_count;\n        progress_trace!(\"init_footer: total_count={}\", total_count);\n\n        // Don't show header when there's only 1 tool - individual progress bar is sufficient\n        if total_count <= 1 {\n            return;\n        }\n\n        // Don't show header in quiet mode\n        if self.quiet {\n            return;\n        }\n\n        // Create header job showing overall progress (only in progress UI mode)\n        // Left-aligned, colored header with \"mise VERSION by @jdx\" and cur/total count\n        if self.use_progress_ui() && !dry_run {\n            use crate::ui::style;\n\n            // Build colored header text parts\n            let mise_text = format!(\"{}\", style::emagenta(\"mise\").bold());\n            let version_text = format!(\"{}\", style::edim(&*VERSION_PLAIN));\n            let by_text = format!(\"{}\", style::edim(\"by @jdx\"));\n\n            // Template showing: \"mise VERSION by @jdx                  [cur/total]\"\n            let header_body = \"{{ mise }} {{ version }} {{ by | flex_fill }} {{ progress }}\";\n\n            let job = ProgressJobBuilder::new()\n                .body(header_body)\n                .prop(\"mise\", &mise_text)\n                .prop(\"version\", &version_text)\n                .prop(\"by\", &by_text)\n                .prop(\"progress\", &format!(\"[0/{}]\", total_count))\n                .progress_total(total_count)\n                .progress_current(0)\n                .start();\n            *self.header_job.lock().unwrap() = Some(job);\n        }\n    }\n\n    pub fn footer_inc(&self, n: usize) {\n        if n == 0 {\n            return;\n        }\n        let completed = {\n            let mut c = self.completed_count.lock().unwrap();\n            *c += n;\n            *c\n        };\n        let total = *self.total_count.lock().unwrap();\n        progress_trace!(\"footer_inc: completed={}, total={}\", completed, total);\n\n        // Update header job progress display\n        if let Some(job) = self.header_job.lock().unwrap().as_ref() {\n            job.prop(\"progress\", &format!(\"[{}/{}]\", completed, total));\n            job.progress_current(completed);\n        }\n    }\n\n    pub fn footer_finish(&self) {\n        let total = *self.total_count.lock().unwrap();\n        let completed = *self.completed_count.lock().unwrap();\n\n        progress_trace!(\"footer_finish: completed={}, total={}\", completed, total);\n\n        // Stop clx progress\n        progress::stop();\n\n        // Reset state for subsequent install operations (e.g., in daemon mode)\n        *self.header_job.lock().unwrap() = None;\n        *self.completed_count.lock().unwrap() = 0;\n        *self.total_count.lock().unwrap() = 0;\n    }\n\n    pub fn stop(&self) -> eyre::Result<()> {\n        progress::stop_clear();\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_multi_progress_report() {\n        let mpr = MultiProgressReport::get();\n        let pr = mpr.add(\"PREFIX\");\n        pr.finish_with_message(\"test\".into());\n        pr.println(\"\".into());\n        pr.set_message(\"test\".into());\n    }\n}\n"
  },
  {
    "path": "src/ui/progress_report.rs",
    "content": "#![allow(unknown_lints)]\n#![allow(clippy::literal_string_with_formatting_args)]\n\nuse std::{\n    fmt::{Display, Formatter},\n    sync::{Arc, Mutex},\n};\n\nuse clx::progress::{ProgressJob, ProgressJobBuilder, ProgressStatus};\nuse std::sync::LazyLock as Lazy;\n\nuse crate::ui::style;\nuse crate::{backend, ui};\n\n#[derive(Debug, Clone, Copy)]\npub enum ProgressIcon {\n    Success,\n    Skipped,\n    Warning,\n    Error,\n}\n\nimpl Display for ProgressIcon {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            ProgressIcon::Success => write!(f, \"{}\", style::egreen(\"✓\").bright()),\n            ProgressIcon::Skipped => write!(f, \"{}\", style::eyellow(\"⇢\").bright()),\n            ProgressIcon::Warning => write!(f, \"{}\", style::eyellow(\"⚠\").bright()),\n            ProgressIcon::Error => write!(f, \"{}\", style::ered(\"✗\").bright()),\n        }\n    }\n}\n\npub trait SingleReport: Send + Sync + std::fmt::Debug {\n    fn println(&self, _message: String) {}\n    fn set_message(&self, _message: String) {}\n    fn inc(&self, _delta: u64) {}\n    fn set_position(&self, _delta: u64) {}\n    fn set_length(&self, _length: u64) {}\n    fn abandon(&self) {}\n    fn finish(&self) {\n        self.finish_with_message(String::new());\n    }\n    fn finish_with_message(&self, message: String) {\n        self.finish_with_icon(message, ProgressIcon::Success);\n    }\n    fn finish_with_icon(&self, _message: String, _icon: ProgressIcon) {}\n\n    /// Declare how many operations this progress report will have\n    /// Each operation will get equal space (1/count)\n    /// For example, if there are 3 operations (download, checksum, extract):\n    /// - start_operations(3) at the beginning\n    ///\n    /// Then each set_length() call will allocate 33.33% of the total progress\n    fn start_operations(&self, _count: usize) {}\n\n    /// Advance to the next operation\n    /// Call this before each new stage (after the first one)\n    fn next_operation(&self) {}\n}\n\nstatic LONGEST_PLUGIN_NAME: Lazy<usize> = Lazy::new(|| {\n    backend::list()\n        .into_iter()\n        .map(|p| p.id().len())\n        .max()\n        .unwrap_or_default()\n        .clamp(15, 35)\n});\n\nfn pad_prefix(w: usize, s: &str) -> String {\n    console::pad_str(s, w, console::Alignment::Left, None).to_string()\n}\n\nfn normal_prefix(pad: usize, prefix: &str) -> String {\n    pad_prefix(pad, prefix)\n}\n\n/// clx-based progress report implementation\n#[derive(Debug)]\npub struct ProgressReport {\n    job: Arc<ProgressJob>,\n}\n\nimpl ProgressReport {\n    pub fn new(prefix: String) -> ProgressReport {\n        ui::ctrlc::show_cursor_after_ctrl_c();\n        let pad = *LONGEST_PLUGIN_NAME;\n        let formatted_prefix = normal_prefix(pad, &prefix);\n\n        // Template: prefix + message + optional bytes/progress bar + spinner on right\n        // Use flex_fill to pad message and push progress bar to right edge\n        // Use \"arc\" spinner style instead of default mini_dot\n        // clx's bytes() function shows actual byte values for the current operation\n        // while clx handles the multi-operation mapping internally for OSC progress\n        // Use bytes(total=false, hide_complete=true) to show only current bytes and hide on completion\n        let body = \"{{ prefix }} {{ message | flex_fill }} {% if total %}{{ bytes(total=false, hide_complete=true) }} {{ eta(hide_complete=true) }} {{ progress_bar(width=20, hide_complete=true) }} {% endif %}{{ spinner(name=\\\"arc\\\") }}\";\n\n        let job = ProgressJobBuilder::new()\n            .body(body)\n            .prop(\"prefix\", &formatted_prefix)\n            .prop(\"message\", \"\")\n            .start();\n\n        ProgressReport { job }\n    }\n}\n\nimpl SingleReport for ProgressReport {\n    fn println(&self, message: String) {\n        self.job.println(&message);\n    }\n\n    fn set_message(&self, message: String) {\n        self.job.prop(\"message\", &message.replace('\\r', \"\"));\n    }\n\n    fn inc(&self, delta: u64) {\n        self.job.increment(delta as usize);\n    }\n\n    fn set_position(&self, pos: u64) {\n        self.job.progress_current(pos as usize);\n    }\n\n    fn set_length(&self, length: u64) {\n        self.job.progress_total(length as usize);\n    }\n\n    fn abandon(&self) {\n        self.job.set_status(ProgressStatus::Hide);\n    }\n\n    fn finish_with_icon(&self, _message: String, icon: ProgressIcon) {\n        // Set status based on icon\n        match icon {\n            ProgressIcon::Success => self.job.set_status(ProgressStatus::Done),\n            ProgressIcon::Error => self.job.set_status(ProgressStatus::Failed),\n            ProgressIcon::Warning => self.job.set_status(ProgressStatus::Warn),\n            ProgressIcon::Skipped => self.job.set_status(ProgressStatus::Done),\n        }\n    }\n\n    fn start_operations(&self, count: usize) {\n        self.job.start_operations(count);\n    }\n\n    fn next_operation(&self) {\n        self.job.next_operation();\n    }\n}\n\n#[derive(Debug)]\npub struct QuietReport {}\n\nimpl QuietReport {\n    pub fn new() -> QuietReport {\n        QuietReport {}\n    }\n}\n\nimpl SingleReport for QuietReport {}\n\n#[derive(Debug)]\npub struct VerboseReport {\n    prefix: String,\n    prev_message: Mutex<String>,\n    pad: usize,\n    total_operations: Mutex<Option<usize>>,\n    current_operation: Mutex<usize>,\n}\n\nimpl VerboseReport {\n    pub fn new(prefix: String) -> VerboseReport {\n        VerboseReport {\n            prefix,\n            prev_message: Mutex::new(\"\".to_string()),\n            pad: *LONGEST_PLUGIN_NAME,\n            total_operations: Mutex::new(None),\n            current_operation: Mutex::new(0),\n        }\n    }\n}\n\nimpl SingleReport for VerboseReport {\n    fn println(&self, message: String) {\n        eprintln!(\"{message}\");\n    }\n    fn set_message(&self, message: String) {\n        let mut prev_message = self.prev_message.lock().unwrap();\n        if *prev_message == message {\n            return;\n        }\n        let total = *self.total_operations.lock().unwrap();\n        let current = *self.current_operation.lock().unwrap();\n        let formatted = if let Some(total) = total {\n            format!(\"[{}/{}] {}\", current, total, message)\n        } else {\n            message.clone()\n        };\n        let prefix = pad_prefix(self.pad, &self.prefix);\n        log::info!(\"{prefix} {formatted}\");\n        *prev_message = message;\n    }\n    fn finish(&self) {\n        self.finish_with_message(style::egreen(\"done\").to_string());\n    }\n    fn finish_with_icon(&self, message: String, icon: ProgressIcon) {\n        let prefix = pad_prefix(self.pad - 2, &self.prefix);\n        log::info!(\"{prefix} {icon} {message}\");\n    }\n    fn start_operations(&self, count: usize) {\n        *self.total_operations.lock().unwrap() = Some(count.max(1));\n        *self.current_operation.lock().unwrap() = 1;\n    }\n    fn next_operation(&self) {\n        let total = *self.total_operations.lock().unwrap();\n        if total.is_some() {\n            let mut current = self.current_operation.lock().unwrap();\n            *current += 1;\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::config::Config;\n\n    use super::*;\n\n    #[tokio::test]\n    async fn test_progress_report() {\n        let _config = Config::get().await.unwrap();\n        let pr = ProgressReport::new(\"foo\".into());\n        pr.set_message(\"message\".into());\n        pr.finish_with_message(\"message\".into());\n    }\n\n    #[tokio::test]\n    async fn test_progress_report_verbose() {\n        let _config = Config::get().await.unwrap();\n        let pr = VerboseReport::new(\"PREFIX\".to_string());\n        pr.set_message(\"message\".into());\n        pr.finish_with_message(\"message\".into());\n    }\n\n    #[tokio::test]\n    async fn test_progress_report_quiet() {\n        let _config = Config::get().await.unwrap();\n        let pr = QuietReport::new();\n        pr.set_message(\"message\".into());\n        pr.finish_with_message(\"message\".into());\n    }\n}\n"
  },
  {
    "path": "src/ui/prompt.rs",
    "content": "use std::sync::Mutex;\n\nuse demand::{Confirm, Dialog, DialogButton};\n\nuse crate::env;\nuse crate::ui::ctrlc;\nuse crate::ui::theme::get_theme;\n\nstatic MUTEX: Mutex<()> = Mutex::new(());\n\nstatic SKIP_PROMPT: Mutex<bool> = Mutex::new(false);\n\npub fn confirm<S: Into<String>>(message: S) -> eyre::Result<bool> {\n    let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once\n    ctrlc::show_cursor_after_ctrl_c();\n\n    if !console::user_attended_stderr() || env::__USAGE.is_some() {\n        return Ok(false);\n    }\n    let theme = get_theme();\n    let result = Confirm::new(message)\n        .clear_screen(true)\n        .theme(&theme)\n        .run()?;\n    Ok(result)\n}\n\npub fn confirm_with_all<S: Into<String>>(message: S) -> eyre::Result<bool> {\n    let _lock = MUTEX.lock().unwrap(); // Prevent multiple prompts at once\n    ctrlc::show_cursor_after_ctrl_c();\n\n    if !console::user_attended_stderr() || env::__USAGE.is_some() {\n        return Ok(false);\n    }\n\n    let mut skip_prompt = SKIP_PROMPT.lock().unwrap();\n    if *skip_prompt {\n        return Ok(true);\n    }\n\n    let theme = get_theme();\n    let answer = Dialog::new(message)\n        .buttons(vec![\n            DialogButton::new(\"Yes\"),\n            DialogButton::new(\"No\"),\n            DialogButton::new(\"All\"),\n        ])\n        .selected_button(1)\n        .clear_screen(true)\n        .theme(&theme)\n        .run()?;\n\n    let result = match answer.as_str() {\n        \"Yes\" => true,\n        \"No\" => false,\n        \"All\" => {\n            *skip_prompt = true;\n            true\n        }\n        _ => false,\n    };\n    Ok(result)\n}\n"
  },
  {
    "path": "src/ui/style.rs",
    "content": "use std::path::Path;\n\nuse crate::file::display_path;\nuse console::{StyledObject, style};\n\npub fn ereset() -> String {\n    if console::colors_enabled_stderr() {\n        \"\\x1b[0m\".to_string()\n    } else {\n        \"\".to_string()\n    }\n}\n\npub fn estyle<D>(val: D) -> StyledObject<D> {\n    style(val).for_stderr()\n}\n\npub fn ecyan<D>(val: D) -> StyledObject<D> {\n    estyle(val).cyan()\n}\n\npub fn eblue<D>(val: D) -> StyledObject<D> {\n    estyle(val).blue()\n}\n\npub fn emagenta<D>(val: D) -> StyledObject<D> {\n    estyle(val).magenta()\n}\n\npub fn egreen<D>(val: D) -> StyledObject<D> {\n    estyle(val).green()\n}\n\npub fn eyellow<D>(val: D) -> StyledObject<D> {\n    estyle(val).yellow()\n}\n\npub fn ered<D>(val: D) -> StyledObject<D> {\n    estyle(val).red()\n}\n\npub fn eblack<D>(val: D) -> StyledObject<D> {\n    estyle(val).black()\n}\n\npub fn eunderline<D>(val: D) -> StyledObject<D> {\n    estyle(val).underlined()\n}\n\npub fn edim<D>(val: D) -> StyledObject<D> {\n    estyle(val).dim()\n}\n\npub fn ebold<D>(val: D) -> StyledObject<D> {\n    estyle(val).bold()\n}\n\npub fn nbold<D>(val: D) -> StyledObject<D> {\n    nstyle(val).bold()\n}\n\npub fn epath(path: &Path) -> StyledObject<String> {\n    estyle(display_path(path))\n}\n\npub fn nstyle<D>(val: D) -> StyledObject<D> {\n    style(val).for_stdout()\n}\n\npub fn ncyan<D>(val: D) -> StyledObject<D> {\n    nstyle(val).cyan()\n}\n\npub fn nunderline<D>(val: D) -> StyledObject<D> {\n    nstyle(val).underlined()\n}\n\npub fn nyellow<D>(val: D) -> StyledObject<D> {\n    nstyle(val).yellow()\n}\n\npub fn nred<D>(val: D) -> StyledObject<D> {\n    nstyle(val).red()\n}\n\npub fn ndim<D>(val: D) -> StyledObject<D> {\n    nstyle(val).dim()\n}\n\npub fn nbright<D>(val: D) -> StyledObject<D> {\n    nstyle(val).bright()\n}\n"
  },
  {
    "path": "src/ui/table.rs",
    "content": "use crate::Result;\nuse crate::env::TERM_WIDTH;\nuse comfy_table::{Attribute, Cell, Color, ContentArrangement, Row};\nuse console::style;\nuse itertools::Itertools;\nuse tabled::Table;\nuse tabled::settings::object::{Columns, Rows};\nuse tabled::settings::peaker::PriorityMax;\nuse tabled::settings::width::{MinWidth, Wrap};\nuse tabled::settings::{Format, Margin, Modify, Padding, Remove, Settings, Style, Width};\nuse xx::regex;\n\ntype SettingPriority = Settings<Settings, Wrap<usize, PriorityMax>>;\ntype SettingMinWidth = Settings<SettingPriority, MinWidth>;\n// type SettingCellHeightLimit = Settings<SettingMinWidth, CellHeightLimit>;\n// type SettingCellHeightIncrease = Settings<SettingCellHeightLimit, CellHeightIncrease>;\n\npub fn term_size_settings() -> SettingMinWidth {\n    Settings::default()\n        .with(Width::wrap(*TERM_WIDTH).priority(PriorityMax::default()))\n        .with(Width::increase(*TERM_WIDTH))\n    // .with(Height::limit(*TERM_HEIGHT))\n    // .with(Height::increase(*TERM_HEIGHT))\n}\n\npub fn default_style(table: &mut Table, no_headers: bool) {\n    let header = |h: &_| style(h).italic().magenta().to_string();\n\n    if no_headers || !console::user_attended() || cfg!(test) {\n        table.with(Remove::row(Rows::first()));\n    } else {\n        table.with(Modify::new(Rows::first()).with(Format::content(header)));\n    }\n    table.with(Style::empty());\n    if console::user_attended() && !cfg!(test) {\n        table.with(term_size_settings());\n    }\n    table\n        .with(Margin::new(0, 0, 0, 0))\n        .with(Modify::new(Columns::first()).with(Padding::new(0, 1, 0, 0)))\n        .with(Modify::new(Columns::last()).with(Padding::zero()));\n}\n\npub struct MiseTable {\n    table: comfy_table::Table,\n    truncate: bool,\n}\n\nimpl MiseTable {\n    pub fn new(no_header: bool, headers: &[&str]) -> Self {\n        let mut table = comfy_table::Table::new();\n        table\n            .load_preset(comfy_table::presets::NOTHING)\n            .set_content_arrangement(ContentArrangement::Dynamic);\n        if !console::colors_enabled() {\n            table.force_no_tty();\n        }\n        if !no_header && console::user_attended() {\n            let headers = headers.iter().map(Self::header).collect_vec();\n            table.set_header(headers);\n        }\n        Self {\n            table,\n            truncate: false,\n        }\n    }\n\n    pub fn truncate(&mut self, truncate: bool) -> &mut Self {\n        self.truncate = truncate;\n        self\n    }\n\n    fn header(title: impl ToString) -> Cell {\n        Cell::new(title)\n            .add_attribute(Attribute::Italic)\n            .fg(Color::Magenta)\n    }\n\n    pub fn add_row(&mut self, row: impl Into<Row>) {\n        let mut row = row.into();\n        row.max_height(1);\n        self.table.add_row(row);\n    }\n\n    pub fn print(&self) -> Result<()> {\n        let table = self.table.to_string();\n        // trim first character, skipping color characters\n        let re = regex!(r\"^(\\x{1b}[^ ]*\\d+m) \");\n        for line in table.lines() {\n            let line = line.strip_prefix(' ').unwrap_or(line);\n            let line = re.replacen(line, 1, \"$1\");\n            let line = line.trim_end();\n            calm_io::stdoutln!(\"{line}\")?;\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "src/ui/theme.rs",
    "content": "use demand::Theme;\n\nuse crate::config::Settings;\n\n/// Returns the demand theme based on the `color_theme` setting.\n///\n/// Available themes:\n/// - \"default\" or \"charm\" - Default charm theme (good for dark terminals)\n/// - \"base16\" - Base16 theme (good for light terminals)\n/// - \"catppuccin\" - Catppuccin theme\n/// - \"dracula\" - Dracula theme\npub fn get_theme() -> Theme {\n    let settings = Settings::get();\n    match settings.color_theme.to_lowercase().as_str() {\n        \"base16\" => Theme::base16(),\n        \"catppuccin\" => Theme::catppuccin(),\n        \"dracula\" => Theme::dracula(),\n        \"charm\" | \"default\" | \"\" => Theme::charm(),\n        other => {\n            warn!(\"Unknown color theme '{}', using default\", other);\n            Theme::charm()\n        }\n    }\n}\n"
  },
  {
    "path": "src/ui/time.rs",
    "content": "use std::time::Duration;\n\npub fn format_duration(dur: Duration) -> String {\n    if dur < Duration::from_millis(1) {\n        format!(\"{dur:.0?}\")\n    } else if dur < Duration::from_secs(1) {\n        format!(\"{dur:.1?}\")\n    } else {\n        format!(\"{dur:.2?}\")\n    }\n}\n"
  },
  {
    "path": "src/ui/tree.rs",
    "content": "use std::borrow::Cow;\n\npub trait TreeItem: Clone {\n    type Child: TreeItem;\n\n    fn write_self(&self) -> std::io::Result<()>;\n\n    fn children(&self) -> Cow<'_, [Self::Child]>;\n}\n\nstruct TreeItemIndentChars {\n    /// Character for pointing down and right (`├`).\n    pub down_and_right: &'static str,\n    /// Character for pointing straight down (`|`).\n    pub down: &'static str,\n    /// Character for turning from down to right (`└`).\n    pub turn_right: &'static str,\n    /// Character for pointing right (`─`).\n    pub right: &'static str,\n    /// Empty character (` `).\n    pub empty: &'static str,\n}\n\nconst TREE_ITEM_CHARS: TreeItemIndentChars = TreeItemIndentChars {\n    down_and_right: \"├\",\n    down: \"│\",\n    turn_right: \"└\",\n    right: \"─\",\n    empty: \" \",\n};\n\nstruct TreeItemIndent {\n    pub regular_prefix: String,\n    pub child_prefix: String,\n    pub last_regular_prefix: String,\n    pub last_child_prefix: String,\n}\n\nimpl TreeItemIndent {\n    pub fn new(\n        indent_size: usize,\n        padding: usize,\n        characters: &TreeItemIndentChars,\n    ) -> TreeItemIndent {\n        let m = 1 + padding;\n        let n = indent_size.saturating_sub(m);\n\n        let right_pad = characters.right.repeat(n);\n        let empty_pad = characters.empty.repeat(n);\n        let item_pad = characters.empty.repeat(padding);\n\n        TreeItemIndent {\n            regular_prefix: format!(\"{}{}{}\", characters.down_and_right, right_pad, item_pad),\n            child_prefix: format!(\"{}{}{}\", characters.down, empty_pad, item_pad),\n            last_regular_prefix: format!(\"{}{}{}\", characters.turn_right, right_pad, item_pad),\n            last_child_prefix: format!(\"{}{}{}\", characters.empty, empty_pad, item_pad),\n        }\n    }\n}\n\npub fn print_tree<T: TreeItem>(item: &T) -> std::io::Result<()> {\n    let indent = TreeItemIndent::new(4, 1, &TREE_ITEM_CHARS);\n    print_tree_item(item, String::from(\"\"), String::from(\"\"), &indent, 0)\n}\n\nfn print_tree_item<T: TreeItem>(\n    item: &T,\n    prefix: String,\n    child_prefix: String,\n    indent: &TreeItemIndent,\n    level: u32,\n) -> std::io::Result<()> {\n    miseprint!(\"{}\", prefix)?;\n    item.write_self()?;\n    miseprintln!(\"\");\n\n    if level < u32::MAX {\n        let children = item.children();\n        if let Some((last_child, children)) = children.split_last() {\n            let rp = child_prefix.clone() + &indent.regular_prefix;\n            let cp = child_prefix.clone() + &indent.child_prefix;\n\n            for c in children {\n                print_tree_item(c, rp.clone(), cp.clone(), indent, level + 1)?;\n            }\n\n            let rp = child_prefix.clone() + &indent.last_regular_prefix;\n            let cp = child_prefix.clone() + &indent.last_child_prefix;\n\n            print_tree_item(last_child, rp, cp, indent, level + 1)?;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "src/uv.rs",
    "content": "use crate::cli::args::BackendArg;\nuse crate::config::env_directive::venv::{Venv, create_python_venv, load_venv};\nuse crate::config::{Config, Settings};\nuse crate::env_diff::EnvMap;\nuse crate::file::display_path;\nuse crate::toolset::Toolset;\nuse crate::{dirs, file};\nuse std::path::{Path, PathBuf};\nuse std::sync::LazyLock as Lazy;\nuse std::{collections::HashMap, sync::Arc};\nuse tokio::sync::OnceCell;\n\n// use a mutex to prevent deadlocks that occurs due to reentrantly initialization\n// when resolving the venv path or env vars\nstatic UV_VENV: Lazy<OnceCell<Option<Venv>>> = Lazy::new(Default::default);\n\npub async fn uv_venv(config: &Arc<Config>, ts: &Toolset) -> &'static Option<Venv> {\n    UV_VENV\n        .get_or_init(async || {\n            let settings = Settings::get();\n            let uv_auto = settings.python.uv_venv_auto;\n            if !uv_auto.should_source() {\n                return None;\n            }\n            let uv_root = uv_root()?;\n            let venv_path = uv_root.join(\".venv\");\n            if !venv_path.exists() {\n                if uv_auto.should_create() {\n                    match create_python_venv(\n                        config,\n                        ts,\n                        &venv_path,\n                        EnvMap::new(),\n                        None,\n                        None,\n                        None,\n                        true,\n                    )\n                    .await\n                    {\n                        Ok(true) => {}            // venv created successfully, fall through to load it\n                        Ok(false) => return None, // uv not available, venv not created\n                        Err(err) => {\n                            warn_once!(\n                                \"uv venv creation failed at: {p}\\n\\n{err}\",\n                                p = display_path(&venv_path)\n                            );\n                            return None;\n                        }\n                    }\n                } else {\n                    if !prepare_uv_enabled(config, &uv_root) {\n                        warn_once!(\n                            \"uv venv not found at: {p}\\n\\n\\\n                            To create it, run a `uv` command like `uv sync` or `uv venv`. \\\n                            Alternatively, enable `[prepare.uv]` and run `mise prepare`.\",\n                            p = display_path(&venv_path)\n                        );\n                    }\n                    return None;\n                }\n            }\n\n            let mut extra_env = HashMap::new();\n            // Set UV_PYTHON for legacy behavior\n            if uv_auto.is_legacy_true()\n                && let Some(python_tv) = ts.versions.get(&BackendArg::from(\"python\"))\n                && let Some(tv) = python_tv.versions.first()\n            {\n                extra_env.insert(\"UV_PYTHON\".to_string(), tv.version.to_string());\n            }\n            Some(load_venv(&venv_path, extra_env))\n        })\n        .await\n}\n\nfn uv_root() -> Option<PathBuf> {\n    file::find_up(dirs::CWD.as_ref()?, &[\"uv.lock\"]).map(|p| p.parent().unwrap().to_path_buf())\n}\n\nfn prepare_uv_enabled(config: &Config, uv_root: &Path) -> bool {\n    config.config_files.values().any(|cf| {\n        if cf.config_root() != uv_root {\n            return false;\n        }\n        cf.prepare_config()\n            .is_some_and(|prepare| prepare.providers.contains_key(\"uv\"))\n    })\n}\n"
  },
  {
    "path": "src/versions_host.rs",
    "content": "use crate::backend::VersionInfo;\nuse crate::config::Settings;\nuse crate::http;\nuse crate::http::HTTP_FETCH;\nuse crate::plugins::core::CORE_PLUGINS;\nuse crate::registry::REGISTRY;\nuse reqwest::header::{HeaderMap, HeaderValue};\nuse std::{\n    collections::{HashMap, HashSet},\n    sync::{\n        LazyLock,\n        atomic::{AtomicBool, Ordering},\n    },\n};\nuse tokio::sync::Mutex;\n\n/// Headers for requests to mise-versions, including CI detection\nstatic VERSIONS_HOST_HEADERS: LazyLock<HeaderMap> = LazyLock::new(|| {\n    let mut headers = HeaderMap::new();\n    if ci_info::is_ci() {\n        headers.insert(\"x-mise-ci\", HeaderValue::from_static(\"true\"));\n    }\n    headers\n});\n\n/// Tools that use the versions host for listing versions\n/// (excludes java/python due to complex version schemes)\nstatic PLUGINS_USE_VERSION_HOST: LazyLock<HashSet<&str>> = LazyLock::new(|| {\n    CORE_PLUGINS\n        .keys()\n        .map(|name| name.as_str())\n        .chain(REGISTRY.keys().copied())\n        .filter(|name| !matches!(*name, \"java\" | \"python\"))\n        .collect()\n});\n\n/// Tools that should have downloads tracked\n/// (all core plugins and registry tools, including java/python)\nstatic PLUGINS_TRACK_DOWNLOADS: LazyLock<HashSet<&str>> = LazyLock::new(|| {\n    CORE_PLUGINS\n        .keys()\n        .map(|name| name.as_str())\n        .chain(REGISTRY.keys().copied())\n        .collect()\n});\n\n/// Response format from the versions host TOML endpoint\n#[derive(serde::Deserialize)]\nstruct VersionsResponse {\n    versions: indexmap::IndexMap<String, VersionEntry>,\n}\n\n#[derive(serde::Deserialize)]\nstruct VersionEntry {\n    created_at: toml::value::Datetime,\n    #[serde(default)]\n    release_url: Option<String>,\n}\n\n/// List versions from the versions host (mise-versions.jdx.dev).\n/// Returns Vec<VersionInfo> with created_at timestamps from the TOML endpoint.\npub async fn list_versions(tool: &str) -> eyre::Result<Option<Vec<VersionInfo>>> {\n    let settings = Settings::get();\n    if settings.prefer_offline()\n        || !settings.use_versions_host\n        || !PLUGINS_USE_VERSION_HOST.contains(tool)\n    {\n        return Ok(None);\n    }\n\n    static CACHE: LazyLock<Mutex<HashMap<String, Vec<VersionInfo>>>> =\n        LazyLock::new(|| Mutex::new(HashMap::new()));\n    static RATE_LIMITED: AtomicBool = AtomicBool::new(false);\n\n    if let Some(versions) = CACHE.lock().await.get(tool) {\n        return Ok(Some(versions.clone()));\n    }\n    if RATE_LIMITED.load(Ordering::Relaxed) {\n        warn!(\"{tool}: skipping versions host check due to rate limit\");\n        return Ok(None);\n    }\n\n    // Use TOML format which includes created_at timestamps\n    let url = format!(\"https://mise-versions.jdx.dev/tools/{}.toml\", tool);\n    let versions: Vec<VersionInfo> = match HTTP_FETCH\n        .get_text_with_headers(&url, &VERSIONS_HOST_HEADERS)\n        .await\n    {\n        Ok(body) => {\n            let response: VersionsResponse = toml::from_str(&body)?;\n            response\n                .versions\n                .into_iter()\n                .map(|(version, entry)| VersionInfo {\n                    version,\n                    created_at: Some(entry.created_at.to_string()),\n                    release_url: entry.release_url,\n                    ..Default::default()\n                })\n                .collect()\n        }\n        Err(err) => match http::error_code(&err).unwrap_or(0) {\n            404 => return Ok(None),\n            429 => {\n                RATE_LIMITED.store(true, Ordering::Relaxed);\n                warn!(\"{tool}: mise-versions rate limited\");\n                return Ok(None);\n            }\n            _ => return Err(err),\n        },\n    };\n\n    trace!(\n        \"got {} {} versions from versions host\",\n        versions.len(),\n        tool\n    );\n\n    if versions.is_empty() {\n        return Ok(None);\n    }\n\n    CACHE\n        .lock()\n        .await\n        .insert(tool.to_string(), versions.clone());\n    Ok(Some(versions))\n}\n\n/// Tracks a tool installation asynchronously (fire-and-forget)\n/// Tracks all core plugins and registry tools (including java/python)\npub fn track_install(tool: &str, full: &str, version: &str) {\n    let settings = Settings::get();\n    if settings.offline() {\n        return;\n    }\n\n    // Check if tracking is enabled (also requires use_versions_host to be enabled)\n    if !settings.use_versions_host || !settings.use_versions_host_track {\n        return;\n    }\n\n    // Only track known tools (core plugins and registry tools)\n    if !PLUGINS_TRACK_DOWNLOADS.contains(tool) {\n        return;\n    }\n\n    let tool = tool.to_string();\n    let full = full.to_string();\n    let version = version.to_string();\n\n    // Fire-and-forget: spawn a task that won't block installation\n    tokio::spawn(async move {\n        if let Err(e) = track_install_async(&tool, &full, &version).await {\n            trace!(\"Failed to track install for {tool}@{version}: {e}\");\n        }\n    });\n}\n\nasync fn track_install_async(tool: &str, full: &str, version: &str) -> eyre::Result<()> {\n    use crate::cli::version::{ARCH, OS};\n\n    let url = \"https://mise-versions.jdx.dev/api/track\";\n\n    let body = serde_json::json!({\n        \"tool\": tool,\n        \"full\": full,\n        \"version\": version,\n        \"os\": *OS,\n        \"arch\": *ARCH\n    });\n\n    match HTTP_FETCH\n        .post_json_with_headers(url, &body, &VERSIONS_HOST_HEADERS)\n        .await\n    {\n        Ok(true) => trace!(\"Tracked install: {full}@{version}\"),\n        Ok(false) => trace!(\"Track request failed\"),\n        Err(e) => trace!(\"Track request error: {e}\"),\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "src/watch_files.rs",
    "content": "use crate::cmd::cmd;\nuse crate::config::{Config, Settings};\nuse crate::dirs;\nuse crate::toolset::Toolset;\nuse eyre::Result;\nuse globset::{GlobBuilder, GlobSetBuilder};\nuse itertools::Itertools;\nuse std::iter::once;\nuse std::path::{Path, PathBuf};\nuse std::sync::Mutex;\nuse std::{collections::BTreeSet, sync::Arc};\n\n#[derive(\n    Debug, Clone, serde::Serialize, serde::Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash,\n)]\npub struct WatchFile {\n    pub patterns: Vec<String>,\n    #[serde(default)]\n    pub run: Option<String>,\n    pub task: Option<String>,\n}\n\npub static MODIFIED_FILES: Mutex<Option<BTreeSet<PathBuf>>> = Mutex::new(None);\n\npub fn add_modified_file(file: PathBuf) {\n    let mut mu = MODIFIED_FILES.lock().unwrap();\n    let set = mu.get_or_insert_with(BTreeSet::new);\n    set.insert(file);\n}\n\npub async fn execute_runs(config: &Arc<Config>, ts: &Toolset) {\n    let files = {\n        let mut mu = MODIFIED_FILES.lock().unwrap();\n        mu.take().unwrap_or_default()\n    };\n    if files.is_empty() {\n        return;\n    }\n    for (root, wf) in config.watch_file_hooks().unwrap_or_default() {\n        match has_matching_files(&root, &wf, &files) {\n            Ok(files) if files.is_empty() => {\n                continue;\n            }\n            Ok(files) => {\n                if wf.task.is_some() && wf.run.is_some() {\n                    warn!(\"watch_file hook has both run and task set, using task\");\n                }\n                let result = if let Some(task_name) = &wf.task {\n                    execute_task(config, ts, &root, task_name, files).await\n                } else if let Some(run) = &wf.run {\n                    execute(config, ts, &root, run, files).await\n                } else {\n                    warn!(\"watch_file hook has neither run nor task set, skipping\");\n                    continue;\n                };\n                if let Err(e) = result {\n                    warn!(\"error executing watch_file hook: {e}\");\n                }\n            }\n            Err(e) => {\n                warn!(\"error matching files: {e}\");\n            }\n        }\n    }\n}\n\nasync fn execute(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    root: &Path,\n    run: &str,\n    files: Vec<&PathBuf>,\n) -> Result<()> {\n    Settings::get().ensure_experimental(\"watch_file_hooks\")?;\n    let modified_files_var = files\n        .iter()\n        .map(|f| f.to_string_lossy().replace(':', \"\\\\:\"))\n        .join(\":\");\n    let shell = Settings::get().default_inline_shell()?;\n\n    let args = shell\n        .iter()\n        .skip(1)\n        .map(|s| s.as_str())\n        .chain(once(run))\n        .collect_vec();\n    let mut env = ts.full_env(config).await?;\n    env.insert(\"MISE_WATCH_FILES_MODIFIED\".to_string(), modified_files_var);\n    if let Some(cwd) = &*dirs::CWD {\n        env.insert(\n            \"MISE_ORIGINAL_CWD\".to_string(),\n            cwd.to_string_lossy().to_string(),\n        );\n    }\n    env.insert(\n        \"MISE_PROJECT_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    // TODO: this should be different but I don't have easy access to it\n    // env.insert(\"MISE_CONFIG_ROOT\".to_string(), root.to_string_lossy().to_string());\n    cmd(&shell[0], args)\n        .stdout_to_stderr()\n        // .dir(root)\n        .full_env(env)\n        .run()?;\n    Ok(())\n}\n\nasync fn execute_task(\n    config: &Arc<Config>,\n    ts: &Toolset,\n    root: &Path,\n    task_name: &str,\n    files: Vec<&PathBuf>,\n) -> Result<()> {\n    Settings::get().ensure_experimental(\"watch_file_hooks\")?;\n    let modified_files_var = files\n        .iter()\n        .map(|f| f.to_string_lossy().replace(':', \"\\\\:\"))\n        .join(\":\");\n    let mise_bin = std::env::current_exe().unwrap_or_else(|_| PathBuf::from(\"mise\"));\n\n    let mut env = ts.full_env(config).await?;\n    env.insert(\"MISE_WATCH_FILES_MODIFIED\".to_string(), modified_files_var);\n    env.insert(\"MISE_NO_HOOKS\".to_string(), \"1\".to_string());\n    if let Some(cwd) = &*dirs::CWD {\n        env.insert(\n            \"MISE_ORIGINAL_CWD\".to_string(),\n            cwd.to_string_lossy().to_string(),\n        );\n    }\n    env.insert(\n        \"MISE_PROJECT_ROOT\".to_string(),\n        root.to_string_lossy().to_string(),\n    );\n    cmd(\n        mise_bin,\n        [\"--cd\", &root.to_string_lossy(), \"run\", task_name],\n    )\n    .stdout_to_stderr()\n    .full_env(env)\n    .run()?;\n    Ok(())\n}\n\nfn has_matching_files<'a>(\n    root: &Path,\n    wf: &'a WatchFile,\n    files: &'a BTreeSet<PathBuf>,\n) -> Result<Vec<&'a PathBuf>> {\n    let mut glob = GlobSetBuilder::new();\n    for pattern in &wf.patterns {\n        match GlobBuilder::new(pattern).literal_separator(true).build() {\n            Ok(g) => {\n                glob.add(g);\n            }\n            Err(e) => {\n                warn!(\"invalid glob pattern: {e}\");\n            }\n        }\n    }\n    let glob = glob.build()?;\n    Ok(files\n        .iter()\n        .filter(|file| {\n            if let Ok(rel) = file.strip_prefix(root) {\n                !glob.matches(rel).is_empty()\n            } else {\n                false\n            }\n        })\n        .collect())\n}\n\npub fn glob(root: &Path, patterns: &[String]) -> Result<Vec<PathBuf>> {\n    if patterns.is_empty() {\n        return Ok(vec![]);\n    }\n    let opts = glob::MatchOptions {\n        require_literal_separator: true,\n        ..Default::default()\n    };\n    Ok(patterns\n        .iter()\n        .map(|pattern| root.join(pattern).to_string_lossy().to_string())\n        .filter_map(|pattern| glob::glob_with(&pattern, opts).ok())\n        .collect::<Vec<_>>()\n        .into_iter()\n        .flat_map(|paths| paths.filter_map(|p| p.ok()))\n        .collect())\n}\n"
  },
  {
    "path": "src/wildcard.rs",
    "content": "use std::str::Chars;\n\npub struct Wildcard {\n    patterns: Vec<String>,\n}\n\nimpl Wildcard {\n    pub fn new(patterns: impl IntoIterator<Item = impl Into<String>>) -> Self {\n        Self {\n            patterns: patterns.into_iter().map(Into::into).collect(),\n        }\n    }\n\n    pub fn match_any(&self, input: &str) -> bool {\n        for pattern in &self.patterns {\n            if wildcard_match_single(input, pattern) {\n                return true;\n            }\n        }\n        false\n    }\n}\n\nfn wildcard_match_single(input: &str, wildcard: &str) -> bool {\n    let mut input_chars = input.chars();\n    let mut wildcard_chars = wildcard.chars();\n\n    loop {\n        match (input_chars.next(), wildcard_chars.next()) {\n            (Some(input_char), Some(wildcard_char)) => {\n                if wildcard_char == '*' {\n                    return wildcard_match_single_star(input_chars, wildcard_chars);\n                } else if wildcard_char == '?' || input_char == wildcard_char {\n                    continue;\n                } else {\n                    return false;\n                }\n            }\n            (None, None) => return true,\n            (None, Some(wildcard_char)) => return wildcard_char == '*',\n            (Some(_), None) => return false,\n        }\n    }\n}\n\nfn wildcard_match_single_star(mut input_chars: Chars, mut wildcard_chars: Chars) -> bool {\n    loop {\n        match wildcard_chars.next() {\n            Some(wildcard_char) => {\n                if wildcard_char == '*' {\n                    continue;\n                } else {\n                    while let Some(input_char) = input_chars.next() {\n                        if wildcard_match_single(\n                            &input_char.to_string(),\n                            &wildcard_char.to_string(),\n                        ) {\n                            return wildcard_match_single_star(input_chars, wildcard_chars);\n                        }\n                    }\n                    return false;\n                }\n            }\n            None => return true,\n        }\n    }\n}\n"
  },
  {
    "path": "tasks.md",
    "content": "## `aqua-tester`\n\n- **Usage**: `aqua-tester`\n\nTest Aqua configuration with fish shell\n\n## `build`\n\n- **Usage**: `build`\n- **Aliases**: `b`\n\nBuild the project\n\n## `ci`\n\n- Depends: format, build, test\n\n- **Usage**: `ci`\n\nRun all CI checks\n\n## `clean`\n\n- **Usage**: `clean`\n\nClean build artifacts\n\n## `docs`\n\n- Depends: docs:setup\n\n- **Usage**: `docs`\n\nStart the documentation development server\n\n## `docs:build`\n\n- Depends: docs:setup\n\n- **Usage**: `docs:build`\n\nBuild the documentation site\n\n## `docs:demos`\n\n- **Usage**: `docs:demos`\n\nCreate recordings with vhs\n\n## `docs:preview`\n\n- Depends: docs:build\n\n- **Usage**: `docs:preview`\n\nPreview the documentation site\n\n## `docs:release`\n\n- Depends: docs:build\n\n- **Usage**: `docs:release`\n\nRelease documentation site to production or remote\n\n## `docs:setup`\n\n- **Usage**: `docs:setup`\n\nInstall documentation dependencies\n\n## `fetch-gpg-keys`\n\n- **Usage**: `fetch-gpg-keys`\n\nFetch GPG keys for signing or verification\n\n## `filetask`\n\n- **Usage**: `filetask [-f --force] [-u --user <user>] [file] [arg_with_default]`\n- **Aliases**: `ft`\n\nThis is a test build script\n\n### Arguments\n\n#### `[file]`\n\nThe file to write\n\n**Default:** `file.txt`\n\n#### `[arg_with_default]`\n\nAn arg with a default\n\n**Default:** `mydefault`\n\n### Flags\n\n#### `-f --force`\n\nOverwrite existing &lt;file>\n\n#### `-u --user <user>`\n\nUser to run as\n\n## `filetask.bat`\n\n- **Usage**: `filetask.bat`\n\n## `flamegraph`\n\n- **Usage**: `flamegraph`\n\nGenerate a flamegraph for performance analysis\n\n## `install-dev`\n\n- **Usage**: `install-dev`\n\nInstall the current project in debug mode\n\n## `lint`\n\n- Depends: lint:*\n\n- **Usage**: `lint`\n\nRun all lint checks\n\n## `lint-fix`\n\n- **Usage**: `lint-fix`\n- **Aliases**: `format`, `fix`\n\nAutomatically fix lint issues\n\n## `lint:hk`\n\n- **Usage**: `lint:hk`\n\nLint HK files\n\n## `pre-commit`\n\n- **Usage**: `pre-commit`\n\nRun pre-commit hooks\n\n## `release`\n\n- **Usage**: `release`\n\nRelease the project\n\n## `release-plz`\n\n- **Usage**: `release-plz`\n\nRelease with release-plz\n\n## `render`\n\n- Depends: render:*\n\n- **Usage**: `render`\n\nRun all render tasks\n\n## `render:completions`\n\n- Depends: build\n\n- **Usage**: `render:completions`\n\nGenerate shell completions\n\n## `render:fig`\n\n- Depends: docs:setup\n\n- **Usage**: `render:fig`\n\nGenerate Fig completion spec\n\n## `render:help`\n\n- Depends: build\n\n- **Usage**: `render:help`\n\nRender help documentation\n\n## `render:mangen`\n\n- Depends: render:usage\n\n- **Usage**: `render:mangen`\n\nGenerate man pages\n\n## `render:schema`\n\n- Depends: docs:setup\n\n- **Usage**: `render:schema`\n\nRender JSON schema\n\n## `render:usage`\n\n- Depends: build\n\n- **Usage**: `render:usage`\n\nGenerate usage documentation\n\n## `show-output-on-failure`\n\n- **Usage**: `show-output-on-failure`\n\nShow output on failure for documentation generation\n\n## `signal-test`\n\n- **Usage**: `signal-test`\n\nTest signal handling in Node.js\n\n## `snapshots`\n\n- **Usage**: `snapshots`\n\nupdate test snapshots\n\n## `test`\n\n- **Usage**: `test`\n- **Aliases**: `t`\n\nrun all tests\n\n## `test-tool-retry`\n\n- **Usage**: `test-tool-retry [--grace-period] <tools>…`\n\nRetry failed test-tools with grace period for recent upstream releases\n\n### Arguments\n\n#### `<tools>…`\n\nFailed tools to retry\n\n### Flags\n\n#### `--grace-period`\n\nIgnore failures from tools whose upstream released &lt;7 days ago\n\n## `test:build-perf-workspace`\n\n- **Usage**: `test:build-perf-workspace`\n\ntask description\n\n## `test:coverage`\n\n- **Usage**: `test:coverage`\n\nRun all tests with coverage report\n\n## `test:e2e`\n\n- Depends: build\n\n- **Usage**: `test:e2e`\n- **Aliases**: `e`, `e2e`\n\nRun end-to-end tests\n\n## `test:perf`\n\n- Depends: test:build-perf-workspace\n\n- **Usage**: `test:perf`\n\nRun performance tests\n\n## `test:shuffle`\n\n- **Usage**: `test:shuffle`\n\nRun tests with shuffling enabled\n\n## `test:unit`\n\n- **Usage**: `test:unit`\n\nrun unit tests\n\n## `update-descriptions`\n\n- **Usage**: `update-descriptions`\n\nUpdate all task descriptions in the project\n"
  },
  {
    "path": "tasks.toml",
    "content": "#:schema ./schema/mise-task.json\n\n[clean]\ndescription = 'Clean build artifacts'\nrun = 'cargo clean'\n\n[release]\ndescription = 'Release the project'\nrun = 'cargo release --exclude-unchanged'\n\n[signal-test]\ndescription = 'Test signal handling in Node.js'\nrun = 'node ./test/fixtures/signal-test.js'\n\n[ci]\ndepends = [\"format\", \"build\", \"test\"]\ndescription = \"Run all CI checks\"\n\n[lint]\ndescription = 'Run all lint checks'\ndepends = ['lint:*']\n\n[build]\nalias = \"b\"\nrun = \"cargo build --all-features\"\nrun_windows = \"cargo build\"\ndescription = \"Build the project\"\n#sources = [\"Cargo.*\", \"src/**/*.rs\"]\n#outputs = [\"target/debug/mise\"]\n\n[docs]\ndescription = 'Start the documentation development server'\ndepends = ['docs:setup']\nrun = \"bun run docs:dev\"\n\n[\"docs:setup\"]\ndescription = 'Install documentation dependencies'\nrun = \"bun i\"\n\n[\"docs:build\"]\ndescription = 'Build the documentation site'\ndepends = [\"docs:setup\"]\nrun = \"bun run docs:build\"\n\n[\"docs:preview\"]\ndescription = 'Preview the documentation site'\ndepends = [\"docs:build\"]\nrun = \"bun run docs:preview\"\n\n[\"docs:demos\"]\ndescription = \"Create recordings with vhs\"\ndir = \"docs\"\nrun = \"\"\"\n#!/usr/bin/env bash\n\nif ! docker info > /dev/null 2>&1; then\n  echo \"This script uses docker, and it isn't running - please start docker and try again!\"\n  exit 1\nfi\n\nvhs() {\n    docker run --rm -v $(pwd)/tapes/:/data -w /data ghcr.io/charmbracelet/vhs \"$@\"\n}\n\n# Create VHS recordings of all tape files in the assets directory\nfor i in $(ls -1 tapes/*.tape); do\n    vhs $(basename $i .tape).tape\ndone\n\"\"\"\n\n[\"render:usage\"]\ndescription = 'Generate usage documentation'\ndepends = [\"build\"]\nenv = { CLICOLOR_FORCE = \"0\" }\nrun = [\n  \"mise usage > mise.usage.kdl\",\n  \"mise generate task-docs > tasks.md\",\n  \"rm -rf docs/cli && mkdir -p docs/cli\",\n  \"usage generate markdown -m --out-dir docs/cli --url-prefix /cli --html-encode --file mise.usage.kdl --replace-pre-with-code-fences\",\n  \"markdownlint --fix docs/cli\",\n]\n\n[\"render:completions\"]\ndescription = 'Generate shell completions'\ndepends = [\"build\"]\nwait_for = [\"render:usage\"]\nenv = { NO_COLOR = \"1\" }\nrun = '''\n#!/usr/bin/env bash\nset -xeuo pipefail\nmise completion bash > completions/mise.bash\nmise completion zsh > completions/_mise\nmise completion fish > completions/mise.fish\nmise completion powershell > completions/mise.ps1\n'''\n\n[\"render:mangen\"]\ndescription = 'Generate man pages'\ndepends = [\"render:usage\"]\nenv = { NO_COLOR = \"1\" }\nrun = \"usage generate manpage --file mise.usage.kdl > man/man1/mise.1\"\n\n[\"render:fig\"]\ndescription = 'Generate Fig completion spec'\nwait_for = [\"render:completions\"]\nrun = [\n  \"usage generate fig --file mise.usage.kdl --out-file xtasks/fig/src/mise.ts\",\n  \"tsx xtasks/fig/addCustomGenerators.ts xtasks/fig/src/mise.ts xtasks/fig/src/mise.ts\",\n  \"bun run lint-fig:fix\",\n]\ndepends = ['docs:setup']\n\n[\"render:help\"]\ndescription = 'Render help documentation'\ndepends = [\"build\"]\nenv = { NO_COLOR = \"1\" }\nsources = [\"mise\"]\noutputs = [\"README.md\"]\nrun = [\n  \"mise render-help\",\n  \"mise run show-output-on-failure -- mise x node@latest -- npx markdown-magic\",\n]\n\n[render]\ndescription = 'Run all render tasks'\ndepends = [\"render:*\"]\n\n[snapshots]\ndescription = \"update test snapshots\"\nrun = \"cargo insta test --all-features --accept --unreferenced delete\"\n\n[test]\ndescription = \"run all tests\"\nalias = 't'\nrun = [\"mise tasks run test:unit\", \"mise tasks run test:e2e\"]\n\n[\"test:unit\"]\ndescription = \"run unit tests\"\nrun = \"cargo test --all-features\"\nenv = { CARGO_TERM_COLOR = \"always\", \"RUST_TEST_THREADS\" = \"1\" }\n\n[\"test:shuffle\"]\ndescription = 'Run tests with shuffling enabled'\nrun = 'cargo +nightly test --all-features -- -Z unstable-options --shuffle'\n\n[install-dev]\ndescription = 'Install the current project in debug mode'\nrun = 'cargo install --path . --debug'\n\n[xxx]\nhide = true\ntools = { gh = \"2.60.0\" }\nrun = \"echo {{arg(name='greeting')}}; sleep 2; echo 2; sleep 2; echo 3; sleep 0.4; echo 4; sleep 1\"\ndescription = \"a task for testing\"\n\n[pre-commit]\ndescription = 'Run pre-commit hooks'\nenv = { PRE_COMMIT = 1 }\nrun = [\"mise run lint\"]\n\n[flamegraph]\ndescription = 'Generate a flamegraph for performance analysis'\ntools = { \"cargo:flamegraph\" = \"latest\" }\nenv = { CARGO_PROFILE_RELEASE_DEBUG = \"true\" }\nrun = 'cargo flamegraph'\n"
  },
  {
    "path": "test/.gitignore",
    "content": "data/\n!data/plugins\ncache/\nstate/\ncwd/\ntest-build-output.txt\n"
  },
  {
    "path": "test/.test-tool-versions",
    "content": "tiny  2\ndummy ref:master\n"
  },
  {
    "path": "test/config/config.toml",
    "content": "[env]\nTEST_ENV_VAR = 'test-123'\n\n[alias.tiny.versions]\n\"my/alias\" = '3.0'\n\n[tasks.configtask]\nrun = 'echo \"configtask:\"'\n[tasks.lint]\nrun = 'echo \"linting!\"'\n[tasks.test]\nrun = 'echo \"testing!\"'\n[settings]\nalways_keep_download = true\nalways_keep_install = true\nidiomatic_version_file = true\nplugin_autoupdate_last_check_duration = \"20m\"\njobs = 2\n"
  },
  {
    "path": "test/config/settings.toml",
    "content": "experimental = true\nverbose = true\n"
  },
  {
    "path": "test/fixtures/.env2",
    "content": "export FOO2=\"foo2\"\n"
  },
  {
    "path": "test/fixtures/.mise.toml",
    "content": "[env]\nNODE_ENV = 'production'\n\n[tools]\nterraform = '1.0.0'\nnode = ['18', 'prefix:20', 'ref:master', 'path:~/.nodes/18']\njq = { prefix = '1.6' }\nshellcheck = { version = '0.9.0' }\npython = [{ version = '3.10.0', venv = '.venv' }, { version = '3.9.0' }]\n\n[plugins]\nnode = 'https://github.com/jdx/rtx-node'\n\n[settings]\nverbose = true\ndisable_tools = ['disabled_tool']\nlegacy_version_file_disable_tools = ['disabled_tool_from_legacy_file']\n\n[alias.node.versions]\nmy_custom_node = '18'\n"
  },
  {
    "path": "test/fixtures/exec-env",
    "content": "#!/usr/bin/env bash\n\nexport UNMODIFIED_VAR=\"unmodified\"\nexport UNMODIFIED_NEWLINE_VAR=\"hello\\nworld\"\nexport UNMODIFIED_SQUOTE_VAR=\"hello\\'world\"\nexport UNMODIFIED_ESCAPE_VAR=\"hello\\\\world\"\nexport MODIFIED_VAR=\"modified\"\nexport ADDED_VAR=\"added\"\nexport MULTILINE_VAR=\"line1\nline2\nline3\"\nexport ESCAPES=\"\\\\n\\\\t\\\\r\\\\v\\\\f\\\\a\\\\b\\\\e\\\\0\\\\x1b\\\\u1234\\\\U00012345\\a\\b\\e\\E\\f\\n\\r\\t\\v\\\"?\\`\\$\\g'\\0\"\nexport BELL=$'\\a'\nexport BACKSPACE=$'\\b'\nexport ESCAPE=$'\\e'\nexport ESCAPE2=$'\\E'\nexport FORM_FEED=$'\\f'\nexport NEWLINE=$'\\n'\nexport CARRIAGE_RETURN=$'\\r'\nexport TAB=$'\\t'\nexport VERTICAL_TAB=$'\\v'\nexport DOUBLE_QUOTE=$'\"'\nexport SINGLE_QUOTE=$\"'\"\nexport QUESTION_MARK=$'?'\nexport BACKTICK=$'`'\nexport DOLLAR=$'$'\nexport G=$'g'\n\n# shellcheck disable=SC2034\nunexported=\"unexported val\"\n"
  },
  {
    "path": "test/fixtures/mise-test-tool/README.md",
    "content": "# mise-test-tool\n\nA simple test tool for validating mise lockfile functionality across multiple platforms and backends.\n\n## Purpose\n\nThis tool is designed to test mise's lockfile generation and validation features by providing:\n\n- Simple Node.js CLI script (no compilation needed)\n- Multi-platform support (linux-x64, linux-arm64, macos-x64, macos-arm64, windows-x64)\n- Environment variable inspection for mise testing\n- Platform information reporting\n\n## Usage\n\n```bash\n# Direct usage\n./bin/mise-test-tool\n\n# Via mise (when integrated)\nmise use github:mise-plugins/mise-test-tool@1.0.0\nmise-test-tool\n\n# Test lockfile generation\nmise lock --platforms macos-arm64,linux-x64 github:mise-plugins/mise-test-tool\n```\n\n## Output\n\nThe tool prints:\n\n- Version information from package.json\n- Current platform (OS and architecture)\n- Command line arguments\n- MISE\\_\\* environment variables\n\n## Testing Scenarios\n\nThis tool enables testing of:\n\n- Multi-platform lockfile generation\n- Platform-specific metadata collection\n- Backend compatibility (github, ubi, aqua, http)\n- Frozen installs with lockfile validation\n- Incremental updates and platform additions\n\n## Implementation\n\n- **Main script**: `bin/mise-test-tool` (Node.js with shebang)\n- **Windows shim**: `bin/mise-test-tool.cmd` (batch file)\n- **Metadata**: `package.json` (version and package info)\n\n## Integration\n\nThis tool will be:\n\n1. Created as a separate GitHub repository: `mise-plugins/mise-test-tool`\n2. Integrated into mise via `git subtree` at `test/fixtures/mise-test-tool/`\n3. Used for comprehensive lockfile testing across all supported backends\n"
  },
  {
    "path": "test/fixtures/mise-test-tool/bin/mise-test-tool",
    "content": "#!/usr/bin/env node\n// bin/mise-test-tool\n\nconst os = require('os');\nconst process = require('process');\nconst fs = require('fs');\nconst path = require('path');\n\n// Read version from package.json\nconst packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));\n\nconsole.log(`mise-test-tool v${packageJson.version}`);\nconsole.log(`Platform: ${os.platform()}-${os.arch()}`);\nconsole.log(`Arguments: ${JSON.stringify(process.argv.slice(2))}`);\nconsole.log('Environment variables:');\n\nObject.keys(process.env)\n  .filter(key => key.startsWith('MISE_'))\n  .sort()\n  .forEach(key => {\n    console.log(`  ${key}=${process.env[key]}`);\n  });\n\nprocess.exit(0);"
  },
  {
    "path": "test/fixtures/mise-test-tool/bin/mise-test-tool.cmd",
    "content": "@echo off\nREM bin/mise-test-tool.cmd - Windows shim\nnode \"%~dp0\\mise-test-tool\" %*"
  },
  {
    "path": "test/fixtures/mise-test-tool/package.json",
    "content": "{\n  \"name\": \"mise-test-tool\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Test tool for mise lockfile development and multi-platform testing\",\n  \"main\": \"bin/mise-test-tool\",\n  \"bin\": {\n    \"mise-test-tool\": \"bin/mise-test-tool\"\n  },\n  \"scripts\": {\n    \"test\": \"node bin/mise-test-tool --version\",\n    \"release\": \"npm run release:tarball && npm run release:gh\",\n    \"release:tarball\": \"cd .. && tar -czf mise-test-tool-v$npm_package_version.tar.gz mise-test-tool/\",\n    \"release:gh\": \"gh release create v$npm_package_version --title \\\"mise-test-tool v$npm_package_version\\\" --notes \\\"Release v$npm_package_version of mise-test-tool for lockfile development and testing.\\\" ../mise-test-tool-v$npm_package_version.tar.gz\"\n  },\n  \"keywords\": [\n    \"mise\",\n    \"test\",\n    \"tool\",\n    \"lockfile\",\n    \"multi-platform\"\n  ],\n  \"author\": \"Mise Contributors\",\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=16.0.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/mise-plugins/mise-test-tool.git\"\n  },\n  \"homepage\": \"https://github.com/mise-plugins/mise-test-tool\",\n  \"bugs\": {\n    \"url\": \"https://github.com/mise-plugins/mise-test-tool/issues\"\n  }\n}\n"
  },
  {
    "path": "test/fixtures/mise.plugin.toml",
    "content": "#:schema ../../schema/mise.plugin.json\n\n[exec-env]\ncache-key = [\"{{'1234'}}\"]\n"
  },
  {
    "path": "test/fixtures/shorthands.toml",
    "content": "node = \"https://node\"\nxxxxxx = \"https://xxxxxx\"\n"
  },
  {
    "path": "test/fixtures/signal-test.js",
    "content": "let i = 3;\n\nprocess.on(\"SIGINT\", function () {\n  if (i > 0) {\n    console.log(`Got SIGINT.  Press Control-D to exit. ${i} times left`);\n    i--;\n  } else {\n    process.exit();\n  }\n});\n\n// wait for 60 seconds\nsetTimeout(function () {}, 60000);\nconsole.log(\"Running.  Press Control-C to test.\");\n"
  },
  {
    "path": "test/plugins/vfox-npm/Injection.lua",
    "content": "--[[\nDo not change any thing in the current file,\nit's just there to show what objects are injected by vfox and what they do.\n\nIt's just handy when developing plugins, IDE can use this object for code hints!\n --]]\nRUNTIME = {\n    --- Operating system type at runtime (Windows, Linux, Darwin)\n    osType = \"\",\n    --- Operating system architecture at runtime (amd64, arm64, etc.)\n    archType = \"\",\n    --- vfox runtime version\n    version = \"\",\n    --- Plugin directory\n    pluginDirPath = \"\",\n}\n"
  },
  {
    "path": "test/plugins/vfox-npm/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2025 jdx\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE. \n"
  },
  {
    "path": "test/plugins/vfox-npm/README.md",
    "content": "# vfox-npm\n\nA vfox plugin for installing npm packages as tools.\n\n## Installation\n\n```bash\nmise plugin install vfox-npm https://github.com/jdx/vfox-npm\n```\n\n## Usage\n\nThis plugin allows you to install npm packages as tools using the `vfox-npm:package` format.\n\n### Examples\n\n```bash\n# Install prettier\nmise install vfox-npm:prettier@latest\n\n# Use prettier\nmise x vfox-npm:prettier -- prettier --version\n\n# Install specific version\nmise install vfox-npm:eslint@8.0.0\n\n# List available versions\nmise ls-remote vfox-npm:prettier\n```\n\n## How it works\n\nThis plugin implements the vfox backend interface to:\n\n1. **List versions**: Fetches available versions from the npm registry\n2. **Install packages**: Uses `npm install` to install packages locally\n3. **Set environment**: Adds `node_modules/.bin` to PATH for binary access\n\n## Requirements\n\n- Node.js and npm must be installed on your system\n- This plugin requires the latest version of mise with vfox backend support\n\n## License\n\nMIT\n"
  },
  {
    "path": "test/plugins/vfox-npm/hooks/backend_exec_env.lua",
    "content": "function PLUGIN:BackendExecEnv(ctx)\n    local file = require(\"file\")\n    return {\n        env_vars = {\n            {key = \"PATH\", value = file.join_path(ctx.install_path, \"node_modules\", \".bin\")}\n        }\n    }\nend\n"
  },
  {
    "path": "test/plugins/vfox-npm/hooks/backend_install.lua",
    "content": "function PLUGIN:BackendInstall(ctx)\n    local tool = ctx.tool\n    local version = ctx.version\n    local install_path = ctx.install_path\n    \n    -- Install the package directly using npm install\n    local cmd = require(\"cmd\")\n    local npm_cmd = \"npm install \" .. tool .. \"@\" .. version .. \" --no-package-lock --no-save --silent\"\n    local result = cmd.exec(npm_cmd, {cwd = install_path})\n    \n    -- If we get here, the command succeeded\n    return {}\nend\n"
  },
  {
    "path": "test/plugins/vfox-npm/hooks/backend_list_versions.lua",
    "content": "function PLUGIN:BackendListVersions(ctx)\n    local cmd = require(\"cmd\")\n    local json = require(\"json\")\n\n    local result = cmd.exec(\"npm view \" .. ctx.tool .. \" versions --json\")\n    local versions = json.decode(result)\n    \n    return {versions = versions}\nend\n"
  },
  {
    "path": "test/plugins/vfox-npm/metadata.lua",
    "content": "--- !!! DO NOT EDIT OR RENAME !!!\nPLUGIN = {}\n\n--- !!! MUST BE SET !!!\n--- Plugin name\nPLUGIN.name = \"vfox-npm\"\n--- Plugin version\nPLUGIN.version = \"1.0.0\"\n--- Plugin homepage\nPLUGIN.homepage = \"https://github.com/jdx/vfox-npm\"\n--- Plugin license, please choose a correct license according to your needs.\nPLUGIN.license = \"MIT\"\n--- Plugin description\nPLUGIN.description = \"vfox backend plugin for npm\"\n\n-- Some things that need user to be attention!\nPLUGIN.notes = {\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/node24/tsconfig.json\",\n  \"include\": [\"**/*\"],\n  \"exclude\": [\"node_modules\"],\n  \"compilerOptions\": {\n    \"outDir\": \"./build\",\n    \"types\": [\"@withfig/autocomplete-types\", \"bun\"]\n  }\n}\n"
  },
  {
    "path": "xtasks/.hidden/bar/baz/hidden-executable",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\ncargo clippy -- -Dwarnings\ncargo fmt --all -- --check\n# shellcheck disable=SC2046\nprettier -c $(git ls-files '*.yml' '*.yaml')\nmarkdownlint .\nactionlint\n"
  },
  {
    "path": "xtasks/.hidden-executable",
    "content": "#!/usr/bin/env bash\nset -euxo pipefail\n\necho \"this should not show as a task\"\n"
  },
  {
    "path": "xtasks/aqua-tester.fish",
    "content": "#!/usr/bin/env fish\n#MISE description=\"Test Aqua configuration with fish shell\"\n\ncargo b\nalias m target/debug/mise\nm registry | grep -v '(core|ubi|aqua|vfox):' | awk '{print $1}'> tmp/missing_asdf_tools\nrm -f tmp/pairs\nfor tool in (cat tmp/missing_asdf_tools)\n     set -l aqua (cat ../mise-versions/docs/aqua-registry/all | grep \"/$tool\\$\")\n     if not test -z \"$aqua\"\n        echo \"$tool aqua:$aqua\"\n        echo \"$tool aqua:$aqua\" >> tmp/pairs\n    end\nend\nfor tool in (cat tmp/pairs | sort -R)\n    set -l tool (string split \" \" $tool)\n    set -l cmd \"m x $tool[2] -- $tool[1] -v\"\n    echo $cmd\n    set -l output (m x $tool[2] -- $tool[1] -v)\n    set -l cmd_status $status\n    if test \"$cmd_status\" = \"0\"\n       echo OK\n       rm -f \"tmp/$tool[1]\"\n       echo \"AQUA: $tool[2]\" > \"tmp/$tool[1]\"\n       echo \"COMMAND: $cmd\" >> \"tmp/$tool[1]\"\n       echo \"OUTPUT: $output\" >> \"tmp/$tool[1]\"\n    else\n        set -l cmd \"m x $tool[2] -- $tool[1] --version\"\n        echo $cmd\n        set -l output (m x $tool[2] -- $tool[1] --version)\n        set -l cmd_status $status\n        if test \"$cmd_status\" = \"0\"\n           echo OK\n           rm -f \"tmp/$tool[1]\"\n           echo \"AQUA: $tool[2]\" > \"tmp/$tool[1]\"\n           echo \"COMMAND: $cmd\" >> \"tmp/$tool[1]\"\n           echo \"OUTPUT: $output\" >> \"tmp/$tool[1]\"\n        else\n            set -l cmd \"m x $tool[2] -- $tool[1] version\"\n            echo $cmd\n            set -l output (m x $tool[2] -- $tool[1] version)\n            set -l cmd_status $status\n            if test \"$cmd_status\" = \"0\"\n               echo OK\n               rm -f \"tmp/$tool[1]\"\n               echo \"AQUA: $tool[2]\" > \"tmp/$tool[1]\"\n               echo \"COMMAND: $cmd\" >> \"tmp/$tool[1]\"\n               echo \"OUTPUT: $output\" >> \"tmp/$tool[1]\"\n            else\n                echo FAIL $cmd_status\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "xtasks/docs/release",
    "content": "#!/usr/bin/env bash\nset -xeuo pipefail\n#MISE depends=[\"docs:build\"]\n#MISE dir=\"docs\"\n#MISE description=\"Release documentation site to production or remote\"\n\naws --version\nexport AWS_REGION=auto\nexport AWS_ENDPOINT_URL=https://6e243906ff257b965bcae8025c2fc344.r2.cloudflarestorage.com\n\nif [ \"${DRY_RUN:-true}\" = \"true\" ]; then\n\taws() {\n\t\techo \"DRY RUN: aws $*\"\n\t}\nfi\n\nif [ $((RANDOM % 30)) -eq 0 ]; then\n\t# delete old assets only roughly 1/30 times\n\t# deleting old assets can break the site for people currently on it\n\t# but it's also good to keep things tidy\n\taws s3 rm --recursive s3://mise/assets/\n\taws s3 rm --recursive --exclude \"*\" --include \"*.html\" s3://mise/\nfi\n\naws s3 cp --recursive --checksum-algorithm CRC32 .vitepress/dist s3://mise/\n"
  },
  {
    "path": "xtasks/fetch-gpg-keys",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Fetch GPG keys for signing or verification\"\n# shellcheck disable=SC2129\nset -euxo pipefail\n\n# Fetch all Node.js release keys from the official nodejs/release-keys repository\n# This includes all current and legacy release maintainer keys\nrm -rf src/assets/gpg\nmkdir -p src/assets/gpg\n\n# Download each key file from nodejs/release-keys repository\nNODE_KEYS_URL=\"https://raw.githubusercontent.com/nodejs/release-keys/main/keys\"\nNODE_KEYS_LIST_URL=\"https://raw.githubusercontent.com/nodejs/release-keys/main/keys.list\"\n\necho \"Fetching Node.js release keys list...\"\nif ! keys_list=$(curl -fsSL \"$NODE_KEYS_LIST_URL\"); then\n\techo \"ERROR: Failed to download keys.list from nodejs/release-keys\" >&2\n\texit 1\nfi\n\nkey_count=0\nfor fingerprint in $keys_list; do\n\techo \"Fetching key: $fingerprint\"\n\tif ! curl -fLSs \"${NODE_KEYS_URL}/${fingerprint}.asc\" >>\"src/assets/gpg/node.asc\"; then\n\t\techo \"ERROR: Failed to download key $fingerprint\" >&2\n\t\texit 1\n\tfi\n\techo \"\" >>\"src/assets/gpg/node.asc\"\n\tkey_count=$((key_count + 1))\ndone\necho \"Successfully fetched $key_count Node.js release keys\"\n\n# Swift release keys\nSWIFT_KEYS=(\n\t\"https://swift.org/keys/automatic-signing-key-4.asc\"\n\t\"https://swift.org/keys/release-key-swift-5.x.asc\"\n\t\"https://swift.org/keys/release-key-swift-6.x.asc\"\n)\nfor url in \"${SWIFT_KEYS[@]}\"; do\n\techo \"Fetching Swift key: $url\"\n\tif ! curl -fLSs --compressed \"$url\" >>src/assets/gpg/swift.asc; then\n\t\techo \"ERROR: Failed to download $url\" >&2\n\t\texit 1\n\tfi\n\techo \"\" >>src/assets/gpg/swift.asc\ndone\necho \"Successfully fetched ${#SWIFT_KEYS[@]} Swift release keys\"\n"
  },
  {
    "path": "xtasks/fig/.gitignore",
    "content": "build/\n"
  },
  {
    "path": "xtasks/fig/addCustomGenerators.ts",
    "content": "import * as fsAsync from \"node:fs/promises\";\nimport * as ts from \"typescript\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\ntype GeneratorIdentifier = {\n  identifier: string;\n  generator_name: string;\n};\n\nconst customGenerators: GeneratorIdentifier[] = [\n  {\n    identifier: \"alias\",\n    generator_name: \"aliasGenerator\",\n  },\n  {\n    identifier: \"shell_alias\",\n    generator_name: \"shellAliasGenerator\",\n  },\n  {\n    identifier: \"plugin\",\n    generator_name: \"pluginGenerator\",\n  },\n  {\n    identifier: \"all_plugins\",\n    generator_name: \"allPluginsGenerator\",\n  },\n  {\n    identifier: \"task\",\n    generator_name: \"simpleTaskGenerator\",\n  },\n  {\n    identifier: \"tasks\",\n    generator_name: \"simpleTaskGenerator\",\n  },\n  {\n    identifier: \"setting\",\n    generator_name: \"settingsGenerator\",\n  },\n  {\n    identifier: \"tool@version\",\n    generator_name: \"toolVersionGenerator\",\n  },\n  {\n    identifier: \"installed_tool@version\",\n    generator_name: \"installedToolVersionGenerator\",\n  },\n  {\n    identifier: \"config_file\",\n    generator_name: \"configPathGenerator\",\n  },\n  {\n    identifier: \"env_vars\",\n    generator_name: \"envVarGenerator\",\n  },\n  {\n    identifier: \"tool@version\",\n    generator_name: \"toolVersionGenerator\",\n  },\n];\n\nconst get_object_literal_name = (node: ts.Node): string => {\n  if (node.kind !== ts.SyntaxKind.ObjectLiteralExpression) {\n    throw \"Not an Object Literal Expr\";\n  }\n\n  const objectLiteralExpr = node as ts.ObjectLiteralExpression;\n  let name = \"\";\n\n  const properties = objectLiteralExpr.properties;\n  properties.forEach((p) => {\n    if (ts.isPropertyAssignment(p) && p.name.getText() == '\"name\"') {\n      const value = p.getChildAt(2);\n      name = value.getText().replaceAll('\"', \"\");\n    }\n  });\n\n  return name;\n};\n\nconst get_identifier = (node: ts.Node): ts.Identifier | undefined => {\n  let name = \"\";\n\n  const objectLiteralExpr = node as ts.ObjectLiteralExpression;\n  const properties = objectLiteralExpr.properties;\n  properties.forEach((p) => {\n    if (ts.isPropertyAssignment(p) && p.name.getText() == '\"name\"') {\n      const value = p.getChildAt(2);\n      name = value.getText().replaceAll('\"', \"\");\n    }\n  });\n\n  const custom = customGenerators\n    .filter((g) => {\n      if (name === g.identifier) {\n        return true;\n        //\n      }\n    })\n    .map((g) => ts.factory.createIdentifier(g.generator_name));\n\n  if (custom.length > 0) return custom[0];\n  return;\n};\n\nconst has_property = (node: ts.Node, propertyName: string): boolean => {\n  if (node.kind !== ts.SyntaxKind.ObjectLiteralExpression) {\n    return false;\n  }\n\n  const objectLiteralExpr = node as ts.ObjectLiteralExpression;\n  const properties = objectLiteralExpr.properties;\n  return properties.some(\n    (p) => ts.isPropertyAssignment(p) && p.name.getText() === propertyName\n  );\n};\n\nfunction transformer<T extends ts.Node>(context: ts.TransformationContext) {\n  return (rootNode: T) => {\n    function visit(node: ts.Node): ts.Node {\n      if (\n        ts.isPropertyAssignment(node) &&\n        node.name.getText() === '\"generators\"'\n      ) {\n        const id = get_identifier(node.parent);\n        if (id) {\n          return ts.factory.updatePropertyAssignment(node, node.name, id);\n        }\n      }\n      const newNode = ts.visitEachChild(node, visit, context);\n      // Add generators to objects that should have them but don't\n      if (\n        newNode &&\n        has_property(newNode, '\"name\"') &&\n        has_property(newNode, '\"description\"') &&\n        !has_property(newNode, '\"generators\"') &&\n        !has_property(newNode, '\"subcommands\"') &&\n        !has_property(newNode, '\"options\"')\n      ) {\n        const id = get_identifier(newNode);\n        if (id) {\n          const objLiteralExpr = newNode as ts.ObjectLiteralExpression;\n          const generatorsProperty = ts.factory.createPropertyAssignment(\n            '\"generators\"',\n            id\n          );\n          const debounceProperty = ts.factory.createPropertyAssignment(\n            '\"debounce\"',\n            ts.factory.createIdentifier(\"true\")\n          );\n          return ts.factory.updateObjectLiteralExpression(objLiteralExpr, [\n            ...objLiteralExpr.properties,\n            generatorsProperty,\n            debounceProperty,\n          ]);\n        }\n      }\n      if (\n        newNode &&\n        has_property(newNode, '\"generators\"') &&\n        !has_property(newNode, '\"debounce\"')\n      ) {\n        const objLiteralExpr = newNode as ts.ObjectLiteralExpression;\n        const debounceProperty = ts.factory.createPropertyAssignment(\n          '\"debounce\"',\n          ts.factory.createIdentifier(\"true\")\n        );\n        return ts.factory.updateObjectLiteralExpression(objLiteralExpr, [\n          ...objLiteralExpr.properties,\n          debounceProperty,\n        ]);\n      }\n      return newNode;\n    }\n    return ts.visitNode(rootNode, visit);\n  };\n}\n\nconst main = async (fileName: string, outFile?: string) => {\n  try {\n    const generatorFileContents = (\n      await fsAsync.readFile(path.join(__dirname, \"generators.ts\"))\n    ).toString();\n    const contents = (await fsAsync.readFile(fileName)).toString();\n    const sourceFile = ts.createSourceFile(\n      \"example.ts\",\n      contents,\n      ts.ScriptTarget.Latest,\n      true\n    );\n    const result = ts.transform(sourceFile, [transformer]);\n    const transformedSourceFile = result.transformed[0];\n\n    const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n    const output = printer.printNode(\n      ts.EmitHint.Unspecified,\n      transformedSourceFile,\n      sourceFile\n    );\n\n    fsAsync.writeFile(\n      outFile ?? `${fileName.replace(\".ts\", \"\")}.out.ts`,\n      generatorFileContents + \"\\n\" + output\n    );\n  } catch (e) {\n    console.error(e);\n  }\n};\n\nmain(process.argv[2], process.argv[3]);\n"
  },
  {
    "path": "xtasks/fig/generators.ts",
    "content": "// If not being published, these need to manually downloaded from https://github.com/withfig/autocomplete/tree/master/src\n/* eslint-disable @withfig/fig-linter/conventional-descriptions */\nimport { createNpmSearchHandler } from \"./npm\";\nimport { searchGenerator as createCargoSearchGenerator } from \"./cargo\";\n\nconst singleCmdNewLineGenerator = (completion_cmd: string): Fig.Generator => ({\n  script: completion_cmd.split(\" \"),\n  splitOn: \"\\n\",\n});\n\nconst singleCmdJsonGenerator = (cmd: string): Fig.Generator => ({\n  script: cmd.split(\" \"),\n  postProcess: (out) =>\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    JSON.parse(out).map((r: any) => ({\n      name: r.name,\n      description: r.description,\n    })),\n});\n\nconst contextualGeneratorLastWord = (cmd: string): Fig.Generator => ({\n  script: (context) => {\n    if (context.length < 2) {\n      return [];\n    }\n\n    const prev = context[context.length - 2]; // -1 is the current word\n    return [\"sh\", \"-c\", [cmd, prev].join(\" \")];\n  },\n});\n\nconst aliasGenerator: Fig.Generator = {\n  ...contextualGeneratorLastWord(\"mise alias ls\"),\n  postProcess: (out) => {\n    //return [{name: out}]\n    //return out.split('\\t').map(l => ({name: l}))\n    //return [{name: \"test\", \"description\": out}]\n    const tokens = out.split(/\\s+/);\n    if (tokens.length == 0) return [];\n\n    return tokens\n      .flatMap((_, i) => {\n        if (i % 3 == 0) {\n          return [tokens[i + 1]];\n        }\n        return [];\n      })\n      .filter((l) => l.trim().length > 0)\n      .map((l) => ({ name: l.trim() }));\n  },\n};\n\nconst shellAliasGenerator: Fig.Generator = {\n  script: [\"sh\", \"-c\", \"mise shell-alias ls --no-header\"],\n  postProcess: (out) => {\n    if (!out.trim()) return [];\n    return out\n      .split(\"\\n\")\n      .filter((l) => l.trim().length > 0)\n      .map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[0], description: tokens.slice(1).join(\" \") };\n      });\n  },\n};\n\nconst pluginWithAlias: Fig.Generator = {\n  script: \"mise alias ls\".split(\" \"),\n  postProcess: (output: string) => {\n    const plugins = output.split(\"\\n\").map((line) => {\n      const tokens = line.split(/\\s+/);\n      return tokens[0];\n    });\n    return [...new Set(plugins)].map((p) => ({ name: p }));\n  },\n};\n\nconst getInstalledTools = async (\n  executeShellCommand: Fig.ExecuteCommandFunction\n) => {\n  const { stdout } = await executeShellCommand({\n    command: \"sh\",\n    args: [\"-c\", \"mise ls --installed\"],\n  });\n  return [\n    ...new Set(\n      stdout.split(\"\\n\").map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[0], version: tokens[1] };\n      })\n    ),\n  ];\n};\n\ntype ConfigLsOutput = {\n  path: string;\n  tools: string[];\n};\n\nconst configPathGenerator: Fig.Generator = {\n  ...singleCmdJsonGenerator(\"mise config ls -J\"),\n  postProcess: (out) =>\n    JSON.parse(out).map((r: ConfigLsOutput) => ({\n      name: r.path,\n      description: r.path,\n    })),\n};\n\ntype ObjectKeyType = string | symbol | number;\ntype ObjectAcceptableKeyValues = {\n  [key: string]: ObjectKeyType;\n};\n\nfunction groupBy<T extends ObjectAcceptableKeyValues>(\n  array: T[],\n  key: keyof T\n): Record<T[keyof T], T[]> {\n  return array.reduce(\n    (result, currentItem) => {\n      (result[currentItem[key] as ObjectKeyType] =\n        result[currentItem[key] as ObjectKeyType] || []).push(currentItem);\n      return result;\n    },\n    {} as Record<ObjectKeyType, T[]>\n  );\n}\n\nconst installedToolsGenerator: Fig.Generator = {\n  script: [\"sh\", \"-c\", \"mise ls --installed\"],\n  postProcess: (stdout: string) => {\n    return [\n      ...new Set(\n        stdout.split(\"\\n\").map((l) => {\n          const tokens = l.split(/\\s+/);\n          return { name: tokens[0], version: tokens[1] };\n        })\n      ),\n    ];\n  },\n};\n\nconst pluginGenerator: Fig.Generator = installedToolsGenerator;\nconst allPluginsGenerator: Fig.Generator =\n  singleCmdNewLineGenerator(\"mise plugins --all\");\nconst simpleTaskGenerator = singleCmdJsonGenerator(\"mise tasks -J\");\nconst settingsGenerator = singleCmdNewLineGenerator(`mise settings --keys`);\n\nconst atsInStr = (s: string) => (s.match(/@/g) || []).length != 0;\nconst backendSepInStr = (s: string) => (s.match(/:/g) || []).length != 0;\n\ntype GitHubRepoInfo = {\n  name: string;\n  full_name: string;\n  description: string;\n};\n\ntype GitHubAssetInfo = {\n  url: string;\n  uploader: object;\n  download_count: number;\n  state: string;\n};\ntype GitHubVersionInfo = {\n  assets: string[];\n  tag_name: string;\n  draft: boolean;\n  body: string; // Markdown\n};\n\nconst searchGitHub = async (\n  package_name: string,\n  executeShellCommand: Fig.ExecuteCommandFunction,\n  shellContext: Fig.GeneratorContext\n): Promise<Fig.Suggestion[]> => {\n  const query = [\n    \"-H\",\n    \"Accept: application/vnd.github+json\",\n    \"-H\",\n    \"X-GitHub-Api-Version: 2022-11-28\",\n  ];\n\n  const generalUrl =\n    \"https://api.github.com/search/repositories?q=$NAME$+in:name\";\n  const versionsUrl = \"https://api.github.com/repos/$FULL_NAME$/releases\";\n\n  try {\n    const envs = (\n      await executeShellCommand({\n        command: envVarGenerator.script[0],\n        args: envVarGenerator.script.slice(1),\n      })\n    ).stdout\n      .split(\"\\n\")\n      .map((l) => ({\n        name: l.split(\"=\")[0].trim(),\n        value: l.split(\"=\")[1].trim(),\n      }));\n\n    const gh_token = envs.find((v) => v.name == \"GITHUB_TOKEN\");\n    if (gh_token) {\n      query.push(\"-H\");\n      query.push(\"Authorization: Bearer $TOKEN$\");\n      query[query.length - 1] = query[query.length - 1].replace(\n        \"$TOKEN$\",\n        gh_token.value\n      );\n    }\n\n    const url =\n      package_name[package_name.length - 1] === \"@\" ? versionsUrl : generalUrl;\n    query.push(url);\n    query[query.length - 1] = query[query.length - 1].replace(\n      \"$NAME$\",\n      package_name\n    );\n    query[query.length - 1] = query[query.length - 1].replace(\n      \"$FULL_NAME$\",\n      package_name.slice(0, package_name.length - 1)\n    );\n\n    const { stdout } = await executeShellCommand({\n      command: \"curl\",\n      args: query,\n    });\n\n    if (package_name[package_name.length - 1] === \"@\") {\n      const package_real_name = package_name.slice(0, package_name.length - 1);\n      return [\n        ...new Set(\n          (JSON.parse(stdout) as GitHubVersionInfo[])\n            .filter((e) => e.assets.length > 0)\n            .slice(0, 200)\n            .map((e) => ({\n              name: `${package_real_name}@${e.tag_name}`,\n              description: e.body,\n            }))\n        ),\n      ];\n    } else {\n      return [\n        ...new Set(\n          (JSON.parse(stdout).items as GitHubRepoInfo[]).slice(0, 200).map(\n            (entry) =>\n              ({\n                name: entry.full_name,\n                displayName: entry.name,\n                description: entry.description,\n              }) as Fig.Suggestion\n          )\n        ),\n      ];\n    }\n  } catch (error) {\n    return [{ name: \"error\", description: error as string }];\n  }\n};\n\nconst searchBackend = async (\n  backend: string,\n  context: string[],\n  executeShellCommand: Fig.ExecuteCommandFunction,\n  shellContext: Fig.GeneratorContext\n): Promise<Fig.Suggestion[]> => {\n  const customContext = context;\n  customContext[context.length - 1] = customContext[context.length - 1].replace(\n    `${backend}:`,\n    \"\"\n  );\n  switch (backend) {\n    case \"npm\":\n      return await createNpmSearchHandler()(\n        context,\n        executeShellCommand,\n        shellContext\n      );\n    case \"cargo\":\n      return await createCargoSearchGenerator.custom(\n        customContext,\n        executeShellCommand,\n        shellContext\n      );\n    case \"asdf\":\n      const { stdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", \"mise registry\"],\n      });\n      return [\n        ...new Set(\n          stdout.split(\"\\n\").map((l) => {\n            const tokens = l.split(/\\s+/);\n            return { name: tokens[1].replace(`${backend}:`, \"\") };\n          })\n        ),\n      ];\n    case \"ubi\":\n      return await searchGitHub(\n        customContext[customContext.length - 1],\n        executeShellCommand,\n        shellContext\n      );\n    default:\n      return [];\n  }\n};\n\nconst compareVersions = (a: string, b: string): number => {\n  const result = [a, b].sort(); // Unless we can add semversort\n  if (result[0] != a) return 1;\n  return -1;\n};\n\nconst getBackends = async (\n  executeShellCommand: Fig.ExecuteCommandFunction\n): Promise<string[]> => {\n  const { stdout, stderr, status } = await executeShellCommand({\n    command: \"sh\",\n    args: [\"-c\", \"mise backends ls\"],\n  });\n  if (status != 0) {\n    return [stderr];\n  }\n  return [stdout];\n};\n\nconst toolVersionGenerator: Fig.Generator = {\n  trigger: (newToken: string, oldToken: string): boolean => {\n    return (\n      (backendSepInStr(newToken) && !backendSepInStr(oldToken)) ||\n      (atsInStr(newToken) && !atsInStr(oldToken))\n    );\n  },\n  getQueryTerm: \"@\",\n\n  custom: async (\n    context: string[],\n    executeShellCommand: Fig.ExecuteCommandFunction,\n    shellContext: Fig.GeneratorContext\n  ): Promise<Fig.Suggestion[]> => {\n    const currentWord = context[context.length - 1];\n    if (backendSepInStr(currentWord)) {\n      // Let's handle backends\n      const backend = currentWord.slice(0, currentWord.lastIndexOf(\":\"));\n\n      return (\n        await searchBackend(backend, context, executeShellCommand, shellContext)\n      ).map((s) => ({\n        ...s,\n        name: `${backend}:${s.name}`,\n        displayName: s.name as string,\n        icon: \"📦\",\n      }));\n    } else if (atsInStr(currentWord)) {\n      const tool = currentWord.slice(0, currentWord.lastIndexOf(\"@\"));\n      const { stdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise ls-remote ${tool}`],\n      });\n      const remote_versions_suggestions = stdout\n        .split(\"\\n\")\n        .sort((a, b) => compareVersions(b, a))\n        .map((l) => ({ name: l }));\n      const { stdout: aliasStdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise alias ls ${tool}`],\n      });\n      const aliases_suggestions = aliasStdout.split(\"\\n\").map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[1] };\n      });\n      return [...aliases_suggestions, ...remote_versions_suggestions];\n    }\n\n    const { stdout: registryStdout } = await executeShellCommand({\n      command: \"sh\",\n      args: [\"-c\", \"mise registry\"],\n    });\n    const registrySuggestions = [\n      ...new Set(\n        registryStdout.split(\"\\n\").map((l) => {\n          const tokens = l.split(/\\s+/);\n          return { name: tokens[0], description: tokens[1] };\n        })\n      ),\n    ];\n\n    const backendSuggestions = (await getBackends(executeShellCommand)).map(\n      (backend) => ({ name: backend, description: \"Backend\" })\n    );\n    return [...backendSuggestions, ...registrySuggestions];\n  },\n};\n\nconst installedToolVersionGenerator: Fig.Generator = {\n  trigger: \"@\",\n  getQueryTerm: \"@\",\n  custom: async (\n    context: string[],\n    executeShellCommand: Fig.ExecuteCommandFunction\n  ) => {\n    const tools = await getInstalledTools(executeShellCommand);\n    const toolsVersions = groupBy(tools, \"name\");\n\n    const currentWord = context[context.length - 1];\n    if (atsInStr(currentWord)) {\n      const tool = currentWord.slice(0, currentWord.lastIndexOf(\"@\"));\n\n      const { stdout: aliasStdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise alias ls ${tool}`],\n      });\n\n      // This lists all aliases even if they are not installed\n      /*\n      const aliases_suggestions = aliasStdout.split('\\n').map(l => {\n        const tokens = l.split(/\\s+/)\n        return {name: tokens[1], description: tokens[2]}\n      }) as Fig.Suggestion[]\n      */\n\n      const toolVersions = (toolsVersions[tool] || []) as {\n        name: string;\n        version: string;\n      }[];\n      const suggestions = toolVersions.map((s) => ({\n        name: s.version,\n      })) as Fig.Suggestion[];\n\n      return [...suggestions];\n    }\n\n    const suggestions: Fig.Suggestion[] = [];\n    Object.keys(toolsVersions).forEach((k) => {\n      if (toolsVersions[k].length == 1) {\n        suggestions.push({ name: k });\n      } else {\n        suggestions.push({ name: `${k}@` });\n      }\n    });\n\n    return suggestions;\n  },\n};\n"
  },
  {
    "path": "xtasks/fig/src/.gitignore",
    "content": ""
  },
  {
    "path": "xtasks/fig/src/mise.ts",
    "content": "// If not being published, these need to manually downloaded from https://github.com/withfig/autocomplete/tree/master/src\n/* eslint-disable @withfig/fig-linter/conventional-descriptions */\nimport { createNpmSearchHandler } from \"./npm\";\nimport { searchGenerator as createCargoSearchGenerator } from \"./cargo\";\n\nconst singleCmdNewLineGenerator = (completion_cmd: string): Fig.Generator => ({\n  script: completion_cmd.split(\" \"),\n  splitOn: \"\\n\",\n});\n\nconst singleCmdJsonGenerator = (cmd: string): Fig.Generator => ({\n  script: cmd.split(\" \"),\n  postProcess: (out) =>\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    JSON.parse(out).map((r: any) => ({\n      name: r.name,\n      description: r.description,\n    })),\n});\n\nconst contextualGeneratorLastWord = (cmd: string): Fig.Generator => ({\n  script: (context) => {\n    if (context.length < 2) {\n      return [];\n    }\n\n    const prev = context[context.length - 2]; // -1 is the current word\n    return [\"sh\", \"-c\", [cmd, prev].join(\" \")];\n  },\n});\n\nconst aliasGenerator: Fig.Generator = {\n  ...contextualGeneratorLastWord(\"mise alias ls\"),\n  postProcess: (out) => {\n    //return [{name: out}]\n    //return out.split('\\t').map(l => ({name: l}))\n    //return [{name: \"test\", \"description\": out}]\n    const tokens = out.split(/\\s+/);\n    if (tokens.length == 0) return [];\n\n    return tokens\n      .flatMap((_, i) => {\n        if (i % 3 == 0) {\n          return [tokens[i + 1]];\n        }\n        return [];\n      })\n      .filter((l) => l.trim().length > 0)\n      .map((l) => ({ name: l.trim() }));\n  },\n};\n\nconst shellAliasGenerator: Fig.Generator = {\n  script: [\"sh\", \"-c\", \"mise shell-alias ls --no-header\"],\n  postProcess: (out) => {\n    if (!out.trim()) return [];\n    return out\n      .split(\"\\n\")\n      .filter((l) => l.trim().length > 0)\n      .map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[0], description: tokens.slice(1).join(\" \") };\n      });\n  },\n};\n\nconst pluginWithAlias: Fig.Generator = {\n  script: \"mise alias ls\".split(\" \"),\n  postProcess: (output: string) => {\n    const plugins = output.split(\"\\n\").map((line) => {\n      const tokens = line.split(/\\s+/);\n      return tokens[0];\n    });\n    return [...new Set(plugins)].map((p) => ({ name: p }));\n  },\n};\n\nconst getInstalledTools = async (\n  executeShellCommand: Fig.ExecuteCommandFunction\n) => {\n  const { stdout } = await executeShellCommand({\n    command: \"sh\",\n    args: [\"-c\", \"mise ls --installed\"],\n  });\n  return [\n    ...new Set(\n      stdout.split(\"\\n\").map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[0], version: tokens[1] };\n      })\n    ),\n  ];\n};\n\ntype ConfigLsOutput = {\n  path: string;\n  tools: string[];\n};\n\nconst configPathGenerator: Fig.Generator = {\n  ...singleCmdJsonGenerator(\"mise config ls -J\"),\n  postProcess: (out) =>\n    JSON.parse(out).map((r: ConfigLsOutput) => ({\n      name: r.path,\n      description: r.path,\n    })),\n};\n\ntype ObjectKeyType = string | symbol | number;\ntype ObjectAcceptableKeyValues = {\n  [key: string]: ObjectKeyType;\n};\n\nfunction groupBy<T extends ObjectAcceptableKeyValues>(\n  array: T[],\n  key: keyof T\n): Record<T[keyof T], T[]> {\n  return array.reduce(\n    (result, currentItem) => {\n      (result[currentItem[key] as ObjectKeyType] =\n        result[currentItem[key] as ObjectKeyType] || []).push(currentItem);\n      return result;\n    },\n    {} as Record<ObjectKeyType, T[]>\n  );\n}\n\nconst installedToolsGenerator: Fig.Generator = {\n  script: [\"sh\", \"-c\", \"mise ls --installed\"],\n  postProcess: (stdout: string) => {\n    return [\n      ...new Set(\n        stdout.split(\"\\n\").map((l) => {\n          const tokens = l.split(/\\s+/);\n          return { name: tokens[0], version: tokens[1] };\n        })\n      ),\n    ];\n  },\n};\n\nconst pluginGenerator: Fig.Generator = installedToolsGenerator;\nconst allPluginsGenerator: Fig.Generator =\n  singleCmdNewLineGenerator(\"mise plugins --all\");\nconst simpleTaskGenerator = singleCmdJsonGenerator(\"mise tasks -J\");\nconst settingsGenerator = singleCmdNewLineGenerator(`mise settings --keys`);\n\nconst atsInStr = (s: string) => (s.match(/@/g) || []).length != 0;\nconst backendSepInStr = (s: string) => (s.match(/:/g) || []).length != 0;\n\ntype GitHubRepoInfo = {\n  name: string;\n  full_name: string;\n  description: string;\n};\n\ntype GitHubAssetInfo = {\n  url: string;\n  uploader: object;\n  download_count: number;\n  state: string;\n};\ntype GitHubVersionInfo = {\n  assets: string[];\n  tag_name: string;\n  draft: boolean;\n  body: string; // Markdown\n};\n\nconst searchGitHub = async (\n  package_name: string,\n  executeShellCommand: Fig.ExecuteCommandFunction,\n  shellContext: Fig.GeneratorContext\n): Promise<Fig.Suggestion[]> => {\n  const query = [\n    \"-H\",\n    \"Accept: application/vnd.github+json\",\n    \"-H\",\n    \"X-GitHub-Api-Version: 2022-11-28\",\n  ];\n\n  const generalUrl =\n    \"https://api.github.com/search/repositories?q=$NAME$+in:name\";\n  const versionsUrl = \"https://api.github.com/repos/$FULL_NAME$/releases\";\n\n  try {\n    const envs = (\n      await executeShellCommand({\n        command: envVarGenerator.script[0],\n        args: envVarGenerator.script.slice(1),\n      })\n    ).stdout\n      .split(\"\\n\")\n      .map((l) => ({\n        name: l.split(\"=\")[0].trim(),\n        value: l.split(\"=\")[1].trim(),\n      }));\n\n    const gh_token = envs.find((v) => v.name == \"GITHUB_TOKEN\");\n    if (gh_token) {\n      query.push(\"-H\");\n      query.push(\"Authorization: Bearer $TOKEN$\");\n      query[query.length - 1] = query[query.length - 1].replace(\n        \"$TOKEN$\",\n        gh_token.value\n      );\n    }\n\n    const url =\n      package_name[package_name.length - 1] === \"@\" ? versionsUrl : generalUrl;\n    query.push(url);\n    query[query.length - 1] = query[query.length - 1].replace(\n      \"$NAME$\",\n      package_name\n    );\n    query[query.length - 1] = query[query.length - 1].replace(\n      \"$FULL_NAME$\",\n      package_name.slice(0, package_name.length - 1)\n    );\n\n    const { stdout } = await executeShellCommand({\n      command: \"curl\",\n      args: query,\n    });\n\n    if (package_name[package_name.length - 1] === \"@\") {\n      const package_real_name = package_name.slice(0, package_name.length - 1);\n      return [\n        ...new Set(\n          (JSON.parse(stdout) as GitHubVersionInfo[])\n            .filter((e) => e.assets.length > 0)\n            .slice(0, 200)\n            .map((e) => ({\n              name: `${package_real_name}@${e.tag_name}`,\n              description: e.body,\n            }))\n        ),\n      ];\n    } else {\n      return [\n        ...new Set(\n          (JSON.parse(stdout).items as GitHubRepoInfo[]).slice(0, 200).map(\n            (entry) =>\n              ({\n                name: entry.full_name,\n                displayName: entry.name,\n                description: entry.description,\n              }) as Fig.Suggestion\n          )\n        ),\n      ];\n    }\n  } catch (error) {\n    return [{ name: \"error\", description: error as string }];\n  }\n};\n\nconst searchBackend = async (\n  backend: string,\n  context: string[],\n  executeShellCommand: Fig.ExecuteCommandFunction,\n  shellContext: Fig.GeneratorContext\n): Promise<Fig.Suggestion[]> => {\n  const customContext = context;\n  customContext[context.length - 1] = customContext[context.length - 1].replace(\n    `${backend}:`,\n    \"\"\n  );\n  switch (backend) {\n    case \"npm\":\n      return await createNpmSearchHandler()(\n        context,\n        executeShellCommand,\n        shellContext\n      );\n    case \"cargo\":\n      return await createCargoSearchGenerator.custom(\n        customContext,\n        executeShellCommand,\n        shellContext\n      );\n    case \"asdf\":\n      const { stdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", \"mise registry\"],\n      });\n      return [\n        ...new Set(\n          stdout.split(\"\\n\").map((l) => {\n            const tokens = l.split(/\\s+/);\n            return { name: tokens[1].replace(`${backend}:`, \"\") };\n          })\n        ),\n      ];\n    case \"ubi\":\n      return await searchGitHub(\n        customContext[customContext.length - 1],\n        executeShellCommand,\n        shellContext\n      );\n    default:\n      return [];\n  }\n};\n\nconst compareVersions = (a: string, b: string): number => {\n  const result = [a, b].sort(); // Unless we can add semversort\n  if (result[0] != a) return 1;\n  return -1;\n};\n\nconst getBackends = async (\n  executeShellCommand: Fig.ExecuteCommandFunction\n): Promise<string[]> => {\n  const { stdout, stderr, status } = await executeShellCommand({\n    command: \"sh\",\n    args: [\"-c\", \"mise backends ls\"],\n  });\n  if (status != 0) {\n    return [stderr];\n  }\n  return [stdout];\n};\n\nconst toolVersionGenerator: Fig.Generator = {\n  trigger: (newToken: string, oldToken: string): boolean => {\n    return (\n      (backendSepInStr(newToken) && !backendSepInStr(oldToken)) ||\n      (atsInStr(newToken) && !atsInStr(oldToken))\n    );\n  },\n  getQueryTerm: \"@\",\n\n  custom: async (\n    context: string[],\n    executeShellCommand: Fig.ExecuteCommandFunction,\n    shellContext: Fig.GeneratorContext\n  ): Promise<Fig.Suggestion[]> => {\n    const currentWord = context[context.length - 1];\n    if (backendSepInStr(currentWord)) {\n      // Let's handle backends\n      const backend = currentWord.slice(0, currentWord.lastIndexOf(\":\"));\n\n      return (\n        await searchBackend(backend, context, executeShellCommand, shellContext)\n      ).map((s) => ({\n        ...s,\n        name: `${backend}:${s.name}`,\n        displayName: s.name as string,\n        icon: \"📦\",\n      }));\n    } else if (atsInStr(currentWord)) {\n      const tool = currentWord.slice(0, currentWord.lastIndexOf(\"@\"));\n      const { stdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise ls-remote ${tool}`],\n      });\n      const remote_versions_suggestions = stdout\n        .split(\"\\n\")\n        .sort((a, b) => compareVersions(b, a))\n        .map((l) => ({ name: l }));\n      const { stdout: aliasStdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise alias ls ${tool}`],\n      });\n      const aliases_suggestions = aliasStdout.split(\"\\n\").map((l) => {\n        const tokens = l.split(/\\s+/);\n        return { name: tokens[1] };\n      });\n      return [...aliases_suggestions, ...remote_versions_suggestions];\n    }\n\n    const { stdout: registryStdout } = await executeShellCommand({\n      command: \"sh\",\n      args: [\"-c\", \"mise registry\"],\n    });\n    const registrySuggestions = [\n      ...new Set(\n        registryStdout.split(\"\\n\").map((l) => {\n          const tokens = l.split(/\\s+/);\n          return { name: tokens[0], description: tokens[1] };\n        })\n      ),\n    ];\n\n    const backendSuggestions = (await getBackends(executeShellCommand)).map(\n      (backend) => ({ name: backend, description: \"Backend\" })\n    );\n    return [...backendSuggestions, ...registrySuggestions];\n  },\n};\n\nconst installedToolVersionGenerator: Fig.Generator = {\n  trigger: \"@\",\n  getQueryTerm: \"@\",\n  custom: async (\n    context: string[],\n    executeShellCommand: Fig.ExecuteCommandFunction\n  ) => {\n    const tools = await getInstalledTools(executeShellCommand);\n    const toolsVersions = groupBy(tools, \"name\");\n\n    const currentWord = context[context.length - 1];\n    if (atsInStr(currentWord)) {\n      const tool = currentWord.slice(0, currentWord.lastIndexOf(\"@\"));\n\n      const { stdout: aliasStdout } = await executeShellCommand({\n        command: \"sh\",\n        args: [\"-c\", `mise alias ls ${tool}`],\n      });\n\n      // This lists all aliases even if they are not installed\n      /*\n      const aliases_suggestions = aliasStdout.split('\\n').map(l => {\n        const tokens = l.split(/\\s+/)\n        return {name: tokens[1], description: tokens[2]}\n      }) as Fig.Suggestion[]\n      */\n\n      const toolVersions = (toolsVersions[tool] || []) as {\n        name: string;\n        version: string;\n      }[];\n      const suggestions = toolVersions.map((s) => ({\n        name: s.version,\n      })) as Fig.Suggestion[];\n\n      return [...suggestions];\n    }\n\n    const suggestions: Fig.Suggestion[] = [];\n    Object.keys(toolsVersions).forEach((k) => {\n      if (toolsVersions[k].length == 1) {\n        suggestions.push({ name: k });\n      } else {\n        suggestions.push({ name: `${k}@` });\n      }\n    });\n\n    return suggestions;\n  },\n};\n\n// @generated by usage-cli from mise.usage.kdl\nconst envVarGenerator = {\n  script: [\"sh\", \"-c\", \"env\"],\n  postProcess: (output: string) => {\n    return output.split(\"\\n\").map((l) => ({ name: l.split(\"=\")[0] }));\n  },\n};\nconst usageGenerateSpec = (cmds: string[]) => {\n  return async (\n    context: string[],\n    executeCommand: Fig.ExecuteCommandFunction\n  ): Promise<Fig.Spec> => {\n    const promises = cmds.map(async (cmd): Promise<Fig.Subcommand[]> => {\n      try {\n        const args = cmd.split(\" \");\n        const {\n          stdout,\n          stderr: cmdStderr,\n          status: cmdStatus,\n        } = await executeCommand({\n          command: args[0],\n          args: args.splice(1),\n        });\n        if (cmdStatus !== 0) {\n          return [{ name: \"error\", description: cmdStderr }];\n        }\n        const {\n          stdout: figSpecOut,\n          stderr: figSpecStderr,\n          status: usageFigStatus,\n        } = await executeCommand({\n          command: \"usage\",\n          args: [\"g\", \"fig\", \"--spec\", stdout],\n        });\n        if (usageFigStatus !== 0) {\n          return [{ name: \"error\", description: figSpecStderr }];\n        }\n        const start_of_json = figSpecOut.indexOf(\"{\");\n        const j = figSpecOut.slice(start_of_json);\n        return JSON.parse(j).subcommands as Fig.Subcommand[];\n      } catch (e) {\n        return [{ name: \"error\", description: e }] as Fig.Subcommand[];\n      }\n    });\n    // eslint-disable-next-line compat/compat\n    const results = await Promise.allSettled(promises);\n    const subcommands = results\n      .filter((p) => p.status === \"fulfilled\")\n      .map((p) => p.value);\n    const failed = results\n      .filter((p) => p.status === \"rejected\")\n      .map((p) => ({ name: \"error\", description: p.reason }));\n    return { subcommands: [...subcommands.flat(), ...failed] } as Fig.Spec;\n  };\n};\nconst completionGeneratorTemplate = (\n  argSuggestionBash: string\n): Fig.Generator => {\n  return {\n    custom: async (tokens: string[], executeCommand) => {\n      let arg = argSuggestionBash;\n      if (tokens.length >= 1) {\n        arg = argSuggestionBash.replace(\n          \"{{words[CURRENT]}}\",\n          tokens[tokens.length - 1]\n        );\n      }\n      if (tokens.length >= 2) {\n        arg = arg.replace(`{{words[PREV]}}`, tokens[tokens.length - 2]);\n      }\n      const { stdout: text } = await executeCommand({\n        command: \"sh\",\n        args: [\"-c\", arg],\n      });\n      if (text.trim().length == 0) return [];\n      return text.split(\"\\n\").map((elm) => ({ name: elm }));\n    },\n  };\n};\nconst completionSpec: Fig.Spec = {\n  name: \"mise\",\n  subcommands: [\n    {\n      name: \"activate\",\n      description: \"Initializes mise in the current shell session\",\n      options: [\n        {\n          name: [\"-q\", \"--quiet\"],\n          description: \"Suppress non-error messages\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-hook-env\",\n          description: \"Do not automatically call hook-env\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--shims\",\n          description:\n            \"Use shims instead of modifying PATH\\nEffectively the same as:\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"shell_type\",\n        description: \"Shell type to generate the script for\",\n        isOptional: true,\n        suggestions: [\"bash\", \"elvish\", \"fish\", \"nu\", \"xonsh\", \"zsh\", \"pwsh\"],\n      },\n    },\n    {\n      name: \"tool-alias\",\n      description: \"Manage tool version aliases.\",\n      subcommands: [\n        {\n          name: \"get\",\n          description: \"Show an alias for a plugin\",\n          args: [\n            {\n              name: \"plugin\",\n              description: \"The plugin to show the alias for\",\n              generators: pluginGenerator,\n              debounce: true,\n            },\n            {\n              name: \"alias\",\n              description: \"The alias to show\",\n              generators: aliasGenerator,\n              debounce: true,\n            },\n          ],\n        },\n        {\n          name: [\"ls\", \"list\"],\n          description:\n            \"List tool version aliases\\nShows the aliases that can be specified.\\nThese can come from user config or from plugins in `bin/list-aliases`.\",\n          options: [\n            {\n              name: \"--no-header\",\n              description: \"Don't show table header\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"tool\",\n            description: \"Show aliases for <TOOL>\",\n            isOptional: true,\n            generators: completionGeneratorTemplate(`mise registry --complete`),\n            debounce: true,\n          },\n        },\n        {\n          name: [\"set\", \"add\", \"create\"],\n          description: \"Add/update an alias for a backend/plugin\",\n          args: [\n            {\n              name: \"plugin\",\n              description: \"The backend/plugin to set the alias for\",\n              generators: pluginGenerator,\n              debounce: true,\n            },\n            {\n              name: \"alias\",\n              description: \"The alias to set\",\n              generators: aliasGenerator,\n              debounce: true,\n            },\n            {\n              name: \"value\",\n              description: \"The value to set the alias to\",\n              isOptional: true,\n            },\n          ],\n        },\n        {\n          name: [\"unset\", \"rm\", \"remove\", \"delete\", \"del\"],\n          description: \"Clears an alias for a backend/plugin\",\n          args: [\n            {\n              name: \"plugin\",\n              description: \"The backend/plugin to remove the alias from\",\n              generators: pluginGenerator,\n              debounce: true,\n            },\n            {\n              name: \"alias\",\n              description: \"The alias to remove\",\n              isOptional: true,\n              generators: aliasGenerator,\n              debounce: true,\n            },\n          ],\n        },\n      ],\n      options: [\n        {\n          name: [\"-p\", \"--plugin\"],\n          description: \"Filter aliases by plugin\",\n          isRepeatable: false,\n          args: {\n            name: \"plugin\",\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"--no-header\",\n          description: \"Don't show table header\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: [\"backends\", \"b\"],\n      description: \"Manage backends\",\n      subcommands: [\n        {\n          name: [\"ls\", \"list\"],\n          description: \"List built-in backends\",\n        },\n      ],\n    },\n    {\n      name: \"bin-paths\",\n      description: \"List all the active runtime bin paths\",\n      args: {\n        name: \"tool@version\",\n        description: \"Tool(s) to look up\\ne.g.: ruby@3\",\n        isOptional: true,\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"cache\",\n      description: \"Manage the mise cache\",\n      subcommands: [\n        {\n          name: [\"clear\", \"c\"],\n          description: \"Deletes all cache files in mise\",\n          args: {\n            name: \"plugin\",\n            description: \"Plugin(s) to clear cache for e.g.: node, python\",\n            isOptional: true,\n            isVariadic: true,\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: [\"path\", \"dir\"],\n          description: \"Show the cache directory path\",\n        },\n        {\n          name: [\"prune\", \"p\"],\n          description: \"Removes stale mise cache files\",\n          options: [\n            {\n              name: [\"-v\", \"--verbose\"],\n              description: \"Show pruned files\",\n              isRepeatable: true,\n            },\n            {\n              name: \"--dry-run\",\n              description: \"Just show what would be pruned\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"plugin\",\n            description: \"Plugin(s) to clear cache for e.g.: node, python\",\n            isOptional: true,\n            isVariadic: true,\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n      ],\n    },\n    {\n      name: \"completion\",\n      description: \"Generate shell completions\",\n      options: [\n        {\n          name: \"--include-bash-completion-lib\",\n          description:\n            \"Include the bash completion library in the bash completion script\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"shell\",\n        description: \"Shell type to generate completions for\",\n        isOptional: true,\n        suggestions: [\"bash\", \"fish\", \"powershell\", \"zsh\"],\n      },\n    },\n    {\n      name: [\"config\", \"cfg\"],\n      description: \"Manage config files\",\n      subcommands: [\n        {\n          name: \"get\",\n          description: \"Display the value of a setting in a mise.toml file\",\n          options: [\n            {\n              name: [\"-f\", \"--file\"],\n              description: \"The path to the mise.toml file to edit\",\n              isRepeatable: false,\n              args: {\n                name: \"file\",\n                template: \"filepaths\",\n              },\n            },\n          ],\n          args: {\n            name: \"key\",\n            description: \"The path of the config to display\",\n            isOptional: true,\n          },\n        },\n        {\n          name: [\"ls\", \"list\"],\n          description: \"List config files currently in use\",\n          options: [\n            {\n              name: [\"-J\", \"--json\"],\n              description: \"Output in JSON format\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--no-header\",\n              description: \"Do not print table header\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--tracked-configs\",\n              description: \"List all tracked config files\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: \"set\",\n          description: \"Set the value of a setting in a mise.toml file\",\n          options: [\n            {\n              name: [\"-f\", \"--file\"],\n              description: \"The path to the mise.toml file to edit\",\n              isRepeatable: false,\n              args: {\n                name: \"file\",\n                template: \"filepaths\",\n              },\n            },\n            {\n              name: [\"-t\", \"--type\"],\n              isRepeatable: false,\n              args: {\n                name: \"type\",\n                suggestions: [\n                  \"infer\",\n                  \"string\",\n                  \"integer\",\n                  \"float\",\n                  \"bool\",\n                  \"list\",\n                  \"set\",\n                ],\n              },\n            },\n          ],\n          args: [\n            {\n              name: \"key\",\n              description: \"The path of the config to display\",\n            },\n            {\n              name: \"value\",\n              description:\n                \"The value to set the key to (optional if provided as KEY=VALUE)\",\n              isOptional: true,\n            },\n          ],\n        },\n      ],\n      options: [\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-header\",\n          description: \"Do not print table header\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--tracked-configs\",\n          description: \"List all tracked config files\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: \"deactivate\",\n      description: \"Disable mise for current shell session\",\n    },\n    {\n      name: [\"doctor\", \"dr\"],\n      description: \"Check mise installation for possible problems\",\n      subcommands: [\n        {\n          name: \"path\",\n          description: \"Print the current PATH entries mise is providing\",\n          options: [\n            {\n              name: [\"-f\", \"--full\"],\n              description:\n                \"Print all entries including those not provided by mise\",\n              isRepeatable: false,\n            },\n          ],\n        },\n      ],\n      options: [\n        {\n          name: [\"-J\", \"--json\"],\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: \"en\",\n      description:\n        \"Starts a new shell with the mise environment built from the current configuration\",\n      options: [\n        {\n          name: [\"-s\", \"--shell\"],\n          description: \"Shell to start\",\n          isRepeatable: false,\n          args: {\n            name: \"shell\",\n          },\n        },\n      ],\n      args: {\n        name: \"dir\",\n        description: \"Directory to start the shell in\",\n        isOptional: true,\n        template: \"folders\",\n      },\n    },\n    {\n      name: [\"env\", \"e\"],\n      description: \"Exports env vars to activate mise a single time\",\n      options: [\n        {\n          name: [\"-D\", \"--dotenv\"],\n          description: \"Output in dotenv format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-s\", \"--shell\"],\n          description: \"Shell type to generate environment variables for\",\n          isRepeatable: false,\n          args: {\n            name: \"shell\",\n            suggestions: [\n              \"bash\",\n              \"elvish\",\n              \"fish\",\n              \"nu\",\n              \"xonsh\",\n              \"zsh\",\n              \"pwsh\",\n            ],\n          },\n        },\n        {\n          name: \"--json-extended\",\n          description:\n            \"Output in JSON format with additional information (source, tool)\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--redacted\",\n          description: \"Only show redacted environment variables\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--values\",\n          description: \"Only show values of environment variables\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description: \"Tool(s) to use\",\n        isOptional: true,\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"exec\", \"x\"],\n      description: \"Execute a command with tool(s) set\",\n      options: [\n        {\n          name: [\"-c\", \"--command\"],\n          description: \"Command string to execute\",\n          isRepeatable: false,\n          args: {\n            name: \"c\",\n          },\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: \"--fresh-env\",\n          description:\n            \"Bypass the environment cache and recompute the environment\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-prepare\",\n          description: \"Skip automatic dependency preparation\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\",\n          isRepeatable: false,\n        },\n      ],\n      args: [\n        {\n          name: \"tool@version\",\n          description: \"Tool(s) to start e.g.: node@20 python@3.10\",\n          isOptional: true,\n          isVariadic: true,\n          generators: toolVersionGenerator,\n          debounce: true,\n        },\n        {\n          name: \"command\",\n          description: \"Command string to execute (same as --command)\",\n          isOptional: true,\n          isVariadic: true,\n        },\n      ],\n    },\n    {\n      name: \"fmt\",\n      description: \"Formats mise.toml\",\n      options: [\n        {\n          name: [\"-a\", \"--all\"],\n          description: \"Format all files from the current directory\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-c\", \"--check\"],\n          description:\n            \"Check if the configs are formatted, no formatting is done\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-s\", \"--stdin\"],\n          description:\n            \"Read config from stdin and write its formatted version into stdout\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: [\"generate\", \"gen\"],\n      description: \"Generate files for various tools/services\",\n      subcommands: [\n        {\n          name: \"bootstrap\",\n          description: \"Generate a script to download+execute mise\",\n          options: [\n            {\n              name: [\"-l\", \"--localize\"],\n              description:\n                \"Sandboxes mise internal directories like MISE_DATA_DIR and MISE_CACHE_DIR into a `.mise` directory in the project\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-V\", \"--version\"],\n              description: \"Specify mise version to fetch\",\n              isRepeatable: false,\n              args: {\n                name: \"version\",\n              },\n            },\n            {\n              name: [\"-w\", \"--write\"],\n              description:\n                \"Instead of outputting the script to stdout, write to a file and make it executable\",\n              isRepeatable: false,\n              args: {\n                name: \"write\",\n              },\n            },\n            {\n              name: \"--localized-dir\",\n              description: \"Directory to put localized data into\",\n              isRepeatable: false,\n              args: {\n                name: \"localized_dir\",\n                template: \"folders\",\n              },\n            },\n          ],\n        },\n        {\n          name: \"config\",\n          description: \"Generate a mise.toml file\",\n          options: [\n            {\n              name: [\"-n\", \"--dry-run\"],\n              description:\n                \"Show what would be generated without writing to file\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-t\", \"--tool-versions\"],\n              description: \"Path to a .tool-versions file to import tools from\",\n              isRepeatable: false,\n              args: {\n                name: \"tool_versions\",\n              },\n            },\n          ],\n          args: {\n            name: \"path\",\n            description: \"Path to the config file to create\",\n            isOptional: true,\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"devcontainer\",\n          description: \"Generate a devcontainer to execute mise\",\n          options: [\n            {\n              name: [\"-i\", \"--image\"],\n              description: \"The image to use for the devcontainer\",\n              isRepeatable: false,\n              args: {\n                name: \"image\",\n              },\n            },\n            {\n              name: [\"-m\", \"--mount-mise-data\"],\n              description: \"Bind the mise-data-volume to the devcontainer\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-n\", \"--name\"],\n              description: \"The name of the devcontainer\",\n              isRepeatable: false,\n              args: {\n                name: \"name\",\n              },\n            },\n            {\n              name: [\"-w\", \"--write\"],\n              description: \"Write to .devcontainer/devcontainer.json\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: [\"git-pre-commit\", \"pre-commit\"],\n          description: \"Generate a git pre-commit hook\",\n          options: [\n            {\n              name: [\"-t\", \"--task\"],\n              description:\n                \"The task to run when the pre-commit hook is triggered\",\n              isRepeatable: false,\n              args: {\n                name: \"task\",\n                generators: simpleTaskGenerator,\n                debounce: true,\n              },\n            },\n            {\n              name: [\"-w\", \"--write\"],\n              description:\n                \"Write to .git/hooks/pre-commit and make it executable\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--hook\",\n              description: \"Which hook to generate (saves to .git/hooks/$hook)\",\n              isRepeatable: false,\n              args: {\n                name: \"hook\",\n              },\n            },\n          ],\n        },\n        {\n          name: \"github-action\",\n          description: \"Generate a GitHub Action workflow file\",\n          options: [\n            {\n              name: [\"-t\", \"--task\"],\n              description: \"The task to run when the workflow is triggered\",\n              isRepeatable: false,\n              args: {\n                name: \"task\",\n                generators: simpleTaskGenerator,\n                debounce: true,\n              },\n            },\n            {\n              name: [\"-w\", \"--write\"],\n              description: \"Write to .github/workflows/$name.yml\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--name\",\n              description: \"The name of the workflow to generate\",\n              isRepeatable: false,\n              args: {\n                name: \"name\",\n              },\n            },\n          ],\n        },\n        {\n          name: \"task-docs\",\n          description: \"Generate documentation for tasks in a project\",\n          options: [\n            {\n              name: [\"-i\", \"--inject\"],\n              description: \"Inserts the documentation into an existing file\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-I\", \"--index\"],\n              description:\n                \"Write only an index of tasks, intended for use with `--multi`\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-m\", \"--multi\"],\n              description:\n                \"Render each task as a separate document, requires `--output` to be a directory\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-o\", \"--output\"],\n              description: \"Writes the generated docs to a file/directory\",\n              isRepeatable: false,\n              args: {\n                name: \"output\",\n              },\n            },\n            {\n              name: [\"-r\", \"--root\"],\n              description: \"Root directory to search for tasks\",\n              isRepeatable: false,\n              args: {\n                name: \"root\",\n              },\n            },\n            {\n              name: [\"-s\", \"--style\"],\n              isRepeatable: false,\n              args: {\n                name: \"style\",\n                suggestions: [\"simple\", \"detailed\"],\n              },\n            },\n          ],\n        },\n        {\n          name: \"task-stubs\",\n          description: \"Generates shims to run mise tasks\",\n          options: [\n            {\n              name: [\"-d\", \"--dir\"],\n              description: \"Directory to create task stubs inside of\",\n              isRepeatable: false,\n              args: {\n                name: \"dir\",\n                template: \"folders\",\n              },\n            },\n            {\n              name: [\"-m\", \"--mise-bin\"],\n              description:\n                \"Path to a mise bin to use when running the task stub.\",\n              isRepeatable: false,\n              args: {\n                name: \"mise_bin\",\n              },\n            },\n          ],\n        },\n        {\n          name: \"tool-stub\",\n          description: \"Generate a tool stub for HTTP-based tools\",\n          options: [\n            {\n              name: [\"-b\", \"--bin\"],\n              description: \"Binary path within the extracted archive\",\n              isRepeatable: false,\n              args: {\n                name: \"bin\",\n              },\n            },\n            {\n              name: \"--bootstrap\",\n              description:\n                \"Wrap stub in a bootstrap script that installs mise if not already present\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--bootstrap-version\",\n              description: \"Specify mise version for the bootstrap script\",\n              isRepeatable: false,\n              args: {\n                name: \"bootstrap_version\",\n              },\n            },\n            {\n              name: \"--fetch\",\n              description:\n                \"Fetch checksums and sizes for an existing tool stub file\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--http\",\n              description: \"HTTP backend type to use\",\n              isRepeatable: false,\n              args: {\n                name: \"http\",\n              },\n            },\n            {\n              name: \"--lock\",\n              description:\n                \"Resolve and embed lockfile data (exact version + platform URLs/checksums) into an existing stub file for reproducible installs without runtime API calls\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--platform-bin\",\n              description:\n                \"Platform-specific binary paths in the format platform:path\",\n              isRepeatable: true,\n              args: {\n                name: \"platform_bin\",\n              },\n            },\n            {\n              name: \"--platform-url\",\n              description:\n                \"Platform-specific URLs in the format platform:url or just url (auto-detect platform)\",\n              isRepeatable: true,\n              args: {\n                name: \"platform_url\",\n              },\n            },\n            {\n              name: \"--skip-download\",\n              description:\n                \"Skip downloading for checksum and binary path detection (faster but less informative)\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-u\", \"--url\"],\n              description: \"URL for downloading the tool\",\n              isRepeatable: false,\n              args: {\n                name: \"url\",\n              },\n            },\n            {\n              name: \"--version\",\n              description: \"Version of the tool\",\n              isRepeatable: false,\n              args: {\n                name: \"version\",\n              },\n            },\n          ],\n          args: {\n            name: \"output\",\n            description: \"Output file path for the tool stub\",\n          },\n        },\n      ],\n    },\n    {\n      name: \"implode\",\n      description: \"Removes mise CLI and all related data\",\n      options: [\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description:\n            \"List directories that would be removed without actually removing them\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--config\",\n          description: \"Also remove config directory\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: \"edit\",\n      description: \"Edit mise.toml interactively\",\n      options: [\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Show what would be generated without writing to file\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-t\", \"--tool-versions\"],\n          description: \"Path to a .tool-versions file to import tools from\",\n          isRepeatable: false,\n          args: {\n            name: \"tool_versions\",\n          },\n        },\n      ],\n      args: {\n        name: \"path\",\n        description: \"Path to the config file to create\",\n        isOptional: true,\n        template: \"filepaths\",\n      },\n    },\n    {\n      name: [\"install\", \"i\"],\n      description: \"Install a tool version\",\n      options: [\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Force reinstall even if already installed\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description:\n            \"Show what would be installed without actually installing\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-v\", \"--verbose\"],\n          description: \"Show installation output\",\n          isRepeatable: true,\n        },\n        {\n          name: \"--before\",\n          description: \"Only install versions released before this date\",\n          isRepeatable: false,\n          args: {\n            name: \"before\",\n          },\n        },\n        {\n          name: \"--dry-run-code\",\n          description:\n            \"Like --dry-run but exits with code 1 if there are tools to install\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--shared\",\n          description: \"[experimental] Install tool(s) to a shared directory\",\n          isRepeatable: false,\n          args: {\n            name: \"shared\",\n          },\n        },\n        {\n          name: \"--system\",\n          description:\n            \"[experimental] Install tool(s) to the system-wide shared directory\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description: \"Tool(s) to install e.g.: node@20\",\n        isOptional: true,\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"install-into\",\n      description: \"Install a tool version to a specific path\",\n      args: [\n        {\n          name: \"tool@version\",\n          description: \"Tool to install e.g.: node@20\",\n          generators: toolVersionGenerator,\n          debounce: true,\n        },\n        {\n          name: \"path\",\n          description: \"Path to install the tool into\",\n          template: \"filepaths\",\n        },\n      ],\n    },\n    {\n      name: \"latest\",\n      description: \"Gets the latest available version for a plugin\",\n      options: [\n        {\n          name: [\"-i\", \"--installed\"],\n          description: \"Show latest installed instead of available version\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description: \"Tool to get the latest version of\",\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"link\", \"ln\"],\n      description: \"Symlinks a tool version into mise\",\n      options: [\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Overwrite an existing tool version if it exists\",\n          isRepeatable: false,\n        },\n      ],\n      args: [\n        {\n          name: \"tool@version\",\n          description: \"Tool name and version to create a symlink for\",\n          generators: toolVersionGenerator,\n          debounce: true,\n        },\n        {\n          name: \"path\",\n          description:\n            \"The local path to the tool version\\ne.g.: ~/.nvm/versions/node/v20.0.0\",\n          template: \"filepaths\",\n        },\n      ],\n    },\n    {\n      name: \"lock\",\n      description:\n        \"Update lockfile checksums and URLs for all specified platforms\",\n      options: [\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Show what would be updated without making changes\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-p\", \"--platform\"],\n          description:\n            \"Comma-separated list of platforms to target\\ne.g.: linux-x64,macos-arm64,windows-x64\\nIf not specified, all platforms already in lockfile will be updated\",\n          isRepeatable: true,\n          args: {\n            name: \"platform\",\n          },\n        },\n        {\n          name: \"--local\",\n          description:\n            \"Update mise.local.lock instead of mise.lock\\nUse for tools defined in .local.toml configs\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool\",\n        description:\n          \"Tool(s) to update in lockfile\\ne.g.: node python\\nIf not specified, all tools in lockfile will be updated\",\n        isOptional: true,\n        isVariadic: true,\n        generators: completionGeneratorTemplate(`mise registry --complete`),\n        debounce: true,\n      },\n    },\n    {\n      name: [\"ls\", \"list\"],\n      description: \"List installed and active tool versions\",\n      options: [\n        {\n          name: [\"-c\", \"--current\"],\n          description:\n            \"Only show tool versions currently specified in a mise.toml\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-g\", \"--global\"],\n          description:\n            \"Only show tool versions currently specified in the global mise.toml\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-i\", \"--installed\"],\n          description:\n            \"Only show tool versions that are installed (Hides tools defined in mise.toml but not installed)\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-l\", \"--local\"],\n          description:\n            \"Only show tool versions currently specified in the local mise.toml\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-m\", \"--missing\"],\n          description: \"Display missing tool versions\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--all-sources\",\n          description: \"Display all tracked config sources for tools\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-header\",\n          description: \"Don't display headers\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--outdated\",\n          description: \"Display whether a version is outdated\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--prefix\",\n          description: \"Display versions matching this prefix\",\n          isRepeatable: false,\n          args: {\n            name: \"prefix\",\n            generators: completionGeneratorTemplate(\n              `mise ls-remote {{words[PREV]}}`\n            ),\n            debounce: true,\n          },\n        },\n        {\n          name: \"--prunable\",\n          description: \"List only tools that can be pruned with `mise prune`\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"installed_tool\",\n        description: \"Only show tool versions from [TOOL]\",\n        isOptional: true,\n        isVariadic: true,\n        generators: completionGeneratorTemplate(\n          `mise ls -i | awk '{print $1}' | uniq`\n        ),\n        debounce: true,\n      },\n    },\n    {\n      name: \"ls-remote\",\n      description: \"List runtime versions available for install.\",\n      options: [\n        {\n          name: \"--all\",\n          description: \"Show all installed plugins and versions\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description:\n            \"Output in JSON format (includes version metadata like created_at timestamps when available)\",\n          isRepeatable: false,\n        },\n      ],\n      args: [\n        {\n          name: \"tool@version\",\n          description: \"Tool to get versions for\",\n          isOptional: true,\n          generators: toolVersionGenerator,\n          debounce: true,\n        },\n        {\n          name: \"prefix\",\n          description:\n            'The version prefix to use when querying the latest version\\nsame as the first argument after the \"@\"',\n          isOptional: true,\n          generators: completionGeneratorTemplate(\n            `mise ls-remote {{words[PREV]}}`\n          ),\n          debounce: true,\n        },\n      ],\n    },\n    {\n      name: \"mcp\",\n      description: \"[experimental] Run Model Context Protocol (MCP) server\",\n    },\n    {\n      name: \"outdated\",\n      description: \"Shows outdated tool versions\",\n      options: [\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-l\", \"--bump\"],\n          description:\n            \"Compares against the latest versions available, not what matches the current config\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--local\",\n          description: \"Only show outdated tools defined in local config files\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-header\",\n          description: \"Don't show table header\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description:\n          \"Tool(s) to show outdated versions for\\ne.g.: node@20 python@3.10\\nIf not specified, all tools in global and local configs will be shown\",\n        isOptional: true,\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"plugins\", \"p\"],\n      description: \"Manage plugins\",\n      subcommands: [\n        {\n          name: [\"install\", \"i\", \"a\", \"add\"],\n          description: \"Install a plugin\",\n          options: [\n            {\n              name: [\"-a\", \"--all\"],\n              description:\n                \"Install all missing plugins\\nThis will only install plugins that have matching shorthands.\\ni.e.: they don't need the full git repo url\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-f\", \"--force\"],\n              description: \"Reinstall even if plugin exists\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-j\", \"--jobs\"],\n              description: \"Number of jobs to run in parallel\",\n              isRepeatable: false,\n              args: {\n                name: \"jobs\",\n              },\n            },\n            {\n              name: [\"-v\", \"--verbose\"],\n              description: \"Show installation output\",\n              isRepeatable: true,\n            },\n          ],\n          args: [\n            {\n              name: \"new_plugin\",\n              description:\n                \"The name of the plugin to install\\ne.g.: cmake, poetry\\nCan specify multiple plugins: `mise plugins install cmake poetry`\",\n              isOptional: true,\n              generators: completionGeneratorTemplate(`mise plugins --all`),\n              debounce: true,\n            },\n            {\n              name: \"git_url\",\n              description: \"The git url of the plugin\",\n              isOptional: true,\n            },\n          ],\n        },\n        {\n          name: [\"link\", \"ln\"],\n          description: \"Symlinks a plugin into mise\",\n          options: [\n            {\n              name: [\"-f\", \"--force\"],\n              description: \"Overwrite existing plugin\",\n              isRepeatable: false,\n            },\n          ],\n          args: [\n            {\n              name: \"name\",\n              description: \"The name of the plugin\\ne.g.: cmake, poetry\",\n            },\n            {\n              name: \"dir\",\n              description: \"The local path to the plugin\\ne.g.: ./vfox-cmake\",\n              isOptional: true,\n              template: \"folders\",\n            },\n          ],\n        },\n        {\n          name: [\"ls\", \"list\"],\n          description: \"List installed plugins\",\n          options: [\n            {\n              name: [\"-o\", \"--outdated\"],\n              description:\n                \"Show plugins with available updates\\nChecks the remote for newer versions and only displays plugins that are outdated\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-u\", \"--urls\"],\n              description:\n                \"Show the git url for each plugin\\ne.g.: https://github.com/mise-plugins/vfox-cmake.git\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: [\"ls-remote\", \"list-remote\", \"list-all\"],\n          description: \"List all available remote plugins\",\n          options: [\n            {\n              name: [\"-u\", \"--urls\"],\n              description:\n                \"Show the git url for each plugin e.g.: https://github.com/mise-plugins/mise-poetry.git\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--only-names\",\n              description:\n                'Only show the name of each plugin by default it will show a \"*\" next to installed plugins',\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: [\"uninstall\", \"remove\", \"rm\"],\n          description: \"Removes a plugin\",\n          options: [\n            {\n              name: [\"-a\", \"--all\"],\n              description: \"Remove all plugins\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-p\", \"--purge\"],\n              description:\n                \"Also remove the plugin's installs, downloads, and cache\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"plugin\",\n            description: \"Plugin(s) to remove\",\n            isOptional: true,\n            isVariadic: true,\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: [\"update\", \"up\", \"upgrade\"],\n          description: \"Updates a plugin to the latest version\",\n          options: [\n            {\n              name: [\"-j\", \"--jobs\"],\n              description: \"Number of jobs to run in parallel\\nDefault: 4\",\n              isRepeatable: false,\n              args: {\n                name: \"jobs\",\n              },\n            },\n          ],\n          args: {\n            name: \"plugin\",\n            description: \"Plugin(s) to update\",\n            isOptional: true,\n            isVariadic: true,\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n      ],\n      options: [\n        {\n          name: [\"-c\", \"--core\"],\n          description:\n            \"The built-in plugins only\\nNormally these are not shown\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-u\", \"--urls\"],\n          description:\n            \"Show the git url for each plugin\\ne.g.: https://github.com/mise-plugins/vfox-cmake.git\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--user\",\n          description: \"List installed plugins\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: [\"prepare\", \"prep\"],\n      description: \"[experimental] Ensure project dependencies are ready\",\n      options: [\n        {\n          name: \"--explain\",\n          description:\n            \"Show why a provider is fresh or stale (requires a provider argument)\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Force run all prepare steps even if outputs are fresh\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Only check if prepare is needed, don't run commands\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--list\",\n          description: \"Show what prepare steps are available\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--only\",\n          description: \"Run specific prepare rule(s) only\",\n          isRepeatable: true,\n          args: {\n            name: \"only\",\n          },\n        },\n        {\n          name: \"--skip\",\n          description: \"Skip specific prepare rule(s)\",\n          isRepeatable: true,\n          args: {\n            name: \"skip\",\n          },\n        },\n      ],\n      args: {\n        name: \"provider\",\n        description:\n          \"Provider to operate on (runs only this provider, or use with --explain)\",\n        isOptional: true,\n      },\n    },\n    {\n      name: \"prune\",\n      description: \"Delete unused versions of tools\",\n      options: [\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Do not actually delete anything\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--configs\",\n          description:\n            \"Prune only tracked and trusted configuration links that point to non-existent configurations\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--dry-run-code\",\n          description:\n            \"Like --dry-run but exits with code 1 if there are tools to prune\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--tools\",\n          description: \"Prune only unused versions of tools\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"installed_tool\",\n        description: \"Prune only these tools\",\n        isOptional: true,\n        isVariadic: true,\n        generators: completionGeneratorTemplate(\n          `mise ls -i | awk '{print $1}' | uniq`\n        ),\n        debounce: true,\n      },\n    },\n    {\n      name: \"registry\",\n      description: \"List available tools to install\",\n      options: [\n        {\n          name: [\"-b\", \"--backend\"],\n          description: \"Show only tools for this backend\",\n          isRepeatable: false,\n          args: {\n            name: \"backend\",\n            generators: completionGeneratorTemplate(`mise backends`),\n            debounce: true,\n          },\n        },\n        {\n          name: \"--hide-aliased\",\n          description: \"Hide aliased tools\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"name\",\n        description: \"Show only the specified tool's full name\",\n        isOptional: true,\n      },\n    },\n    {\n      name: \"reshim\",\n      description:\n        \"Creates new shims based on bin paths from currently installed tools.\",\n      options: [\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Removes all shims before reshimming\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: [\"run\", \"r\"],\n      description: \"Run task(s)\",\n      options: [\n        {\n          name: [\"-c\", \"--continue-on-error\"],\n          description: \"Continue running tasks even if one fails\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-C\", \"--cd\"],\n          description: \"Change to this directory before executing the command\",\n          isRepeatable: false,\n          args: {\n            name: \"cd\",\n          },\n        },\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Force the tasks to run even if outputs are up to date\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description:\n            \"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description:\n            \"Don't actually run the task(s), just print them in order of execution\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-o\", \"--output\"],\n          description:\n            \"Change how tasks information is output when running tasks\",\n          isRepeatable: false,\n          args: {\n            name: \"output\",\n          },\n        },\n        {\n          name: [\"-q\", \"--quiet\"],\n          description: \"Don't show extra output\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-r\", \"--raw\"],\n          description:\n            \"Read/write directly to stdin/stdout/stderr instead of by line\\nRedactions are not applied with this option\\nConfigure with `raw` config or `MISE_RAW` env var\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-s\", \"--shell\"],\n          description: \"Shell to use to run toml tasks\",\n          isRepeatable: false,\n          args: {\n            name: \"shell\",\n          },\n        },\n        {\n          name: [\"-S\", \"--silent\"],\n          description: \"Don't show any output except for errors\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-t\", \"--tool\"],\n          description:\n            \"Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\",\n          isRepeatable: true,\n          args: {\n            name: \"tool@version\",\n            generators: toolVersionGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"--fresh-env\",\n          description:\n            \"Bypass the environment cache and recompute the environment\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-cache\",\n          description: \"Do not use cache on remote tasks\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-prepare\",\n          description: \"Skip automatic dependency preparation\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-timings\",\n          description: \"Hides elapsed time after each task completes\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--skip-deps\",\n          description: \"Run only the specified tasks skipping all dependencies\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--timeout\",\n          description: \"Timeout for the task to complete\\ne.g.: 30s, 5m\",\n          isRepeatable: false,\n          args: {\n            name: \"timeout\",\n          },\n        },\n      ],\n      generateSpec: usageGenerateSpec([\"mise tasks --usage\"]),\n      cache: false,\n    },\n    {\n      name: \"search\",\n      description: \"Search for tools in the registry\",\n      options: [\n        {\n          name: [\"-i\", \"--interactive\"],\n          description: \"Show interactive search\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-m\", \"--match-type\"],\n          description: \"Match type: equal, contains, or fuzzy\",\n          isRepeatable: false,\n          args: {\n            name: \"match_type\",\n            suggestions: [\"equal\", \"contains\", \"fuzzy\"],\n          },\n        },\n        {\n          name: \"--no-header\",\n          description: \"Don't display headers\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"name\",\n        description: \"The tool to search for\",\n        isOptional: true,\n      },\n    },\n    {\n      name: \"self-update\",\n      description: \"Updates mise itself.\",\n      options: [\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Update even if already up to date\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-y\", \"--yes\"],\n          description: \"Skip confirmation prompt\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-plugins\",\n          description: \"Disable auto-updating plugins\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"version\",\n        description: \"Update to a specific version\",\n        isOptional: true,\n      },\n    },\n    {\n      name: \"set\",\n      description: \"Set environment variables in mise.toml\",\n      options: [\n        {\n          name: [\"-E\", \"--env\"],\n          description:\n            \"Create/modify an environment-specific config file like .mise.<env>.toml\",\n          isRepeatable: false,\n          args: {\n            name: \"env\",\n          },\n        },\n        {\n          name: [\"-g\", \"--global\"],\n          description: \"Set the environment variable in the global config file\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--age-encrypt\",\n          description:\n            \"[experimental] Encrypt the value with age before storing\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--age-key-file\",\n          description: \"[experimental] Age identity file for encryption\",\n          isRepeatable: false,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--age-recipient\",\n          description:\n            \"[experimental] Age recipient (x25519 public key) for encryption\",\n          isRepeatable: true,\n          args: {\n            name: \"recipient\",\n          },\n        },\n        {\n          name: \"--age-ssh-recipient\",\n          description:\n            \"[experimental] SSH recipient (public key or path) for age encryption\",\n          isRepeatable: true,\n          args: {\n            name: \"path_or_pubkey\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--file\",\n          description: \"The TOML file to update\",\n          isRepeatable: false,\n          args: {\n            name: \"file\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--no-redact\",\n          description: \"Show raw values instead of redacting secrets\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--prompt\",\n          description: \"Prompt for environment variable values\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--stdin\",\n          description: \"Read the value from stdin (for multiline input)\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"env_var\",\n        description:\n          \"Environment variable(s) to set\\ne.g.: NODE_ENV=production\",\n        isOptional: true,\n        isVariadic: true,\n        generators: envVarGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"settings\",\n      description: \"Manage settings\",\n      subcommands: [\n        {\n          name: \"add\",\n          description: \"Adds a setting to the configuration file\",\n          options: [\n            {\n              name: [\"-l\", \"--local\"],\n              description:\n                \"Use the local config file instead of the global one\",\n              isRepeatable: false,\n            },\n          ],\n          args: [\n            {\n              name: \"setting\",\n              description: \"The setting to set\",\n              generators: settingsGenerator,\n              debounce: true,\n            },\n            {\n              name: \"value\",\n              description:\n                \"The value to set (optional if provided as KEY=VALUE)\",\n              isOptional: true,\n            },\n          ],\n        },\n        {\n          name: \"get\",\n          description: \"Show a current setting\",\n          options: [\n            {\n              name: [\"-l\", \"--local\"],\n              description:\n                \"Use the local config file instead of the global one\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"setting\",\n            description: \"The setting to show\",\n            generators: settingsGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: [\"ls\", \"list\"],\n          description: \"Show current settings\",\n          options: [\n            {\n              name: [\"-a\", \"--all\"],\n              description: \"List all settings\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-J\", \"--json\"],\n              description: \"Output in JSON format\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-l\", \"--local\"],\n              description:\n                \"Use the local config file instead of the global one\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-T\", \"--toml\"],\n              description: \"Output in TOML format\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--json-extended\",\n              description: \"Output in JSON format with sources\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"setting\",\n            description: \"Name of setting\",\n            isOptional: true,\n            generators: settingsGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: [\"set\", \"create\"],\n          description: \"Add/update a setting\",\n          options: [\n            {\n              name: [\"-l\", \"--local\"],\n              description:\n                \"Use the local config file instead of the global one\",\n              isRepeatable: false,\n            },\n          ],\n          args: [\n            {\n              name: \"setting\",\n              description: \"The setting to set\",\n              generators: settingsGenerator,\n              debounce: true,\n            },\n            {\n              name: \"value\",\n              description:\n                \"The value to set (optional if provided as KEY=VALUE)\",\n              isOptional: true,\n            },\n          ],\n        },\n        {\n          name: [\"unset\", \"rm\", \"remove\", \"delete\", \"del\"],\n          description: \"Clears a setting\",\n          options: [\n            {\n              name: [\"-l\", \"--local\"],\n              description:\n                \"Use the local config file instead of the global one\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"key\",\n            description: \"The setting to remove\",\n          },\n        },\n      ],\n      options: [\n        {\n          name: [\"-a\", \"--all\"],\n          description: \"List all settings\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-l\", \"--local\"],\n          description: \"Use the local config file instead of the global one\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-T\", \"--toml\"],\n          description: \"Output in TOML format\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--json-extended\",\n          description: \"Output in JSON format with sources\",\n          isRepeatable: false,\n        },\n      ],\n      args: [\n        {\n          name: \"setting\",\n          description: \"Name of setting\",\n          isOptional: true,\n          generators: settingsGenerator,\n          debounce: true,\n        },\n        {\n          name: \"value\",\n          description: \"Setting value to set\",\n          isOptional: true,\n        },\n      ],\n    },\n    {\n      name: [\"shell\", \"sh\"],\n      description: \"Sets a tool version for the current session.\",\n      options: [\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-u\", \"--unset\"],\n          description: \"Removes a previously set version\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description: \"Tool(s) to use\",\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"shell-alias\",\n      description: \"Manage shell aliases.\",\n      subcommands: [\n        {\n          name: \"get\",\n          description: \"Show the command for a shell alias\",\n          args: {\n            name: \"shell_alias\",\n            description: \"The alias to show\",\n            generators: shellAliasGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: [\"ls\", \"list\"],\n          description: \"List shell aliases\",\n          options: [\n            {\n              name: \"--no-header\",\n              description: \"Don't show table header\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: [\"set\", \"add\", \"create\"],\n          description: \"Add/update a shell alias\",\n          args: [\n            {\n              name: \"shell_alias\",\n              description: \"The alias name\",\n              generators: shellAliasGenerator,\n              debounce: true,\n            },\n            {\n              name: \"command\",\n              description:\n                \"The command to run (optional if provided as ALIAS=COMMAND)\",\n              isOptional: true,\n            },\n          ],\n        },\n        {\n          name: [\"unset\", \"rm\", \"remove\", \"delete\", \"del\"],\n          description: \"Removes a shell alias\",\n          args: {\n            name: \"shell_alias\",\n            description: \"The alias to remove\",\n            generators: shellAliasGenerator,\n            debounce: true,\n          },\n        },\n      ],\n      options: [\n        {\n          name: \"--no-header\",\n          description: \"Don't show table header\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: \"sync\",\n      description: \"Synchronize tools from other version managers with mise\",\n      subcommands: [\n        {\n          name: \"node\",\n          description:\n            \"Symlinks all tool versions from an external tool into mise\",\n          options: [\n            {\n              name: \"--brew\",\n              description: \"Get tool versions from Homebrew\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--nodenv\",\n              description: \"Get tool versions from nodenv\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--nvm\",\n              description: \"Get tool versions from nvm\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: \"python\",\n          description:\n            \"Symlinks all tool versions from an external tool into mise\",\n          options: [\n            {\n              name: \"--pyenv\",\n              description: \"Get tool versions from pyenv\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--uv\",\n              description: \"Sync tool versions with uv (2-way sync)\",\n              isRepeatable: false,\n            },\n          ],\n        },\n        {\n          name: \"ruby\",\n          description:\n            \"Symlinks all ruby tool versions from an external tool into mise\",\n          options: [\n            {\n              name: \"--brew\",\n              description: \"Get tool versions from Homebrew\",\n              isRepeatable: false,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      name: [\"tasks\", \"t\"],\n      description: \"Manage tasks\",\n      subcommands: [\n        {\n          name: \"add\",\n          description: \"Create a new task\",\n          options: [\n            {\n              name: [\"-a\", \"--alias\"],\n              description: \"Other names for the task\",\n              isRepeatable: true,\n              args: {\n                name: \"alias\",\n                generators: aliasGenerator,\n                debounce: true,\n              },\n            },\n            {\n              name: [\"-d\", \"--depends\"],\n              description: \"Add dependencies to the task\",\n              isRepeatable: true,\n              args: {\n                name: \"depends\",\n              },\n            },\n            {\n              name: [\"-D\", \"--dir\"],\n              description: \"Run the task in a specific directory\",\n              isRepeatable: false,\n              args: {\n                name: \"dir\",\n                template: \"folders\",\n              },\n            },\n            {\n              name: [\"-f\", \"--file\"],\n              description: \"Create a file task instead of a toml task\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-H\", \"--hide\"],\n              description: \"Hide the task from `mise tasks` and completions\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-q\", \"--quiet\"],\n              description: \"Do not print the command before running\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-r\", \"--raw\"],\n              description: \"Directly connect stdin/stdout/stderr\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-s\", \"--sources\"],\n              description: \"Glob patterns of files this task uses as input\",\n              isRepeatable: true,\n              args: {\n                name: \"sources\",\n              },\n            },\n            {\n              name: [\"-w\", \"--wait-for\"],\n              description:\n                \"Wait for these tasks to complete if they are to run\",\n              isRepeatable: true,\n              args: {\n                name: \"wait_for\",\n              },\n            },\n            {\n              name: \"--depends-post\",\n              description: \"Dependencies to run after the task runs\",\n              isRepeatable: true,\n              args: {\n                name: \"depends_post\",\n              },\n            },\n            {\n              name: \"--description\",\n              description: \"Description of the task\",\n              isRepeatable: false,\n              args: {\n                name: \"description\",\n              },\n            },\n            {\n              name: \"--outputs\",\n              description:\n                \"Glob patterns of files this task creates, to skip if they are not modified\",\n              isRepeatable: true,\n              args: {\n                name: \"outputs\",\n              },\n            },\n            {\n              name: \"--run-windows\",\n              description: \"Command to run on windows\",\n              isRepeatable: false,\n              args: {\n                name: \"run_windows\",\n              },\n            },\n            {\n              name: \"--shell\",\n              description: \"Run the task in a specific shell\",\n              isRepeatable: false,\n              args: {\n                name: \"shell\",\n              },\n            },\n            {\n              name: \"--silent\",\n              description: \"Do not print the command or its output\",\n              isRepeatable: false,\n            },\n          ],\n          args: [\n            {\n              name: \"task\",\n              description: \"Tasks name to add\",\n              generators: simpleTaskGenerator,\n              debounce: true,\n            },\n            {\n              name: \"run\",\n              isOptional: true,\n              isVariadic: true,\n            },\n          ],\n        },\n        {\n          name: \"deps\",\n          description: \"Display a tree visualization of a dependency graph\",\n          options: [\n            {\n              name: \"--dot\",\n              description: \"Display dependencies in DOT format\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--hidden\",\n              description: \"Show hidden tasks\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"tasks\",\n            description:\n              \"Tasks to show dependencies for\\nCan specify multiple tasks by separating with spaces\\ne.g.: mise tasks deps lint test check\",\n            isOptional: true,\n            isVariadic: true,\n            generators: simpleTaskGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"edit\",\n          description: \"Edit a task with $EDITOR\",\n          options: [\n            {\n              name: [\"-p\", \"--path\"],\n              description: \"Display the path to the task instead of editing it\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"task\",\n            description: \"Task to edit\",\n            generators: simpleTaskGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"info\",\n          description: \"Get information about a task\",\n          options: [\n            {\n              name: [\"-J\", \"--json\"],\n              description: \"Output in JSON format\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"task\",\n            description: \"Name of the task to get information about\",\n            generators: simpleTaskGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"ls\",\n          description:\n            \"List available tasks to execute\\nThese may be included from the config file or from the project's .mise/tasks directory\\nmise will merge all tasks from all parent directories into this list.\",\n          options: [\n            {\n              name: [\"-g\", \"--global\"],\n              description: \"Only show global tasks\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-J\", \"--json\"],\n              description: \"Output in JSON format\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-l\", \"--local\"],\n              description: \"Only show non-global tasks\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-x\", \"--extended\"],\n              description: \"Show all columns\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--all\",\n              description:\n                \"Load all tasks from the entire monorepo, including sibling directories.\\nBy default, only tasks from the current directory hierarchy are loaded.\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--hidden\",\n              description: \"Show hidden tasks\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--no-header\",\n              description: \"Do not print table header\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--sort\",\n              description: \"Sort by column. Default is name.\",\n              isRepeatable: false,\n              args: {\n                name: \"column\",\n                suggestions: [\"name\", \"alias\", \"description\", \"source\"],\n              },\n            },\n            {\n              name: \"--sort-order\",\n              description: \"Sort order. Default is asc.\",\n              isRepeatable: false,\n              args: {\n                name: \"sort_order\",\n                suggestions: [\"asc\", \"desc\"],\n              },\n            },\n          ],\n        },\n        {\n          name: [\"run\", \"r\"],\n          description: \"Run task(s)\",\n          options: [\n            {\n              name: [\"-c\", \"--continue-on-error\"],\n              description: \"Continue running tasks even if one fails\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-C\", \"--cd\"],\n              description:\n                \"Change to this directory before executing the command\",\n              isRepeatable: false,\n              args: {\n                name: \"cd\",\n              },\n            },\n            {\n              name: [\"-f\", \"--force\"],\n              description:\n                \"Force the tasks to run even if outputs are up to date\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-j\", \"--jobs\"],\n              description:\n                \"Number of tasks to run in parallel\\n[default: 4]\\nConfigure with `jobs` config or `MISE_JOBS` env var\",\n              isRepeatable: false,\n              args: {\n                name: \"jobs\",\n              },\n            },\n            {\n              name: [\"-n\", \"--dry-run\"],\n              description:\n                \"Don't actually run the task(s), just print them in order of execution\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-o\", \"--output\"],\n              description:\n                \"Change how tasks information is output when running tasks\",\n              isRepeatable: false,\n              args: {\n                name: \"output\",\n              },\n            },\n            {\n              name: [\"-q\", \"--quiet\"],\n              description: \"Don't show extra output\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-r\", \"--raw\"],\n              description:\n                \"Read/write directly to stdin/stdout/stderr instead of by line\\nRedactions are not applied with this option\\nConfigure with `raw` config or `MISE_RAW` env var\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-s\", \"--shell\"],\n              description: \"Shell to use to run toml tasks\",\n              isRepeatable: false,\n              args: {\n                name: \"shell\",\n              },\n            },\n            {\n              name: [\"-S\", \"--silent\"],\n              description: \"Don't show any output except for errors\",\n              isRepeatable: false,\n            },\n            {\n              name: [\"-t\", \"--tool\"],\n              description:\n                \"Tool(s) to run in addition to what is in mise.toml files e.g.: node@20 python@3.10\",\n              isRepeatable: true,\n              args: {\n                name: \"tool@version\",\n                generators: toolVersionGenerator,\n                debounce: true,\n              },\n            },\n            {\n              name: \"--fresh-env\",\n              description:\n                \"Bypass the environment cache and recompute the environment\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--no-cache\",\n              description: \"Do not use cache on remote tasks\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--no-prepare\",\n              description: \"Skip automatic dependency preparation\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--no-timings\",\n              description: \"Hides elapsed time after each task completes\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--skip-deps\",\n              description:\n                \"Run only the specified tasks skipping all dependencies\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--timeout\",\n              description: \"Timeout for the task to complete\\ne.g.: 30s, 5m\",\n              isRepeatable: false,\n              args: {\n                name: \"timeout\",\n              },\n            },\n          ],\n          args: [\n            {\n              name: \"task\",\n              description:\n                \"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2\",\n              isOptional: true,\n              generators: simpleTaskGenerator,\n              debounce: true,\n            },\n            {\n              name: \"args\",\n              description:\n                'Arguments to pass to the tasks. Use \":::\" to separate tasks',\n              isOptional: true,\n              isVariadic: true,\n            },\n          ],\n          generateSpec: usageGenerateSpec([\"mise tasks --usage\"]),\n          cache: false,\n        },\n        {\n          name: \"validate\",\n          description: \"Validate tasks for common errors and issues\",\n          options: [\n            {\n              name: \"--errors-only\",\n              description: \"Only show errors (skip warnings)\",\n              isRepeatable: false,\n            },\n            {\n              name: \"--json\",\n              description: \"Output validation results in JSON format\",\n              isRepeatable: false,\n            },\n          ],\n          args: {\n            name: \"tasks\",\n            description:\n              \"Tasks to validate\\nIf not specified, validates all tasks\",\n            isOptional: true,\n            isVariadic: true,\n            generators: simpleTaskGenerator,\n            debounce: true,\n          },\n        },\n      ],\n      options: [\n        {\n          name: [\"-g\", \"--global\"],\n          description: \"Only show global tasks\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-l\", \"--local\"],\n          description: \"Only show non-global tasks\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-x\", \"--extended\"],\n          description: \"Show all columns\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--all\",\n          description:\n            \"Load all tasks from the entire monorepo, including sibling directories.\\nBy default, only tasks from the current directory hierarchy are loaded.\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--hidden\",\n          description: \"Show hidden tasks\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-header\",\n          description: \"Do not print table header\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--sort\",\n          description: \"Sort by column. Default is name.\",\n          isRepeatable: false,\n          args: {\n            name: \"column\",\n            suggestions: [\"name\", \"alias\", \"description\", \"source\"],\n          },\n        },\n        {\n          name: \"--sort-order\",\n          description: \"Sort order. Default is asc.\",\n          isRepeatable: false,\n          args: {\n            name: \"sort_order\",\n            suggestions: [\"asc\", \"desc\"],\n          },\n        },\n      ],\n      args: {\n        name: \"task\",\n        description: \"Task name to get info of\",\n        isOptional: true,\n        generators: simpleTaskGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"test-tool\",\n      description: \"Test a tool installs and executes\",\n      options: [\n        {\n          name: [\"-a\", \"--all\"],\n          description: \"Test every tool specified in registry/\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: \"--all-config\",\n          description: \"Test all tools specified in config files\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--include-non-defined\",\n          description:\n            \"Also test tools not defined in registry/, guessing how to test it\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tools\",\n        description: \"Tool(s) to test\",\n        isOptional: true,\n        isVariadic: true,\n      },\n    },\n    {\n      name: \"tool\",\n      description: \"Gets information about a tool\",\n      options: [\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Output in JSON format\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--active\",\n          description: \"Only show active versions\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--backend\",\n          description: \"Only show backend field\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--config-source\",\n          description: \"Only show config source\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--description\",\n          description: \"Only show description field\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--installed\",\n          description: \"Only show installed versions\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--requested\",\n          description: \"Only show requested versions\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--tool-options\",\n          description: \"Only show tool options\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"tool\",\n        description: \"Tool name to get information about\",\n        generators: completionGeneratorTemplate(`mise registry --complete`),\n        debounce: true,\n      },\n    },\n    {\n      name: \"tool-stub\",\n      description: \"Execute a tool stub\",\n      args: [\n        {\n          name: \"file\",\n          description: \"Path to the TOML tool stub file to execute\",\n          template: \"filepaths\",\n        },\n        {\n          name: \"args\",\n          description: \"Arguments to pass to the tool\",\n          isOptional: true,\n          isVariadic: true,\n        },\n      ],\n    },\n    {\n      name: \"trust\",\n      description: \"Marks a config file as trusted\",\n      options: [\n        {\n          name: [\"-a\", \"--all\"],\n          description:\n            \"Trust all config files in the current directory and its parents\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--ignore\",\n          description: \"Do not trust this config and ignore it in the future\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--show\",\n          description:\n            \"Show the trusted status of config files from the current directory and its parents.\\nDoes not trust or untrust any files.\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--untrust\",\n          description: \"No longer trust this config, will prompt in the future\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"config_file\",\n        description: \"The config file to trust\",\n        isOptional: true,\n        template: \"filepaths\",\n        generators: configPathGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"uninstall\",\n      description: \"Removes installed tool versions\",\n      options: [\n        {\n          name: [\"-a\", \"--all\"],\n          description: \"Delete all installed versions\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Do not actually delete anything\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--dry-run-code\",\n          description:\n            \"Like --dry-run but exits with code 1 if there are tools to uninstall\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"installed_tool@version\",\n        description: \"Tool(s) to remove\",\n        isOptional: true,\n        isVariadic: true,\n        generators: installedToolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"unset\",\n      description: \"Remove environment variable(s) from the config file.\",\n      options: [\n        {\n          name: [\"-f\", \"--file\"],\n          description: \"Specify a file to use instead of `mise.toml`\",\n          isRepeatable: false,\n          args: {\n            name: \"file\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: [\"-g\", \"--global\"],\n          description: \"Use the global config file\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"env_key\",\n        description: \"Environment variable(s) to remove\\ne.g.: NODE_ENV\",\n        isOptional: true,\n        isVariadic: true,\n        generators: completionGeneratorTemplate(`mise set --complete`),\n        debounce: true,\n      },\n    },\n    {\n      name: [\"unuse\", \"rm\", \"remove\"],\n      description: \"Removes installed tool versions from mise.toml\",\n      options: [\n        {\n          name: [\"-e\", \"--env\"],\n          description:\n            \"Create/modify an environment-specific config file like .mise.<env>.toml\",\n          isRepeatable: false,\n          args: {\n            name: \"env\",\n          },\n        },\n        {\n          name: [\"-g\", \"--global\"],\n          description:\n            \"Use the global config file (`~/.config/mise/config.toml`) instead of the local one\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-p\", \"--path\"],\n          description: \"Specify a path to a config file or directory\",\n          isRepeatable: false,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--no-prune\",\n          description: \"Do not also prune the installed version\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"installed_tool@version\",\n        description: \"Tool(s) to remove\",\n        isVariadic: true,\n        generators: installedToolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"upgrade\", \"up\"],\n      description: \"Upgrades outdated tools\",\n      options: [\n        {\n          name: [\"-i\", \"--interactive\"],\n          description:\n            \"Display multiselect menu to choose which tools to upgrade\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-l\", \"--bump\"],\n          description:\n            \"Upgrades to the latest version available, bumping the version in mise.toml\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description: \"Just print what would be done, don't actually do it\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-x\", \"--exclude\"],\n          description: \"Tool(s) to exclude from upgrading\\ne.g.: go python\",\n          isRepeatable: true,\n          args: {\n            name: \"installed_tool\",\n            generators: completionGeneratorTemplate(\n              `mise ls -i | awk '{print $1}' | uniq`\n            ),\n            debounce: true,\n          },\n        },\n        {\n          name: \"--before\",\n          description: \"Only upgrade to versions released before this date\",\n          isRepeatable: false,\n          args: {\n            name: \"before\",\n          },\n        },\n        {\n          name: \"--dry-run-code\",\n          description:\n            \"Like --dry-run but exits with code 1 if there are outdated tools\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--local\",\n          description: \"Only upgrade tools defined in local config files\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"installed_tool@version\",\n        description:\n          \"Tool(s) to upgrade\\ne.g.: node@20 python@3.10\\nIf not specified, all current tools will be upgraded\",\n        isOptional: true,\n        isVariadic: true,\n        generators: installedToolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"use\", \"u\"],\n      description: \"Installs a tool and adds the version to mise.toml.\",\n      options: [\n        {\n          name: [\"-e\", \"--env\"],\n          description:\n            \"Create/modify an environment-specific config file like .mise.<env>.toml\",\n          isRepeatable: false,\n          args: {\n            name: \"env\",\n          },\n        },\n        {\n          name: [\"-f\", \"--force\"],\n          description: \"Force reinstall even if already installed\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-g\", \"--global\"],\n          description:\n            \"Use the global config file (`~/.config/mise/config.toml`) instead of the local one\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-j\", \"--jobs\"],\n          description: \"Number of jobs to run in parallel\\n[default: 4]\",\n          isRepeatable: false,\n          args: {\n            name: \"jobs\",\n          },\n        },\n        {\n          name: [\"-n\", \"--dry-run\"],\n          description:\n            \"Perform a dry run, showing what would be installed and modified without making changes\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-p\", \"--path\"],\n          description: \"Specify a path to a config file or directory\",\n          isRepeatable: false,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--before\",\n          description: \"Only install versions released before this date\",\n          isRepeatable: false,\n          args: {\n            name: \"before\",\n          },\n        },\n        {\n          name: \"--dry-run-code\",\n          description:\n            \"Like --dry-run but exits with code 1 if there are changes to make\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--fuzzy\",\n          description: \"Save fuzzy version to config file\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--pin\",\n          description:\n            \"Save exact version to config file\\ne.g.: `mise use --pin node@20` will save 20.0.0 as the version\\nSet `MISE_PIN=1` to make this the default behavior\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--raw\",\n          description:\n            \"Directly pipe stdin/stdout/stderr from plugin to user Sets `--jobs=1`\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--remove\",\n          description: \"Remove the plugin(s) from config file\",\n          isRepeatable: true,\n          args: {\n            name: \"plugin\",\n            generators: pluginGenerator,\n            debounce: true,\n          },\n        },\n      ],\n      args: {\n        name: \"tool@version\",\n        description: \"Tool(s) to add to config file\",\n        isOptional: true,\n        isVariadic: true,\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: [\"version\", \"v\"],\n      description: \"Display the version of mise\",\n      options: [\n        {\n          name: [\"-J\", \"--json\"],\n          description: \"Print the version information in JSON format\",\n          isRepeatable: false,\n        },\n      ],\n    },\n    {\n      name: [\"watch\", \"w\"],\n      description: \"Run task(s) and watch for changes to rerun it\",\n      options: [\n        {\n          name: \"--skip-deps\",\n          description: \"Run only the specified tasks skipping all dependencies\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-w\", \"--watch\"],\n          description: \"Watch a specific file or directory\",\n          isRepeatable: true,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: [\"-W\", \"--watch-non-recursive\"],\n          description: \"Watch a specific directory, non-recursively\",\n          isRepeatable: true,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: [\"-F\", \"--watch-file\"],\n          description: \"Watch files and directories from a file\",\n          isRepeatable: false,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: [\"-c\", \"--clear\"],\n          description: \"Clear screen before running command\",\n          isRepeatable: false,\n          args: {\n            name: \"mode\",\n            suggestions: [\"clear\", \"reset\"],\n          },\n        },\n        {\n          name: [\"-o\", \"--on-busy-update\"],\n          description:\n            \"What to do when receiving events while the command is running\",\n          isRepeatable: false,\n          args: {\n            name: \"mode\",\n            suggestions: [\"queue\", \"do-nothing\", \"restart\", \"signal\"],\n          },\n        },\n        {\n          name: [\"-r\", \"--restart\"],\n          description: \"Restart the process if it's still running\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-s\", \"--signal\"],\n          description: \"Send a signal to the process when it's still running\",\n          isRepeatable: false,\n          args: {\n            name: \"signal\",\n          },\n        },\n        {\n          name: \"--stop-signal\",\n          description: \"Signal to send to stop the command\",\n          isRepeatable: false,\n          args: {\n            name: \"signal\",\n          },\n        },\n        {\n          name: \"--stop-timeout\",\n          description: \"Time to wait for the command to exit gracefully\",\n          isRepeatable: false,\n          args: {\n            name: \"timeout\",\n          },\n        },\n        {\n          name: \"--map-signal\",\n          description:\n            \"Translate signals from the OS to signals to send to the command\",\n          isRepeatable: true,\n          args: {\n            name: \"signal:signal\",\n          },\n        },\n        {\n          name: [\"-d\", \"--debounce\"],\n          description: \"Time to wait for new events before taking action\",\n          isRepeatable: false,\n          args: {\n            name: \"timeout\",\n          },\n        },\n        {\n          name: \"--stdin-quit\",\n          description: \"Exit when stdin closes\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-vcs-ignore\",\n          description: \"Don't load gitignores\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-project-ignore\",\n          description: \"Don't load project-local ignores\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-global-ignore\",\n          description: \"Don't load global ignores\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-default-ignore\",\n          description: \"Don't use internal default ignores\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--no-discover-ignore\",\n          description: \"Don't discover ignore files at all\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--ignore-nothing\",\n          description: \"Don't ignore anything at all\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-p\", \"--postpone\"],\n          description: \"Wait until first change before running command\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--delay-run\",\n          description: \"Sleep before running the command\",\n          isRepeatable: false,\n          args: {\n            name: \"duration\",\n          },\n        },\n        {\n          name: \"--poll\",\n          description: \"Poll for filesystem changes\",\n          isRepeatable: false,\n          args: {\n            name: \"interval\",\n          },\n        },\n        {\n          name: \"--shell\",\n          description: \"Use a different shell\",\n          isRepeatable: false,\n          args: {\n            name: \"shell\",\n          },\n        },\n        {\n          name: \"-n\",\n          description: \"Shorthand for '--shell=none'\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--emit-events-to\",\n          description: \"Configure event emission\",\n          isRepeatable: false,\n          args: {\n            name: \"mode\",\n            suggestions: [\n              \"environment\",\n              \"stdio\",\n              \"file\",\n              \"json-stdio\",\n              \"json-file\",\n              \"none\",\n            ],\n          },\n        },\n        {\n          name: \"--only-emit-events\",\n          description: \"Only emit events to stdout, run no commands\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-E\", \"--env\"],\n          description: \"Add env vars to the command\",\n          isRepeatable: true,\n          args: {\n            name: \"key=value\",\n          },\n        },\n        {\n          name: \"--wrap-process\",\n          description: \"Configure how the process is wrapped\",\n          isRepeatable: false,\n          args: {\n            name: \"mode\",\n            suggestions: [\"group\", \"session\", \"none\"],\n          },\n        },\n        {\n          name: [\"-N\", \"--notify\"],\n          description: \"Alert when commands start and end\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--color\",\n          description: \"When to use terminal colours\",\n          isRepeatable: false,\n          args: {\n            name: \"mode\",\n            suggestions: [\"auto\", \"always\", \"never\"],\n          },\n        },\n        {\n          name: \"--timings\",\n          description: \"Print how long the command took to run\",\n          isRepeatable: false,\n        },\n        {\n          name: [\"-q\", \"--quiet\"],\n          description: \"Don't print starting and stopping messages\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--bell\",\n          description: \"Ring the terminal bell on command completion\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--project-origin\",\n          description: \"Set the project origin\",\n          isRepeatable: false,\n          args: {\n            name: \"directory\",\n            template: \"folders\",\n          },\n        },\n        {\n          name: \"--workdir\",\n          description: \"Set the working directory\",\n          isRepeatable: false,\n          args: {\n            name: \"directory\",\n            template: \"folders\",\n          },\n        },\n        {\n          name: [\"-e\", \"--exts\"],\n          description: \"Filename extensions to filter to\",\n          isRepeatable: true,\n          args: {\n            name: \"extensions\",\n          },\n        },\n        {\n          name: [\"-f\", \"--filter\"],\n          description: \"Filename patterns to filter to\",\n          isRepeatable: true,\n          args: {\n            name: \"pattern\",\n          },\n        },\n        {\n          name: \"--filter-file\",\n          description: \"Files to load filters from\",\n          isRepeatable: true,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: [\"-J\", \"--filter-prog\"],\n          description: \"[experimental] Filter programs\",\n          isRepeatable: true,\n          args: {\n            name: \"expression\",\n          },\n        },\n        {\n          name: [\"-i\", \"--ignore\"],\n          description: \"Filename patterns to filter out\",\n          isRepeatable: true,\n          args: {\n            name: \"pattern\",\n          },\n        },\n        {\n          name: \"--ignore-file\",\n          description: \"Files to load ignores from\",\n          isRepeatable: true,\n          args: {\n            name: \"path\",\n            template: \"filepaths\",\n          },\n        },\n        {\n          name: \"--fs-events\",\n          description: \"Filesystem events to filter to\",\n          isRepeatable: true,\n          args: {\n            name: \"events\",\n            suggestions: [\n              \"access\",\n              \"create\",\n              \"remove\",\n              \"rename\",\n              \"modify\",\n              \"metadata\",\n            ],\n          },\n        },\n        {\n          name: \"--no-meta\",\n          description: \"Don't emit fs events for metadata changes\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--print-events\",\n          description: \"Print events that trigger actions\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--manual\",\n          description: \"Show the manual page\",\n          isRepeatable: false,\n        },\n      ],\n      args: [\n        {\n          name: \"task\",\n          description:\n            \"Tasks to run\\nCan specify multiple tasks by separating with `:::`\\ne.g.: `mise run task1 arg1 arg2 ::: task2 arg1 arg2`\",\n          isOptional: true,\n          generators: simpleTaskGenerator,\n          debounce: true,\n        },\n        {\n          name: \"args\",\n          description: \"Task and arguments to run\",\n          isOptional: true,\n          isVariadic: true,\n        },\n      ],\n    },\n    {\n      name: \"where\",\n      description: \"Display the installation path for a tool\",\n      args: {\n        name: \"tool@version\",\n        description:\n          'Tool(s) to look up\\ne.g.: ruby@3\\nif \"@<PREFIX>\" is specified, it will show the latest installed version\\nthat matches the prefix\\notherwise, it will show the current, active installed version',\n        generators: toolVersionGenerator,\n        debounce: true,\n      },\n    },\n    {\n      name: \"which\",\n      description: \"Shows the path that a tool's bin points to.\",\n      options: [\n        {\n          name: [\"-t\", \"--tool\"],\n          description:\n            \"Use a specific tool@version\\ne.g.: `mise which npm --tool=node@20`\",\n          isRepeatable: false,\n          args: {\n            name: \"tool@version\",\n            generators: toolVersionGenerator,\n            debounce: true,\n          },\n        },\n        {\n          name: \"--plugin\",\n          description: \"Show the plugin name instead of the path\",\n          isRepeatable: false,\n        },\n        {\n          name: \"--version\",\n          description: \"Show the version instead of the path\",\n          isRepeatable: false,\n        },\n      ],\n      args: {\n        name: \"bin_name\",\n        description: \"The bin to look up\",\n        isOptional: true,\n        generators: completionGeneratorTemplate(`mise which --complete`),\n        debounce: true,\n      },\n    },\n  ],\n  options: [\n    {\n      name: [\"-C\", \"--cd\"],\n      description: \"Change directory before running command\",\n      isRepeatable: false,\n      args: {\n        name: \"dir\",\n        template: \"folders\",\n      },\n    },\n    {\n      name: [\"-E\", \"--env\"],\n      description: \"Set the environment for loading `mise.<ENV>.toml`\",\n      isRepeatable: true,\n      args: {\n        name: \"env\",\n      },\n    },\n    {\n      name: [\"-j\", \"--jobs\"],\n      description: \"How many jobs to run in parallel [default: 8]\",\n      isRepeatable: false,\n      args: {\n        name: \"jobs\",\n      },\n    },\n    {\n      name: [\"-q\", \"--quiet\"],\n      description: \"Suppress non-error messages\",\n      isRepeatable: false,\n    },\n    {\n      name: [\"-v\", \"--verbose\"],\n      description: \"Show extra output (use -vv for even more)\",\n      isRepeatable: true,\n    },\n    {\n      name: [\"-y\", \"--yes\"],\n      description: \"Answer yes to all confirmation prompts\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--no-config\",\n      description: \"Do not load any config files\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--no-env\",\n      description: \"Do not load environment variables from config files\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--no-hooks\",\n      description: \"Do not execute hooks from config files\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--output\",\n      isRepeatable: false,\n      args: {\n        name: \"output\",\n      },\n    },\n    {\n      name: \"--raw\",\n      description:\n        \"Read/write directly to stdin/stdout/stderr instead of by line\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--locked\",\n      description: \"Require lockfile URLs to be present during installation\",\n      isRepeatable: false,\n    },\n    {\n      name: \"--silent\",\n      description: \"Suppress all task output and mise non-error messages\",\n      isRepeatable: false,\n    },\n  ],\n  args: {\n    name: \"task\",\n    description: \"Task to run\",\n    isOptional: true,\n    generators: simpleTaskGenerator,\n    debounce: true,\n  },\n};\nexport default completionSpec;\n"
  },
  {
    "path": "xtasks/filetask",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2154\n#USAGE flag \"-f --force\" help=\"Overwrite existing <file>\"\n#USAGE flag \"-u --user <user>\" help=\"User to run as\"\n#USAGE arg \"<file>\" help=\"The file to write\" default=\"file.txt\"\n#USAGE arg \"<arg_with_default>\" help=\"An arg with a default\" default=\"mydefault\"\n\n#MISE description=\"This is a test build script\"\n#MISE sources=[\".test-tool-versions\"]\n#MISE outputs=[\"$MISE_PROJECT_ROOT/test/test-build-output.txt\"]\n#MISE env={TEST_BUILDSCRIPT_ENV_VAR = \"VALID\"}\n#MISE dir=\"{{config_root}}\"\n#MISE alias=\"ft\"\n\nset -exo pipefail\ncd \"$MISE_PROJECT_ROOT\" || exit 1\necho \"running test-build script\"\necho \"TEST_BUILDSCRIPT_ENV_VAR: $TEST_BUILDSCRIPT_ENV_VAR\" >test/test-build-output.txt\necho \"ARGS:\" \"$@\"\n\necho \"usage_force: $usage_force\"\necho \"usage_user: $usage_user\"\necho \"usage_file: $usage_file\"\n"
  },
  {
    "path": "xtasks/filetask.bat",
    "content": "echo mytask\n"
  },
  {
    "path": "xtasks/lint/hk",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Lint HK files\"\n#MISE wait_for=[\"build\"]\nHK_FAIL_FAST=0 exec hk check --all --exclude aqua-registry\n"
  },
  {
    "path": "xtasks/lint-fix.ps1",
    "content": "#MISE alias=[\"format\"]\n#MISE wait_for=[\"build\", \"render:schema\"]\n$ErrorActionPreference = \"Stop\"\n$PSNativeCommandUseErrorActionPreference = $true\n\ncargo clippy --fix --allow-staged --allow-dirty -- -Dwarnings\nprettier -w .\ncargo fmt --all\n"
  },
  {
    "path": "xtasks/lint-fix.sh",
    "content": "#!/usr/bin/env bash\n#MISE alias=[\"format\", \"fix\"]\n#MISE wait_for=[\"render:schema\"]\n#MISE description=\"Automatically fix lint issues\"\nset -euxo pipefail\n\nhk fix --all --exclude crates/aqua-registry/aqua-registry\n"
  },
  {
    "path": "xtasks/release-plz",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Release with release-plz\"\nset -euxo pipefail\n\n# Ensure this script is only run in GitHub Actions\nif [[ -z ${GITHUB_ACTIONS:-} ]]; then\n\techo \"Error: This script must be run in GitHub Actions\"\n\techo \"The release-plz script should only be executed in the CI/CD pipeline\"\n\texit 1\nfi\n\ngit config user.name mise-en-dev\ngit config user.email release@mise.jdx.dev\n\n# Check if the most recent tag has a matching GitHub Release.\n# If not, the previous release workflow likely failed to fire — re-trigger it.\nlatest_tag=\"$(git tag --list 'v[0-9]*' --sort=-v:refname | head -1 || true)\"\nif [[ -n $latest_tag ]]; then\n\tif ! gh api \"repos/$GITHUB_REPOSITORY/releases/tags/$latest_tag\" --silent 2>/dev/null; then\n\t\techo \"Tag $latest_tag has no GitHub Release — triggering release workflow\"\n\t\tgh workflow run release.yml --ref \"$latest_tag\"\n\tfi\nfi\n\nexists_on_crates() {\n\tcrate=\"$1\"\n\tversion=\"$2\"\n\tif cargo info --registry \"crates-io\" --color never --quiet \"$crate@$version\" 2>/dev/null | grep -qE \"^version:\\s+$version\\b\"; then\n\t\treturn 0\n\tfi\n\tif curl -fsSL \"https://crates.io/api/v1/crates/$crate/$version\" >/dev/null 2>&1; then\n\t\treturn 0\n\tfi\n\treturn 1\n}\n\n# Check if a subcrate has changes since its last tagged release\n# Returns 0 if changes exist (should publish), 1 if no changes\nhas_crate_changes() {\n\tlocal crate_name=\"$1\"\n\tlocal crate_dir=\"$2\"\n\n\t# Get the latest tag for this crate\n\tlocal latest_tag\n\tlatest_tag=$(git tag --list \"${crate_name}-v*\" --sort=-v:refname | head -1 || true)\n\n\tif [[ -z $latest_tag ]]; then\n\t\techo \"No previous tag found for $crate_name, will publish\"\n\t\treturn 0\n\tfi\n\n\t# Check if there are changes in the crate directory since the tag\n\tif git diff --quiet \"$latest_tag\" -- \"$crate_dir\"; then\n\t\techo \"No changes in $crate_name since $latest_tag\"\n\t\treturn 1\n\telse\n\t\techo \"Changes detected in $crate_name since $latest_tag\"\n\t\treturn 0\n\tfi\n}\n\n# Get the latest published version of a crate from crates.io\nget_latest_crates_version() {\n\tlocal crate=\"$1\"\n\tcargo info --registry \"crates-io\" --color never --quiet \"$crate\" 2>/dev/null | grep \"^version:\" | cut -d' ' -f2 || echo \"\"\n}\n\n# Check if a directory has uncommitted changes (staged or unstaged)\nhas_uncommitted_changes() {\n\tlocal dir=\"$1\"\n\t# Check for any changes (staged or unstaged) in the directory\n\tif git diff --quiet HEAD -- \"$dir\" 2>/dev/null && git diff --quiet --cached -- \"$dir\" 2>/dev/null; then\n\t\t# Also check for untracked files\n\t\tif [[ -z $(git ls-files --others --exclude-standard -- \"$dir\") ]]; then\n\t\t\treturn 1 # No changes\n\t\tfi\n\tfi\n\treturn 0 # Has changes\n}\n\n# Bump subcrate version if it has uncommitted changes (for prep phase)\nbump_subcrate_if_changed() {\n\tlocal crate_name=\"$1\"\n\tlocal crate_dir=\"$2\"\n\n\tif ! has_uncommitted_changes \"$crate_dir\"; then\n\t\techo \"No uncommitted changes in $crate_name, keeping current version\"\n\t\treturn\n\tfi\n\n\techo \"Uncommitted changes detected in $crate_name, bumping version\"\n\tlocal cur_version\n\tcur_version=\"$(cargo pkgid -p \"$crate_name\" | cut -d# -f2)\"\n\n\t# Use calver: YYYY.M.PATCH\n\tlocal year month\n\tyear=\"$(date +%Y)\"\n\tmonth=\"$(date +%-m)\"\n\n\tif echo \"$cur_version\" | grep -qE \"^$year\\.$month\\.\"; then\n\t\t# Same year.month, bump patch (e.g., 2025.12.0 -> 2025.12.1)\n\t\tcargo set-version --bump patch -p \"$crate_name\"\n\telse\n\t\t# New month or new year, start fresh at YYYY.MM.0\n\t\tcargo set-version \"$year.$month.0\" -p \"$crate_name\"\n\tfi\n\n\tlocal new_version\n\tnew_version=\"$(cargo pkgid -p \"$crate_name\" | cut -d# -f2)\"\n\techo \"Bumped $crate_name from $cur_version to $new_version\"\n}\n\n# Bump and publish a subcrate if it has changes\n# Sets PUBLISHED_<CRATE>_VERSION variable with the version to use\nbump_and_publish_subcrate() {\n\tlocal crate_name=\"$1\"\n\tlocal crate_dir=\"$2\"\n\tlocal var_name=\"$3\" # Variable name to set (e.g., VFOX_VERSION)\n\n\tlocal cur_version\n\tcur_version=\"$(cargo pkgid -p \"$crate_name\" | cut -d# -f2)\"\n\n\tif ! has_crate_changes \"$crate_name\" \"$crate_dir\"; then\n\t\t# No changes - use the current published version\n\t\tlocal published_version\n\t\tpublished_version=$(get_latest_crates_version \"$crate_name\")\n\t\tif [[ -n $published_version ]]; then\n\t\t\techo \"Using existing $crate_name@$published_version (no changes)\"\n\t\t\teval \"$var_name=$published_version\"\n\t\telse\n\t\t\techo \"Warning: $crate_name not found on crates.io, using current version\"\n\t\t\teval \"$var_name=$cur_version\"\n\t\tfi\n\t\treturn\n\tfi\n\n\t# Has changes - bump version and publish\n\t# Use calver: YYYY.M.PATCH\n\tlocal year month\n\tyear=\"$(date +%Y)\"\n\tmonth=\"$(date +%-m)\"\n\n\tif echo \"$cur_version\" | grep -qE \"^$year\\.$month\\.\"; then\n\t\t# Same year.month, bump patch (e.g., 2025.12.0 -> 2025.12.1)\n\t\tcargo set-version --bump patch -p \"$crate_name\"\n\telse\n\t\t# New month or new year, start fresh at YYYY.MM.0\n\t\tcargo set-version \"$year.$month.0\" -p \"$crate_name\"\n\tfi\n\n\tlocal new_version\n\tnew_version=\"$(cargo pkgid -p \"$crate_name\" | cut -d# -f2)\"\n\n\t# Keep bumping if the version already exists on crates.io\n\t# This handles cases where a version was published but local code has changed since\n\twhile exists_on_crates \"$crate_name\" \"$new_version\"; do\n\t\techo \"$crate_name@$new_version already on crates.io, bumping again\"\n\t\tcargo set-version --bump patch -p \"$crate_name\"\n\t\tnew_version=\"$(cargo pkgid -p \"$crate_name\" | cut -d# -f2)\"\n\tdone\n\n\techo \"Publishing $crate_name@$new_version\"\n\tcargo publish --allow-dirty -p \"$crate_name\"\n\n\t# Create tag for this subcrate release\n\tlocal tag_name=\"${crate_name}-v${new_version}\"\n\tif git rev-parse -q --verify \"refs/tags/$tag_name\" >/dev/null ||\n\t\tgit ls-remote --exit-code --tags origin \"$tag_name\" >/dev/null 2>&1; then\n\t\techo \"Tag $tag_name already exists, skipping tag creation\"\n\telse\n\t\tgit tag \"$tag_name\" -s -m \"Release $crate_name $new_version\"\n\tfi\n\n\teval \"$var_name=$new_version\"\n}\n\ncur_version=\"$(cargo pkgid mise | cut -d# -f2)\"\nlatest_version=\"$(cargo info --registry \"crates-io\" --color never --quiet mise | grep \"^version:\" | cut -d' ' -f2)\"\nif [[ $cur_version != \"$latest_version\" ]]; then\n\techo \"Releasing mise $cur_version\"\n\n\t# Handle subcrates with independent versioning\n\tVFOX_VERSION=\"\"\n\tAQUA_REGISTRY_VERSION=\"\"\n\tINTERACTIVE_CONFIG_VERSION=\"\"\n\n\tbump_and_publish_subcrate \"vfox\" \"crates/vfox\" \"VFOX_VERSION\"\n\tcargo add \"vfox@$VFOX_VERSION\"\n\n\tbump_and_publish_subcrate \"aqua-registry\" \"crates/aqua-registry\" \"AQUA_REGISTRY_VERSION\"\n\tcargo add \"aqua-registry@$AQUA_REGISTRY_VERSION\"\n\n\t# Copy schema into crate directory so cargo publish verification can find it\n\tcp schema/mise.json crates/mise-interactive-config/mise.json\n\tbump_and_publish_subcrate \"mise-interactive-config\" \"crates/mise-interactive-config\" \"INTERACTIVE_CONFIG_VERSION\"\n\trm -f crates/mise-interactive-config/mise.json\n\tcargo add \"mise-interactive-config@$INTERACTIVE_CONFIG_VERSION\"\n\n\tif exists_on_crates mise \"$cur_version\"; then\n\t\techo \"mise@$cur_version already on crates.io, skipping publish\"\n\telse\n\t\tcargo publish --allow-dirty -p mise\n\tfi\n\n\tchangelog=\"$(git cliff --tag \"v$cur_version\" --strip all --unreleased)\"\n\tchangelog=\"$(echo \"$changelog\" | tail -n +3)\"\n\tif git rev-parse -q --verify \"refs/tags/v$cur_version\" >/dev/null ||\n\t\tgit ls-remote --exit-code --tags origin \"v$cur_version\" >/dev/null 2>&1; then\n\t\techo \"Tag v$cur_version already exists, skipping tag creation\"\n\telse\n\t\tgit tag \"v$cur_version\" -s -m \"$changelog\"\n\tfi\n\n\t# Push all tags (mise + any subcrate tags)\n\tgit push --tags\n\texit 0\nfi\n\nyear=\"$(date +%Y)\"\nmonth=\"$(date +%-m)\"\nif echo \"$cur_version\" | grep -e \"^$year\\.$month\\.\"; then\n\tcargo set-version --bump patch -p mise\nelif echo \"$cur_version\" | grep -e \"^$year\\.\"; then\n\tcargo set-version --bump minor -p mise\nelse\n\tcargo set-version \"$year.1.0\" -p mise\nfi\n\nversion=\"$(cargo pkgid mise | cut -d# -f2)\"\nsed -i.bak \"s/^[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\\(-rc\\.[0-9]\\+\\)\\? macos-arm64 ([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\})$/$version macos-arm64 ($(date +%Y-%m-%d))/\" README.md\nsed -i.bak \"s/^Version: [0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\\(-rc\\.[0-9]\\+\\)\\?$/Version: $version/\" packaging/rpm/mise.spec\nsed -i.bak \"s/version = \\\"[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\\(-rc\\.[0-9]\\+\\)\\?\\\";$/version = \\\"$version\\\";/\" default.nix\nsed -i.bak \"s/version: \\\"[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+\\(-rc\\.[0-9]\\+\\)\\?\\\"$/version: \\\"$version\\\"/\" snapcraft.yaml\n\n# Update GitHub star count using gh CLI\nstars_raw=\"$(gh api repos/jdx/mise --jq '.stargazers_count')\"\nif [[ -n $stars_raw ]]; then\n\tif [[ $stars_raw -ge 1000 ]]; then\n\t\t# Format as k notation (e.g., 19346 -> 19.3k)\n\t\tstars_formatted=\"$(echo \"scale=1; $stars_raw / 1000\" | bc)k\"\n\t\t# Remove trailing .0k\n\t\tstars_formatted=\"${stars_formatted/.0k/k}\"\n\telse\n\t\tstars_formatted=\"$stars_raw\"\n\tfi\n\n\t# Update the stars data file\n\tcat >docs/.vitepress/stars.data.ts <<EOF\n// This file is auto-updated by xtasks/release-plz\n// Current star count from GitHub API\nexport default {\n  load() {\n    return {\n      stars: \"$stars_formatted\",\n    };\n  },\n};\nEOF\n\techo \"Updated star count to $stars_formatted\"\nfi\n\n# fetch-gpg-keys must run before render (which includes build) since it\n# recreates src/assets/gpg/ which is read at compile time via include_str!\nmise run fetch-gpg-keys\nmise run render ::: lint-fix\n\n# Capture current aqua-registry package list before updating\nOLD_AQUA_PKGS=\"\"\nif [[ -d crates/aqua-registry/aqua-registry/pkgs ]]; then\n\tOLD_AQUA_PKGS=\"$(find crates/aqua-registry/aqua-registry/pkgs -name registry.yaml -type f | sed 's|crates/aqua-registry/aqua-registry/pkgs/||;s|/registry.yaml||' | sort)\"\nfi\n\nrm -rf crates/aqua-registry/aqua-registry\ngit clone https://github.com/aquaproj/aqua-registry crates/aqua-registry/aqua-registry\n# Keep only pkgs/**/registry.yaml files, remove everything else\nfind crates/aqua-registry/aqua-registry -type f ! -path \"crates/aqua-registry/aqua-registry/pkgs/*/registry.yaml\" ! -name LICENSE -delete\nfind crates/aqua-registry/aqua-registry -type d -empty -delete\n\n# Capture new aqua-registry package list after updating\nNEW_AQUA_PKGS=\"$(find crates/aqua-registry/aqua-registry/pkgs -name registry.yaml -type f | sed 's|crates/aqua-registry/aqua-registry/pkgs/||;s|/registry.yaml||' | sort)\"\n\n# Generate aqua-registry changelog section for both CHANGELOG.md and PR body\nAQUA_CHANGELOG_MD=\"$(./scripts/gen-aqua-changelog.sh \"$OLD_AQUA_PKGS\" \"$NEW_AQUA_PKGS\" \"###\" || true)\"\nAQUA_CHANGELOG_PR=\"$(./scripts/gen-aqua-changelog.sh \"$OLD_AQUA_PKGS\" \"$NEW_AQUA_PKGS\" \"##\" || true)\"\n\n# Generate changelog using git-cliff with explicit calver version (not --bump which uses semver)\n# LLM editorialization happens in release.yml after merge\n# Use --unreleased --prepend to only add the new release entry, preserving existing content\n# (including previously injected aqua-registry sections from older releases)\ngit cliff --tag \"v$version\" --unreleased --prepend CHANGELOG.md\n\n# Get the unreleased notes for PR body (strip version header since PR title has version)\nPR_NOTES=\"$(git cliff --tag \"v$version\" --unreleased --strip all | tail -n +3)\"\n\n# Inject aqua-registry updates into CHANGELOG.md if there are any\nif [[ -n $AQUA_CHANGELOG_MD ]]; then\n\t# Find the FIRST release section (the one we just added) and inject aqua section at the end, before the next release\n\t# Use ENVIRON instead of -v to avoid awk interpreting backslash escape sequences\n\texport AQUA_CHANGELOG_MD\n\tawk '\n\t\t/^## \\[/ {\n\t\t\tif (release_count == 1 && !inserted) {\n\t\t\t\t# We are at the second release, inject aqua section before it\n\t\t\t\tprint ENVIRON[\"AQUA_CHANGELOG_MD\"]\n\t\t\t\tprint \"\"\n\t\t\t\tinserted = 1\n\t\t\t}\n\t\t\trelease_count++\n\t\t}\n\t\t{print}\n\t\tEND {\n\t\t\t# If we never hit a second release (only one release in file), append at end\n\t\t\tif (release_count == 1 && !inserted) {\n\t\t\t\tprint \"\"\n\t\t\t\tprint ENVIRON[\"AQUA_CHANGELOG_MD\"]\n\t\t\t}\n\t\t}\n\t' CHANGELOG.md >CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md\nfi\n\n# TODO: re-enable once fd v10.4.0 asset is fixed (missing fd-v10.4.0-x86_64-unknown-linux-musl.tar.gz)\n# mise up\nmise lock\n# Refresh PATH after mise up, since upgraded tools have new install paths\neval \"$(mise env)\"\n\n# Update embedded vfox plugins (delete all and re-clone fresh, similar to aqua-registry)\nEMBEDDED_PLUGINS_DIR=\"crates/vfox/embedded-plugins\"\nrm -rf \"$EMBEDDED_PLUGINS_DIR\"\nmkdir -p \"$EMBEDDED_PLUGINS_DIR\"\n\n# Clone all tools where vfox is the FIRST (default) backend\nmise registry | awk '$2 ~ /^vfox:/ {print $2}' | sed 's|vfox:||' | sort -u | while read -r repo_path; do\n\tplugin=\"$(basename \"$repo_path\")\"\n\techo \"Cloning $plugin from https://github.com/$repo_path\"\n\tTEMP_DIR=\"$(mktemp -d)\"\n\tgit clone --depth 1 \"https://github.com/$repo_path.git\" \"$TEMP_DIR\" 2>&1 | grep -v \"^Cloning\" || true\n\tDEST_DIR=\"$EMBEDDED_PLUGINS_DIR/$plugin\"\n\tmkdir -p \"$DEST_DIR/hooks\"\n\tcp \"$TEMP_DIR/metadata.lua\" \"$DEST_DIR/\"\n\tcp \"$TEMP_DIR/hooks/\"*.lua \"$DEST_DIR/hooks/\" 2>/dev/null || true\n\tif [[ -d \"$TEMP_DIR/lib\" ]]; then\n\t\tmkdir -p \"$DEST_DIR/lib\"\n\t\tcp \"$TEMP_DIR/lib/\"*.lua \"$DEST_DIR/lib/\" 2>/dev/null || true\n\tfi\n\trm -rf \"$TEMP_DIR\"\ndone\n\n# Bump subcrate versions if they have changes (from aqua-registry/vfox updates)\nbump_subcrate_if_changed \"aqua-registry\" \"crates/aqua-registry\"\nbump_subcrate_if_changed \"vfox\" \"crates/vfox\"\nbump_subcrate_if_changed \"mise-interactive-config\" \"crates/mise-interactive-config\"\n\ngit status\n# cargo update\ngit add \\\n\tCargo.lock \\\n\tCargo.toml \\\n\tCHANGELOG.md \\\n\tREADME.md \\\n\tcrates/aqua-registry/aqua-registry \\\n\tcrates/aqua-registry/Cargo.toml \\\n\tcrates/vfox/embedded-plugins \\\n\tcrates/vfox/Cargo.toml \\\n\tcrates/mise-interactive-config/Cargo.toml \\\n\tdefault.nix \\\n\tsnapcraft.yaml \\\n\tdocs/.vitepress/stars.data.ts \\\n\tpackaging/rpm/mise.spec \\\n\tmise.usage.kdl \\\n\tcompletions \\\n\tmise.lock \\\n\tman/ \\\n\tsrc/assets/gpg/\ngit clean -df\ngit checkout -B release\ngit commit -m \"chore: release $version\"\ngit push origin release --force\n\n# Append aqua-registry updates to PR body if available\nPR_BODY=\"$PR_NOTES\"\nif [[ -n $AQUA_CHANGELOG_PR ]]; then\n\tPR_BODY=\"$PR_NOTES\"$'\\n\\n'\"$AQUA_CHANGELOG_PR\"\nfi\n\n# Check for existing PR from the release branch specifically (not by label repo-wide)\nif [[ \"$(gh pr list --head release --state open)\" == \"\" ]]; then\n\tgh pr create --title \"chore: release $version\" --body \"$PR_BODY\" --label \"release\" --head release\nelse\n\tgh pr edit release --title \"chore: release $version\" --body \"$PR_BODY\"\nfi\n"
  },
  {
    "path": "xtasks/render/schema.ts",
    "content": "#!/usr/bin/env bun\n\n//MISE description=\"Render JSON schema\"\n//MISE depends=[\"docs:setup\"]\n\nimport * as fs from \"node:fs\";\nimport * as child_process from \"node:child_process\";\nimport * as toml from \"toml\";\n\ntype EnumValue = string | boolean | number;\ntype EnumItem = EnumValue | { value: EnumValue; description?: string };\n\ntype Props = {\n  type: string;\n  description: string;\n  default?: unknown;\n  deprecated?: string;\n  enum?: EnumItem[];\n  rc?: boolean;\n};\n\ntype SettingsToml = Record<string, Props | Record<string, Props>>;\n\ntype Element = {\n  type: string | string[];\n  default: unknown;\n  description: string;\n  deprecated?: true;\n  enum?: EnumValue[];\n  items?: {\n    type: string | string[];\n  };\n  additionalProperties?: {\n    type: string;\n  };\n};\n\ntype NestedElement = {\n  type: \"object\";\n  additionalProperties: false;\n  deprecated?: true;\n  properties: Record<string, Element>;\n};\n\nfunction buildElement(key: string, props: Props): Element {\n  const typeMap: Record<string, string | string[]> = {\n    String: \"string\",\n    Path: \"string\",\n    Url: \"string\",\n    Duration: \"string\",\n    Bool: \"boolean\",\n    Integer: \"number\",\n    ListString: \"string[]\",\n    ListPath: \"string[]\",\n    SetString: \"string[]\",\n    \"IndexMap<String, String>\": \"object\",\n    BoolOrString: [\"boolean\", \"string\"],\n  };\n  const type = props.type ? typeMap[props.type] : undefined;\n  if (!type) {\n    throw new Error(`Unknown type: ${props.type}`);\n  }\n\n  if (!props.description) {\n    throw new Error(`Missing description for ${key}`);\n  }\n\n  const element: Element = {\n    default: props.default,\n    description: props.description,\n    type,\n  };\n\n  if (props.deprecated) {\n    element.deprecated = true;\n  }\n  if (props.enum) {\n    element.enum = props.enum.map((e) =>\n      typeof e === \"object\" && e !== null && \"value\" in e ? e.value : e,\n    );\n  }\n\n  if (type === \"string[]\") {\n    element.type = \"array\";\n    element.items = {\n      type: \"string\",\n    };\n  }\n\n  if (type === \"object\") {\n    element.additionalProperties = {\n      type: \"string\",\n    };\n  }\n\n  return element;\n}\n\nconst doc = toml.parse(\n  fs.readFileSync(\"settings.toml\", \"utf-8\"),\n) as SettingsToml;\nconst settings: Record<string, Element | NestedElement> = {};\n\nconst hasSubkeys = (props: SettingsToml[string]): props is Props => {\n  return \"type\" in props;\n};\n\nfor (const key in doc) {\n  const props = doc[key];\n  if (hasSubkeys(props)) {\n    settings[key] = buildElement(key, props);\n  } else {\n    for (const subkey in props) {\n      settings[key] ??= {\n        type: \"object\",\n        additionalProperties: false,\n        properties: {},\n      };\n      if (props.deprecated) {\n        settings[key].deprecated = true;\n      }\n      (settings[key] as NestedElement).properties[subkey] = buildElement(\n        `${key}.${subkey}`,\n        props[subkey],\n      );\n    }\n  }\n}\n\nconst schema = JSON.parse(fs.readFileSync(\"schema/mise.json\", \"utf-8\"));\nschema[\"$defs\"].settings.properties = settings;\n\n// Generate task and task_template from task_props to avoid unevaluatedProperties\n// (which Tombi doesn't support) while keeping extends only on tasks, not templates.\nconst taskProps = schema[\"$defs\"].task_props;\n\n// task_template: task_props + additionalProperties: false\nschema[\"$defs\"].task_template = {\n  description: \"task template that can be extended by tasks\",\n  properties: { ...taskProps.properties },\n  additionalProperties: false,\n  type: \"object\",\n};\n\n// task (object variant): task_props + extends + additionalProperties: false\nconst taskObjectVariant = {\n  properties: {\n    ...taskProps.properties,\n    extends: {\n      description: \"name of the task template to extend\",\n      type: \"string\",\n    },\n  },\n  additionalProperties: false,\n  type: \"object\",\n};\n\n// Overwrite the object variant (last entry) in task oneOf with inlined properties\nconst taskDef = schema[\"$defs\"].task;\ntaskDef.oneOf[taskDef.oneOf.length - 1] = taskObjectVariant;\n\nfs.writeFileSync(\"schema/mise.json.tmp\", JSON.stringify(schema));\n\nchild_process.execSync(\"jq . < schema/mise.json.tmp > schema/mise.json\");\nchild_process.execSync(\"prettier --write schema/mise.json\");\nfs.unlinkSync(\"schema/mise.json.tmp\");\n\nconst taskSchema = JSON.parse(\n  fs.readFileSync(\"schema/mise-task.json\", \"utf-8\"),\n);\ntaskSchema[\"$defs\"].env_directive = schema[\"$defs\"].env_directive;\ntaskSchema[\"$defs\"].env = schema[\"$defs\"].env;\ntaskSchema[\"$defs\"].vars = schema[\"$defs\"].vars;\ntaskSchema[\"$defs\"].task_run_entry = schema[\"$defs\"].task_run_entry;\ntaskSchema[\"$defs\"].task = schema[\"$defs\"].task;\ntaskSchema[\"$defs\"].task_template = schema[\"$defs\"].task_template;\ndelete taskSchema[\"$defs\"].task_props;\nfs.writeFileSync(\"schema/mise-task.json.tmp\", JSON.stringify(taskSchema));\nchild_process.execSync(\n  \"jq . < schema/mise-task.json.tmp > schema/mise-task.json\",\n);\nchild_process.execSync(\"prettier --write schema/mise-task.json\");\nfs.unlinkSync(\"schema/mise-task.json.tmp\");\n\n// Generate .miserc.toml schema with only rc=true settings\nconst misercSettings: Record<string, Element> = {};\n\nfor (const key in doc) {\n  const props = doc[key];\n  if (hasSubkeys(props) && props.rc === true) {\n    misercSettings[key] = buildElement(key, props);\n  }\n}\n\nconst misercSchema = {\n  $schema: \"https://json-schema.org/draft/2020-12/schema\",\n  title: \"mise rc config\",\n  description:\n    \"Early initialization settings for mise. These settings are loaded before the main config files.\",\n  type: \"object\",\n  additionalProperties: false,\n  properties: misercSettings,\n};\n\nfs.writeFileSync(\"schema/miserc.json.tmp\", JSON.stringify(misercSchema));\nchild_process.execSync(\"jq . < schema/miserc.json.tmp > schema/miserc.json\");\nchild_process.execSync(\"prettier --write schema/miserc.json\");\nfs.unlinkSync(\"schema/miserc.json.tmp\");\n"
  },
  {
    "path": "xtasks/show-output-on-failure",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Show output on failure for documentation generation\"\nset -euo pipefail\n\noutput=$(\"$@\" 2>&1)\nstatus=$?\nif ((status)); then\n\techo \"$output\" >&2\nfi\n\nexit $status\n"
  },
  {
    "path": "xtasks/show-output-on-failure.bat",
    "content": "%*\n"
  },
  {
    "path": "xtasks/test/build-perf-workspace",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Build the performance test workspace\"\nset -euo pipefail\n\nmkdir -p perf-workspace\ncd perf-workspace\nMISE_DATA_DIR=\"${MISE_DATA_DIR:-$HOME/.local/share/mise}\"\nmkdir -p .mise-tasks \"$MISE_DATA_DIR/plugins\"\n\nnum_tasks=${NUM_TASKS:-1000}\nnum_tools=${NUM_TOOLS:-100}\n\ncreate_tasks() {\n\tcat <<EOF >.mise-tasks/perf-0\n#!/bin/sh\n#MISE description=\"task description\"\necho running task\nEOF\n\tchmod +x .mise-tasks/perf-0\n\tfor i in $(seq 1 \"$num_tasks\"); do\n\t\tln -sf ./perf-0 \".mise-tasks/perf-$i\"\n\tdone\n}\n\ncreate_tools() {\n\t# shellcheck disable=SC2207\n\ttools=($(seq 0 \"$num_tools\"))\n\tif [ ! -d \"$MISE_DATA_DIR/plugins/tiny\" ]; then\n\t\tgit clone https://github.com/jdx/mise-tiny.git \"$MISE_DATA_DIR/plugins/tiny\"\n\tfi\n\t{\n\t\techo \"[tools]\"\n\t\tfor i in \"${tools[@]}\"; do\n\t\t\techo \"\\\"perf-$i\\\" = \\\"$i\\\"\"\n\t\tdone\n\t\techo \"[alias]\"\n\t\tfor i in \"${tools[@]}\"; do\n\t\t\techo \"\\\"perf-$i\\\" = \\\"asdf:jdx/mise-tiny\\\"\"\n\t\tdone\n\t} >mise.toml\n\n\tfor i in \"${tools[@]}\"; do\n\t\tln -sf ./tiny \"$MISE_DATA_DIR/plugins/perf-$i\"\n\tdone\n}\n\ncreate_tasks\ncreate_tools\n"
  },
  {
    "path": "xtasks/test/coverage",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Run all tests with coverage report\"\n\necho \"::group::Setup\"\nset -euxo pipefail\nexport CARGO_TARGET_DIR=\"${CARGO_TARGET_DIR:-$PWD/target}\"\nexport PATH=\"${CARGO_TARGET_DIR}/debug:$PATH\"\n\necho \"::endgroup::\"\necho \"::group::mise install\"\nmise install\nmise x -- bun i\necho \"::endgroup::\"\nmise x -- ./e2e/run_all_tests\n"
  },
  {
    "path": "xtasks/test/e2e",
    "content": "#!/usr/bin/env bash\n#MISE depends=[\"build\"]\n#MISE alias=[\"e\", \"e2e\"]\n#MISE description=\"Run end-to-end tests\"\nset -euo pipefail\n\nexport RUST_TEST_THREADS=1\n\n# Show help\nif [[ ${1:-} == --help ]]; then\n\tcat >&2 <<EOF\nUsage: mise run test:e2e [OPTIONS] [TEST_PATTERNS...]\n\nOptions:\n  --help     Show this help message\n  --list     List all available tests\n  --all      Run all tests\n\nArguments:\n  TEST_PATTERNS...  Test patterns to run (e.g., \"tasks\", \"cli\", \"test_task_run\")\n\nExamples:\n  mise run test:e2e --list                    # List all available tests\n  mise run test:e2e --all                     # Run all tests\n  mise run test:e2e -- tasks                  # Run all task-related tests\n  mise run test:e2e -- cli                    # Run all CLI-related tests\n  mise run test:e2e -- test_task_run          # Run specific test\nEOF\n\texit 0\nfi\n\n# List all available tests\nif [[ ${1:-} == --list ]]; then\n\techo \"Available tests:\" >&2\n\tpushd e2e >/dev/null\n\tfd -tf \"^test_\" | sort\n\tpopd >/dev/null\n\texit 0\nfi\n\nif [[ ${1:-} == --all ]]; then\n\t./e2e/run_all_tests\nelse\n\t# Handle multiple test arguments\n\tfor TEST_ARG in \"$@\"; do\n\t\t# Strip e2e/ prefix if present, then extract just the filename\n\t\tPATTERN=\"${TEST_ARG#e2e/}\"\n\t\tFILENAME=\"$(basename \"$PATTERN\")\"\n\n\t\tpushd e2e >/dev/null\n\t\tFILES=\"$(fd -tf \"$FILENAME\" --and \"^test_\")\"\n\t\tpopd >/dev/null\n\n\t\tif [[ -z $FILES ]]; then\n\t\t\techo \"No test matches $TEST_ARG\" >&2\n\t\t\texit 1\n\t\tfi\n\n\t\tfor FILE in $FILES; do\n\t\t\techo \"[xtask:e2e] Running test: $FILE\" >&2\n\t\t\t./e2e/run_test \"$FILE\"\n\t\tdone\n\tdone\nfi\n"
  },
  {
    "path": "xtasks/test/perf",
    "content": "#!/usr/bin/env bash\n#MISE depends=[\"test:build-perf-workspace\"]\n#MISE description=\"Run performance tests\"\n# shellcheck disable=SC2086,SC2129\nset -euo pipefail\n\nruns=\"${RUNS:-1}\"\ncd perf-workspace\nmkdir -p flamegraphs\nMISE_DATA_DIR=\"${MISE_DATA_DIR:-$HOME/.local/share/mise}\"\ndeclare -A benchmarks\ndeclare -A alt_benchmarks\nnames=()\n\nif [ -v MISE_ALT ]; then\n\twhich mise\n\twhich \"$MISE_ALT\"\nfi\n\ntime_command() {\n\tlocal uncached=\"$1\"\n\tshift\n\tlocal cmd=\"$1\"\n\tlocal start_time\n\tlocal end_time\n\tlocal duration\n\tlocal total=0\n\tshift\n\techo \"running $cmd $* $runs times...\" >&2\n\tfor _ in $(seq 1 $runs); do\n\t\tif [ \"$uncached\" = \"uncached\" ]; then\n\t\t\t\"$cmd\" cache clear\n\t\tfi\n\t\tstart_time=$(date +%s%N)\n\t\ttimeout -v 20 \"$cmd\" \"$@\" >/dev/null || true\n\t\tend_time=$(date +%s%N)\n\t\tduration=$(((end_time - start_time) / 1000000))\n\t\ttotal=$((total + duration))\n\tdone\n\techo $((total / runs))\n}\n\nbenchmark() {\n\tlocal name=\"$1\"\n\t# local uncached_duration\n\tlocal cached_duration\n\tshift\n\t# uncached_duration=$(time_command uncached mise \"$@\")\n\tcached_duration=$(time_command cached mise \"$@\")\n\tbenchmarks[\"$name-cached\"]=$cached_duration\n\n\tif [ -n \"${MISE_ALT:-}\" ]; then\n\t\t# alt_uncached_duration=$(time_command uncached \"$MISE_ALT\" \"$@\")\n\t\talt_cached_duration=$(time_command cached \"$MISE_ALT\" \"$@\")\n\t\talt_benchmarks[\"$name-cached\"]=$alt_cached_duration\n\tfi\n\n\tnames+=(\"$name\")\n}\n\nmise install\n# Warmup call to prime caches before measuring\nmise install >/dev/null 2>&1 || true\nif [ -n \"${MISE_ALT:-}\" ]; then\n\t\"$MISE_ALT\" install >/dev/null 2>&1 || true\nfi\nbenchmark install install\n# Warmup call to prime caches before measuring\nmise ls >/dev/null 2>&1 || true\nif [ -n \"${MISE_ALT:-}\" ]; then\n\t\"$MISE_ALT\" ls >/dev/null 2>&1 || true\nfi\nbenchmark ls ls\nbenchmark bin-paths bin-paths\nbenchmark task-ls task ls\nset +x\n\nget_performance_emoji() {\n\tlocal variance=\"$1\"\n\tif [ ${variance#-} -gt 10 ]; then\n\t\tif [ $variance -gt 0 ]; then\n\t\t\techo \"✅ \"\n\t\telse\n\t\t\techo \"⚠️ \"\n\t\tfi\n\tfi\n}\n\nget_performance_warning() {\n\tlocal name=\"$1\"\n\tlocal variance=\"$2\"\n\tlocal type=\"$3\"\n\tif [ ${variance#-} -gt 10 ]; then\n\t\tif [ $variance -gt 0 ]; then\n\t\t\techo \"✅  Performance improvement: $name $type is ${variance}%\"\n\t\telse\n\t\t\tlocal msg=\"⚠️  Warning: $name $type performance variance is ${variance}%\"\n\t\t\techo \"::warning file=xtasks/test/perf::$msg\" >&2\n\t\t\techo \"$msg\"\n\t\tfi\n\tfi\n}\n\nprint_performance_table() {\n\tlocal output_file=\"$1\"\n\tif [ -n \"${MISE_ALT:-}\" ]; then\n\t\techo \"| Command    | $MISE_ALT | mise | Variance |\" >>\"$output_file\"\n\t\techo \"|------------|-----------|------|----------|\" >>\"$output_file\"\n\t\tfor name in \"${names[@]}\"; do\n\t\t\t# uncached_variance=$(((${alt_benchmarks[\"$name-uncached\"]} - ${benchmarks[\"$name-uncached\"]}) * 100 / ${benchmarks[\"$name-uncached\"]}))\n\t\t\tcached_variance=$(((${alt_benchmarks[\"$name-cached\"]} - ${benchmarks[\"$name-cached\"]}) * 100 / ${benchmarks[\"$name-cached\"]}))\n\n\t\t\t# uncached_emoji=$(get_performance_emoji \"$uncached_variance\")\n\t\t\tcached_emoji=$(get_performance_emoji \"$cached_variance\")\n\n\t\t\t# printf \"| %-10s | %6dms | %s%6dms | %+d%% |\\n\" \\\n\t\t\t#   \"$name (uncached)\" \\\n\t\t\t#   \"${alt_benchmarks[\\\"$name-uncached\\\"]}\" \\\n\t\t\t#   \"$uncached_emoji\" \\\n\t\t\t#   \"${benchmarks[\\\"$name-uncached\\\"]}\" \\\n\t\t\t#   \"$uncached_variance\" >>\"$output_file\"\n\t\t\tprintf \"| %-10s | %6dms | %s%6dms | %+d%% |\\n\" \\\n\t\t\t\t\"$name (cached)\" \\\n\t\t\t\t\"${alt_benchmarks[\"$name-cached\"]}\" \\\n\t\t\t\t\"$cached_emoji\" \\\n\t\t\t\t\"${benchmarks[\"$name-cached\"]}\" \\\n\t\t\t\t\"$cached_variance\" >>\"$output_file\"\n\t\tdone\n\telse\n\t\techo \"| Command    | Time   |\" >>\"$output_file\"\n\t\techo \"|------------|--------|\" >>\"$output_file\"\n\t\tfor name in \"${names[@]}\"; do\n\t\t\t# printf \"| %-10s | %6dms |\\n\" \"$name (uncached)\" \"${benchmarks[\\\"$name-uncached\\\"]}\" >>\"$output_file\"\n\t\t\tprintf \"| %-10s | %6dms |\\n\" \"$name (cached)\" \"${benchmarks[\"$name-cached\"]}\" >>\"$output_file\"\n\t\tdone\n\tfi\n}\n\nprint_performance_warnings() {\n\tlocal output_file=\"$1\"\n\tif [ -n \"${MISE_ALT:-}\" ]; then\n\t\tfor name in \"${names[@]}\"; do\n\t\t\t# uncached_variance=$(((${alt_benchmarks[\"$name-uncached\"]} - ${benchmarks[\"$name-uncached\"]}) * 100 / ${benchmarks[\"$name-uncached\"]}))\n\t\t\tcached_variance=$(((${alt_benchmarks[\"$name-cached\"]} - ${benchmarks[\"$name-cached\"]}) * 100 / ${benchmarks[\"$name-cached\"]}))\n\n\t\t\t# warning=$(get_performance_warning \"$name\" \"$uncached_variance\" \"uncached\")\n\t\t\t# if [ -n \"$warning\" ]; then\n\t\t\t#   echo \"$warning\" >>\"$output_file\"\n\t\t\t# fi\n\t\t\twarning=$(get_performance_warning \"$name\" \"$cached_variance\" \"cached\")\n\t\t\tif [ -n \"$warning\" ]; then\n\t\t\t\techo \"$warning\" >>\"$output_file\"\n\t\t\tfi\n\t\tdone\n\tfi\n}\n\n# Print table to console\nprint_performance_table \"/dev/stdout\"\n\nif [ -v GITHUB_STEP_SUMMARY ]; then\n\t# shellcheck disable=SC2016\n\techo '## `xtasks/test/perf`' >>../comment.md\n\t# echo \"\" >>../comment.md\n\t# echo \"- NUM_TASKS: $num_tasks\" >>../comment.md\n\t# echo \"- NUM_TOOLS: $num_tools\" >>../comment.md\n\t# echo \"- RUNS: $runs\" >>../comment.md\n\t# echo \"\" >>../comment.md\n\n\tprint_performance_table \"../comment.md\"\n\techo \"\" >>../comment.md\n\tprint_performance_warnings \"../comment.md\"\nfi\n"
  },
  {
    "path": "xtasks/test-tool-retry.py",
    "content": "#!/usr/bin/env python3\n#MISE description=\"Retry failed test-tools with grace period for recent upstream releases\"\n#USAGE flag \"--grace-period\" help=\"Ignore failures from tools whose upstream released <7 days ago\"\n#USAGE arg \"<tools>...\" help=\"Failed tools to retry\"\n\"\"\"Retries failed test-tool runs. With --grace-period, tools backed by\nGitHub/aqua whose latest upstream release is less than 7 days old have\ntheir failures treated as warnings instead of errors.\"\"\"\n\nimport json\nimport os\nimport re\nimport subprocess\nimport sys\nfrom datetime import datetime, timezone, timedelta\nfrom pathlib import Path\n\nGRACE_PERIOD = timedelta(days=7)\n\n\ndef get_repo(tool: str) -> str | None:\n    \"\"\"Extract the GitHub owner/repo from a tool's backend via mise.\"\"\"\n    try:\n        result = subprocess.run(\n            [\"mise\", \"tool\", \"--json\", tool],\n            capture_output=True, text=True, timeout=30,\n        )\n        if result.returncode != 0:\n            return None\n        data = json.loads(result.stdout)\n        backend = data.get(\"backend\", \"\")\n        # backend looks like \"github:owner/repo[bin=x]\" or \"aqua:owner/repo/subpath\"\n        for prefix in (\"github:\", \"aqua:\"):\n            if backend.startswith(prefix):\n                repo = backend[len(prefix):]\n                # strip any trailing [options]\n                repo = repo.split(\"[\")[0]\n                # aqua backends can have subpaths (e.g. kubernetes/kubernetes/kubectl)\n                # extract just owner/repo for the GitHub API\n                parts = repo.split(\"/\")\n                if len(parts) >= 2:\n                    return f\"{parts[0]}/{parts[1]}\"\n                return None\n        return None\n    except (subprocess.TimeoutExpired, json.JSONDecodeError, KeyError):\n        return None\n\n\ndef get_latest_release_date(repo: str) -> datetime | None:\n    \"\"\"Get the published_at date of the latest GitHub release.\"\"\"\n    try:\n        result = subprocess.run(\n            [\"gh\", \"api\", f\"repos/{repo}/releases/latest\", \"--jq\", \".published_at\"],\n            capture_output=True, text=True, timeout=30,\n        )\n        if result.returncode != 0 or not result.stdout.strip():\n            return None\n        return datetime.fromisoformat(result.stdout.strip().replace(\"Z\", \"+00:00\"))\n    except (subprocess.TimeoutExpired, subprocess.SubprocessError, ValueError):\n        return None\n\n\ndef get_failed_tools_from_summary() -> list[str]:\n    \"\"\"Parse failed tools from GITHUB_STEP_SUMMARY.\"\"\"\n    summary_path = os.environ.get(\"GITHUB_STEP_SUMMARY\")\n    if not summary_path or not Path(summary_path).exists():\n        return []\n    content = Path(summary_path).read_text()\n    failed = []\n    for line in content.splitlines():\n        if \"Failed Tools\" in line:\n            cleaned = re.sub(r\"\\*\\*Failed Tools\\*\\*:\\s*\", \"\", line).strip()\n            failed = [t.strip() for t in cleaned.split(\",\") if t.strip()]\n    return failed\n\n\ndef retry_tools(tools: list[str]) -> list[str]:\n    \"\"\"Retry failed tools and return any that still fail.\"\"\"\n    result = subprocess.run([\"mise\", \"test-tool\"] + tools)\n    if result.returncode == 0:\n        return []\n    failed = get_failed_tools_from_summary()\n    return failed if failed else tools\n\n\ndef check_grace_period(tools: list[str]) -> list[str]:\n    \"\"\"Return tools that are NOT within the grace period.\"\"\"\n    hard_failures = []\n    now = datetime.now(timezone.utc)\n\n    for tool in tools:\n        repo = get_repo(tool)\n        if not repo:\n            print(f\"::warning::Ignoring {tool} failure — no github/aqua backend found, \"\n                  \"grace period check not applicable\")\n            continue\n\n        published = get_latest_release_date(repo)\n        if not published:\n            print(f\"::error::{tool}: could not fetch latest release for {repo}\")\n            hard_failures.append(tool)\n            continue\n\n        age = now - published\n        if age < GRACE_PERIOD:\n            print(f\"::warning::Ignoring {tool} failure — latest release of {repo} \"\n                  f\"({published.isoformat()}) is {age.days}d old (< 7d grace period)\")\n        else:\n            print(f\"::error::{tool}: latest release of {repo} is {age.days}d old\")\n            hard_failures.append(tool)\n\n    return hard_failures\n\n\ndef main():\n    grace_period = \"--grace-period\" in sys.argv\n    tools = [a for a in sys.argv[1:] if not a.startswith(\"-\")]\n\n    if not tools:\n        print(\"Usage: test-tool-retry [--grace-period] <tool1> [tool2] ...\")\n        sys.exit(1)\n\n    still_failing = retry_tools(tools)\n    if not still_failing:\n        print(\"All tools passed on retry.\")\n        sys.exit(0)\n\n    if not grace_period:\n        print(f\"Failed tools: {', '.join(still_failing)}\")\n        sys.exit(1)\n\n    hard_failures = check_grace_period(still_failing)\n    if hard_failures:\n        print(f\"\\nHard failures: {', '.join(hard_failures)}\")\n        sys.exit(1)\n\n    print(\"\\nAll failures are within the 7-day grace period for new releases.\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "xtasks/testtask.ps1",
    "content": "Write-Host windows\n"
  },
  {
    "path": "xtasks/testtask.sh",
    "content": "#!/usr/bin/env bash\necho unix\n"
  },
  {
    "path": "xtasks/update-descriptions",
    "content": "#!/usr/bin/env bash\n#MISE description=\"Update all task descriptions in the project\"\nset -euxo pipefail\n\nfor tool in $(mise registry | awk '{print $1}'); do\n\tdescription=\"$(mise tool --description \"$tool\")\"\n\tif [ \"$description\" != \"[none]\" ] && [ -f \"registry/$tool.toml\" ]; then\n\t\ttoml set \"registry/$tool.toml\" \"tools.$tool.description\" \"$description\" >\"registry/$tool.toml.tmp\"\n\t\tmv \"registry/$tool.toml.tmp\" \"registry/$tool.toml\"\n\tfi\ndone\n"
  },
  {
    "path": "zipsign.pub",
    "content": "\u001auy=q\u0012D\u0004A%R]J\u0017"
  }
]